From f447f01403a4b43065c10699d4e900f792781a34 Mon Sep 17 00:00:00 2001 From: Jonathan Kelley Date: Tue, 27 Feb 2024 16:33:34 -0800 Subject: [PATCH] Commit js --- packages/interpreter/a.txt | 1 - packages/interpreter/build.rs | 70 +- packages/interpreter/gen/README.md | 3 - packages/interpreter/src/js/hash.txt | 1 + packages/interpreter/src/js/native.js | 681 ++++++++++++++++++ packages/interpreter/src/js/web.js | 159 ++++ packages/interpreter/src/lib.rs | 4 +- packages/interpreter/src/ts/.gitignore | 3 + .../interpreter/src/ts/interpreter_core.ts | 1 + packages/interpreter/tsconfig.json | 5 - packages/interpreter/tsconfig.native.json | 10 + packages/interpreter/tsconfig.web.json | 10 + 12 files changed, 903 insertions(+), 45 deletions(-) delete mode 100644 packages/interpreter/a.txt delete mode 100644 packages/interpreter/gen/README.md create mode 100644 packages/interpreter/src/js/hash.txt create mode 100644 packages/interpreter/src/js/native.js create mode 100644 packages/interpreter/src/js/web.js create mode 100644 packages/interpreter/src/ts/.gitignore create mode 100644 packages/interpreter/tsconfig.native.json create mode 100644 packages/interpreter/tsconfig.web.json diff --git a/packages/interpreter/a.txt b/packages/interpreter/a.txt deleted file mode 100644 index db9748690..000000000 --- a/packages/interpreter/a.txt +++ /dev/null @@ -1 +0,0 @@ -pub const SLEDGEHAMMER_JS: &str = "let m,p,ls,d,t,op,i,e,z,metaflags;\n const namespace = [];\n let namespace_cache_hit, namespace_cache_idx;\n function get_namespace() {\n namespace_cache_idx = u8buf[u8bufp++];\n if(namespace_cache_idx & 128){\n namespace_cache_hit=s.substring(sp,sp+=u8buf[u8bufp++]);\n namespace[namespace_cache_idx&4294967167]=namespace_cache_hit;\n return namespace_cache_hit;\n }\n else{\n return namespace[namespace_cache_idx&4294967167];\n }\n }let u8buf,u8bufp;const attr = [];\n let attr_cache_hit, attr_cache_idx;\n function get_attr() {\n attr_cache_idx = u8buf[u8bufp++];\n if(attr_cache_idx & 128){\n attr_cache_hit=s.substring(sp,sp+=u8buf[u8bufp++]);\n attr[attr_cache_idx&4294967167]=attr_cache_hit;\n return attr_cache_hit;\n }\n else{\n return attr[attr_cache_idx&4294967167];\n }\n }const evt = [];\n let evt_cache_hit, evt_cache_idx;\n function get_evt() {\n evt_cache_idx = u8buf[u8bufp++];\n if(evt_cache_idx & 128){\n evt_cache_hit=s.substring(sp,sp+=u8buf[u8bufp++]);\n evt[evt_cache_idx&4294967167]=evt_cache_hit;\n return evt_cache_hit;\n }\n else{\n return evt[evt_cache_idx&4294967167];\n }\n }const el = [];\n let el_cache_hit, el_cache_idx;\n function get_el() {\n el_cache_idx = u8buf[u8bufp++];\n if(el_cache_idx & 128){\n el_cache_hit=s.substring(sp,sp+=u8buf[u8bufp++]);\n el[el_cache_idx&4294967167]=el_cache_hit;\n return el_cache_hit;\n }\n else{\n return el[el_cache_idx&4294967167];\n }\n }let u32buf,u32bufp;let s = \"\";let lsp,sp,sl; let c = new TextDecoder();let u16buf,u16bufp;const ns_cache = [];\n let ns_cache_cache_hit, ns_cache_cache_idx;\n function get_ns_cache() {\n ns_cache_cache_idx = u8buf[u8bufp++];\n if(ns_cache_cache_idx & 128){\n ns_cache_cache_hit=s.substring(sp,sp+=u8buf[u8bufp++]);\n ns_cache[ns_cache_cache_idx&4294967167]=ns_cache_cache_hit;\n return ns_cache_cache_hit;\n }\n else{\n return ns_cache[ns_cache_cache_idx&4294967167];\n }\n }\n let field,ptr,array,ns,id,value,len,event,many,bubbles,event_name;\n export function create(r){\n d=r;\n }\n export function update_memory(b){\n m=new DataView(b.buffer)\n }\n export function run(){\n metaflags=m.getUint32(d,true);\n if((metaflags>>>6)&1){\n ls=m.getUint32(d+6*4,true);\n }\n p=ls;\n if ((metaflags>>>5)&1){\n t = m.getUint32(d+5*4,true);\n u8buf=new Uint8Array(m.buffer,t,((m.buffer.byteLength-t)-(m.buffer.byteLength-t)%1)/1);\n }\n u8bufp=0;if ((metaflags>>>3)&1){\n t = m.getUint32(d+3*4,true);\n u32buf=new Uint32Array(m.buffer,t,((m.buffer.byteLength-t)-(m.buffer.byteLength-t)%4)/4);\n }\n u32bufp=0;if (metaflags&1){\n lsp = m.getUint32(d+1*4,true);\n }\n if ((metaflags>>>2)&1) {\n sl = m.getUint32(d+2*4,true);\n if ((metaflags>>>1)&1) {\n sp = lsp;\n s = \"\";\n e = sp + ((sl / 4) | 0) * 4;\n while (sp < e) {\n t = m.getUint32(sp, true);\n s += String.fromCharCode(\n t & 255,\n (t & 65280) >> 8,\n (t & 16711680) >> 16,\n t >> 24\n );\n sp += 4;\n }\n while (sp < lsp + sl) {\n s += String.fromCharCode(m.getUint8(sp++));\n }\n } else {\n s = c.decode(new DataView(m.buffer, lsp, sl));\n }\n }\n sp=0;if ((metaflags>>>4)&1){\n t = m.getUint32(d+4*4,true);\n u16buf=new Uint16Array(m.buffer,t,((m.buffer.byteLength-t)-(m.buffer.byteLength-t)%2)/2);\n }\n u16bufp=0;\n for(;;){\n op=m.getUint32(p,true);\n p+=4;\n z=0;\n while(z++<4){\n switch(op&255){\n case 0:{AppendChildren(root, stack.length-1);}break;case 1:{stack.push(nodes[u32buf[u32bufp++]]);}break;case 2:{AppendChildren(u32buf[u32bufp++], u16buf[u16bufp++]);}break;case 3:{stack.pop();}break;case 4:{root = nodes[u32buf[u32bufp++]]; els = stack.splice(stack.length-u16buf[u16bufp++]); if (root.listening) { listeners.removeAllNonBubbling(root); } root.replaceWith(...els);}break;case 5:{nodes[u32buf[u32bufp++]].after(...stack.splice(stack.length-u16buf[u16bufp++]));}break;case 6:{nodes[u32buf[u32bufp++]].before(...stack.splice(stack.length-u16buf[u16bufp++]));}break;case 7:{node = nodes[u32buf[u32bufp++]]; if (node !== undefined) { if (node.listening) { listeners.removeAllNonBubbling(node); } node.remove(); }}break;case 8:{stack.push(document.createTextNode(s.substring(sp,sp+=u32buf[u32bufp++])));}break;case 9:{node = document.createTextNode(s.substring(sp,sp+=u32buf[u32bufp++])); nodes[u32buf[u32bufp++]] = node; stack.push(node);}break;case 10:{node = document.createElement('pre'); node.hidden = true; stack.push(node); nodes[u32buf[u32bufp++]] = node;}break;case 11:event_name=get_evt();id=u32buf[u32bufp++];bubbles=u8buf[u8bufp++];node = nodes[id]; if(node.listening){node.listening += 1;}else{node.listening = 1;} node.setAttribute('data-dioxus-id', `${id}`); listeners.create(event_name, node, bubbles);break;case 12:{node = nodes[u32buf[u32bufp++]]; node.listening -= 1; node.removeAttribute('data-dioxus-id'); listeners.remove(node, get_evt(), u8buf[u8bufp++]);}break;case 13:{nodes[u32buf[u32bufp++]].textContent = s.substring(sp,sp+=u32buf[u32bufp++]);}break;case 14:{node = nodes[u32buf[u32bufp++]]; setAttributeInner(node, get_attr(), s.substring(sp,sp+=u32buf[u32bufp++]), get_ns_cache());}break;case 15:id=u32buf[u32bufp++];field=get_attr();ns=get_ns_cache();{\n node = nodes[id];\n if (!ns) {\n switch (field) {\n case \"value\":\n node.value = \"\";\n break;\n case \"checked\":\n node.checked = false;\n break;\n case \"selected\":\n node.selected = false;\n break;\n case \"dangerous_inner_html\":\n node.innerHTML = \"\";\n break;\n default:\n node.removeAttribute(field);\n break;\n }\n } else if (ns == \"style\") {\n node.style.removeProperty(name);\n } else {\n node.removeAttributeNS(ns, field);\n }\n }break;case 16:{nodes[u32buf[u32bufp++]] = LoadChild(u32buf[u32bufp++], u8buf[u8bufp++]);}break;case 17:ptr=u32buf[u32bufp++];len=u8buf[u8bufp++];value=s.substring(sp,sp+=u32buf[u32bufp++]);id=u32buf[u32bufp++];{\n node = LoadChild(ptr, len);\n if (node.nodeType == Node.TEXT_NODE) {\n node.textContent = value;\n } else {\n let text = document.createTextNode(value);\n node.replaceWith(text);\n node = text;\n }\n nodes[id] = node;\n }break;case 18:{els = stack.splice(stack.length - u16buf[u16bufp++]); node = LoadChild(u32buf[u32bufp++], u8buf[u8bufp++]); node.replaceWith(...els);}break;case 19:{node = templates[u16buf[u16bufp++]][u16buf[u16bufp++]].cloneNode(true); nodes[u32buf[u32bufp++]] = node; stack.push(node);}break;case 20:many=u16buf[u16bufp++];{\n root = stack[stack.length-many-1];\n els = stack.splice(stack.length-many);\n for (k = 0; k < many; k++) {\n root.appendChild(els[k]);\n }\n }break;case 21:{setAttributeInner(stack[stack.length-1], get_attr(), s.substring(sp,sp+=u32buf[u32bufp++]), get_ns_cache());}break;case 22:{node = document.createElement('pre'); node.hidden = true; stack.push(node);}break;case 23:{stack.push(document.createElementNS(get_namespace(), get_el()))}break;case 24:{stack.push(document.createElement(get_el()))}break;case 25:{templates[u16buf[u16bufp++]] = stack.splice(stack.length-u16buf[u16bufp++]);}break;case 26:event=get_evt();id=u32buf[u32bufp++];bubbles=u8buf[u8bufp++];\n bubbles = bubbles == 1;\n node = nodes[id];\n if(node.listening){\n node.listening += 1;\n } else {\n node.listening = 1;\n }\n node.setAttribute('data-dioxus-id', `${id}`);\n const event_name = event;\n\n // if this is a mounted listener, we send the event immediately\n if (event_name === \"mounted\") {\n window.ipc.postMessage(\n window.interpreter.serializeIpcMessage(\"user_event\", {\n name: event_name,\n element: id,\n data: null,\n bubbles,\n })\n );\n } else {\n listeners.create(event_name, node, bubbles, (event) => {\n handler(event, event_name, bubbles, config);\n });\n }break;case 27:{nodes[u32buf[u32bufp++]] = LoadChild((()=>{e=u8bufp+u32buf[u32bufp++];const final_array = u8buf.slice(u8bufp,e);u8bufp=e;return final_array;})());}break;case 28:array=(()=>{e=u8bufp+u32buf[u32bufp++];const final_array = u8buf.slice(u8bufp,e);u8bufp=e;return final_array;})();value=s.substring(sp,sp+=u32buf[u32bufp++]);id=u32buf[u32bufp++];{\n node = LoadChild(array);\n if (node.nodeType == Node.TEXT_NODE) {\n node.textContent = value;\n } else {\n let text = document.createTextNode(value);\n node.replaceWith(text);\n node = text;\n }\n nodes[id] = node;\n }break;case 29:{els = stack.splice(stack.length - u16buf[u16bufp++]); node = LoadChild((()=>{e=u8bufp+u32buf[u32bufp++];const final_array = u8buf.slice(u8bufp,e);u8bufp=e;return final_array;})()); node.replaceWith(...els);}break;case 30:return true;\n }\n op>>>=8;\n }\n }\n }\n export function run_from_bytes(bytes){\n d = 0;\n update_memory(new Uint8Array(bytes))\n run()\n }" diff --git a/packages/interpreter/build.rs b/packages/interpreter/build.rs index a211c37c2..8066cec89 100644 --- a/packages/interpreter/build.rs +++ b/packages/interpreter/build.rs @@ -6,11 +6,41 @@ use std::{ fn main() { // If any TS changes, re-run the build script - println!("cargo:rerun-if-changed=src/*.ts"); + println!("cargo:rerun-if-changed=src/ts/*.ts"); - // for entry in ["common", "form", "interpreter"].iter() { - // gen_bindings(entry); - // } + // Compute the hash of the ts files + let hash = hash_dir("src/ts"); + + // If the hash matches the one on disk, we're good and don't need to update bindings + if let Ok(contents) = read_to_string("src/js/hash.txt") { + if contents.trim() == hash.to_string() { + return; + } + } + + // Otherwise, generate the bindings and write the new hash to disk + // Generate the bindings for both native and web + gen_bindings("native"); + gen_bindings("web"); + + std::fs::write("src/js/hash.txt", hash.to_string()).unwrap(); +} + +/// Hashes the contents of a directory +fn hash_dir(dir: &str) -> u64 { + let mut hasher = DefaultHasher::new(); + + for entry in std::fs::read_dir(dir).unwrap() { + let entry = entry.unwrap(); + let path = entry.path(); + let metadata = std::fs::metadata(&path).unwrap(); + if metadata.is_file() { + let contents = std::fs::read(&path).unwrap(); + contents.hash(&mut hasher); + } + } + + hasher.finish() } // okay...... so tsc might fail if the user doesn't have it installed @@ -21,27 +51,10 @@ fn main() { // if the hashes don't match, we need to fail the build // that way we also don't need fn gen_bindings(name: &str) { - let contents = read_to_string(&format!("src/{name}.ts")).unwrap(); - let generated = read_to_string(&format!("src/gen/{name}.js")).unwrap_or_default(); - let hashed = hash_it(&contents); - - // If the file is generated, and the hash is the same, we're good, don't do anything - if generated - .lines() - .next() - .unwrap_or_default() - .starts_with(&format!("// DO NOT EDIT THIS FILE. HASH: {}", hashed)) - { - return; - } - // If the file is generated, and the hash is different, we need to generate it let status = Command::new("tsc") - .arg(format!("src/{name}.ts")) - .arg("--outDir") - .arg("gen") - .arg("--target") - .arg("es6") + .arg("--p") + .arg(format!("tsconfig.{name}.json")) .status() .unwrap(); @@ -51,15 +64,4 @@ fn gen_bindings(name: &str) { name ); } - - // The file should exist, and now we need write the TS hash to the file - let generated = read_to_string(&format!("gen/{name}.js")).unwrap(); - let generated = format!("// DO NOT EDIT THIS FILE. HASH: {}\n{}", hashed, generated); - std::fs::write(&format!("src/gen/{name}.js"), generated).unwrap(); -} - -fn hash_it(obj: impl Hash) -> u64 { - let mut hasher = DefaultHasher::new(); - obj.hash(&mut hasher); - hasher.finish() } diff --git a/packages/interpreter/gen/README.md b/packages/interpreter/gen/README.md deleted file mode 100644 index e6d41cee9..000000000 --- a/packages/interpreter/gen/README.md +++ /dev/null @@ -1,3 +0,0 @@ -temporary generated code directory since tsc doesn't have a crossplatform way of generating typescript to stdout - -https://github.com/microsoft/TypeScript/issues/1226#issuecomment-523544134 diff --git a/packages/interpreter/src/js/hash.txt b/packages/interpreter/src/js/hash.txt new file mode 100644 index 000000000..e3bf98bdd --- /dev/null +++ b/packages/interpreter/src/js/hash.txt @@ -0,0 +1 @@ +16803007677292896021 \ No newline at end of file diff --git a/packages/interpreter/src/js/native.js b/packages/interpreter/src/js/native.js new file mode 100644 index 000000000..0c59cc667 --- /dev/null +++ b/packages/interpreter/src/js/native.js @@ -0,0 +1,681 @@ +var __extends = (this && this.__extends) || (function () { + var extendStatics = function (d, b) { + extendStatics = Object.setPrototypeOf || + ({ __proto__: [] } instanceof Array && function (d, b) { d.__proto__ = b; }) || + function (d, b) { for (var p in b) if (Object.prototype.hasOwnProperty.call(b, p)) d[p] = b[p]; }; + return extendStatics(d, b); + }; + return function (d, b) { + if (typeof b !== "function" && b !== null) + throw new TypeError("Class extends value " + String(b) + " is not a constructor or null"); + extendStatics(d, b); + function __() { this.constructor = d; } + d.prototype = b === null ? Object.create(b) : (__.prototype = b.prototype, new __()); + }; +})(); +var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) { + function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); } + return new (P || (P = Promise))(function (resolve, reject) { + function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } } + function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } } + function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); } + step((generator = generator.apply(thisArg, _arguments || [])).next()); + }); +}; +var __generator = (this && this.__generator) || function (thisArg, body) { + var _ = { label: 0, sent: function() { if (t[0] & 1) throw t[1]; return t[1]; }, trys: [], ops: [] }, f, y, t, g; + return g = { next: verb(0), "throw": verb(1), "return": verb(2) }, typeof Symbol === "function" && (g[Symbol.iterator] = function() { return this; }), g; + function verb(n) { return function (v) { return step([n, v]); }; } + function step(op) { + if (f) throw new TypeError("Generator is already executing."); + while (g && (g = 0, op[0] && (_ = 0)), _) try { + if (f = 1, y && (t = op[0] & 2 ? y["return"] : op[0] ? y["throw"] || ((t = y["return"]) && t.call(y), 0) : y.next) && !(t = t.call(y, op[1])).done) return t; + if (y = 0, t) op = [op[0] & 2, t.value]; + switch (op[0]) { + case 0: case 1: t = op; break; + case 4: _.label++; return { value: op[1], done: false }; + case 5: _.label++; y = op[1]; op = [0]; continue; + case 7: op = _.ops.pop(); _.trys.pop(); continue; + default: + if (!(t = _.trys, t = t.length > 0 && t[t.length - 1]) && (op[0] === 6 || op[0] === 2)) { _ = 0; continue; } + if (op[0] === 3 && (!t || (op[1] > t[0] && op[1] < t[3]))) { _.label = op[1]; break; } + if (op[0] === 6 && _.label < t[1]) { _.label = t[1]; t = op; break; } + if (t && _.label < t[2]) { _.label = t[2]; _.ops.push(op); break; } + if (t[2]) _.ops.pop(); + _.trys.pop(); continue; + } + op = body.call(thisArg, _); + } catch (e) { op = [6, e]; y = 0; } finally { f = t = 0; } + if (op[0] & 5) throw op[1]; return { value: op[0] ? op[1] : void 0, done: true }; + } +}; +System.register("form", [], function (exports_1, context_1) { + "use strict"; + var __moduleName = context_1 && context_1.id; + function retriveValues(event, target) { + var contents = {}; + if (target instanceof HTMLFormElement && (event.type === "submit" || event.type === "input")) { + retrieveFormValues(target, contents); + } + if (target instanceof HTMLSelectElement && (event.type === "input" || event.type === "change")) { + retriveInputsValues(target, contents); + } + return contents; + } + exports_1("retriveValues", retriveValues); + function retrieveFormValues(form, contents) { + var formData = new FormData(form); + for (var name_1 in formData.keys()) { + var element = form.elements.namedItem(name_1); + if (!(element instanceof HTMLInputElement)) { + continue; + } + switch (element.type) { + case "select-multiple": + contents[name_1] = formData.getAll(name_1); + break; + default: + contents[name_1] = [formData.get(name_1)]; + break; + } + } + } + exports_1("retrieveFormValues", retrieveFormValues); + function retriveInputsValues(target, contents) { + var selectData = target.options; + contents["options"] = []; + for (var i = 0; i < selectData.length; i++) { + var option = selectData[i]; + if (option.selected) { + contents["options"].push(option.value.toString()); + } + } + } + exports_1("retriveInputsValues", retriveInputsValues); + return { + setters: [], + execute: function () { + } + }; +}); +System.register("interpreter_core", [], function (exports_2, context_2) { + "use strict"; + var Interpreter; + var __moduleName = context_2 && context_2.id; + return { + setters: [], + execute: function () { + Interpreter = (function () { + function Interpreter(root, handler) { + this.root = root; + this.nodes = [root]; + this.stack = [root]; + this.global = {}; + this.local = {}; + this.handler = handler; + } + Interpreter.prototype.createListener = function (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 { + var id = element.getAttribute("data-dioxus-id"); + if (!this.local[id]) { + this.local[id] = {}; + } + element.addEventListener(event_name, this.handler); + } + }; + Interpreter.prototype.removeListener = function (element, event_name, bubbles) { + if (bubbles) { + this.removeBubblingListener(event_name); + } + else { + this.removeNonBubblingListener(element, event_name); + } + }; + Interpreter.prototype.removeBubblingListener = function (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]; + } + }; + Interpreter.prototype.removeNonBubblingListener = function (element, event_name) { + var 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); + }; + Interpreter.prototype.removeAllNonBubblingListeners = function (element) { + var id = element.getAttribute("data-dioxus-id"); + delete this.local[id]; + }; + return Interpreter; + }()); + exports_2("Interpreter", Interpreter); + } + }; +}); +System.register("serialize", [], function (exports_3, context_3) { + "use strict"; + var __moduleName = context_3 && context_3.id; + function serializeEvent(event) { + if (event instanceof KeyboardEvent) { + return { + char_code: event.charCode, + is_composing: event.isComposing, + key: event.key, + alt_key: event.altKey, + ctrl_key: event.ctrlKey, + meta_key: event.metaKey, + key_code: event.keyCode, + shift_key: event.shiftKey, + location: event.location, + repeat: event.repeat, + which: event.which, + code: event.code, + }; + } + if (event instanceof PointerEvent) { + 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, + }; + } + if (event instanceof MouseEvent) { + 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, + offset_x: event.offsetX, + offset_y: event.offsetY, + page_x: event.pageX, + page_y: event.pageY, + screen_x: event.screenX, + screen_y: event.screenY, + shift_key: event.shiftKey, + }; + } + if (event instanceof TouchEvent) { + 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, + }; + } + if (event instanceof WheelEvent) { + return { + delta_x: event.deltaX, + delta_y: event.deltaY, + delta_z: event.deltaZ, + delta_mode: event.deltaMode, + }; + } + if (event instanceof AnimationEvent) { + return { + animation_name: event.animationName, + elapsed_time: event.elapsedTime, + pseudo_element: event.pseudoElement, + }; + } + if (event instanceof TransitionEvent) { + return { + property_name: event.propertyName, + elapsed_time: event.elapsedTime, + pseudo_element: event.pseudoElement, + }; + } + if (event instanceof ClipboardEvent) { + return {}; + } + if (event instanceof CompositionEvent) { + return { + data: event.data, + }; + } + if (event instanceof DragEvent) { + return { + mouse: { + alt_key: event.altKey, + ctrl_key: event.ctrlKey, + meta_key: event.metaKey, + shift_key: event.shiftKey, + }, + files: [], + }; + } + if (event instanceof FocusEvent) { + return {}; + } + return {}; + } + exports_3("serializeEvent", serializeEvent); + function isElementNode(node) { + return node.nodeType == 1; + } + function eventBubbles(eventName) { + switch (eventName) { + case "copy": + return true; + case "cut": + return true; + case "paste": + return true; + case "compositionend": + return true; + case "compositionstart": + return true; + case "compositionupdate": + return true; + case "keydown": + return true; + case "keypress": + return true; + case "keyup": + return true; + case "focus": + return false; + case "focusout": + return true; + case "focusin": + return true; + case "blur": + return false; + case "change": + return true; + case "input": + return true; + case "invalid": + return true; + case "reset": + return true; + case "submit": + return true; + case "click": + return true; + case "contextmenu": + return true; + case "doubleclick": + return true; + case "dblclick": + return true; + case "drag": + return true; + case "dragend": + return true; + case "dragenter": + return false; + case "dragexit": + return false; + case "dragleave": + return true; + case "dragover": + return true; + case "dragstart": + return true; + case "drop": + return true; + case "mousedown": + return true; + case "mouseenter": + return false; + case "mouseleave": + return false; + case "mousemove": + return true; + case "mouseout": + return true; + case "scroll": + return false; + case "mouseover": + return true; + case "mouseup": + return true; + case "pointerdown": + return true; + case "pointermove": + return true; + case "pointerup": + return true; + case "pointercancel": + return true; + case "gotpointercapture": + return true; + case "lostpointercapture": + return true; + case "pointerenter": + return false; + case "pointerleave": + return false; + case "pointerover": + return true; + case "pointerout": + return true; + case "select": + return true; + case "touchcancel": + return true; + case "touchend": + return true; + case "touchmove": + return true; + case "touchstart": + return true; + case "wheel": + return true; + case "abort": + return false; + case "canplay": + return false; + case "canplaythrough": + return false; + case "durationchange": + return false; + case "emptied": + return false; + case "encrypted": + return true; + case "ended": + return false; + case "error": + return false; + case "loadeddata": + case "loadedmetadata": + case "loadstart": + case "load": + return false; + case "pause": + return false; + case "play": + return false; + case "playing": + return false; + case "progress": + return false; + case "ratechange": + return false; + case "seeked": + return false; + case "seeking": + return false; + case "stalled": + return false; + case "suspend": + return false; + case "timeupdate": + return false; + case "volumechange": + return false; + case "waiting": + return false; + case "animationstart": + return true; + case "animationend": + return true; + case "animationiteration": + return true; + case "transitionend": + return true; + case "toggle": + return true; + case "mounted": + return false; + } + return true; + } + return { + setters: [], + execute: function () { + } + }; +}); +System.register("interpreter_native", ["form", "interpreter_core", "serialize"], function (exports_4, context_4) { + "use strict"; + var form_1, interpreter_core_1, serialize_1, NativeInterpreter; + var __moduleName = context_4 && context_4.id; + function handleVirtualdomEventSync(contents) { + var xhr = new XMLHttpRequest(); + xhr.timeout = 1000; + xhr.open("GET", "/handle/event.please", false); + xhr.setRequestHeader("Content-Type", "application/json"); + xhr.send(contents); + return JSON.parse(xhr.responseText); + } + function targetId(target) { + if (!(target instanceof Node)) { + return null; + } + var ourTarget = target; + var realId = null; + while (realId == null) { + if (ourTarget === null) { + return null; + } + if (ourTarget instanceof Element) { + realId = ourTarget.getAttribute("data-dioxus-id"); + } + ourTarget = ourTarget.parentNode; + } + return parseInt(realId); + } + return { + setters: [ + function (form_1_1) { + form_1 = form_1_1; + }, + function (interpreter_core_1_1) { + interpreter_core_1 = interpreter_core_1_1; + }, + function (serialize_1_1) { + serialize_1 = serialize_1_1; + } + ], + execute: function () { + NativeInterpreter = (function (_super) { + __extends(NativeInterpreter, _super); + function NativeInterpreter(root) { + var _this = _super.call(this, root, function (event) { return _this.handleEvent(event, event.type, true); }) || this; + _this.intercept_link_redirects = true; + _this.liveview = false; + _this.ipc = window.ipc; + return _this; + } + NativeInterpreter.prototype.serializeIpcMessage = function (method, params) { + if (params === void 0) { params = {}; } + return JSON.stringify({ method: method, params: params }); + }; + NativeInterpreter.prototype.scrollTo = function (id, behavior) { + var node = this.nodes[id]; + if (node instanceof HTMLElement) { + node.scrollIntoView({ behavior: behavior }); + } + }; + NativeInterpreter.prototype.getClientRect = function (id) { + var node = this.nodes[id]; + if (node instanceof HTMLElement) { + var rect = node.getBoundingClientRect(); + return { + type: "GetClientRect", + origin: [rect.x, rect.y], + size: [rect.width, rect.height], + }; + } + }; + NativeInterpreter.prototype.setFocus = function (id, focus) { + var node = this.nodes[id]; + if (node instanceof HTMLElement) { + if (focus) { + node.focus(); + } + else { + node.blur(); + } + } + }; + NativeInterpreter.prototype.LoadChild = function (array) { + var node = this.stack[this.stack.length - 1]; + for (var i = 0; i < array.length; i++) { + var end = array[i]; + for (node = node.firstChild; end > 0; end--) { + node = node.nextSibling; + } + } + return node; + }; + NativeInterpreter.prototype.AppendChildren = function (id, many) { + var root = this.nodes[id]; + var els = this.stack.splice(this.stack.length - many); + for (var k = 0; k < many; k++) { + root.appendChild(els[k]); + } + }; + NativeInterpreter.prototype.handleEvent = function (event, name, bubbles) { + var target = event.target; + var realId = targetId(target); + var contents = serialize_1.serializeEvent(event); + if (target instanceof HTMLElement) { + contents.values = form_1.retriveValues(event, target); + } + var body = { + name: name, + data: contents, + element: realId, + bubbles: bubbles, + }; + this.preventDefaults(event, target); + if (this.liveview) { + if (target instanceof HTMLInputElement && (event.type === "change" || event.type === "input")) { + if (target.getAttribute("type") === "file") { + this.readFiles(target, contents, bubbles, realId, name); + } + } + } + else { + var res = handleVirtualdomEventSync(JSON.stringify(body)); + if (res.preventDefault) { + event.preventDefault(); + } + if (res.stopPropagation) { + event.stopPropagation(); + } + } + }; + NativeInterpreter.prototype.readFiles = function (target, contents, bubbles, realId, name) { + return __awaiter(this, void 0, void 0, function () { + var files, file_contents, i, file, _a, _b, _c, _d, _e, message; + return __generator(this, function (_f) { + switch (_f.label) { + case 0: + files = target.files; + file_contents = {}; + i = 0; + _f.label = 1; + case 1: + if (!(i < files.length)) return [3, 4]; + file = files[i]; + _a = file_contents; + _b = file.name; + _d = (_c = Array).from; + _e = Uint8Array.bind; + return [4, file.arrayBuffer()]; + case 2: + _a[_b] = _d.apply(_c, [new (_e.apply(Uint8Array, [void 0, _f.sent()]))()]); + _f.label = 3; + case 3: + i++; + return [3, 1]; + case 4: + contents.files = { files: file_contents }; + message = this.serializeIpcMessage("user_event", { + name: name, + element: realId, + data: contents, + bubbles: bubbles, + }); + this.ipc.postMessage(message); + return [2]; + } + }); + }); + }; + NativeInterpreter.prototype.preventDefaults = function (event, target) { + var preventDefaultRequests = null; + if (target instanceof Element) { + preventDefaultRequests = target.getAttribute("dioxus-prevent-default"); + } + if (preventDefaultRequests && preventDefaultRequests.includes("on".concat(event.type))) { + event.preventDefault(); + } + if (event.type === "submit") { + event.preventDefault(); + } + if (target instanceof Element && event.type === "click") { + this.handleClickNavigate(event, target, preventDefaultRequests); + } + }; + NativeInterpreter.prototype.handleClickNavigate = function (event, target, preventDefaultRequests) { + if (!this.intercept_link_redirects) { + return; + } + if (target.tagName === "BUTTON" && event.type == "submit") { + event.preventDefault(); + } + var a_element = target.closest("a"); + if (a_element == null) { + return; + } + event.preventDefault(); + var elementShouldPreventDefault = preventDefaultRequests && preventDefaultRequests.includes("onclick"); + var aElementShouldPreventDefault = a_element.getAttribute("dioxus-prevent-default"); + var linkShouldPreventDefault = aElementShouldPreventDefault && + aElementShouldPreventDefault.includes("onclick"); + if (!elementShouldPreventDefault && !linkShouldPreventDefault) { + var href = a_element.getAttribute("href"); + if (href !== "" && href !== null && href !== undefined) { + this.ipc.postMessage(this.serializeIpcMessage("browser_open", { href: href })); + } + } + }; + return NativeInterpreter; + }(interpreter_core_1.Interpreter)); + exports_4("NativeInterpreter", NativeInterpreter); + } + }; +}); diff --git a/packages/interpreter/src/js/web.js b/packages/interpreter/src/js/web.js new file mode 100644 index 000000000..bb4a724d4 --- /dev/null +++ b/packages/interpreter/src/js/web.js @@ -0,0 +1,159 @@ +var __extends = (this && this.__extends) || (function () { + var extendStatics = function (d, b) { + extendStatics = Object.setPrototypeOf || + ({ __proto__: [] } instanceof Array && function (d, b) { d.__proto__ = b; }) || + function (d, b) { for (var p in b) if (Object.prototype.hasOwnProperty.call(b, p)) d[p] = b[p]; }; + return extendStatics(d, b); + }; + return function (d, b) { + if (typeof b !== "function" && b !== null) + throw new TypeError("Class extends value " + String(b) + " is not a constructor or null"); + extendStatics(d, b); + function __() { this.constructor = d; } + d.prototype = b === null ? Object.create(b) : (__.prototype = b.prototype, new __()); + }; +})(); +System.register("interpreter_core", [], function (exports_1, context_1) { + "use strict"; + var Interpreter; + var __moduleName = context_1 && context_1.id; + return { + setters: [], + execute: function () { + Interpreter = (function () { + function Interpreter(root, handler) { + this.root = root; + this.nodes = [root]; + this.stack = [root]; + this.global = {}; + this.local = {}; + this.handler = handler; + } + Interpreter.prototype.createListener = function (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 { + var id = element.getAttribute("data-dioxus-id"); + if (!this.local[id]) { + this.local[id] = {}; + } + element.addEventListener(event_name, this.handler); + } + }; + Interpreter.prototype.removeListener = function (element, event_name, bubbles) { + if (bubbles) { + this.removeBubblingListener(event_name); + } + else { + this.removeNonBubblingListener(element, event_name); + } + }; + Interpreter.prototype.removeBubblingListener = function (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]; + } + }; + Interpreter.prototype.removeNonBubblingListener = function (element, event_name) { + var 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); + }; + Interpreter.prototype.removeAllNonBubblingListeners = function (element) { + var id = element.getAttribute("data-dioxus-id"); + delete this.local[id]; + }; + return Interpreter; + }()); + exports_1("Interpreter", Interpreter); + } + }; +}); +System.register("interpreter_web", ["interpreter_core"], function (exports_2, context_2) { + "use strict"; + var interpreter_core_1, WebInterpreter; + var __moduleName = context_2 && context_2.id; + return { + setters: [ + function (interpreter_core_1_1) { + interpreter_core_1 = interpreter_core_1_1; + } + ], + execute: function () { + WebInterpreter = (function (_super) { + __extends(WebInterpreter, _super); + function WebInterpreter(root, handler) { + return _super.call(this, root, handler) || this; + } + WebInterpreter.prototype.LoadChild = function (ptr, len) { + var node = this.stack[this.stack.length - 1]; + var ptr_end = ptr + len; + for (; ptr < ptr_end; ptr++) { + var end = this.m.getUint8(ptr); + for (node = node.firstChild; end > 0; end--) { + node = node.nextSibling; + } + } + return node; + }; + WebInterpreter.prototype.saveTemplate = function (nodes, tmpl_id) { + this.templates[tmpl_id] = nodes; + }; + WebInterpreter.prototype.hydrateRoot = function (ids) { + var hydrateNodes = document.querySelectorAll('[data-node-hydration]'); + for (var i = 0; i < hydrateNodes.length; i++) { + var hydrateNode = hydrateNodes[i]; + var hydration = hydrateNode.getAttribute('data-node-hydration'); + var split = hydration.split(','); + var 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 (var j = 1; j < split.length; j++) { + var listener = split[j]; + var split2 = listener.split(':'); + var event_name = split2[0]; + var bubbles = split2[1] === '1'; + this.createListener(event_name, hydrateNode, bubbles); + } + } + } + var treeWalker = document.createTreeWalker(document.body, NodeFilter.SHOW_COMMENT); + var currentNode = treeWalker.nextNode(); + while (currentNode) { + var id = currentNode.textContent; + var split = id.split('node-id'); + if (split.length > 1) { + this.nodes[ids[parseInt(split[1])]] = currentNode.nextSibling; + } + currentNode = treeWalker.nextNode(); + } + }; + WebInterpreter.prototype.getNode = function (id) { + return this.nodes[id]; + }; + WebInterpreter.prototype.appendChildren = function (id, many) { + var root = this.nodes[id]; + var els = this.stack.splice(this.stack.length - many); + for (var k = 0; k < many; k++) { + root.appendChild(els[k]); + } + }; + return WebInterpreter; + }(interpreter_core_1.Interpreter)); + exports_2("WebInterpreter", WebInterpreter); + } + }; +}); diff --git a/packages/interpreter/src/lib.rs b/packages/interpreter/src/lib.rs index 685e51af3..b50f2dfeb 100644 --- a/packages/interpreter/src/lib.rs +++ b/packages/interpreter/src/lib.rs @@ -2,8 +2,8 @@ #![doc(html_logo_url = "https://avatars.githubusercontent.com/u/79236386")] #![doc(html_favicon_url = "https://avatars.githubusercontent.com/u/79236386")] -pub static INTERPRETER_JS: &str = include_str!("./gen/interpreter.js"); -pub static COMMON_JS: &str = include_str!("./gen/common.js"); +pub static INTERPRETER_JS: &str = include_str!("./js/native.js"); +pub static COMMON_JS: &str = include_str!("./js/web.js"); #[cfg(all(feature = "binary-protocol", feature = "sledgehammer"))] mod write_native_mutations; diff --git a/packages/interpreter/src/ts/.gitignore b/packages/interpreter/src/ts/.gitignore new file mode 100644 index 000000000..68b79b0d3 --- /dev/null +++ b/packages/interpreter/src/ts/.gitignore @@ -0,0 +1,3 @@ +# please dont accidentally run tsc and commit your js in this dir. +*.js + diff --git a/packages/interpreter/src/ts/interpreter_core.ts b/packages/interpreter/src/ts/interpreter_core.ts index 557dab3e5..57ec4c5b8 100644 --- a/packages/interpreter/src/ts/interpreter_core.ts +++ b/packages/interpreter/src/ts/interpreter_core.ts @@ -12,6 +12,7 @@ export class Interpreter { [key: string]: EventListener } }; + root: HTMLElement; handler: EventListener; nodes: Node[]; diff --git a/packages/interpreter/tsconfig.json b/packages/interpreter/tsconfig.json index 0f5c66032..fe0cdc8ab 100644 --- a/packages/interpreter/tsconfig.json +++ b/packages/interpreter/tsconfig.json @@ -11,12 +11,7 @@ "noImplicitAny": true, "removeComments": true, "preserveConstEnums": true, - "outFile": "gen/main.js", - "sourceMap": true }, - "include": [ - "src/ts/*.ts" - ], "exclude": [ "**/*.spec.ts" ] diff --git a/packages/interpreter/tsconfig.native.json b/packages/interpreter/tsconfig.native.json new file mode 100644 index 000000000..57feec085 --- /dev/null +++ b/packages/interpreter/tsconfig.native.json @@ -0,0 +1,10 @@ +{ + // extends the base + "extends": "./tsconfig.json", + "compilerOptions": { + "outFile": "src/js/native.js" + }, + "files": [ + "src/ts/interpreter_native.ts" + ], +} diff --git a/packages/interpreter/tsconfig.web.json b/packages/interpreter/tsconfig.web.json new file mode 100644 index 000000000..ac1961b32 --- /dev/null +++ b/packages/interpreter/tsconfig.web.json @@ -0,0 +1,10 @@ +{ + // extends the base + "extends": "./tsconfig.json", + "compilerOptions": { + "outFile": "src/js/web.js" + }, + "files": [ + "src/ts/interpreter_web.ts" + ], +}