fix: [webview] fix missing properties on events when contextIsolation: true (#26289)

This commit is contained in:
Jeremy Rose 2020-11-03 18:15:20 -08:00 committed by GitHub
parent c856b5fa53
commit 34156c424c
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
5 changed files with 51 additions and 24 deletions

View file

@ -1,4 +1,4 @@
import { webFrame, IpcMessageEvent } from 'electron'; import { webFrame } from 'electron';
import { ipcRendererInternal } from '@electron/internal/renderer/ipc-renderer-internal'; import { ipcRendererInternal } from '@electron/internal/renderer/ipc-renderer-internal';
import * as ipcRendererUtils from '@electron/internal/renderer/ipc-renderer-internal-utils'; import * as ipcRendererUtils from '@electron/internal/renderer/ipc-renderer-internal-utils';
import { webViewEvents } from '@electron/internal/common/web-view-events'; import { webViewEvents } from '@electron/internal/common/web-view-events';
@ -17,15 +17,15 @@ const dispatchEvent = function (
dispatchEvent(webView, DEPRECATED_EVENTS[eventName], eventKey, ...args); dispatchEvent(webView, DEPRECATED_EVENTS[eventName], eventKey, ...args);
} }
const domEvent = new Event(eventName) as ElectronInternal.WebViewEvent; const props: Record<string, any> = {};
webViewEvents[eventKey].forEach((prop, index) => { webViewEvents[eventKey].forEach((prop, index) => {
(domEvent as any)[prop] = args[index]; props[prop] = args[index];
}); });
webView.dispatchEvent(domEvent); webView.dispatchEvent(eventName, props);
if (eventName === 'load-commit') { if (eventName === 'load-commit') {
webView.onLoadCommit(domEvent); webView.onLoadCommit(props);
} else if (eventName === 'focus-change') { } else if (eventName === 'focus-change') {
webView.onFocusChange(); webView.onFocusChange();
} }
@ -35,8 +35,7 @@ export function registerEvents (webView: WebViewImpl, viewInstanceId: number) {
ipcRendererInternal.on(`${IPC_MESSAGES.GUEST_VIEW_INTERNAL_DESTROY_GUEST}-${viewInstanceId}`, function () { ipcRendererInternal.on(`${IPC_MESSAGES.GUEST_VIEW_INTERNAL_DESTROY_GUEST}-${viewInstanceId}`, function () {
webView.guestInstanceId = undefined; webView.guestInstanceId = undefined;
webView.reset(); webView.reset();
const domEvent = new Event('destroyed'); webView.dispatchEvent('destroyed');
webView.dispatchEvent(domEvent);
}); });
ipcRendererInternal.on(`${IPC_MESSAGES.GUEST_VIEW_INTERNAL_DISPATCH_EVENT}-${viewInstanceId}`, function (event, eventName, ...args) { ipcRendererInternal.on(`${IPC_MESSAGES.GUEST_VIEW_INTERNAL_DISPATCH_EVENT}-${viewInstanceId}`, function (event, eventName, ...args) {
@ -44,11 +43,7 @@ export function registerEvents (webView: WebViewImpl, viewInstanceId: number) {
}); });
ipcRendererInternal.on(`${IPC_MESSAGES.GUEST_VIEW_INTERNAL_IPC_MESSAGE}-${viewInstanceId}`, function (event, channel, ...args) { ipcRendererInternal.on(`${IPC_MESSAGES.GUEST_VIEW_INTERNAL_IPC_MESSAGE}-${viewInstanceId}`, function (event, channel, ...args) {
const domEvent = new Event('ipc-message') as IpcMessageEvent; webView.dispatchEvent('ipc-message', { channel, args });
domEvent.channel = channel;
domEvent.args = args;
webView.dispatchEvent(domEvent);
}); });
} }

View file

@ -39,7 +39,13 @@ const defineWebViewElement = (v8Util: NodeJS.V8UtilBinding, webViewImpl: typeof
constructor () { constructor () {
super(); super();
v8Util.setHiddenValue(this, 'internal', new WebViewImpl(this)); const internal = new WebViewImpl(this);
internal.dispatchEventInMainWorld = (eventName, props) => {
const event = new Event(eventName);
Object.assign(event, props);
return internal.webviewNode.dispatchEvent(event);
};
v8Util.setHiddenValue(this, 'internal', internal);
} }
connectedCallback () { connectedCallback () {

View file

@ -38,6 +38,8 @@ export class WebViewImpl {
public attributes = new Map<string, WebViewAttribute>(); public attributes = new Map<string, WebViewAttribute>();
public setupWebViewAttributes (): void {} public setupWebViewAttributes (): void {}
public dispatchEventInMainWorld?: (eventName: string, props: any) => boolean;
constructor (public webviewNode: HTMLElement) { constructor (public webviewNode: HTMLElement) {
// Create internal iframe element. // Create internal iframe element.
this.internalElement = this.createInternalElement(); this.internalElement = this.createInternalElement();
@ -106,10 +108,11 @@ export class WebViewImpl {
} }
onElementResize () { onElementResize () {
const resizeEvent = new Event('resize') as ElectronInternal.WebFrameResizeEvent; const props = {
resizeEvent.newWidth = this.webviewNode.clientWidth; newWidth: this.webviewNode.clientWidth,
resizeEvent.newHeight = this.webviewNode.clientHeight; newHeight: this.webviewNode.clientHeight
this.dispatchEvent(resizeEvent); };
this.dispatchEvent('resize', props);
} }
createGuest () { createGuest () {
@ -118,8 +121,8 @@ export class WebViewImpl {
}); });
} }
dispatchEvent (webViewEvent: Electron.Event) { dispatchEvent (eventName: string, props: Record<string, any> = {}) {
this.webviewNode.dispatchEvent(webViewEvent); this.dispatchEventInMainWorld!(eventName, props);
} }
// Adds an 'on<event>' property on the webview, which can be used to set/unset // Adds an 'on<event>' property on the webview, which can be used to set/unset
@ -144,10 +147,10 @@ export class WebViewImpl {
} }
// Updates state upon loadcommit. // Updates state upon loadcommit.
onLoadCommit (webViewEvent: ElectronInternal.WebViewEvent) { onLoadCommit (props: Record<string, any>) {
const oldValue = this.webviewNode.getAttribute(WEB_VIEW_CONSTANTS.ATTRIBUTE_SRC); const oldValue = this.webviewNode.getAttribute(WEB_VIEW_CONSTANTS.ATTRIBUTE_SRC);
const newValue = webViewEvent.url; const newValue = props.url;
if (webViewEvent.isMainFrame && (oldValue !== newValue)) { if (props.isMainFrame && (oldValue !== newValue)) {
// Touching the src attribute triggers a navigation. To avoid // Touching the src attribute triggers a navigation. To avoid
// triggering a page reload on every guest-initiated navigation, // triggering a page reload on every guest-initiated navigation,
// we do not handle this mutation. // we do not handle this mutation.
@ -160,7 +163,7 @@ export class WebViewImpl {
const hasFocus = document.activeElement === this.webviewNode; const hasFocus = document.activeElement === this.webviewNode;
if (hasFocus !== this.hasFocus) { if (hasFocus !== this.hasFocus) {
this.hasFocus = hasFocus; this.hasFocus = hasFocus;
this.dispatchEvent(new Event(hasFocus ? 'focus' : 'blur')); this.dispatchEvent(hasFocus ? 'focus' : 'blur');
} }
} }

View file

@ -650,4 +650,27 @@ describe('<webview> tag', function () {
generateSpecs('without sandbox', false); generateSpecs('without sandbox', false);
generateSpecs('with sandbox', true); generateSpecs('with sandbox', true);
}); });
describe('DOM events', () => {
afterEach(closeAllWindows);
it('receives extra properties on DOM events when contextIsolation is enabled', async () => {
const w = new BrowserWindow({
show: false,
webPreferences: {
webviewTag: true,
contextIsolation: true
}
});
await w.loadURL('about:blank');
const message = await w.webContents.executeJavaScript(`new Promise((resolve, reject) => {
const webview = new WebView()
webview.setAttribute('src', 'data:text/html,<script>console.log("hi")</script>')
webview.addEventListener('console-message', (e) => {
resolve(e.message)
})
document.body.appendChild(webview)
})`);
expect(message).to.equal('hi');
});
});
}); });

View file

@ -254,7 +254,7 @@ declare namespace ElectronInternal {
loader: ModuleLoader; loader: ModuleLoader;
} }
interface WebFrameResizeEvent extends Electron.Event { interface WebFrameResizeEvent extends WebViewEvent {
newWidth: number; newWidth: number;
newHeight: number; newHeight: number;
} }