1 year ago
#173764
Elias Holzmann
Chrome: How can I dyn_cast() JavaScript objects that are part of a window created by window.open()
I am working on a Rust WASM library that works with the DOM. To simplify matters, let's assume that this library receives a Node as argument, determines its root node and appends a newly created div to that root node (Link to repo with complete MRE including HTML/JS):
#[wasm_bindgen]
pub fn append_div_to_document_containing(element: web_sys::HtmlElement) {
console_error_panic_hook::set_once();
let document = element
.get_root_node()
.dyn_into::<web_sys::HtmlDocument>()
.expect("get_root_node() did not return Document");
let div = document
.create_element("div")
.expect("create_element() failed");
div.set_text_content(Some("Created by WASM"));
document
.body()
.expect("root_node.body() returned null")
.append_with_node_1(&div)
.expect("Appending failed");
}
Additionally, I have created JavaScript that can run this function on either a div contained in the current window or a div contained in a new window created via window.open
:
<input type="button" id="div_here" value="Add div here">
<input type="button" id="div_window_open" value="Add div via window.open()">
<script type="module">
import init, { append_div_to_document_containing } from './pkg/window_open_chrome_instanceof.js';
window.onload = () => {
async function run() {
await init();
function createDivsWithJsAndWasm(document) {
let div = document.createElement("div");
div.textContent = "Created by JS";
document.body.append(div);
append_div_to_document_containing(div);
}
document.querySelector("#div_here").addEventListener("click", () => {
createDivsWithJsAndWasm(document);
});
document.querySelector("#div_window_open").addEventListener("click", () => {
createDivsWithJsAndWasm(window.open("", "", "popup").document);
});
}
run();
};
</script>
Both cases work in Firefox. However, the window.open()
case fails in Chrome:
window_open_chrome_instanceof.js:260 panicked at 'get_root_node() did not return Document: Node { obj: EventTarget { obj: Object { obj: JsValue(HTMLDocument) } } }', src/lib.rs:11:10
Stack:
Error
at http://192.168.12.34:8000/pkg/window_open_chrome_instanceof.js:266:19
at logError (http://192.168.12.34:8000/pkg/window_open_chrome_instanceof.js:189:18)
at imports.wbg.__wbg_new_693216e109162396 (http://192.168.12.34:8000/pkg/window_open_chrome_instanceof.js:265:66)
at console_error_panic_hook::Error::new::h04dcf1f78b1b65a5 (http://192.168.12.34:8000/pkg/window_open_chrome_instanceof_bg.wasm:wasm-function[433]:0x1577b)
at console_error_panic_hook::hook_impl::haf0cbfc93cb83b73 (http://192.168.12.34:8000/pkg/window_open_chrome_instanceof_bg.wasm:wasm-function[43]:0x6e7a)
at console_error_panic_hook::hook::hff46bfaa806ee83e (http://192.168.12.34:8000/pkg/window_open_chrome_instanceof_bg.wasm:wasm-function[483]:0x162ad)
at core::ops::function::Fn::call::hd9fb438233d248fe (http://192.168.12.34:8000/pkg/window_open_chrome_instanceof_bg.wasm:wasm-function[406]:0x150dc)
at std::panicking::rust_panic_with_hook::hf4c39fada27bd187 (http://192.168.12.34:8000/pkg/window_open_chrome_instanceof_bg.wasm:wasm-function[116]:0xc839)
at std::panicking::begin_panic_handler::{{closure}}::he7338bd7a89ffcbb (http://192.168.12.34:8000/pkg/window_open_chrome_instanceof_bg.wasm:wasm-function[186]:0xfc2b)
at std::sys_common::backtrace::__rust_end_short_backtrace::h0ded0f05f9eb8d88 (http://192.168.12.34:8000/pkg/window_open_chrome_instanceof_bg.wasm:wasm-function[612]:0x175c5)
I assume this is because in Chrome, the document contained in the opened window is not instanceof HTMLDocument
, but instanceof new_window.HTMLDocument
:
let new_window = window.open("", "", "popup")
console.log(new_window.document instanceof HTMLDocument); // false in Chrome, true in Firefox
console.log(new_window.document instanceof new_window.HTMLDocument); // true in Chrome, true in Firefox
This isn't just a problem with the document
object, but with every JavaScript object that is associated with the new window. For example, the CanvasRenderingContext2D
of a canvas inside the new window is not instanceof CanvasRenderingContext2D
, but instanceof new_window.CanvasRenderingContext2D
. Even the window itself is not instanceof Window
, but instanceof new_window.Window
:
let new_window = window.open("", "", "popup")
console.log(new_window instanceof Window); // false in Chrome, true in Firefox
console.log(new_window instanceof new_window.Window); // true in Chrome, true in Firefox
An easy solution in this example would be to use unchecked_into()
instead of dyn_into()
. However, in my real code, there are multiple dyn_into()
invocations that I would need to replace with unchecked_into()
, and I don't like the idea of giving up type safety just for this edge case.
Is there any workaround that allows successful dyn_into()
casts on JavaScript objects that are part of a window created via window.open
?
javascript
google-chrome
rust
wasm-bindgen
0 Answers
Your Answer