Add proper bundling to tsc
This commit is contained in:
15 files changed
+267
-1065
No files matched your search
@@ -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
|
||||
|
||||
Reference in new issue
Block a user