feat: remove deprecated additionalFeatures (#28548)

This commit is contained in:
Jeremy Rose 2021-04-19 15:46:54 -07:00 committed by GitHub
parent 8164322195
commit e12a3cb59c
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
7 changed files with 47 additions and 41 deletions

View file

@ -147,7 +147,8 @@ Returns:
* `options` BrowserWindowConstructorOptions - The options which will be used for creating the new * `options` BrowserWindowConstructorOptions - The options which will be used for creating the new
[`BrowserWindow`](browser-window.md). [`BrowserWindow`](browser-window.md).
* `additionalFeatures` String[] - The non-standard features (features not handled * `additionalFeatures` String[] - The non-standard features (features not handled
by Chromium or Electron) given to `window.open()`. by Chromium or Electron) given to `window.open()`. Deprecated, and will now
always be the empty array `[]`.
* `referrer` [Referrer](structures/referrer.md) - The referrer that will be * `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 passed to the new window. May or may not result in the `Referer` header being
sent, depending on the referrer policy. sent, depending on the referrer policy.
@ -207,8 +208,6 @@ Returns:
`window.open()`, and options given by `window.open()`, and options given by
[`webContents.setWindowOpenHandler`](web-contents.md#contentssetwindowopenhandlerhandler). [`webContents.setWindowOpenHandler`](web-contents.md#contentssetwindowopenhandlerhandler).
Unrecognized options are not filtered out. 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 * `referrer` [Referrer](structures/referrer.md) - The referrer that will be
passed to the new window. May or may not result in the `Referer` header passed to the new window. May or may not result in the `Referer` header
being sent, depending on the referrer policy. being sent, depending on the referrer policy.

View file

@ -63,7 +63,7 @@ window.open('https://github.com', '_blank', 'top=500,left=200,frame=false,nodeIn
the parent window. the parent window.
* Non-standard features (that are not handled by Chromium or Electron) given in * Non-standard features (that are not handled by Chromium or Electron) given in
`features` will be passed to any registered `webContents`'s `features` will be passed to any registered `webContents`'s
`did-create-window` event handler in the `additionalFeatures` argument. `did-create-window` event handler in the `options` argument.
* `frameName` follows the specification of `windowName` located in the [native documentation](https://developer.mozilla.org/en-US/docs/Web/API/Window/open#parameters). * `frameName` follows the specification of `windowName` located in the [native documentation](https://developer.mozilla.org/en-US/docs/Web/API/Window/open#parameters).
To customize or cancel the creation of the window, you can optionally set an To customize or cancel the creation of the window, you can optionally set an

View file

@ -38,6 +38,32 @@ to open synchronously scriptable child windows, among other incompatibilities.
See the documentation for [window.open in Electron](api/window-open.md) See the documentation for [window.open in Electron](api/window-open.md)
for more details. for more details.
### Removed: `additionalFeatures`
The deprecated `additionalFeatures` property in the `new-window` and
`did-create-window` events of WebContents has been removed. Since `new-window`
uses positional arguments, the argument is still present, but will always be
the empty array `[]`. (Though note, the `new-window` event itself is
deprecated, and is replaced by `setWindowOpenHandler`.) Bare keys in window
features will now present as keys with the value `true` in the options object.
```js
// Removed in Electron 14
// Triggered by window.open('...', '', 'my-key')
webContents.on('did-create-window', (window, details) => {
if (details.additionalFeatures.includes('my-key')) {
// ...
}
})
// Replace with
webContents.on('did-create-window', (window, details) => {
if (details.options['my-key']) {
// ...
}
})
```
## Planned Breaking API Changes (13.0) ## Planned Breaking API Changes (13.0)
### API Changed: `session.setPermissionCheckHandler(handler)` ### API Changed: `session.setPermissionCheckHandler(handler)`

View file

@ -42,7 +42,7 @@ export function openGuestWindow ({ event, embedder, guest, referrer, disposition
windowOpenArgs: WindowOpenArgs, windowOpenArgs: WindowOpenArgs,
}): BrowserWindow | undefined { }): BrowserWindow | undefined {
const { url, frameName, features } = windowOpenArgs; const { url, frameName, features } = windowOpenArgs;
const { options: browserWindowOptions, additionalFeatures } = makeBrowserWindowOptions({ const { options: browserWindowOptions } = makeBrowserWindowOptions({
embedder, embedder,
features, features,
overrideOptions: overrideBrowserWindowOptions overrideOptions: overrideBrowserWindowOptions
@ -54,7 +54,6 @@ export function openGuestWindow ({ event, embedder, guest, referrer, disposition
guest, guest,
browserWindowOptions, browserWindowOptions,
windowOpenArgs, windowOpenArgs,
additionalFeatures,
disposition, disposition,
postData, postData,
referrer referrer
@ -93,7 +92,7 @@ export function openGuestWindow ({ event, embedder, guest, referrer, disposition
handleWindowLifecycleEvents({ embedder, frameName, guest: window }); handleWindowLifecycleEvents({ embedder, frameName, guest: window });
embedder.emit('did-create-window', window, { url, frameName, options: browserWindowOptions, disposition, additionalFeatures, referrer, postData }); embedder.emit('did-create-window', window, { url, frameName, options: browserWindowOptions, disposition, referrer, postData });
return window; return window;
} }
@ -134,13 +133,12 @@ const handleWindowLifecycleEvents = function ({ embedder, guest, frameName }: {
* Deprecated in favor of `webContents.setWindowOpenHandler` and * Deprecated in favor of `webContents.setWindowOpenHandler` and
* `did-create-window` in 11.0.0. Will be removed in 12.0.0. * `did-create-window` in 11.0.0. Will be removed in 12.0.0.
*/ */
function emitDeprecatedNewWindowEvent ({ event, embedder, guest, windowOpenArgs, browserWindowOptions, additionalFeatures, disposition, referrer, postData }: { function emitDeprecatedNewWindowEvent ({ event, embedder, guest, windowOpenArgs, browserWindowOptions, disposition, referrer, postData }: {
event: { sender: WebContents, defaultPrevented: boolean, newGuest?: BrowserWindow }, event: { sender: WebContents, defaultPrevented: boolean, newGuest?: BrowserWindow },
embedder: WebContents, embedder: WebContents,
guest?: WebContents, guest?: WebContents,
windowOpenArgs: WindowOpenArgs, windowOpenArgs: WindowOpenArgs,
browserWindowOptions: BrowserWindowConstructorOptions, browserWindowOptions: BrowserWindowConstructorOptions,
additionalFeatures: string[]
disposition: string, disposition: string,
referrer: Referrer, referrer: Referrer,
postData?: PostData, postData?: PostData,
@ -162,7 +160,7 @@ function emitDeprecatedNewWindowEvent ({ event, embedder, guest, windowOpenArgs,
...browserWindowOptions, ...browserWindowOptions,
webContents: guest webContents: guest
}, },
additionalFeatures, [], // additionalFeatures
referrer, referrer,
postBody postBody
); );
@ -200,19 +198,17 @@ const securityWebPreferences: { [key: string]: boolean } = {
enableWebSQL: false enableWebSQL: false
}; };
function makeBrowserWindowOptions ({ embedder, features, overrideOptions, useDeprecatedBehaviorForBareValues = true, useDeprecatedBehaviorForOptionInheritance = true }: { function makeBrowserWindowOptions ({ embedder, features, overrideOptions, useDeprecatedBehaviorForOptionInheritance = true }: {
embedder: WebContents, embedder: WebContents,
features: string, features: string,
overrideOptions?: BrowserWindowConstructorOptions, overrideOptions?: BrowserWindowConstructorOptions,
useDeprecatedBehaviorForBareValues?: boolean
useDeprecatedBehaviorForOptionInheritance?: boolean useDeprecatedBehaviorForOptionInheritance?: boolean
}) { }) {
const { options: parsedOptions, webPreferences: parsedWebPreferences, additionalFeatures } = parseFeatures(features, useDeprecatedBehaviorForBareValues); const { options: parsedOptions, webPreferences: parsedWebPreferences } = parseFeatures(features);
const deprecatedInheritedOptions = getDeprecatedInheritedOptions(embedder); const deprecatedInheritedOptions = getDeprecatedInheritedOptions(embedder);
return { return {
additionalFeatures,
options: { options: {
...(useDeprecatedBehaviorForOptionInheritance && deprecatedInheritedOptions), ...(useDeprecatedBehaviorForOptionInheritance && deprecatedInheritedOptions),
show: true, show: true,
@ -232,7 +228,6 @@ export function makeWebPreferences ({ embedder, secureOverrideWebPreferences = {
// sourced from the main process, as they override security defaults. If you // sourced from the main process, as they override security defaults. If you
// have unvetted prefs, use parsedWebPreferences. // have unvetted prefs, use parsedWebPreferences.
secureOverrideWebPreferences?: BrowserWindowConstructorOptions['webPreferences'], secureOverrideWebPreferences?: BrowserWindowConstructorOptions['webPreferences'],
useDeprecatedBehaviorForBareValues?: boolean
useDeprecatedBehaviorForOptionInheritance?: boolean useDeprecatedBehaviorForOptionInheritance?: boolean
}) { }) {
const deprecatedInheritedOptions = getDeprecatedInheritedOptions(embedder); const deprecatedInheritedOptions = getDeprecatedInheritedOptions(embedder);

View file

@ -56,23 +56,18 @@ function coerce (key: string, value: string): CoercedValue {
} }
} }
export function parseCommaSeparatedKeyValue (source: string, useSoonToBeDeprecatedBehaviorForBareKeys: boolean) { export function parseCommaSeparatedKeyValue (source: string) {
const bareKeys = [] as string[];
const parsed = {} as { [key: string]: any }; const parsed = {} as { [key: string]: any };
for (const keyValuePair of source.split(',')) { for (const keyValuePair of source.split(',')) {
const [key, value] = keyValuePair.split('=').map(str => str.trim()); const [key, value] = keyValuePair.split('=').map(str => str.trim());
if (useSoonToBeDeprecatedBehaviorForBareKeys && value === undefined) { if (key) { parsed[key] = coerce(key, value); }
if (key) { bareKeys.push(key); }
continue;
}
parsed[key] = coerce(key, value);
} }
return { parsed, bareKeys }; return parsed;
} }
export function parseWebViewWebPreferences (preferences: string) { export function parseWebViewWebPreferences (preferences: string) {
return parseCommaSeparatedKeyValue(preferences, false).parsed; return parseCommaSeparatedKeyValue(preferences);
} }
const allowedWebPreferences = ['zoomFactor', 'nodeIntegration', 'javascript', 'contextIsolation', 'webviewTag'] as const; const allowedWebPreferences = ['zoomFactor', 'nodeIntegration', 'javascript', 'contextIsolation', 'webviewTag'] as const;
@ -80,17 +75,9 @@ type AllowedWebPreference = (typeof allowedWebPreferences)[number];
/** /**
* Parses a feature string that has the format used in window.open(). * Parses a feature string that has the format used in window.open().
*
* `useSoonToBeDeprecatedBehaviorForBareKeys` - In the html spec, windowFeatures keys
* without values are interpreted as `true`. Previous versions of Electron did
* not respect this. In order to not break any applications, this will be
* flipped in the next major version.
*/ */
export function parseFeatures ( export function parseFeatures (features: string) {
features: string, const parsed = parseCommaSeparatedKeyValue(features);
useSoonToBeDeprecatedBehaviorForBareKeys: boolean = true
) {
const { parsed, bareKeys } = parseCommaSeparatedKeyValue(features, useSoonToBeDeprecatedBehaviorForBareKeys);
const webPreferences: { [K in AllowedWebPreference]?: any } = {}; const webPreferences: { [K in AllowedWebPreference]?: any } = {};
allowedWebPreferences.forEach((key) => { allowedWebPreferences.forEach((key) => {
@ -104,7 +91,6 @@ export function parseFeatures (
return { return {
options: parsed as Omit<BrowserWindowConstructorOptions, 'webPreferences'>, options: parsed as Omit<BrowserWindowConstructorOptions, 'webPreferences'>,
webPreferences, webPreferences
additionalFeatures: bareKeys
}; };
} }

View file

@ -3003,12 +3003,12 @@ describe('BrowserWindow module', () => {
it('emits when window.open is called', (done) => { it('emits when window.open is called', (done) => {
const w = new BrowserWindow({ show: false, webPreferences: { nodeIntegration: true } }); const w = new BrowserWindow({ show: false, webPreferences: { nodeIntegration: true } });
w.webContents.once('new-window', (e, url, frameName, disposition, options, additionalFeatures) => { w.webContents.once('new-window', (e, url, frameName, disposition, options) => {
e.preventDefault(); e.preventDefault();
try { try {
expect(url).to.equal('http://host/'); expect(url).to.equal('http://host/');
expect(frameName).to.equal('host'); expect(frameName).to.equal('host');
expect(additionalFeatures[0]).to.equal('this-is-not-a-standard-feature'); expect((options as any)['this-is-not-a-standard-feature']).to.equal(true);
done(); done();
} catch (e) { } catch (e) {
done(e); done(e);
@ -3019,12 +3019,12 @@ describe('BrowserWindow module', () => {
it('emits when window.open is called with no webPreferences', (done) => { it('emits when window.open is called with no webPreferences', (done) => {
const w = new BrowserWindow({ show: false }); const w = new BrowserWindow({ show: false });
w.webContents.once('new-window', function (e, url, frameName, disposition, options, additionalFeatures) { w.webContents.once('new-window', function (e, url, frameName, disposition, options) {
e.preventDefault(); e.preventDefault();
try { try {
expect(url).to.equal('http://host/'); expect(url).to.equal('http://host/');
expect(frameName).to.equal('host'); expect(frameName).to.equal('host');
expect(additionalFeatures[0]).to.equal('this-is-not-a-standard-feature'); expect((options as any)['this-is-not-a-standard-feature']).to.equal(true);
done(); done();
} catch (e) { } catch (e) {
done(e); done(e);

View file

@ -4,7 +4,7 @@ describe('feature-string parsing', () => {
it('is indifferent to whitespace around keys and values', () => { it('is indifferent to whitespace around keys and values', () => {
const { parseCommaSeparatedKeyValue } = require('../lib/common/parse-features-string'); const { parseCommaSeparatedKeyValue } = require('../lib/common/parse-features-string');
const checkParse = (string: string, parsed: Record<string, string | boolean>) => { const checkParse = (string: string, parsed: Record<string, string | boolean>) => {
const features = parseCommaSeparatedKeyValue(string, true).parsed; const features = parseCommaSeparatedKeyValue(string);
expect(features).to.deep.equal(parsed); expect(features).to.deep.equal(parsed);
}; };
checkParse('a=yes,c=d', { a: true, c: 'd' }); checkParse('a=yes,c=d', { a: true, c: 'd' });