Use javascript modules for webview host script

This commit is contained in:
Matt Bierner 2021-04-09 16:43:15 -07:00
parent b4d42b1424
commit 62c62103fc
No known key found for this signature in database
GPG key ID: 099C331567E11888
4 changed files with 735 additions and 750 deletions

View file

@ -3,115 +3,112 @@
* Licensed under the MIT License. See License.txt in the project root for license information.
*--------------------------------------------------------------------------------------------*/
// @ts-check
(function () {
const id = document.location.search.match(/\bid=([\w-]+)/)[1];
const onElectron = /platform=electron/.test(document.location.search);
const hostMessaging = new class HostMessaging {
constructor() {
/** @type {Map<string, Array<(event: MessageEvent, data: any) => void>>} */
this.handlers = new Map();
import { createWebviewManager } from './main.js';
window.addEventListener('message', (e) => {
const channel = e.data.channel;
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);
const id = document.location.search.match(/\bid=([\w-]+)/)[1];
const onElectron = /platform=electron/.test(document.location.search);
const hostMessaging = new class HostMessaging {
constructor() {
/** @type {Map<string, Array<(event: MessageEvent, data: any) => void>>} */
this.handlers = new Map();
window.addEventListener('message', (e) => {
const channel = e.data.channel;
const handlers = this.handlers.get(channel);
if (handlers) {
for (const handler of handlers) {
handler(e, e.data.args);
}
});
}
/**
* @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) {
let handlers = this.handlers.get(channel);
if (!handlers) {
handlers = [];
this.handlers.set(channel, handlers);
} else {
console.log('no handler for ', e);
}
handlers.push(handler);
});
}
/**
* @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) {
let handlers = this.handlers.get(channel);
if (!handlers) {
handlers = [];
this.handlers.set(channel, handlers);
}
}();
handlers.push(handler);
}
}();
const unloadMonitor = new class {
const unloadMonitor = new class {
constructor() {
this.confirmBeforeClose = 'keyboardOnly';
this.isModifierKeyDown = false;
constructor() {
this.confirmBeforeClose = 'keyboardOnly';
this.isModifierKeyDown = false;
hostMessaging.onMessage('set-confirm-before-close', (_e, /** @type {string} */ data) => {
this.confirmBeforeClose = data;
});
hostMessaging.onMessage('set-confirm-before-close', (_e, /** @type {string} */ data) => {
this.confirmBeforeClose = data;
});
hostMessaging.onMessage('content', (_e, /** @type {any} */ data) => {
this.confirmBeforeClose = data.confirmBeforeClose;
});
hostMessaging.onMessage('content', (_e, /** @type {any} */ data) => {
this.confirmBeforeClose = data.confirmBeforeClose;
});
window.addEventListener('beforeunload', (event) => {
if (onElectron) {
return;
}
window.addEventListener('beforeunload', (event) => {
if (onElectron) {
return;
}
switch (this.confirmBeforeClose) {
case 'always':
{
event.preventDefault();
event.returnValue = '';
return '';
}
case 'never':
{
break;
}
case 'keyboardOnly':
default: {
if (this.isModifierKeyDown) {
event.preventDefault();
event.returnValue = '';
return '';
}
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(/** @type {HTMLIFrameElement} */frame) {
frame.contentWindow.addEventListener('keydown', e => {
this.isModifierKeyDown = e.metaKey || e.ctrlKey || e.altKey;
});
onIframeLoaded(/** @type {HTMLIFrameElement} */frame) {
frame.contentWindow.addEventListener('keydown', e => {
this.isModifierKeyDown = e.metaKey || e.ctrlKey || e.altKey;
});
frame.contentWindow.addEventListener('keyup', () => {
this.isModifierKeyDown = false;
});
}
};
frame.contentWindow.addEventListener('keyup', () => {
this.isModifierKeyDown = false;
});
}
};
/** @type {import('./main').WebviewHost} */
const host = {
postMessage: hostMessaging.postMessage.bind(hostMessaging),
onMessage: hostMessaging.onMessage.bind(hostMessaging),
onElectron: onElectron,
useParentPostMessage: false,
onIframeLoaded: (/** @type {HTMLIFrameElement} */ frame) => {
unloadMonitor.onIframeLoaded(frame);
}
};
(/** @type {any} */ (window)).createWebviewManager(host);
}());
createWebviewManager({
postMessage: hostMessaging.postMessage.bind(hostMessaging),
onMessage: hostMessaging.onMessage.bind(hostMessaging),
onElectron: onElectron,
useParentPostMessage: false,
onIframeLoaded: (frame) => {
unloadMonitor.onIframeLoaded(frame);
}
});

View file

@ -13,8 +13,7 @@
</head>
<body style="margin: 0; overflow: hidden; width: 100%; height: 100%" role="document">
<script src="main.js"></script>
<script src="host.js"></script>
<script type="module" src="host.js"></script>
</body>
</html>

File diff suppressed because it is too large Load diff

View file

@ -6,44 +6,43 @@
</head>
<body style="margin: 0; overflow: hidden; width: 100%; height: 100%" role="document">
<script src="main.js"></script>
<script>
(function () {
(/** @type {any} */ (window)).createWebviewManager({
...window.vscodeHost,
onIframeLoaded: (newFrame) => {
newFrame.contentWindow.onbeforeunload = () => {
if (window.vscodeHost.isInDevelopmentMode) { // Allow reloads while developing a webview
window.vscodeHost.postMessage('do-reload');
return false;
}
// Block navigation when not in development mode
console.log('prevented webview navigation');
<script type="module">
import { createWebviewManager } from './main.js';
createWebviewManager({
...window.vscodeHost,
onIframeLoaded: (newFrame) => {
newFrame.contentWindow.onbeforeunload = () => {
if (window.vscodeHost.isInDevelopmentMode) { // Allow reloads while developing a webview
window.vscodeHost.postMessage('do-reload');
return false;
};
}
// Block navigation when not in development mode
console.log('prevented webview navigation');
return false;
};
// Electron 4 eats mouseup events from inside webviews
// https://github.com/microsoft/vscode/issues/75090
// Try to fix this by rebroadcasting mouse moves and mouseups so that we can
// emulate these on the main window
let isMouseDown = false;
newFrame.contentWindow.addEventListener('mousedown', () => {
isMouseDown = true;
});
// Electron 4 eats mouseup events from inside webviews
// https://github.com/microsoft/vscode/issues/75090
// Try to fix this by rebroadcasting mouse moves and mouseups so that we can
// emulate these on the main window
let isMouseDown = false;
newFrame.contentWindow.addEventListener('mousedown', () => {
isMouseDown = true;
});
const tryDispatchSyntheticMouseEvent = (e) => {
if (!isMouseDown) {
window.vscodeHost.postMessage('synthetic-mouse-event', { type: e.type, screenX: e.screenX, screenY: e.screenY, clientX: e.clientX, clientY: e.clientY });
}
};
newFrame.contentWindow.addEventListener('mouseup', e => {
tryDispatchSyntheticMouseEvent(e);
isMouseDown = false;
});
newFrame.contentWindow.addEventListener('mousemove', tryDispatchSyntheticMouseEvent);
},
});
}());
const tryDispatchSyntheticMouseEvent = (e) => {
if (!isMouseDown) {
window.vscodeHost.postMessage('synthetic-mouse-event', { type: e.type, screenX: e.screenX, screenY: e.screenY, clientX: e.clientX, clientY: e.clientY });
}
};
newFrame.contentWindow.addEventListener('mouseup', e => {
tryDispatchSyntheticMouseEvent(e);
isMouseDown = false;
});
newFrame.contentWindow.addEventListener('mousemove', tryDispatchSyntheticMouseEvent);
},
});
</script>
</body>