Skip to content

Commit

Permalink
feat: add support for DOM elements going over the context bridge (#26776
Browse files Browse the repository at this point in the history
)

* feat: add support for DOM elements going over the context bridge

* Update context-bridge.md
  • Loading branch information
MarshallOfSound committed Dec 10, 2020
1 parent 51db2a6 commit b9c9e7f
Show file tree
Hide file tree
Showing 3 changed files with 42 additions and 3 deletions.
1 change: 1 addition & 0 deletions docs/api/context-bridge.md
Expand Up @@ -106,6 +106,7 @@ has been included below for completeness:
| `Promise` | Complex ||| Promises are only proxied if they are the return value or exact parameter. Promises nested in arrays or objects will be dropped. |
| `Function` | Complex ||| Prototype modifications are dropped. Sending classes or constructors will not work. |
| [Cloneable Types](https://developer.mozilla.org/en-US/docs/Web/API/Web_Workers_API/Structured_clone_algorithm) | Simple ||| See the linked document on cloneable types |
| `Element` | Complex ||| Prototype modifications are dropped. Sending custom elements will not work. |
| `Symbol` | N/A ||| Symbols cannot be copied across contexts so they are dropped |

If the type you care about is not in the above table, it is probably not supported.
9 changes: 9 additions & 0 deletions shell/renderer/api/electron_api_context_bridge.cc
Expand Up @@ -22,6 +22,7 @@
#include "shell/common/gin_helper/promise.h"
#include "shell/common/node_includes.h"
#include "shell/common/world_ids.h"
#include "third_party/blink/public/web/web_element.h"
#include "third_party/blink/public/web/web_local_frame.h"

namespace electron {
Expand Down Expand Up @@ -319,6 +320,14 @@ v8::MaybeLocal<v8::Value> PassValueToOtherContext(
return v8::MaybeLocal<v8::Value>(cloned_arr);
}

// Custom logic to "clone" Element references
blink::WebElement elem = blink::WebElement::FromV8Value(value);
if (!elem.IsNull()) {
v8::Context::Scope destination_context_scope(destination_context);
return v8::MaybeLocal<v8::Value>(elem.ToV8Value(
destination_context->Global(), destination_context->GetIsolate()));
}

// Proxy all objects
if (IsPlainObject(value)) {
auto object_value = v8::Local<v8::Object>::Cast(value);
Expand Down
35 changes: 32 additions & 3 deletions spec-main/api-context-bridge-spec.ts
Expand Up @@ -517,7 +517,7 @@ describe('contextBridge', () => {
expect(result).to.deep.equal([true, true]);
});

it('it should handle recursive objects', async () => {
it('should handle recursive objects', async () => {
await makeBindingWindow(() => {
const o: any = { value: 135 };
o.o = o;
Expand All @@ -531,6 +531,33 @@ describe('contextBridge', () => {
expect(result).to.deep.equal([135, 135, 135]);
});

it('should handle DOM elements', async () => {
await makeBindingWindow(() => {
contextBridge.exposeInMainWorld('example', {
getElem: () => document.body
});
});
const result = await callWithBindings((root: any) => {
return [root.example.getElem().tagName, root.example.getElem().constructor.name, typeof root.example.getElem().querySelector];
});
expect(result).to.deep.equal(['BODY', 'HTMLBodyElement', 'function']);
});

it('should handle DOM elements going backwards over the bridge', async () => {
await makeBindingWindow(() => {
contextBridge.exposeInMainWorld('example', {
getElemInfo: (fn: Function) => {
const elem = fn();
return [elem.tagName, elem.constructor.name, typeof elem.querySelector];
}
});
});
const result = await callWithBindings((root: any) => {
return root.example.getElemInfo(() => document.body);
});
expect(result).to.deep.equal(['BODY', 'HTMLBodyElement', 'function']);
});

// Can only run tests which use the GCRunner in non-sandboxed environments
if (!useSandbox) {
it('should release the global hold on methods sent across contexts', async () => {
Expand Down Expand Up @@ -735,7 +762,8 @@ describe('contextBridge', () => {
receiveArguments: (fn: any) => fn({ key: 'value' }),
symbolKeyed: {
[Symbol('foo')]: 123
}
},
getBody: () => document.body
});
});
const result = await callWithBindings(async (root: any) => {
Expand Down Expand Up @@ -807,7 +835,8 @@ describe('contextBridge', () => {
[(await example.object.getPromise()).arr[3], Array],
[(await example.object.getPromise()).arr[3][0], String],
[arg, Object],
[arg.key, String]
[arg.key, String],
[example.getBody(), HTMLBodyElement]
];
return {
protoMatches: protoChecks.map(([a, Constructor]) => Object.getPrototypeOf(a) === Constructor.prototype)
Expand Down

0 comments on commit b9c9e7f

Please sign in to comment.