feat: promisify executeJavaScript (#17312)
This commit is contained in:
parent
878538f2e8
commit
2e89348541
14 changed files with 164 additions and 100 deletions
|
@ -14,6 +14,7 @@
|
||||||
#include "atom/common/native_mate_converters/gfx_converter.h"
|
#include "atom/common/native_mate_converters/gfx_converter.h"
|
||||||
#include "atom/common/native_mate_converters/string16_converter.h"
|
#include "atom/common/native_mate_converters/string16_converter.h"
|
||||||
#include "atom/common/node_includes.h"
|
#include "atom/common/node_includes.h"
|
||||||
|
#include "atom/common/promise_util.h"
|
||||||
#include "atom/renderer/api/atom_api_spell_check_client.h"
|
#include "atom/renderer/api/atom_api_spell_check_client.h"
|
||||||
#include "base/memory/memory_pressure_listener.h"
|
#include "base/memory/memory_pressure_listener.h"
|
||||||
#include "content/public/renderer/render_frame.h"
|
#include "content/public/renderer/render_frame.h"
|
||||||
|
@ -92,23 +93,20 @@ class RenderFrameStatus : public content::RenderFrameObserver {
|
||||||
|
|
||||||
class ScriptExecutionCallback : public blink::WebScriptExecutionCallback {
|
class ScriptExecutionCallback : public blink::WebScriptExecutionCallback {
|
||||||
public:
|
public:
|
||||||
using CompletionCallback =
|
explicit ScriptExecutionCallback(atom::util::Promise promise)
|
||||||
base::Callback<void(const v8::Local<v8::Value>& result)>;
|
: promise_(std::move(promise)) {}
|
||||||
|
|
||||||
explicit ScriptExecutionCallback(const CompletionCallback& callback)
|
|
||||||
: callback_(callback) {}
|
|
||||||
~ScriptExecutionCallback() override {}
|
~ScriptExecutionCallback() override {}
|
||||||
|
|
||||||
void Completed(
|
void Completed(
|
||||||
const blink::WebVector<v8::Local<v8::Value>>& result) override {
|
const blink::WebVector<v8::Local<v8::Value>>& result) override {
|
||||||
if (!callback_.is_null() && !result.empty() && !result[0].IsEmpty())
|
if (!result.empty() && !result[0].IsEmpty())
|
||||||
// Right now only single results per frame is supported.
|
// Right now only single results per frame is supported.
|
||||||
callback_.Run(result[0]);
|
promise_.Resolve(result[0]);
|
||||||
delete this;
|
delete this;
|
||||||
}
|
}
|
||||||
|
|
||||||
private:
|
private:
|
||||||
CompletionCallback callback_;
|
atom::util::Promise promise_;
|
||||||
|
|
||||||
DISALLOW_COPY_AND_ASSIGN(ScriptExecutionCallback);
|
DISALLOW_COPY_AND_ASSIGN(ScriptExecutionCallback);
|
||||||
};
|
};
|
||||||
|
@ -322,25 +320,32 @@ void InsertCSS(v8::Local<v8::Value> window, const std::string& css) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void ExecuteJavaScript(mate::Arguments* args,
|
v8::Local<v8::Promise> ExecuteJavaScript(mate::Arguments* args,
|
||||||
v8::Local<v8::Value> window,
|
v8::Local<v8::Value> window,
|
||||||
const base::string16& code) {
|
const base::string16& code) {
|
||||||
|
v8::Isolate* isolate = args->isolate();
|
||||||
|
util::Promise promise(isolate);
|
||||||
|
v8::Local<v8::Promise> handle = promise.GetHandle();
|
||||||
|
|
||||||
bool has_user_gesture = false;
|
bool has_user_gesture = false;
|
||||||
args->GetNext(&has_user_gesture);
|
args->GetNext(&has_user_gesture);
|
||||||
ScriptExecutionCallback::CompletionCallback completion_callback;
|
|
||||||
args->GetNext(&completion_callback);
|
|
||||||
std::unique_ptr<blink::WebScriptExecutionCallback> callback(
|
|
||||||
new ScriptExecutionCallback(completion_callback));
|
|
||||||
GetRenderFrame(window)->GetWebFrame()->RequestExecuteScriptAndReturnValue(
|
GetRenderFrame(window)->GetWebFrame()->RequestExecuteScriptAndReturnValue(
|
||||||
blink::WebScriptSource(blink::WebString::FromUTF16(code)),
|
blink::WebScriptSource(blink::WebString::FromUTF16(code)),
|
||||||
has_user_gesture, callback.release());
|
has_user_gesture, new ScriptExecutionCallback(std::move(promise)));
|
||||||
|
|
||||||
|
return handle;
|
||||||
}
|
}
|
||||||
|
|
||||||
void ExecuteJavaScriptInIsolatedWorld(
|
v8::Local<v8::Promise> ExecuteJavaScriptInIsolatedWorld(
|
||||||
mate::Arguments* args,
|
mate::Arguments* args,
|
||||||
v8::Local<v8::Value> window,
|
v8::Local<v8::Value> window,
|
||||||
int world_id,
|
int world_id,
|
||||||
const std::vector<mate::Dictionary>& scripts) {
|
const std::vector<mate::Dictionary>& scripts) {
|
||||||
|
v8::Isolate* isolate = args->isolate();
|
||||||
|
util::Promise promise(isolate);
|
||||||
|
v8::Local<v8::Promise> handle = promise.GetHandle();
|
||||||
|
|
||||||
std::vector<blink::WebScriptSource> sources;
|
std::vector<blink::WebScriptSource> sources;
|
||||||
|
|
||||||
for (const auto& script : scripts) {
|
for (const auto& script : scripts) {
|
||||||
|
@ -351,8 +356,8 @@ void ExecuteJavaScriptInIsolatedWorld(
|
||||||
script.Get("startLine", &start_line);
|
script.Get("startLine", &start_line);
|
||||||
|
|
||||||
if (!script.Get("code", &code)) {
|
if (!script.Get("code", &code)) {
|
||||||
args->ThrowError("Invalid 'code'");
|
promise.RejectWithErrorMessage("Invalid 'code'");
|
||||||
return;
|
return handle;
|
||||||
}
|
}
|
||||||
|
|
||||||
sources.emplace_back(
|
sources.emplace_back(
|
||||||
|
@ -367,14 +372,11 @@ void ExecuteJavaScriptInIsolatedWorld(
|
||||||
blink::WebLocalFrame::kSynchronous;
|
blink::WebLocalFrame::kSynchronous;
|
||||||
args->GetNext(&scriptExecutionType);
|
args->GetNext(&scriptExecutionType);
|
||||||
|
|
||||||
ScriptExecutionCallback::CompletionCallback completion_callback;
|
|
||||||
args->GetNext(&completion_callback);
|
|
||||||
std::unique_ptr<blink::WebScriptExecutionCallback> callback(
|
|
||||||
new ScriptExecutionCallback(completion_callback));
|
|
||||||
|
|
||||||
GetRenderFrame(window)->GetWebFrame()->RequestExecuteScriptInIsolatedWorld(
|
GetRenderFrame(window)->GetWebFrame()->RequestExecuteScriptInIsolatedWorld(
|
||||||
world_id, &sources.front(), sources.size(), has_user_gesture,
|
world_id, &sources.front(), sources.size(), has_user_gesture,
|
||||||
scriptExecutionType, callback.release());
|
scriptExecutionType, new ScriptExecutionCallback(std::move(promise)));
|
||||||
|
|
||||||
|
return handle;
|
||||||
}
|
}
|
||||||
|
|
||||||
void SetIsolatedWorldInfo(v8::Local<v8::Value> window,
|
void SetIsolatedWorldInfo(v8::Local<v8::Value> window,
|
||||||
|
|
|
@ -11,16 +11,13 @@ When a majority of affected functions are migrated, this flag will be enabled by
|
||||||
- [app.importCertificate(options, callback)](https://github.com/electron/electron/blob/master/docs/api/app.md#importCertificate)
|
- [app.importCertificate(options, callback)](https://github.com/electron/electron/blob/master/docs/api/app.md#importCertificate)
|
||||||
- [dialog.showMessageBox([browserWindow, ]options[, callback])](https://github.com/electron/electron/blob/master/docs/api/dialog.md#showMessageBox)
|
- [dialog.showMessageBox([browserWindow, ]options[, callback])](https://github.com/electron/electron/blob/master/docs/api/dialog.md#showMessageBox)
|
||||||
- [dialog.showCertificateTrustDialog([browserWindow, ]options, callback)](https://github.com/electron/electron/blob/master/docs/api/dialog.md#showCertificateTrustDialog)
|
- [dialog.showCertificateTrustDialog([browserWindow, ]options, callback)](https://github.com/electron/electron/blob/master/docs/api/dialog.md#showCertificateTrustDialog)
|
||||||
- [contents.executeJavaScript(code[, userGesture, callback])](https://github.com/electron/electron/blob/master/docs/api/web-contents.md#executeJavaScript)
|
|
||||||
- [contents.print([options], [callback])](https://github.com/electron/electron/blob/master/docs/api/web-contents.md#print)
|
- [contents.print([options], [callback])](https://github.com/electron/electron/blob/master/docs/api/web-contents.md#print)
|
||||||
- [webFrame.executeJavaScript(code[, userGesture, callback])](https://github.com/electron/electron/blob/master/docs/api/web-frame.md#executeJavaScript)
|
|
||||||
- [webFrame.executeJavaScriptInIsolatedWorld(worldId, scripts[, userGesture, callback])](https://github.com/electron/electron/blob/master/docs/api/web-frame.md#executeJavaScriptInIsolatedWorld)
|
|
||||||
- [webviewTag.executeJavaScript(code[, userGesture, callback])](https://github.com/electron/electron/blob/master/docs/api/webview-tag.md#executeJavaScript)
|
|
||||||
|
|
||||||
### Converted Functions
|
### Converted Functions
|
||||||
|
|
||||||
- [app.getFileIcon(path[, options], callback)](https://github.com/electron/electron/blob/master/docs/api/app.md#getFileIcon)
|
- [app.getFileIcon(path[, options], callback)](https://github.com/electron/electron/blob/master/docs/api/app.md#getFileIcon)
|
||||||
- [contents.capturePage([rect, ]callback)](https://github.com/electron/electron/blob/master/docs/api/web-contents.md#capturePage)
|
- [contents.capturePage([rect, ]callback)](https://github.com/electron/electron/blob/master/docs/api/web-contents.md#capturePage)
|
||||||
|
- [contents.executeJavaScript(code[, userGesture, callback])](https://github.com/electron/electron/blob/master/docs/api/web-contents.md#executeJavaScript)
|
||||||
- [contents.printToPDF(options, callback)](https://github.com/electron/electron/blob/master/docs/api/web-contents.md#printToPDF)
|
- [contents.printToPDF(options, callback)](https://github.com/electron/electron/blob/master/docs/api/web-contents.md#printToPDF)
|
||||||
- [contents.savePage(fullPath, saveType, callback)](https://github.com/electron/electron/blob/master/docs/api/web-contents.md#savePage)
|
- [contents.savePage(fullPath, saveType, callback)](https://github.com/electron/electron/blob/master/docs/api/web-contents.md#savePage)
|
||||||
- [contentTracing.getCategories(callback)](https://github.com/electron/electron/blob/master/docs/api/content-tracing.md#getCategories)
|
- [contentTracing.getCategories(callback)](https://github.com/electron/electron/blob/master/docs/api/content-tracing.md#getCategories)
|
||||||
|
@ -48,6 +45,9 @@ When a majority of affected functions are migrated, this flag will be enabled by
|
||||||
- [ses.clearCache(callback)](https://github.com/electron/electron/blob/master/docs/api/session.md#clearCache)
|
- [ses.clearCache(callback)](https://github.com/electron/electron/blob/master/docs/api/session.md#clearCache)
|
||||||
- [ses.getBlobData(identifier, callback)](https://github.com/electron/electron/blob/master/docs/api/session.md#getBlobData)
|
- [ses.getBlobData(identifier, callback)](https://github.com/electron/electron/blob/master/docs/api/session.md#getBlobData)
|
||||||
- [shell.openExternal(url[, options, callback])](https://github.com/electron/electron/blob/master/docs/api/shell.md#openExternal)
|
- [shell.openExternal(url[, options, callback])](https://github.com/electron/electron/blob/master/docs/api/shell.md#openExternal)
|
||||||
|
- [webFrame.executeJavaScript(code[, userGesture, callback])](https://github.com/electron/electron/blob/master/docs/api/web-frame.md#executeJavaScript)
|
||||||
|
- [webFrame.executeJavaScriptInIsolatedWorld(worldId, scripts[, userGesture, callback])](https://github.com/electron/electron/blob/master/docs/api/web-frame.md#executeJavaScriptInIsolatedWorld)
|
||||||
- [webviewTag.capturePage([rect, ]callback)](https://github.com/electron/electron/blob/master/docs/api/webview-tag.md#capturePage)
|
- [webviewTag.capturePage([rect, ]callback)](https://github.com/electron/electron/blob/master/docs/api/webview-tag.md#capturePage)
|
||||||
|
- [webviewTag.executeJavaScript(code[, userGesture, callback])](https://github.com/electron/electron/blob/master/docs/api/webview-tag.md#executeJavaScript)
|
||||||
- [webviewTag.printToPDF(options, callback)](https://github.com/electron/electron/blob/master/docs/api/webview-tag.md#printToPDF)
|
- [webviewTag.printToPDF(options, callback)](https://github.com/electron/electron/blob/master/docs/api/webview-tag.md#printToPDF)
|
||||||
- [win.capturePage([rect, ]callback)](https://github.com/electron/electron/blob/master/docs/api/browser-window.md#capturePage)
|
- [win.capturePage([rect, ]callback)](https://github.com/electron/electron/blob/master/docs/api/browser-window.md#capturePage)
|
||||||
|
|
|
@ -973,9 +973,28 @@ In the browser window some HTML APIs like `requestFullScreen` can only be
|
||||||
invoked by a gesture from the user. Setting `userGesture` to `true` will remove
|
invoked by a gesture from the user. Setting `userGesture` to `true` will remove
|
||||||
this limitation.
|
this limitation.
|
||||||
|
|
||||||
If the result of the executed code is a promise the callback result will be the
|
```js
|
||||||
resolved value of the promise. We recommend that you use the returned Promise
|
contents.executeJavaScript('fetch("https://jsonplaceholder.typicode.com/users/1").then(resp => resp.json())', true)
|
||||||
to handle code that results in a Promise.
|
.then((result) => {
|
||||||
|
console.log(result) // Will be the JSON object from the fetch call
|
||||||
|
})
|
||||||
|
```
|
||||||
|
|
||||||
|
**[Deprecated Soon](promisification.md)**
|
||||||
|
|
||||||
|
#### `contents.executeJavaScript(code[, userGesture])`
|
||||||
|
|
||||||
|
* `code` String
|
||||||
|
* `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.
|
||||||
|
|
||||||
|
Evaluates `code` in page.
|
||||||
|
|
||||||
|
In the browser window some HTML APIs like `requestFullScreen` can only be
|
||||||
|
invoked by a gesture from the user. Setting `userGesture` to `true` will remove
|
||||||
|
this limitation.
|
||||||
|
|
||||||
```js
|
```js
|
||||||
contents.executeJavaScript('fetch("https://jsonplaceholder.typicode.com/users/1").then(resp => resp.json())', true)
|
contents.executeJavaScript('fetch("https://jsonplaceholder.typicode.com/users/1").then(resp => resp.json())', true)
|
||||||
|
|
|
@ -123,6 +123,22 @@ In the browser window some HTML APIs like `requestFullScreen` can only be
|
||||||
invoked by a gesture from the user. Setting `userGesture` to `true` will remove
|
invoked by a gesture from the user. Setting `userGesture` to `true` will remove
|
||||||
this limitation.
|
this limitation.
|
||||||
|
|
||||||
|
**[Deprecated Soon](promisification.md)**
|
||||||
|
|
||||||
|
### `webFrame.executeJavaScript(code[, userGesture])`
|
||||||
|
|
||||||
|
* `code` String
|
||||||
|
* `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.
|
||||||
|
|
||||||
|
Evaluates `code` in page.
|
||||||
|
|
||||||
|
In the browser window some HTML APIs like `requestFullScreen` can only be
|
||||||
|
invoked by a gesture from the user. Setting `userGesture` to `true` will remove
|
||||||
|
this limitation.
|
||||||
|
|
||||||
### `webFrame.executeJavaScriptInIsolatedWorld(worldId, scripts[, userGesture, callback])`
|
### `webFrame.executeJavaScriptInIsolatedWorld(worldId, scripts[, userGesture, callback])`
|
||||||
|
|
||||||
* `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. Chrome extensions reserve the range of IDs in `[1 << 20, 1 << 29)`. 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 Electrons `contextIsolation` feature. Chrome extensions reserve the range of IDs in `[1 << 20, 1 << 29)`. You can provide any integer here.
|
||||||
|
@ -131,7 +147,23 @@ this limitation.
|
||||||
* `callback` Function (optional) - Called after script has been executed.
|
* `callback` Function (optional) - Called after script has been executed.
|
||||||
* `result` Any
|
* `result` Any
|
||||||
|
|
||||||
Work like `executeJavaScript` but evaluates `scripts` in an isolated context.
|
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.
|
||||||
|
|
||||||
|
**[Deprecated Soon](promisification.md)**
|
||||||
|
|
||||||
|
### `webFrame.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<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.
|
||||||
|
|
||||||
### `webFrame.setIsolatedWorldContentSecurityPolicy(worldId, csp)` _(Deprecated)_
|
### `webFrame.setIsolatedWorldContentSecurityPolicy(worldId, csp)` _(Deprecated)_
|
||||||
|
|
||||||
|
|
|
@ -374,6 +374,23 @@ Injects CSS into the guest page.
|
||||||
* `callback` Function (optional) - Called after script has been executed.
|
* `callback` Function (optional) - Called after script has been executed.
|
||||||
* `result` Any
|
* `result` Any
|
||||||
|
|
||||||
|
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.
|
||||||
|
|
||||||
|
Evaluates `code` in page. If `userGesture` is set, it will create the user
|
||||||
|
gesture context in the page. HTML APIs like `requestFullScreen`, which require
|
||||||
|
user action, can take advantage of this option for automation.
|
||||||
|
|
||||||
|
**[Deprecated Soon](promisification.md)**
|
||||||
|
|
||||||
|
### `<webview>.executeJavaScript(code[, userGesture])`
|
||||||
|
|
||||||
|
* `code` String
|
||||||
|
* `userGesture` Boolean (optional) - Default `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.
|
||||||
|
|
||||||
Evaluates `code` in page. If `userGesture` is set, it will create the user
|
Evaluates `code` in page. If `userGesture` is set, it will create the user
|
||||||
gesture context in the page. HTML APIs like `requestFullScreen`, which require
|
gesture context in the page. HTML APIs like `requestFullScreen`, which require
|
||||||
user action, can take advantage of this option for automation.
|
user action, can take advantage of this option for automation.
|
||||||
|
|
|
@ -178,47 +178,25 @@ const webFrameMethods = [
|
||||||
'setVisualZoomLevelLimits'
|
'setVisualZoomLevelLimits'
|
||||||
]
|
]
|
||||||
|
|
||||||
const asyncWebFrameMethods = function (requestId, method, callback, ...args) {
|
|
||||||
return new Promise((resolve, reject) => {
|
|
||||||
ipcMainInternal.once(`ELECTRON_INTERNAL_BROWSER_ASYNC_WEB_FRAME_RESPONSE_${requestId}`, function (event, error, result) {
|
|
||||||
if (error == null) {
|
|
||||||
if (typeof callback === 'function') callback(result)
|
|
||||||
resolve(result)
|
|
||||||
} else {
|
|
||||||
reject(errorUtils.deserialize(error))
|
|
||||||
}
|
|
||||||
})
|
|
||||||
this._sendInternal('ELECTRON_INTERNAL_RENDERER_ASYNC_WEB_FRAME_METHOD', requestId, method, args)
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
||||||
for (const method of webFrameMethods) {
|
for (const method of webFrameMethods) {
|
||||||
WebContents.prototype[method] = function (...args) {
|
WebContents.prototype[method] = function (...args) {
|
||||||
ipcMainUtils.invokeInWebContents(this, 'ELECTRON_INTERNAL_RENDERER_WEB_FRAME_METHOD', method, ...args)
|
ipcMainUtils.invokeInWebContents(this, 'ELECTRON_INTERNAL_RENDERER_WEB_FRAME_METHOD', method, ...args)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const executeJavaScript = (contents, code, hasUserGesture) => {
|
||||||
|
return ipcMainUtils.invokeInWebContents(contents, 'ELECTRON_INTERNAL_RENDERER_WEB_FRAME_METHOD', 'executeJavaScript', code, hasUserGesture)
|
||||||
|
}
|
||||||
|
|
||||||
// Make sure WebContents::executeJavaScript would run the code only when the
|
// Make sure WebContents::executeJavaScript would run the code only when the
|
||||||
// WebContents has been loaded.
|
// WebContents has been loaded.
|
||||||
WebContents.prototype.executeJavaScript = function (code, hasUserGesture, callback) {
|
WebContents.prototype.executeJavaScript = function (code, hasUserGesture) {
|
||||||
const requestId = getNextId()
|
|
||||||
|
|
||||||
if (typeof hasUserGesture === 'function') {
|
|
||||||
// Shift.
|
|
||||||
callback = hasUserGesture
|
|
||||||
hasUserGesture = null
|
|
||||||
}
|
|
||||||
|
|
||||||
if (hasUserGesture == null) {
|
|
||||||
hasUserGesture = false
|
|
||||||
}
|
|
||||||
|
|
||||||
if (this.getURL() && !this.isLoadingMainFrame()) {
|
if (this.getURL() && !this.isLoadingMainFrame()) {
|
||||||
return asyncWebFrameMethods.call(this, requestId, 'executeJavaScript', callback, code, hasUserGesture)
|
return executeJavaScript(this, code, hasUserGesture)
|
||||||
} else {
|
} else {
|
||||||
return new Promise((resolve, reject) => {
|
return new Promise((resolve, reject) => {
|
||||||
this.once('did-stop-loading', () => {
|
this.once('did-stop-loading', () => {
|
||||||
asyncWebFrameMethods.call(this, requestId, 'executeJavaScript', callback, code, hasUserGesture).then(resolve).catch(reject)
|
executeJavaScript(this, code, hasUserGesture).then(resolve, reject)
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
@ -345,6 +323,7 @@ WebContents.prototype.loadFile = function (filePath, options = {}) {
|
||||||
}
|
}
|
||||||
|
|
||||||
WebContents.prototype.capturePage = deprecate.promisify(WebContents.prototype.capturePage)
|
WebContents.prototype.capturePage = deprecate.promisify(WebContents.prototype.capturePage)
|
||||||
|
WebContents.prototype.executeJavaScript = deprecate.promisify(WebContents.prototype.executeJavaScript)
|
||||||
WebContents.prototype.printToPDF = deprecate.promisify(WebContents.prototype.printToPDF)
|
WebContents.prototype.printToPDF = deprecate.promisify(WebContents.prototype.printToPDF)
|
||||||
WebContents.prototype.savePage = deprecate.promisify(WebContents.prototype.savePage)
|
WebContents.prototype.savePage = deprecate.promisify(WebContents.prototype.savePage)
|
||||||
|
|
||||||
|
|
|
@ -94,10 +94,12 @@ const deprecate: ElectronInternal.DeprecationUtil = {
|
||||||
process.nextTick(() => {
|
process.nextTick(() => {
|
||||||
cb!.length === 2 ? cb!(null, res) : cb!(res)
|
cb!.length === 2 ? cb!(null, res) : cb!(res)
|
||||||
})
|
})
|
||||||
|
return res
|
||||||
}, (err: Error) => {
|
}, (err: Error) => {
|
||||||
process.nextTick(() => {
|
process.nextTick(() => {
|
||||||
cb!.length === 2 ? cb!(err) : cb!()
|
cb!.length === 2 ? cb!(err) : cb!()
|
||||||
})
|
})
|
||||||
|
throw err
|
||||||
})
|
})
|
||||||
} as T
|
} as T
|
||||||
},
|
},
|
||||||
|
|
|
@ -85,6 +85,15 @@ function getWebFrame (context: Window) {
|
||||||
return context ? new WebFrame(context) : null
|
return context ? new WebFrame(context) : null
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const promisifiedMethods = new Set<string>([
|
||||||
|
'executeJavaScript',
|
||||||
|
'executeJavaScriptInIsolatedWorld'
|
||||||
|
])
|
||||||
|
|
||||||
|
for (const method of promisifiedMethods) {
|
||||||
|
(WebFrame as any).prototype[method] = deprecate.promisify((WebFrame as any).prototype[method])
|
||||||
|
}
|
||||||
|
|
||||||
const _webFrame = new WebFrame(window)
|
const _webFrame = new WebFrame(window)
|
||||||
|
|
||||||
export default _webFrame
|
export default _webFrame
|
||||||
|
|
|
@ -64,16 +64,14 @@ const getIsRemoteProtocol = function () {
|
||||||
* @returns {boolean} Is a CSP with `unsafe-eval` set?
|
* @returns {boolean} Is a CSP with `unsafe-eval` set?
|
||||||
*/
|
*/
|
||||||
const isUnsafeEvalEnabled = function () {
|
const isUnsafeEvalEnabled = function () {
|
||||||
return new Promise((resolve) => {
|
return webFrame.executeJavaScript(`(${(() => {
|
||||||
webFrame.executeJavaScript(`(${(() => {
|
try {
|
||||||
try {
|
new Function('') // eslint-disable-line no-new,no-new-func
|
||||||
new Function('') // eslint-disable-line no-new,no-new-func
|
} catch {
|
||||||
} catch {
|
return false
|
||||||
return false
|
}
|
||||||
}
|
return true
|
||||||
return true
|
}).toString()})()`, false)
|
||||||
}).toString()})()`, false, resolve)
|
|
||||||
})
|
|
||||||
}
|
}
|
||||||
|
|
||||||
const moreInformation = `\nFor more information and help, consult
|
const moreInformation = `\nFor more information and help, consult
|
||||||
|
|
|
@ -1,7 +1,5 @@
|
||||||
import { webFrame, WebFrame } from 'electron'
|
import { webFrame, WebFrame } from 'electron'
|
||||||
import { ipcRendererInternal } from '@electron/internal/renderer/ipc-renderer-internal'
|
|
||||||
import * as ipcRendererUtils from '@electron/internal/renderer/ipc-renderer-internal-utils'
|
import * as ipcRendererUtils from '@electron/internal/renderer/ipc-renderer-internal-utils'
|
||||||
import * as errorUtils from '@electron/internal/common/error-utils'
|
|
||||||
|
|
||||||
// All keys of WebFrame that extend Function
|
// All keys of WebFrame that extend Function
|
||||||
type WebFrameMethod = {
|
type WebFrameMethod = {
|
||||||
|
@ -19,21 +17,4 @@ export const webFrameInit = () => {
|
||||||
// will be caught by "keyof WebFrameMethod" though.
|
// will be caught by "keyof WebFrameMethod" though.
|
||||||
return (webFrame[method] as any)(...args)
|
return (webFrame[method] as any)(...args)
|
||||||
})
|
})
|
||||||
|
|
||||||
ipcRendererInternal.on('ELECTRON_INTERNAL_RENDERER_ASYNC_WEB_FRAME_METHOD', (
|
|
||||||
event, requestId: number, method: keyof WebFrameMethod, args: any[]
|
|
||||||
) => {
|
|
||||||
new Promise(resolve =>
|
|
||||||
// The TypeScript compiler cannot handle the sheer number of
|
|
||||||
// call signatures here and simply gives up. Incorrect invocations
|
|
||||||
// will be caught by "keyof WebFrameMethod" though.
|
|
||||||
(webFrame[method] as any)(...args, resolve)
|
|
||||||
).then(result => {
|
|
||||||
return [null, result]
|
|
||||||
}, error => {
|
|
||||||
return [errorUtils.serialize(error)]
|
|
||||||
}).then(responseArgs => {
|
|
||||||
event.sender.send(`ELECTRON_INTERNAL_BROWSER_ASYNC_WEB_FRAME_RESPONSE_${requestId}`, ...responseArgs)
|
|
||||||
})
|
|
||||||
})
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -1075,7 +1075,21 @@ describe('webContents module', () => {
|
||||||
})
|
})
|
||||||
|
|
||||||
describe('webframe messages in sandboxed contents', () => {
|
describe('webframe messages in sandboxed contents', () => {
|
||||||
it('responds to executeJavaScript', (done) => {
|
it('responds to executeJavaScript', async () => {
|
||||||
|
w.destroy()
|
||||||
|
w = new BrowserWindow({
|
||||||
|
show: false,
|
||||||
|
webPreferences: {
|
||||||
|
sandbox: true
|
||||||
|
}
|
||||||
|
})
|
||||||
|
await w.loadURL('about:blank')
|
||||||
|
const result = await w.webContents.executeJavaScript('37 + 5')
|
||||||
|
assert.strictEqual(result, 42)
|
||||||
|
})
|
||||||
|
|
||||||
|
// TODO(miniak): remove when promisification is complete
|
||||||
|
it('responds to executeJavaScript (callback)', (done) => {
|
||||||
w.destroy()
|
w.destroy()
|
||||||
w = new BrowserWindow({
|
w = new BrowserWindow({
|
||||||
show: false,
|
show: false,
|
||||||
|
|
|
@ -97,6 +97,7 @@ app.on('ready', () => {
|
||||||
mainWindow.webContents.printToPDF({}, (err, data) => console.log(err))
|
mainWindow.webContents.printToPDF({}, (err, data) => console.log(err))
|
||||||
|
|
||||||
mainWindow.webContents.executeJavaScript('return true;').then((v: boolean) => console.log(v))
|
mainWindow.webContents.executeJavaScript('return true;').then((v: boolean) => console.log(v))
|
||||||
|
mainWindow.webContents.executeJavaScript('return true;', true).then((v: boolean) => console.log(v))
|
||||||
mainWindow.webContents.executeJavaScript('return true;', true)
|
mainWindow.webContents.executeJavaScript('return true;', true)
|
||||||
mainWindow.webContents.executeJavaScript('return true;', true, (result: boolean) => console.log(result))
|
mainWindow.webContents.executeJavaScript('return true;', true, (result: boolean) => console.log(result))
|
||||||
mainWindow.webContents.insertText('blah, blah, blah')
|
mainWindow.webContents.insertText('blah, blah, blah')
|
||||||
|
|
|
@ -72,9 +72,10 @@ webFrame.setSpellCheckProvider('en-US', {
|
||||||
|
|
||||||
webFrame.insertText('text')
|
webFrame.insertText('text')
|
||||||
|
|
||||||
webFrame.executeJavaScript('JSON.stringify({})', false, (result) => {
|
webFrame.executeJavaScript('return true;').then((v: boolean) => console.log(v))
|
||||||
console.log(result)
|
webFrame.executeJavaScript('return true;', true).then((v: boolean) => console.log(v))
|
||||||
}).then((result: string) => console.log('OK:' + result))
|
webFrame.executeJavaScript('return true;', true)
|
||||||
|
webFrame.executeJavaScript('return true;', true, (result: boolean) => console.log(result))
|
||||||
|
|
||||||
console.log(webFrame.getResourceUsage())
|
console.log(webFrame.getResourceUsage())
|
||||||
webFrame.clearCache()
|
webFrame.clearCache()
|
||||||
|
|
|
@ -789,11 +789,7 @@ describe('<webview> tag', function () {
|
||||||
const devtools = webview2.getWebContents()
|
const devtools = webview2.getWebContents()
|
||||||
assert.ok(devtools.getURL().startsWith('chrome-devtools://devtools'))
|
assert.ok(devtools.getURL().startsWith('chrome-devtools://devtools'))
|
||||||
|
|
||||||
const name = await new Promise((resolve) => {
|
const name = await devtools.executeJavaScript('InspectorFrontendHost.constructor.name')
|
||||||
devtools.executeJavaScript('InspectorFrontendHost.constructor.name', (name) => {
|
|
||||||
resolve(name)
|
|
||||||
})
|
|
||||||
})
|
|
||||||
document.body.removeChild(webview2)
|
document.body.removeChild(webview2)
|
||||||
|
|
||||||
expect(name).to.be.equal('InspectorFrontendHostImpl')
|
expect(name).to.be.equal('InspectorFrontendHostImpl')
|
||||||
|
@ -1001,6 +997,19 @@ describe('<webview> tag', function () {
|
||||||
const jsScript = "'4'+2"
|
const jsScript = "'4'+2"
|
||||||
const expectedResult = '42'
|
const expectedResult = '42'
|
||||||
|
|
||||||
|
const result = await webview.executeJavaScript(jsScript)
|
||||||
|
assert.strictEqual(result, expectedResult)
|
||||||
|
})
|
||||||
|
|
||||||
|
// TODO(miniak): remove when promisification is complete
|
||||||
|
it('can return the result of the executed script (callback)', async () => {
|
||||||
|
await loadWebView(webview, {
|
||||||
|
src: 'about:blank'
|
||||||
|
})
|
||||||
|
|
||||||
|
const jsScript = "'4'+2"
|
||||||
|
const expectedResult = '42'
|
||||||
|
|
||||||
const result = await new Promise((resolve) => {
|
const result = await new Promise((resolve) => {
|
||||||
webview.executeJavaScript(jsScript, false, (result) => {
|
webview.executeJavaScript(jsScript, false, (result) => {
|
||||||
resolve(result)
|
resolve(result)
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue