From 91af216c0a0dd3ac758286c43f59e790b462c308 Mon Sep 17 00:00:00 2001 From: Samuel Attard Date: Mon, 18 Nov 2019 17:22:48 -0800 Subject: [PATCH 1/2] feat: expose executeJavaScriptInIsolatedWorld on webContents --- docs/api/web-contents.md | 11 +++++++++++ lib/browser/api/web-contents.js | 27 +++++++++++++++------------ spec-main/api-web-contents-spec.ts | 19 +++++++++++++++++++ 3 files changed, 45 insertions(+), 12 deletions(-) diff --git a/docs/api/web-contents.md b/docs/api/web-contents.md index 163a0f9ac4623..3e7e0f86c5f1d 100644 --- a/docs/api/web-contents.md +++ b/docs/api/web-contents.md @@ -1031,6 +1031,17 @@ contents.executeJavaScript('fetch("https://jsonplaceholder.typicode.com/users/1" }) ``` +#### `contents.executeJavaScriptInIsolatedWorld(worldId, scripts[, userGesture])` + +* `worldId` Integer - The ID of the world to run the javascript in, `0` is the default world, `999` is the world used by Electrons `contextIsolation` feature. You can provide any integer here. +* `scripts` [WebSource[]](structures/web-source.md) +* `userGesture` Boolean (optional) - Default is `false`. + +Returns `Promise` - A promise that resolves with the result of the executed code +or is rejected if the result of the code is a rejected promise. + +Works like `executeJavaScript` but evaluates `scripts` in an isolated context. + #### `contents.setIgnoreMenuShortcuts(ignore)` _Experimental_ * `ignore` Boolean diff --git a/lib/browser/api/web-contents.js b/lib/browser/api/web-contents.js index 6b5f82ddb4c96..d8dd7b1d9c1f2 100644 --- a/lib/browser/api/web-contents.js +++ b/lib/browser/api/web-contents.js @@ -183,22 +183,25 @@ for (const method of webFrameMethods) { } } -const executeJavaScript = (contents, code, hasUserGesture) => { - return ipcMainUtils.invokeInWebContents(contents, false, 'ELECTRON_INTERNAL_RENDERER_WEB_FRAME_METHOD', 'executeJavaScript', code, hasUserGesture) +const waitTillCanExecuteJavaScript = async (webContents) => { + if (webContents.getURL() && !webContents.isLoadingMainFrame()) return + + return new Promise((resolve) => { + webContents.once('did-stop-loading', () => { + resolve() + }) + }) } // Make sure WebContents::executeJavaScript would run the code only when the // WebContents has been loaded. -WebContents.prototype.executeJavaScript = function (code, hasUserGesture) { - if (this.getURL() && !this.isLoadingMainFrame()) { - return executeJavaScript(this, code, hasUserGesture) - } else { - return new Promise((resolve, reject) => { - this.once('did-stop-loading', () => { - executeJavaScript(this, code, hasUserGesture).then(resolve, reject) - }) - }) - } +WebContents.prototype.executeJavaScript = async function (code, hasUserGesture) { + await waitTillCanExecuteJavaScript(this) + return ipcMainUtils.invokeInWebContents(this, false, 'ELECTRON_INTERNAL_RENDERER_WEB_FRAME_METHOD', 'executeJavaScript', code, hasUserGesture) +} +WebContents.prototype.executeJavaScriptInIsolatedWorld = async function (code, hasUserGesture) { + await waitTillCanExecuteJavaScript(this) + return ipcMainUtils.invokeInWebContents(this, false, 'ELECTRON_INTERNAL_RENDERER_WEB_FRAME_METHOD', 'executeJavaScriptInIsolatedWorld', code, hasUserGesture) } // Translate the options of printToPDF. diff --git a/spec-main/api-web-contents-spec.ts b/spec-main/api-web-contents-spec.ts index a15be8c4404d3..874bb6a0563dd 100644 --- a/spec-main/api-web-contents-spec.ts +++ b/spec-main/api-web-contents-spec.ts @@ -214,6 +214,25 @@ describe('webContents module', () => { }) }) + describe('webContents.executeJavaScriptInIsolatedWorld', () => { + let w: BrowserWindow + + before(async () => { + w = new BrowserWindow({ show: false, webPreferences: { contextIsolation: true } }) + await w.loadURL('about:blank') + }) + + it('resolves the returned promise with the result', async () => { + await w.webContents.executeJavaScriptInIsolatedWorld(999, [{ code: 'window.X = 123' }]) + const isolatedResult = await w.webContents.executeJavaScriptInIsolatedWorld(999, [{ code: 'window.X' }]) + console.log(isolatedResult) + const mainWorldResult = await w.webContents.executeJavaScript('window.X') + console.log(mainWorldResult) + expect(isolatedResult).to.equal(123) + expect(mainWorldResult).to.equal(undefined) + }) + }) + describe('loadURL() promise API', () => { let w: BrowserWindow beforeEach(async () => { From 3439752620cc0636b80e0e4095b4191506eb9f2f Mon Sep 17 00:00:00 2001 From: Samuel Attard Date: Wed, 20 Nov 2019 14:17:52 -0800 Subject: [PATCH 2/2] Apply suggestions from code review Co-Authored-By: loc --- docs/api/web-contents.md | 2 +- spec-main/api-web-contents-spec.ts | 2 -- 2 files changed, 1 insertion(+), 3 deletions(-) diff --git a/docs/api/web-contents.md b/docs/api/web-contents.md index 3e7e0f86c5f1d..cfa470875393a 100644 --- a/docs/api/web-contents.md +++ b/docs/api/web-contents.md @@ -1033,7 +1033,7 @@ contents.executeJavaScript('fetch("https://jsonplaceholder.typicode.com/users/1" #### `contents.executeJavaScriptInIsolatedWorld(worldId, scripts[, userGesture])` -* `worldId` Integer - The ID of the world to run the javascript in, `0` is the default world, `999` is the world used by Electrons `contextIsolation` feature. You can provide any integer here. +* `worldId` Integer - The ID of the world to run the javascript in, `0` is the default world, `999` is the world used by Electron's `contextIsolation` feature. You can provide any integer here. * `scripts` [WebSource[]](structures/web-source.md) * `userGesture` Boolean (optional) - Default is `false`. diff --git a/spec-main/api-web-contents-spec.ts b/spec-main/api-web-contents-spec.ts index 874bb6a0563dd..dd155a781c550 100644 --- a/spec-main/api-web-contents-spec.ts +++ b/spec-main/api-web-contents-spec.ts @@ -225,9 +225,7 @@ describe('webContents module', () => { it('resolves the returned promise with the result', async () => { await w.webContents.executeJavaScriptInIsolatedWorld(999, [{ code: 'window.X = 123' }]) const isolatedResult = await w.webContents.executeJavaScriptInIsolatedWorld(999, [{ code: 'window.X' }]) - console.log(isolatedResult) const mainWorldResult = await w.webContents.executeJavaScript('window.X') - console.log(mainWorldResult) expect(isolatedResult).to.equal(123) expect(mainWorldResult).to.equal(undefined) })