Add proper bundling to tsc
This commit is contained in:
15 files changed
+267
-1065
No files matched your search
@@ -23,7 +23,7 @@ fn main() {
|
||||
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_file(&contents);
|
||||
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
|
||||
@@ -58,7 +58,7 @@ fn gen_bindings(name: &str) {
|
||||
std::fs::write(&format!("src/gen/{name}.js"), generated).unwrap();
|
||||
}
|
||||
|
||||
fn hash_file(obj: &str) -> u64 {
|
||||
fn hash_it(obj: impl Hash) -> u64 {
|
||||
let mut hasher = DefaultHasher::new();
|
||||
obj.hash(&mut hasher);
|
||||
hasher.finish()
|
||||
|
||||
@@ -1,79 +0,0 @@
|
||||
this.setAttributeInner = function (node, field, value, ns) {
|
||||
const name = field;
|
||||
if (ns === "style") {
|
||||
// ????? why do we need to do this
|
||||
if (node.style === undefined) {
|
||||
node.style = {};
|
||||
}
|
||||
node.style[name] = value;
|
||||
} else if (!!ns) {
|
||||
node.setAttributeNS(ns, name, value);
|
||||
} else {
|
||||
switch (name) {
|
||||
case "value":
|
||||
if (value !== node.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:
|
||||
// https://github.com/facebook/react/blob/8b88ac2592c5f555f315f9440cbb665dd1e7457a/packages/react-dom/src/shared/DOMProperty.js#L352-L364
|
||||
if (!truthy(value) && bool_attrs.hasOwnProperty(name)) {
|
||||
node.removeAttribute(name);
|
||||
} else {
|
||||
node.setAttribute(name, value);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
const bool_attrs = {
|
||||
allowfullscreen: true,
|
||||
allowpaymentrequest: true,
|
||||
async: true,
|
||||
autofocus: true,
|
||||
autoplay: true,
|
||||
checked: true,
|
||||
controls: true,
|
||||
default: true,
|
||||
defer: true,
|
||||
disabled: true,
|
||||
formnovalidate: true,
|
||||
hidden: true,
|
||||
ismap: true,
|
||||
itemscope: true,
|
||||
loop: true,
|
||||
multiple: true,
|
||||
muted: true,
|
||||
nomodule: true,
|
||||
novalidate: true,
|
||||
open: true,
|
||||
playsinline: true,
|
||||
readonly: true,
|
||||
required: true,
|
||||
reversed: true,
|
||||
selected: true,
|
||||
truespeed: true,
|
||||
webkitdirectory: true,
|
||||
};
|
||||
|
||||
function truthy(val) {
|
||||
return val === "true" || val === true;
|
||||
}
|
||||
@@ -1,79 +0,0 @@
|
||||
export function setAttributeInner(node, field, value, ns) {
|
||||
const name = field;
|
||||
if (ns === "style") {
|
||||
// ????? why do we need to do this
|
||||
if (node.style === undefined) {
|
||||
node.style = {};
|
||||
}
|
||||
node.style[name] = value;
|
||||
} else if (!!ns) {
|
||||
node.setAttributeNS(ns, name, value);
|
||||
} else {
|
||||
switch (name) {
|
||||
case "value":
|
||||
if (value !== node.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:
|
||||
// https://github.com/facebook/react/blob/8b88ac2592c5f555f315f9440cbb665dd1e7457a/packages/react-dom/src/shared/DOMProperty.js#L352-L364
|
||||
if (!truthy(value) && bool_attrs.hasOwnProperty(name)) {
|
||||
node.removeAttribute(name);
|
||||
} else {
|
||||
node.setAttribute(name, value);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
const bool_attrs = {
|
||||
allowfullscreen: true,
|
||||
allowpaymentrequest: true,
|
||||
async: true,
|
||||
autofocus: true,
|
||||
autoplay: true,
|
||||
checked: true,
|
||||
controls: true,
|
||||
default: true,
|
||||
defer: true,
|
||||
disabled: true,
|
||||
formnovalidate: true,
|
||||
hidden: true,
|
||||
ismap: true,
|
||||
itemscope: true,
|
||||
loop: true,
|
||||
multiple: true,
|
||||
muted: true,
|
||||
nomodule: true,
|
||||
novalidate: true,
|
||||
open: true,
|
||||
playsinline: true,
|
||||
readonly: true,
|
||||
required: true,
|
||||
reversed: true,
|
||||
selected: true,
|
||||
truespeed: true,
|
||||
webkitdirectory: true,
|
||||
};
|
||||
|
||||
function truthy(val) {
|
||||
return val === "true" || val === true;
|
||||
}
|
||||
@@ -1,81 +0,0 @@
|
||||
// DO NOT EDIT THIS FILE. HASH: 9578489549991746027
|
||||
export function setAttributeInner(node, field, value, ns) {
|
||||
const name = field;
|
||||
if (ns === "style") {
|
||||
// ????? why do we need to do this
|
||||
if (node.style === undefined) {
|
||||
node.style = {};
|
||||
}
|
||||
node.style[name] = value;
|
||||
}
|
||||
else if (!!ns) {
|
||||
node.setAttributeNS(ns, name, value);
|
||||
}
|
||||
else {
|
||||
switch (name) {
|
||||
case "value":
|
||||
if (value !== node.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:
|
||||
// https://github.com/facebook/react/blob/8b88ac2592c5f555f315f9440cbb665dd1e7457a/packages/react-dom/src/shared/DOMProperty.js#L352-L364
|
||||
if (!truthy(value) && bool_attrs.hasOwnProperty(name)) {
|
||||
node.removeAttribute(name);
|
||||
}
|
||||
else {
|
||||
node.setAttribute(name, value);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
const bool_attrs = {
|
||||
allowfullscreen: true,
|
||||
allowpaymentrequest: true,
|
||||
async: true,
|
||||
autofocus: true,
|
||||
autoplay: true,
|
||||
checked: true,
|
||||
controls: true,
|
||||
default: true,
|
||||
defer: true,
|
||||
disabled: true,
|
||||
formnovalidate: true,
|
||||
hidden: true,
|
||||
ismap: true,
|
||||
itemscope: true,
|
||||
loop: true,
|
||||
multiple: true,
|
||||
muted: true,
|
||||
nomodule: true,
|
||||
novalidate: true,
|
||||
open: true,
|
||||
playsinline: true,
|
||||
readonly: true,
|
||||
required: true,
|
||||
reversed: true,
|
||||
selected: true,
|
||||
truespeed: true,
|
||||
webkitdirectory: true,
|
||||
};
|
||||
function truthy(val) {
|
||||
return val === "true" || val === true;
|
||||
}
|
||||
@@ -1 +0,0 @@
|
||||
// DO NOT EDIT THIS FILE. HASH: 3476900567878811119
|
||||
Whitespace-only changes.
Whitespace-only changes.
@@ -145,609 +145,3 @@ this.handler = async function (event, name, bubbles) {
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
function find_real_id(target) {
|
||||
let realId = null;
|
||||
if (target instanceof Element) {
|
||||
realId = target.getAttribute(`data-dioxus-id`);
|
||||
}
|
||||
// walk the tree to find the real element
|
||||
while (realId == null) {
|
||||
// we've reached the root we don't want to send an event
|
||||
if (target.parentElement === null) {
|
||||
return;
|
||||
}
|
||||
|
||||
target = target.parentElement;
|
||||
if (target instanceof Element) {
|
||||
realId = target.getAttribute(`data-dioxus-id`);
|
||||
}
|
||||
}
|
||||
return realId;
|
||||
}
|
||||
|
||||
class ListenerMap {
|
||||
constructor(root) {
|
||||
// bubbling events can listen at the root element
|
||||
this.global = {};
|
||||
// non bubbling events listen at the element the listener was created at
|
||||
this.local = {};
|
||||
this.root = null;
|
||||
}
|
||||
|
||||
create(event_name, element, bubbles, handler) {
|
||||
if (bubbles) {
|
||||
if (this.global[event_name] === undefined) {
|
||||
this.global[event_name] = {};
|
||||
this.global[event_name].active = 1;
|
||||
this.root.addEventListener(event_name, 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, handler);
|
||||
}
|
||||
}
|
||||
|
||||
remove(element, event_name, bubbles) {
|
||||
if (bubbles) {
|
||||
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];
|
||||
}
|
||||
}
|
||||
else {
|
||||
const id = element.getAttribute("data-dioxus-id");
|
||||
delete this.local[id][event_name];
|
||||
if (this.local[id].length === 0) {
|
||||
delete this.local[id];
|
||||
}
|
||||
element.removeEventListener(event_name, this.global[event_name].callback);
|
||||
}
|
||||
}
|
||||
|
||||
removeAllNonBubbling(element) {
|
||||
const id = element.getAttribute("data-dioxus-id");
|
||||
delete this.local[id];
|
||||
}
|
||||
}
|
||||
this.LoadChild = function (array) {
|
||||
// iterate through each number and get that child
|
||||
let node = this.stack[this.stack.length - 1];
|
||||
|
||||
for (let i = 0; i < array.length; i++) {
|
||||
this.end = array[i];
|
||||
for (node = node.firstChild; this.end > 0; this.end--) {
|
||||
node = node.nextSibling;
|
||||
}
|
||||
}
|
||||
return node;
|
||||
}
|
||||
this.listeners = new ListenerMap();
|
||||
this.nodes = [];
|
||||
this.stack = [];
|
||||
this.root;
|
||||
this.templates = {};
|
||||
this.els = null;
|
||||
this.end = null;
|
||||
|
||||
this.AppendChildren = function (id, many) {
|
||||
this.root = this.nodes[id];
|
||||
this.els = this.stack.splice(this.stack.length - many);
|
||||
for (let k = 0; k < many; k++) {
|
||||
this.root.appendChild(this.els[k]);
|
||||
}
|
||||
}
|
||||
|
||||
this.initialize = function (root) {
|
||||
this.nodes = [root];
|
||||
this.stack = [root];
|
||||
this.listeners.root = root;
|
||||
}
|
||||
|
||||
this.getClientRect = function (id) {
|
||||
const node = this.nodes[id];
|
||||
if (!node) {
|
||||
return;
|
||||
}
|
||||
const rect = node.getBoundingClientRect();
|
||||
return {
|
||||
type: "GetClientRect",
|
||||
origin: [rect.x, rect.y],
|
||||
size: [rect.width, rect.height],
|
||||
};
|
||||
}
|
||||
|
||||
this.scrollTo = function (id, behavior) {
|
||||
const node = this.nodes[id];
|
||||
if (!node) {
|
||||
return false;
|
||||
}
|
||||
node.scrollIntoView({
|
||||
behavior: behavior,
|
||||
});
|
||||
return true;
|
||||
}
|
||||
|
||||
/// Set the focus on the element
|
||||
this.setFocus = function (id, focus) {
|
||||
const node = this.nodes[id];
|
||||
if (!node) {
|
||||
return false;
|
||||
}
|
||||
if (focus) {
|
||||
node.focus();
|
||||
} else {
|
||||
node.blur();
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
function get_mouse_data(event) {
|
||||
const {
|
||||
altKey,
|
||||
button,
|
||||
buttons,
|
||||
clientX,
|
||||
clientY,
|
||||
ctrlKey,
|
||||
metaKey,
|
||||
offsetX,
|
||||
offsetY,
|
||||
pageX,
|
||||
pageY,
|
||||
screenX,
|
||||
screenY,
|
||||
shiftKey,
|
||||
} = event;
|
||||
return {
|
||||
alt_key: altKey,
|
||||
button: button,
|
||||
buttons: buttons,
|
||||
client_x: clientX,
|
||||
client_y: clientY,
|
||||
ctrl_key: ctrlKey,
|
||||
meta_key: metaKey,
|
||||
offset_x: offsetX,
|
||||
offset_y: offsetY,
|
||||
page_x: pageX,
|
||||
page_y: pageY,
|
||||
screen_x: screenX,
|
||||
screen_y: screenY,
|
||||
shift_key: shiftKey,
|
||||
};
|
||||
}
|
||||
|
||||
async function serialize_event(event) {
|
||||
switch (event.type) {
|
||||
case "copy":
|
||||
case "cut":
|
||||
case "past": {
|
||||
return {};
|
||||
}
|
||||
case "compositionend":
|
||||
case "compositionstart":
|
||||
case "compositionupdate": {
|
||||
let { data } = event;
|
||||
return {
|
||||
data,
|
||||
};
|
||||
}
|
||||
case "keydown":
|
||||
case "keypress":
|
||||
case "keyup": {
|
||||
let {
|
||||
charCode,
|
||||
isComposing,
|
||||
key,
|
||||
altKey,
|
||||
ctrlKey,
|
||||
metaKey,
|
||||
keyCode,
|
||||
shiftKey,
|
||||
location,
|
||||
repeat,
|
||||
which,
|
||||
code,
|
||||
} = event;
|
||||
return {
|
||||
char_code: charCode,
|
||||
is_composing: isComposing,
|
||||
key: key,
|
||||
alt_key: altKey,
|
||||
ctrl_key: ctrlKey,
|
||||
meta_key: metaKey,
|
||||
key_code: keyCode,
|
||||
shift_key: shiftKey,
|
||||
location: location,
|
||||
repeat: repeat,
|
||||
which: which,
|
||||
code,
|
||||
};
|
||||
}
|
||||
case "focus":
|
||||
case "blur": {
|
||||
return {};
|
||||
}
|
||||
case "change": {
|
||||
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,
|
||||
values: {},
|
||||
};
|
||||
}
|
||||
case "input":
|
||||
case "invalid":
|
||||
case "reset":
|
||||
case "submit": {
|
||||
let target = event.target;
|
||||
let value = target.value ?? target.textContent;
|
||||
|
||||
if (target.type === "checkbox") {
|
||||
value = target.checked ? "true" : "false";
|
||||
}
|
||||
|
||||
return {
|
||||
value: value,
|
||||
values: {},
|
||||
};
|
||||
}
|
||||
case "drag":
|
||||
case "dragend":
|
||||
case "dragenter":
|
||||
case "dragexit":
|
||||
case "dragleave":
|
||||
case "dragover":
|
||||
case "dragstart":
|
||||
case "drop": {
|
||||
let files = null;
|
||||
if (event.dataTransfer && event.dataTransfer.files) {
|
||||
files = await serializeFileList(event.dataTransfer.files);
|
||||
}
|
||||
|
||||
return { mouse: get_mouse_data(event), files };
|
||||
}
|
||||
case "click":
|
||||
case "contextmenu":
|
||||
case "doubleclick":
|
||||
case "dblclick":
|
||||
case "mousedown":
|
||||
case "mouseenter":
|
||||
case "mouseleave":
|
||||
case "mousemove":
|
||||
case "mouseout":
|
||||
case "mouseover":
|
||||
case "mouseup": {
|
||||
return get_mouse_data(event);
|
||||
}
|
||||
case "pointerdown":
|
||||
case "pointermove":
|
||||
case "pointerup":
|
||||
case "pointercancel":
|
||||
case "gotpointercapture":
|
||||
case "lostpointercapture":
|
||||
case "pointerenter":
|
||||
case "pointerleave":
|
||||
case "pointerover":
|
||||
case "pointerout": {
|
||||
const {
|
||||
altKey,
|
||||
button,
|
||||
buttons,
|
||||
clientX,
|
||||
clientY,
|
||||
ctrlKey,
|
||||
metaKey,
|
||||
pageX,
|
||||
pageY,
|
||||
screenX,
|
||||
screenY,
|
||||
shiftKey,
|
||||
pointerId,
|
||||
width,
|
||||
height,
|
||||
pressure,
|
||||
tangentialPressure,
|
||||
tiltX,
|
||||
tiltY,
|
||||
twist,
|
||||
pointerType,
|
||||
isPrimary,
|
||||
} = event;
|
||||
return {
|
||||
alt_key: altKey,
|
||||
button: button,
|
||||
buttons: buttons,
|
||||
client_x: clientX,
|
||||
client_y: clientY,
|
||||
ctrl_key: ctrlKey,
|
||||
meta_key: metaKey,
|
||||
page_x: pageX,
|
||||
page_y: pageY,
|
||||
screen_x: screenX,
|
||||
screen_y: screenY,
|
||||
shift_key: shiftKey,
|
||||
pointer_id: pointerId,
|
||||
width: width,
|
||||
height: height,
|
||||
pressure: pressure,
|
||||
tangential_pressure: tangentialPressure,
|
||||
tilt_x: tiltX,
|
||||
tilt_y: tiltY,
|
||||
twist: twist,
|
||||
pointer_type: pointerType,
|
||||
is_primary: isPrimary,
|
||||
};
|
||||
}
|
||||
case "select": {
|
||||
return {};
|
||||
}
|
||||
case "touchcancel":
|
||||
case "touchend":
|
||||
case "touchmove":
|
||||
case "touchstart": {
|
||||
const { altKey, ctrlKey, metaKey, shiftKey } = event;
|
||||
return {
|
||||
// changed_touches: event.changedTouches,
|
||||
// target_touches: event.targetTouches,
|
||||
// touches: event.touches,
|
||||
alt_key: altKey,
|
||||
ctrl_key: ctrlKey,
|
||||
meta_key: metaKey,
|
||||
shift_key: shiftKey,
|
||||
};
|
||||
}
|
||||
case "scroll": {
|
||||
return {};
|
||||
}
|
||||
case "wheel": {
|
||||
const { deltaX, deltaY, deltaZ, deltaMode } = event;
|
||||
return {
|
||||
delta_x: deltaX,
|
||||
delta_y: deltaY,
|
||||
delta_z: deltaZ,
|
||||
delta_mode: deltaMode,
|
||||
};
|
||||
}
|
||||
case "animationstart":
|
||||
case "animationend":
|
||||
case "animationiteration": {
|
||||
const { animationName, elapsedTime, pseudoElement } = event;
|
||||
return {
|
||||
animation_name: animationName,
|
||||
elapsed_time: elapsedTime,
|
||||
pseudo_element: pseudoElement,
|
||||
};
|
||||
}
|
||||
case "transitionend": {
|
||||
const { propertyName, elapsedTime, pseudoElement } = event;
|
||||
return {
|
||||
property_name: propertyName,
|
||||
elapsed_time: elapsedTime,
|
||||
pseudo_element: pseudoElement,
|
||||
};
|
||||
}
|
||||
case "abort":
|
||||
case "canplay":
|
||||
case "canplaythrough":
|
||||
case "durationchange":
|
||||
case "emptied":
|
||||
case "encrypted":
|
||||
case "ended":
|
||||
case "error":
|
||||
case "loadeddata":
|
||||
case "loadedmetadata":
|
||||
case "loadstart":
|
||||
case "pause":
|
||||
case "play":
|
||||
case "playing":
|
||||
case "progress":
|
||||
case "ratechange":
|
||||
case "seeked":
|
||||
case "seeking":
|
||||
case "stalled":
|
||||
case "suspend":
|
||||
case "timeupdate":
|
||||
case "volumechange":
|
||||
case "waiting": {
|
||||
return {};
|
||||
}
|
||||
case "toggle": {
|
||||
return {};
|
||||
}
|
||||
default: {
|
||||
return {};
|
||||
}
|
||||
}
|
||||
}
|
||||
this.serializeIpcMessage = function (method, params = {}) {
|
||||
return JSON.stringify({ method, params });
|
||||
}
|
||||
|
||||
function is_element_node(node) {
|
||||
return node.nodeType == 1;
|
||||
}
|
||||
|
||||
function event_bubbles(event) {
|
||||
switch (event) {
|
||||
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;
|
||||
}
|
||||
@@ -1,3 +1,53 @@
|
||||
function retrieveFormValues() {
|
||||
// Consistently deserialize forms and form elements for use across web/desktop/mobile
|
||||
|
||||
type FormValues = { [key: string]: FormDataEntryValue[] };
|
||||
|
||||
export function retriveValues(event: Event, target: HTMLElement): FormValues {
|
||||
const contents: FormValues = {};
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
export function retrieveFormValues(form: HTMLFormElement, contents: FormValues) {
|
||||
const formData = new FormData(form);
|
||||
|
||||
for (let name in formData.keys()) {
|
||||
let element = form.elements.namedItem(name);
|
||||
|
||||
// todo: this is going to be a problem for select-multiple?
|
||||
if (!(element instanceof HTMLInputElement)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
switch (element.type) {
|
||||
case "select-multiple":
|
||||
contents[name] = formData.getAll(name);
|
||||
break;
|
||||
|
||||
// By default, it's just a single value
|
||||
default:
|
||||
contents[name] = [formData.get(name)];
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
export function retriveInputsValues(target: HTMLSelectElement, contents: FormValues,) {
|
||||
const selectData = target.options;
|
||||
contents["options"] = [];
|
||||
|
||||
for (let i = 0; i < selectData.length; i++) {
|
||||
let option = selectData[i];
|
||||
if (option.selected) {
|
||||
contents["options"].push(option.value.toString());
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,9 +1,6 @@
|
||||
// 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
|
||||
|
||||
// todo: we want to make these vars that the interpreter uses to be isolated so we can have multiple interpreters
|
||||
export let m: DataView; // p, ls, d, t, op, i, e, z, metaflags;
|
||||
|
||||
export class Interpreter {
|
||||
// non bubbling events listen at the element the listener was created at
|
||||
global: {
|
||||
@@ -15,15 +12,15 @@ export class Interpreter {
|
||||
[key: string]: EventListener
|
||||
}
|
||||
};
|
||||
root: Element;
|
||||
root: HTMLElement;
|
||||
handler: EventListener;
|
||||
nodes: Element[];
|
||||
stack: Element[];
|
||||
nodes: Node[];
|
||||
stack: Node[];
|
||||
templates: {
|
||||
[key: string]: Element[]
|
||||
[key: string]: Node[]
|
||||
};
|
||||
|
||||
constructor(root: Element, handler: EventListener) {
|
||||
constructor(root: HTMLElement, handler: EventListener) {
|
||||
this.root = root;
|
||||
this.nodes = [root];
|
||||
this.stack = [root];
|
||||
@@ -32,7 +29,7 @@ export class Interpreter {
|
||||
this.handler = handler;
|
||||
}
|
||||
|
||||
createListener(event_name: string, element: Element, bubbles: boolean) {
|
||||
createListener(event_name: string, element: HTMLElement, bubbles: boolean) {
|
||||
if (bubbles) {
|
||||
if (this.global[event_name] === undefined) {
|
||||
this.global[event_name] = { active: 1, callback: this.handler };
|
||||
@@ -49,7 +46,7 @@ export class Interpreter {
|
||||
}
|
||||
}
|
||||
|
||||
removeListener(element: Element, event_name: string, bubbles: boolean) {
|
||||
removeListener(element: HTMLElement, event_name: string, bubbles: boolean) {
|
||||
if (bubbles) {
|
||||
this.removeBubblingListener(event_name);
|
||||
} else {
|
||||
@@ -65,7 +62,7 @@ export class Interpreter {
|
||||
}
|
||||
}
|
||||
|
||||
removeNonBubblingListener(element: Element, event_name: string) {
|
||||
removeNonBubblingListener(element: HTMLElement, event_name: string) {
|
||||
const id = element.getAttribute("data-dioxus-id");
|
||||
delete this.local[id][event_name];
|
||||
if (Object.keys(this.local[id]).length === 0) {
|
||||
@@ -74,7 +71,7 @@ export class Interpreter {
|
||||
element.removeEventListener(event_name, this.handler);
|
||||
}
|
||||
|
||||
removeAllNonBubblingListeners(element: Element) {
|
||||
removeAllNonBubblingListeners(element: HTMLElement) {
|
||||
const id = element.getAttribute("data-dioxus-id");
|
||||
delete this.local[id];
|
||||
}
|
||||
|
||||
@@ -1,14 +1,27 @@
|
||||
// This file provides an extended variant of the interpreter used for desktop and liveview interaction
|
||||
//
|
||||
//
|
||||
// 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.
|
||||
|
||||
import { retriveValues } from "./form";
|
||||
import { Interpreter } from "./interpreter_core";
|
||||
import { SerializedEvent, serializeEvent } from "./serialize";
|
||||
|
||||
export class NativeInterpreter extends Interpreter {
|
||||
intercept_link_redirects: boolean;
|
||||
ipc: any;
|
||||
|
||||
constructor(root: Element) {
|
||||
super(root, (event) => handler(event, this, event.type, true));
|
||||
// eventually we want to remove liveview and build it into the server-side-events of fullstack
|
||||
// however, for now we need to support it since SSE in fullstack doesn't exist yet
|
||||
liveview: boolean;
|
||||
|
||||
constructor(root: HTMLElement) {
|
||||
super(root, (event) => this.handleEvent(event, event.type, true));
|
||||
this.intercept_link_redirects = true;
|
||||
this.liveview = false;
|
||||
|
||||
// @ts-ignore - wry gives us this
|
||||
this.ipc = window.ipc;
|
||||
}
|
||||
|
||||
serializeIpcMessage(method: string, params = {}) {
|
||||
@@ -17,50 +30,38 @@ export class NativeInterpreter extends Interpreter {
|
||||
|
||||
scrollTo(id: number, behavior: ScrollBehavior) {
|
||||
const node = this.nodes[id];
|
||||
|
||||
if (!(node instanceof HTMLElement)) {
|
||||
return false;
|
||||
if (node instanceof HTMLElement) {
|
||||
node.scrollIntoView({ behavior });
|
||||
}
|
||||
|
||||
node.scrollIntoView({
|
||||
behavior: behavior,
|
||||
});
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
getClientRect(id: number) {
|
||||
const node = this.nodes[id];
|
||||
if (!node) {
|
||||
return;
|
||||
if (node instanceof HTMLElement) {
|
||||
const rect = node.getBoundingClientRect();
|
||||
return {
|
||||
type: "GetClientRect",
|
||||
origin: [rect.x, rect.y],
|
||||
size: [rect.width, rect.height],
|
||||
};
|
||||
}
|
||||
const rect = node.getBoundingClientRect();
|
||||
return {
|
||||
type: "GetClientRect",
|
||||
origin: [rect.x, rect.y],
|
||||
size: [rect.width, rect.height],
|
||||
};
|
||||
}
|
||||
|
||||
setFocus(id: number, focus: boolean) {
|
||||
const node = this.nodes[id];
|
||||
|
||||
if (!(node instanceof HTMLElement)) {
|
||||
return false;
|
||||
if (node instanceof HTMLElement) {
|
||||
if (focus) {
|
||||
node.focus();
|
||||
} else {
|
||||
node.blur();
|
||||
}
|
||||
}
|
||||
|
||||
if (focus) {
|
||||
node.focus();
|
||||
} else {
|
||||
node.blur();
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
LoadChild(array: number[]) {
|
||||
// iterate through each number and get that child
|
||||
let node = this.stack[this.stack.length - 1] as Node;
|
||||
let node = this.stack[this.stack.length - 1];
|
||||
|
||||
for (let i = 0; i < array.length; i++) {
|
||||
let end = array[i];
|
||||
@@ -80,73 +81,162 @@ export class NativeInterpreter extends Interpreter {
|
||||
root.appendChild(els[k]);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
handleEvent(event: Event, name: string, bubbles: boolean) {
|
||||
const target = event.target!;
|
||||
const realId = targetId(target)!;
|
||||
const contents = serializeEvent(event);
|
||||
|
||||
// Attempt to retrive the values from the form and inputs
|
||||
if (target instanceof HTMLElement) {
|
||||
contents.values = retriveValues(event, target);
|
||||
}
|
||||
|
||||
// Handle the event on the virtualdom and then preventDefault if it also preventsDefault
|
||||
// Some listeners
|
||||
let body = {
|
||||
name: name,
|
||||
data: contents,
|
||||
element: realId,
|
||||
bubbles,
|
||||
};
|
||||
|
||||
// Run any prevent defaults the user might've set
|
||||
// This is to support the prevent_default: "onclick" attribute that dioxus has had for a while, but is not necessary
|
||||
// now that we expose preventDefault to the virtualdom on desktop
|
||||
// Liveview will still need to use this
|
||||
this.preventDefaults(event, target);
|
||||
|
||||
|
||||
// liveview does not have syncronous event handling, so we need to send the event to the host
|
||||
if (this.liveview) {
|
||||
// Okay, so the user might've requested some files to be read
|
||||
if (target instanceof HTMLInputElement && (event.type === "change" || event.type === "input")) {
|
||||
if (target.getAttribute("type") === "file") {
|
||||
this.readFiles(target, contents, bubbles, realId, name);
|
||||
}
|
||||
}
|
||||
} else {
|
||||
|
||||
// Run the event handler on the virtualdom
|
||||
// capture/prevent default of the event if the virtualdom wants to
|
||||
const res = handleVirtualdomEventSync(JSON.stringify(body));
|
||||
|
||||
function handler(event: Event, interpreter: NativeInterpreter, name: string, bubbles: boolean) {
|
||||
const target = event.target!;
|
||||
const realId = target_id(target)!;
|
||||
let contents = serializeEvent(event);
|
||||
if (res.preventDefault) {
|
||||
event.preventDefault();
|
||||
}
|
||||
|
||||
if (target instanceof HTMLFormElement && (event.type === "submit" || event.type === "input")) {
|
||||
const formData = new FormData(target);
|
||||
|
||||
for (let name of formData.keys()) {
|
||||
const fieldType = target.elements[name].type;
|
||||
|
||||
switch (fieldType) {
|
||||
case "select-multiple":
|
||||
contents.values[name] = formData.getAll(name);
|
||||
break;
|
||||
|
||||
// add cases for fieldTypes that can hold multiple values here
|
||||
default:
|
||||
contents.values[name] = formData.get(name);
|
||||
break;
|
||||
if (res.stopPropagation) {
|
||||
event.stopPropagation();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (target instanceof HTMLSelectElement && (event.type === "input" || event.type === "change")) {
|
||||
const selectData = target.options;
|
||||
contents.values["options"] = [];
|
||||
for (let i = 0; i < selectData.length; i++) {
|
||||
let option = selectData[i];
|
||||
if (option.selected) {
|
||||
contents.values["options"].push(option.value.toString());
|
||||
}
|
||||
async readFiles(target: HTMLInputElement, contents: SerializedEvent, bubbles: boolean, realId: number, name: string) {
|
||||
let files = target.files!;
|
||||
let file_contents: { [name: string]: number[] } = {};
|
||||
|
||||
for (let i = 0; i < files.length; i++) {
|
||||
const file = files[i];
|
||||
file_contents[file.name] = Array.from(
|
||||
new Uint8Array(await file.arrayBuffer())
|
||||
);
|
||||
}
|
||||
|
||||
contents.files = { files: file_contents };
|
||||
|
||||
const message = this.serializeIpcMessage("user_event", {
|
||||
name: name,
|
||||
element: realId,
|
||||
data: contents,
|
||||
bubbles,
|
||||
});
|
||||
|
||||
this.ipc.postMessage(message);
|
||||
}
|
||||
|
||||
|
||||
// This should:
|
||||
// - prevent form submissions from navigating
|
||||
// - prevent anchor tags from navigating
|
||||
// - prevent buttons from submitting forms
|
||||
// - let the virtualdom attempt to prevent the event
|
||||
preventDefaults(event: Event, target: EventTarget) {
|
||||
let preventDefaultRequests: string | null = null;
|
||||
|
||||
// Some events can be triggered on text nodes, which don't have attributes
|
||||
if (target instanceof Element) {
|
||||
preventDefaultRequests = target.getAttribute(`dioxus-prevent-default`);
|
||||
}
|
||||
|
||||
if (preventDefaultRequests && preventDefaultRequests.includes(`on${event.type}`)) {
|
||||
event.preventDefault();
|
||||
}
|
||||
|
||||
if (event.type === "submit") {
|
||||
event.preventDefault();
|
||||
}
|
||||
|
||||
// Attempt to intercept if the event is a click
|
||||
if (target instanceof Element && event.type === "click") {
|
||||
this.handleClickNavigate(event, target, preventDefaultRequests);
|
||||
}
|
||||
}
|
||||
|
||||
// If there's files to read
|
||||
if (target instanceof HTMLInputElement && (event.type === "change" || event.type === "input")) {
|
||||
if (target.getAttribute("type") === "file") {
|
||||
read_files(target, contents, bubbles, realId, name);
|
||||
handleClickNavigate(event: Event, target: Element, preventDefaultRequests: string) {
|
||||
// todo call prevent default if it's the right type of event
|
||||
if (!this.intercept_link_redirects) {
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
prevents_default(event, target);
|
||||
// prevent buttons in forms from submitting the form
|
||||
if (target.tagName === "BUTTON" && event.type == "submit") {
|
||||
event.preventDefault();
|
||||
}
|
||||
|
||||
// If the target is an anchor tag, we want to intercept the click too, to prevent the browser from navigating
|
||||
let a_element = target.closest("a");
|
||||
if (a_element == null) {
|
||||
return;
|
||||
}
|
||||
|
||||
// Handle the event on the virtualdom and then process whatever its output was
|
||||
let body = {
|
||||
name: name,
|
||||
data: serializeEvent(event),
|
||||
element: parseInt(realId),
|
||||
bubbles,
|
||||
};
|
||||
|
||||
if (waitForVirtualDomPreventDefault(JSON.stringify(body))) {
|
||||
event.preventDefault();
|
||||
|
||||
let elementShouldPreventDefault =
|
||||
preventDefaultRequests && preventDefaultRequests.includes(`onclick`);
|
||||
|
||||
let aElementShouldPreventDefault = a_element.getAttribute(
|
||||
`dioxus-prevent-default`
|
||||
);
|
||||
|
||||
let linkShouldPreventDefault =
|
||||
aElementShouldPreventDefault &&
|
||||
aElementShouldPreventDefault.includes(`onclick`);
|
||||
|
||||
if (!elementShouldPreventDefault && !linkShouldPreventDefault) {
|
||||
const href = a_element.getAttribute("href");
|
||||
if (href !== "" && href !== null && href !== undefined) {
|
||||
this.ipc.postMessage(
|
||||
this.serializeIpcMessage("browser_open", { href })
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
export function waitForVirtualDomPreventDefault(contents: string): boolean {
|
||||
|
||||
type EventSyncResult = {
|
||||
preventDefault: boolean;
|
||||
stopPropagation: boolean;
|
||||
stopImmediatePropagation: boolean;
|
||||
filesRequested: boolean;
|
||||
};
|
||||
|
||||
// This function sends the event to the virtualdom and then waits for the virtualdom to process it
|
||||
//
|
||||
// However, it's not really suitable for liveview, because it's synchronous and will block the main thread
|
||||
// We should definitely consider using a websocket if we want to block... or just not block on liveview
|
||||
// Liveview is a little bit of a tricky beast
|
||||
function handleVirtualdomEventSync(contents: string): EventSyncResult {
|
||||
// Handle the event on the virtualdom and then process whatever its output was
|
||||
const xhr = new XMLHttpRequest();
|
||||
|
||||
@@ -157,130 +247,29 @@ export function waitForVirtualDomPreventDefault(contents: string): boolean {
|
||||
xhr.send(contents);
|
||||
|
||||
// Deserialize the response, and then prevent the default/capture the event if the virtualdom wants to
|
||||
return JSON.parse(xhr.responseText).preventDefault;
|
||||
return JSON.parse(xhr.responseText);
|
||||
}
|
||||
|
||||
|
||||
async function read_files(target: HTMLInputElement, contents, bubbles, realId, name) {
|
||||
let files = target.files!;
|
||||
let file_contents: { [name: string]: number[] } = {};
|
||||
|
||||
for (let i = 0; i < files.length; i++) {
|
||||
const file = files[i];
|
||||
file_contents[file.name] = Array.from(
|
||||
new Uint8Array(await file.arrayBuffer())
|
||||
);
|
||||
}
|
||||
|
||||
contents.files = { files: file_contents };
|
||||
|
||||
if (realId === null) {
|
||||
return;
|
||||
}
|
||||
|
||||
const message = window.interpreter.serializeIpcMessage("user_event", {
|
||||
name: name,
|
||||
element: parseInt(realId),
|
||||
data: contents,
|
||||
bubbles,
|
||||
});
|
||||
|
||||
window.ipc.postMessage(message);
|
||||
}
|
||||
|
||||
|
||||
export function target_id(target: EventTarget): string | null {
|
||||
if (!(target instanceof Element)) {
|
||||
function targetId(target: EventTarget): number | null {
|
||||
// Ensure that the target is a node, sometimes it's nota
|
||||
if (!(target instanceof Node)) {
|
||||
return null;
|
||||
}
|
||||
|
||||
function find_real_id(target: Element): string | null {
|
||||
let realId = target.getAttribute(`data-dioxus-id`);
|
||||
let ourTarget = target;
|
||||
let realId = null;
|
||||
|
||||
// walk the tree to find the real element
|
||||
while (realId == null) {
|
||||
// we've reached the root we don't want to send an event
|
||||
if (target.parentElement === null) {
|
||||
return null;
|
||||
}
|
||||
|
||||
target = target.parentElement;
|
||||
if (target instanceof Element) {
|
||||
realId = target.getAttribute(`data-dioxus-id`);
|
||||
}
|
||||
while (realId == null) {
|
||||
if (ourTarget === null) {
|
||||
return null;
|
||||
}
|
||||
|
||||
return realId;
|
||||
}
|
||||
|
||||
return find_real_id(target);
|
||||
}
|
||||
|
||||
|
||||
|
||||
// This should:
|
||||
// - prevent form submissions from navigating
|
||||
// - prevent anchor tags from navigating
|
||||
// - prevent buttons from submitting forms
|
||||
// - let the virtualdom attempt to prevent the event
|
||||
preventDefaults(event: Event, target: EventTarget) {
|
||||
let preventDefaultRequests: string | null = null;
|
||||
|
||||
// Some events can be triggered on text nodes, which don't have attributes
|
||||
if (target instanceof Element) {
|
||||
preventDefaultRequests = target.getAttribute(`dioxus-prevent-default`);
|
||||
}
|
||||
|
||||
if (preventDefaultRequests && preventDefaultRequests.includes(`on${event.type}`)) {
|
||||
event.preventDefault();
|
||||
}
|
||||
|
||||
if (event.type === "submit") {
|
||||
event.preventDefault();
|
||||
}
|
||||
|
||||
// Attempt to intercept if the event is a click
|
||||
if (target instanceof Element && event.type === "click") {
|
||||
this.preventFormNavigate(event, target);
|
||||
}
|
||||
}
|
||||
|
||||
preventFormNavigate(event: Event, target: Element) {
|
||||
// todo call prevent default if it's the right type of event
|
||||
if (!this.intercept_link_redirects) {
|
||||
return;
|
||||
}
|
||||
|
||||
// prevent buttons in forms from submitting the form
|
||||
if (target.tagName === "BUTTON") { // && event.type == "submit"
|
||||
event.preventDefault();
|
||||
}
|
||||
|
||||
// If the target is an anchor tag, we want to intercept the click too, to prevent the browser from navigating
|
||||
let a_element = target.closest("a");
|
||||
if (a_element == null) {
|
||||
return;
|
||||
}
|
||||
|
||||
event.preventDefault();
|
||||
|
||||
let elementShouldPreventDefault =
|
||||
preventDefaultRequests && preventDefaultRequests.includes(`onclick`);
|
||||
|
||||
let aElementShouldPreventDefault = a_element.getAttribute(
|
||||
`dioxus-prevent-default`
|
||||
);
|
||||
|
||||
let linkShouldPreventDefault =
|
||||
aElementShouldPreventDefault &&
|
||||
aElementShouldPreventDefault.includes(`onclick`);
|
||||
|
||||
if (!elementShouldPreventDefault && !linkShouldPreventDefault) {
|
||||
const href = a_element.getAttribute("href");
|
||||
if (href !== "" && href !== null && href !== undefined) {
|
||||
window.ipc.postMessage(
|
||||
window.interpreter.serializeIpcMessage("browser_open", { href })
|
||||
);
|
||||
if (ourTarget instanceof Element) {
|
||||
realId = ourTarget.getAttribute(`data-dioxus-id`);
|
||||
}
|
||||
|
||||
ourTarget = ourTarget.parentNode;
|
||||
}
|
||||
|
||||
return parseInt(realId);
|
||||
}
|
||||
@@ -4,10 +4,12 @@
|
||||
//
|
||||
// We're using sledgehammer directly
|
||||
|
||||
import { Interpreter, m } from "./interpreter_core";
|
||||
import { Interpreter } from "./interpreter_core";
|
||||
|
||||
export class WebInterpreter extends Interpreter {
|
||||
constructor(root: Element, handler: EventListener) {
|
||||
m: any;
|
||||
|
||||
constructor(root: HTMLElement, handler: EventListener) {
|
||||
super(root, handler);
|
||||
}
|
||||
|
||||
@@ -17,7 +19,7 @@ export class WebInterpreter extends Interpreter {
|
||||
let ptr_end = ptr + len;
|
||||
|
||||
for (; ptr < ptr_end; ptr++) {
|
||||
let end = m.getUint8(ptr);
|
||||
let end = this.m.getUint8(ptr);
|
||||
for (node = node.firstChild; end > 0; end--) {
|
||||
node = node.nextSibling;
|
||||
}
|
||||
@@ -26,7 +28,7 @@ export class WebInterpreter extends Interpreter {
|
||||
return node;
|
||||
}
|
||||
|
||||
saveTemplate(nodes: Element[], tmpl_id: string) {
|
||||
saveTemplate(nodes: HTMLElement[], tmpl_id: string) {
|
||||
this.templates[tmpl_id] = nodes;
|
||||
}
|
||||
|
||||
@@ -34,7 +36,7 @@ export class WebInterpreter extends Interpreter {
|
||||
const hydrateNodes = document.querySelectorAll('[data-node-hydration]');
|
||||
|
||||
for (let i = 0; i < hydrateNodes.length; i++) {
|
||||
const hydrateNode = hydrateNodes[i];
|
||||
const hydrateNode = hydrateNodes[i] as HTMLElement;
|
||||
const hydration = hydrateNode.getAttribute('data-node-hydration');
|
||||
const split = hydration!.split(',');
|
||||
const id = ids[parseInt(split[0])];
|
||||
@@ -54,22 +56,27 @@ export class WebInterpreter extends Interpreter {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
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 as Element;
|
||||
this.nodes[ids[parseInt(split[1])]] = currentNode.nextSibling;
|
||||
}
|
||||
|
||||
currentNode = treeWalker.nextNode();
|
||||
}
|
||||
}
|
||||
|
||||
getNode(id: number): Element {
|
||||
getNode(id: number): Node {
|
||||
return this.nodes[id];
|
||||
}
|
||||
|
||||
@@ -77,7 +84,7 @@ export class WebInterpreter extends Interpreter {
|
||||
const root = this.nodes[id];
|
||||
const els = this.stack.splice(this.stack.length - many);
|
||||
for (let k = 0; k < many; k++) {
|
||||
this.root.appendChild(els[k]);
|
||||
root.appendChild(els[k]);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,12 +1,12 @@
|
||||
// Handle serialization of the event data across the IPC boundarytype SerialziedEvent = {};
|
||||
|
||||
type SerializedEvent = {
|
||||
values?: { [key: string]: FormDataEntryValue[] } | FormDataEntryValue[];
|
||||
export type SerializedEvent = {
|
||||
values?: { [key: string]: FormDataEntryValue[] };
|
||||
value?: string;
|
||||
[key: string]: any;
|
||||
};
|
||||
|
||||
function serializeEvent(event: Event): SerializedEvent {
|
||||
export function serializeEvent(event: Event): SerializedEvent {
|
||||
|
||||
// copy, cut, paste
|
||||
if (event instanceof KeyboardEvent) {
|
||||
|
||||
@@ -1,3 +1,5 @@
|
||||
// A unified interface for setting attributes on a node
|
||||
|
||||
// this function should try and stay fast, if possible
|
||||
export function setAttributeInner(node: HTMLElement, field: string, value: string, ns: string) {
|
||||
// we support a single namespace by default: style
|
||||
|
||||
@@ -3,7 +3,10 @@
|
||||
"module": "system",
|
||||
"lib": [
|
||||
"ES2015",
|
||||
"DOM"
|
||||
"DOM",
|
||||
"dom",
|
||||
"dom.iterable",
|
||||
"esnext"
|
||||
],
|
||||
"noImplicitAny": true,
|
||||
"removeComments": true,
|
||||
|
||||
Reference in new issue
Block a user