webContents: provide responses for executeJavscript method
This commit is contained in:
parent
d00490271b
commit
2b547bd44a
9 changed files with 113 additions and 13 deletions
|
@ -1,3 +1,7 @@
|
||||||
const EventEmitter = require('events').EventEmitter;
|
const EventEmitter = require('events').EventEmitter;
|
||||||
|
|
||||||
module.exports = new EventEmitter;
|
module.exports = new EventEmitter;
|
||||||
|
|
||||||
|
// Every webContents would add a listenter to the
|
||||||
|
// WEB_FRAME_RESPONSE event, so ignore the listenters warning.
|
||||||
|
module.exports.setMaxListeners(0);
|
||||||
|
|
|
@ -11,6 +11,7 @@ const debuggerBinding = process.atomBinding('debugger');
|
||||||
|
|
||||||
let slice = [].slice;
|
let slice = [].slice;
|
||||||
let nextId = 0;
|
let nextId = 0;
|
||||||
|
let responseCallback = {};
|
||||||
|
|
||||||
let getNextId = function() {
|
let getNextId = function() {
|
||||||
return ++nextId;
|
return ++nextId;
|
||||||
|
@ -109,13 +110,24 @@ let wrapWebContents = function(webContents) {
|
||||||
// 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.
|
||||||
const executeJavaScript = webContents.executeJavaScript;
|
const executeJavaScript = webContents.executeJavaScript;
|
||||||
webContents.executeJavaScript = function(code, hasUserGesture) {
|
webContents.executeJavaScript = function(code, hasUserGesture, callback) {
|
||||||
|
if (typeof hasUserGesture === "function") {
|
||||||
|
callback = hasUserGesture;
|
||||||
|
hasUserGesture = false;
|
||||||
|
}
|
||||||
|
if (callback !== null)
|
||||||
|
responseCallback["executeJavaScript"] = callback;
|
||||||
if (this.getURL() && !this.isLoading())
|
if (this.getURL() && !this.isLoading())
|
||||||
return executeJavaScript.call(this, code, hasUserGesture);
|
return executeJavaScript.call(this, code, hasUserGesture);
|
||||||
else
|
else
|
||||||
return this.once('did-finish-load', executeJavaScript.bind(this, code, hasUserGesture));
|
return this.once('did-finish-load', executeJavaScript.bind(this, code, hasUserGesture));
|
||||||
};
|
};
|
||||||
|
|
||||||
|
ipcMain.on('ELECTRON_INTERNAL_RENDERER_WEB_FRAME_RESPONSE', function(event, method, result) {
|
||||||
|
if (responseCallback[method])
|
||||||
|
responseCallback[method].apply(null, [result]);
|
||||||
|
});
|
||||||
|
|
||||||
// Dispatch IPC messages to the ipc module.
|
// Dispatch IPC messages to the ipc module.
|
||||||
webContents.on('ipc-message', function(event, packed) {
|
webContents.on('ipc-message', function(event, packed) {
|
||||||
var args, channel;
|
var args, channel;
|
||||||
|
|
|
@ -6,6 +6,7 @@
|
||||||
#define ATOM_COMMON_NATIVE_MATE_CONVERTERS_BLINK_CONVERTER_H_
|
#define ATOM_COMMON_NATIVE_MATE_CONVERTERS_BLINK_CONVERTER_H_
|
||||||
|
|
||||||
#include "native_mate/converter.h"
|
#include "native_mate/converter.h"
|
||||||
|
#include "third_party/WebKit/public/platform/WebVector.h"
|
||||||
|
|
||||||
namespace blink {
|
namespace blink {
|
||||||
class WebInputEvent;
|
class WebInputEvent;
|
||||||
|
@ -87,6 +88,19 @@ struct Converter<blink::WebFindOptions> {
|
||||||
blink::WebFindOptions* out);
|
blink::WebFindOptions* out);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
template<typename T>
|
||||||
|
struct Converter<blink::WebVector<T> > {
|
||||||
|
static v8::Local<v8::Value> ToV8(v8::Isolate* isolate,
|
||||||
|
const blink::WebVector<T>& val) {
|
||||||
|
v8::Local<v8::Array> result(
|
||||||
|
MATE_ARRAY_NEW(isolate, static_cast<int>(val.size())));
|
||||||
|
for (size_t i = 0; i < val.size(); ++i) {
|
||||||
|
result->Set(static_cast<int>(i), Converter<T>::ToV8(isolate, val[i]));
|
||||||
|
}
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
} // namespace mate
|
} // namespace mate
|
||||||
|
|
||||||
#endif // ATOM_COMMON_NATIVE_MATE_CONVERTERS_BLINK_CONVERTER_H_
|
#endif // ATOM_COMMON_NATIVE_MATE_CONVERTERS_BLINK_CONVERTER_H_
|
||||||
|
|
|
@ -8,6 +8,7 @@
|
||||||
#include "atom/common/native_mate_converters/callback.h"
|
#include "atom/common/native_mate_converters/callback.h"
|
||||||
#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/native_mate_converters/blink_converter.h"
|
||||||
#include "atom/renderer/api/atom_api_spell_check_client.h"
|
#include "atom/renderer/api/atom_api_spell_check_client.h"
|
||||||
#include "content/public/renderer/render_frame.h"
|
#include "content/public/renderer/render_frame.h"
|
||||||
#include "content/public/renderer/render_view.h"
|
#include "content/public/renderer/render_view.h"
|
||||||
|
@ -15,7 +16,7 @@
|
||||||
#include "native_mate/object_template_builder.h"
|
#include "native_mate/object_template_builder.h"
|
||||||
#include "third_party/WebKit/public/web/WebDocument.h"
|
#include "third_party/WebKit/public/web/WebDocument.h"
|
||||||
#include "third_party/WebKit/public/web/WebLocalFrame.h"
|
#include "third_party/WebKit/public/web/WebLocalFrame.h"
|
||||||
#include "third_party/WebKit/public/web/WebScopedUserGesture.h"
|
#include "third_party/WebKit/public/web/WebScriptExecutionCallback.h"
|
||||||
#include "third_party/WebKit/public/web/WebScriptSource.h"
|
#include "third_party/WebKit/public/web/WebScriptSource.h"
|
||||||
#include "third_party/WebKit/public/web/WebSecurityPolicy.h"
|
#include "third_party/WebKit/public/web/WebSecurityPolicy.h"
|
||||||
#include "third_party/WebKit/public/web/WebView.h"
|
#include "third_party/WebKit/public/web/WebView.h"
|
||||||
|
@ -26,6 +27,33 @@ namespace atom {
|
||||||
|
|
||||||
namespace api {
|
namespace api {
|
||||||
|
|
||||||
|
namespace {
|
||||||
|
|
||||||
|
class ScriptExecutionCallback : public blink::WebScriptExecutionCallback {
|
||||||
|
public:
|
||||||
|
using CompletionCallback =
|
||||||
|
base::Callback<void(
|
||||||
|
const blink::WebVector<v8::Local<v8::Value>>& result)>;
|
||||||
|
|
||||||
|
explicit ScriptExecutionCallback(const CompletionCallback& callback)
|
||||||
|
: callback_(callback) {}
|
||||||
|
~ScriptExecutionCallback() {}
|
||||||
|
|
||||||
|
void completed(
|
||||||
|
const blink::WebVector<v8::Local<v8::Value>>& result) override {
|
||||||
|
if (!callback_.is_null())
|
||||||
|
callback_.Run(result);
|
||||||
|
delete this;
|
||||||
|
}
|
||||||
|
|
||||||
|
private:
|
||||||
|
CompletionCallback callback_;
|
||||||
|
|
||||||
|
DISALLOW_COPY_AND_ASSIGN(ScriptExecutionCallback);
|
||||||
|
};
|
||||||
|
|
||||||
|
} // namespace
|
||||||
|
|
||||||
WebFrame::WebFrame()
|
WebFrame::WebFrame()
|
||||||
: web_frame_(blink::WebLocalFrame::frameForCurrentContext()) {
|
: web_frame_(blink::WebLocalFrame::frameForCurrentContext()) {
|
||||||
}
|
}
|
||||||
|
@ -124,9 +152,14 @@ void WebFrame::ExecuteJavaScript(const base::string16& code,
|
||||||
mate::Arguments* args) {
|
mate::Arguments* args) {
|
||||||
bool has_user_gesture = false;
|
bool has_user_gesture = false;
|
||||||
args->GetNext(&has_user_gesture);
|
args->GetNext(&has_user_gesture);
|
||||||
scoped_ptr<blink::WebScopedUserGesture> gesture(
|
ScriptExecutionCallback::CompletionCallback completion_callback;
|
||||||
has_user_gesture ? new blink::WebScopedUserGesture : nullptr);
|
args->GetNext(&completion_callback);
|
||||||
web_frame_->executeScriptAndReturnValue(blink::WebScriptSource(code));
|
scoped_ptr<blink::WebScriptExecutionCallback> callback(
|
||||||
|
new ScriptExecutionCallback(completion_callback));
|
||||||
|
web_frame_->requestExecuteScriptAndReturnValue(
|
||||||
|
blink::WebScriptSource(code),
|
||||||
|
has_user_gesture,
|
||||||
|
callback.release());
|
||||||
}
|
}
|
||||||
|
|
||||||
mate::ObjectTemplateBuilder WebFrame::GetObjectTemplateBuilder(
|
mate::ObjectTemplateBuilder WebFrame::GetObjectTemplateBuilder(
|
||||||
|
|
|
@ -32,7 +32,17 @@ v8Util.setHiddenValue(global, 'ipc', new events.EventEmitter);
|
||||||
const electron = require('electron');
|
const electron = require('electron');
|
||||||
|
|
||||||
// Call webFrame method.
|
// Call webFrame method.
|
||||||
|
const asyncWebFrameMethods = [
|
||||||
|
'executeJavaScript'
|
||||||
|
];
|
||||||
|
|
||||||
electron.ipcRenderer.on('ELECTRON_INTERNAL_RENDERER_WEB_FRAME_METHOD', (event, method, args) => {
|
electron.ipcRenderer.on('ELECTRON_INTERNAL_RENDERER_WEB_FRAME_METHOD', (event, method, args) => {
|
||||||
|
if (asyncWebFrameMethods.includes(method)) {
|
||||||
|
const responseCallback = function(result) {
|
||||||
|
event.sender.send('ELECTRON_INTERNAL_RENDERER_WEB_FRAME_RESPONSE', method, result);
|
||||||
|
};
|
||||||
|
args.push(responseCallback);
|
||||||
|
}
|
||||||
electron.webFrame[method].apply(electron.webFrame, args);
|
electron.webFrame[method].apply(electron.webFrame, args);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|
|
@ -307,7 +307,7 @@ var registerBrowserPluginElement = function() {
|
||||||
|
|
||||||
// Registers <webview> custom element.
|
// Registers <webview> custom element.
|
||||||
var registerWebViewElement = function() {
|
var registerWebViewElement = function() {
|
||||||
var createBlockHandler, createNonBlockHandler, i, j, len, len1, m, methods, nonblockMethods, proto;
|
var createBlockHandler, createNonBlockHandler, i, j, len, len1, m, methods, nonblockMethods, webFrameMethods, proto;
|
||||||
proto = Object.create(HTMLObjectElement.prototype);
|
proto = Object.create(HTMLObjectElement.prototype);
|
||||||
proto.createdCallback = function() {
|
proto.createdCallback = function() {
|
||||||
return new WebViewImpl(this);
|
return new WebViewImpl(this);
|
||||||
|
@ -391,14 +391,16 @@ var registerWebViewElement = function() {
|
||||||
'printToPDF',
|
'printToPDF',
|
||||||
];
|
];
|
||||||
nonblockMethods = [
|
nonblockMethods = [
|
||||||
'executeJavaScript',
|
|
||||||
'insertCSS',
|
'insertCSS',
|
||||||
'insertText',
|
|
||||||
'send',
|
'send',
|
||||||
'sendInputEvent',
|
'sendInputEvent'
|
||||||
|
];
|
||||||
|
webFrameMethods = [
|
||||||
|
'executeJavaScript',
|
||||||
|
'insertText',
|
||||||
'setZoomFactor',
|
'setZoomFactor',
|
||||||
'setZoomLevel',
|
'setZoomLevel',
|
||||||
'setZoomLevelLimits',
|
'setZoomLevelLimits'
|
||||||
];
|
];
|
||||||
|
|
||||||
// Forward proto.foo* method calls to WebViewImpl.foo*.
|
// Forward proto.foo* method calls to WebViewImpl.foo*.
|
||||||
|
@ -430,6 +432,11 @@ var registerWebViewElement = function() {
|
||||||
proto[m] = createNonBlockHandler(m);
|
proto[m] = createNonBlockHandler(m);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Forward proto.foo* webframe method calls to WebFrame.foo*.
|
||||||
|
for (let method of webFrameMethods) {
|
||||||
|
proto[method] = webFrame[method].bind(webFrame);
|
||||||
|
}
|
||||||
|
|
||||||
// WebContents associated with this webview.
|
// WebContents associated with this webview.
|
||||||
proto.getWebContents = function() {
|
proto.getWebContents = function() {
|
||||||
var internal = v8Util.getHiddenValue(this, 'internal');
|
var internal = v8Util.getHiddenValue(this, 'internal');
|
||||||
|
|
|
@ -425,10 +425,12 @@ Returns a `String` representing the user agent for this web page.
|
||||||
|
|
||||||
Injects CSS into the current web page.
|
Injects CSS into the current web page.
|
||||||
|
|
||||||
### `webContents.executeJavaScript(code[, userGesture])`
|
### `webContents.executeJavaScript(code[, userGesture, callback])`
|
||||||
|
|
||||||
* `code` String
|
* `code` String
|
||||||
* `userGesture` Boolean (optional)
|
* `userGesture` Boolean (optional)
|
||||||
|
* `callback` Function (optional) - Called after script has been executed.
|
||||||
|
* `result` Array
|
||||||
|
|
||||||
Evaluates `code` in page.
|
Evaluates `code` in page.
|
||||||
|
|
||||||
|
|
|
@ -279,10 +279,12 @@ Returns a `String` representing the user agent for guest page.
|
||||||
|
|
||||||
Injects CSS into the guest page.
|
Injects CSS into the guest page.
|
||||||
|
|
||||||
### `<webview>.executeJavaScript(code, userGesture)`
|
### `<webview>.executeJavaScript(code, userGesture, callback)`
|
||||||
|
|
||||||
* `code` String
|
* `code` String
|
||||||
* `userGesture` Boolean - Default `false`.
|
* `userGesture` Boolean - Default `false`.
|
||||||
|
* `callback` Function (optional) - Called after script has been executed.
|
||||||
|
* `result` Array
|
||||||
|
|
||||||
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
|
||||||
|
|
|
@ -194,6 +194,7 @@ describe('<webview> tag', function() {
|
||||||
document.body.appendChild(webview);
|
document.body.appendChild(webview);
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
describe('partition attribute', function() {
|
describe('partition attribute', function() {
|
||||||
it('inserts no node symbols when not set', function(done) {
|
it('inserts no node symbols when not set', function(done) {
|
||||||
webview.addEventListener('console-message', function(e) {
|
webview.addEventListener('console-message', function(e) {
|
||||||
|
@ -356,6 +357,7 @@ describe('<webview> tag', function() {
|
||||||
document.body.appendChild(webview);
|
document.body.appendChild(webview);
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
describe('did-navigate-in-page event', function() {
|
describe('did-navigate-in-page event', function() {
|
||||||
it('emits when an anchor link is clicked', function(done) {
|
it('emits when an anchor link is clicked', function(done) {
|
||||||
var p = path.join(fixtures, 'pages', 'webview-did-navigate-in-page.html');
|
var p = path.join(fixtures, 'pages', 'webview-did-navigate-in-page.html');
|
||||||
|
@ -556,7 +558,7 @@ describe('<webview> tag', function() {
|
||||||
done();
|
done();
|
||||||
};
|
};
|
||||||
var listener2 = function() {
|
var listener2 = function() {
|
||||||
var jsScript = 'document.getElementsByTagName("video")[0].webkitRequestFullScreen()';
|
var jsScript = "document.querySelector('video').webkitRequestFullscreen()";
|
||||||
webview.executeJavaScript(jsScript, true);
|
webview.executeJavaScript(jsScript, true);
|
||||||
webview.removeEventListener('did-finish-load', listener2);
|
webview.removeEventListener('did-finish-load', listener2);
|
||||||
};
|
};
|
||||||
|
@ -565,6 +567,20 @@ describe('<webview> tag', function() {
|
||||||
webview.src = "file://" + fixtures + "/pages/fullscreen.html";
|
webview.src = "file://" + fixtures + "/pages/fullscreen.html";
|
||||||
document.body.appendChild(webview);
|
document.body.appendChild(webview);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
it('can return the result of the executed script', function(done) {
|
||||||
|
var listener = function() {
|
||||||
|
var jsScript = "'4'+2";
|
||||||
|
webview.executeJavaScript(jsScript, false, function(result) {
|
||||||
|
assert.equal(result[0], '42');
|
||||||
|
done();
|
||||||
|
});
|
||||||
|
webview.removeEventListener('did-finish-load', listener);
|
||||||
|
};
|
||||||
|
webview.addEventListener('did-finish-load', listener);
|
||||||
|
webview.src = "about:blank";
|
||||||
|
document.body.appendChild(webview);
|
||||||
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
describe('sendInputEvent', function() {
|
describe('sendInputEvent', function() {
|
||||||
|
|
Loading…
Reference in a new issue