feat: enhance native window.open to match the custom implementation's behavior (#19703)
Co-authored-by: Andy Locascio <andy@slack-corp.com>
This commit is contained in:
parent
b1f4ac00f0
commit
74372d65ae
20 changed files with 350 additions and 143 deletions
23
docs/api/structures/post-body.md
Normal file
23
docs/api/structures/post-body.md
Normal file
|
@ -0,0 +1,23 @@
|
||||||
|
# PostBody Object
|
||||||
|
|
||||||
|
* `data` Array<[PostData](./post-data.md)> - The post data to be sent to the
|
||||||
|
new window.
|
||||||
|
* `contentType` String - The `content-type` header used for the data. One of
|
||||||
|
`application/x-www-form-urlencoded` or `multipart/form-data`. Corresponds to
|
||||||
|
the `enctype` attribute of the submitted HTML form.
|
||||||
|
* `boundary` String (optional) - The boundary used to separate multiple parts of
|
||||||
|
the message. Only valid when `contentType` is `multipart/form-data`.
|
||||||
|
|
||||||
|
Note that keys starting with `--` are not currently supported. For example, this will errantly submit as `multipart/form-data` when `nativeWindowOpen` is set to `false` in webPreferences:
|
||||||
|
|
||||||
|
```html
|
||||||
|
<form
|
||||||
|
target="_blank"
|
||||||
|
method="POST"
|
||||||
|
enctype="application/x-www-form-urlencoded"
|
||||||
|
action="https://postman-echo.com/post"
|
||||||
|
>
|
||||||
|
<input type="text" name="--theKey">
|
||||||
|
<input type="submit">
|
||||||
|
</form>
|
||||||
|
```
|
21
docs/api/structures/post-data.md
Normal file
21
docs/api/structures/post-data.md
Normal file
|
@ -0,0 +1,21 @@
|
||||||
|
# PostData Object
|
||||||
|
|
||||||
|
* `type` String - One of the following:
|
||||||
|
* `rawData` - The data is available as a `Buffer`, in the `rawData` field.
|
||||||
|
* `file` - The object represents a file. The `filePath`, `offset`, `length`
|
||||||
|
and `modificationTime` fields will be used to describe the file.
|
||||||
|
* `blob` - The object represents a `Blob`. The `blobUUID` field will be used
|
||||||
|
to describe the `Blob`.
|
||||||
|
* `bytes` String (optional) - The raw bytes of the post data in a `Buffer`.
|
||||||
|
Required for the `rawData` type.
|
||||||
|
* `filePath` String (optional) - The path of the file being uploaded. Required
|
||||||
|
for the `file` type.
|
||||||
|
* `blobUUID` String (optional) - The `UUID` of the `Blob` being uploaded.
|
||||||
|
Required for the `blob` type.
|
||||||
|
* `offset` Integer (optional) - The offset from the beginning of the file being
|
||||||
|
uploaded, in bytes. Only valid for `file` types.
|
||||||
|
* `length` Integer (optional) - The length of the file being uploaded, in bytes.
|
||||||
|
If set to `-1`, the whole file will be uploaded. Only valid for `file` types.
|
||||||
|
* `modificationTime` Double (optional) - The modification time of the file
|
||||||
|
represented by a double, which is the number of seconds since the `UNIX Epoch`
|
||||||
|
(Jan 1, 1970). Only valid for `file` types.
|
|
@ -150,6 +150,10 @@ Returns:
|
||||||
* `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.
|
||||||
|
* `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`.
|
||||||
|
|
||||||
Emitted when the page requests to open a new window for a `url`. It could be
|
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'>`.
|
requested by `window.open` or an external link like `<a target='_blank'>`.
|
||||||
|
@ -162,7 +166,7 @@ new [`BrowserWindow`](browser-window.md). If you call `event.preventDefault()` a
|
||||||
instance, failing to do so may result in unexpected behavior. For example:
|
instance, failing to do so may result in unexpected behavior. For example:
|
||||||
|
|
||||||
```javascript
|
```javascript
|
||||||
myBrowserWindow.webContents.on('new-window', (event, url, frameName, disposition, options) => {
|
myBrowserWindow.webContents.on('new-window', (event, url, frameName, disposition, options, additionalFeatures, referrer, postBody) => {
|
||||||
event.preventDefault()
|
event.preventDefault()
|
||||||
const win = new BrowserWindow({
|
const win = new BrowserWindow({
|
||||||
webContents: options.webContents, // use existing webContents if provided
|
webContents: options.webContents, // use existing webContents if provided
|
||||||
|
@ -170,7 +174,16 @@ myBrowserWindow.webContents.on('new-window', (event, url, frameName, disposition
|
||||||
})
|
})
|
||||||
win.once('ready-to-show', () => win.show())
|
win.once('ready-to-show', () => win.show())
|
||||||
if (!options.webContents) {
|
if (!options.webContents) {
|
||||||
win.loadURL(url) // existing webContents will be navigated automatically
|
const loadOptions = {
|
||||||
|
httpReferrer: referrer
|
||||||
|
}
|
||||||
|
if (postBody != null) {
|
||||||
|
const { data, contentType, boundary } = postBody
|
||||||
|
loadOptions.postData = postBody.data
|
||||||
|
loadOptions.extraHeaders = `content-type: ${contentType}; boundary=${boundary}`
|
||||||
|
}
|
||||||
|
|
||||||
|
win.loadURL(url, loadOptions) // existing webContents will be navigated automatically
|
||||||
}
|
}
|
||||||
event.newGuest = win
|
event.newGuest = win
|
||||||
})
|
})
|
||||||
|
|
|
@ -102,6 +102,8 @@ auto_filenames = {
|
||||||
"docs/api/structures/mouse-wheel-input-event.md",
|
"docs/api/structures/mouse-wheel-input-event.md",
|
||||||
"docs/api/structures/notification-action.md",
|
"docs/api/structures/notification-action.md",
|
||||||
"docs/api/structures/point.md",
|
"docs/api/structures/point.md",
|
||||||
|
"docs/api/structures/post-body.md",
|
||||||
|
"docs/api/structures/post-data.md",
|
||||||
"docs/api/structures/printer-info.md",
|
"docs/api/structures/printer-info.md",
|
||||||
"docs/api/structures/process-memory-info.md",
|
"docs/api/structures/process-memory-info.md",
|
||||||
"docs/api/structures/process-metric.md",
|
"docs/api/structures/process-metric.md",
|
||||||
|
|
|
@ -126,7 +126,6 @@ class SlurpStream extends Writable {
|
||||||
this._data = Buffer.concat([this._data, chunk]);
|
this._data = Buffer.concat([this._data, chunk]);
|
||||||
callback();
|
callback();
|
||||||
}
|
}
|
||||||
|
|
||||||
data () { return this._data; }
|
data () { return this._data; }
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -11,6 +11,7 @@ const { internalWindowOpen } = require('@electron/internal/browser/guest-window-
|
||||||
const NavigationController = require('@electron/internal/browser/navigation-controller');
|
const NavigationController = require('@electron/internal/browser/navigation-controller');
|
||||||
const { ipcMainInternal } = require('@electron/internal/browser/ipc-main-internal');
|
const { ipcMainInternal } = require('@electron/internal/browser/ipc-main-internal');
|
||||||
const ipcMainUtils = require('@electron/internal/browser/ipc-main-internal-utils');
|
const ipcMainUtils = require('@electron/internal/browser/ipc-main-internal-utils');
|
||||||
|
const { convertFeaturesString } = require('@electron/internal/common/parse-features-string');
|
||||||
const { MessagePortMain } = require('@electron/internal/browser/message-port-main');
|
const { MessagePortMain } = require('@electron/internal/browser/message-port-main');
|
||||||
|
|
||||||
// session is not used here, the purpose is to make sure session is initalized
|
// session is not used here, the purpose is to make sure session is initalized
|
||||||
|
@ -506,40 +507,42 @@ WebContents.prototype._init = function () {
|
||||||
this.reload();
|
this.reload();
|
||||||
});
|
});
|
||||||
|
|
||||||
// Handle window.open for BrowserWindow and BrowserView.
|
if (this.getType() !== 'remote') {
|
||||||
if (['browserView', 'window'].includes(this.getType())) {
|
|
||||||
// Make new windows requested by links behave like "window.open".
|
// Make new windows requested by links behave like "window.open".
|
||||||
this.on('-new-window', (event, url, frameName, disposition,
|
this.on('-new-window', (event, url, frameName, disposition,
|
||||||
additionalFeatures, postData,
|
rawFeatures, referrer, postData) => {
|
||||||
referrer) => {
|
const { options, additionalFeatures } = convertFeaturesString(rawFeatures, frameName);
|
||||||
const options = {
|
const mergedOptions = {
|
||||||
show: true,
|
show: true,
|
||||||
width: 800,
|
width: 800,
|
||||||
height: 600
|
height: 600,
|
||||||
|
...options
|
||||||
};
|
};
|
||||||
internalWindowOpen(event, url, referrer, frameName, disposition, options, additionalFeatures, postData);
|
|
||||||
|
internalWindowOpen(event, url, referrer, frameName, disposition, mergedOptions, additionalFeatures, postData);
|
||||||
});
|
});
|
||||||
|
|
||||||
// Create a new browser window for the native implementation of
|
// Create a new browser window for the native implementation of
|
||||||
// "window.open", used in sandbox and nativeWindowOpen mode.
|
// "window.open", used in sandbox and nativeWindowOpen mode.
|
||||||
this.on('-add-new-contents', (event, webContents, disposition,
|
this.on('-add-new-contents', (event, webContents, disposition,
|
||||||
userGesture, left, top, width, height, url, frameName) => {
|
userGesture, left, top, width, height, url, frameName,
|
||||||
|
referrer, rawFeatures, postData) => {
|
||||||
if ((disposition !== 'foreground-tab' && disposition !== 'new-window' &&
|
if ((disposition !== 'foreground-tab' && disposition !== 'new-window' &&
|
||||||
disposition !== 'background-tab')) {
|
disposition !== 'background-tab')) {
|
||||||
event.preventDefault();
|
event.preventDefault();
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
const options = {
|
const { options, additionalFeatures } = convertFeaturesString(rawFeatures, frameName);
|
||||||
|
const mergedOptions = {
|
||||||
show: true,
|
show: true,
|
||||||
x: left,
|
width: 800,
|
||||||
y: top,
|
height: 600,
|
||||||
width: width || 800,
|
webContents,
|
||||||
height: height || 600,
|
...options
|
||||||
webContents
|
|
||||||
};
|
};
|
||||||
const referrer = { url: '', policy: 'default' };
|
|
||||||
internalWindowOpen(event, url, referrer, frameName, disposition, options);
|
internalWindowOpen(event, url, referrer, frameName, disposition, mergedOptions, additionalFeatures, postData);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -3,7 +3,7 @@
|
||||||
const { webContents } = require('electron');
|
const { webContents } = require('electron');
|
||||||
const { ipcMainInternal } = require('@electron/internal/browser/ipc-main-internal');
|
const { ipcMainInternal } = require('@electron/internal/browser/ipc-main-internal');
|
||||||
const ipcMainUtils = require('@electron/internal/browser/ipc-main-internal-utils');
|
const ipcMainUtils = require('@electron/internal/browser/ipc-main-internal-utils');
|
||||||
const parseFeaturesString = require('@electron/internal/common/parse-features-string');
|
const { parseFeaturesString } = require('@electron/internal/common/parse-features-string');
|
||||||
const { syncMethods, asyncMethods, properties } = require('@electron/internal/common/web-view-methods');
|
const { syncMethods, asyncMethods, properties } = require('@electron/internal/common/web-view-methods');
|
||||||
const { serialize } = require('@electron/internal/common/type-utils');
|
const { serialize } = require('@electron/internal/common/type-utils');
|
||||||
|
|
||||||
|
@ -141,17 +141,6 @@ const createGuest = function (embedder, params) {
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
// Forward internal web contents event to embedder to handle
|
|
||||||
// native window.open setup
|
|
||||||
guest.on('-add-new-contents', (...args) => {
|
|
||||||
if (guest.getLastWebPreferences().nativeWindowOpen === true) {
|
|
||||||
const embedder = getEmbedder(guestInstanceId);
|
|
||||||
if (embedder != null) {
|
|
||||||
embedder.emit('-add-new-contents', ...args);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
return guestInstanceId;
|
return guestInstanceId;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
@ -5,7 +5,7 @@ const { BrowserWindow } = electron;
|
||||||
const { isSameOrigin } = process.electronBinding('v8_util');
|
const { isSameOrigin } = process.electronBinding('v8_util');
|
||||||
const { ipcMainInternal } = require('@electron/internal/browser/ipc-main-internal');
|
const { ipcMainInternal } = require('@electron/internal/browser/ipc-main-internal');
|
||||||
const ipcMainUtils = require('@electron/internal/browser/ipc-main-internal-utils');
|
const ipcMainUtils = require('@electron/internal/browser/ipc-main-internal-utils');
|
||||||
const parseFeaturesString = require('@electron/internal/common/parse-features-string');
|
const { convertFeaturesString } = require('@electron/internal/common/parse-features-string');
|
||||||
|
|
||||||
const hasProp = {}.hasOwnProperty;
|
const hasProp = {}.hasOwnProperty;
|
||||||
const frameToGuest = new Map();
|
const frameToGuest = new Map();
|
||||||
|
@ -57,7 +57,11 @@ const mergeBrowserWindowOptions = function (embedder, options) {
|
||||||
// if parent's visibility is available, that overrides 'show' flag (#12125)
|
// if parent's visibility is available, that overrides 'show' flag (#12125)
|
||||||
const win = BrowserWindow.fromWebContents(embedder.webContents);
|
const win = BrowserWindow.fromWebContents(embedder.webContents);
|
||||||
if (win != null) {
|
if (win != null) {
|
||||||
parentOptions = { ...embedder.browserWindowOptions, show: win.isVisible() };
|
parentOptions = {
|
||||||
|
...win.getBounds(),
|
||||||
|
...embedder.browserWindowOptions,
|
||||||
|
show: win.isVisible()
|
||||||
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
// Inherit the original options if it is a BrowserWindow.
|
// Inherit the original options if it is a BrowserWindow.
|
||||||
|
@ -83,6 +87,40 @@ const mergeBrowserWindowOptions = function (embedder, options) {
|
||||||
return options;
|
return options;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
const MULTIPART_CONTENT_TYPE = 'multipart/form-data';
|
||||||
|
const URL_ENCODED_CONTENT_TYPE = 'application/x-www-form-urlencoded';
|
||||||
|
function makeContentTypeHeader ({ contentType, boundary }) {
|
||||||
|
const header = `content-type: ${contentType};`;
|
||||||
|
if (contentType === MULTIPART_CONTENT_TYPE) {
|
||||||
|
return `${header} boundary=${boundary}`;
|
||||||
|
}
|
||||||
|
return header;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Figure out appropriate headers for post data.
|
||||||
|
const parseContentTypeFormat = function (postData) {
|
||||||
|
if (postData.length) {
|
||||||
|
// For multipart forms, the first element will start with the boundary
|
||||||
|
// notice, which looks something like `------WebKitFormBoundary12345678`
|
||||||
|
// Note, this regex would fail when submitting a urlencoded form with an
|
||||||
|
// input attribute of name="--theKey", but, uhh, don't do that?
|
||||||
|
const postDataFront = postData[0].bytes.toString();
|
||||||
|
const boundary = /^--.*[^-\r\n]/.exec(postDataFront);
|
||||||
|
if (boundary) {
|
||||||
|
return {
|
||||||
|
boundary: boundary[0].substr(2),
|
||||||
|
contentType: MULTIPART_CONTENT_TYPE
|
||||||
|
};
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// Either the form submission didn't contain any inputs (the postData array
|
||||||
|
// was empty), or we couldn't find the boundary and thus we can assume this is
|
||||||
|
// a key=value style form.
|
||||||
|
return {
|
||||||
|
contentType: URL_ENCODED_CONTENT_TYPE
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
// Setup a new guest with |embedder|
|
// Setup a new guest with |embedder|
|
||||||
const setupGuest = function (embedder, frameName, guest, options) {
|
const setupGuest = function (embedder, frameName, guest, options) {
|
||||||
// When |embedder| is destroyed we should also destroy attached guest, and if
|
// When |embedder| is destroyed we should also destroy attached guest, and if
|
||||||
|
@ -134,14 +172,7 @@ const createGuest = function (embedder, url, referrer, frameName, options, postD
|
||||||
};
|
};
|
||||||
if (postData != null) {
|
if (postData != null) {
|
||||||
loadOptions.postData = postData;
|
loadOptions.postData = postData;
|
||||||
loadOptions.extraHeaders = 'content-type: application/x-www-form-urlencoded';
|
loadOptions.extraHeaders = makeContentTypeHeader(parseContentTypeFormat(postData));
|
||||||
if (postData.length > 0) {
|
|
||||||
const postDataFront = postData[0].bytes.toString();
|
|
||||||
const boundary = /^--.*[^-\r\n]/.exec(postDataFront);
|
|
||||||
if (boundary != null) {
|
|
||||||
loadOptions.extraHeaders = `content-type: multipart/form-data; boundary=${boundary[0].substr(2)}`;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
guest.loadURL(url, loadOptions);
|
guest.loadURL(url, loadOptions);
|
||||||
}
|
}
|
||||||
|
@ -192,68 +223,21 @@ ipcMainInternal.on('ELECTRON_GUEST_WINDOW_MANAGER_WINDOW_OPEN', (event, url, fra
|
||||||
if (frameName == null) frameName = '';
|
if (frameName == null) frameName = '';
|
||||||
if (features == null) features = '';
|
if (features == null) features = '';
|
||||||
|
|
||||||
const options = {};
|
|
||||||
|
|
||||||
const ints = ['x', 'y', 'width', 'height', 'minWidth', 'maxWidth', 'minHeight', 'maxHeight', 'zoomFactor'];
|
|
||||||
const webPreferences = ['zoomFactor', 'nodeIntegration', 'enableRemoteModule', 'preload', 'javascript', 'contextIsolation', 'webviewTag'];
|
|
||||||
const disposition = 'new-window';
|
const disposition = 'new-window';
|
||||||
|
const { options, additionalFeatures } = convertFeaturesString(features, frameName);
|
||||||
// Used to store additional features
|
|
||||||
const additionalFeatures = [];
|
|
||||||
|
|
||||||
// Parse the features
|
|
||||||
parseFeaturesString(features, function (key, value) {
|
|
||||||
if (value === undefined) {
|
|
||||||
additionalFeatures.push(key);
|
|
||||||
} else {
|
|
||||||
// Don't allow webPreferences to be set since it must be an object
|
|
||||||
// that cannot be directly overridden
|
|
||||||
if (key === 'webPreferences') return;
|
|
||||||
|
|
||||||
if (webPreferences.includes(key)) {
|
|
||||||
if (options.webPreferences == null) {
|
|
||||||
options.webPreferences = {};
|
|
||||||
}
|
|
||||||
options.webPreferences[key] = value;
|
|
||||||
} else {
|
|
||||||
options[key] = value;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
});
|
|
||||||
if (options.left) {
|
|
||||||
if (options.x == null) {
|
|
||||||
options.x = options.left;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if (options.top) {
|
|
||||||
if (options.y == null) {
|
|
||||||
options.y = options.top;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if (options.title == null) {
|
|
||||||
options.title = frameName;
|
|
||||||
}
|
|
||||||
if (options.width == null) {
|
|
||||||
options.width = 800;
|
|
||||||
}
|
|
||||||
if (options.height == null) {
|
|
||||||
options.height = 600;
|
|
||||||
}
|
|
||||||
|
|
||||||
for (const name of ints) {
|
|
||||||
if (options[name] != null) {
|
|
||||||
options[name] = parseInt(options[name], 10);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
const referrer = { url: '', policy: 'default' };
|
const referrer = { url: '', policy: 'default' };
|
||||||
internalWindowOpen(event, url, referrer, frameName, disposition, options, additionalFeatures);
|
internalWindowOpen(event, url, referrer, frameName, disposition, options, additionalFeatures, null);
|
||||||
});
|
});
|
||||||
|
|
||||||
// Routed window.open messages with fully parsed options
|
// Routed window.open messages with fully parsed options
|
||||||
function internalWindowOpen (event, url, referrer, frameName, disposition, options, additionalFeatures, postData) {
|
function internalWindowOpen (event, url, referrer, frameName, disposition, options, additionalFeatures, postData) {
|
||||||
options = mergeBrowserWindowOptions(event.sender, options);
|
options = mergeBrowserWindowOptions(event.sender, options);
|
||||||
event.sender.emit('new-window', event, url, frameName, disposition, options, additionalFeatures, referrer);
|
const postBody = postData ? {
|
||||||
|
data: postData,
|
||||||
|
...parseContentTypeFormat(postData)
|
||||||
|
} : null;
|
||||||
|
|
||||||
|
event.sender.emit('new-window', event, url, frameName, disposition, options, additionalFeatures, referrer, postBody);
|
||||||
const { newGuest } = event;
|
const { newGuest } = event;
|
||||||
if ((event.sender.getType() === 'webview' && event.sender.getLastWebPreferences().disablePopups) || event.defaultPrevented) {
|
if ((event.sender.getType() === 'webview' && event.sender.getLastWebPreferences().disablePopups) || event.defaultPrevented) {
|
||||||
if (newGuest != null) {
|
if (newGuest != null) {
|
||||||
|
|
|
@ -3,7 +3,7 @@
|
||||||
// parses a feature string that has the format used in window.open()
|
// parses a feature string that has the format used in window.open()
|
||||||
// - `features` input string
|
// - `features` input string
|
||||||
// - `emit` function(key, value) - called for each parsed KV
|
// - `emit` function(key, value) - called for each parsed KV
|
||||||
module.exports = function parseFeaturesString (features, emit) {
|
function parseFeaturesString (features, emit) {
|
||||||
features = `${features}`.trim();
|
features = `${features}`.trim();
|
||||||
// split the string by ','
|
// split the string by ','
|
||||||
features.split(/\s*,\s*/).forEach((feature) => {
|
features.split(/\s*,\s*/).forEach((feature) => {
|
||||||
|
@ -18,4 +18,68 @@ module.exports = function parseFeaturesString (features, emit) {
|
||||||
// emit the parsed pair
|
// emit the parsed pair
|
||||||
emit(key, value);
|
emit(key, value);
|
||||||
});
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
function convertFeaturesString (features, frameName) {
|
||||||
|
const options = {};
|
||||||
|
|
||||||
|
const ints = ['x', 'y', 'width', 'height', 'minWidth', 'maxWidth', 'minHeight', 'maxHeight', 'zoomFactor'];
|
||||||
|
const webPreferences = ['zoomFactor', 'nodeIntegration', 'enableRemoteModule', 'preload', 'javascript', 'contextIsolation', 'webviewTag'];
|
||||||
|
|
||||||
|
// Used to store additional features
|
||||||
|
const additionalFeatures = [];
|
||||||
|
|
||||||
|
// Parse the features
|
||||||
|
parseFeaturesString(features, function (key, value) {
|
||||||
|
if (value === undefined) {
|
||||||
|
additionalFeatures.push(key);
|
||||||
|
} else {
|
||||||
|
// Don't allow webPreferences to be set since it must be an object
|
||||||
|
// that cannot be directly overridden
|
||||||
|
if (key === 'webPreferences') return;
|
||||||
|
|
||||||
|
if (webPreferences.includes(key)) {
|
||||||
|
if (options.webPreferences == null) {
|
||||||
|
options.webPreferences = {};
|
||||||
|
}
|
||||||
|
options.webPreferences[key] = value;
|
||||||
|
} else {
|
||||||
|
options[key] = value;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
if (options.left) {
|
||||||
|
if (options.x == null) {
|
||||||
|
options.x = options.left;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (options.top) {
|
||||||
|
if (options.y == null) {
|
||||||
|
options.y = options.top;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (options.title == null) {
|
||||||
|
options.title = frameName;
|
||||||
|
}
|
||||||
|
if (options.width == null) {
|
||||||
|
options.width = 800;
|
||||||
|
}
|
||||||
|
if (options.height == null) {
|
||||||
|
options.height = 600;
|
||||||
|
}
|
||||||
|
|
||||||
|
for (const name of ints) {
|
||||||
|
if (options[name] != null) {
|
||||||
|
options[name] = parseInt(options[name], 10);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return {
|
||||||
|
options, additionalFeatures
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
module.exports = {
|
||||||
|
parseFeaturesString, convertFeaturesString
|
||||||
};
|
};
|
||||||
|
|
|
@ -16,10 +16,27 @@ index 47749c430a71c3060c3e258ce1671bf6b03fa8c8..f2aedf5321a13742c6e3c2c4b7492b23
|
||||||
last_committed_origin_, params->window_container_type,
|
last_committed_origin_, params->window_container_type,
|
||||||
params->target_url, params->referrer.To<Referrer>(),
|
params->target_url, params->referrer.To<Referrer>(),
|
||||||
params->frame_name, params->disposition, *params->features,
|
params->frame_name, params->disposition, *params->features,
|
||||||
+ params->additional_features, params->body,
|
+ params->raw_features, params->body,
|
||||||
effective_transient_activation_state, params->opener_suppressed,
|
effective_transient_activation_state, params->opener_suppressed,
|
||||||
&no_javascript_access);
|
&no_javascript_access);
|
||||||
|
|
||||||
|
diff --git a/content/browser/web_contents/web_contents_impl.cc b/content/browser/web_contents/web_contents_impl.cc
|
||||||
|
index 4311fd59dfd8db1dfbebd898c43c3b48caf6cdd7..2ddb86702558920cb372d2c8b3423b2d53d68e56 100644
|
||||||
|
--- a/content/browser/web_contents/web_contents_impl.cc
|
||||||
|
+++ b/content/browser/web_contents/web_contents_impl.cc
|
||||||
|
@@ -2910,9 +2910,9 @@ void WebContentsImpl::CreateNewWindow(
|
||||||
|
}
|
||||||
|
|
||||||
|
if (delegate_) {
|
||||||
|
- delegate_->WebContentsCreated(this, render_process_id,
|
||||||
|
- opener->GetRoutingID(), params.frame_name,
|
||||||
|
- params.target_url, new_contents_impl);
|
||||||
|
+ delegate_->WebContentsCreatedWithFullParams(this, render_process_id,
|
||||||
|
+ opener->GetRoutingID(),
|
||||||
|
+ params, new_contents_impl);
|
||||||
|
}
|
||||||
|
|
||||||
|
for (auto& observer : observers_) {
|
||||||
diff --git a/content/common/frame.mojom b/content/common/frame.mojom
|
diff --git a/content/common/frame.mojom b/content/common/frame.mojom
|
||||||
index 00d9c34304266b49e3f9703ef1aea6524d026ed5..44bb5868b8c3699230d74de0f0903af572d000fc 100644
|
index 00d9c34304266b49e3f9703ef1aea6524d026ed5..44bb5868b8c3699230d74de0f0903af572d000fc 100644
|
||||||
--- a/content/common/frame.mojom
|
--- a/content/common/frame.mojom
|
||||||
|
@ -30,7 +47,7 @@ index 00d9c34304266b49e3f9703ef1aea6524d026ed5..44bb5868b8c3699230d74de0f0903af5
|
||||||
blink.mojom.WindowFeatures features;
|
blink.mojom.WindowFeatures features;
|
||||||
+
|
+
|
||||||
+ // Extra fields added by Electron.
|
+ // Extra fields added by Electron.
|
||||||
+ array<string> additional_features;
|
+ string raw_features;
|
||||||
+ network.mojom.URLRequestBody? body;
|
+ network.mojom.URLRequestBody? body;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -43,7 +60,7 @@ index 702cd0792df47809d9278dd3af40e0e70494e229..75cd0ad7a8dc1efd89683d8da1920506
|
||||||
const std::string& frame_name,
|
const std::string& frame_name,
|
||||||
WindowOpenDisposition disposition,
|
WindowOpenDisposition disposition,
|
||||||
const blink::mojom::WindowFeatures& features,
|
const blink::mojom::WindowFeatures& features,
|
||||||
+ const std::vector<std::string>& additional_features,
|
+ const std::string& raw_features,
|
||||||
+ const scoped_refptr<network::ResourceRequestBody>& body,
|
+ const scoped_refptr<network::ResourceRequestBody>& body,
|
||||||
bool user_gesture,
|
bool user_gesture,
|
||||||
bool opener_suppressed,
|
bool opener_suppressed,
|
||||||
|
@ -64,11 +81,59 @@ index ed0460f7e3c9e2149eed89f7d35a4bb457f6b29f..5fc3d0e31927b618d04024fcc42b2061
|
||||||
const std::string& frame_name,
|
const std::string& frame_name,
|
||||||
WindowOpenDisposition disposition,
|
WindowOpenDisposition disposition,
|
||||||
const blink::mojom::WindowFeatures& features,
|
const blink::mojom::WindowFeatures& features,
|
||||||
+ const std::vector<std::string>& additional_features,
|
+ const std::string& raw_features,
|
||||||
+ const scoped_refptr<network::ResourceRequestBody>& body,
|
+ const scoped_refptr<network::ResourceRequestBody>& body,
|
||||||
bool user_gesture,
|
bool user_gesture,
|
||||||
bool opener_suppressed,
|
bool opener_suppressed,
|
||||||
bool* no_javascript_access);
|
bool* no_javascript_access);
|
||||||
|
diff --git a/content/public/browser/web_contents_delegate.cc b/content/public/browser/web_contents_delegate.cc
|
||||||
|
index 5aa89aef4dbf3fe4ac7ce56b99c371d188584351..72a434fa612cdb4521aab981f98883af87783a80 100644
|
||||||
|
--- a/content/public/browser/web_contents_delegate.cc
|
||||||
|
+++ b/content/public/browser/web_contents_delegate.cc
|
||||||
|
@@ -26,6 +26,17 @@ namespace content {
|
||||||
|
|
||||||
|
WebContentsDelegate::WebContentsDelegate() = default;
|
||||||
|
|
||||||
|
+void WebContentsDelegate::WebContentsCreatedWithFullParams(
|
||||||
|
+ WebContents* source_contents,
|
||||||
|
+ int opener_render_process_id,
|
||||||
|
+ int opener_render_frame_id,
|
||||||
|
+ const mojom::CreateNewWindowParams& params,
|
||||||
|
+ WebContents* new_contents) {
|
||||||
|
+ WebContentsCreated(source_contents, opener_render_process_id,
|
||||||
|
+ opener_render_frame_id, params.frame_name,
|
||||||
|
+ params.target_url, new_contents);
|
||||||
|
+}
|
||||||
|
+
|
||||||
|
WebContents* WebContentsDelegate::OpenURLFromTab(WebContents* source,
|
||||||
|
const OpenURLParams& params) {
|
||||||
|
return nullptr;
|
||||||
|
diff --git a/content/public/browser/web_contents_delegate.h b/content/public/browser/web_contents_delegate.h
|
||||||
|
index 01db3853cb915dca4873c779f06bbf84b002abf6..4a8e4cf2386594e27e2dd8117bac78531b28830c 100644
|
||||||
|
--- a/content/public/browser/web_contents_delegate.h
|
||||||
|
+++ b/content/public/browser/web_contents_delegate.h
|
||||||
|
@@ -16,6 +16,7 @@
|
||||||
|
#include "base/strings/string16.h"
|
||||||
|
#include "build/build_config.h"
|
||||||
|
#include "content/common/content_export.h"
|
||||||
|
+#include "content/common/frame.mojom.h"
|
||||||
|
#include "content/public/browser/bluetooth_chooser.h"
|
||||||
|
#include "content/public/browser/bluetooth_scanning_prompt.h"
|
||||||
|
#include "content/public/browser/invalidate_type.h"
|
||||||
|
@@ -333,6 +334,13 @@ class CONTENT_EXPORT WebContentsDelegate {
|
||||||
|
const std::string& partition_id,
|
||||||
|
SessionStorageNamespace* session_storage_namespace);
|
||||||
|
|
||||||
|
+ virtual void WebContentsCreatedWithFullParams(
|
||||||
|
+ WebContents* source_contents,
|
||||||
|
+ int opener_render_process_id,
|
||||||
|
+ int opener_render_frame_id,
|
||||||
|
+ const mojom::CreateNewWindowParams& params,
|
||||||
|
+ WebContents* new_contents);
|
||||||
|
+
|
||||||
|
// Notifies the delegate about the creation of a new WebContents. This
|
||||||
|
// typically happens when popups are created.
|
||||||
|
virtual void WebContentsCreated(WebContents* source_contents,
|
||||||
diff --git a/content/renderer/render_view_impl.cc b/content/renderer/render_view_impl.cc
|
diff --git a/content/renderer/render_view_impl.cc b/content/renderer/render_view_impl.cc
|
||||||
index b3388258feb1d9fd791a975b08a382addd06af3a..98855151d1f07177a20b0f6079f2f48826d215ca 100644
|
index b3388258feb1d9fd791a975b08a382addd06af3a..98855151d1f07177a20b0f6079f2f48826d215ca 100644
|
||||||
--- a/content/renderer/render_view_impl.cc
|
--- a/content/renderer/render_view_impl.cc
|
||||||
|
@ -81,10 +146,12 @@ index b3388258feb1d9fd791a975b08a382addd06af3a..98855151d1f07177a20b0f6079f2f488
|
||||||
#include "content/renderer/media/audio/audio_device_factory.h"
|
#include "content/renderer/media/audio/audio_device_factory.h"
|
||||||
#include "content/renderer/render_frame_impl.h"
|
#include "content/renderer/render_frame_impl.h"
|
||||||
#include "content/renderer/render_frame_proxy.h"
|
#include "content/renderer/render_frame_proxy.h"
|
||||||
@@ -1255,6 +1256,8 @@ WebView* RenderViewImpl::CreateView(
|
@@ -1255,6 +1256,10 @@ WebView* RenderViewImpl::CreateView(
|
||||||
}
|
}
|
||||||
params->features = ConvertWebWindowFeaturesToMojoWindowFeatures(features);
|
params->features = ConvertWebWindowFeaturesToMojoWindowFeatures(features);
|
||||||
|
|
||||||
|
+ params->raw_features = features.raw_features.Utf8(
|
||||||
|
+ WTF::UTF8ConversionMode::kStrictUTF8ConversionReplacingUnpairedSurrogatesWithFFFD);
|
||||||
+ params->body = GetRequestBodyForWebURLRequest(request);
|
+ params->body = GetRequestBodyForWebURLRequest(request);
|
||||||
+
|
+
|
||||||
// We preserve this information before sending the message since |params| is
|
// We preserve this information before sending the message since |params| is
|
||||||
|
@ -98,7 +165,7 @@ index bf7c4bf0b76a89b1ecee6edc11fcfd06fe679968..79b2ba79653a251d3a4c3a54adbcd5c1
|
||||||
const std::string& frame_name,
|
const std::string& frame_name,
|
||||||
WindowOpenDisposition disposition,
|
WindowOpenDisposition disposition,
|
||||||
const blink::mojom::WindowFeatures& features,
|
const blink::mojom::WindowFeatures& features,
|
||||||
+ const std::vector<std::string>& additional_features,
|
+ const std::string& raw_features,
|
||||||
+ const scoped_refptr<network::ResourceRequestBody>& body,
|
+ const scoped_refptr<network::ResourceRequestBody>& body,
|
||||||
bool user_gesture,
|
bool user_gesture,
|
||||||
bool opener_suppressed,
|
bool opener_suppressed,
|
||||||
|
@ -111,8 +178,42 @@ index aaf3b8fed16bc2959941effaffd3aec87017ca59..1ea96df464f61c963a6d9aa224b9607e
|
||||||
const std::string& frame_name,
|
const std::string& frame_name,
|
||||||
WindowOpenDisposition disposition,
|
WindowOpenDisposition disposition,
|
||||||
const blink::mojom::WindowFeatures& features,
|
const blink::mojom::WindowFeatures& features,
|
||||||
+ const std::vector<std::string>& additional_features,
|
+ const std::string& raw_features,
|
||||||
+ const scoped_refptr<network::ResourceRequestBody>& body,
|
+ const scoped_refptr<network::ResourceRequestBody>& body,
|
||||||
bool user_gesture,
|
bool user_gesture,
|
||||||
bool opener_suppressed,
|
bool opener_suppressed,
|
||||||
bool* no_javascript_access) override;
|
bool* no_javascript_access) override;
|
||||||
|
diff --git a/third_party/blink/public/web/web_window_features.h b/third_party/blink/public/web/web_window_features.h
|
||||||
|
index 4f735ad0d97eaac9a57dad137e479f8a7ec33a36..0a3c5821962c85609b64b3625fa6b8d658cd9ab2 100644
|
||||||
|
--- a/third_party/blink/public/web/web_window_features.h
|
||||||
|
+++ b/third_party/blink/public/web/web_window_features.h
|
||||||
|
@@ -31,6 +31,8 @@
|
||||||
|
#ifndef THIRD_PARTY_BLINK_PUBLIC_WEB_WEB_WINDOW_FEATURES_H_
|
||||||
|
#define THIRD_PARTY_BLINK_PUBLIC_WEB_WEB_WINDOW_FEATURES_H_
|
||||||
|
|
||||||
|
+#include "third_party/blink/renderer/platform/wtf/text/wtf_string.h"
|
||||||
|
+
|
||||||
|
namespace blink {
|
||||||
|
|
||||||
|
struct WebWindowFeatures {
|
||||||
|
@@ -60,6 +62,8 @@ struct WebWindowFeatures {
|
||||||
|
bool noreferrer = false;
|
||||||
|
bool background = false;
|
||||||
|
bool persistent = false;
|
||||||
|
+
|
||||||
|
+ String raw_features;
|
||||||
|
};
|
||||||
|
|
||||||
|
} // namespace blink
|
||||||
|
diff --git a/third_party/blink/renderer/core/frame/local_dom_window.cc b/third_party/blink/renderer/core/frame/local_dom_window.cc
|
||||||
|
index 07cb6e3fabfa7a32f9923dcf4fbc8cebccdbde46..58e768bfcac2561f4427c71b6c31ba73f9be4b7b 100644
|
||||||
|
--- a/third_party/blink/renderer/core/frame/local_dom_window.cc
|
||||||
|
+++ b/third_party/blink/renderer/core/frame/local_dom_window.cc
|
||||||
|
@@ -1492,6 +1492,7 @@ DOMWindow* LocalDOMWindow::open(v8::Isolate* isolate,
|
||||||
|
}
|
||||||
|
|
||||||
|
WebWindowFeatures window_features = GetWindowFeaturesFromString(features);
|
||||||
|
+ window_features.raw_features = features;
|
||||||
|
|
||||||
|
FrameLoadRequest frame_request(active_document,
|
||||||
|
ResourceRequest(completed_url));
|
||||||
|
|
|
@ -671,7 +671,7 @@ bool App::CanCreateWindow(
|
||||||
const std::string& frame_name,
|
const std::string& frame_name,
|
||||||
WindowOpenDisposition disposition,
|
WindowOpenDisposition disposition,
|
||||||
const blink::mojom::WindowFeatures& features,
|
const blink::mojom::WindowFeatures& features,
|
||||||
const std::vector<std::string>& additional_features,
|
const std::string& raw_features,
|
||||||
const scoped_refptr<network::ResourceRequestBody>& body,
|
const scoped_refptr<network::ResourceRequestBody>& body,
|
||||||
bool user_gesture,
|
bool user_gesture,
|
||||||
bool opener_suppressed,
|
bool opener_suppressed,
|
||||||
|
@ -685,7 +685,7 @@ bool App::CanCreateWindow(
|
||||||
// No need to emit any event if the WebContents is not available in JS.
|
// No need to emit any event if the WebContents is not available in JS.
|
||||||
if (!api_web_contents.IsEmpty()) {
|
if (!api_web_contents.IsEmpty()) {
|
||||||
api_web_contents->OnCreateWindow(target_url, referrer, frame_name,
|
api_web_contents->OnCreateWindow(target_url, referrer, frame_name,
|
||||||
disposition, additional_features, body);
|
disposition, raw_features, body);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -131,7 +131,7 @@ class App : public ElectronBrowserClient::Delegate,
|
||||||
const std::string& frame_name,
|
const std::string& frame_name,
|
||||||
WindowOpenDisposition disposition,
|
WindowOpenDisposition disposition,
|
||||||
const blink::mojom::WindowFeatures& features,
|
const blink::mojom::WindowFeatures& features,
|
||||||
const std::vector<std::string>& additional_features,
|
const std::string& raw_features,
|
||||||
const scoped_refptr<network::ResourceRequestBody>& body,
|
const scoped_refptr<network::ResourceRequestBody>& body,
|
||||||
bool user_gesture,
|
bool user_gesture,
|
||||||
bool opener_suppressed,
|
bool opener_suppressed,
|
||||||
|
|
|
@ -44,6 +44,7 @@
|
||||||
#include "content/public/browser/site_instance.h"
|
#include "content/public/browser/site_instance.h"
|
||||||
#include "content/public/browser/storage_partition.h"
|
#include "content/public/browser/storage_partition.h"
|
||||||
#include "content/public/browser/web_contents.h"
|
#include "content/public/browser/web_contents.h"
|
||||||
|
#include "content/public/common/referrer_type_converters.h"
|
||||||
#include "electron/buildflags/buildflags.h"
|
#include "electron/buildflags/buildflags.h"
|
||||||
#include "electron/shell/common/api/api.mojom.h"
|
#include "electron/shell/common/api/api.mojom.h"
|
||||||
#include "gin/data_object_builder.h"
|
#include "gin/data_object_builder.h"
|
||||||
|
@ -641,25 +642,25 @@ void WebContents::OnCreateWindow(
|
||||||
const content::Referrer& referrer,
|
const content::Referrer& referrer,
|
||||||
const std::string& frame_name,
|
const std::string& frame_name,
|
||||||
WindowOpenDisposition disposition,
|
WindowOpenDisposition disposition,
|
||||||
const std::vector<std::string>& features,
|
const std::string& features,
|
||||||
const scoped_refptr<network::ResourceRequestBody>& body) {
|
const scoped_refptr<network::ResourceRequestBody>& body) {
|
||||||
if (type_ == Type::BROWSER_WINDOW || type_ == Type::OFF_SCREEN)
|
Emit("-new-window", target_url, frame_name, disposition, features, referrer,
|
||||||
Emit("-new-window", target_url, frame_name, disposition, features, body,
|
body);
|
||||||
referrer);
|
|
||||||
else
|
|
||||||
Emit("new-window", target_url, frame_name, disposition, features);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void WebContents::WebContentsCreated(content::WebContents* source_contents,
|
void WebContents::WebContentsCreatedWithFullParams(
|
||||||
int opener_render_process_id,
|
content::WebContents* source_contents,
|
||||||
int opener_render_frame_id,
|
int opener_render_process_id,
|
||||||
const std::string& frame_name,
|
int opener_render_frame_id,
|
||||||
const GURL& target_url,
|
const content::mojom::CreateNewWindowParams& params,
|
||||||
content::WebContents* new_contents) {
|
content::WebContents* new_contents) {
|
||||||
ChildWebContentsTracker::CreateForWebContents(new_contents);
|
ChildWebContentsTracker::CreateForWebContents(new_contents);
|
||||||
auto* tracker = ChildWebContentsTracker::FromWebContents(new_contents);
|
auto* tracker = ChildWebContentsTracker::FromWebContents(new_contents);
|
||||||
tracker->url = target_url;
|
tracker->url = params.target_url;
|
||||||
tracker->frame_name = frame_name;
|
tracker->frame_name = params.frame_name;
|
||||||
|
tracker->referrer = params.referrer.To<content::Referrer>();
|
||||||
|
tracker->raw_features = params.raw_features;
|
||||||
|
tracker->body = params.body;
|
||||||
}
|
}
|
||||||
|
|
||||||
void WebContents::AddNewContents(
|
void WebContents::AddNewContents(
|
||||||
|
@ -678,7 +679,8 @@ void WebContents::AddNewContents(
|
||||||
CreateAndTake(isolate(), std::move(new_contents), Type::BROWSER_WINDOW);
|
CreateAndTake(isolate(), std::move(new_contents), Type::BROWSER_WINDOW);
|
||||||
if (Emit("-add-new-contents", api_web_contents, disposition, user_gesture,
|
if (Emit("-add-new-contents", api_web_contents, disposition, user_gesture,
|
||||||
initial_rect.x(), initial_rect.y(), initial_rect.width(),
|
initial_rect.x(), initial_rect.y(), initial_rect.width(),
|
||||||
initial_rect.height(), tracker->url, tracker->frame_name)) {
|
initial_rect.height(), tracker->url, tracker->frame_name,
|
||||||
|
tracker->referrer, tracker->raw_features, tracker->body)) {
|
||||||
// TODO(zcbenz): Can we make this sync?
|
// TODO(zcbenz): Can we make this sync?
|
||||||
api_web_contents->DestroyWebContents(true /* async */);
|
api_web_contents->DestroyWebContents(true /* async */);
|
||||||
}
|
}
|
||||||
|
@ -688,10 +690,8 @@ content::WebContents* WebContents::OpenURLFromTab(
|
||||||
content::WebContents* source,
|
content::WebContents* source,
|
||||||
const content::OpenURLParams& params) {
|
const content::OpenURLParams& params) {
|
||||||
if (params.disposition != WindowOpenDisposition::CURRENT_TAB) {
|
if (params.disposition != WindowOpenDisposition::CURRENT_TAB) {
|
||||||
if (type_ == Type::BROWSER_WINDOW || type_ == Type::OFF_SCREEN)
|
Emit("-new-window", params.url, "", params.disposition, "", params.referrer,
|
||||||
Emit("-new-window", params.url, "", params.disposition);
|
params.post_data);
|
||||||
else
|
|
||||||
Emit("new-window", params.url, "", params.disposition);
|
|
||||||
return nullptr;
|
return nullptr;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -13,6 +13,7 @@
|
||||||
#include "base/observer_list.h"
|
#include "base/observer_list.h"
|
||||||
#include "base/observer_list_types.h"
|
#include "base/observer_list_types.h"
|
||||||
#include "content/common/cursors/webcursor.h"
|
#include "content/common/cursors/webcursor.h"
|
||||||
|
#include "content/common/frame.mojom.h"
|
||||||
#include "content/public/browser/devtools_agent_host.h"
|
#include "content/public/browser/devtools_agent_host.h"
|
||||||
#include "content/public/browser/keyboard_event_processing_result.h"
|
#include "content/public/browser/keyboard_event_processing_result.h"
|
||||||
#include "content/public/browser/render_widget_host.h"
|
#include "content/public/browser/render_widget_host.h"
|
||||||
|
@ -312,7 +313,7 @@ class WebContents : public gin_helper::TrackableObject<WebContents>,
|
||||||
const content::Referrer& referrer,
|
const content::Referrer& referrer,
|
||||||
const std::string& frame_name,
|
const std::string& frame_name,
|
||||||
WindowOpenDisposition disposition,
|
WindowOpenDisposition disposition,
|
||||||
const std::vector<std::string>& features,
|
const std::string& features,
|
||||||
const scoped_refptr<network::ResourceRequestBody>& body);
|
const scoped_refptr<network::ResourceRequestBody>& body);
|
||||||
|
|
||||||
// Returns the preload script path of current WebContents.
|
// Returns the preload script path of current WebContents.
|
||||||
|
@ -383,12 +384,12 @@ class WebContents : public gin_helper::TrackableObject<WebContents>,
|
||||||
const base::string16& message,
|
const base::string16& message,
|
||||||
int32_t line_no,
|
int32_t line_no,
|
||||||
const base::string16& source_id) override;
|
const base::string16& source_id) override;
|
||||||
void WebContentsCreated(content::WebContents* source_contents,
|
void WebContentsCreatedWithFullParams(
|
||||||
int opener_render_process_id,
|
content::WebContents* source_contents,
|
||||||
int opener_render_frame_id,
|
int opener_render_process_id,
|
||||||
const std::string& frame_name,
|
int opener_render_frame_id,
|
||||||
const GURL& target_url,
|
const content::mojom::CreateNewWindowParams& params,
|
||||||
content::WebContents* new_contents) override;
|
content::WebContents* new_contents) override;
|
||||||
void AddNewContents(content::WebContents* source,
|
void AddNewContents(content::WebContents* source,
|
||||||
std::unique_ptr<content::WebContents> new_contents,
|
std::unique_ptr<content::WebContents> new_contents,
|
||||||
WindowOpenDisposition disposition,
|
WindowOpenDisposition disposition,
|
||||||
|
|
|
@ -9,6 +9,8 @@ namespace electron {
|
||||||
ChildWebContentsTracker::ChildWebContentsTracker(
|
ChildWebContentsTracker::ChildWebContentsTracker(
|
||||||
content::WebContents* web_contents) {}
|
content::WebContents* web_contents) {}
|
||||||
|
|
||||||
|
ChildWebContentsTracker::~ChildWebContentsTracker() {}
|
||||||
|
|
||||||
WEB_CONTENTS_USER_DATA_KEY_IMPL(ChildWebContentsTracker)
|
WEB_CONTENTS_USER_DATA_KEY_IMPL(ChildWebContentsTracker)
|
||||||
|
|
||||||
} // namespace electron
|
} // namespace electron
|
||||||
|
|
|
@ -15,8 +15,13 @@ namespace electron {
|
||||||
// created by native `window.open()`
|
// created by native `window.open()`
|
||||||
struct ChildWebContentsTracker
|
struct ChildWebContentsTracker
|
||||||
: public content::WebContentsUserData<ChildWebContentsTracker> {
|
: public content::WebContentsUserData<ChildWebContentsTracker> {
|
||||||
|
~ChildWebContentsTracker() override;
|
||||||
|
|
||||||
GURL url;
|
GURL url;
|
||||||
std::string frame_name;
|
std::string frame_name;
|
||||||
|
content::Referrer referrer;
|
||||||
|
std::string raw_features;
|
||||||
|
scoped_refptr<network::ResourceRequestBody> body;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
explicit ChildWebContentsTracker(content::WebContents* web_contents);
|
explicit ChildWebContentsTracker(content::WebContents* web_contents);
|
||||||
|
|
|
@ -762,7 +762,7 @@ bool ElectronBrowserClient::CanCreateWindow(
|
||||||
const std::string& frame_name,
|
const std::string& frame_name,
|
||||||
WindowOpenDisposition disposition,
|
WindowOpenDisposition disposition,
|
||||||
const blink::mojom::WindowFeatures& features,
|
const blink::mojom::WindowFeatures& features,
|
||||||
const std::vector<std::string>& additional_features,
|
const std::string& raw_features,
|
||||||
const scoped_refptr<network::ResourceRequestBody>& body,
|
const scoped_refptr<network::ResourceRequestBody>& body,
|
||||||
bool user_gesture,
|
bool user_gesture,
|
||||||
bool opener_suppressed,
|
bool opener_suppressed,
|
||||||
|
@ -786,7 +786,7 @@ bool ElectronBrowserClient::CanCreateWindow(
|
||||||
return delegate_->CanCreateWindow(
|
return delegate_->CanCreateWindow(
|
||||||
opener, opener_url, opener_top_level_frame_url, source_origin,
|
opener, opener_url, opener_top_level_frame_url, source_origin,
|
||||||
container_type, target_url, referrer, frame_name, disposition, features,
|
container_type, target_url, referrer, frame_name, disposition, features,
|
||||||
additional_features, body, user_gesture, opener_suppressed,
|
raw_features, body, user_gesture, opener_suppressed,
|
||||||
no_javascript_access);
|
no_javascript_access);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -128,7 +128,7 @@ class ElectronBrowserClient : public content::ContentBrowserClient,
|
||||||
const std::string& frame_name,
|
const std::string& frame_name,
|
||||||
WindowOpenDisposition disposition,
|
WindowOpenDisposition disposition,
|
||||||
const blink::mojom::WindowFeatures& features,
|
const blink::mojom::WindowFeatures& features,
|
||||||
const std::vector<std::string>& additional_features,
|
const std::string& raw_features,
|
||||||
const scoped_refptr<network::ResourceRequestBody>& body,
|
const scoped_refptr<network::ResourceRequestBody>& body,
|
||||||
bool user_gesture,
|
bool user_gesture,
|
||||||
bool opener_suppressed,
|
bool opener_suppressed,
|
||||||
|
|
|
@ -2,7 +2,7 @@ import { expect } from 'chai';
|
||||||
|
|
||||||
describe('feature-string parsing', () => {
|
describe('feature-string parsing', () => {
|
||||||
it('is indifferent to whitespace around keys and values', () => {
|
it('is indifferent to whitespace around keys and values', () => {
|
||||||
const parseFeaturesString = require('../lib/common/parse-features-string');
|
const { parseFeaturesString } = 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: Record<string, string | boolean> = {};
|
const features: Record<string, string | boolean> = {};
|
||||||
parseFeaturesString(string, (k: string, v: any) => { features[k] = v; });
|
parseFeaturesString(string, (k: string, v: any) => { features[k] = v; });
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue