feat: add webContents.setWindowOpenHandler API (#24517)

Co-authored-by: Jeremy Rose <jeremya@chromium.org>
This commit is contained in:
loc 2020-11-10 09:06:03 -08:00 committed by GitHub
parent 6b222a2d8a
commit 0b85fdf26c
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
56 changed files with 2087 additions and 885 deletions

View file

@ -134,7 +134,7 @@ Returns:
Emitted when page receives favicon urls.
#### Event: 'new-window'
#### Event: 'new-window' _Deprecated_
Returns:
@ -155,6 +155,8 @@ Returns:
be set. If no post data is to be sent, the value will be `null`. Only defined
when the window is being created by a form that set `target=_blank`.
Deprecated in favor of [`webContents.setWindowOpenHandler`](web-contents.md#contentssetwindowopenhandler-handler).
Emitted when the page requests to open a new window for a `url`. It could be
requested by `window.open` or an external link like `<a target='_blank'>`.
@ -189,6 +191,39 @@ myBrowserWindow.webContents.on('new-window', (event, url, frameName, disposition
})
```
#### Event: 'did-create-window'
Returns:
* `window` BrowserWindow
* `details` Object
* `url` String - URL for the created window.
* `frameName` String - Name given to the created window in the
`window.open()` call.
* `options` BrowserWindowConstructorOptions - The options used to create the
BrowserWindow. They are merged in increasing precedence: options inherited
from the parent, parsed options from the `features` string from
`window.open()`, and options given by
[`webContents.setWindowOpenHandler`](web-contents.md#contentssetwindowopenhandler-handler).
Unrecognized options are not filtered out.
* `additionalFeatures` String[] - The non-standard features (features not
handled Chromium or Electron) _Deprecated_
* `referrer` [Referrer](structures/referrer.md) - The referrer that will be
passed to the new window. May or may not result in the `Referer` header
being sent, depending on the referrer policy.
* `postBody` [PostBody](structures/post-body.md) (optional) - The post data
that will be sent to the new window, along with the appropriate headers
that will be set. If no post data is to be sent, the value will be `null`.
Only defined when the window is being created by a form that set
`target=_blank`.
* `disposition` String - Can be `default`, `foreground-tab`,
`background-tab`, `new-window`, `save-to-disk` and `other`.
Emitted _after_ successful creation of a window via `window.open` in the renderer.
Not emitted if the creation of the window is canceled from
[`webContents.setWindowOpenHandler`](web-contents.md#contentssetwindowopenhandler-handler).
See [`window.open()`](window-open.md) for more details and how to use this in conjunction with `webContents.setWindowOpenHandler`.
#### Event: 'will-navigate'
Returns:
@ -1123,6 +1158,22 @@ Works like `executeJavaScript` but evaluates `scripts` in an isolated context.
Ignore application menu shortcuts while this web contents is focused.
#### `contents.setWindowOpenHandler(handler)`
* `handler` Function<{action: 'deny'} | {action: 'allow', overrideBrowserWindowOptions?: BrowserWindowConstructorOptions}>
* `details` Object
* `url` String - The _resolved_ version of the URL passed to `window.open()`. e.g. opening a window with `window.open('foo')` will yield something like `https://the-origin/the/current/path/foo`.
* `frameName` String - Name of the window provided in `window.open()`
* `features` String - Comma separated list of window features provided to `window.open()`.
Returns `{action: 'deny'} | {action: 'allow', overrideBrowserWindowOptions?: BrowserWindowConstructorOptions}` - `deny` cancels the creation of the new
window. `allow` will allow the new window to be created. Specifying `overrideBrowserWindowOptions` allows customization of the created window.
Returning an unrecognized value such as a null, undefined, or an object
without a recognized 'action' value will result in a console error and have
the same effect as returning `{action: 'deny'}`.
Called before creating a window when `window.open()` is called from the
renderer. See [`window.open()`](window-open.md) for more details and how to use this in conjunction with `did-create-window`.
#### `contents.setAudioMuted(muted)`
* `muted` Boolean

View file

@ -1,18 +1,34 @@
# `window.open` Function
# Opening windows from the renderer
> Open a new window and load a URL.
There are several ways to control how windows are created from trusted or
untrusted content within a renderer. Windows can be created from the renderer in two ways:
When `window.open` is called to create a new window in a web page, a new instance
of [`BrowserWindow`](browser-window.md) will be created for the `url` and a proxy will be returned
to `window.open` to let the page have limited control over it.
- clicking on links or submitting forms adorned with `target=_blank`
- JavaScript calling `window.open()`
The proxy has limited standard functionality implemented to be
compatible with traditional web pages. For full control of the new window
you should create a `BrowserWindow` directly.
In non-sandboxed renderers, or when `nativeWindowOpen` is false (the default), this results in the creation of a
[`BrowserWindowProxy`](browser-window-proxy.md), a light wrapper around
`BrowserWindow`.
The newly created `BrowserWindow` will inherit the parent window's options by
default. To override inherited options you can set them in the `features`
string.
However, when the `sandbox` (or directly, `nativeWindowOpen`) option is set, a
`Window` instance is created, as you'd expect in the browser. For same-origin
content, the new window is created within the same process, enabling the parent
to access the child window directly. This can be very useful for app sub-windows that act
as preference panels, or similar, as the parent can render to the sub-window
directly, as if it were a `div` in the parent.
Electron pairs this native Chrome `Window` with a BrowserWindow under the hood.
You can take advantage of all the customization available when creating a
BrowserWindow in the main process by using `webContents.setWindowOpenHandler()`
for renderer-created windows.
BrowserWindow constructor options are set by, in increasing precedence
order: options inherited from the parent, parsed options
from the `features` string from `window.open()`, security-related webPreferences
inherited from the parent, and options given by
[`webContents.setWindowOpenHandler`](web-contents.md#contentssetwindowopenhandler-handler).
Note that `webContents.setWindowOpenHandler` has final say and full privilege
because it is invoked in the main process.
### `window.open(url[, frameName][, features])`
@ -20,16 +36,22 @@ string.
* `frameName` String (optional)
* `features` String (optional)
Returns [`BrowserWindowProxy`](browser-window-proxy.md) - Creates a new window
and returns an instance of `BrowserWindowProxy` class.
Returns [`BrowserWindowProxy`](browser-window-proxy.md) | [`Window`](https://developer.mozilla.org/en-US/docs/Web/API/Window)
The `features` string follows the format of standard browser, but each feature
has to be a field of `BrowserWindow`'s options. These are the features you can set via `features` string: `zoomFactor`, `nodeIntegration`, `preload`, `javascript`, `contextIsolation`, `webviewTag`.
`features` is a comma-separated key-value list, following the standard format of
the browser. Electron will parse `BrowserWindowConstructorOptions` out of this
list where possible, for convenience. For full control and better ergonomics,
consider using `webContents.setWindowOpenHandler` to customize the
BrowserWindow creation.
A subset of `WebPreferences` can be set directly,
unnested, from the features string: `zoomFactor`, `nodeIntegration`, `preload`,
`javascript`, `contextIsolation`, and `webviewTag`.
For example:
```js
window.open('https://github.com', '_blank', 'nodeIntegration=no')
window.open('https://github.com', '_blank', 'top=500,left=200,frame=false,nodeIntegration=no')
```
**Notes:**
@ -41,60 +63,74 @@ window.open('https://github.com', '_blank', 'nodeIntegration=no')
* JavaScript will always be disabled in the opened `window` if it is disabled on
the parent window.
* Non-standard features (that are not handled by Chromium or Electron) given in
`features` will be passed to any registered `webContent`'s `new-window` event
handler in the `additionalFeatures` argument.
`features` will be passed to any registered `webContents`'s
`did-create-window` event handler in the `additionalFeatures` argument.
### `window.opener.postMessage(message, targetOrigin)`
To customize or cancel the creation of the window, you can optionally set an
override handler with `webContents.setWindowOpenHandler()` from the main
process. Returning `false` cancels the window, while returning an object sets
the `BrowserWindowConstructorOptions` used when creating the window. Note that
this is more powerful than passing options through the feature string, as the
renderer has more limited privileges in deciding security preferences than the
main process.
* `message` String
* `targetOrigin` String
Sends a message to the parent window with the specified origin or `*` for no
origin preference.
### Using Chrome's `window.open()` implementation
If you want to use Chrome's built-in `window.open()` implementation, set
`nativeWindowOpen` to `true` in the `webPreferences` options object.
Native `window.open()` allows synchronous access to opened windows so it is
convenient choice if you need to open a dialog or a preferences window.
This option can also be set on `<webview>` tags as well:
```html
<webview webpreferences="nativeWindowOpen=yes"></webview>
```
The creation of the `BrowserWindow` is customizable via `WebContents`'s
`new-window` event.
### `BrowserWindowProxy` example
```javascript
// main process
// main.js
const mainWindow = new BrowserWindow()
mainWindow.webContents.setWindowOpenHandler(({ url }) => {
if (url.startsWith('https://github.com/')) {
return true
}
return false
})
mainWindow.webContents.on('did-create-window', (childWindow) => {
// For example...
childWindow.webContents('will-navigate', (e) => {
e.preventDefault()
})
})
```
```javascript
// renderer.js
const windowProxy = window.open('https://github.com/', null, 'minimizable=false')
windowProxy.postMessage('hi', '*')
```
### Native `Window` example
```javascript
// main.js
const mainWindow = new BrowserWindow({
width: 800,
height: 600,
webPreferences: {
nativeWindowOpen: true
}
})
mainWindow.webContents.on('new-window', (event, url, frameName, disposition, options, additionalFeatures) => {
if (frameName === 'modal') {
// open window as modal
event.preventDefault()
Object.assign(options, {
modal: true,
parent: mainWindow,
width: 100,
height: 100
})
event.newGuest = new BrowserWindow(options)
// In this example, only windows with the `about:blank` url will be created.
// All other urls will be blocked.
mainWindow.webContents.setWindowOpenHandler(({ url }) => {
if (url === 'about:blank') {
return {
frame: false,
fullscreenable: false,
backgroundColor: 'black',
webPreferences: {
preload: 'my-child-window-preload-script.js'
}
}
}
return false
})
```
```javascript
// renderer process (mainWindow)
const modal = window.open('', 'modal')
modal.document.write('<h1>Hello</h1>')
const childWindow = window.open('', 'modal')
childWindow.document.write('<h1>Hello</h1>')
```