refactor: implement <webview> using contextBridge (#29037)

* refactor: implement <webview> using contextBridge

* chore: address PR feedback

* chore: address PR feedback

* fix: check for HTMLIFrameElement instance in attachGuest
This commit is contained in:
Milan Burda 2021-05-15 09:42:07 +02:00 committed by GitHub
parent 5e6f8349ec
commit c68c65f383
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
17 changed files with 220 additions and 214 deletions

View file

@ -9,14 +9,13 @@
// modules must be passed from outside, all included files must be plain JS.
import { WEB_VIEW_CONSTANTS } from '@electron/internal/renderer/web-view/web-view-constants';
import type * as webViewImplModule from '@electron/internal/renderer/web-view/web-view-impl';
import { WebViewImpl, WebViewImplHooks, setupMethods } from '@electron/internal/renderer/web-view/web-view-impl';
import type { SrcAttribute } from '@electron/internal/renderer/web-view/web-view-attributes';
const internals = new WeakMap<HTMLElement, webViewImplModule.WebViewImpl>();
const internals = new WeakMap<HTMLElement, WebViewImpl>();
// Return a WebViewElement class that is defined in this context.
const defineWebViewElement = (webViewImpl: typeof webViewImplModule) => {
const { guestViewInternal, WebViewImpl } = webViewImpl;
const defineWebViewElement = (hooks: WebViewImplHooks) => {
return class WebViewElement extends HTMLElement {
static get observedAttributes () {
return [
@ -38,13 +37,7 @@ const defineWebViewElement = (webViewImpl: typeof webViewImplModule) => {
constructor () {
super();
const internal = new WebViewImpl(this);
internal.dispatchEventInMainWorld = (eventName, props) => {
const event = new Event(eventName);
Object.assign(event, props);
return internal.webviewNode.dispatchEvent(event);
};
internals.set(this, internal);
internals.set(this, new WebViewImpl(this, hooks));
}
getWebContentsId () {
@ -61,7 +54,10 @@ const defineWebViewElement = (webViewImpl: typeof webViewImplModule) => {
return;
}
if (!internal.elementAttached) {
guestViewInternal.registerEvents(internal, internal.viewInstanceId);
hooks.guestViewInternal.registerEvents(internal.viewInstanceId, {
dispatchEvent: internal.dispatchEvent.bind(internal),
reset: internal.reset.bind(internal)
});
internal.elementAttached = true;
(internal.attributes.get(WEB_VIEW_CONSTANTS.ATTRIBUTE_SRC) as SrcAttribute).parse();
}
@ -79,9 +75,9 @@ const defineWebViewElement = (webViewImpl: typeof webViewImplModule) => {
if (!internal) {
return;
}
guestViewInternal.deregisterEvents(internal.viewInstanceId);
hooks.guestViewInternal.deregisterEvents(internal.viewInstanceId);
if (internal.guestInstanceId) {
guestViewInternal.detachGuest(internal.guestInstanceId);
hooks.guestViewInternal.detachGuest(internal.guestInstanceId);
}
internal.elementAttached = false;
internal.reset();
@ -90,15 +86,15 @@ const defineWebViewElement = (webViewImpl: typeof webViewImplModule) => {
};
// Register <webview> custom element.
const registerWebViewElement = (webViewImpl: typeof webViewImplModule) => {
const registerWebViewElement = (hooks: WebViewImplHooks) => {
// I wish eslint wasn't so stupid, but it is
// eslint-disable-next-line
const WebViewElement = defineWebViewElement(webViewImpl) as unknown as typeof ElectronInternal.WebViewElement
const WebViewElement = defineWebViewElement(hooks) as unknown as typeof ElectronInternal.WebViewElement
webViewImpl.setupMethods(WebViewElement);
setupMethods(WebViewElement, hooks);
// The customElements.define has to be called in a special scope.
webViewImpl.webFrame.allowGuestViewElementDefinition(window, () => {
hooks.allowGuestViewElementDefinition(window, () => {
window.customElements.define('webview', WebViewElement);
window.WebView = WebViewElement;
@ -116,14 +112,14 @@ const registerWebViewElement = (webViewImpl: typeof webViewImplModule) => {
};
// Prepare to register the <webview> element.
export const setupWebView = (webViewImpl: typeof webViewImplModule) => {
export const setupWebView = (hooks: WebViewImplHooks) => {
const useCapture = true;
const listener = (event: Event) => {
if (document.readyState === 'loading') {
return;
}
registerWebViewElement(webViewImpl);
registerWebViewElement(hooks);
window.removeEventListener(event.type, listener, useCapture);
};