refactor: Port renderer/web-view to TypeScript (#17250)
This commit is contained in:
parent
8c6bf9c848
commit
f3fc4023cf
13 changed files with 441 additions and 301 deletions
|
@ -73,12 +73,12 @@ filenames = {
|
||||||
"lib/renderer/security-warnings.ts",
|
"lib/renderer/security-warnings.ts",
|
||||||
"lib/renderer/window-setup.ts",
|
"lib/renderer/window-setup.ts",
|
||||||
"lib/renderer/web-frame-init.ts",
|
"lib/renderer/web-frame-init.ts",
|
||||||
"lib/renderer/web-view/guest-view-internal.js",
|
"lib/renderer/web-view/guest-view-internal.ts",
|
||||||
"lib/renderer/web-view/web-view-attributes.js",
|
"lib/renderer/web-view/web-view-attributes.ts",
|
||||||
"lib/renderer/web-view/web-view-constants.js",
|
"lib/renderer/web-view/web-view-constants.ts",
|
||||||
"lib/renderer/web-view/web-view-element.js",
|
"lib/renderer/web-view/web-view-element.ts",
|
||||||
"lib/renderer/web-view/web-view-impl.js",
|
"lib/renderer/web-view/web-view-impl.ts",
|
||||||
"lib/renderer/web-view/web-view-init.js",
|
"lib/renderer/web-view/web-view-init.ts",
|
||||||
"lib/renderer/api/exports/electron.js",
|
"lib/renderer/api/exports/electron.js",
|
||||||
"lib/renderer/api/crash-reporter.js",
|
"lib/renderer/api/crash-reporter.js",
|
||||||
"lib/renderer/api/ipc-renderer.js",
|
"lib/renderer/api/ipc-renderer.js",
|
||||||
|
|
|
@ -93,7 +93,8 @@ switch (window.location.protocol) {
|
||||||
|
|
||||||
// Load webview tag implementation.
|
// Load webview tag implementation.
|
||||||
if (process.isMainFrame) {
|
if (process.isMainFrame) {
|
||||||
require('@electron/internal/renderer/web-view/web-view-init')(contextIsolation, webviewTag, guestInstanceId)
|
const { webViewInit } = require('@electron/internal/renderer/web-view/web-view-init')
|
||||||
|
webViewInit(contextIsolation, webviewTag, guestInstanceId)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Pass the arguments to isolatedWorld.
|
// Pass the arguments to isolatedWorld.
|
||||||
|
|
|
@ -1,105 +0,0 @@
|
||||||
'use strict'
|
|
||||||
|
|
||||||
const { webFrame } = require('electron')
|
|
||||||
const { ipcRendererInternal } = require('@electron/internal/renderer/ipc-renderer-internal')
|
|
||||||
const ipcRendererUtils = require('@electron/internal/renderer/ipc-renderer-internal-utils')
|
|
||||||
|
|
||||||
const WEB_VIEW_EVENTS = {
|
|
||||||
'load-commit': ['url', 'isMainFrame'],
|
|
||||||
'did-attach': [],
|
|
||||||
'did-finish-load': [],
|
|
||||||
'did-fail-load': ['errorCode', 'errorDescription', 'validatedURL', 'isMainFrame', 'frameProcessId', 'frameRoutingId'],
|
|
||||||
'did-frame-finish-load': ['isMainFrame', 'frameProcessId', 'frameRoutingId'],
|
|
||||||
'did-start-loading': [],
|
|
||||||
'did-stop-loading': [],
|
|
||||||
'dom-ready': [],
|
|
||||||
'console-message': ['level', 'message', 'line', 'sourceId'],
|
|
||||||
'context-menu': ['params'],
|
|
||||||
'devtools-opened': [],
|
|
||||||
'devtools-closed': [],
|
|
||||||
'devtools-focused': [],
|
|
||||||
'new-window': ['url', 'frameName', 'disposition', 'options'],
|
|
||||||
'will-navigate': ['url'],
|
|
||||||
'did-start-navigation': ['url', 'isInPlace', 'isMainFrame', 'frameProcessId', 'frameRoutingId'],
|
|
||||||
'did-navigate': ['url', 'httpResponseCode', 'httpStatusText'],
|
|
||||||
'did-frame-navigate': ['url', 'httpResponseCode', 'httpStatusText', 'isMainFrame', 'frameProcessId', 'frameRoutingId'],
|
|
||||||
'did-navigate-in-page': ['url', 'isMainFrame', 'frameProcessId', 'frameRoutingId'],
|
|
||||||
'focus-change': ['focus', 'guestInstanceId'],
|
|
||||||
'close': [],
|
|
||||||
'crashed': [],
|
|
||||||
'gpu-crashed': [],
|
|
||||||
'plugin-crashed': ['name', 'version'],
|
|
||||||
'destroyed': [],
|
|
||||||
'page-title-updated': ['title', 'explicitSet'],
|
|
||||||
'page-favicon-updated': ['favicons'],
|
|
||||||
'enter-html-full-screen': [],
|
|
||||||
'leave-html-full-screen': [],
|
|
||||||
'media-started-playing': [],
|
|
||||||
'media-paused': [],
|
|
||||||
'found-in-page': ['result'],
|
|
||||||
'did-change-theme-color': ['themeColor'],
|
|
||||||
'update-target-url': ['url']
|
|
||||||
}
|
|
||||||
|
|
||||||
const DEPRECATED_EVENTS = {
|
|
||||||
'page-title-updated': 'page-title-set'
|
|
||||||
}
|
|
||||||
|
|
||||||
const dispatchEvent = function (webView, eventName, eventKey, ...args) {
|
|
||||||
if (DEPRECATED_EVENTS[eventName] != null) {
|
|
||||||
dispatchEvent(webView, DEPRECATED_EVENTS[eventName], eventKey, ...args)
|
|
||||||
}
|
|
||||||
const domEvent = new Event(eventName)
|
|
||||||
WEB_VIEW_EVENTS[eventKey].forEach((prop, index) => {
|
|
||||||
domEvent[prop] = args[index]
|
|
||||||
})
|
|
||||||
webView.dispatchEvent(domEvent)
|
|
||||||
if (eventName === 'load-commit') {
|
|
||||||
webView.onLoadCommit(domEvent)
|
|
||||||
} else if (eventName === 'focus-change') {
|
|
||||||
webView.onFocusChange(domEvent)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
module.exports = {
|
|
||||||
registerEvents: function (webView, viewInstanceId) {
|
|
||||||
ipcRendererInternal.on(`ELECTRON_GUEST_VIEW_INTERNAL_DESTROY_GUEST-${viewInstanceId}`, function () {
|
|
||||||
webView.guestInstanceId = undefined
|
|
||||||
webView.reset()
|
|
||||||
const domEvent = new Event('destroyed')
|
|
||||||
webView.dispatchEvent(domEvent)
|
|
||||||
})
|
|
||||||
|
|
||||||
ipcRendererInternal.on(`ELECTRON_GUEST_VIEW_INTERNAL_DISPATCH_EVENT-${viewInstanceId}`, function (event, eventName, ...args) {
|
|
||||||
dispatchEvent(webView, eventName, eventName, ...args)
|
|
||||||
})
|
|
||||||
|
|
||||||
ipcRendererInternal.on(`ELECTRON_GUEST_VIEW_INTERNAL_IPC_MESSAGE-${viewInstanceId}`, function (event, channel, ...args) {
|
|
||||||
const domEvent = new Event('ipc-message')
|
|
||||||
domEvent.channel = channel
|
|
||||||
domEvent.args = args
|
|
||||||
webView.dispatchEvent(domEvent)
|
|
||||||
})
|
|
||||||
},
|
|
||||||
deregisterEvents: function (viewInstanceId) {
|
|
||||||
ipcRendererInternal.removeAllListeners(`ELECTRON_GUEST_VIEW_INTERNAL_DESTROY_GUEST-${viewInstanceId}`)
|
|
||||||
ipcRendererInternal.removeAllListeners(`ELECTRON_GUEST_VIEW_INTERNAL_DISPATCH_EVENT-${viewInstanceId}`)
|
|
||||||
ipcRendererInternal.removeAllListeners(`ELECTRON_GUEST_VIEW_INTERNAL_IPC_MESSAGE-${viewInstanceId}`)
|
|
||||||
},
|
|
||||||
createGuest: function (params) {
|
|
||||||
return ipcRendererUtils.invoke('ELECTRON_GUEST_VIEW_MANAGER_CREATE_GUEST', params)
|
|
||||||
},
|
|
||||||
createGuestSync: function (params) {
|
|
||||||
return ipcRendererUtils.invokeSync('ELECTRON_GUEST_VIEW_MANAGER_CREATE_GUEST', params)
|
|
||||||
},
|
|
||||||
destroyGuest: function (guestInstanceId) {
|
|
||||||
ipcRendererUtils.invoke('ELECTRON_GUEST_VIEW_MANAGER_DESTROY_GUEST', guestInstanceId)
|
|
||||||
},
|
|
||||||
attachGuest: function (elementInstanceId, guestInstanceId, params, contentWindow) {
|
|
||||||
const embedderFrameId = webFrame.getWebFrameId(contentWindow)
|
|
||||||
if (embedderFrameId < 0) { // this error should not happen.
|
|
||||||
throw new Error('Invalid embedder frame')
|
|
||||||
}
|
|
||||||
ipcRendererUtils.invoke('ELECTRON_GUEST_VIEW_MANAGER_ATTACH_GUEST', embedderFrameId, elementInstanceId, guestInstanceId, params)
|
|
||||||
}
|
|
||||||
}
|
|
124
lib/renderer/web-view/guest-view-internal.ts
Normal file
124
lib/renderer/web-view/guest-view-internal.ts
Normal file
|
@ -0,0 +1,124 @@
|
||||||
|
import { webFrame, IpcMessageEvent } from 'electron'
|
||||||
|
import { ipcRendererInternal } from '@electron/internal/renderer/ipc-renderer-internal'
|
||||||
|
import { invoke, invokeSync } from '@electron/internal/renderer/ipc-renderer-internal-utils'
|
||||||
|
|
||||||
|
import { WebViewImpl } from '@electron/internal/renderer/web-view/web-view-impl'
|
||||||
|
|
||||||
|
const WEB_VIEW_EVENTS: Record<string, Array<string>> = {
|
||||||
|
'load-commit': ['url', 'isMainFrame'],
|
||||||
|
'did-attach': [],
|
||||||
|
'did-finish-load': [],
|
||||||
|
'did-fail-load': ['errorCode', 'errorDescription', 'validatedURL', 'isMainFrame', 'frameProcessId', 'frameRoutingId'],
|
||||||
|
'did-frame-finish-load': ['isMainFrame', 'frameProcessId', 'frameRoutingId'],
|
||||||
|
'did-start-loading': [],
|
||||||
|
'did-stop-loading': [],
|
||||||
|
'dom-ready': [],
|
||||||
|
'console-message': ['level', 'message', 'line', 'sourceId'],
|
||||||
|
'context-menu': ['params'],
|
||||||
|
'devtools-opened': [],
|
||||||
|
'devtools-closed': [],
|
||||||
|
'devtools-focused': [],
|
||||||
|
'new-window': ['url', 'frameName', 'disposition', 'options'],
|
||||||
|
'will-navigate': ['url'],
|
||||||
|
'did-start-navigation': ['url', 'isInPlace', 'isMainFrame', 'frameProcessId', 'frameRoutingId'],
|
||||||
|
'did-navigate': ['url', 'httpResponseCode', 'httpStatusText'],
|
||||||
|
'did-frame-navigate': ['url', 'httpResponseCode', 'httpStatusText', 'isMainFrame', 'frameProcessId', 'frameRoutingId'],
|
||||||
|
'did-navigate-in-page': ['url', 'isMainFrame', 'frameProcessId', 'frameRoutingId'],
|
||||||
|
'focus-change': ['focus', 'guestInstanceId'],
|
||||||
|
'close': [],
|
||||||
|
'crashed': [],
|
||||||
|
'gpu-crashed': [],
|
||||||
|
'plugin-crashed': ['name', 'version'],
|
||||||
|
'destroyed': [],
|
||||||
|
'page-title-updated': ['title', 'explicitSet'],
|
||||||
|
'page-favicon-updated': ['favicons'],
|
||||||
|
'enter-html-full-screen': [],
|
||||||
|
'leave-html-full-screen': [],
|
||||||
|
'media-started-playing': [],
|
||||||
|
'media-paused': [],
|
||||||
|
'found-in-page': ['result'],
|
||||||
|
'did-change-theme-color': ['themeColor'],
|
||||||
|
'update-target-url': ['url']
|
||||||
|
}
|
||||||
|
|
||||||
|
const DEPRECATED_EVENTS: Record<string, string> = {
|
||||||
|
'page-title-updated': 'page-title-set'
|
||||||
|
}
|
||||||
|
|
||||||
|
const dispatchEvent = function (
|
||||||
|
webView: WebViewImpl, eventName: string, eventKey: string, ...args: Array<any>
|
||||||
|
) {
|
||||||
|
if (DEPRECATED_EVENTS[eventName] != null) {
|
||||||
|
dispatchEvent(webView, DEPRECATED_EVENTS[eventName], eventKey, ...args)
|
||||||
|
}
|
||||||
|
|
||||||
|
const domEvent = new Event(eventName) as ElectronInternal.WebViewEvent
|
||||||
|
WEB_VIEW_EVENTS[eventKey].forEach((prop, index) => {
|
||||||
|
(domEvent as any)[prop] = args[index]
|
||||||
|
})
|
||||||
|
|
||||||
|
webView.dispatchEvent(domEvent)
|
||||||
|
|
||||||
|
if (eventName === 'load-commit') {
|
||||||
|
webView.onLoadCommit(domEvent)
|
||||||
|
} else if (eventName === 'focus-change') {
|
||||||
|
webView.onFocusChange()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
export function registerEvents (webView: WebViewImpl, viewInstanceId: number) {
|
||||||
|
ipcRendererInternal.on(`ELECTRON_GUEST_VIEW_INTERNAL_DESTROY_GUEST-${viewInstanceId}`, function () {
|
||||||
|
webView.guestInstanceId = undefined
|
||||||
|
webView.reset()
|
||||||
|
const domEvent = new Event('destroyed')
|
||||||
|
webView.dispatchEvent(domEvent)
|
||||||
|
})
|
||||||
|
|
||||||
|
ipcRendererInternal.on(`ELECTRON_GUEST_VIEW_INTERNAL_DISPATCH_EVENT-${viewInstanceId}`, function (event, eventName, ...args) {
|
||||||
|
dispatchEvent(webView, eventName, eventName, ...args)
|
||||||
|
})
|
||||||
|
|
||||||
|
ipcRendererInternal.on(`ELECTRON_GUEST_VIEW_INTERNAL_IPC_MESSAGE-${viewInstanceId}`, function (event, channel, ...args) {
|
||||||
|
const domEvent = new Event('ipc-message') as IpcMessageEvent
|
||||||
|
domEvent.channel = channel
|
||||||
|
domEvent.args = args
|
||||||
|
|
||||||
|
webView.dispatchEvent(domEvent)
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
export function deregisterEvents (viewInstanceId: number) {
|
||||||
|
ipcRendererInternal.removeAllListeners(`ELECTRON_GUEST_VIEW_INTERNAL_DESTROY_GUEST-${viewInstanceId}`)
|
||||||
|
ipcRendererInternal.removeAllListeners(`ELECTRON_GUEST_VIEW_INTERNAL_DISPATCH_EVENT-${viewInstanceId}`)
|
||||||
|
ipcRendererInternal.removeAllListeners(`ELECTRON_GUEST_VIEW_INTERNAL_IPC_MESSAGE-${viewInstanceId}`)
|
||||||
|
}
|
||||||
|
|
||||||
|
export function createGuest (params: Record<string, any>): Promise<number> {
|
||||||
|
return invoke('ELECTRON_GUEST_VIEW_MANAGER_CREATE_GUEST', params)
|
||||||
|
}
|
||||||
|
|
||||||
|
export function createGuestSync (params: Record<string, any>): number {
|
||||||
|
return invokeSync('ELECTRON_GUEST_VIEW_MANAGER_CREATE_GUEST', params)
|
||||||
|
}
|
||||||
|
|
||||||
|
export function destroyGuest (guestInstanceId: number): void {
|
||||||
|
invoke('ELECTRON_GUEST_VIEW_MANAGER_DESTROY_GUEST', guestInstanceId)
|
||||||
|
}
|
||||||
|
|
||||||
|
export function attachGuest (
|
||||||
|
elementInstanceId: number, guestInstanceId: number, params: Record<string, any>, contentWindow: Window
|
||||||
|
) {
|
||||||
|
const embedderFrameId = (webFrame as ElectronInternal.WebFrameInternal).getWebFrameId(contentWindow)
|
||||||
|
if (embedderFrameId < 0) { // this error should not happen.
|
||||||
|
throw new Error('Invalid embedder frame')
|
||||||
|
}
|
||||||
|
invoke('ELECTRON_GUEST_VIEW_MANAGER_ATTACH_GUEST', embedderFrameId, elementInstanceId, guestInstanceId, params)
|
||||||
|
}
|
||||||
|
|
||||||
|
export const guestViewInternalModule = {
|
||||||
|
deregisterEvents,
|
||||||
|
createGuest,
|
||||||
|
createGuestSync,
|
||||||
|
destroyGuest,
|
||||||
|
attachGuest
|
||||||
|
}
|
|
@ -1,14 +1,12 @@
|
||||||
'use strict'
|
import * as ipcRendererUtils from '@electron/internal/renderer/ipc-renderer-internal-utils'
|
||||||
|
import { WebViewImpl } from '@electron/internal/renderer/web-view/web-view-impl'
|
||||||
const ipcRendererUtils = require('@electron/internal/renderer/ipc-renderer-internal-utils')
|
import { WEB_VIEW_CONSTANTS } from '@electron/internal/renderer/web-view/web-view-constants'
|
||||||
const { WebViewImpl } = require('@electron/internal/renderer/web-view/web-view-impl')
|
|
||||||
const webViewConstants = require('@electron/internal/renderer/web-view/web-view-constants')
|
|
||||||
|
|
||||||
// Helper function to resolve url set in attribute.
|
// Helper function to resolve url set in attribute.
|
||||||
const a = document.createElement('a')
|
const a = document.createElement('a')
|
||||||
|
|
||||||
const resolveURL = function (url) {
|
const resolveURL = function (url?: string | null) {
|
||||||
if (url === '') return ''
|
if (!url) return ''
|
||||||
a.href = url
|
a.href = url
|
||||||
return a.href
|
return a.href
|
||||||
}
|
}
|
||||||
|
@ -16,33 +14,35 @@ const resolveURL = function (url) {
|
||||||
// Attribute objects.
|
// Attribute objects.
|
||||||
// Default implementation of a WebView attribute.
|
// Default implementation of a WebView attribute.
|
||||||
class WebViewAttribute {
|
class WebViewAttribute {
|
||||||
constructor (name, webViewImpl) {
|
public value: any;
|
||||||
|
public ignoreMutation = false;
|
||||||
|
|
||||||
|
constructor (public name: string, public webViewImpl: WebViewImpl) {
|
||||||
this.name = name
|
this.name = name
|
||||||
this.value = webViewImpl.webviewNode[name] || ''
|
this.value = (webViewImpl.webviewNode as Record<string, any>)[name] || ''
|
||||||
this.webViewImpl = webViewImpl
|
this.webViewImpl = webViewImpl
|
||||||
this.ignoreMutation = false
|
|
||||||
this.defineProperty()
|
this.defineProperty()
|
||||||
}
|
}
|
||||||
|
|
||||||
// Retrieves and returns the attribute's value.
|
// Retrieves and returns the attribute's value.
|
||||||
getValue () {
|
public getValue () {
|
||||||
return this.webViewImpl.webviewNode.getAttribute(this.name) || this.value
|
return this.webViewImpl.webviewNode.getAttribute(this.name) || this.value
|
||||||
}
|
}
|
||||||
|
|
||||||
// Sets the attribute's value.
|
// Sets the attribute's value.
|
||||||
setValue (value) {
|
public setValue (value: any) {
|
||||||
this.webViewImpl.webviewNode.setAttribute(this.name, value || '')
|
this.webViewImpl.webviewNode.setAttribute(this.name, value || '')
|
||||||
}
|
}
|
||||||
|
|
||||||
// Changes the attribute's value without triggering its mutation handler.
|
// Changes the attribute's value without triggering its mutation handler.
|
||||||
setValueIgnoreMutation (value) {
|
public setValueIgnoreMutation (value: any) {
|
||||||
this.ignoreMutation = true
|
this.ignoreMutation = true
|
||||||
this.setValue(value)
|
this.setValue(value)
|
||||||
this.ignoreMutation = false
|
this.ignoreMutation = false
|
||||||
}
|
}
|
||||||
|
|
||||||
// Defines this attribute as a property on the webview node.
|
// Defines this attribute as a property on the webview node.
|
||||||
defineProperty () {
|
public defineProperty () {
|
||||||
return Object.defineProperty(this.webViewImpl.webviewNode, this.name, {
|
return Object.defineProperty(this.webViewImpl.webviewNode, this.name, {
|
||||||
get: () => {
|
get: () => {
|
||||||
return this.getValue()
|
return this.getValue()
|
||||||
|
@ -55,7 +55,7 @@ class WebViewAttribute {
|
||||||
}
|
}
|
||||||
|
|
||||||
// Called when the attribute's value changes.
|
// Called when the attribute's value changes.
|
||||||
handleMutation () {}
|
public handleMutation (..._args: Array<any>): any {}
|
||||||
}
|
}
|
||||||
|
|
||||||
// An attribute that is treated as a Boolean.
|
// An attribute that is treated as a Boolean.
|
||||||
|
@ -64,7 +64,7 @@ class BooleanAttribute extends WebViewAttribute {
|
||||||
return this.webViewImpl.webviewNode.hasAttribute(this.name)
|
return this.webViewImpl.webviewNode.hasAttribute(this.name)
|
||||||
}
|
}
|
||||||
|
|
||||||
setValue (value) {
|
setValue (value: boolean) {
|
||||||
if (value) {
|
if (value) {
|
||||||
this.webViewImpl.webviewNode.setAttribute(this.name, '')
|
this.webViewImpl.webviewNode.setAttribute(this.name, '')
|
||||||
} else {
|
} else {
|
||||||
|
@ -75,35 +75,38 @@ class BooleanAttribute extends WebViewAttribute {
|
||||||
|
|
||||||
// Attribute representing the state of the storage partition.
|
// Attribute representing the state of the storage partition.
|
||||||
class PartitionAttribute extends WebViewAttribute {
|
class PartitionAttribute extends WebViewAttribute {
|
||||||
constructor (webViewImpl) {
|
public validPartitionId = true
|
||||||
super(webViewConstants.ATTRIBUTE_PARTITION, webViewImpl)
|
|
||||||
this.validPartitionId = true
|
constructor (public webViewImpl: WebViewImpl) {
|
||||||
|
super(WEB_VIEW_CONSTANTS.ATTRIBUTE_PARTITION, webViewImpl)
|
||||||
}
|
}
|
||||||
|
|
||||||
handleMutation (oldValue, newValue) {
|
public handleMutation (oldValue: any, newValue: any) {
|
||||||
newValue = newValue || ''
|
newValue = newValue || ''
|
||||||
|
|
||||||
// The partition cannot change if the webview has already navigated.
|
// The partition cannot change if the webview has already navigated.
|
||||||
if (!this.webViewImpl.beforeFirstNavigation) {
|
if (!this.webViewImpl.beforeFirstNavigation) {
|
||||||
console.error(webViewConstants.ERROR_MSG_ALREADY_NAVIGATED)
|
console.error(WEB_VIEW_CONSTANTS.ERROR_MSG_ALREADY_NAVIGATED)
|
||||||
this.setValueIgnoreMutation(oldValue)
|
this.setValueIgnoreMutation(oldValue)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
if (newValue === 'persist:') {
|
if (newValue === 'persist:') {
|
||||||
this.validPartitionId = false
|
this.validPartitionId = false
|
||||||
console.error(webViewConstants.ERROR_MSG_INVALID_PARTITION_ATTRIBUTE)
|
console.error(WEB_VIEW_CONSTANTS.ERROR_MSG_INVALID_PARTITION_ATTRIBUTE)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Attribute that handles the location and navigation of the webview.
|
// Attribute that handles the location and navigation of the webview.
|
||||||
class SrcAttribute extends WebViewAttribute {
|
class SrcAttribute extends WebViewAttribute {
|
||||||
constructor (webViewImpl) {
|
public observer!: MutationObserver;
|
||||||
super(webViewConstants.ATTRIBUTE_SRC, webViewImpl)
|
|
||||||
|
constructor (public webViewImpl: WebViewImpl) {
|
||||||
|
super(WEB_VIEW_CONSTANTS.ATTRIBUTE_SRC, webViewImpl)
|
||||||
this.setupMutationObserver()
|
this.setupMutationObserver()
|
||||||
}
|
}
|
||||||
|
|
||||||
getValue () {
|
public getValue () {
|
||||||
if (this.webViewImpl.webviewNode.hasAttribute(this.name)) {
|
if (this.webViewImpl.webviewNode.hasAttribute(this.name)) {
|
||||||
return resolveURL(this.webViewImpl.webviewNode.getAttribute(this.name))
|
return resolveURL(this.webViewImpl.webviewNode.getAttribute(this.name))
|
||||||
} else {
|
} else {
|
||||||
|
@ -111,7 +114,7 @@ class SrcAttribute extends WebViewAttribute {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
setValueIgnoreMutation (value) {
|
public setValueIgnoreMutation (value: any) {
|
||||||
super.setValueIgnoreMutation(value)
|
super.setValueIgnoreMutation(value)
|
||||||
|
|
||||||
// takeRecords() is needed to clear queued up src mutations. Without it, it
|
// takeRecords() is needed to clear queued up src mutations. Without it, it
|
||||||
|
@ -121,7 +124,7 @@ class SrcAttribute extends WebViewAttribute {
|
||||||
this.observer.takeRecords()
|
this.observer.takeRecords()
|
||||||
}
|
}
|
||||||
|
|
||||||
handleMutation (oldValue, newValue) {
|
public handleMutation (oldValue: any, newValue: any) {
|
||||||
// Once we have navigated, we don't allow clearing the src attribute.
|
// Once we have navigated, we don't allow clearing the src attribute.
|
||||||
// Once <webview> enters a navigated state, it cannot return to a
|
// Once <webview> enters a navigated state, it cannot return to a
|
||||||
// placeholder state.
|
// placeholder state.
|
||||||
|
@ -139,7 +142,7 @@ class SrcAttribute extends WebViewAttribute {
|
||||||
// attribute without any changes to its value. This is useful in the case
|
// attribute without any changes to its value. This is useful in the case
|
||||||
// where the webview guest has crashed and navigating to the same address
|
// where the webview guest has crashed and navigating to the same address
|
||||||
// spawns off a new process.
|
// spawns off a new process.
|
||||||
setupMutationObserver () {
|
public setupMutationObserver () {
|
||||||
this.observer = new MutationObserver((mutations) => {
|
this.observer = new MutationObserver((mutations) => {
|
||||||
for (const mutation of mutations) {
|
for (const mutation of mutations) {
|
||||||
const { oldValue } = mutation
|
const { oldValue } = mutation
|
||||||
|
@ -150,16 +153,18 @@ class SrcAttribute extends WebViewAttribute {
|
||||||
this.handleMutation(oldValue, newValue)
|
this.handleMutation(oldValue, newValue)
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
|
|
||||||
const params = {
|
const params = {
|
||||||
attributes: true,
|
attributes: true,
|
||||||
attributeOldValue: true,
|
attributeOldValue: true,
|
||||||
attributeFilter: [this.name]
|
attributeFilter: [this.name]
|
||||||
}
|
}
|
||||||
|
|
||||||
this.observer.observe(this.webViewImpl.webviewNode, params)
|
this.observer.observe(this.webViewImpl.webviewNode, params)
|
||||||
}
|
}
|
||||||
|
|
||||||
parse () {
|
public parse () {
|
||||||
if (!this.webViewImpl.elementAttached || !this.webViewImpl.attributes[webViewConstants.ATTRIBUTE_PARTITION].validPartitionId || !this.getValue()) {
|
if (!this.webViewImpl.elementAttached || !this.webViewImpl.attributes[WEB_VIEW_CONSTANTS.ATTRIBUTE_PARTITION].validPartitionId || !this.getValue()) {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
if (this.webViewImpl.guestInstanceId == null) {
|
if (this.webViewImpl.guestInstanceId == null) {
|
||||||
|
@ -171,12 +176,14 @@ class SrcAttribute extends WebViewAttribute {
|
||||||
}
|
}
|
||||||
|
|
||||||
// Navigate to |this.src|.
|
// Navigate to |this.src|.
|
||||||
const opts = {}
|
const opts: Record<string, string> = {}
|
||||||
const httpreferrer = this.webViewImpl.attributes[webViewConstants.ATTRIBUTE_HTTPREFERRER].getValue()
|
|
||||||
|
const httpreferrer = this.webViewImpl.attributes[WEB_VIEW_CONSTANTS.ATTRIBUTE_HTTPREFERRER].getValue()
|
||||||
if (httpreferrer) {
|
if (httpreferrer) {
|
||||||
opts.httpReferrer = httpreferrer
|
opts.httpReferrer = httpreferrer
|
||||||
}
|
}
|
||||||
const useragent = this.webViewImpl.attributes[webViewConstants.ATTRIBUTE_USERAGENT].getValue()
|
|
||||||
|
const useragent = this.webViewImpl.attributes[WEB_VIEW_CONSTANTS.ATTRIBUTE_USERAGENT].getValue()
|
||||||
if (useragent) {
|
if (useragent) {
|
||||||
opts.userAgent = useragent
|
opts.userAgent = useragent
|
||||||
}
|
}
|
||||||
|
@ -191,69 +198,72 @@ class SrcAttribute extends WebViewAttribute {
|
||||||
|
|
||||||
// Attribute specifies HTTP referrer.
|
// Attribute specifies HTTP referrer.
|
||||||
class HttpReferrerAttribute extends WebViewAttribute {
|
class HttpReferrerAttribute extends WebViewAttribute {
|
||||||
constructor (webViewImpl) {
|
constructor (webViewImpl: WebViewImpl) {
|
||||||
super(webViewConstants.ATTRIBUTE_HTTPREFERRER, webViewImpl)
|
super(WEB_VIEW_CONSTANTS.ATTRIBUTE_HTTPREFERRER, webViewImpl)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Attribute specifies user agent
|
// Attribute specifies user agent
|
||||||
class UserAgentAttribute extends WebViewAttribute {
|
class UserAgentAttribute extends WebViewAttribute {
|
||||||
constructor (webViewImpl) {
|
constructor (webViewImpl: WebViewImpl) {
|
||||||
super(webViewConstants.ATTRIBUTE_USERAGENT, webViewImpl)
|
super(WEB_VIEW_CONSTANTS.ATTRIBUTE_USERAGENT, webViewImpl)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Attribute that set preload script.
|
// Attribute that set preload script.
|
||||||
class PreloadAttribute extends WebViewAttribute {
|
class PreloadAttribute extends WebViewAttribute {
|
||||||
constructor (webViewImpl) {
|
constructor (webViewImpl: WebViewImpl) {
|
||||||
super(webViewConstants.ATTRIBUTE_PRELOAD, webViewImpl)
|
super(WEB_VIEW_CONSTANTS.ATTRIBUTE_PRELOAD, webViewImpl)
|
||||||
}
|
}
|
||||||
|
|
||||||
getValue () {
|
public getValue () {
|
||||||
if (!this.webViewImpl.webviewNode.hasAttribute(this.name)) {
|
if (!this.webViewImpl.webviewNode.hasAttribute(this.name)) {
|
||||||
return this.value
|
return this.value
|
||||||
}
|
}
|
||||||
|
|
||||||
let preload = resolveURL(this.webViewImpl.webviewNode.getAttribute(this.name))
|
let preload = resolveURL(this.webViewImpl.webviewNode.getAttribute(this.name))
|
||||||
const protocol = preload.substr(0, 5)
|
const protocol = preload.substr(0, 5)
|
||||||
|
|
||||||
if (protocol !== 'file:') {
|
if (protocol !== 'file:') {
|
||||||
console.error(webViewConstants.ERROR_MSG_INVALID_PRELOAD_ATTRIBUTE)
|
console.error(WEB_VIEW_CONSTANTS.ERROR_MSG_INVALID_PRELOAD_ATTRIBUTE)
|
||||||
preload = ''
|
preload = ''
|
||||||
}
|
}
|
||||||
|
|
||||||
return preload
|
return preload
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Attribute that specifies the blink features to be enabled.
|
// Attribute that specifies the blink features to be enabled.
|
||||||
class BlinkFeaturesAttribute extends WebViewAttribute {
|
class BlinkFeaturesAttribute extends WebViewAttribute {
|
||||||
constructor (webViewImpl) {
|
constructor (webViewImpl: WebViewImpl) {
|
||||||
super(webViewConstants.ATTRIBUTE_BLINKFEATURES, webViewImpl)
|
super(WEB_VIEW_CONSTANTS.ATTRIBUTE_BLINKFEATURES, webViewImpl)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Attribute that specifies the blink features to be disabled.
|
// Attribute that specifies the blink features to be disabled.
|
||||||
class DisableBlinkFeaturesAttribute extends WebViewAttribute {
|
class DisableBlinkFeaturesAttribute extends WebViewAttribute {
|
||||||
constructor (webViewImpl) {
|
constructor (webViewImpl: WebViewImpl) {
|
||||||
super(webViewConstants.ATTRIBUTE_DISABLEBLINKFEATURES, webViewImpl)
|
super(WEB_VIEW_CONSTANTS.ATTRIBUTE_DISABLEBLINKFEATURES, webViewImpl)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Attribute that specifies the web preferences to be enabled.
|
// Attribute that specifies the web preferences to be enabled.
|
||||||
class WebPreferencesAttribute extends WebViewAttribute {
|
class WebPreferencesAttribute extends WebViewAttribute {
|
||||||
constructor (webViewImpl) {
|
constructor (webViewImpl: WebViewImpl) {
|
||||||
super(webViewConstants.ATTRIBUTE_WEBPREFERENCES, webViewImpl)
|
super(WEB_VIEW_CONSTANTS.ATTRIBUTE_WEBPREFERENCES, webViewImpl)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
class EnableRemoteModuleAttribute extends WebViewAttribute {
|
class EnableRemoteModuleAttribute extends WebViewAttribute {
|
||||||
constructor (webViewImpl) {
|
constructor (webViewImpl: WebViewImpl) {
|
||||||
super(webViewConstants.ATTRIBUTE_ENABLEREMOTEMODULE, webViewImpl)
|
super(WEB_VIEW_CONSTANTS.ATTRIBUTE_ENABLEREMOTEMODULE, webViewImpl)
|
||||||
}
|
}
|
||||||
|
|
||||||
getValue () {
|
public getValue () {
|
||||||
return this.webViewImpl.webviewNode.getAttribute(this.name) !== 'false'
|
return this.webViewImpl.webviewNode.getAttribute(this.name) !== 'false'
|
||||||
}
|
}
|
||||||
|
|
||||||
setValue (value) {
|
public setValue (value: any) {
|
||||||
this.webViewImpl.webviewNode.setAttribute(this.name, value ? 'true' : 'false')
|
this.webViewImpl.webviewNode.setAttribute(this.name, value ? 'true' : 'false')
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -261,17 +271,17 @@ class EnableRemoteModuleAttribute extends WebViewAttribute {
|
||||||
// Sets up all of the webview attributes.
|
// Sets up all of the webview attributes.
|
||||||
WebViewImpl.prototype.setupWebViewAttributes = function () {
|
WebViewImpl.prototype.setupWebViewAttributes = function () {
|
||||||
this.attributes = {}
|
this.attributes = {}
|
||||||
this.attributes[webViewConstants.ATTRIBUTE_PARTITION] = new PartitionAttribute(this)
|
this.attributes[WEB_VIEW_CONSTANTS.ATTRIBUTE_PARTITION] = new PartitionAttribute(this)
|
||||||
this.attributes[webViewConstants.ATTRIBUTE_SRC] = new SrcAttribute(this)
|
this.attributes[WEB_VIEW_CONSTANTS.ATTRIBUTE_SRC] = new SrcAttribute(this)
|
||||||
this.attributes[webViewConstants.ATTRIBUTE_HTTPREFERRER] = new HttpReferrerAttribute(this)
|
this.attributes[WEB_VIEW_CONSTANTS.ATTRIBUTE_HTTPREFERRER] = new HttpReferrerAttribute(this)
|
||||||
this.attributes[webViewConstants.ATTRIBUTE_USERAGENT] = new UserAgentAttribute(this)
|
this.attributes[WEB_VIEW_CONSTANTS.ATTRIBUTE_USERAGENT] = new UserAgentAttribute(this)
|
||||||
this.attributes[webViewConstants.ATTRIBUTE_NODEINTEGRATION] = new BooleanAttribute(webViewConstants.ATTRIBUTE_NODEINTEGRATION, this)
|
this.attributes[WEB_VIEW_CONSTANTS.ATTRIBUTE_NODEINTEGRATION] = new BooleanAttribute(WEB_VIEW_CONSTANTS.ATTRIBUTE_NODEINTEGRATION, this)
|
||||||
this.attributes[webViewConstants.ATTRIBUTE_PLUGINS] = new BooleanAttribute(webViewConstants.ATTRIBUTE_PLUGINS, this)
|
this.attributes[WEB_VIEW_CONSTANTS.ATTRIBUTE_PLUGINS] = new BooleanAttribute(WEB_VIEW_CONSTANTS.ATTRIBUTE_PLUGINS, this)
|
||||||
this.attributes[webViewConstants.ATTRIBUTE_DISABLEWEBSECURITY] = new BooleanAttribute(webViewConstants.ATTRIBUTE_DISABLEWEBSECURITY, this)
|
this.attributes[WEB_VIEW_CONSTANTS.ATTRIBUTE_DISABLEWEBSECURITY] = new BooleanAttribute(WEB_VIEW_CONSTANTS.ATTRIBUTE_DISABLEWEBSECURITY, this)
|
||||||
this.attributes[webViewConstants.ATTRIBUTE_ALLOWPOPUPS] = new BooleanAttribute(webViewConstants.ATTRIBUTE_ALLOWPOPUPS, this)
|
this.attributes[WEB_VIEW_CONSTANTS.ATTRIBUTE_ALLOWPOPUPS] = new BooleanAttribute(WEB_VIEW_CONSTANTS.ATTRIBUTE_ALLOWPOPUPS, this)
|
||||||
this.attributes[webViewConstants.ATTRIBUTE_ENABLEREMOTEMODULE] = new EnableRemoteModuleAttribute(this)
|
this.attributes[WEB_VIEW_CONSTANTS.ATTRIBUTE_ENABLEREMOTEMODULE] = new EnableRemoteModuleAttribute(this)
|
||||||
this.attributes[webViewConstants.ATTRIBUTE_PRELOAD] = new PreloadAttribute(this)
|
this.attributes[WEB_VIEW_CONSTANTS.ATTRIBUTE_PRELOAD] = new PreloadAttribute(this)
|
||||||
this.attributes[webViewConstants.ATTRIBUTE_BLINKFEATURES] = new BlinkFeaturesAttribute(this)
|
this.attributes[WEB_VIEW_CONSTANTS.ATTRIBUTE_BLINKFEATURES] = new BlinkFeaturesAttribute(this)
|
||||||
this.attributes[webViewConstants.ATTRIBUTE_DISABLEBLINKFEATURES] = new DisableBlinkFeaturesAttribute(this)
|
this.attributes[WEB_VIEW_CONSTANTS.ATTRIBUTE_DISABLEBLINKFEATURES] = new DisableBlinkFeaturesAttribute(this)
|
||||||
this.attributes[webViewConstants.ATTRIBUTE_WEBPREFERENCES] = new WebPreferencesAttribute(this)
|
this.attributes[WEB_VIEW_CONSTANTS.ATTRIBUTE_WEBPREFERENCES] = new WebPreferencesAttribute(this)
|
||||||
}
|
}
|
|
@ -1,28 +0,0 @@
|
||||||
'use strict'
|
|
||||||
|
|
||||||
module.exports = {
|
|
||||||
// Attributes.
|
|
||||||
ATTRIBUTE_NAME: 'name',
|
|
||||||
ATTRIBUTE_PARTITION: 'partition',
|
|
||||||
ATTRIBUTE_SRC: 'src',
|
|
||||||
ATTRIBUTE_HTTPREFERRER: 'httpreferrer',
|
|
||||||
ATTRIBUTE_NODEINTEGRATION: 'nodeintegration',
|
|
||||||
ATTRIBUTE_ENABLEREMOTEMODULE: 'enableremotemodule',
|
|
||||||
ATTRIBUTE_PLUGINS: 'plugins',
|
|
||||||
ATTRIBUTE_DISABLEWEBSECURITY: 'disablewebsecurity',
|
|
||||||
ATTRIBUTE_ALLOWPOPUPS: 'allowpopups',
|
|
||||||
ATTRIBUTE_PRELOAD: 'preload',
|
|
||||||
ATTRIBUTE_USERAGENT: 'useragent',
|
|
||||||
ATTRIBUTE_BLINKFEATURES: 'blinkfeatures',
|
|
||||||
ATTRIBUTE_DISABLEBLINKFEATURES: 'disableblinkfeatures',
|
|
||||||
ATTRIBUTE_WEBPREFERENCES: 'webpreferences',
|
|
||||||
|
|
||||||
// Internal attribute.
|
|
||||||
ATTRIBUTE_INTERNALINSTANCEID: 'internalinstanceid',
|
|
||||||
|
|
||||||
// Error messages.
|
|
||||||
ERROR_MSG_ALREADY_NAVIGATED: 'The object has already navigated, so its partition cannot be changed.',
|
|
||||||
ERROR_MSG_CANNOT_INJECT_SCRIPT: '<webview>: ' + 'Script cannot be injected into content until the page has loaded.',
|
|
||||||
ERROR_MSG_INVALID_PARTITION_ATTRIBUTE: 'Invalid partition attribute.',
|
|
||||||
ERROR_MSG_INVALID_PRELOAD_ATTRIBUTE: 'Only "file:" protocol is supported in "preload" attribute.'
|
|
||||||
}
|
|
26
lib/renderer/web-view/web-view-constants.ts
Normal file
26
lib/renderer/web-view/web-view-constants.ts
Normal file
|
@ -0,0 +1,26 @@
|
||||||
|
export const enum WEB_VIEW_CONSTANTS {
|
||||||
|
// Attributes.
|
||||||
|
ATTRIBUTE_NAME = 'name',
|
||||||
|
ATTRIBUTE_PARTITION = 'partition',
|
||||||
|
ATTRIBUTE_SRC = 'src',
|
||||||
|
ATTRIBUTE_HTTPREFERRER = 'httpreferrer',
|
||||||
|
ATTRIBUTE_NODEINTEGRATION = 'nodeintegration',
|
||||||
|
ATTRIBUTE_ENABLEREMOTEMODULE = 'enableremotemodule',
|
||||||
|
ATTRIBUTE_PLUGINS = 'plugins',
|
||||||
|
ATTRIBUTE_DISABLEWEBSECURITY = 'disablewebsecurity',
|
||||||
|
ATTRIBUTE_ALLOWPOPUPS = 'allowpopups',
|
||||||
|
ATTRIBUTE_PRELOAD = 'preload',
|
||||||
|
ATTRIBUTE_USERAGENT = 'useragent',
|
||||||
|
ATTRIBUTE_BLINKFEATURES = 'blinkfeatures',
|
||||||
|
ATTRIBUTE_DISABLEBLINKFEATURES = 'disableblinkfeatures',
|
||||||
|
ATTRIBUTE_WEBPREFERENCES = 'webpreferences',
|
||||||
|
|
||||||
|
// Internal attribute.
|
||||||
|
ATTRIBUTE_INTERNALINSTANCEID = 'internalinstanceid',
|
||||||
|
|
||||||
|
// Error messages.
|
||||||
|
ERROR_MSG_ALREADY_NAVIGATED = 'The object has already navigated, so its partition cannot be changed.',
|
||||||
|
ERROR_MSG_CANNOT_INJECT_SCRIPT = '<webview> = ' + 'Script cannot be injected into content until the page has loaded.',
|
||||||
|
ERROR_MSG_INVALID_PARTITION_ATTRIBUTE = 'Invalid partition attribute.',
|
||||||
|
ERROR_MSG_INVALID_PRELOAD_ATTRIBUTE = 'Only "file:" protocol is supported in "preload" attribute.'
|
||||||
|
}
|
|
@ -1,5 +1,3 @@
|
||||||
'use strict'
|
|
||||||
|
|
||||||
// When using context isolation, the WebViewElement and the custom element
|
// When using context isolation, the WebViewElement and the custom element
|
||||||
// methods have to be defined in the main world to be able to be registered.
|
// methods have to be defined in the main world to be able to be registered.
|
||||||
//
|
//
|
||||||
|
@ -10,27 +8,30 @@
|
||||||
// which runs in browserify environment instead of Node environment, all native
|
// which runs in browserify environment instead of Node environment, all native
|
||||||
// modules must be passed from outside, all included files must be plain JS.
|
// modules must be passed from outside, all included files must be plain JS.
|
||||||
|
|
||||||
const webViewConstants = require('@electron/internal/renderer/web-view/web-view-constants')
|
import { WEB_VIEW_CONSTANTS } from '@electron/internal/renderer/web-view/web-view-constants'
|
||||||
|
import { WebViewImpl, webViewImplModule } from '@electron/internal/renderer/web-view/web-view-impl'
|
||||||
|
|
||||||
// Return a WebViewElement class that is defined in this context.
|
// Return a WebViewElement class that is defined in this context.
|
||||||
const defineWebViewElement = (v8Util, webViewImpl) => {
|
const defineWebViewElement = (v8Util: NodeJS.V8UtilBinding, webViewImpl: typeof webViewImplModule) => {
|
||||||
const { guestViewInternal, WebViewImpl } = webViewImpl
|
const { guestViewInternal, WebViewImpl } = webViewImpl
|
||||||
return class WebViewElement extends HTMLElement {
|
return class WebViewElement extends HTMLElement {
|
||||||
|
public internalInstanceId?: number;
|
||||||
|
|
||||||
static get observedAttributes () {
|
static get observedAttributes () {
|
||||||
return [
|
return [
|
||||||
webViewConstants.ATTRIBUTE_PARTITION,
|
WEB_VIEW_CONSTANTS.ATTRIBUTE_PARTITION,
|
||||||
webViewConstants.ATTRIBUTE_SRC,
|
WEB_VIEW_CONSTANTS.ATTRIBUTE_SRC,
|
||||||
webViewConstants.ATTRIBUTE_HTTPREFERRER,
|
WEB_VIEW_CONSTANTS.ATTRIBUTE_HTTPREFERRER,
|
||||||
webViewConstants.ATTRIBUTE_USERAGENT,
|
WEB_VIEW_CONSTANTS.ATTRIBUTE_USERAGENT,
|
||||||
webViewConstants.ATTRIBUTE_NODEINTEGRATION,
|
WEB_VIEW_CONSTANTS.ATTRIBUTE_NODEINTEGRATION,
|
||||||
webViewConstants.ATTRIBUTE_PLUGINS,
|
WEB_VIEW_CONSTANTS.ATTRIBUTE_PLUGINS,
|
||||||
webViewConstants.ATTRIBUTE_DISABLEWEBSECURITY,
|
WEB_VIEW_CONSTANTS.ATTRIBUTE_DISABLEWEBSECURITY,
|
||||||
webViewConstants.ATTRIBUTE_ALLOWPOPUPS,
|
WEB_VIEW_CONSTANTS.ATTRIBUTE_ALLOWPOPUPS,
|
||||||
webViewConstants.ATTRIBUTE_ENABLEREMOTEMODULE,
|
WEB_VIEW_CONSTANTS.ATTRIBUTE_ENABLEREMOTEMODULE,
|
||||||
webViewConstants.ATTRIBUTE_PRELOAD,
|
WEB_VIEW_CONSTANTS.ATTRIBUTE_PRELOAD,
|
||||||
webViewConstants.ATTRIBUTE_BLINKFEATURES,
|
WEB_VIEW_CONSTANTS.ATTRIBUTE_BLINKFEATURES,
|
||||||
webViewConstants.ATTRIBUTE_DISABLEBLINKFEATURES,
|
WEB_VIEW_CONSTANTS.ATTRIBUTE_DISABLEBLINKFEATURES,
|
||||||
webViewConstants.ATTRIBUTE_WEBPREFERENCES
|
WEB_VIEW_CONSTANTS.ATTRIBUTE_WEBPREFERENCES
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -40,26 +41,26 @@ const defineWebViewElement = (v8Util, webViewImpl) => {
|
||||||
}
|
}
|
||||||
|
|
||||||
connectedCallback () {
|
connectedCallback () {
|
||||||
const internal = v8Util.getHiddenValue(this, 'internal')
|
const internal = v8Util.getHiddenValue<WebViewImpl>(this, 'internal')
|
||||||
if (!internal) {
|
if (!internal) {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
if (!internal.elementAttached) {
|
if (!internal.elementAttached) {
|
||||||
guestViewInternal.registerEvents(internal, internal.viewInstanceId)
|
guestViewInternal.registerEvents(internal, internal.viewInstanceId)
|
||||||
internal.elementAttached = true
|
internal.elementAttached = true
|
||||||
internal.attributes[webViewConstants.ATTRIBUTE_SRC].parse()
|
internal.attributes[WEB_VIEW_CONSTANTS.ATTRIBUTE_SRC].parse()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
attributeChangedCallback (name, oldValue, newValue) {
|
attributeChangedCallback (name: string, oldValue: any, newValue: any) {
|
||||||
const internal = v8Util.getHiddenValue(this, 'internal')
|
const internal = v8Util.getHiddenValue<WebViewImpl>(this, 'internal')
|
||||||
if (internal) {
|
if (internal) {
|
||||||
internal.handleWebviewAttributeMutation(name, oldValue, newValue)
|
internal.handleWebviewAttributeMutation(name, oldValue, newValue)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
disconnectedCallback () {
|
disconnectedCallback () {
|
||||||
const internal = v8Util.getHiddenValue(this, 'internal')
|
const internal = v8Util.getHiddenValue<WebViewImpl>(this, 'internal')
|
||||||
if (!internal) {
|
if (!internal) {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
@ -72,15 +73,18 @@ const defineWebViewElement = (v8Util, webViewImpl) => {
|
||||||
}
|
}
|
||||||
|
|
||||||
// Register <webview> custom element.
|
// Register <webview> custom element.
|
||||||
const registerWebViewElement = (v8Util, webViewImpl) => {
|
const registerWebViewElement = (v8Util: NodeJS.V8UtilBinding, webViewImpl: typeof webViewImplModule) => {
|
||||||
const WebViewElement = defineWebViewElement(v8Util, webViewImpl)
|
// I wish eslint wasn't so stupid, but it is
|
||||||
|
// eslint-disable-next-line
|
||||||
|
const WebViewElement = defineWebViewElement(v8Util, webViewImpl) as unknown as typeof ElectronInternal.WebViewElement
|
||||||
|
|
||||||
webViewImpl.setupMethods(WebViewElement)
|
webViewImpl.setupMethods(WebViewElement)
|
||||||
|
|
||||||
// The customElements.define has to be called in a special scope.
|
// The customElements.define has to be called in a special scope.
|
||||||
webViewImpl.webFrame.allowGuestViewElementDefinition(window, () => {
|
const webFrame = webViewImpl.webFrame as ElectronInternal.WebFrameInternal
|
||||||
window.customElements.define('webview', WebViewElement)
|
webFrame.allowGuestViewElementDefinition(window, () => {
|
||||||
window.WebView = WebViewElement
|
window.customElements.define('webview', WebViewElement);
|
||||||
|
(window as any).WebView = WebViewElement
|
||||||
|
|
||||||
// Delete the callbacks so developers cannot call them and produce unexpected
|
// Delete the callbacks so developers cannot call them and produce unexpected
|
||||||
// behavior.
|
// behavior.
|
||||||
|
@ -90,21 +94,24 @@ const registerWebViewElement = (v8Util, webViewImpl) => {
|
||||||
|
|
||||||
// Now that |observedAttributes| has been retrieved, we can hide it from
|
// Now that |observedAttributes| has been retrieved, we can hide it from
|
||||||
// user code as well.
|
// user code as well.
|
||||||
delete WebViewElement.observedAttributes
|
// TypeScript is concerned that we're deleting a read-only attribute
|
||||||
|
delete (WebViewElement as any).observedAttributes
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
// Prepare to register the <webview> element.
|
// Prepare to register the <webview> element.
|
||||||
const setupWebView = (v8Util, webViewImpl) => {
|
export const setupWebView = (v8Util: NodeJS.V8UtilBinding, webViewImpl: typeof webViewImplModule) => {
|
||||||
const useCapture = true
|
const useCapture = true
|
||||||
window.addEventListener('readystatechange', function listener (event) {
|
const listener = (event: Event) => {
|
||||||
if (document.readyState === 'loading') {
|
if (document.readyState === 'loading') {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
webViewImpl.setupAttributes()
|
webViewImpl.setupAttributes()
|
||||||
registerWebViewElement(v8Util, webViewImpl)
|
registerWebViewElement(v8Util, webViewImpl)
|
||||||
window.removeEventListener(event.type, listener, useCapture)
|
|
||||||
}, useCapture)
|
|
||||||
}
|
|
||||||
|
|
||||||
module.exports = { setupWebView }
|
window.removeEventListener(event.type, listener, useCapture)
|
||||||
|
}
|
||||||
|
|
||||||
|
window.addEventListener('readystatechange', listener, useCapture)
|
||||||
|
}
|
|
@ -1,16 +1,15 @@
|
||||||
'use strict'
|
import { deprecate, webFrame } from 'electron'
|
||||||
|
|
||||||
const { webFrame, deprecate } = require('electron')
|
import * as ipcRendererUtils from '@electron/internal/renderer/ipc-renderer-internal-utils'
|
||||||
|
import * as guestViewInternal from '@electron/internal/renderer/web-view/guest-view-internal'
|
||||||
const v8Util = process.atomBinding('v8_util')
|
import { WEB_VIEW_CONSTANTS } from '@electron/internal/renderer/web-view/web-view-constants'
|
||||||
const ipcRendererUtils = require('@electron/internal/renderer/ipc-renderer-internal-utils')
|
import {
|
||||||
const guestViewInternal = require('@electron/internal/renderer/web-view/guest-view-internal')
|
|
||||||
const webViewConstants = require('@electron/internal/renderer/web-view/web-view-constants')
|
|
||||||
const {
|
|
||||||
syncMethods,
|
syncMethods,
|
||||||
asyncCallbackMethods,
|
asyncCallbackMethods,
|
||||||
asyncPromiseMethods
|
asyncPromiseMethods
|
||||||
} = require('@electron/internal/common/web-view-methods')
|
} from '@electron/internal/common/web-view-methods'
|
||||||
|
|
||||||
|
const v8Util = process.atomBinding('v8_util')
|
||||||
|
|
||||||
// ID generator.
|
// ID generator.
|
||||||
let nextId = 0
|
let nextId = 0
|
||||||
|
@ -20,16 +19,25 @@ const getNextId = function () {
|
||||||
}
|
}
|
||||||
|
|
||||||
// Represents the internal state of the WebView node.
|
// Represents the internal state of the WebView node.
|
||||||
class WebViewImpl {
|
export class WebViewImpl {
|
||||||
constructor (webviewNode) {
|
public beforeFirstNavigation = true
|
||||||
this.webviewNode = webviewNode
|
public elementAttached = false
|
||||||
this.elementAttached = false
|
public guestInstanceId?: number
|
||||||
this.beforeFirstNavigation = true
|
public hasFocus = false
|
||||||
this.hasFocus = false
|
public internalInstanceId?: number;
|
||||||
|
public resizeObserver?: ResizeObserver;
|
||||||
|
public userAgentOverride?: string;
|
||||||
|
public viewInstanceId: number
|
||||||
|
|
||||||
// on* Event handlers.
|
// on* Event handlers.
|
||||||
this.on = {}
|
public on: Record<string, any> = {}
|
||||||
|
public internalElement: HTMLIFrameElement
|
||||||
|
|
||||||
|
// Replaced in web-view-attributes
|
||||||
|
public attributes: Record<string, any> = {}
|
||||||
|
public setupWebViewAttributes (): void {}
|
||||||
|
|
||||||
|
constructor (public webviewNode: HTMLElement) {
|
||||||
// Create internal iframe element.
|
// Create internal iframe element.
|
||||||
this.internalElement = this.createInternalElement()
|
this.internalElement = this.createInternalElement()
|
||||||
const shadowRoot = this.webviewNode.attachShadow({ mode: 'open' })
|
const shadowRoot = this.webviewNode.attachShadow({ mode: 'open' })
|
||||||
|
@ -70,22 +78,17 @@ class WebViewImpl {
|
||||||
}
|
}
|
||||||
|
|
||||||
this.beforeFirstNavigation = true
|
this.beforeFirstNavigation = true
|
||||||
this.attributes[webViewConstants.ATTRIBUTE_PARTITION].validPartitionId = true
|
this.attributes[WEB_VIEW_CONSTANTS.ATTRIBUTE_PARTITION].validPartitionId = true
|
||||||
|
|
||||||
// Since attachment swaps a local frame for a remote frame, we need our
|
// Since attachment swaps a local frame for a remote frame, we need our
|
||||||
// internal iframe element to be local again before we can reattach.
|
// internal iframe element to be local again before we can reattach.
|
||||||
const newFrame = this.createInternalElement()
|
const newFrame = this.createInternalElement()
|
||||||
const oldFrame = this.internalElement
|
const oldFrame = this.internalElement
|
||||||
this.internalElement = newFrame
|
this.internalElement = newFrame
|
||||||
oldFrame.parentNode.replaceChild(newFrame, oldFrame)
|
|
||||||
}
|
|
||||||
|
|
||||||
// Sets the <webview>.request property.
|
if (oldFrame && oldFrame.parentNode) {
|
||||||
setRequestPropertyOnWebViewNode (request) {
|
oldFrame.parentNode.replaceChild(newFrame, oldFrame)
|
||||||
Object.defineProperty(this.webviewNode, 'request', {
|
}
|
||||||
value: request,
|
|
||||||
enumerable: true
|
|
||||||
})
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// This observer monitors mutations to attributes of the <webview> and
|
// This observer monitors mutations to attributes of the <webview> and
|
||||||
|
@ -93,7 +96,7 @@ class WebViewImpl {
|
||||||
// a BrowserPlugin property will update the corresponding BrowserPlugin
|
// a BrowserPlugin property will update the corresponding BrowserPlugin
|
||||||
// attribute, if necessary. See BrowserPlugin::UpdateDOMAttribute for more
|
// attribute, if necessary. See BrowserPlugin::UpdateDOMAttribute for more
|
||||||
// details.
|
// details.
|
||||||
handleWebviewAttributeMutation (attributeName, oldValue, newValue) {
|
handleWebviewAttributeMutation (attributeName: string, oldValue: any, newValue: any) {
|
||||||
if (!this.attributes[attributeName] || this.attributes[attributeName].ignoreMutation) {
|
if (!this.attributes[attributeName] || this.attributes[attributeName].ignoreMutation) {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
@ -103,7 +106,7 @@ class WebViewImpl {
|
||||||
}
|
}
|
||||||
|
|
||||||
onElementResize () {
|
onElementResize () {
|
||||||
const resizeEvent = new Event('resize')
|
const resizeEvent = new Event('resize') as ElectronInternal.WebFrameResizeEvent
|
||||||
resizeEvent.newWidth = this.webviewNode.clientWidth
|
resizeEvent.newWidth = this.webviewNode.clientWidth
|
||||||
resizeEvent.newHeight = this.webviewNode.clientHeight
|
resizeEvent.newHeight = this.webviewNode.clientHeight
|
||||||
this.dispatchEvent(resizeEvent)
|
this.dispatchEvent(resizeEvent)
|
||||||
|
@ -120,13 +123,13 @@ class WebViewImpl {
|
||||||
this.attachGuestInstance(guestViewInternal.createGuestSync(this.buildParams()))
|
this.attachGuestInstance(guestViewInternal.createGuestSync(this.buildParams()))
|
||||||
}
|
}
|
||||||
|
|
||||||
dispatchEvent (webViewEvent) {
|
dispatchEvent (webViewEvent: Electron.Event) {
|
||||||
this.webviewNode.dispatchEvent(webViewEvent)
|
this.webviewNode.dispatchEvent(webViewEvent)
|
||||||
}
|
}
|
||||||
|
|
||||||
// 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
|
||||||
// an event handler.
|
// an event handler.
|
||||||
setupEventProperty (eventName) {
|
setupEventProperty (eventName: string) {
|
||||||
const propertyName = `on${eventName.toLowerCase()}`
|
const propertyName = `on${eventName.toLowerCase()}`
|
||||||
return Object.defineProperty(this.webviewNode, propertyName, {
|
return Object.defineProperty(this.webviewNode, propertyName, {
|
||||||
get: () => {
|
get: () => {
|
||||||
|
@ -146,14 +149,14 @@ class WebViewImpl {
|
||||||
}
|
}
|
||||||
|
|
||||||
// Updates state upon loadcommit.
|
// Updates state upon loadcommit.
|
||||||
onLoadCommit (webViewEvent) {
|
onLoadCommit (webViewEvent: ElectronInternal.WebViewEvent) {
|
||||||
const oldValue = this.webviewNode.getAttribute(webViewConstants.ATTRIBUTE_SRC)
|
const oldValue = this.webviewNode.getAttribute(WEB_VIEW_CONSTANTS.ATTRIBUTE_SRC)
|
||||||
const newValue = webViewEvent.url
|
const newValue = webViewEvent.url
|
||||||
if (webViewEvent.isMainFrame && (oldValue !== newValue)) {
|
if (webViewEvent.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.
|
||||||
this.attributes[webViewConstants.ATTRIBUTE_SRC].setValueIgnoreMutation(newValue)
|
this.attributes[WEB_VIEW_CONSTANTS.ATTRIBUTE_SRC].setValueIgnoreMutation(newValue)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -166,52 +169,66 @@ class WebViewImpl {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
onAttach (storagePartitionId) {
|
onAttach (storagePartitionId: number) {
|
||||||
return this.attributes[webViewConstants.ATTRIBUTE_PARTITION].setValue(storagePartitionId)
|
return this.attributes[WEB_VIEW_CONSTANTS.ATTRIBUTE_PARTITION].setValue(storagePartitionId)
|
||||||
}
|
}
|
||||||
|
|
||||||
buildParams () {
|
buildParams () {
|
||||||
const params = {
|
const params: Record<string, any> = {
|
||||||
instanceId: this.viewInstanceId,
|
instanceId: this.viewInstanceId,
|
||||||
userAgentOverride: this.userAgentOverride
|
userAgentOverride: this.userAgentOverride
|
||||||
}
|
}
|
||||||
|
|
||||||
for (const attributeName in this.attributes) {
|
for (const attributeName in this.attributes) {
|
||||||
if (this.attributes.hasOwnProperty(attributeName)) {
|
if (this.attributes.hasOwnProperty(attributeName)) {
|
||||||
params[attributeName] = this.attributes[attributeName].getValue()
|
params[attributeName] = this.attributes[attributeName].getValue()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return params
|
return params
|
||||||
}
|
}
|
||||||
|
|
||||||
attachGuestInstance (guestInstanceId) {
|
attachGuestInstance (guestInstanceId: number) {
|
||||||
if (!this.elementAttached) {
|
if (!this.elementAttached) {
|
||||||
// The element could be detached before we got response from browser.
|
// The element could be detached before we got response from browser.
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
this.internalInstanceId = getNextId()
|
this.internalInstanceId = getNextId()
|
||||||
this.guestInstanceId = guestInstanceId
|
this.guestInstanceId = guestInstanceId
|
||||||
guestViewInternal.attachGuest(this.internalInstanceId, this.guestInstanceId, this.buildParams(), this.internalElement.contentWindow)
|
|
||||||
|
guestViewInternal.attachGuest(
|
||||||
|
this.internalInstanceId,
|
||||||
|
this.guestInstanceId,
|
||||||
|
this.buildParams(),
|
||||||
|
this.internalElement.contentWindow!
|
||||||
|
)
|
||||||
|
|
||||||
// ResizeObserver is a browser global not recognized by "standard".
|
// ResizeObserver is a browser global not recognized by "standard".
|
||||||
/* globals ResizeObserver */
|
/* globals ResizeObserver */
|
||||||
// TODO(zcbenz): Should we deprecate the "resize" event? Wait, it is not
|
// TODO(zcbenz): Should we deprecate the "resize" event? Wait, it is not
|
||||||
// even documented.
|
// even documented.
|
||||||
this.resizeObserver = new ResizeObserver(this.onElementResize.bind(this)).observe(this.internalElement)
|
this.resizeObserver = new ResizeObserver(this.onElementResize.bind(this))
|
||||||
|
this.resizeObserver.observe(this.internalElement)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
const setupAttributes = () => {
|
export const setupAttributes = () => {
|
||||||
require('@electron/internal/renderer/web-view/web-view-attributes')
|
require('@electron/internal/renderer/web-view/web-view-attributes')
|
||||||
}
|
}
|
||||||
|
|
||||||
const setupMethods = (WebViewElement) => {
|
// I wish eslint wasn't so stupid, but it is
|
||||||
|
// eslint-disable-next-line
|
||||||
|
export const setupMethods = (WebViewElement: typeof ElectronInternal.WebViewElement) => {
|
||||||
// WebContents associated with this webview.
|
// WebContents associated with this webview.
|
||||||
WebViewElement.prototype.getWebContents = function () {
|
WebViewElement.prototype.getWebContents = function () {
|
||||||
const { getRemote } = require('@electron/internal/renderer/remote')
|
const { getRemote } = require('@electron/internal/renderer/remote')
|
||||||
const getGuestWebContents = getRemote('getGuestWebContents')
|
const getGuestWebContents = getRemote('getGuestWebContents')
|
||||||
const internal = v8Util.getHiddenValue(this, 'internal')
|
const internal = v8Util.getHiddenValue<WebViewImpl>(this, 'internal')
|
||||||
|
|
||||||
if (!internal.guestInstanceId) {
|
if (!internal.guestInstanceId) {
|
||||||
internal.createGuestSync()
|
internal.createGuestSync()
|
||||||
}
|
}
|
||||||
|
|
||||||
return getGuestWebContents(internal.guestInstanceId)
|
return getGuestWebContents(internal.guestInstanceId)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -220,8 +237,8 @@ const setupMethods = (WebViewElement) => {
|
||||||
this.contentWindow.focus()
|
this.contentWindow.focus()
|
||||||
}
|
}
|
||||||
|
|
||||||
const getGuestInstanceId = function (self) {
|
const getGuestInstanceId = function (self: any) {
|
||||||
const internal = v8Util.getHiddenValue(self, 'internal')
|
const internal = v8Util.getHiddenValue<WebViewImpl>(self, 'internal')
|
||||||
if (!internal.guestInstanceId) {
|
if (!internal.guestInstanceId) {
|
||||||
throw new Error('The WebView must be attached to the DOM and the dom-ready event emitted before this method can be called.')
|
throw new Error('The WebView must be attached to the DOM and the dom-ready event emitted before this method can be called.')
|
||||||
}
|
}
|
||||||
|
@ -229,34 +246,41 @@ const setupMethods = (WebViewElement) => {
|
||||||
}
|
}
|
||||||
|
|
||||||
// Forward proto.foo* method calls to WebViewImpl.foo*.
|
// Forward proto.foo* method calls to WebViewImpl.foo*.
|
||||||
const createBlockHandler = function (method) {
|
const createBlockHandler = function (method: string) {
|
||||||
return function (...args) {
|
return function (this: any, ...args: Array<any>) {
|
||||||
return ipcRendererUtils.invokeSync('ELECTRON_GUEST_VIEW_MANAGER_CALL', getGuestInstanceId(this), method, args)
|
return ipcRendererUtils.invokeSync('ELECTRON_GUEST_VIEW_MANAGER_CALL', getGuestInstanceId(this), method, args)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
for (const method of syncMethods) {
|
for (const method of syncMethods) {
|
||||||
WebViewElement.prototype[method] = createBlockHandler(method)
|
(WebViewElement.prototype as Record<string, any>)[method] = createBlockHandler(method)
|
||||||
}
|
}
|
||||||
|
|
||||||
const createNonBlockHandler = function (method) {
|
const createNonBlockHandler = function (method: string) {
|
||||||
return function (...args) {
|
return function (this: any, ...args: Array<any>) {
|
||||||
ipcRendererUtils.invoke('ELECTRON_GUEST_VIEW_MANAGER_CALL', getGuestInstanceId(this), method, args)
|
ipcRendererUtils.invoke('ELECTRON_GUEST_VIEW_MANAGER_CALL', getGuestInstanceId(this), method, args)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
for (const method of asyncCallbackMethods) {
|
for (const method of asyncCallbackMethods) {
|
||||||
WebViewElement.prototype[method] = createNonBlockHandler(method)
|
(WebViewElement.prototype as Record<string, any>)[method] = createNonBlockHandler(method)
|
||||||
}
|
}
|
||||||
|
|
||||||
const createPromiseHandler = function (method) {
|
const createPromiseHandler = function (method: string) {
|
||||||
return function (...args) {
|
return function (this: any, ...args: Array<any>) {
|
||||||
return ipcRendererUtils.invoke('ELECTRON_GUEST_VIEW_MANAGER_CALL', getGuestInstanceId(this), method, args)
|
return ipcRendererUtils.invoke('ELECTRON_GUEST_VIEW_MANAGER_CALL', getGuestInstanceId(this), method, args)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
for (const method of asyncPromiseMethods) {
|
for (const method of asyncPromiseMethods) {
|
||||||
WebViewElement.prototype[method] = deprecate.promisify(createPromiseHandler(method))
|
(WebViewElement.prototype as Record<string, any>)[method] = deprecate.promisify(createPromiseHandler(method))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
module.exports = { setupAttributes, setupMethods, guestViewInternal, webFrame, WebViewImpl }
|
export const webViewImplModule = {
|
||||||
|
setupAttributes,
|
||||||
|
setupMethods,
|
||||||
|
guestViewInternal,
|
||||||
|
webFrame,
|
||||||
|
WebViewImpl
|
||||||
|
}
|
|
@ -1,9 +1,8 @@
|
||||||
'use strict'
|
import { ipcRendererInternal } from '@electron/internal/renderer/ipc-renderer-internal'
|
||||||
|
|
||||||
const { ipcRendererInternal } = require('@electron/internal/renderer/ipc-renderer-internal')
|
|
||||||
const v8Util = process.atomBinding('v8_util')
|
const v8Util = process.atomBinding('v8_util')
|
||||||
|
|
||||||
function handleFocusBlur (guestInstanceId) {
|
function handleFocusBlur (guestInstanceId: number) {
|
||||||
// Note that while Chromium content APIs have observer for focus/blur, they
|
// Note that while Chromium content APIs have observer for focus/blur, they
|
||||||
// unfortunately do not work for webview.
|
// unfortunately do not work for webview.
|
||||||
|
|
||||||
|
@ -16,15 +15,17 @@ function handleFocusBlur (guestInstanceId) {
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
module.exports = function (contextIsolation, webviewTag, guestInstanceId) {
|
export function webViewInit (
|
||||||
|
contextIsolation: boolean, webviewTag: ElectronInternal.WebViewElement, guestInstanceId: number
|
||||||
|
) {
|
||||||
// Don't allow recursive `<webview>`.
|
// Don't allow recursive `<webview>`.
|
||||||
if (webviewTag && guestInstanceId == null) {
|
if (webviewTag && guestInstanceId == null) {
|
||||||
const webViewImpl = require('@electron/internal/renderer/web-view/web-view-impl')
|
const { webViewImplModule } = require('@electron/internal/renderer/web-view/web-view-impl')
|
||||||
if (contextIsolation) {
|
if (contextIsolation) {
|
||||||
v8Util.setHiddenValue(window, 'web-view-impl', webViewImpl)
|
v8Util.setHiddenValue(window, 'web-view-impl', webViewImplModule)
|
||||||
} else {
|
} else {
|
||||||
const { setupWebView } = require('@electron/internal/renderer/web-view/web-view-element')
|
const { setupWebView } = require('@electron/internal/renderer/web-view/web-view-element')
|
||||||
setupWebView(v8Util, webViewImpl)
|
setupWebView(v8Util, webViewImplModule)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -116,7 +116,8 @@ const guestInstanceId = binding.guestInstanceId && parseInt(binding.guestInstanc
|
||||||
|
|
||||||
// Load webview tag implementation.
|
// Load webview tag implementation.
|
||||||
if (process.isMainFrame) {
|
if (process.isMainFrame) {
|
||||||
require('@electron/internal/renderer/web-view/web-view-init')(contextIsolation, isWebViewTagEnabled, guestInstanceId)
|
const { webViewInit } = require('@electron/internal/renderer/web-view/web-view-init')
|
||||||
|
webViewInit(contextIsolation, isWebViewTagEnabled, guestInstanceId)
|
||||||
}
|
}
|
||||||
|
|
||||||
const errorUtils = require('@electron/internal/common/error-utils')
|
const errorUtils = require('@electron/internal/common/error-utils')
|
||||||
|
|
53
typings/internal-ambient.d.ts
vendored
53
typings/internal-ambient.d.ts
vendored
|
@ -62,5 +62,56 @@ declare interface Window {
|
||||||
FileSystemWorkspaceBinding: {
|
FileSystemWorkspaceBinding: {
|
||||||
completeURL: (project: string, path: string) => string;
|
completeURL: (project: string, path: string) => string;
|
||||||
}
|
}
|
||||||
}
|
};
|
||||||
|
ResizeObserver: ResizeObserver;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The ResizeObserver interface is used to observe changes to Element's content
|
||||||
|
* rect.
|
||||||
|
*
|
||||||
|
* It is modeled after MutationObserver and IntersectionObserver.
|
||||||
|
*/
|
||||||
|
declare class ResizeObserver {
|
||||||
|
constructor (callback: ResizeObserverCallback);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Adds target to the list of observed elements.
|
||||||
|
*/
|
||||||
|
observe: (target: Element) => void;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Removes target from the list of observed elements.
|
||||||
|
*/
|
||||||
|
unobserve: (target: Element) => void;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Clears both the observationTargets and activeTargets lists.
|
||||||
|
*/
|
||||||
|
disconnect: () => void;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* This callback delivers ResizeObserver's notifications. It is invoked by a
|
||||||
|
* broadcast active observations algorithm.
|
||||||
|
*/
|
||||||
|
interface ResizeObserverCallback {
|
||||||
|
(entries: ResizeObserverEntry[], observer: ResizeObserver): void;
|
||||||
|
}
|
||||||
|
|
||||||
|
interface ResizeObserverEntry {
|
||||||
|
/**
|
||||||
|
* @param target The Element whose size has changed.
|
||||||
|
*/
|
||||||
|
new (target: Element): ResizeObserverEntry;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The Element whose size has changed.
|
||||||
|
*/
|
||||||
|
readonly target: Element;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Element's content rect when ResizeObserverCallback is invoked.
|
||||||
|
*/
|
||||||
|
readonly contentRect: DOMRectReadOnly;
|
||||||
}
|
}
|
28
typings/internal-electron.d.ts
vendored
28
typings/internal-electron.d.ts
vendored
|
@ -80,6 +80,34 @@ declare namespace ElectronInternal {
|
||||||
on(channel: string, listener: (event: IpcMainInternalEvent, ...args: any[]) => void): this;
|
on(channel: string, listener: (event: IpcMainInternalEvent, ...args: any[]) => void): this;
|
||||||
once(channel: string, listener: (event: IpcMainInternalEvent, ...args: any[]) => void): this;
|
once(channel: string, listener: (event: IpcMainInternalEvent, ...args: any[]) => void): this;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
interface WebFrameInternal extends Electron.WebFrame {
|
||||||
|
getWebFrameId(window: Window): number;
|
||||||
|
allowGuestViewElementDefinition(window: Window, context: any): void;
|
||||||
|
}
|
||||||
|
|
||||||
|
interface WebFrameResizeEvent extends Electron.Event {
|
||||||
|
newWidth: number;
|
||||||
|
newHeight: number;
|
||||||
|
}
|
||||||
|
|
||||||
|
interface WebViewEvent extends Event {
|
||||||
|
url: string;
|
||||||
|
isMainFrame: boolean;
|
||||||
|
}
|
||||||
|
|
||||||
|
abstract class WebViewElement extends HTMLElement {
|
||||||
|
static observedAttributes: Array<string>;
|
||||||
|
|
||||||
|
public contentWindow: Window;
|
||||||
|
|
||||||
|
public connectedCallback(): void;
|
||||||
|
public attributeChangedCallback(): void;
|
||||||
|
public disconnectedCallback(): void;
|
||||||
|
|
||||||
|
// Created in web-view-impl
|
||||||
|
public getWebContents(): Electron.WebContents;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
declare namespace Chrome {
|
declare namespace Chrome {
|
||||||
|
|
Loading…
Reference in a new issue