diff --git a/Cargo.lock b/Cargo.lock index 456f4bf7a6..de7afb9eb3 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -8524,9 +8524,19 @@ dependencies = [ [[package]] name = "sledgehammer_bindgen" -version = "0.3.1" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fa1ca40134578bf7cf17973defcd4eb8d7d2adf7868b29892481722957bd543e" +dependencies = [ + "sledgehammer_bindgen_macro", + "wasm-bindgen", +] + +[[package]] +name = "sledgehammer_bindgen_macro" +version = "0.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9298e863f0143b89972299110a7fa3e2fc08c412341d588c497bae38409f9e68" +checksum = "04559ded3de5c62f08457cadcb6c44649c4d90e72fdc0804c6c30ce1bc526304" dependencies = [ "quote", "syn 2.0.50", diff --git a/packages/desktop/src/protocol.rs b/packages/desktop/src/protocol.rs index 1337f03252..dbbd905aea 100644 --- a/packages/desktop/src/protocol.rs +++ b/packages/desktop/src/protocol.rs @@ -43,6 +43,7 @@ fn handle_edits_code() -> String { }"#; let polling_request = format!( r#"// Poll for requests + window.interpreter = new JSChannel(); window.interpreter.wait_for_request = (headless) => {{ fetch(new Request("{EDITS_PATH}")) .then(response => {{ @@ -50,11 +51,11 @@ fn handle_edits_code() -> String { .then(bytes => {{ // In headless mode, the requestAnimationFrame callback is never called, so we need to run the bytes directly if (headless) {{ - run_from_bytes(bytes); + window.interpreter.run_from_bytes(bytes); }} else {{ requestAnimationFrame(() => {{ - run_from_bytes(bytes); + window.interpreter.run_from_bytes(bytes); }}); }} window.interpreter.wait_for_request(headless); @@ -74,7 +75,7 @@ fn handle_edits_code() -> String { interpreter.replace_range(import_start..import_end, ""); } - format!("{interpreter}\nconst config = new InterpreterConfig(true);") + format!("{interpreter}\nconst intercept_link_redirects = true;") } static DEFAULT_INDEX: &str = include_str!("./index.html"); diff --git a/packages/interpreter/Cargo.toml b/packages/interpreter/Cargo.toml index 009873a6e0..ba813a538e 100644 --- a/packages/interpreter/Cargo.toml +++ b/packages/interpreter/Cargo.toml @@ -17,7 +17,7 @@ web-sys = { version = "0.3.56", optional = true, features = [ "Element", "Node", ] } -sledgehammer_bindgen = { version = "0.3.1", default-features = false, optional = true } +sledgehammer_bindgen = { version = "0.4.0", default-features = false, optional = true } sledgehammer_utils = { version = "0.2", optional = true } serde = { version = "1.0", features = ["derive"], optional = true } diff --git a/packages/interpreter/src/common.js b/packages/interpreter/src/common.js index 0c64085f98..055353fa56 100644 --- a/packages/interpreter/src/common.js +++ b/packages/interpreter/src/common.js @@ -1,4 +1,4 @@ -export function setAttributeInner(node, field, value, ns) { +this.setAttributeInner = function (node, field, value, ns) { const name = field; if (ns === "style") { // ????? why do we need to do this diff --git a/packages/interpreter/src/common_exported.js b/packages/interpreter/src/common_exported.js new file mode 100644 index 0000000000..0c64085f98 --- /dev/null +++ b/packages/interpreter/src/common_exported.js @@ -0,0 +1,79 @@ +export function setAttributeInner(node, field, value, ns) { + const name = field; + if (ns === "style") { + // ????? why do we need to do this + if (node.style === undefined) { + node.style = {}; + } + node.style[name] = value; + } else if (!!ns) { + node.setAttributeNS(ns, name, value); + } else { + switch (name) { + case "value": + if (value !== node.value) { + node.value = value; + } + break; + case "initial_value": + node.defaultValue = value; + break; + case "checked": + node.checked = truthy(value); + break; + case "initial_checked": + node.defaultChecked = truthy(value); + break; + case "selected": + node.selected = truthy(value); + break; + case "initial_selected": + node.defaultSelected = truthy(value); + break; + case "dangerous_inner_html": + node.innerHTML = value; + break; + default: + // https://github.com/facebook/react/blob/8b88ac2592c5f555f315f9440cbb665dd1e7457a/packages/react-dom/src/shared/DOMProperty.js#L352-L364 + if (!truthy(value) && bool_attrs.hasOwnProperty(name)) { + node.removeAttribute(name); + } else { + node.setAttribute(name, value); + } + } + } +} + +const bool_attrs = { + allowfullscreen: true, + allowpaymentrequest: true, + async: true, + autofocus: true, + autoplay: true, + checked: true, + controls: true, + default: true, + defer: true, + disabled: true, + formnovalidate: true, + hidden: true, + ismap: true, + itemscope: true, + loop: true, + multiple: true, + muted: true, + nomodule: true, + novalidate: true, + open: true, + playsinline: true, + readonly: true, + required: true, + reversed: true, + selected: true, + truespeed: true, + webkitdirectory: true, +}; + +function truthy(val) { + return val === "true" || val === true; +} diff --git a/packages/interpreter/src/interpreter.js b/packages/interpreter/src/interpreter.js index 0e98006450..5887828c7f 100644 --- a/packages/interpreter/src/interpreter.js +++ b/packages/interpreter/src/interpreter.js @@ -1,12 +1,6 @@ -class InterpreterConfig { - constructor(intercept_link_redirects) { - this.intercept_link_redirects = intercept_link_redirects; - } -} - // this handler is only provided on the desktop and liveview implementations since this // method is not used by the web implementation -async function handler(event, name, bubbles, config) { +this.handler = async function (event, name, bubbles) { let target = event.target; if (target != null) { let preventDefaultRequests = null; @@ -17,7 +11,7 @@ async function handler(event, name, bubbles, config) { if (event.type === "click") { // todo call prevent default if it's the right type of event - if (config.intercept_link_redirects) { + if (intercept_link_redirects) { let a_element = target.closest("a"); if (a_element != null) { event.preventDefault(); @@ -35,7 +29,7 @@ async function handler(event, name, bubbles, config) { const href = a_element.getAttribute("href"); if (href !== "" && href !== null && href !== undefined) { window.ipc.postMessage( - window.interpreter.serializeIpcMessage("browser_open", { href }) + this.serializeIpcMessage("browser_open", { href }) ); } } @@ -142,7 +136,7 @@ async function handler(event, name, bubbles, config) { return; } window.ipc.postMessage( - window.interpreter.serializeIpcMessage("user_event", { + this.serializeIpcMessage("user_event", { name: name, element: parseInt(realId), data: contents, @@ -223,43 +217,42 @@ class ListenerMap { delete this.local[id]; } } -function LoadChild(array) { +this.LoadChild = function (array) { // iterate through each number and get that child - node = stack[stack.length - 1]; + let node = this.stack[this.stack.length - 1]; for (let i = 0; i < array.length; i++) { - end = array[i]; - for (node = node.firstChild; end > 0; end--) { + this.end = array[i]; + for (node = node.firstChild; this.end > 0; this.end--) { node = node.nextSibling; } } return node; } -const listeners = new ListenerMap(); -let nodes = []; -let stack = []; -let root; -const templates = {}; -let node, els, end, k; - -function AppendChildren(id, many) { - root = nodes[id]; - els = stack.splice(stack.length - many); - for (k = 0; k < many; k++) { - root.appendChild(els[k]); +this.listeners = new ListenerMap(); +this.nodes = []; +this.stack = []; +this.root; +this.templates = {}; +this.els = null; +this.end = null; + +this.AppendChildren = function (id, many) { + this.root = this.nodes[id]; + this.els = this.stack.splice(this.stack.length - many); + for (let k = 0; k < many; k++) { + this.root.appendChild(this.els[k]); } } -window.interpreter = {} - -window.interpreter.initialize = function (root) { - nodes = [root]; - stack = [root]; - listeners.root = root; +this.initialize = function (root) { + this.nodes = [root]; + this.stack = [root]; + this.listeners.root = root; } -window.interpreter.getClientRect = function (id) { - const node = nodes[id]; +this.getClientRect = function (id) { + const node = this.nodes[id]; if (!node) { return; } @@ -271,8 +264,8 @@ window.interpreter.getClientRect = function (id) { }; } -window.interpreter.scrollTo = function (id, behavior) { - const node = nodes[id]; +this.scrollTo = function (id, behavior) { + const node = this.nodes[id]; if (!node) { return false; } @@ -283,8 +276,8 @@ window.interpreter.scrollTo = function (id, behavior) { } /// Set the focus on the element -window.interpreter.setFocus = function (id, focus) { - const node = nodes[id]; +this.setFocus = function (id, focus) { + const node = this.nodes[id]; if (!node) { return false; } @@ -579,7 +572,7 @@ async function serialize_event(event) { } } } -window.interpreter.serializeIpcMessage = function (method, params = {}) { +this.serializeIpcMessage = function (method, params = {}) { return JSON.stringify({ method, params }); } diff --git a/packages/interpreter/src/lib.rs b/packages/interpreter/src/lib.rs index b1aaebf046..0d92475e0a 100644 --- a/packages/interpreter/src/lib.rs +++ b/packages/interpreter/src/lib.rs @@ -20,7 +20,7 @@ pub use write_native_mutations::*; #[cfg(all(feature = "minimal_bindings", feature = "webonly"))] pub mod minimal_bindings { use wasm_bindgen::{prelude::wasm_bindgen, JsValue}; - #[wasm_bindgen(module = "/src/common.js")] + #[wasm_bindgen(module = "/src/common_exported.js")] extern "C" { pub fn setAttributeInner(node: JsValue, name: &str, value: JsValue, ns: Option<&str>); } diff --git a/packages/interpreter/src/sledgehammer_bindings.rs b/packages/interpreter/src/sledgehammer_bindings.rs index e368d83f3b..18e4b9df5c 100644 --- a/packages/interpreter/src/sledgehammer_bindings.rs +++ b/packages/interpreter/src/sledgehammer_bindings.rs @@ -19,7 +19,7 @@ mod js { this.global = {}; // non bubbling events listen at the element the listener was created at this.local = {}; - this.root = null; + this.root = root; this.handler = null; } @@ -65,35 +65,35 @@ mod js { delete this.local[id]; } } - function LoadChild(ptr, len) { + this.LoadChild = function(ptr, len) { // iterate through each number and get that child - node = stack[stack.length - 1]; - ptr_end = ptr + len; + let node = this.stack[this.stack.length - 1]; + let ptr_end = ptr + len; for (; ptr < ptr_end; ptr++) { - end = m.getUint8(ptr); + let end = this.m.getUint8(ptr); for (node = node.firstChild; end > 0; end--) { node = node.nextSibling; } } return node; } - const listeners = new ListenerMap(); - let nodes = []; - let stack = []; - let root; - const templates = {}; - let node, els, end, ptr_end, k; - export function save_template(nodes, tmpl_id) { - templates[tmpl_id] = nodes; + this.listeners = new ListenerMap(); + this.nodes = []; + this.stack = []; + this.root = null; + this.templates = {}; + this.els = null; + this.save_template = function(nodes, tmpl_id) { + this.templates[tmpl_id] = nodes; } - export function hydrate(ids) { + this.hydrate = function (ids) { const hydrateNodes = document.querySelectorAll('[data-node-hydration]'); for (let i = 0; i < hydrateNodes.length; i++) { const hydrateNode = hydrateNodes[i]; const hydration = hydrateNode.getAttribute('data-node-hydration'); const split = hydration.split(','); const id = ids[parseInt(split[0])]; - nodes[id] = hydrateNode; + this.nodes[id] = hydrateNode; if (split.length > 1) { hydrateNode.listening = split.length - 1; hydrateNode.setAttribute('data-dioxus-id', id); @@ -102,7 +102,7 @@ mod js { const split2 = listener.split(':'); const event_name = split2[0]; const bubbles = split2[1] === '1'; - listeners.create(event_name, hydrateNode, bubbles); + this.listeners.create(event_name, hydrateNode, bubbles); } } } @@ -115,91 +115,77 @@ mod js { const id = currentNode.textContent; const split = id.split('node-id'); if (split.length > 1) { - nodes[ids[parseInt(split[1])]] = currentNode.nextSibling; + this.nodes[ids[parseInt(split[1])]] = currentNode.nextSibling; } currentNode = treeWalker.nextNode(); } } - export function get_node(id) { - return nodes[id]; + this.get_node = function(id) { + return this.nodes[id]; } - export function initialize(root, handler) { - listeners.handler = handler; - nodes = [root]; - stack = [root]; - listeners.root = root; + this.initialize = function(root, handler) { + this.listeners.handler = handler; + this.nodes = [root]; + this.stack = [root]; + this.listeners.root = root; } - function AppendChildren(id, many){ - root = nodes[id]; - els = stack.splice(stack.length-many); - for (k = 0; k < many; k++) { - root.appendChild(els[k]); + this.AppendChildren = function (id, many){ + let root = this.nodes[id]; + this.els = this.stack.splice(this.stack.length-many); + for (let k = 0; k < many; k++) { + root.appendChild(this.els[k]); } } "#; - extern "C" { - #[wasm_bindgen] - pub fn save_template(nodes: Vec, tmpl_id: u16); - - #[wasm_bindgen] - pub fn hydrate(ids: Vec); - - #[wasm_bindgen] - pub fn get_node(id: u32) -> Node; - - #[wasm_bindgen] - pub fn initialize(root: Node, handler: &Function); - } - fn mount_to_root() { - "{AppendChildren(root, stack.length-1);}" + "{this.AppendChildren(this.root, this.stack.length-1);}" } fn push_root(root: u32) { - "{stack.push(nodes[$root$]);}" + "{this.stack.push(this.nodes[$root$]);}" } fn append_children(id: u32, many: u16) { - "{AppendChildren($id$, $many$);}" + "{this.AppendChildren($id$, $many$);}" } fn pop_root() { - "{stack.pop();}" + "{this.stack.pop();}" } fn replace_with(id: u32, n: u16) { - "{root = nodes[$id$]; els = stack.splice(stack.length-$n$); if (root.listening) { listeners.removeAllNonBubbling(root); } root.replaceWith(...els);}" + "{const root = this.nodes[$id$]; this.els = this.stack.splice(this.stack.length-$n$); if (root.listening) { this.listeners.removeAllNonBubbling(root); } root.replaceWith(...this.els);}" } fn insert_after(id: u32, n: u16) { - "{nodes[$id$].after(...stack.splice(stack.length-$n$));}" + "{this.nodes[$id$].after(...this.stack.splice(this.stack.length-$n$));}" } fn insert_before(id: u32, n: u16) { - "{nodes[$id$].before(...stack.splice(stack.length-$n$));}" + "{this.nodes[$id$].before(...this.stack.splice(this.stack.length-$n$));}" } fn remove(id: u32) { - "{node = nodes[$id$]; if (node !== undefined) { if (node.listening) { listeners.removeAllNonBubbling(node); } node.remove(); }}" + "{let node = this.nodes[$id$]; if (node !== undefined) { if (node.listening) { this.listeners.removeAllNonBubbling(node); } node.remove(); }}" } fn create_raw_text(text: &str) { - "{stack.push(document.createTextNode($text$));}" + "{this.stack.push(document.createTextNode($text$));}" } fn create_text_node(text: &str, id: u32) { - "{node = document.createTextNode($text$); nodes[$id$] = node; stack.push(node);}" + "{let node = document.createTextNode($text$); this.nodes[$id$] = node; this.stack.push(node);}" } fn create_placeholder(id: u32) { - "{node = document.createElement('pre'); node.hidden = true; stack.push(node); nodes[$id$] = node;}" + "{let node = document.createElement('pre'); node.hidden = true; this.stack.push(node); this.nodes[$id$] = node;}" } fn new_event_listener(event_name: &str, id: u32, bubbles: u8) { - r#"node = nodes[id]; if(node.listening){node.listening += 1;}else{node.listening = 1;} node.setAttribute('data-dioxus-id', `\${id}`); listeners.create($event_name$, node, $bubbles$);"# + r#"let node = this.nodes[id]; if(node.listening){node.listening += 1;}else{node.listening = 1;} node.setAttribute('data-dioxus-id', `\${id}`); this.listeners.create($event_name$, node, $bubbles$);"# } fn remove_event_listener(event_name: &str, id: u32, bubbles: u8) { - "{node = nodes[$id$]; node.listening -= 1; node.removeAttribute('data-dioxus-id'); listeners.remove(node, $event_name$, $bubbles$);}" + "{let node = this.nodes[$id$]; node.listening -= 1; node.removeAttribute('data-dioxus-id'); this.listeners.remove(node, $event_name$, $bubbles$);}" } fn set_text(id: u32, text: &str) { - "{nodes[$id$].textContent = $text$;}" + "{this.nodes[$id$].textContent = $text$;}" } fn set_attribute(id: u32, field: &str, value: &str, ns: &str) { - "{node = nodes[$id$]; setAttributeInner(node, $field$, $value$, $ns$);}" + "{let node = this.nodes[$id$]; this.setAttributeInner(node, $field$, $value$, $ns$);}" } fn remove_attribute(id: u32, field: &str, ns: &str) { r#"{ - node = nodes[$id$]; + let node = this.nodes[$id$]; if (!ns) { switch (field) { case "value": @@ -226,29 +212,54 @@ mod js { }"# } fn assign_id(ptr: u32, len: u8, id: u32) { - "{nodes[$id$] = LoadChild($ptr$, $len$);}" + "{this.nodes[$id$] = this.LoadChild($ptr$, $len$);}" } fn hydrate_text(ptr: u32, len: u8, value: &str, id: u32) { r#"{ - node = LoadChild($ptr$, $len$); - if (node.nodeType == Node.TEXT_NODE) { + let node = this.LoadChild($ptr$, $len$); + if (node.nodeType == node.TEXT_NODE) { node.textContent = value; } else { let text = document.createTextNode(value); node.replaceWith(text); node = text; } - nodes[$id$] = node; + this.nodes[$id$] = node; }"# } fn replace_placeholder(ptr: u32, len: u8, n: u16) { - "{els = stack.splice(stack.length - $n$); node = LoadChild($ptr$, $len$); node.replaceWith(...els);}" + "{this.els = this.stack.splice(this.stack.length - $n$); let node = this.LoadChild($ptr$, $len$); node.replaceWith(...this.els);}" } fn load_template(tmpl_id: u16, index: u16, id: u32) { - "{node = templates[$tmpl_id$][$index$].cloneNode(true); nodes[$id$] = node; stack.push(node);}" + "{let node = this.templates[$tmpl_id$][$index$].cloneNode(true); this.nodes[$id$] = node; this.stack.push(node);}" } } +#[cfg(feature = "webonly")] +#[wasm_bindgen::prelude::wasm_bindgen(inline_js = r#" +export function save_template(channel, nodes, tmpl_id) { + channel.save_template(nodes, tmpl_id); +} +export function hydrate(channel, ids) { + channel.hydrate(ids); +} +export function get_node(channel, id) { + return channel.get_node(id); +} +export function initialize(channel, root, handler) { + channel.initialize(root, handler); +} +"#)] +extern "C" { + pub fn save_template(channel: &JSChannel, nodes: Vec, tmpl_id: u16); + + pub fn hydrate(channel: &JSChannel, ids: Vec); + + pub fn get_node(channel: &JSChannel, id: u32) -> Node; + + pub fn initialize(channel: &JSChannel, root: Node, handler: &Function); +} + #[cfg(feature = "binary-protocol")] pub mod binary_protocol { use sledgehammer_bindgen::bindgen; @@ -260,60 +271,60 @@ pub mod binary_protocol { const JS_FILE: &str = "./src/common.js"; fn mount_to_root() { - "{AppendChildren(root, stack.length-1);}" + "{this.AppendChildren(this.root, this.stack.length-1);}" } fn push_root(root: u32) { - "{stack.push(nodes[$root$]);}" + "{this.stack.push(this.nodes[$root$]);}" } fn append_children(id: u32, many: u16) { - "{AppendChildren($id$, $many$);}" + "{this.AppendChildren($id$, $many$);}" } fn append_children_to_top(many: u16) { "{ - root = stack[stack.length-many-1]; - els = stack.splice(stack.length-many); - for (k = 0; k < many; k++) { - root.appendChild(els[k]); + let root = this.stack[this.stack.length-many-1]; + this.els = this.stack.splice(this.stack.length-many); + for (let k = 0; k < many; k++) { + root.appendChild(this.els[k]); } }" } fn pop_root() { - "{stack.pop();}" + "{this.stack.pop();}" } fn replace_with(id: u32, n: u16) { - "{root = nodes[$id$]; els = stack.splice(stack.length-$n$); if (root.listening) { listeners.removeAllNonBubbling(root); } root.replaceWith(...els);}" + "{let root = this.nodes[$id$]; this.els = this.stack.splice(this.stack.length-$n$); if (root.listening) { this.listeners.removeAllNonBubbling(root); } root.replaceWith(...this.els);}" } fn insert_after(id: u32, n: u16) { - "{nodes[$id$].after(...stack.splice(stack.length-$n$));}" + "{this.nodes[$id$].after(...this.stack.splice(this.stack.length-$n$));}" } fn insert_before(id: u32, n: u16) { - "{nodes[$id$].before(...stack.splice(stack.length-$n$));}" + "{this.nodes[$id$].before(...this.stack.splice(this.stack.length-$n$));}" } fn remove(id: u32) { - "{node = nodes[$id$]; if (node !== undefined) { if (node.listening) { listeners.removeAllNonBubbling(node); } node.remove(); }}" + "{let node = this.nodes[$id$]; if (node !== undefined) { if (node.listening) { this.listeners.removeAllNonBubbling(node); } node.remove(); }}" } fn create_raw_text(text: &str) { - "{stack.push(document.createTextNode($text$));}" + "{this.stack.push(document.createTextNode($text$));}" } fn create_text_node(text: &str, id: u32) { - "{node = document.createTextNode($text$); nodes[$id$] = node; stack.push(node);}" + "{let node = document.createTextNode($text$); this.nodes[$id$] = node; this.stack.push(node);}" } fn create_element(element: &'static str) { - "{stack.push(document.createElement($element$))}" + "{this.stack.push(document.createElement($element$))}" } fn create_element_ns(element: &'static str, ns: &'static str) { - "{stack.push(document.createElementNS($ns$, $element$))}" + "{this.stack.push(document.createElementNS($ns$, $element$))}" } fn create_placeholder(id: u32) { - "{node = document.createElement('pre'); node.hidden = true; stack.push(node); nodes[$id$] = node;}" + "{let node = document.createElement('pre'); node.hidden = true; this.stack.push(node); this.nodes[$id$] = node;}" } fn add_placeholder() { - "{node = document.createElement('pre'); node.hidden = true; stack.push(node);}" + "{let node = document.createElement('pre'); node.hidden = true; this.stack.push(node);}" } fn new_event_listener(event: &str, id: u32, bubbles: u8) { r#" bubbles = bubbles == 1; - node = nodes[id]; + let node = this.nodes[id]; if(node.listening){ node.listening += 1; } else { @@ -325,7 +336,7 @@ pub mod binary_protocol { // if this is a mounted listener, we send the event immediately if (event_name === "mounted") { window.ipc.postMessage( - window.interpreter.serializeIpcMessage("user_event", { + this.serializeIpcMessage("user_event", { name: event_name, element: id, data: null, @@ -333,26 +344,26 @@ pub mod binary_protocol { }) ); } else { - listeners.create(event_name, node, bubbles, (event) => { - handler(event, event_name, bubbles, config); + this.listeners.create(event_name, node, bubbles, (event) => { + this.handler(event, event_name, bubbles); }); }"# } fn remove_event_listener(event_name: &str, id: u32, bubbles: u8) { - "{node = nodes[$id$]; node.listening -= 1; node.removeAttribute('data-dioxus-id'); listeners.remove(node, $event_name$, $bubbles$);}" + "{let node = this.nodes[$id$]; node.listening -= 1; node.removeAttribute('data-dioxus-id'); this.listeners.remove(node, $event_name$, $bubbles$);}" } fn set_text(id: u32, text: &str) { - "{nodes[$id$].textContent = $text$;}" + "{this.nodes[$id$].textContent = $text$;}" } fn set_attribute(id: u32, field: &str, value: &str, ns: &str) { - "{node = nodes[$id$]; setAttributeInner(node, $field$, $value$, $ns$);}" + "{let node = this.nodes[$id$]; this.setAttributeInner(node, $field$, $value$, $ns$);}" } fn set_top_attribute(field: &str, value: &str, ns: &str) { - "{setAttributeInner(stack[stack.length-1], $field$, $value$, $ns$);}" + "{this.setAttributeInner(this.stack[this.stack.length-1], $field$, $value$, $ns$);}" } fn remove_attribute(id: u32, field: &str, ns: &str) { r#"{ - node = nodes[$id$]; + let node = this.nodes[$id$]; if (!ns) { switch (field) { case "value": @@ -379,29 +390,29 @@ pub mod binary_protocol { }"# } fn assign_id(array: &[u8], id: u32) { - "{nodes[$id$] = LoadChild($array$);}" + "{this.nodes[$id$] = this.LoadChild($array$);}" } fn hydrate_text(array: &[u8], value: &str, id: u32) { r#"{ - node = LoadChild($array$); - if (node.nodeType == Node.TEXT_NODE) { + let node = this.LoadChild($array$); + if (node.nodeType == node.TEXT_NODE) { node.textContent = value; } else { let text = document.createTextNode(value); node.replaceWith(text); node = text; } - nodes[$id$] = node; + this.nodes[$id$] = node; }"# } fn replace_placeholder(array: &[u8], n: u16) { - "{els = stack.splice(stack.length - $n$); node = LoadChild($array$); node.replaceWith(...els);}" + "{this.els = this.stack.splice(this.stack.length - $n$); let node = this.LoadChild($array$); node.replaceWith(...this.els);}" } fn load_template(tmpl_id: u16, index: u16, id: u32) { - "{node = templates[$tmpl_id$][$index$].cloneNode(true); nodes[$id$] = node; stack.push(node);}" + "{let node = this.templates[$tmpl_id$][$index$].cloneNode(true); this.nodes[$id$] = node; this.stack.push(node);}" } fn add_templates(tmpl_id: u16, len: u16) { - "{templates[$tmpl_id$] = stack.splice(stack.length-$len$);}" + "{this.templates[$tmpl_id$] = this.stack.splice(this.stack.length-$len$);}" } } } diff --git a/packages/liveview/src/main.js b/packages/liveview/src/main.js index 22267dbaba..59a32dd0b6 100644 --- a/packages/liveview/src/main.js +++ b/packages/liveview/src/main.js @@ -1,4 +1,4 @@ -const config = new InterpreterConfig(false); +const intercept_link_redirects = false; function main() { let root = window.document.getElementById("main"); @@ -9,6 +9,7 @@ function main() { class IPC { constructor(root) { + window.interpreter = new JSChannel(); window.interpreter.initialize(root); const ws = new WebSocket(WS_ADDR); ws.binaryType = "arraybuffer"; @@ -34,7 +35,7 @@ class IPC { // The first byte tells the shim if this is a binary of text frame if (binaryFrame) { // binary frame - run_from_bytes(messageData); + window.interpreter.run_from_bytes(messageData); } else { // text frame diff --git a/packages/web/src/dom.rs b/packages/web/src/dom.rs index 33f44c1d8a..00cfa1478e 100644 --- a/packages/web/src/dom.rs +++ b/packages/web/src/dom.rs @@ -110,6 +110,7 @@ impl WebsysDom { })); dioxus_interpreter_js::initialize( + interpreter.js_channel(), root.clone().unchecked_into(), handler.as_ref().unchecked_ref(), ); diff --git a/packages/web/src/mutations.rs b/packages/web/src/mutations.rs index feadb29957..c3c2a8147b 100644 --- a/packages/web/src/mutations.rs +++ b/packages/web/src/mutations.rs @@ -62,7 +62,7 @@ impl WebsysDom { // Now that we've flushed the edits and the dom nodes exist, we can send the mounted events. { for id in self.queued_mounted_events.drain(..) { - let node = get_node(id.0 as u32); + let node = get_node(self.interpreter.js_channel(), id.0 as u32); if let Some(element) = node.dyn_ref::() { let _ = self.event_channel.unbounded_send(UiEvent { name: "mounted".to_string(), @@ -91,7 +91,7 @@ impl WriteMutations for WebsysDom { self.templates .insert(template.name.to_owned(), self.max_template_id); - save_template(roots, self.max_template_id); + save_template(self.interpreter.js_channel(), roots, self.max_template_id); self.max_template_id += 1 } diff --git a/packages/web/src/rehydrate.rs b/packages/web/src/rehydrate.rs index 7593e47d0d..271b3daabe 100644 --- a/packages/web/src/rehydrate.rs +++ b/packages/web/src/rehydrate.rs @@ -23,7 +23,7 @@ impl WebsysDom { // Recursively rehydrate the dom from the VirtualDom self.rehydrate_scope(root_scope, dom, &mut ids, &mut to_mount)?; - dioxus_interpreter_js::hydrate(ids); + dioxus_interpreter_js::hydrate(self.interpreter.js_channel(), ids); #[cfg(feature = "mounted")] for id in to_mount { @@ -168,7 +168,11 @@ impl WriteMutations for OnlyWriteTemplates<'_> { self.0 .templates .insert(template.name.to_owned(), self.0.max_template_id); - save_template(roots, self.0.max_template_id); + save_template( + self.0.interpreter.js_channel(), + roots, + self.0.max_template_id, + ); self.0.max_template_id += 1 }