提交 4d4f3a30 编写于 作者: M Matt Bierner

Observe the confirmBeforeClose setting for webviews

上级 08e6047a
......@@ -26,6 +26,7 @@ export const enum WebviewMessageChannels {
didLoad = 'did-load',
doUpdateState = 'do-update-state',
doReload = 'do-reload',
setConfirmBeforeClose = 'set-confirm-before-close',
loadResource = 'load-resource',
loadLocalhost = 'load-localhost',
webviewReady = 'webview-ready',
......
......@@ -9,7 +9,7 @@
const hostMessaging = new class HostMessaging {
constructor() {
/** @type {Map<string, (event: MessageEvent, data: any) => void>} */
/** @type {Map<string, Array<(event: MessageEvent, data: any) => void>>} */
this.handlers = new Map();
window.addEventListener('message', (e) => {
......@@ -20,21 +20,36 @@
}
const channel = e.data.channel;
const handler = this.handlers.get(channel);
if (handler) {
handler(e, e.data.args);
const handlers = this.handlers.get(channel);
if (handlers) {
for (const handler of handlers) {
handler(e, e.data.args);
}
} else {
console.log('no handler for ', e);
}
});
}
/**
* @param {string} channel
* @param {any} data
*/
postMessage(channel, data) {
window.parent.postMessage({ target: id, channel, data }, '*');
}
/**
* @param {string} channel
* @param {(event: MessageEvent, data: any) => void} handler
*/
onMessage(channel, handler) {
this.handlers.set(channel, handler);
let handlers = this.handlers.get(channel);
if (!handlers) {
handlers = [];
this.handlers.set(channel, handlers);
}
handlers.push(handler);
}
}();
......@@ -108,30 +123,59 @@
}
}
/** @type {undefined | ((iframe: HTMLIFrameElement) => void)} */
let onIframeLoaded;
const unloadMonitor = new class {
constructor() {
this.confirmBeforeClose = 'keyboardOnly';
this.isModifierKeyDown = false;
hostMessaging.onMessage('set-confirm-before-close', (_e, /** @type {string} */ data) => {
this.confirmBeforeClose = data;
});
hostMessaging.onMessage('content', (_e, /** @type {any} */ data) => {
this.confirmBeforeClose = data.confirmBeforeClose;
});
window.addEventListener('beforeunload', (event) => {
if (onElectron) {
return;
}
if (!onElectron) {
let isModifierDown = false;
switch (this.confirmBeforeClose) {
case 'always':
{
event.preventDefault();
event.returnValue = '';
return '';
}
case 'never':
{
break;
}
case 'keyboardOnly':
default: {
if (this.isModifierKeyDown) {
event.preventDefault();
event.returnValue = '';
return '';
}
break;
}
}
});
}
onIframeLoaded = (frame) => {
onIframeLoaded(/** @type {HTMLIFrameElement} */frame) {
frame.contentWindow.addEventListener('keydown', e => {
isModifierDown = e.metaKey || e.ctrlKey || e.altKey;
this.isModifierKeyDown = e.metaKey || e.ctrlKey || e.altKey;
});
frame.contentWindow.addEventListener('keyup', () => {
isModifierDown = false;
this.isModifierKeyDown = false;
});
};
window.addEventListener('beforeunload', (event) => {
if (isModifierDown) {
event.preventDefault();
event.returnValue = '';
return '';
}
});
}
}
};
/** @type {import('./main').WebviewHost} */
const host = {
......@@ -140,7 +184,9 @@
ready: workerReady,
fakeLoad: !onElectron,
onElectron: onElectron,
onIframeLoaded,
onIframeLoaded: (/** @type {HTMLIFrameElement} */ frame) => {
unloadMonitor.onIframeLoaded(frame);
},
rewriteCSP: onElectron
? (csp) => {
return csp.replace(/vscode-resource:(?=(\s|;|$))/g, 'vscode-webview-resource:');
......
......@@ -8,6 +8,7 @@ import { streamToBuffer } from 'vs/base/common/buffer';
import { IDisposable } from 'vs/base/common/lifecycle';
import { Schemas } from 'vs/base/common/network';
import { URI } from 'vs/base/common/uri';
import { IConfigurationService } from 'vs/platform/configuration/common/configuration';
import { IFileService } from 'vs/platform/files/common/files';
import { ILogService } from 'vs/platform/log/common/log';
import { INotificationService } from 'vs/platform/notification/common/notification';
......@@ -24,6 +25,7 @@ import { IWorkbenchEnvironmentService } from 'vs/workbench/services/environment/
export class IFrameWebview extends BaseWebview<HTMLIFrameElement> implements Webview {
private readonly _portMappingManager: WebviewPortMappingManager;
private _confirmBeforeClose: string;
constructor(
id: string,
......@@ -37,6 +39,7 @@ export class IFrameWebview extends BaseWebview<HTMLIFrameElement> implements Web
@IRequestService private readonly requestService: IRequestService,
@ITelemetryService telemetryService: ITelemetryService,
@IWorkbenchEnvironmentService environmentService: IWorkbenchEnvironmentService,
@IConfigurationService private readonly _configurationService: IConfigurationService,
@IRemoteAuthorityResolverService private readonly _remoteAuthorityResolverService: IRemoteAuthorityResolverService,
@ILogService logService: ILogService,
) {
......@@ -59,6 +62,15 @@ export class IFrameWebview extends BaseWebview<HTMLIFrameElement> implements Web
this.localLocalhost(entry.origin);
}));
this._confirmBeforeClose = this._configurationService.getValue<string>('window.confirmBeforeClose');
this._register(this._configurationService.onDidChangeConfiguration(e => {
if (e.affectsConfiguration('window.confirmBeforeClose')) {
this._confirmBeforeClose = this._configurationService.getValue('window.confirmBeforeClose');
this._send(WebviewMessageChannels.setConfirmBeforeClose, this._confirmBeforeClose);
}
}));
this.initElement(extension, options);
}
......@@ -75,8 +87,19 @@ export class IFrameWebview extends BaseWebview<HTMLIFrameElement> implements Web
}
protected initElement(extension: WebviewExtensionDescription | undefined, options: WebviewOptions) {
// The extensionId and purpose in the URL are used for filtering in js-debug:
this.element!.setAttribute('src', `${this.externalEndpoint}/index.html?id=${this.id}&extensionId=${extension?.id.value ?? ''}&purpose=${options.purpose}`);
const params = {
id: this.id,
// The extensionId and purpose in the URL are used for filtering in js-debug:
extensionId: extension?.id.value ?? '',
purpose: options.purpose,
} as const;
const queryString = (Object.keys(params) as Array<keyof typeof params>)
.map((key) => `${key}=${params[key]}`)
.join('&');
this.element!.setAttribute('src', `${this.externalEndpoint}/index.html?${queryString}`);
}
private get externalEndpoint(): string {
......@@ -116,6 +139,7 @@ export class IFrameWebview extends BaseWebview<HTMLIFrameElement> implements Web
protected get extraContentOptions(): any {
return {
endpoint: this.externalEndpoint,
confirmBeforeClose: this._confirmBeforeClose,
};
}
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册