feat: add webFrameMain.executeJavaScriptInIsolatedWorld() (#26913)
This commit is contained in:
parent
5f99569b6c
commit
3d59aa5609
4 changed files with 73 additions and 0 deletions
|
@ -86,6 +86,17 @@ 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.
|
||||||
|
|
||||||
|
#### `frame.executeJavaScriptInIsolatedWorld(worldId, code[, userGesture])`
|
||||||
|
|
||||||
|
* `worldId` Integer - The ID of the world to run the javascript in, `0` is the default world, `999` is the world used by Electron's `contextIsolation` feature. You can provide any integer here.
|
||||||
|
* `code` String
|
||||||
|
* `userGesture` Boolean (optional) - Default is `false`.
|
||||||
|
|
||||||
|
Returns `Promise<unknown>` - A promise that resolves with the result of the executed
|
||||||
|
code or is rejected if execution throws or results in a rejected promise.
|
||||||
|
|
||||||
|
Works like `executeJavaScript` but evaluates `scripts` in an isolated context.
|
||||||
|
|
||||||
#### `frame.reload()`
|
#### `frame.reload()`
|
||||||
|
|
||||||
Returns `boolean` - Whether the reload was initiated successfully. Only results in `false` when the frame has no history.
|
Returns `boolean` - Whether the reload was initiated successfully. Only results in `false` when the frame has no history.
|
||||||
|
|
|
@ -108,6 +108,49 @@ v8::Local<v8::Promise> WebFrameMain::ExecuteJavaScript(
|
||||||
return handle;
|
return handle;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
v8::Local<v8::Promise> WebFrameMain::ExecuteJavaScriptInIsolatedWorld(
|
||||||
|
gin::Arguments* args,
|
||||||
|
int world_id,
|
||||||
|
const base::string16& code) {
|
||||||
|
gin_helper::Promise<base::Value> promise(args->isolate());
|
||||||
|
v8::Local<v8::Promise> handle = promise.GetHandle();
|
||||||
|
|
||||||
|
// Optional userGesture parameter
|
||||||
|
bool user_gesture;
|
||||||
|
if (!args->PeekNext().IsEmpty()) {
|
||||||
|
if (args->PeekNext()->IsBoolean()) {
|
||||||
|
args->GetNext(&user_gesture);
|
||||||
|
} else {
|
||||||
|
args->ThrowTypeError("userGesture must be a boolean");
|
||||||
|
return handle;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
user_gesture = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (render_frame_disposed_) {
|
||||||
|
promise.RejectWithErrorMessage(
|
||||||
|
"Render frame was disposed before WebFrameMain could be accessed");
|
||||||
|
return handle;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (user_gesture) {
|
||||||
|
auto* ftn = content::FrameTreeNode::From(render_frame_);
|
||||||
|
ftn->UpdateUserActivationState(
|
||||||
|
blink::mojom::UserActivationUpdateType::kNotifyActivation,
|
||||||
|
blink::mojom::UserActivationNotificationType::kTest);
|
||||||
|
}
|
||||||
|
|
||||||
|
render_frame_->ExecuteJavaScriptForTests(
|
||||||
|
code,
|
||||||
|
base::BindOnce([](gin_helper::Promise<base::Value> promise,
|
||||||
|
base::Value value) { promise.Resolve(value); },
|
||||||
|
std::move(promise)),
|
||||||
|
world_id);
|
||||||
|
|
||||||
|
return handle;
|
||||||
|
}
|
||||||
|
|
||||||
bool WebFrameMain::Reload(v8::Isolate* isolate) {
|
bool WebFrameMain::Reload(v8::Isolate* isolate) {
|
||||||
if (!CheckRenderFrame())
|
if (!CheckRenderFrame())
|
||||||
return false;
|
return false;
|
||||||
|
@ -222,6 +265,8 @@ gin::ObjectTemplateBuilder WebFrameMain::GetObjectTemplateBuilder(
|
||||||
v8::Isolate* isolate) {
|
v8::Isolate* isolate) {
|
||||||
return gin::Wrappable<WebFrameMain>::GetObjectTemplateBuilder(isolate)
|
return gin::Wrappable<WebFrameMain>::GetObjectTemplateBuilder(isolate)
|
||||||
.SetMethod("executeJavaScript", &WebFrameMain::ExecuteJavaScript)
|
.SetMethod("executeJavaScript", &WebFrameMain::ExecuteJavaScript)
|
||||||
|
.SetMethod("executeJavaScriptInIsolatedWorld",
|
||||||
|
&WebFrameMain::ExecuteJavaScriptInIsolatedWorld)
|
||||||
.SetMethod("reload", &WebFrameMain::Reload)
|
.SetMethod("reload", &WebFrameMain::Reload)
|
||||||
.SetProperty("frameTreeNodeId", &WebFrameMain::FrameTreeNodeID)
|
.SetProperty("frameTreeNodeId", &WebFrameMain::FrameTreeNodeID)
|
||||||
.SetProperty("name", &WebFrameMain::Name)
|
.SetProperty("name", &WebFrameMain::Name)
|
||||||
|
|
|
@ -66,6 +66,10 @@ class WebFrameMain : public gin::Wrappable<WebFrameMain> {
|
||||||
|
|
||||||
v8::Local<v8::Promise> ExecuteJavaScript(gin::Arguments* args,
|
v8::Local<v8::Promise> ExecuteJavaScript(gin::Arguments* args,
|
||||||
const base::string16& code);
|
const base::string16& code);
|
||||||
|
v8::Local<v8::Promise> ExecuteJavaScriptInIsolatedWorld(
|
||||||
|
gin::Arguments* args,
|
||||||
|
int world_id,
|
||||||
|
const base::string16& code);
|
||||||
bool Reload(v8::Isolate* isolate);
|
bool Reload(v8::Isolate* isolate);
|
||||||
|
|
||||||
int FrameTreeNodeID(v8::Isolate* isolate) const;
|
int FrameTreeNodeID(v8::Isolate* isolate) const;
|
||||||
|
|
|
@ -147,6 +147,19 @@ describe('webFrameMain module', () => {
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
|
describe('WebFrame.executeJavaScriptInIsolatedWorld', () => {
|
||||||
|
it('can inject code into any subframe', async () => {
|
||||||
|
const w = new BrowserWindow({ show: false, webPreferences: { contextIsolation: true } });
|
||||||
|
await w.loadFile(path.join(subframesPath, 'frame-with-frame-container.html'));
|
||||||
|
const webFrame = w.webContents.mainFrame;
|
||||||
|
|
||||||
|
const getUrl = (frame: WebFrameMain) => frame.executeJavaScriptInIsolatedWorld(999, 'location.href');
|
||||||
|
expect(await getUrl(webFrame)).to.equal(fileUrl('frame-with-frame-container.html'));
|
||||||
|
expect(await getUrl(webFrame.frames[0])).to.equal(fileUrl('frame-with-frame.html'));
|
||||||
|
expect(await getUrl(webFrame.frames[0].frames[0])).to.equal(fileUrl('frame.html'));
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
describe('WebFrame.reload', () => {
|
describe('WebFrame.reload', () => {
|
||||||
it('reloads a frame', async () => {
|
it('reloads a frame', async () => {
|
||||||
const w = new BrowserWindow({ show: false, webPreferences: { contextIsolation: true } });
|
const w = new BrowserWindow({ show: false, webPreferences: { contextIsolation: true } });
|
||||||
|
|
Loading…
Reference in a new issue