487 lines
11 KiB
JavaScript
487 lines
11 KiB
JavaScript
|
|
class Interpreter {
|
|
constructor(root) {
|
|
this.root = root;
|
|
this.stack = [root];
|
|
this.listeners = {
|
|
"onclick": {}
|
|
};
|
|
this.lastNodeWasText = false;
|
|
this.nodes = [root];
|
|
}
|
|
|
|
top() {
|
|
return this.stack[this.stack.length - 1];
|
|
}
|
|
|
|
pop() {
|
|
return this.stack.pop();
|
|
}
|
|
|
|
PushRoot(edit) {
|
|
const id = edit.root;
|
|
const node = this.nodes[id];
|
|
this.stack.push(node);
|
|
}
|
|
|
|
PopRoot(_edit) {
|
|
this.stack.pop();
|
|
}
|
|
|
|
AppendChildren(edit) {
|
|
let root = this.stack[this.stack.length - (1 + edit.many)];
|
|
|
|
let to_add = this.stack.splice(this.stack.length - edit.many);
|
|
|
|
for (let i = 0; i < edit.many; i++) {
|
|
root.appendChild(to_add[i]);
|
|
}
|
|
}
|
|
|
|
ReplaceWith(edit) {
|
|
// console.log(edit);
|
|
let root = this.nodes[edit.root];
|
|
let els = this.stack.splice(this.stack.length - edit.m);
|
|
|
|
// console.log(root);
|
|
// console.log(els);
|
|
|
|
|
|
root.replaceWith(...els);
|
|
}
|
|
|
|
InsertAfter(edit) {
|
|
let old = this.nodes[edit.root];
|
|
let new_nodes = this.stack.splice(this.stack.length - edit.n);
|
|
old.after(...new_nodes);
|
|
}
|
|
|
|
InsertBefore(edit) {
|
|
let old = this.nodes[edit.root];
|
|
let new_nodes = this.stack.splice(this.stack.length - edit.n);
|
|
old.before(...new_nodes);
|
|
}
|
|
|
|
Remove(edit) {
|
|
let node = this.nodes[edit.root];
|
|
if (node !== undefined) {
|
|
node.remove();
|
|
}
|
|
}
|
|
|
|
CreateTextNode(edit) {
|
|
const node = document.createTextNode(edit.text);
|
|
this.nodes[edit.root] = node;
|
|
this.stack.push(node);
|
|
}
|
|
|
|
CreateElement(edit) {
|
|
const tagName = edit.tag;
|
|
const el = document.createElement(tagName);
|
|
this.nodes[edit.root] = el;
|
|
this.stack.push(el);
|
|
}
|
|
|
|
CreateElementNs(edit) {
|
|
let el = document.createElementNS(edit.ns, edit.tag);
|
|
this.stack.push(el);
|
|
this.nodes[edit.root] = el;
|
|
}
|
|
|
|
CreatePlaceholder(edit) {
|
|
let el = document.createElement("pre");
|
|
this.stack.push(el);
|
|
this.nodes[edit.root] = el;
|
|
}
|
|
|
|
RemoveEventListener(edit) { }
|
|
|
|
NewEventListener(edit) {
|
|
const event_name = edit.event_name;
|
|
const mounted_node_id = edit.root;
|
|
const scope = edit.scope;
|
|
|
|
const element = this.nodes[edit.root]
|
|
element.setAttribute(`dioxus-event-${event_name}`, `${scope}.${mounted_node_id}`);
|
|
|
|
if (this.listeners[event_name] === undefined) {
|
|
this.listeners[event_name] = "bla";
|
|
|
|
this.root.addEventListener(event_name, (event) => {
|
|
// console.log("CLICKED");
|
|
const target = event.target;
|
|
const val = target.getAttribute(`dioxus-event-${event_name}`);
|
|
if (val == null) {
|
|
return;
|
|
}
|
|
|
|
const fields = val.split(".");
|
|
const scope_id = parseInt(fields[0]);
|
|
const real_id = parseInt(fields[1]);
|
|
|
|
// // console.log(`parsed event with scope_id ${scope_id} and real_id ${real_id}`);
|
|
|
|
// console.log("message fired");
|
|
let contents = serialize_event(event);
|
|
let evt = {
|
|
event: event_name,
|
|
scope: scope_id,
|
|
mounted_dom_id: real_id,
|
|
contents: contents,
|
|
};
|
|
// console.log(evt);
|
|
rpc.call('user_event', evt).then((reply) => {
|
|
// console.log("reply received", reply);
|
|
|
|
this.stack.push(this.root);
|
|
|
|
reply.map((reply) => {
|
|
let edits = reply.edits;
|
|
for (let x = 0; x < edits.length; x++) {
|
|
let edit = edits[x];
|
|
let f = this[edit.type];
|
|
f.call(this, edit);
|
|
}
|
|
});
|
|
|
|
})
|
|
});
|
|
}
|
|
}
|
|
|
|
SetText(edit) {
|
|
this.nodes[edit.root].textContent = edit.text;
|
|
}
|
|
|
|
SetAttribute(edit) {
|
|
// console.log("setting attr", edit);
|
|
const name = edit.field;
|
|
const value = edit.value;
|
|
const ns = edit.ns;
|
|
const node = this.nodes[edit.root]
|
|
|
|
if (ns == "style") {
|
|
node.style[name] = value;
|
|
} else if ((ns != null) || (ns != undefined)) {
|
|
node.setAttributeNS(ns, name, value);
|
|
} else {
|
|
switch (name) {
|
|
case "value":
|
|
node.value = value;
|
|
break;
|
|
case "checked":
|
|
// console.log("setting checked");
|
|
node.checked = (value === "true");
|
|
break;
|
|
case "selected":
|
|
node.selected = (value === "true");
|
|
break;
|
|
case "dangerous_inner_html":
|
|
node.innerHTML = value;
|
|
break;
|
|
default:
|
|
// console.log("setting attr directly ", name, value);
|
|
node.setAttribute(name, value);
|
|
}
|
|
}
|
|
}
|
|
RemoveAttribute(edit) {
|
|
const name = edit.field;
|
|
const node = this.nodes[edit.root];
|
|
node.removeAttribute(name);
|
|
|
|
if (name === "value") {
|
|
node.value = null;
|
|
}
|
|
if (name === "checked") {
|
|
node.checked = false;
|
|
}
|
|
if (name === "selected") {
|
|
node.selected = false;
|
|
}
|
|
}
|
|
|
|
}
|
|
|
|
async function initialize() {
|
|
let root = window.document.getElementById("_dioxusroot");
|
|
const interpreter = new Interpreter(root);
|
|
|
|
const reply = await rpc.call('initiate');
|
|
|
|
let pre_rendered = reply.pre_rendered;
|
|
if (pre_rendered !== undefined) {
|
|
root.innerHTML = pre_rendered;
|
|
}
|
|
|
|
const edits = reply.edits;
|
|
|
|
apply_edits(edits, interpreter);
|
|
}
|
|
|
|
function apply_edits(edits, interpreter) {
|
|
// console.log(edits);
|
|
for (let x = 0; x < edits.length; x++) {
|
|
let edit = edits[x];
|
|
let f = interpreter[edit.type];
|
|
f.call(interpreter, edit);
|
|
}
|
|
|
|
// // console.log("stack completed: ", interpreter.stack);
|
|
}
|
|
|
|
function serialize_event(event) {
|
|
let serializer = SerializeMap[event.type];
|
|
if (serializer === undefined) {
|
|
return {};
|
|
} else {
|
|
return serializer(event);
|
|
}
|
|
}
|
|
|
|
const SerializeMap = {
|
|
"copy": serialize_clipboard,
|
|
"cut": serialize_clipboard,
|
|
"paste": serialize_clipboard,
|
|
|
|
"compositionend": serialize_composition,
|
|
"compositionstart": serialize_composition,
|
|
"compositionupdate": serialize_composition,
|
|
|
|
"keydown": serialize_keyboard,
|
|
"keypress": serialize_keyboard,
|
|
"keyup": serialize_keyboard,
|
|
|
|
"focus": serialize_focus,
|
|
"blur": serialize_focus,
|
|
|
|
// "change": serialize_form,
|
|
"change": serialize_change,
|
|
|
|
"input": serialize_form,
|
|
"invalid": serialize_form,
|
|
"reset": serialize_form,
|
|
"submit": serialize_form,
|
|
|
|
"click": serialize_mouse,
|
|
"contextmenu": serialize_mouse,
|
|
"doubleclick": serialize_mouse,
|
|
"drag": serialize_mouse,
|
|
"dragend": serialize_mouse,
|
|
"dragenter": serialize_mouse,
|
|
"dragexit": serialize_mouse,
|
|
"dragleave": serialize_mouse,
|
|
"dragover": serialize_mouse,
|
|
"dragstart": serialize_mouse,
|
|
"drop": serialize_mouse,
|
|
"mousedown": serialize_mouse,
|
|
"mouseenter": serialize_mouse,
|
|
"mouseleave": serialize_mouse,
|
|
"mousemove": serialize_mouse,
|
|
"mouseout": serialize_mouse,
|
|
"mouseover": serialize_mouse,
|
|
"mouseup": serialize_mouse,
|
|
|
|
"pointerdown": serialize_pointer,
|
|
"pointermove": serialize_pointer,
|
|
"pointerup": serialize_pointer,
|
|
"pointercancel": serialize_pointer,
|
|
"gotpointercapture": serialize_pointer,
|
|
"lostpointercapture": serialize_pointer,
|
|
"pointerenter": serialize_pointer,
|
|
"pointerleave": serialize_pointer,
|
|
"pointerover": serialize_pointer,
|
|
"pointerout": serialize_pointer,
|
|
|
|
"select": serialize_selection,
|
|
|
|
"touchcancel": serialize_touch,
|
|
"touchend": serialize_touch,
|
|
"touchmove": serialize_touch,
|
|
"touchstart": serialize_touch,
|
|
|
|
"scroll": serialize_scroll,
|
|
|
|
"wheel": serialize_wheel,
|
|
|
|
"animationstart": serialize_animation,
|
|
"animationend": serialize_animation,
|
|
"animationiteration": serialize_animation,
|
|
|
|
"transitionend": serialize_transition,
|
|
|
|
"abort": serialize_media,
|
|
"canplay": serialize_media,
|
|
"canplaythrough": serialize_media,
|
|
"durationchange": serialize_media,
|
|
"emptied": serialize_media,
|
|
"encrypted": serialize_media,
|
|
"ended": serialize_media,
|
|
"error": serialize_media,
|
|
"loadeddata": serialize_media,
|
|
"loadedmetadata": serialize_media,
|
|
"loadstart": serialize_media,
|
|
"pause": serialize_media,
|
|
"play": serialize_media,
|
|
"playing": serialize_media,
|
|
"progress": serialize_media,
|
|
"ratechange": serialize_media,
|
|
"seeked": serialize_media,
|
|
"seeking": serialize_media,
|
|
"stalled": serialize_media,
|
|
"suspend": serialize_media,
|
|
"timeupdate": serialize_media,
|
|
"volumechange": serialize_media,
|
|
"waiting": serialize_media,
|
|
|
|
"toggle": serialize_toggle
|
|
}
|
|
|
|
function serialize_clipboard(_event) {
|
|
return {};
|
|
}
|
|
function serialize_composition(event) {
|
|
return {
|
|
data: event.data
|
|
}
|
|
}
|
|
function serialize_keyboard(event) {
|
|
return {
|
|
char_code: event.charCode,
|
|
key: event.key,
|
|
alt_key: event.altKey,
|
|
ctrl_key: event.ctrlKey,
|
|
meta_key: event.metaKey,
|
|
key_code: event.keyCode,
|
|
shift_key: event.shiftKey,
|
|
locale: "locale",
|
|
// locale: event.locale,
|
|
location: event.location,
|
|
repeat: event.repeat,
|
|
which: event.which,
|
|
}
|
|
}
|
|
function serialize_focus(_event) {
|
|
return {}
|
|
}
|
|
|
|
function serialize_change(event) {
|
|
let target = event.target;
|
|
let value;
|
|
if (target.type === "checkbox" || target.type === "radio") {
|
|
value = target.checked ? "true" : "false";
|
|
} else {
|
|
value = target.value ?? target.textContent;
|
|
}
|
|
|
|
return {
|
|
value: value
|
|
}
|
|
}
|
|
function serialize_form(event) {
|
|
let target = event.target;
|
|
let value = target.value ?? target.textContent;
|
|
return {
|
|
value: value
|
|
}
|
|
}
|
|
function serialize_mouse(event) {
|
|
return {
|
|
alt_key: event.altKey,
|
|
button: event.button,
|
|
buttons: event.buttons,
|
|
client_x: event.clientX,
|
|
client_y: event.clientY,
|
|
ctrl_key: event.ctrlKey,
|
|
meta_key: event.metaKey,
|
|
page_x: event.pageX,
|
|
page_y: event.pageY,
|
|
screen_x: event.screenX,
|
|
screen_y: event.screenY,
|
|
shift_key: event.shiftKey,
|
|
}
|
|
}
|
|
|
|
function serialize_pointer(event) {
|
|
return {
|
|
alt_key: event.altKey,
|
|
button: event.button,
|
|
buttons: event.buttons,
|
|
client_x: event.clientX,
|
|
client_y: event.clientY,
|
|
ctrl_key: event.ctrlKey,
|
|
meta_key: event.metaKey,
|
|
page_x: event.pageX,
|
|
page_y: event.pageY,
|
|
screen_x: event.screenX,
|
|
screen_y: event.screenY,
|
|
shift_key: event.shiftKey,
|
|
pointer_id: event.pointerId,
|
|
width: event.width,
|
|
height: event.height,
|
|
pressure: event.pressure,
|
|
tangential_pressure: event.tangentialPressure,
|
|
tilt_x: event.tiltX,
|
|
tilt_y: event.tiltY,
|
|
twist: event.twist,
|
|
pointer_type: event.pointerType,
|
|
is_primary: event.isPrimary,
|
|
}
|
|
}
|
|
|
|
function serialize_selection(event) {
|
|
return {}
|
|
}
|
|
|
|
function serialize_touch(event) {
|
|
return {
|
|
alt_key: event.altKey,
|
|
ctrl_key: event.ctrlKey,
|
|
meta_key: event.metaKey,
|
|
shift_key: event.shiftKey,
|
|
|
|
// changed_touches: event.changedTouches,
|
|
// target_touches: event.targetTouches,
|
|
// touches: event.touches,
|
|
}
|
|
}
|
|
function serialize_scroll(event) {
|
|
return {}
|
|
}
|
|
|
|
function serialize_wheel(event) {
|
|
return {
|
|
delta_x: event.deltaX,
|
|
delta_y: event.deltaY,
|
|
delta_z: event.deltaZ,
|
|
delta_mode: event.deltaMode,
|
|
}
|
|
}
|
|
|
|
function serialize_animation(event) {
|
|
return {
|
|
animation_name: event.animationName,
|
|
elapsed_time: event.elapsedTime,
|
|
pseudo_element: event.pseudoElement,
|
|
}
|
|
}
|
|
|
|
function serialize_transition(event) {
|
|
return {
|
|
property_name: event.propertyName,
|
|
elapsed_time: event.elapsedTime,
|
|
pseudo_element: event.pseudoElement,
|
|
}
|
|
}
|
|
|
|
function serialize_media(event) {
|
|
return {}
|
|
}
|
|
|
|
function serialize_toggle(event) {
|
|
return {}
|
|
}
|
|
|
|
|
|
initialize();
|