Web works with the js structure

This commit is contained in:
Jonathan Kelley committed 2024-03-05 11:16:34 -08:00
1 parent 16b38e339d
commit b751674354
16 files changed
+470 -325

No files matched your search

+64 -60
View File
@@ -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);}"
}
}