diff --git a/src/vs/workbench/contrib/webview/browser/pre/index.html b/src/vs/workbench/contrib/webview/browser/pre/index.html index 7629db38a295c..0c6829c08f8b0 100644 --- a/src/vs/workbench/contrib/webview/browser/pre/index.html +++ b/src/vs/workbench/contrib/webview/browser/pre/index.html @@ -5,7 +5,9 @@ + + content="default-src 'none'; script-src 'sha256-EJBlYt9sOvo6RhZZJG+duTqIZCB8pctk1a62h/ZIElc=' 'self'; frame-src 'self'; style-src 'unsafe-inline';"> + void} callback */ @@ -881,7 +894,9 @@ window.addEventListener('keydown', handleInnerKeydown); window.addEventListener('keyup', handleInnerKeyup); window.addEventListener('dragenter', handleInnerDragStartEvent); - window.addEventListener('dragover', handleInnerDragStartEvent); + window.addEventListener('dragover', handleInnerDragEvent); + window.addEventListener('drag', handleInnerDragEvent); + onDomReady(() => { if (!document.body) { @@ -1163,7 +1178,8 @@ }); contentWindow.addEventListener('dragenter', handleInnerDragStartEvent); - contentWindow.addEventListener('dragover', handleInnerDragStartEvent); + contentWindow.addEventListener('dragover', handleInnerDragEvent); + contentWindow.addEventListener('drag', handleInnerDragEvent); unloadMonitor.onIframeLoaded(newFrame); } diff --git a/src/vs/workbench/contrib/webview/browser/webviewElement.ts b/src/vs/workbench/contrib/webview/browser/webviewElement.ts index 3d5d21f080f7f..5d6e403159f46 100644 --- a/src/vs/workbench/contrib/webview/browser/webviewElement.ts +++ b/src/vs/workbench/contrib/webview/browser/webviewElement.ts @@ -34,7 +34,7 @@ import { loadLocalResource, WebviewResourceResponse } from 'vs/workbench/contrib import { WebviewThemeDataProvider } from 'vs/workbench/contrib/webview/browser/themeing'; import { areWebviewContentOptionsEqual, IWebview, WebviewContentOptions, WebviewExtensionDescription, WebviewInitInfo, WebviewMessageReceivedEvent, WebviewOptions } from 'vs/workbench/contrib/webview/browser/webview'; import { WebviewFindDelegate, WebviewFindWidget } from 'vs/workbench/contrib/webview/browser/webviewFindWidget'; -import { FromWebviewMessage, KeyEvent, ToWebviewMessage } from 'vs/workbench/contrib/webview/browser/webviewMessages'; +import { FromWebviewMessage, KeyEvent, ToWebviewMessage, WebViewDragEvent } from 'vs/workbench/contrib/webview/browser/webviewMessages'; import { decodeAuthority, webviewGenericCspSource, webviewRootResourceAuthority } from 'vs/workbench/contrib/webview/common/webview'; import { IWorkbenchEnvironmentService } from 'vs/workbench/services/environment/common/environmentService'; import { CodeWindow } from 'vs/base/browser/window'; @@ -310,6 +310,10 @@ export class WebviewElement extends Disposable implements IWebview, WebviewFindD this._startBlockingIframeDragEvents(); })); + this._register(this.on('drag', (event) => { + this.handleDragEvent('drag', event); + })); + if (initInfo.options.enableFindWidget) { this._webviewFindWidget = this._register(instantiationService.createInstance(WebviewFindWidget, this)); } @@ -697,6 +701,17 @@ export class WebviewElement extends Disposable implements IWebview, WebviewFindD this.window?.dispatchEvent(emulatedKeyboardEvent); } + private handleDragEvent(type: 'drag', event: WebViewDragEvent) { + // Create a fake DragEvent from the data provided + const emulatedDragEvent = new DragEvent(type, event); + // Force override the target + Object.defineProperty(emulatedDragEvent, 'target', { + get: () => this.element, + }); + // And re-dispatch + this.window?.dispatchEvent(emulatedDragEvent); + } + windowDidDragStart(): void { // Webview break drag and dropping around the main window (no events are generated when you are over them) // Work around this by disabling pointer events during the drag. diff --git a/src/vs/workbench/contrib/webview/browser/webviewMessages.d.ts b/src/vs/workbench/contrib/webview/browser/webviewMessages.d.ts index eae9c80fa6872..dde553ec05724 100644 --- a/src/vs/workbench/contrib/webview/browser/webviewMessages.d.ts +++ b/src/vs/workbench/contrib/webview/browser/webviewMessages.d.ts @@ -17,6 +17,10 @@ type KeyEvent = { repeat: boolean; } +type WebViewDragEvent = { + shiftKey: boolean; +} + export type FromWebviewMessage = { 'onmessage': { message: any; transfer?: ArrayBuffer[] }; 'did-click-link': { uri: string }; @@ -36,6 +40,7 @@ export type FromWebviewMessage = { 'did-keyup': KeyEvent; 'did-context-menu': { clientX: number; clientY: number; context: { [key: string]: unknown } }; 'drag-start': void; + 'drag': WebViewDragEvent }; interface UpdateContentEvent { diff --git a/src/vs/workbench/contrib/webview/browser/webviewWindowDragMonitor.ts b/src/vs/workbench/contrib/webview/browser/webviewWindowDragMonitor.ts index e4dc5eaf0e904..d009ae186da59 100644 --- a/src/vs/workbench/contrib/webview/browser/webviewWindowDragMonitor.ts +++ b/src/vs/workbench/contrib/webview/browser/webviewWindowDragMonitor.ts @@ -18,19 +18,41 @@ export class WebviewWindowDragMonitor extends Disposable { constructor(targetWindow: CodeWindow, getWebview: () => IWebview | undefined) { super(); - this._register(DOM.addDisposableListener(targetWindow, DOM.EventType.DRAG_START, () => { + const onDragStart = () => { getWebview()?.windowDidDragStart(); - })); + }; const onDragEnd = () => { getWebview()?.windowDidDragEnd(); }; + this._register(DOM.addDisposableListener(targetWindow, DOM.EventType.DRAG_START, () => { + onDragStart(); + })); + this._register(DOM.addDisposableListener(targetWindow, DOM.EventType.DRAG_END, onDragEnd)); + this._register(DOM.addDisposableListener(targetWindow, DOM.EventType.MOUSE_MOVE, currentEvent => { if (currentEvent.buttons === 0) { onDragEnd(); } })); + + this._register(DOM.addDisposableListener(targetWindow, DOM.EventType.DRAG, (event) => { + if (event.shiftKey) { + onDragEnd(); + } else { + onDragStart(); + } + })); + + this._register(DOM.addDisposableListener(targetWindow, DOM.EventType.DRAG_OVER, (event) => { + if (event.shiftKey) { + onDragEnd(); + } else { + onDragStart(); + } + })); + } }