diff --git a/lib/browser/guest-view-manager.js b/lib/browser/guest-view-manager.js index 2f8ffefebc1c..556441f6332d 100644 --- a/lib/browser/guest-view-manager.js +++ b/lib/browser/guest-view-manager.js @@ -1,7 +1,6 @@ 'use strict' -const ipcMain = require('electron').ipcMain -const webContents = require('electron').webContents +const {ipcMain, webContents} = require('electron') const parseFeaturesString = require('../common/parse-features-string') // Doesn't exist in early initialization. @@ -48,7 +47,7 @@ const embedderElementsMap = {} // Moves the last element of array to the first one. const moveLastToFirst = function (list) { - return list.unshift(list.pop()) + list.unshift(list.pop()) } // Generate guestInstanceId. @@ -77,7 +76,6 @@ const createGuest = function (embedder, params) { // Init guest web view after attached. guest.on('did-attach', function () { - let opts params = this.attachParams delete this.attachParams this.viewInstanceId = params.instanceId @@ -97,7 +95,7 @@ const createGuest = function (embedder, params) { } }) if (params.src) { - opts = {} + const opts = {} if (params.httpreferrer) { opts.httpReferrer = params.httpreferrer } @@ -109,14 +107,17 @@ const createGuest = function (embedder, params) { guest.allowPopups = params.allowpopups }) + const sendToEmbedder = (channel, ...args) => { + const embedder = getEmbedder(guestInstanceId) + if (embedder != null) { + embedder.send(`${channel}-${guest.viewInstanceId}`, ...args) + } + } + // Dispatch events to embedder. const fn = function (event) { guest.on(event, function (_, ...args) { - const embedder = getEmbedder(guestInstanceId) - if (!embedder) { - return - } - embedder.send.apply(embedder, ['ELECTRON_GUEST_VIEW_INTERNAL_DISPATCH_EVENT-' + guest.viewInstanceId, event].concat(args)) + sendToEmbedder('ELECTRON_GUEST_VIEW_INTERNAL_DISPATCH_EVENT', event, ...args) }) } for (const event of supportedWebViewEvents) { @@ -125,20 +126,12 @@ const createGuest = function (embedder, params) { // Dispatch guest's IPC messages to embedder. guest.on('ipc-message-host', function (_, [channel, ...args]) { - const embedder = getEmbedder(guestInstanceId) - if (!embedder) { - return - } - embedder.send.apply(embedder, ['ELECTRON_GUEST_VIEW_INTERNAL_IPC_MESSAGE-' + guest.viewInstanceId, channel].concat(args)) + sendToEmbedder('ELECTRON_GUEST_VIEW_INTERNAL_IPC_MESSAGE', channel, ...args) }) // Autosize. guest.on('size-changed', function (_, ...args) { - const embedder = getEmbedder(guestInstanceId) - if (!embedder) { - return - } - embedder.send.apply(embedder, ['ELECTRON_GUEST_VIEW_INTERNAL_SIZE_CHANGED-' + guest.viewInstanceId].concat(args)) + sendToEmbedder('ELECTRON_GUEST_VIEW_INTERNAL_SIZE_CHANGED', ...args) }) return guestInstanceId @@ -146,11 +139,9 @@ const createGuest = function (embedder, params) { // Attach the guest to an element of embedder. const attachGuest = function (embedder, elementInstanceId, guestInstanceId, params) { - let guest, guestInstance, key, oldKey, oldGuestInstanceId, ref1, webPreferences - // Destroy the old guest when attaching. - key = (embedder.getId()) + '-' + elementInstanceId - oldGuestInstanceId = embedderElementsMap[key] + const key = `${embedder.getId()}-${elementInstanceId}` + const oldGuestInstanceId = embedderElementsMap[key] if (oldGuestInstanceId != null) { // Reattachment to the same guest is just a no-op. if (oldGuestInstanceId === guestInstanceId) { @@ -160,24 +151,24 @@ const attachGuest = function (embedder, elementInstanceId, guestInstanceId, para destroyGuest(embedder, oldGuestInstanceId) } - guestInstance = guestInstances[guestInstanceId] + const guestInstance = guestInstances[guestInstanceId] // If this isn't a valid guest instance then do nothing. if (!guestInstance) { return } - guest = guestInstance.guest + const {guest} = guestInstance // If this guest is already attached to an element then remove it if (guestInstance.elementInstanceId) { - oldKey = (guestInstance.embedder.getId()) + '-' + guestInstance.elementInstanceId + const oldKey = `${guestInstance.embedder.getId()}-${guestInstance.elementInstanceId}` delete embedderElementsMap[oldKey] webViewManager.removeGuest(guestInstance.embedder, guestInstanceId) - guestInstance.embedder.send('ELECTRON_GUEST_VIEW_INTERNAL_DESTROY_GUEST-' + guest.viewInstanceId) + guestInstance.embedder.send(`ELECTRON_GUEST_VIEW_INTERNAL_DESTROY_GUEST-${guest.viewInstanceId}`) } - webPreferences = { + const webPreferences = { guestInstanceId: guestInstanceId, - nodeIntegration: (ref1 = params.nodeintegration) != null ? ref1 : false, + nodeIntegration: params.nodeintegration != null ? params.nodeintegration : false, plugins: params.plugins, zoomFactor: params.zoomFactor, webSecurity: !params.disablewebsecurity, @@ -217,7 +208,7 @@ const destroyGuest = function (embedder, guestInstanceId) { return } - let guestInstance = guestInstances[guestInstanceId] + const guestInstance = guestInstances[guestInstanceId] if (embedder !== guestInstance.embedder) { return } @@ -226,8 +217,8 @@ const destroyGuest = function (embedder, guestInstanceId) { guestInstance.guest.destroy() delete guestInstances[guestInstanceId] - const key = embedder.getId() + '-' + guestInstance.elementInstanceId - return delete embedderElementsMap[key] + const key = `${embedder.getId()}-${guestInstance.elementInstanceId}` + delete embedderElementsMap[key] } // Once an embedder has had a guest attached we watch it for destruction to @@ -268,7 +259,7 @@ const watchEmbedder = function (embedder) { } ipcMain.on('ELECTRON_GUEST_VIEW_MANAGER_CREATE_GUEST', function (event, params, requestId) { - event.sender.send('ELECTRON_RESPONSE_' + requestId, createGuest(event.sender, params)) + event.sender.send(`ELECTRON_RESPONSE_${requestId}`, createGuest(event.sender, params)) }) ipcMain.on('ELECTRON_GUEST_VIEW_MANAGER_ATTACH_GUEST', function (event, elementInstanceId, guestInstanceId, params) { @@ -280,19 +271,21 @@ ipcMain.on('ELECTRON_GUEST_VIEW_MANAGER_DESTROY_GUEST', function (event, guestIn }) ipcMain.on('ELECTRON_GUEST_VIEW_MANAGER_SET_SIZE', function (event, guestInstanceId, params) { - const guestInstance = guestInstances[guestInstanceId] - return guestInstance != null ? guestInstance.guest.setSize(params) : void 0 + const guest = getGuest(guestInstanceId) + if (guest != null) guest.setSize(params) }) // Returns WebContents from its guest id. -exports.getGuest = function (guestInstanceId) { +const getGuest = function (guestInstanceId) { const guestInstance = guestInstances[guestInstanceId] - return guestInstance != null ? guestInstance.guest : void 0 + if (guestInstance != null) return guestInstance.guest } // Returns the embedder of the guest. const getEmbedder = function (guestInstanceId) { const guestInstance = guestInstances[guestInstanceId] - return guestInstance != null ? guestInstance.embedder : void 0 + if (guestInstance != null) return guestInstance.embedder } + +exports.getGuest = getGuest exports.getEmbedder = getEmbedder diff --git a/lib/renderer/web-view/guest-view-internal.js b/lib/renderer/web-view/guest-view-internal.js index 9947c27eeed0..f07ded2c3155 100644 --- a/lib/renderer/web-view/guest-view-internal.js +++ b/lib/renderer/web-view/guest-view-internal.js @@ -1,11 +1,10 @@ 'use strict' -const ipcRenderer = require('electron').ipcRenderer -const webFrame = require('electron').webFrame +const {ipcRenderer, webFrame} = require('electron') -var requestId = 0 +let requestId = 0 -var WEB_VIEW_EVENTS = { +const WEB_VIEW_EVENTS = { 'load-commit': ['url', 'isMainFrame'], 'did-attach': [], 'did-finish-load': [], @@ -40,79 +39,74 @@ var WEB_VIEW_EVENTS = { 'update-target-url': ['url'] } -var DEPRECATED_EVENTS = { +const DEPRECATED_EVENTS = { 'page-title-updated': 'page-title-set' } -var dispatchEvent = function (webView, eventName, eventKey, ...args) { - var domEvent, f, i, j, len, ref1 +const dispatchEvent = function (webView, eventName, eventKey, ...args) { if (DEPRECATED_EVENTS[eventName] != null) { - dispatchEvent.apply(null, [webView, DEPRECATED_EVENTS[eventName], eventKey].concat(args)) - } - domEvent = new Event(eventName) - ref1 = WEB_VIEW_EVENTS[eventKey] - for (i = j = 0, len = ref1.length; j < len; i = ++j) { - f = ref1[i] - domEvent[f] = args[i] + 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') { - return webView.onLoadCommit(domEvent) + webView.onLoadCommit(domEvent) } } module.exports = { registerEvents: function (webView, viewInstanceId) { - ipcRenderer.on('ELECTRON_GUEST_VIEW_INTERNAL_DESTROY_GUEST-' + viewInstanceId, function () { - var domEvent + ipcRenderer.on(`ELECTRON_GUEST_VIEW_INTERNAL_DESTROY_GUEST-${viewInstanceId}`, function () { webFrame.detachGuest(webView.internalInstanceId) webView.guestInstanceId = undefined webView.reset() - domEvent = new Event('destroyed') + const domEvent = new Event('destroyed') webView.dispatchEvent(domEvent) }) - ipcRenderer.on('ELECTRON_GUEST_VIEW_INTERNAL_DISPATCH_EVENT-' + viewInstanceId, function (event, eventName, ...args) { - dispatchEvent.apply(null, [webView, eventName, eventName].concat(args)) + ipcRenderer.on(`ELECTRON_GUEST_VIEW_INTERNAL_DISPATCH_EVENT-${viewInstanceId}`, function (event, eventName, ...args) { + dispatchEvent(webView, eventName, eventName, ...args) }) - ipcRenderer.on('ELECTRON_GUEST_VIEW_INTERNAL_IPC_MESSAGE-' + viewInstanceId, function (event, channel, ...args) { - var domEvent = new Event('ipc-message') + ipcRenderer.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) }) - return ipcRenderer.on('ELECTRON_GUEST_VIEW_INTERNAL_SIZE_CHANGED-' + viewInstanceId, function (event, ...args) { - var domEvent, f, i, j, len, ref1 - domEvent = new Event('size-changed') - ref1 = ['oldWidth', 'oldHeight', 'newWidth', 'newHeight'] - for (i = j = 0, len = ref1.length; j < len; i = ++j) { - f = ref1[i] - domEvent[f] = args[i] + ipcRenderer.on(`ELECTRON_GUEST_VIEW_INTERNAL_SIZE_CHANGED-${viewInstanceId}`, function (event, ...args) { + const domEvent = new Event('size-changed') + const props = ['oldWidth', 'oldHeight', 'newWidth', 'newHeight'] + for (let i = 0; i < props.length; i++) { + const prop = props[i] + domEvent[prop] = args[i] } webView.onSizeChanged(domEvent) }) }, deregisterEvents: function (viewInstanceId) { - ipcRenderer.removeAllListeners('ELECTRON_GUEST_VIEW_INTERNAL_DESTROY_GUEST-' + viewInstanceId) - ipcRenderer.removeAllListeners('ELECTRON_GUEST_VIEW_INTERNAL_DISPATCH_EVENT-' + viewInstanceId) - ipcRenderer.removeAllListeners('ELECTRON_GUEST_VIEW_INTERNAL_IPC_MESSAGE-' + viewInstanceId) - return ipcRenderer.removeAllListeners('ELECTRON_GUEST_VIEW_INTERNAL_SIZE_CHANGED-' + viewInstanceId) + ipcRenderer.removeAllListeners(`ELECTRON_GUEST_VIEW_INTERNAL_DESTROY_GUEST-${viewInstanceId}`) + ipcRenderer.removeAllListeners(`ELECTRON_GUEST_VIEW_INTERNAL_DISPATCH_EVENT-${viewInstanceId}`) + ipcRenderer.removeAllListeners(`ELECTRON_GUEST_VIEW_INTERNAL_IPC_MESSAGE-${viewInstanceId}`) + ipcRenderer.removeAllListeners(`ELECTRON_GUEST_VIEW_INTERNAL_SIZE_CHANGED-${viewInstanceId}`) }, createGuest: function (params, callback) { requestId++ ipcRenderer.send('ELECTRON_GUEST_VIEW_MANAGER_CREATE_GUEST', params, requestId) - return ipcRenderer.once('ELECTRON_RESPONSE_' + requestId, callback) + ipcRenderer.once(`ELECTRON_RESPONSE_${requestId}`, callback) }, attachGuest: function (elementInstanceId, guestInstanceId, params) { ipcRenderer.send('ELECTRON_GUEST_VIEW_MANAGER_ATTACH_GUEST', elementInstanceId, guestInstanceId, params) - return webFrame.attachGuest(elementInstanceId) + webFrame.attachGuest(elementInstanceId) }, destroyGuest: function (guestInstanceId) { - return ipcRenderer.send('ELECTRON_GUEST_VIEW_MANAGER_DESTROY_GUEST', guestInstanceId) + ipcRenderer.send('ELECTRON_GUEST_VIEW_MANAGER_DESTROY_GUEST', guestInstanceId) }, setSize: function (guestInstanceId, params) { - return ipcRenderer.send('ELECTRON_GUEST_VIEW_MANAGER_SET_SIZE', guestInstanceId, params) + ipcRenderer.send('ELECTRON_GUEST_VIEW_MANAGER_SET_SIZE', guestInstanceId, params) } } diff --git a/lib/renderer/web-view/web-view-attributes.js b/lib/renderer/web-view/web-view-attributes.js index f87fca312238..f42fcc5e781b 100644 --- a/lib/renderer/web-view/web-view-attributes.js +++ b/lib/renderer/web-view/web-view-attributes.js @@ -3,12 +3,12 @@ const WebViewImpl = require('./web-view') const guestViewInternal = require('./guest-view-internal') const webViewConstants = require('./web-view-constants') -const remote = require('electron').remote +const {remote} = require('electron') // Helper function to resolve url set in attribute. -var a = document.createElement('a') +const a = document.createElement('a') -var resolveURL = function (url) { +const resolveURL = function (url) { if (url === '') return '' a.href = url return a.href @@ -32,7 +32,7 @@ class WebViewAttribute { // Sets the attribute's value. setValue (value) { - return this.webViewImpl.webviewNode.setAttribute(this.name, value || '') + this.webViewImpl.webviewNode.setAttribute(this.name, value || '') } // Changes the attribute's value without triggering its mutation handler. @@ -66,10 +66,10 @@ class BooleanAttribute extends WebViewAttribute { } setValue (value) { - if (!value) { - return this.webViewImpl.webviewNode.removeAttribute(this.name) + if (value) { + this.webViewImpl.webviewNode.setAttribute(this.name, '') } else { - return this.webViewImpl.webviewNode.setAttribute(this.name, '') + this.webViewImpl.webviewNode.removeAttribute(this.name) } } } @@ -84,7 +84,7 @@ class AutosizeDimensionAttribute extends WebViewAttribute { if (!this.webViewImpl.guestInstanceId) { return } - return guestViewInternal.setSize(this.webViewImpl.guestInstanceId, { + guestViewInternal.setSize(this.webViewImpl.guestInstanceId, { enableAutoSize: this.webViewImpl.attributes[webViewConstants.ATTRIBUTE_AUTOSIZE].getValue(), min: { width: parseInt(this.webViewImpl.attributes[webViewConstants.ATTRIBUTE_MINWIDTH].getValue() || 0), @@ -125,7 +125,7 @@ class PartitionAttribute extends WebViewAttribute { } if (newValue === 'persist:') { this.validPartitionId = false - return window.console.error(webViewConstants.ERROR_MSG_INVALID_PARTITION_ATTRIBUTE) + window.console.error(webViewConstants.ERROR_MSG_INVALID_PARTITION_ATTRIBUTE) } } } @@ -141,18 +141,15 @@ class GuestInstanceAttribute extends WebViewAttribute { if (this.webViewImpl.webviewNode.hasAttribute(this.name)) { return parseInt(this.webViewImpl.webviewNode.getAttribute(this.name)) } - return undefined } // Sets the attribute's value. setValue (value) { if (!value) { - return this.webViewImpl.webviewNode.removeAttribute(this.name) + this.webViewImpl.webviewNode.removeAttribute(this.name) + } else if (!isNaN(value)) { + this.webViewImpl.webviewNode.setAttribute(this.name, value) } - if (isNaN(value)) { - return - } - return this.webViewImpl.webviewNode.setAttribute(this.name, value) } handleMutation (oldValue, newValue) { @@ -192,7 +189,7 @@ class SrcAttribute extends WebViewAttribute { // is possible for this change to get picked up asyncronously by src's // mutation observer |observer|, and then get handled even though we do not // want to handle this mutation. - return this.observer.takeRecords() + this.observer.takeRecords() } handleMutation (oldValue, newValue) { @@ -206,7 +203,7 @@ class SrcAttribute extends WebViewAttribute { this.setValueIgnoreMutation(oldValue) return } - return this.parse() + this.parse() } // The purpose of this mutation observer is to catch assignment to the src @@ -214,29 +211,25 @@ class SrcAttribute extends WebViewAttribute { // where the webview guest has crashed and navigating to the same address // spawns off a new process. setupMutationObserver () { - var params this.observer = new MutationObserver((mutations) => { - var i, len, mutation, newValue, oldValue - for (i = 0, len = mutations.length; i < len; i++) { - mutation = mutations[i] - oldValue = mutation.oldValue - newValue = this.getValue() + for (const mutation of mutations) { + const {oldValue} = mutation + const newValue = this.getValue() if (oldValue !== newValue) { return } this.handleMutation(oldValue, newValue) } }) - params = { + const params = { attributes: true, attributeOldValue: true, attributeFilter: [this.name] } - return this.observer.observe(this.webViewImpl.webviewNode, params) + this.observer.observe(this.webViewImpl.webviewNode, params) } parse () { - var guestContents, httpreferrer, opts, useragent if (!this.webViewImpl.elementAttached || !this.webViewImpl.attributes[webViewConstants.ATTRIBUTE_PARTITION].validPartitionId || !this.getValue()) { return } @@ -249,17 +242,17 @@ class SrcAttribute extends WebViewAttribute { } // Navigate to |this.src|. - opts = {} - httpreferrer = this.webViewImpl.attributes[webViewConstants.ATTRIBUTE_HTTPREFERRER].getValue() + const opts = {} + const httpreferrer = this.webViewImpl.attributes[webViewConstants.ATTRIBUTE_HTTPREFERRER].getValue() if (httpreferrer) { opts.httpReferrer = httpreferrer } - useragent = this.webViewImpl.attributes[webViewConstants.ATTRIBUTE_USERAGENT].getValue() + const useragent = this.webViewImpl.attributes[webViewConstants.ATTRIBUTE_USERAGENT].getValue() if (useragent) { opts.userAgent = useragent } - guestContents = remote.getGuestWebContents(this.webViewImpl.guestInstanceId) - return guestContents.loadURL(this.getValue(), opts) + const guestContents = remote.getGuestWebContents(this.webViewImpl.guestInstanceId) + guestContents.loadURL(this.getValue(), opts) } } @@ -284,12 +277,11 @@ class PreloadAttribute extends WebViewAttribute { } getValue () { - var preload, protocol if (!this.webViewImpl.webviewNode.hasAttribute(this.name)) { return this.value } - preload = resolveURL(this.webViewImpl.webviewNode.getAttribute(this.name)) - protocol = preload.substr(0, 5) + let preload = resolveURL(this.webViewImpl.webviewNode.getAttribute(this.name)) + const protocol = preload.substr(0, 5) if (protocol !== 'file:') { console.error(webViewConstants.ERROR_MSG_INVALID_PRELOAD_ATTRIBUTE) preload = '' diff --git a/lib/renderer/web-view/web-view.js b/lib/renderer/web-view/web-view.js index dee602b03b2f..fc8b9a4abdde 100644 --- a/lib/renderer/web-view/web-view.js +++ b/lib/renderer/web-view/web-view.js @@ -1,26 +1,23 @@ 'use strict' -const webFrame = require('electron').webFrame -const remote = require('electron').remote -const ipcRenderer = require('electron').ipcRenderer +const {ipcRenderer, remote, webFrame} = require('electron') const v8Util = process.atomBinding('v8_util') const guestViewInternal = require('./guest-view-internal') const webViewConstants = require('./web-view-constants') -var hasProp = {}.hasOwnProperty +const hasProp = {}.hasOwnProperty // ID generator. -var nextId = 0 +let nextId = 0 -var getNextId = function () { +const getNextId = function () { return ++nextId } // Represents the internal state of the WebView node. -var WebViewImpl = (function () { - function WebViewImpl (webviewNode) { - var shadowRoot +class WebViewImpl { + constructor (webviewNode) { this.webviewNode = webviewNode v8Util.setHiddenValue(this.webviewNode, 'internal', this) this.attached = false @@ -30,7 +27,7 @@ var WebViewImpl = (function () { // on* Event handlers. this.on = {} this.browserPluginNode = this.createBrowserPluginNode() - shadowRoot = this.webviewNode.createShadowRoot() + const shadowRoot = this.webviewNode.createShadowRoot() shadowRoot.innerHTML = '' this.setupWebViewAttributes() this.setupFocusPropagation() @@ -49,16 +46,16 @@ var WebViewImpl = (function () { ipcRenderer.on('ELECTRON_RENDERER_WINDOW_VISIBILITY_CHANGE', this.onVisibilityChanged) } - WebViewImpl.prototype.createBrowserPluginNode = function () { + createBrowserPluginNode () { // We create BrowserPlugin as a custom element in order to observe changes // to attributes synchronously. - var browserPluginNode = new WebViewImpl.BrowserPlugin() + const browserPluginNode = new WebViewImpl.BrowserPlugin() v8Util.setHiddenValue(browserPluginNode, 'internal', this) return browserPluginNode } // Resets some state upon reattaching element to the DOM. - WebViewImpl.prototype.reset = function () { + reset () { // Unlisten the zoom-level-changed event. webFrame.removeListener('zoom-level-changed', this.onZoomLevelChanged) ipcRenderer.removeListener('ELECTRON_RENDERER_WINDOW_VISIBILITY_CHANGE', this.onVisibilityChanged) @@ -81,14 +78,14 @@ var WebViewImpl = (function () { } // Sets the .request property. - WebViewImpl.prototype.setRequestPropertyOnWebViewNode = function (request) { - return Object.defineProperty(this.webviewNode, 'request', { + setRequestPropertyOnWebViewNode (request) { + Object.defineProperty(this.webviewNode, 'request', { value: request, enumerable: true }) } - WebViewImpl.prototype.setupFocusPropagation = function () { + setupFocusPropagation () { if (!this.webviewNode.hasAttribute('tabIndex')) { // needs a tabIndex in order to be focusable. // TODO(fsamuel): It would be nice to avoid exposing a tabIndex attribute @@ -113,58 +110,54 @@ var WebViewImpl = (function () { // a BrowserPlugin property will update the corresponding BrowserPlugin // attribute, if necessary. See BrowserPlugin::UpdateDOMAttribute for more // details. - WebViewImpl.prototype.handleWebviewAttributeMutation = function (attributeName, oldValue, newValue) { + handleWebviewAttributeMutation (attributeName, oldValue, newValue) { if (!this.attributes[attributeName] || this.attributes[attributeName].ignoreMutation) { return } // Let the changed attribute handle its own mutation - return this.attributes[attributeName].handleMutation(oldValue, newValue) + this.attributes[attributeName].handleMutation(oldValue, newValue) } - WebViewImpl.prototype.handleBrowserPluginAttributeMutation = function (attributeName, oldValue, newValue) { + handleBrowserPluginAttributeMutation (attributeName, oldValue, newValue) { if (attributeName === webViewConstants.ATTRIBUTE_INTERNALINSTANCEID && !oldValue && !!newValue) { this.browserPluginNode.removeAttribute(webViewConstants.ATTRIBUTE_INTERNALINSTANCEID) this.internalInstanceId = parseInt(newValue) // Track when the element resizes using the element resize callback. webFrame.registerElementResizeCallback(this.internalInstanceId, this.onElementResize.bind(this)) - if (!this.guestInstanceId) { - return + if (this.guestInstanceId) { + guestViewInternal.attachGuest(this.internalInstanceId, this.guestInstanceId, this.buildParams()) } - return guestViewInternal.attachGuest(this.internalInstanceId, this.guestInstanceId, this.buildParams()) } } - WebViewImpl.prototype.onSizeChanged = function (webViewEvent) { - var maxHeight, maxWidth, minHeight, minWidth, newHeight, newWidth, node, width - newWidth = webViewEvent.newWidth - newHeight = webViewEvent.newHeight - node = this.webviewNode - width = node.offsetWidth + onSizeChanged (webViewEvent) { + const {newHeight, newWidth} = webViewEvent + const node = this.webviewNode + const width = node.offsetWidth // Check the current bounds to make sure we do not resize // outside of current constraints. - maxWidth = this.attributes[webViewConstants.ATTRIBUTE_MAXWIDTH].getValue() | width - maxHeight = this.attributes[webViewConstants.ATTRIBUTE_MAXHEIGHT].getValue() | width - minWidth = this.attributes[webViewConstants.ATTRIBUTE_MINWIDTH].getValue() | width - minHeight = this.attributes[webViewConstants.ATTRIBUTE_MINHEIGHT].getValue() | width + const maxWidth = this.attributes[webViewConstants.ATTRIBUTE_MAXWIDTH].getValue() | width + const maxHeight = this.attributes[webViewConstants.ATTRIBUTE_MAXHEIGHT].getValue() | width + let minWidth = this.attributes[webViewConstants.ATTRIBUTE_MINWIDTH].getValue() | width + let minHeight = this.attributes[webViewConstants.ATTRIBUTE_MINHEIGHT].getValue() | width minWidth = Math.min(minWidth, maxWidth) minHeight = Math.min(minHeight, maxHeight) if (!this.attributes[webViewConstants.ATTRIBUTE_AUTOSIZE].getValue() || (newWidth >= minWidth && newWidth <= maxWidth && newHeight >= minHeight && newHeight <= maxHeight)) { - node.style.width = newWidth + 'px' - node.style.height = newHeight + 'px' + node.style.width = `${newWidth}px` + node.style.height = `${newHeight}px` // Only fire the DOM event if the size of the has actually // changed. - return this.dispatchEvent(webViewEvent) + this.dispatchEvent(webViewEvent) } } - WebViewImpl.prototype.onElementResize = function (newSize) { + onElementResize (newSize) { // Dispatch the 'resize' event. - var resizeEvent - resizeEvent = new Event('resize', { + const resizeEvent = new Event('resize', { bubbles: true }) @@ -177,27 +170,26 @@ var WebViewImpl = (function () { resizeEvent.newHeight = newSize.height this.dispatchEvent(resizeEvent) if (this.guestInstanceId) { - return guestViewInternal.setSize(this.guestInstanceId, { + guestViewInternal.setSize(this.guestInstanceId, { normal: newSize }) } } - WebViewImpl.prototype.createGuest = function () { + createGuest () { return guestViewInternal.createGuest(this.buildParams(), (event, guestInstanceId) => { this.attachGuestInstance(guestInstanceId) }) } - WebViewImpl.prototype.dispatchEvent = function (webViewEvent) { - return this.webviewNode.dispatchEvent(webViewEvent) + dispatchEvent (webViewEvent) { + this.webviewNode.dispatchEvent(webViewEvent) } // Adds an 'on' property on the webview, which can be used to set/unset // an event handler. - WebViewImpl.prototype.setupEventProperty = function (eventName) { - var propertyName - propertyName = 'on' + eventName.toLowerCase() + setupEventProperty (eventName) { + const propertyName = `on${eventName.toLowerCase()}` return Object.defineProperty(this.webviewNode, propertyName, { get: () => { return this.on[propertyName] @@ -216,34 +208,31 @@ var WebViewImpl = (function () { } // Updates state upon loadcommit. - WebViewImpl.prototype.onLoadCommit = function (webViewEvent) { - var newValue, oldValue - oldValue = this.webviewNode.getAttribute(webViewConstants.ATTRIBUTE_SRC) - newValue = webViewEvent.url + onLoadCommit (webViewEvent) { + const oldValue = this.webviewNode.getAttribute(webViewConstants.ATTRIBUTE_SRC) + const newValue = webViewEvent.url if (webViewEvent.isMainFrame && (oldValue !== newValue)) { // Touching the src attribute triggers a navigation. To avoid // triggering a page reload on every guest-initiated navigation, // we do not handle this mutation. - return this.attributes[webViewConstants.ATTRIBUTE_SRC].setValueIgnoreMutation(newValue) + this.attributes[webViewConstants.ATTRIBUTE_SRC].setValueIgnoreMutation(newValue) } } - WebViewImpl.prototype.onAttach = function (storagePartitionId) { + onAttach (storagePartitionId) { return this.attributes[webViewConstants.ATTRIBUTE_PARTITION].setValue(storagePartitionId) } - WebViewImpl.prototype.buildParams = function () { - var attribute, attributeName, css, elementRect, params, ref1 - params = { + buildParams () { + const params = { instanceId: this.viewInstanceId, userAgentOverride: this.userAgentOverride, zoomFactor: webFrame.getZoomFactor() } - ref1 = this.attributes - for (attributeName in ref1) { - if (!hasProp.call(ref1, attributeName)) continue - attribute = ref1[attributeName] - params[attributeName] = attribute.getValue() + for (const attributeName in this.attributes) { + if (hasProp.call(this.attributes, attributeName)) { + params[attributeName] = this.attributes[attributeName].getValue() + } } // When the WebView is not participating in layout (display:none) @@ -251,14 +240,14 @@ var WebViewImpl = (function () { // However, in the case where the WebView has a fixed size we can // use that value to initially size the guest so as to avoid a relayout of // the on display:block. - css = window.getComputedStyle(this.webviewNode, null) - elementRect = this.webviewNode.getBoundingClientRect() + const css = window.getComputedStyle(this.webviewNode, null) + const elementRect = this.webviewNode.getBoundingClientRect() params.elementWidth = parseInt(elementRect.width) || parseInt(css.getPropertyValue('width')) params.elementHeight = parseInt(elementRect.height) || parseInt(css.getPropertyValue('height')) return params } - WebViewImpl.prototype.attachGuestInstance = function (guestInstanceId) { + attachGuestInstance (guestInstanceId) { this.guestInstanceId = guestInstanceId this.attributes[webViewConstants.ATTRIBUTE_GUESTINSTANCE].setValueIgnoreMutation(guestInstanceId) this.webContents = remote.getGuestWebContents(this.guestInstanceId) @@ -267,16 +256,14 @@ var WebViewImpl = (function () { } return guestViewInternal.attachGuest(this.internalInstanceId, this.guestInstanceId, this.buildParams()) } - - return WebViewImpl -})() +} // Registers browser plugin custom element. -var registerBrowserPluginElement = function () { - var proto = Object.create(HTMLObjectElement.prototype) +const registerBrowserPluginElement = function () { + const proto = Object.create(HTMLObjectElement.prototype) proto.createdCallback = function () { this.setAttribute('type', 'application/browser-plugin') - this.setAttribute('id', 'browser-plugin-' + getNextId()) + this.setAttribute('id', `browser-plugin-${getNextId()}`) // The node fills in the container. this.style.flex = '1 1 auto' @@ -284,10 +271,9 @@ var registerBrowserPluginElement = function () { proto.attributeChangedCallback = function (name, oldValue, newValue) { var internal internal = v8Util.getHiddenValue(this, 'internal') - if (!internal) { - return + if (internal) { + internal.handleBrowserPluginAttributeMutation(name, oldValue, newValue) } - return internal.handleBrowserPluginAttributeMutation(name, oldValue, newValue) } proto.attachedCallback = function () { // Load the plugin immediately. @@ -300,23 +286,21 @@ var registerBrowserPluginElement = function () { delete proto.createdCallback delete proto.attachedCallback delete proto.detachedCallback - return delete proto.attributeChangedCallback + delete proto.attributeChangedCallback } // Registers custom element. var registerWebViewElement = function () { - var createBlockHandler, createNonBlockHandler, i, j, len, len1, m, methods, nonblockMethods, proto - proto = Object.create(HTMLObjectElement.prototype) + const proto = Object.create(HTMLObjectElement.prototype) proto.createdCallback = function () { return new WebViewImpl(this) } proto.attributeChangedCallback = function (name, oldValue, newValue) { var internal internal = v8Util.getHiddenValue(this, 'internal') - if (!internal) { - return + if (internal) { + internal.handleWebviewAttributeMutation(name, oldValue, newValue) } - return internal.handleWebviewAttributeMutation(name, oldValue, newValue) } proto.detachedCallback = function () { var internal @@ -340,14 +324,15 @@ var registerWebViewElement = function () { internal.elementAttached = true instance = internal.attributes[webViewConstants.ATTRIBUTE_GUESTINSTANCE].getValue() if (instance) { - return internal.attachGuestInstance(instance) + internal.attachGuestInstance(instance) + } else { + internal.attributes[webViewConstants.ATTRIBUTE_SRC].parse() } - return internal.attributes[webViewConstants.ATTRIBUTE_SRC].parse() } } // Public-facing API methods. - methods = [ + const methods = [ 'getURL', 'loadURL', 'getTitle', @@ -396,7 +381,7 @@ var registerWebViewElement = function () { 'showDefinitionForSelection', 'capturePage' ] - nonblockMethods = [ + const nonblockMethods = [ 'insertCSS', 'insertText', 'send', @@ -407,38 +392,37 @@ var registerWebViewElement = function () { ] // Forward proto.foo* method calls to WebViewImpl.foo*. - createBlockHandler = function (m) { + const createBlockHandler = function (m) { return function (...args) { const internal = v8Util.getHiddenValue(this, 'internal') if (internal.webContents) { - return internal.webContents[m].apply(internal.webContents, args) + return internal.webContents[m](...args) } else { throw new Error(`Cannot call ${m} because the webContents is unavailable. The WebView must be attached to the DOM and the dom-ready event emitted before this method can be called.`) } } } - for (i = 0, len = methods.length; i < len; i++) { - m = methods[i] - proto[m] = createBlockHandler(m) + for (const method of methods) { + proto[method] = createBlockHandler(method) } - createNonBlockHandler = function (m) { + + const createNonBlockHandler = function (m) { return function (...args) { const internal = v8Util.getHiddenValue(this, 'internal') - return ipcRenderer.send.apply(ipcRenderer, ['ELECTRON_BROWSER_ASYNC_CALL_TO_GUEST_VIEW', null, internal.guestInstanceId, m].concat(args)) + ipcRenderer.send('ELECTRON_BROWSER_ASYNC_CALL_TO_GUEST_VIEW', null, internal.guestInstanceId, m, ...args) } } - for (j = 0, len1 = nonblockMethods.length; j < len1; j++) { - m = nonblockMethods[j] - proto[m] = createNonBlockHandler(m) + for (const method of nonblockMethods) { + proto[method] = createNonBlockHandler(method) } proto.executeJavaScript = function (code, hasUserGesture, callback) { - var internal = v8Util.getHiddenValue(this, 'internal') + const internal = v8Util.getHiddenValue(this, 'internal') if (typeof hasUserGesture === 'function') { callback = hasUserGesture hasUserGesture = false } - let requestId = getNextId() + const requestId = getNextId() ipcRenderer.send('ELECTRON_BROWSER_ASYNC_CALL_TO_GUEST_VIEW', requestId, internal.guestInstanceId, 'executeJavaScript', code, hasUserGesture) ipcRenderer.once(`ELECTRON_RENDERER_ASYNC_CALL_TO_GUEST_VIEW_RESPONSE_${requestId}`, function (event, result) { if (callback) callback(result) @@ -447,8 +431,7 @@ var registerWebViewElement = function () { // WebContents associated with this webview. proto.getWebContents = function () { - var internal = v8Util.getHiddenValue(this, 'internal') - return internal.webContents + return v8Util.getHiddenValue(this, 'internal').webContents } window.WebView = webFrame.registerEmbedderCustomElement('webview', { @@ -460,18 +443,18 @@ var registerWebViewElement = function () { delete proto.createdCallback delete proto.attachedCallback delete proto.detachedCallback - return delete proto.attributeChangedCallback + delete proto.attributeChangedCallback } -var useCapture = true +const useCapture = true -var listener = function (event) { +const listener = function (event) { if (document.readyState === 'loading') { return } registerBrowserPluginElement() registerWebViewElement() - return window.removeEventListener(event.type, listener, useCapture) + window.removeEventListener(event.type, listener, useCapture) } window.addEventListener('readystatechange', listener, true) diff --git a/spec/webview-spec.js b/spec/webview-spec.js index d1acbeb80cd8..e00bc222549a 100644 --- a/spec/webview-spec.js +++ b/spec/webview-spec.js @@ -3,6 +3,7 @@ const path = require('path') const http = require('http') const url = require('url') const {app, session, getGuestWebContents, ipcMain, BrowserWindow} = require('electron').remote +const {closeWindow} = require('./window-helpers') describe(' tag', function () { this.timeout(20000) @@ -21,10 +22,7 @@ describe(' tag', function () { document.body.appendChild(webview) } webview.remove() - if (w) { - w.destroy() - w = null - } + return closeWindow(w).then(function () { w = null }) }) it('works without script tag in page', function (done) { @@ -1256,4 +1254,40 @@ describe(' tag', function () { document.body.appendChild(webview) }) }) + + describe('DOM events', function () { + let div + + beforeEach(function () { + div = document.createElement('div') + div.style.width = '100px' + div.style.height = '10px' + div.style.overflow = 'hidden' + webview.style.height = '100%' + webview.style.width = '100%' + }) + + afterEach(function () { + if (div != null) div.remove() + }) + + it('emits resize events', function (done) { + webview.addEventListener('dom-ready', function () { + div.style.width = '1234px' + div.style.height = '789px' + }) + + webview.addEventListener('resize', function onResize (event) { + webview.removeEventListener('resize', onResize) + assert.equal(event.newWidth, 1234) + assert.equal(event.newHeight, 789) + assert.equal(event.target, webview) + done() + }) + + webview.src = `file://${fixtures}/pages/a.html` + div.appendChild(webview) + document.body.appendChild(div) + }) + }) })