Skip to content

Commit

Permalink
feat: expose executeJavaScriptInIsolatedWorld on webContents (#21267)
Browse files Browse the repository at this point in the history
* feat: expose executeJavaScriptInIsolatedWorld on webContents

* Apply suggestions from code review

Co-Authored-By: loc <andy@slack-corp.com>
  • Loading branch information
2 people authored and MarshallOfSound committed Nov 23, 2019
1 parent 88375be commit 88c1f2c
Show file tree
Hide file tree
Showing 3 changed files with 43 additions and 12 deletions.
11 changes: 11 additions & 0 deletions docs/api/web-contents.md
Expand Up @@ -1042,6 +1042,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 Electron's `contextIsolation` feature. You can provide any integer here.
* `scripts` [WebSource[]](structures/web-source.md)
* `userGesture` Boolean (optional) - Default is `false`.

Returns `Promise<any>` - 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
Expand Down
27 changes: 15 additions & 12 deletions lib/browser/api/web-contents.js
Expand Up @@ -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.
Expand Down
17 changes: 17 additions & 0 deletions spec-main/api-web-contents-spec.ts
Expand Up @@ -219,6 +219,23 @@ 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' }])
const mainWorldResult = await w.webContents.executeJavaScript('window.X')
expect(isolatedResult).to.equal(123)
expect(mainWorldResult).to.equal(undefined)
})
})

describe('loadURL() promise API', () => {
let w: BrowserWindow
beforeEach(async () => {
Expand Down

0 comments on commit 88c1f2c

Please sign in to comment.