|
@@ -1,32 +1,54 @@
|
|
|
#[cfg(feature = "webonly")]
|
|
|
use web_sys::Node;
|
|
|
|
|
|
+pub const SLEDGEHAMMER_JS: &str = GENERATED_JS;
|
|
|
+
|
|
|
#[cfg(feature = "webonly")]
|
|
|
-use wasm_bindgen::prelude::wasm_bindgen;
|
|
|
+#[wasm_bindgen::prelude::wasm_bindgen]
|
|
|
+extern "C" {
|
|
|
+ pub type BaseInterpreter;
|
|
|
|
|
|
-use sledgehammer_bindgen::bindgen;
|
|
|
+ #[wasm_bindgen(method)]
|
|
|
+ pub fn initialize(this: &BaseInterpreter, root: Node, handler: &js_sys::Function);
|
|
|
|
|
|
-/// Combine the interpreter class with the sledgehammer_bindgen generated methods.
|
|
|
-pub fn native_js() -> String {
|
|
|
- format!("{}\n{}", include_str!("./js/native.js"), GENERATED_JS,)
|
|
|
+ #[wasm_bindgen(method, js_name = "saveTemplate")]
|
|
|
+ pub fn save_template(this: &BaseInterpreter, nodes: Vec<Node>, tmpl_id: u16);
|
|
|
+
|
|
|
+ #[wasm_bindgen(method)]
|
|
|
+ pub fn hydrate(this: &BaseInterpreter, ids: Vec<u32>);
|
|
|
+
|
|
|
+ #[wasm_bindgen(method, js_name = "getNode")]
|
|
|
+ pub fn get_node(this: &BaseInterpreter, id: u32) -> Node;
|
|
|
}
|
|
|
|
|
|
-pub const SLEDGEHAMMER_JS: &str = GENERATED_JS;
|
|
|
+// Note that this impl is for the sledgehammer interpreter to allow us dropping down to the base interpreter
|
|
|
+// During hydration and initialization we need to the base interpreter methods
|
|
|
+#[cfg(feature = "webonly")]
|
|
|
+impl Interpreter {
|
|
|
+ /// Convert the interpreter to its baseclass, giving
|
|
|
+ pub fn base(&self) -> &BaseInterpreter {
|
|
|
+ use wasm_bindgen::prelude::JsCast;
|
|
|
+ &self.js_channel().unchecked_ref()
|
|
|
+ }
|
|
|
+}
|
|
|
|
|
|
-#[bindgen(module)]
|
|
|
+#[sledgehammer_bindgen::bindgen(module)]
|
|
|
mod js {
|
|
|
+ // Extend the web base class
|
|
|
+ const BASE: &str = "./src/js/core.js";
|
|
|
+
|
|
|
/// The interpreter extends the core interpreter which contains the state for the interpreter along with some functions that all platforms use like `AppendChildren`.
|
|
|
- #[extends(PlatformInterpreter)]
|
|
|
+ #[extends(BaseInterpreter)]
|
|
|
pub struct Interpreter;
|
|
|
|
|
|
fn mount_to_root() {
|
|
|
- "{this.AppendChildren(this.root, this.stack.length-1);}"
|
|
|
+ "{this.appendChildren(this.root, this.stack.length-1);}"
|
|
|
}
|
|
|
fn push_root(root: u32) {
|
|
|
"{this.stack.push(this.nodes[$root$]);}"
|
|
|
}
|
|
|
fn append_children(id: u32, many: u16) {
|
|
|
- "{this.AppendChildren($id$, $many$);}"
|
|
|
+ "{this.appendChildren($id$, $many$);}"
|
|
|
}
|
|
|
fn pop_root() {
|
|
|
"{this.stack.pop();}"
|
|
@@ -93,11 +115,11 @@ mod js {
|
|
|
}"#
|
|
|
}
|
|
|
fn assign_id(ptr: u32, len: u8, id: u32) {
|
|
|
- "{this.nodes[$id$] = this.LoadChild($ptr$, $len$);}"
|
|
|
+ "{this.nodes[$id$] = this.loadChild($ptr$, $len$);}"
|
|
|
}
|
|
|
fn hydrate_text(ptr: u32, len: u8, value: &str, id: u32) {
|
|
|
r#"{
|
|
|
- let node = this.LoadChild($ptr$, $len$);
|
|
|
+ let node = this.loadChild($ptr$, $len$);
|
|
|
if (node.nodeType == node.TEXT_NODE) {
|
|
|
node.textContent = value;
|
|
|
} else {
|
|
@@ -109,20 +131,13 @@ mod js {
|
|
|
}"#
|
|
|
}
|
|
|
fn replace_placeholder(ptr: u32, len: u8, n: u16) {
|
|
|
- "{this.els = this.stack.splice(this.stack.length - $n$); let node = this.LoadChild($ptr$, $len$); node.replaceWith(...this.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) {
|
|
|
"{let node = this.templates[$tmpl_id$][$index$].cloneNode(true); this.nodes[$id$] = node; this.stack.push(node);}"
|
|
|
}
|
|
|
|
|
|
- /*
|
|
|
- Binary protocol methods only!
|
|
|
-
|
|
|
- These methods let us support binary packing mutations for use on boundaries like desktop where we prefer to send
|
|
|
- binary data instead of JSON.
|
|
|
-
|
|
|
- We're using native types in a number of places
|
|
|
- */
|
|
|
+ #[cfg(feature = "binary-protocol")]
|
|
|
fn append_children_to_top(many: u16) {
|
|
|
"{
|
|
|
let root = this.stack[this.stack.length-many-1];
|
|
@@ -130,23 +145,35 @@ mod js {
|
|
|
for (let k = 0; k < many; k++) {
|
|
|
root.appendChild(this.els[k]);
|
|
|
}
|
|
|
- }"
|
|
|
+ }"
|
|
|
}
|
|
|
+
|
|
|
+ #[cfg(feature = "binary-protocol")]
|
|
|
fn set_top_attribute(field: &str<u8, attr>, value: &str, ns: &str<u8, ns_cache>) {
|
|
|
"{this.setAttributeInner(this.stack[this.stack.length-1], $field$, $value$, $ns$);}"
|
|
|
}
|
|
|
+
|
|
|
+ #[cfg(feature = "binary-protocol")]
|
|
|
fn add_placeholder() {
|
|
|
"{let node = document.createElement('pre'); node.hidden = true; this.stack.push(node);}"
|
|
|
}
|
|
|
+
|
|
|
+ #[cfg(feature = "binary-protocol")]
|
|
|
fn create_element(element: &'static str<u8, el>) {
|
|
|
"{this.stack.push(document.createElement($element$))}"
|
|
|
}
|
|
|
+
|
|
|
+ #[cfg(feature = "binary-protocol")]
|
|
|
fn create_element_ns(element: &'static str<u8, el>, ns: &'static str<u8, namespace>) {
|
|
|
"{this.stack.push(document.createElementNS($ns$, $element$))}"
|
|
|
}
|
|
|
+
|
|
|
+ #[cfg(feature = "binary-protocol")]
|
|
|
fn add_templates(tmpl_id: u16, len: u16) {
|
|
|
"{this.templates[$tmpl_id$] = this.stack.splice(this.stack.length-$len$);}"
|
|
|
}
|
|
|
+
|
|
|
+ #[cfg(feature = "binary-protocol")]
|
|
|
fn foreign_event_listener(event: &str<u8, evt>, id: u32, bubbles: u8) {
|
|
|
r#"
|
|
|
bubbles = bubbles == 1;
|
|
@@ -175,12 +202,18 @@ mod js {
|
|
|
});
|
|
|
}"#
|
|
|
}
|
|
|
+
|
|
|
+ /// Assign the ID
|
|
|
+ #[cfg(feature = "binary-protocol")]
|
|
|
fn assign_id_ref(array: &[u8], id: u32) {
|
|
|
- "{this.nodes[$id$] = this.LoadChild($array$);}"
|
|
|
+ "{this.nodes[$id$] = this.loadChild($array$);}"
|
|
|
}
|
|
|
+
|
|
|
+ /// The coolest ID ever!
|
|
|
+ #[cfg(feature = "binary-protocol")]
|
|
|
fn hydrate_text_ref(array: &[u8], value: &str, id: u32) {
|
|
|
r#"{
|
|
|
- let node = this.LoadChild($array$);
|
|
|
+ let node = this.loadChild($array$);
|
|
|
if (node.nodeType == node.TEXT_NODE) {
|
|
|
node.textContent = value;
|
|
|
} else {
|
|
@@ -191,38 +224,9 @@ mod js {
|
|
|
this.nodes[$id$] = node;
|
|
|
}"#
|
|
|
}
|
|
|
- fn replace_placeholder_ref(array: &[u8], n: u16) {
|
|
|
- "{this.els = this.stack.splice(this.stack.length - $n$); let node = this.LoadChild($array$); node.replaceWith(...this.els);}"
|
|
|
- }
|
|
|
-}
|
|
|
-
|
|
|
-/// Extensions to the interpreter that are specific to the web platform.
|
|
|
-#[cfg(feature = "webonly")]
|
|
|
-#[wasm_bindgen(module = "src/js/web.js")]
|
|
|
-extern "C" {
|
|
|
- pub type WebInterpreter;
|
|
|
-
|
|
|
- #[wasm_bindgen(method)]
|
|
|
- pub fn initialize(this: &WebInterpreter, root: Node, handler: &js_sys::Function);
|
|
|
-
|
|
|
- #[wasm_bindgen(method, js_name = "saveTemplate")]
|
|
|
- pub fn save_template(this: &WebInterpreter, nodes: Vec<Node>, tmpl_id: u16);
|
|
|
|
|
|
- #[wasm_bindgen(method)]
|
|
|
- pub fn hydrate(this: &WebInterpreter, ids: Vec<u32>);
|
|
|
-
|
|
|
- #[wasm_bindgen(method, js_name = "getNode")]
|
|
|
- pub fn get_node(this: &WebInterpreter, id: u32) -> Node;
|
|
|
-}
|
|
|
-
|
|
|
-#[cfg(feature = "webonly")]
|
|
|
-type PlatformInterpreter = WebInterpreter;
|
|
|
-
|
|
|
-#[cfg(feature = "webonly")]
|
|
|
-impl Interpreter {
|
|
|
- /// Convert the interpreter to a web interpreter, enabling methods like hydrate and save_template.
|
|
|
- pub fn as_web(&self) -> &WebInterpreter {
|
|
|
- use wasm_bindgen::prelude::JsCast;
|
|
|
- &self.js_channel().unchecked_ref()
|
|
|
+ #[cfg(feature = "binary-protocol")]
|
|
|
+ fn replace_placeholder_ref(array: &[u8], n: u16) {
|
|
|
+ "{this.els = this.stack.splice(this.stack.length - $n$); let node = this.loadChild($array$); node.replaceWith(...this.els);}"
|
|
|
}
|
|
|
}
|