Web works with the js structure
This commit is contained in:
16 files changed
+470
-325
No files matched your search
@@ -1,32 +1,54 @@
|
||||
#[cfg(feature = "webonly")]
|
||||
use web_sys::Node;
|
||||
|
||||
#[cfg(feature = "webonly")]
|
||||
use wasm_bindgen::prelude::wasm_bindgen;
|
||||
|
||||
use sledgehammer_bindgen::bindgen;
|
||||
|
||||
/// Combine the interpreter class with the sledgehammer_bindgen generated methods.
|
||||
pub fn native_js() -> String {
|
||||
format!("{}\n{}", include_str!("./js/native.js"), GENERATED_JS,)
|
||||
}
|
||||
|
||||
pub const SLEDGEHAMMER_JS: &str = GENERATED_JS;
|
||||
|
||||
#[bindgen(module)]
|
||||
#[cfg(feature = "webonly")]
|
||||
#[wasm_bindgen::prelude::wasm_bindgen]
|
||||
extern "C" {
|
||||
pub type BaseInterpreter;
|
||||
|
||||
#[wasm_bindgen(method)]
|
||||
pub fn initialize(this: &BaseInterpreter, root: Node, handler: &js_sys::Function);
|
||||
|
||||
#[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;
|
||||
}
|
||||
|
||||
// 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()
|
||||
}
|
||||
}
|
||||
|
||||
#[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;
|
||||
}"#
|
||||
}
|
||||
|
||||
#[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);}"
|
||||
}
|
||||
}
|
||||
|
||||
/// 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()
|
||||
"{this.els = this.stack.splice(this.stack.length - $n$); let node = this.loadChild($array$); node.replaceWith(...this.els);}"
|
||||
}
|
||||
}
|
||||
Reference in new issue
Block a user