From f894da13b076668d5f4ee4bc2cfbd53e391d760e Mon Sep 17 00:00:00 2001 From: Kevin Sawicki Date: Thu, 1 Dec 2016 17:29:51 -0800 Subject: [PATCH 1/6] Pass args array instead of arguments object --- lib/renderer/api/remote.js | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/lib/renderer/api/remote.js b/lib/renderer/api/remote.js index be0b71af6d9e..c3c8e3b89cd1 100644 --- a/lib/renderer/api/remote.js +++ b/lib/renderer/api/remote.js @@ -88,7 +88,7 @@ const wrapArgs = function (args, visited) { } } } - return Array.prototype.slice.call(args).map(valueToMeta) + return args.map(valueToMeta) } // Populate object's members from descriptors. @@ -102,14 +102,14 @@ const setObjectMembers = function (ref, object, metaId, members) { let descriptor = { enumerable: member.enumerable } if (member.type === 'method') { - const remoteMemberFunction = function () { + const remoteMemberFunction = function (...args) { if (this && this.constructor === remoteMemberFunction) { // Constructor call. - let ret = ipcRenderer.sendSync('ELECTRON_BROWSER_MEMBER_CONSTRUCTOR', metaId, member.name, wrapArgs(arguments)) + let ret = ipcRenderer.sendSync('ELECTRON_BROWSER_MEMBER_CONSTRUCTOR', metaId, member.name, wrapArgs(args)) return metaToValue(ret) } else { // Call member function. - let ret = ipcRenderer.sendSync('ELECTRON_BROWSER_MEMBER_CALL', metaId, member.name, wrapArgs(arguments)) + let ret = ipcRenderer.sendSync('ELECTRON_BROWSER_MEMBER_CALL', metaId, member.name, wrapArgs(args)) return metaToValue(ret) } } @@ -220,17 +220,17 @@ const metaToValue = function (meta) { if (meta.type === 'function') { // A shadow class to represent the remote function object. - let remoteFunction = function () { + let remoteFunction = function (...args) { if (this && this.constructor === remoteFunction) { // Constructor call. - let obj = ipcRenderer.sendSync('ELECTRON_BROWSER_CONSTRUCTOR', meta.id, wrapArgs(arguments)) + let obj = ipcRenderer.sendSync('ELECTRON_BROWSER_CONSTRUCTOR', meta.id, wrapArgs(args)) // Returning object in constructor will replace constructed object // with the returned object. // http://stackoverflow.com/questions/1978049/what-values-can-a-constructor-return-to-avoid-returning-this return metaToValue(obj) } else { // Function call. - let obj = ipcRenderer.sendSync('ELECTRON_BROWSER_FUNCTION_CALL', meta.id, wrapArgs(arguments)) + let obj = ipcRenderer.sendSync('ELECTRON_BROWSER_FUNCTION_CALL', meta.id, wrapArgs(args)) return metaToValue(obj) } } From 635c909aab474cb609e254be26974217f461188e Mon Sep 17 00:00:00 2001 From: Kevin Sawicki Date: Thu, 1 Dec 2016 17:34:14 -0800 Subject: [PATCH 2/6] Implement window.alert/confirm/close in main process --- lib/browser/rpc-server.js | 31 ++++++++++++++++++++ lib/renderer/override.js | 62 ++++++++++++++++----------------------- 2 files changed, 56 insertions(+), 37 deletions(-) diff --git a/lib/browser/rpc-server.js b/lib/browser/rpc-server.js index e52546415509..b12b518888a2 100644 --- a/lib/browser/rpc-server.js +++ b/lib/browser/rpc-server.js @@ -416,3 +416,34 @@ ipcMain.on('ELECTRON_BROWSER_SEND_TO', function (event, sendToAll, webContentsId contents.send(channel, ...args) } }) + +// Implements window.alert(message, title) +ipcMain.on('ELECTRON_BROWSER_WINDOW_ALERT', function (event, message, title) { + if (message == null) message = '' + if (title == null) title = '' + + event.returnValue = electron.dialog.showMessageBox(event.sender.getOwnerBrowserWindow(), { + message: `${message}`, + title: `${title}`, + buttons: ['OK'] + }) +}) + +// Implements window.confirm(message, title) +ipcMain.on('ELECTRON_BROWSER_WINDOW_CONFIRM', function (event, message, title) { + if (message == null) message = '' + if (title == null) title = '' + + event.returnValue = !electron.dialog.showMessageBox(event.sender.getOwnerBrowserWindow(), { + message: `${message}`, + title: `${title}`, + buttons: ['OK', 'Cancel'], + cancelId: 1 + }) +}) + +// Implements window.close() +ipcMain.on('ELECTRON_BROWSER_WINDOW_CLOSE', function (event) { + event.sender.getOwnerBrowserWindow().close() + event.returnValue = null +}) diff --git a/lib/renderer/override.js b/lib/renderer/override.js index 6a8a50c378e8..a9cc19455b90 100644 --- a/lib/renderer/override.js +++ b/lib/renderer/override.js @@ -1,24 +1,29 @@ 'use strict' -const ipcRenderer = require('electron').ipcRenderer -const remote = require('electron').remote +const {ipcRenderer} = require('electron') const parseFeaturesString = require('../common/parse-features-string') +const {captureStackTrace} = Error +const {defineProperty} = Object + // Helper function to resolve relative url. -var a = window.top.document.createElement('a') -var resolveURL = function (url) { +const a = window.top.document.createElement('a') +const resolveURL = function (url) { a.href = url return a.href } // Window object returned by "window.open". -var BrowserWindowProxy = (function () { +const BrowserWindowProxy = (function () { BrowserWindowProxy.proxies = {} BrowserWindowProxy.getOrCreate = function (guestId) { - var base = this.proxies - base[guestId] != null ? base[guestId] : base[guestId] = new BrowserWindowProxy(guestId) - return base[guestId] + let proxy = this.proxies[guestId] + if (proxy == null) { + proxy = new BrowserWindowProxy(guestId) + this.proxies[guestId] = proxy + } + return proxy } BrowserWindowProxy.remove = function (guestId) { @@ -26,7 +31,7 @@ var BrowserWindowProxy = (function () { } function BrowserWindowProxy (guestId1) { - Object.defineProperty(this, 'guestId', { + defineProperty(this, 'guestId', { configurable: false, enumerable: true, writeable: false, @@ -56,7 +61,7 @@ var BrowserWindowProxy = (function () { ipcRenderer.send('ELECTRON_GUEST_WINDOW_MANAGER_WEB_CONTENTS_METHOD', this.guestId, 'print') } - Object.defineProperty(BrowserWindowProxy.prototype, 'location', { + defineProperty(BrowserWindowProxy.prototype, 'location', { get: function () { return ipcRenderer.sendSync('ELECTRON_GUEST_WINDOW_MANAGER_WEB_CONTENTS_METHOD_SYNC', this.guestId, 'getURL') }, @@ -83,13 +88,13 @@ var BrowserWindowProxy = (function () { if (process.guestInstanceId == null) { // Override default window.close. window.close = function () { - return remote.getCurrentWindow().close() + ipcRenderer.sendSync('ELECTRON_BROWSER_WINDOW_CLOSE') } } // Make the browser window or guest view emit "new-window" event. window.open = function (url, frameName, features) { - var guestId, j, len1, name, options, additionalFeatures + let guestId, j, len1, name, options, additionalFeatures if (frameName == null) { frameName = '' } @@ -160,29 +165,12 @@ window.open = function (url, frameName, features) { } } -// Use the dialog API to implement alert(). -window.alert = function (message = '', title = '') { - remote.dialog.showMessageBox(remote.getCurrentWindow(), { - message: String(message), - title: String(title), - buttons: ['OK'] - }) +window.alert = function (message, title) { + ipcRenderer.sendSync('ELECTRON_BROWSER_WINDOW_ALERT', message, title) } -// And the confirm(). window.confirm = function (message, title) { - var buttons, cancelId - if (title == null) { - title = '' - } - buttons = ['OK', 'Cancel'] - cancelId = 1 - return !remote.dialog.showMessageBox(remote.getCurrentWindow(), { - message: message, - title: title, - buttons: buttons, - cancelId: cancelId - }) + return ipcRenderer.sendSync('ELECTRON_BROWSER_WINDOW_CONFIRM', message, title) } // But we do not support prompt(). @@ -206,11 +194,11 @@ ipcRenderer.on('ELECTRON_GUEST_WINDOW_POSTMESSAGE', function (event, sourceId, m }) // Forward history operations to browser. -var sendHistoryOperation = function (...args) { +const sendHistoryOperation = function (...args) { ipcRenderer.send('ELECTRON_NAVIGATION_CONTROLLER', ...args) } -var getHistoryOperation = function (...args) { +const getHistoryOperation = function (...args) { return ipcRenderer.sendSync('ELECTRON_SYNC_NAVIGATION_CONTROLLER', ...args) } @@ -226,7 +214,7 @@ window.history.go = function (offset) { sendHistoryOperation('goToOffset', offset) } -Object.defineProperty(window.history, 'length', { +defineProperty(window.history, 'length', { get: function () { return getHistoryOperation('length') } @@ -244,13 +232,13 @@ ipcRenderer.on('ELECTRON_RENDERER_WINDOW_VISIBILITY_CHANGE', function (event, vi }) // Make document.hidden and document.visibilityState return the correct value. -Object.defineProperty(document, 'hidden', { +defineProperty(document, 'hidden', { get: function () { return cachedVisibilityState !== 'visible' } }) -Object.defineProperty(document, 'visibilityState', { +defineProperty(document, 'visibilityState', { get: function () { return cachedVisibilityState } From 3b99827540a8f6391aca8000f8aed1f78578f7f7 Mon Sep 17 00:00:00 2001 From: Kevin Sawicki Date: Thu, 1 Dec 2016 17:35:26 -0800 Subject: [PATCH 3/6] Coerce features to string --- lib/common/parse-features-string.js | 1 + 1 file changed, 1 insertion(+) diff --git a/lib/common/parse-features-string.js b/lib/common/parse-features-string.js index a700617e6c9e..d6682f639a10 100644 --- a/lib/common/parse-features-string.js +++ b/lib/common/parse-features-string.js @@ -2,6 +2,7 @@ // - `features` input string // - `emit` function(key, value) - called for each parsed KV module.exports = function parseFeaturesString (features, emit) { + features = `${features}` // split the string by ',' features.split(/,\s*/).forEach((feature) => { // expected form is either a key by itself or a key/value pair in the form of From de0ec9b33ccce1c577a9a073c27ec814f7007120 Mon Sep 17 00:00:00 2001 From: Kevin Sawicki Date: Thu, 1 Dec 2016 09:31:11 -0800 Subject: [PATCH 4/6] Tweak cancelId docs --- docs/api/dialog.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/docs/api/dialog.md b/docs/api/dialog.md index 8cebc727e488..97ab1e212a65 100644 --- a/docs/api/dialog.md +++ b/docs/api/dialog.md @@ -106,8 +106,8 @@ will be passed via `callback(filename)` * `cancelId` Integer (optional) - The value will be returned when user cancels the dialog instead of clicking the buttons of the dialog. By default it is the index of the buttons that have "cancel" or "no" as label, or 0 if there is no such - buttons. On macOS and Windows the index of "Cancel" button will always be - used as `cancelId`, not matter whether it is already specified. + buttons. On macOS and Windows the index of the "Cancel" button will always + be used as `cancelId` even if it is specified. * `noLink` Boolean (optional) - On Windows Electron will try to figure out which one of the `buttons` are common buttons (like "Cancel" or "Yes"), and show the others as command links in the dialog. This can make the dialog appear in From 1278e8cebc0a9fdbdf4341e8989dd6dff6e114b3 Mon Sep 17 00:00:00 2001 From: Kevin Sawicki Date: Fri, 2 Dec 2016 10:37:16 -0800 Subject: [PATCH 5/6] Remove unused variable --- lib/renderer/override.js | 1 - 1 file changed, 1 deletion(-) diff --git a/lib/renderer/override.js b/lib/renderer/override.js index a9cc19455b90..a05eb898bbc0 100644 --- a/lib/renderer/override.js +++ b/lib/renderer/override.js @@ -3,7 +3,6 @@ const {ipcRenderer} = require('electron') const parseFeaturesString = require('../common/parse-features-string') -const {captureStackTrace} = Error const {defineProperty} = Object // Helper function to resolve relative url. From d6d85ade8ed19095c31d9020a5f2d47a45d8597b Mon Sep 17 00:00:00 2001 From: Kevin Sawicki Date: Fri, 2 Dec 2016 10:37:27 -0800 Subject: [PATCH 6/6] :art: Assign binding as const --- lib/common/init.js | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/lib/common/init.js b/lib/common/init.js index b82102cf24d2..44939b52f41b 100644 --- a/lib/common/init.js +++ b/lib/common/init.js @@ -1,11 +1,13 @@ const timers = require('timers') +const {binding} = process + process.atomBinding = function (name) { try { - return process.binding(`atom_${process.type}_${name}`) + return binding(`atom_${process.type}_${name}`) } catch (error) { if (/No such module/.test(error.message)) { - return process.binding(`atom_common_${name}`) + return binding(`atom_common_${name}`) } else { throw error }