Web works with the js structure
This commit is contained in:
16 files changed
+470
-325
No files matched your search
Generated
-2
@@ -8527,7 +8527,6 @@ dependencies = [
|
|||||||
[[package]]
|
[[package]]
|
||||||
name = "sledgehammer_bindgen"
|
name = "sledgehammer_bindgen"
|
||||||
version = "0.4.0"
|
version = "0.4.0"
|
||||||
source = "git+https://github.com/ealmloff/sledgehammer_bindgen#6f90290e1655014f22623eb8b2ea41fb098e1164"
|
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"sledgehammer_bindgen_macro",
|
"sledgehammer_bindgen_macro",
|
||||||
"wasm-bindgen",
|
"wasm-bindgen",
|
||||||
@@ -8536,7 +8535,6 @@ dependencies = [
|
|||||||
[[package]]
|
[[package]]
|
||||||
name = "sledgehammer_bindgen_macro"
|
name = "sledgehammer_bindgen_macro"
|
||||||
version = "0.4.0"
|
version = "0.4.0"
|
||||||
source = "git+https://github.com/ealmloff/sledgehammer_bindgen#6f90290e1655014f22623eb8b2ea41fb098e1164"
|
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"quote",
|
"quote",
|
||||||
"syn 2.0.51",
|
"syn 2.0.51",
|
||||||
|
|||||||
@@ -17,7 +17,8 @@ web-sys = { version = "0.3.56", optional = true, features = [
|
|||||||
"Element",
|
"Element",
|
||||||
"Node",
|
"Node",
|
||||||
] }
|
] }
|
||||||
sledgehammer_bindgen = { git = "https://github.com/ealmloff/sledgehammer_bindgen", default-features = false, optional = true }
|
sledgehammer_bindgen = { path = "../../../Tinkering/sledgehammer_bindgen", default-features = false, optional = true }
|
||||||
|
# sledgehammer_bindgen = { git = "https://github.com/ealmloff/sledgehammer_bindgen", default-features = false, optional = true }
|
||||||
sledgehammer_utils = { version = "0.2", optional = true }
|
sledgehammer_utils = { version = "0.2", optional = true }
|
||||||
serde = { version = "1.0", features = ["derive"], optional = true }
|
serde = { version = "1.0", features = ["derive"], optional = true }
|
||||||
|
|
||||||
|
|||||||
@@ -20,8 +20,9 @@ fn main() {
|
|||||||
|
|
||||||
// Otherwise, generate the bindings and write the new hash to disk
|
// Otherwise, generate the bindings and write the new hash to disk
|
||||||
// Generate the bindings for both native and web
|
// Generate the bindings for both native and web
|
||||||
gen_bindings("interpreter_native", "native");
|
gen_bindings("common", "common");
|
||||||
gen_bindings("interpreter_web", "web");
|
gen_bindings("native", "native");
|
||||||
|
gen_bindings("core", "core");
|
||||||
|
|
||||||
std::fs::write("src/js/hash.txt", hash.to_string()).unwrap();
|
std::fs::write("src/js/hash.txt", hash.to_string()).unwrap();
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -0,0 +1,99 @@
|
|||||||
|
// src/ts/set_attribute.ts
|
||||||
|
function setAttributeInner(node, field, value, ns) {
|
||||||
|
if (ns === "style") {
|
||||||
|
node.style.setProperty(field, value);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (!!ns) {
|
||||||
|
node.setAttributeNS(ns, field, value);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
switch (field) {
|
||||||
|
case "value":
|
||||||
|
if (node.value !== 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:
|
||||||
|
if (!truthy(value) && isBoolAttr(field)) {
|
||||||
|
node.removeAttribute(field);
|
||||||
|
} else {
|
||||||
|
node.setAttribute(field, value);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
var truthy = function(val) {
|
||||||
|
return val === "true" || val === true;
|
||||||
|
};
|
||||||
|
var isBoolAttr = function(field) {
|
||||||
|
switch (field) {
|
||||||
|
case "allowfullscreen":
|
||||||
|
case "allowpaymentrequest":
|
||||||
|
case "async":
|
||||||
|
case "autofocus":
|
||||||
|
case "autoplay":
|
||||||
|
case "checked":
|
||||||
|
case "controls":
|
||||||
|
case "default":
|
||||||
|
case "defer":
|
||||||
|
case "disabled":
|
||||||
|
case "formnovalidate":
|
||||||
|
case "hidden":
|
||||||
|
case "ismap":
|
||||||
|
case "itemscope":
|
||||||
|
case "loop":
|
||||||
|
case "multiple":
|
||||||
|
case "muted":
|
||||||
|
case "nomodule":
|
||||||
|
case "novalidate":
|
||||||
|
case "open":
|
||||||
|
case "playsinline":
|
||||||
|
case "readonly":
|
||||||
|
case "required":
|
||||||
|
case "reversed":
|
||||||
|
case "selected":
|
||||||
|
case "truespeed":
|
||||||
|
case "webkitdirectory":
|
||||||
|
return true;
|
||||||
|
default:
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
// src/ts/form.ts
|
||||||
|
function retrieveFormValues(form) {
|
||||||
|
const formData = new FormData(form);
|
||||||
|
const contents = {};
|
||||||
|
formData.forEach((value, key) => {
|
||||||
|
if (contents[key]) {
|
||||||
|
contents[key] += "," + value;
|
||||||
|
} else {
|
||||||
|
contents[key] = value;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
return {
|
||||||
|
valid: form.checkValidity(),
|
||||||
|
values: contents
|
||||||
|
};
|
||||||
|
}
|
||||||
|
export {
|
||||||
|
setAttributeInner,
|
||||||
|
retrieveFormValues
|
||||||
|
};
|
||||||
@@ -1,81 +1,3 @@
|
|||||||
// src/ts/interpreter_core.ts
|
|
||||||
class Interpreter {
|
|
||||||
global;
|
|
||||||
local;
|
|
||||||
root;
|
|
||||||
handler;
|
|
||||||
nodes;
|
|
||||||
stack;
|
|
||||||
templates;
|
|
||||||
constructor(root, handler) {
|
|
||||||
this.handler = handler;
|
|
||||||
this.initialize(root);
|
|
||||||
}
|
|
||||||
initialize(root, handler = null) {
|
|
||||||
this.global = {};
|
|
||||||
this.local = {};
|
|
||||||
this.root = root;
|
|
||||||
this.nodes = [root];
|
|
||||||
this.stack = [root];
|
|
||||||
this.templates = {};
|
|
||||||
if (handler) {
|
|
||||||
this.handler = handler;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
createListener(event_name, element, bubbles) {
|
|
||||||
if (bubbles) {
|
|
||||||
if (this.global[event_name] === undefined) {
|
|
||||||
this.global[event_name] = { active: 1, callback: this.handler };
|
|
||||||
this.root.addEventListener(event_name, this.handler);
|
|
||||||
} else {
|
|
||||||
this.global[event_name].active++;
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
const id = element.getAttribute("data-dioxus-id");
|
|
||||||
if (!this.local[id]) {
|
|
||||||
this.local[id] = {};
|
|
||||||
}
|
|
||||||
element.addEventListener(event_name, this.handler);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
removeListener(element, event_name, bubbles) {
|
|
||||||
if (bubbles) {
|
|
||||||
this.removeBubblingListener(event_name);
|
|
||||||
} else {
|
|
||||||
this.removeNonBubblingListener(element, event_name);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
removeBubblingListener(event_name) {
|
|
||||||
this.global[event_name].active--;
|
|
||||||
if (this.global[event_name].active === 0) {
|
|
||||||
this.root.removeEventListener(event_name, this.global[event_name].callback);
|
|
||||||
delete this.global[event_name];
|
|
||||||
}
|
|
||||||
}
|
|
||||||
removeNonBubblingListener(element, event_name) {
|
|
||||||
const id = element.getAttribute("data-dioxus-id");
|
|
||||||
delete this.local[id][event_name];
|
|
||||||
if (Object.keys(this.local[id]).length === 0) {
|
|
||||||
delete this.local[id];
|
|
||||||
}
|
|
||||||
element.removeEventListener(event_name, this.handler);
|
|
||||||
}
|
|
||||||
removeAllNonBubblingListeners(element) {
|
|
||||||
const id = element.getAttribute("data-dioxus-id");
|
|
||||||
delete this.local[id];
|
|
||||||
}
|
|
||||||
getNode(id) {
|
|
||||||
return this.nodes[id];
|
|
||||||
}
|
|
||||||
appendChildren(id, many) {
|
|
||||||
const root = this.nodes[id];
|
|
||||||
const els = this.stack.splice(this.stack.length - many);
|
|
||||||
for (let k = 0;k < many; k++) {
|
|
||||||
root.appendChild(els[k]);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// src/ts/set_attribute.ts
|
// src/ts/set_attribute.ts
|
||||||
function setAttributeInner(node, field, value, ns) {
|
function setAttributeInner(node, field, value, ns) {
|
||||||
if (ns === "style") {
|
if (ns === "style") {
|
||||||
@@ -156,13 +78,84 @@ var isBoolAttr = function(field) {
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
// src/ts/interpreter_web.ts
|
// src/ts/core.ts
|
||||||
class PlatformInterpreter extends Interpreter {
|
class BaseInterpreter {
|
||||||
|
global;
|
||||||
|
local;
|
||||||
|
root;
|
||||||
|
handler;
|
||||||
|
nodes;
|
||||||
|
stack;
|
||||||
|
templates;
|
||||||
m;
|
m;
|
||||||
constructor(root, handler) {
|
constructor(root, handler) {
|
||||||
super(root, handler);
|
this.handler = handler;
|
||||||
|
this.initialize(root);
|
||||||
}
|
}
|
||||||
LoadChild(ptr, len) {
|
initialize(root, handler = null) {
|
||||||
|
this.global = {};
|
||||||
|
this.local = {};
|
||||||
|
this.root = root;
|
||||||
|
this.nodes = [root];
|
||||||
|
this.stack = [root];
|
||||||
|
this.templates = {};
|
||||||
|
if (handler) {
|
||||||
|
this.handler = handler;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
createListener(event_name, element, bubbles) {
|
||||||
|
if (bubbles) {
|
||||||
|
if (this.global[event_name] === undefined) {
|
||||||
|
this.global[event_name] = { active: 1, callback: this.handler };
|
||||||
|
this.root.addEventListener(event_name, this.handler);
|
||||||
|
} else {
|
||||||
|
this.global[event_name].active++;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
const id = element.getAttribute("data-dioxus-id");
|
||||||
|
if (!this.local[id]) {
|
||||||
|
this.local[id] = {};
|
||||||
|
}
|
||||||
|
element.addEventListener(event_name, this.handler);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
removeListener(element, event_name, bubbles) {
|
||||||
|
if (bubbles) {
|
||||||
|
this.removeBubblingListener(event_name);
|
||||||
|
} else {
|
||||||
|
this.removeNonBubblingListener(element, event_name);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
removeBubblingListener(event_name) {
|
||||||
|
this.global[event_name].active--;
|
||||||
|
if (this.global[event_name].active === 0) {
|
||||||
|
this.root.removeEventListener(event_name, this.global[event_name].callback);
|
||||||
|
delete this.global[event_name];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
removeNonBubblingListener(element, event_name) {
|
||||||
|
const id = element.getAttribute("data-dioxus-id");
|
||||||
|
delete this.local[id][event_name];
|
||||||
|
if (Object.keys(this.local[id]).length === 0) {
|
||||||
|
delete this.local[id];
|
||||||
|
}
|
||||||
|
element.removeEventListener(event_name, this.handler);
|
||||||
|
}
|
||||||
|
removeAllNonBubblingListeners(element) {
|
||||||
|
const id = element.getAttribute("data-dioxus-id");
|
||||||
|
delete this.local[id];
|
||||||
|
}
|
||||||
|
getNode(id) {
|
||||||
|
return this.nodes[id];
|
||||||
|
}
|
||||||
|
appendChildren(id, many) {
|
||||||
|
const root = this.nodes[id];
|
||||||
|
const els = this.stack.splice(this.stack.length - many);
|
||||||
|
for (let k = 0;k < many; k++) {
|
||||||
|
root.appendChild(els[k]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
loadChild(ptr, len) {
|
||||||
let node = this.stack[this.stack.length - 1];
|
let node = this.stack[this.stack.length - 1];
|
||||||
let ptr_end = ptr + len;
|
let ptr_end = ptr + len;
|
||||||
for (;ptr < ptr_end; ptr++) {
|
for (;ptr < ptr_end; ptr++) {
|
||||||
@@ -207,8 +200,10 @@ class PlatformInterpreter extends Interpreter {
|
|||||||
currentNode = treeWalker.nextNode();
|
currentNode = treeWalker.nextNode();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
setAttributeInner(node, field, value, ns) {
|
||||||
|
setAttributeInner(node, field, value, ns);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
export {
|
export {
|
||||||
setAttributeInner,
|
BaseInterpreter
|
||||||
PlatformInterpreter
|
|
||||||
};
|
};
|
||||||
@@ -1 +1 @@
|
|||||||
3599957386864841107
|
7906913262979346544
|
||||||
@@ -1,5 +1,85 @@
|
|||||||
// src/ts/interpreter_core.ts
|
// src/ts/set_attribute.ts
|
||||||
class Interpreter {
|
function setAttributeInner(node, field, value, ns) {
|
||||||
|
if (ns === "style") {
|
||||||
|
node.style.setProperty(field, value);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (!!ns) {
|
||||||
|
node.setAttributeNS(ns, field, value);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
switch (field) {
|
||||||
|
case "value":
|
||||||
|
if (node.value !== 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:
|
||||||
|
if (!truthy(value) && isBoolAttr(field)) {
|
||||||
|
node.removeAttribute(field);
|
||||||
|
} else {
|
||||||
|
node.setAttribute(field, value);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
var truthy = function(val) {
|
||||||
|
return val === "true" || val === true;
|
||||||
|
};
|
||||||
|
var isBoolAttr = function(field) {
|
||||||
|
switch (field) {
|
||||||
|
case "allowfullscreen":
|
||||||
|
case "allowpaymentrequest":
|
||||||
|
case "async":
|
||||||
|
case "autofocus":
|
||||||
|
case "autoplay":
|
||||||
|
case "checked":
|
||||||
|
case "controls":
|
||||||
|
case "default":
|
||||||
|
case "defer":
|
||||||
|
case "disabled":
|
||||||
|
case "formnovalidate":
|
||||||
|
case "hidden":
|
||||||
|
case "ismap":
|
||||||
|
case "itemscope":
|
||||||
|
case "loop":
|
||||||
|
case "multiple":
|
||||||
|
case "muted":
|
||||||
|
case "nomodule":
|
||||||
|
case "novalidate":
|
||||||
|
case "open":
|
||||||
|
case "playsinline":
|
||||||
|
case "readonly":
|
||||||
|
case "required":
|
||||||
|
case "reversed":
|
||||||
|
case "selected":
|
||||||
|
case "truespeed":
|
||||||
|
case "webkitdirectory":
|
||||||
|
return true;
|
||||||
|
default:
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
// src/ts/core.ts
|
||||||
|
class BaseInterpreter {
|
||||||
global;
|
global;
|
||||||
local;
|
local;
|
||||||
root;
|
root;
|
||||||
@@ -7,6 +87,7 @@ class Interpreter {
|
|||||||
nodes;
|
nodes;
|
||||||
stack;
|
stack;
|
||||||
templates;
|
templates;
|
||||||
|
m;
|
||||||
constructor(root, handler) {
|
constructor(root, handler) {
|
||||||
this.handler = handler;
|
this.handler = handler;
|
||||||
this.initialize(root);
|
this.initialize(root);
|
||||||
@@ -74,6 +155,54 @@ class Interpreter {
|
|||||||
root.appendChild(els[k]);
|
root.appendChild(els[k]);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
loadChild(ptr, len) {
|
||||||
|
let node = this.stack[this.stack.length - 1];
|
||||||
|
let ptr_end = ptr + len;
|
||||||
|
for (;ptr < ptr_end; ptr++) {
|
||||||
|
let end = this.m.getUint8(ptr);
|
||||||
|
for (node = node.firstChild;end > 0; end--) {
|
||||||
|
node = node.nextSibling;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return node;
|
||||||
|
}
|
||||||
|
saveTemplate(nodes, tmpl_id) {
|
||||||
|
this.templates[tmpl_id] = nodes;
|
||||||
|
}
|
||||||
|
hydrateRoot(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])];
|
||||||
|
this.nodes[id] = hydrateNode;
|
||||||
|
if (split.length > 1) {
|
||||||
|
hydrateNode.listening = split.length - 1;
|
||||||
|
hydrateNode.setAttribute("data-dioxus-id", id.toString());
|
||||||
|
for (let j = 1;j < split.length; j++) {
|
||||||
|
const listener = split[j];
|
||||||
|
const split2 = listener.split(":");
|
||||||
|
const event_name = split2[0];
|
||||||
|
const bubbles = split2[1] === "1";
|
||||||
|
this.createListener(event_name, hydrateNode, bubbles);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
const treeWalker = document.createTreeWalker(document.body, NodeFilter.SHOW_COMMENT);
|
||||||
|
let currentNode = treeWalker.nextNode();
|
||||||
|
while (currentNode) {
|
||||||
|
const id = currentNode.textContent;
|
||||||
|
const split = id.split("node-id");
|
||||||
|
if (split.length > 1) {
|
||||||
|
this.nodes[ids[parseInt(split[1])]] = currentNode.nextSibling;
|
||||||
|
}
|
||||||
|
currentNode = treeWalker.nextNode();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
setAttributeInner(node, field, value, ns) {
|
||||||
|
setAttributeInner(node, field, value, ns);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// src/ts/form.ts
|
// src/ts/form.ts
|
||||||
@@ -291,87 +420,7 @@ var serializeDragEvent = function(event) {
|
|||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|
||||||
// src/ts/set_attribute.ts
|
// src/ts/native.ts
|
||||||
function setAttributeInner(node, field, value, ns) {
|
|
||||||
if (ns === "style") {
|
|
||||||
node.style.setProperty(field, value);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
if (!!ns) {
|
|
||||||
node.setAttributeNS(ns, field, value);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
switch (field) {
|
|
||||||
case "value":
|
|
||||||
if (node.value !== 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:
|
|
||||||
if (!truthy(value) && isBoolAttr(field)) {
|
|
||||||
node.removeAttribute(field);
|
|
||||||
} else {
|
|
||||||
node.setAttribute(field, value);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
var truthy = function(val) {
|
|
||||||
return val === "true" || val === true;
|
|
||||||
};
|
|
||||||
var isBoolAttr = function(field) {
|
|
||||||
switch (field) {
|
|
||||||
case "allowfullscreen":
|
|
||||||
case "allowpaymentrequest":
|
|
||||||
case "async":
|
|
||||||
case "autofocus":
|
|
||||||
case "autoplay":
|
|
||||||
case "checked":
|
|
||||||
case "controls":
|
|
||||||
case "default":
|
|
||||||
case "defer":
|
|
||||||
case "disabled":
|
|
||||||
case "formnovalidate":
|
|
||||||
case "hidden":
|
|
||||||
case "ismap":
|
|
||||||
case "itemscope":
|
|
||||||
case "loop":
|
|
||||||
case "multiple":
|
|
||||||
case "muted":
|
|
||||||
case "nomodule":
|
|
||||||
case "novalidate":
|
|
||||||
case "open":
|
|
||||||
case "playsinline":
|
|
||||||
case "readonly":
|
|
||||||
case "required":
|
|
||||||
case "reversed":
|
|
||||||
case "selected":
|
|
||||||
case "truespeed":
|
|
||||||
case "webkitdirectory":
|
|
||||||
return true;
|
|
||||||
default:
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
// src/ts/interpreter_native.ts
|
|
||||||
var targetId = function(target) {
|
var targetId = function(target) {
|
||||||
if (!(target instanceof Node)) {
|
if (!(target instanceof Node)) {
|
||||||
return null;
|
return null;
|
||||||
@@ -390,7 +439,7 @@ var targetId = function(target) {
|
|||||||
return parseInt(realId);
|
return parseInt(realId);
|
||||||
};
|
};
|
||||||
|
|
||||||
class PlatformInterpreter extends Interpreter {
|
class PlatformInterpreter extends BaseInterpreter {
|
||||||
intercept_link_redirects;
|
intercept_link_redirects;
|
||||||
ipc;
|
ipc;
|
||||||
liveview;
|
liveview;
|
||||||
|
|||||||
@@ -2,8 +2,11 @@
|
|||||||
#![doc(html_logo_url = "https://avatars.githubusercontent.com/u/79236386")]
|
#![doc(html_logo_url = "https://avatars.githubusercontent.com/u/79236386")]
|
||||||
#![doc(html_favicon_url = "https://avatars.githubusercontent.com/u/79236386")]
|
#![doc(html_favicon_url = "https://avatars.githubusercontent.com/u/79236386")]
|
||||||
|
|
||||||
pub static INTERPRETER_JS: &str = include_str!("./js/native.js");
|
/// The base class that the JS channel will extend
|
||||||
pub static COMMON_JS: &str = include_str!("./js/web.js");
|
pub static INTERPRETER_JS: &str = include_str!("./js/core.js");
|
||||||
|
|
||||||
|
/// The code explicitly for desktop/liveview that bridges the eval gap between the two
|
||||||
|
pub static NATIVE_JS: &str = include_str!("./js/native.js");
|
||||||
|
|
||||||
#[cfg(all(feature = "binary-protocol", feature = "sledgehammer"))]
|
#[cfg(all(feature = "binary-protocol", feature = "sledgehammer"))]
|
||||||
mod write_native_mutations;
|
mod write_native_mutations;
|
||||||
@@ -25,7 +28,7 @@ pub mod minimal_bindings {
|
|||||||
/// Some useful snippets that we use to share common functionality between the different platforms we support.
|
/// Some useful snippets that we use to share common functionality between the different platforms we support.
|
||||||
///
|
///
|
||||||
/// This maintains some sort of consistency between web, desktop, and liveview
|
/// This maintains some sort of consistency between web, desktop, and liveview
|
||||||
#[wasm_bindgen(module = "/src/js/web.js")]
|
#[wasm_bindgen(module = "/src/js/common.js")]
|
||||||
extern "C" {
|
extern "C" {
|
||||||
/// Set the attribute of the node
|
/// Set the attribute of the node
|
||||||
pub fn setAttributeInner(node: JsValue, name: &str, value: JsValue, ns: Option<&str>);
|
pub fn setAttributeInner(node: JsValue, name: &str, value: JsValue, ns: Option<&str>);
|
||||||
|
|||||||
@@ -0,0 +1,2 @@
|
|||||||
|
export { setAttributeInner } from "./set_attribute";
|
||||||
|
export { retrieveFormValues } from "./form";
|
||||||
+73
-1
@@ -1,9 +1,11 @@
|
|||||||
// The root interpreter class that holds state about the mapping between DOM and VirtualDom
|
// The root interpreter class that holds state about the mapping between DOM and VirtualDom
|
||||||
// This always lives in the JS side of things, and is extended by the native and web interpreters
|
// This always lives in the JS side of things, and is extended by the native and web interpreters
|
||||||
|
|
||||||
|
import { setAttributeInner } from "./set_attribute";
|
||||||
|
|
||||||
export type NodeId = number;
|
export type NodeId = number;
|
||||||
|
|
||||||
export class Interpreter {
|
export class BaseInterpreter {
|
||||||
// non bubbling events listen at the element the listener was created at
|
// non bubbling events listen at the element the listener was created at
|
||||||
global: {
|
global: {
|
||||||
[key: string]: { active: number, callback: EventListener }
|
[key: string]: { active: number, callback: EventListener }
|
||||||
@@ -23,6 +25,9 @@ export class Interpreter {
|
|||||||
[key: string]: Node[]
|
[key: string]: Node[]
|
||||||
};
|
};
|
||||||
|
|
||||||
|
// sledgehammer is generating this...
|
||||||
|
m: any;
|
||||||
|
|
||||||
constructor(root: HTMLElement, handler: EventListener) {
|
constructor(root: HTMLElement, handler: EventListener) {
|
||||||
this.handler = handler;
|
this.handler = handler;
|
||||||
this.initialize(root);
|
this.initialize(root);
|
||||||
@@ -100,5 +105,72 @@ export class Interpreter {
|
|||||||
root.appendChild(els[k]);
|
root.appendChild(els[k]);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
loadChild(ptr: number, len: number): Node {
|
||||||
|
// iterate through each number and get that child
|
||||||
|
let node = this.stack[this.stack.length - 1] as Node;
|
||||||
|
let ptr_end = ptr + len;
|
||||||
|
|
||||||
|
for (; ptr < ptr_end; ptr++) {
|
||||||
|
let end = this.m.getUint8(ptr);
|
||||||
|
for (node = node.firstChild; end > 0; end--) {
|
||||||
|
node = node.nextSibling;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return node;
|
||||||
|
}
|
||||||
|
|
||||||
|
saveTemplate(nodes: HTMLElement[], tmpl_id: string) {
|
||||||
|
this.templates[tmpl_id] = nodes;
|
||||||
|
}
|
||||||
|
|
||||||
|
hydrateRoot(ids: { [key: number]: number }) {
|
||||||
|
const hydrateNodes = document.querySelectorAll('[data-node-hydration]');
|
||||||
|
|
||||||
|
for (let i = 0; i < hydrateNodes.length; i++) {
|
||||||
|
const hydrateNode = hydrateNodes[i] as HTMLElement;
|
||||||
|
const hydration = hydrateNode.getAttribute('data-node-hydration');
|
||||||
|
const split = hydration!.split(',');
|
||||||
|
const id = ids[parseInt(split[0])];
|
||||||
|
|
||||||
|
this.nodes[id] = hydrateNode;
|
||||||
|
|
||||||
|
if (split.length > 1) {
|
||||||
|
// @ts-ignore
|
||||||
|
hydrateNode.listening = split.length - 1;
|
||||||
|
hydrateNode.setAttribute('data-dioxus-id', id.toString());
|
||||||
|
for (let j = 1; j < split.length; j++) {
|
||||||
|
const listener = split[j];
|
||||||
|
const split2 = listener.split(':');
|
||||||
|
const event_name = split2[0];
|
||||||
|
const bubbles = split2[1] === '1';
|
||||||
|
this.createListener(event_name, hydrateNode, bubbles);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
const treeWalker = document.createTreeWalker(
|
||||||
|
document.body,
|
||||||
|
NodeFilter.SHOW_COMMENT,
|
||||||
|
);
|
||||||
|
|
||||||
|
let currentNode = treeWalker.nextNode();
|
||||||
|
|
||||||
|
while (currentNode) {
|
||||||
|
const id = currentNode.textContent!;
|
||||||
|
const split = id.split('node-id');
|
||||||
|
|
||||||
|
if (split.length > 1) {
|
||||||
|
this.nodes[ids[parseInt(split[1])]] = currentNode.nextSibling;
|
||||||
|
}
|
||||||
|
|
||||||
|
currentNode = treeWalker.nextNode();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
setAttributeInner(node: HTMLElement, field: string, value: string, ns: string) {
|
||||||
|
setAttributeInner(node, field, value, ns);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1,79 +0,0 @@
|
|||||||
// The JS<->Rust bridge
|
|
||||||
// This file is thin, suitable just for the web
|
|
||||||
// If you want the more full-featured intrepreter, look at the native interpreter which extends this with additional functionality
|
|
||||||
//
|
|
||||||
// We're using sledgehammer directly
|
|
||||||
|
|
||||||
import { Interpreter } from "./interpreter_core";
|
|
||||||
export { setAttributeInner } from "./set_attribute";
|
|
||||||
|
|
||||||
export class PlatformInterpreter extends Interpreter {
|
|
||||||
m: any;
|
|
||||||
|
|
||||||
constructor(root: HTMLElement, handler: EventListener) {
|
|
||||||
super(root, handler);
|
|
||||||
}
|
|
||||||
|
|
||||||
LoadChild(ptr: number, len: number): Node {
|
|
||||||
// iterate through each number and get that child
|
|
||||||
let node = this.stack[this.stack.length - 1] as Node;
|
|
||||||
let ptr_end = ptr + len;
|
|
||||||
|
|
||||||
for (; ptr < ptr_end; ptr++) {
|
|
||||||
let end = this.m.getUint8(ptr);
|
|
||||||
for (node = node.firstChild; end > 0; end--) {
|
|
||||||
node = node.nextSibling;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return node;
|
|
||||||
}
|
|
||||||
|
|
||||||
saveTemplate(nodes: HTMLElement[], tmpl_id: string) {
|
|
||||||
this.templates[tmpl_id] = nodes;
|
|
||||||
}
|
|
||||||
|
|
||||||
hydrateRoot(ids: { [key: number]: number }) {
|
|
||||||
const hydrateNodes = document.querySelectorAll('[data-node-hydration]');
|
|
||||||
|
|
||||||
for (let i = 0; i < hydrateNodes.length; i++) {
|
|
||||||
const hydrateNode = hydrateNodes[i] as HTMLElement;
|
|
||||||
const hydration = hydrateNode.getAttribute('data-node-hydration');
|
|
||||||
const split = hydration!.split(',');
|
|
||||||
const id = ids[parseInt(split[0])];
|
|
||||||
|
|
||||||
this.nodes[id] = hydrateNode;
|
|
||||||
|
|
||||||
if (split.length > 1) {
|
|
||||||
// @ts-ignore
|
|
||||||
hydrateNode.listening = split.length - 1;
|
|
||||||
hydrateNode.setAttribute('data-dioxus-id', id.toString());
|
|
||||||
for (let j = 1; j < split.length; j++) {
|
|
||||||
const listener = split[j];
|
|
||||||
const split2 = listener.split(':');
|
|
||||||
const event_name = split2[0];
|
|
||||||
const bubbles = split2[1] === '1';
|
|
||||||
this.createListener(event_name, hydrateNode, bubbles);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
const treeWalker = document.createTreeWalker(
|
|
||||||
document.body,
|
|
||||||
NodeFilter.SHOW_COMMENT,
|
|
||||||
);
|
|
||||||
|
|
||||||
let currentNode = treeWalker.nextNode();
|
|
||||||
|
|
||||||
while (currentNode) {
|
|
||||||
const id = currentNode.textContent!;
|
|
||||||
const split = id.split('node-id');
|
|
||||||
|
|
||||||
if (split.length > 1) {
|
|
||||||
this.nodes[ids[parseInt(split[1])]] = currentNode.nextSibling;
|
|
||||||
}
|
|
||||||
|
|
||||||
currentNode = treeWalker.nextNode();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
+2
-2
@@ -3,11 +3,11 @@
|
|||||||
// This file lives on the renderer, not the host. It's basically a polyfill over functionality that the host can't
|
// This file lives on the renderer, not the host. It's basically a polyfill over functionality that the host can't
|
||||||
// provide since it doesn't have access to the dom.
|
// provide since it doesn't have access to the dom.
|
||||||
|
|
||||||
import { Interpreter, NodeId } from "./interpreter_core";
|
import { BaseInterpreter, NodeId } from "./core";
|
||||||
import { SerializedEvent, serializeEvent } from "./serialize";
|
import { SerializedEvent, serializeEvent } from "./serialize";
|
||||||
import { setAttributeInner } from "./set_attribute";
|
import { setAttributeInner } from "./set_attribute";
|
||||||
|
|
||||||
export class PlatformInterpreter extends Interpreter {
|
export class PlatformInterpreter extends BaseInterpreter {
|
||||||
intercept_link_redirects: boolean;
|
intercept_link_redirects: boolean;
|
||||||
ipc: any;
|
ipc: any;
|
||||||
|
|
||||||
@@ -1,32 +1,54 @@
|
|||||||
#[cfg(feature = "webonly")]
|
#[cfg(feature = "webonly")]
|
||||||
use web_sys::Node;
|
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;
|
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 {
|
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`.
|
/// 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;
|
pub struct Interpreter;
|
||||||
|
|
||||||
fn mount_to_root() {
|
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) {
|
fn push_root(root: u32) {
|
||||||
"{this.stack.push(this.nodes[$root$]);}"
|
"{this.stack.push(this.nodes[$root$]);}"
|
||||||
}
|
}
|
||||||
fn append_children(id: u32, many: u16) {
|
fn append_children(id: u32, many: u16) {
|
||||||
"{this.AppendChildren($id$, $many$);}"
|
"{this.appendChildren($id$, $many$);}"
|
||||||
}
|
}
|
||||||
fn pop_root() {
|
fn pop_root() {
|
||||||
"{this.stack.pop();}"
|
"{this.stack.pop();}"
|
||||||
@@ -93,11 +115,11 @@ mod js {
|
|||||||
}"#
|
}"#
|
||||||
}
|
}
|
||||||
fn assign_id(ptr: u32, len: u8, id: u32) {
|
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) {
|
fn hydrate_text(ptr: u32, len: u8, value: &str, id: u32) {
|
||||||
r#"{
|
r#"{
|
||||||
let node = this.LoadChild($ptr$, $len$);
|
let node = this.loadChild($ptr$, $len$);
|
||||||
if (node.nodeType == node.TEXT_NODE) {
|
if (node.nodeType == node.TEXT_NODE) {
|
||||||
node.textContent = value;
|
node.textContent = value;
|
||||||
} else {
|
} else {
|
||||||
@@ -109,20 +131,13 @@ mod js {
|
|||||||
}"#
|
}"#
|
||||||
}
|
}
|
||||||
fn replace_placeholder(ptr: u32, len: u8, n: u16) {
|
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) {
|
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);}"
|
"{let node = this.templates[$tmpl_id$][$index$].cloneNode(true); this.nodes[$id$] = node; this.stack.push(node);}"
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
#[cfg(feature = "binary-protocol")]
|
||||||
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
|
|
||||||
*/
|
|
||||||
fn append_children_to_top(many: u16) {
|
fn append_children_to_top(many: u16) {
|
||||||
"{
|
"{
|
||||||
let root = this.stack[this.stack.length-many-1];
|
let root = this.stack[this.stack.length-many-1];
|
||||||
@@ -130,23 +145,35 @@ mod js {
|
|||||||
for (let k = 0; k < many; k++) {
|
for (let k = 0; k < many; k++) {
|
||||||
root.appendChild(this.els[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>) {
|
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$);}"
|
"{this.setAttributeInner(this.stack[this.stack.length-1], $field$, $value$, $ns$);}"
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[cfg(feature = "binary-protocol")]
|
||||||
fn add_placeholder() {
|
fn add_placeholder() {
|
||||||
"{let node = document.createElement('pre'); node.hidden = true; this.stack.push(node);}"
|
"{let node = document.createElement('pre'); node.hidden = true; this.stack.push(node);}"
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[cfg(feature = "binary-protocol")]
|
||||||
fn create_element(element: &'static str<u8, el>) {
|
fn create_element(element: &'static str<u8, el>) {
|
||||||
"{this.stack.push(document.createElement($element$))}"
|
"{this.stack.push(document.createElement($element$))}"
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[cfg(feature = "binary-protocol")]
|
||||||
fn create_element_ns(element: &'static str<u8, el>, ns: &'static str<u8, namespace>) {
|
fn create_element_ns(element: &'static str<u8, el>, ns: &'static str<u8, namespace>) {
|
||||||
"{this.stack.push(document.createElementNS($ns$, $element$))}"
|
"{this.stack.push(document.createElementNS($ns$, $element$))}"
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[cfg(feature = "binary-protocol")]
|
||||||
fn add_templates(tmpl_id: u16, len: u16) {
|
fn add_templates(tmpl_id: u16, len: u16) {
|
||||||
"{this.templates[$tmpl_id$] = this.stack.splice(this.stack.length-$len$);}"
|
"{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) {
|
fn foreign_event_listener(event: &str<u8, evt>, id: u32, bubbles: u8) {
|
||||||
r#"
|
r#"
|
||||||
bubbles = bubbles == 1;
|
bubbles = bubbles == 1;
|
||||||
@@ -175,12 +202,18 @@ mod js {
|
|||||||
});
|
});
|
||||||
}"#
|
}"#
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Assign the ID
|
||||||
|
#[cfg(feature = "binary-protocol")]
|
||||||
fn assign_id_ref(array: &[u8], id: u32) {
|
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) {
|
fn hydrate_text_ref(array: &[u8], value: &str, id: u32) {
|
||||||
r#"{
|
r#"{
|
||||||
let node = this.LoadChild($array$);
|
let node = this.loadChild($array$);
|
||||||
if (node.nodeType == node.TEXT_NODE) {
|
if (node.nodeType == node.TEXT_NODE) {
|
||||||
node.textContent = value;
|
node.textContent = value;
|
||||||
} else {
|
} else {
|
||||||
@@ -191,38 +224,9 @@ mod js {
|
|||||||
this.nodes[$id$] = node;
|
this.nodes[$id$] = node;
|
||||||
}"#
|
}"#
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[cfg(feature = "binary-protocol")]
|
||||||
fn replace_placeholder_ref(array: &[u8], n: u16) {
|
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);}"
|
"{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()
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -8,7 +8,7 @@
|
|||||||
|
|
||||||
use dioxus_core::ElementId;
|
use dioxus_core::ElementId;
|
||||||
use dioxus_html::PlatformEventData;
|
use dioxus_html::PlatformEventData;
|
||||||
use dioxus_interpreter_js::{unified_bindings::Interpreter, WebInterpreter};
|
use dioxus_interpreter_js::unified_bindings::Interpreter;
|
||||||
use futures_channel::mpsc;
|
use futures_channel::mpsc;
|
||||||
use rustc_hash::FxHashMap;
|
use rustc_hash::FxHashMap;
|
||||||
use wasm_bindgen::{closure::Closure, JsCast};
|
use wasm_bindgen::{closure::Closure, JsCast};
|
||||||
@@ -112,7 +112,7 @@ impl WebsysDom {
|
|||||||
}
|
}
|
||||||
}));
|
}));
|
||||||
|
|
||||||
let _interpreter: &WebInterpreter = interpreter.as_web();
|
let _interpreter = interpreter.base();
|
||||||
_interpreter.initialize(
|
_interpreter.initialize(
|
||||||
root.clone().unchecked_into(),
|
root.clone().unchecked_into(),
|
||||||
handler.as_ref().unchecked_ref(),
|
handler.as_ref().unchecked_ref(),
|
||||||
|
|||||||
@@ -65,7 +65,7 @@ impl WebsysDom {
|
|||||||
#[cfg(feature = "mounted")]
|
#[cfg(feature = "mounted")]
|
||||||
fn flush_queued_mounted_events(&mut self) {
|
fn flush_queued_mounted_events(&mut self) {
|
||||||
for id in self.queued_mounted_events.drain(..) {
|
for id in self.queued_mounted_events.drain(..) {
|
||||||
let node = self.interpreter.as_web().get_node(id.0 as u32);
|
let node = self.interpreter.base().get_node(id.0 as u32);
|
||||||
if let Some(element) = node.dyn_ref::<web_sys::Element>() {
|
if let Some(element) = node.dyn_ref::<web_sys::Element>() {
|
||||||
let _ = self.event_channel.unbounded_send(UiEvent {
|
let _ = self.event_channel.unbounded_send(UiEvent {
|
||||||
name: "mounted".to_string(),
|
name: "mounted".to_string(),
|
||||||
@@ -92,7 +92,7 @@ impl WriteMutations for WebsysDom {
|
|||||||
self.templates
|
self.templates
|
||||||
.insert(template.name.to_owned(), self.max_template_id);
|
.insert(template.name.to_owned(), self.max_template_id);
|
||||||
self.interpreter
|
self.interpreter
|
||||||
.as_web()
|
.base()
|
||||||
.save_template(roots, self.max_template_id);
|
.save_template(roots, self.max_template_id);
|
||||||
self.max_template_id += 1
|
self.max_template_id += 1
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -22,7 +22,7 @@ impl WebsysDom {
|
|||||||
// Recursively rehydrate the dom from the VirtualDom
|
// Recursively rehydrate the dom from the VirtualDom
|
||||||
self.rehydrate_scope(root_scope, dom, &mut ids, &mut to_mount)?;
|
self.rehydrate_scope(root_scope, dom, &mut ids, &mut to_mount)?;
|
||||||
|
|
||||||
self.interpreter.as_web().hydrate(ids);
|
self.interpreter.base().hydrate(ids);
|
||||||
|
|
||||||
#[cfg(feature = "mounted")]
|
#[cfg(feature = "mounted")]
|
||||||
for id in to_mount {
|
for id in to_mount {
|
||||||
@@ -168,7 +168,7 @@ impl WriteMutations for OnlyWriteTemplates<'_> {
|
|||||||
.insert(template.name.to_owned(), self.0.max_template_id);
|
.insert(template.name.to_owned(), self.0.max_template_id);
|
||||||
self.0
|
self.0
|
||||||
.interpreter
|
.interpreter
|
||||||
.as_web()
|
.base()
|
||||||
.save_template(roots, self.0.max_template_id);
|
.save_template(roots, self.0.max_template_id);
|
||||||
self.0.max_template_id += 1
|
self.0.max_template_id += 1
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in new issue
Block a user