From 3f7ac550473c362debd4fc1dbad1ec8da69e262f Mon Sep 17 00:00:00 2001 From: benStre Date: Sun, 29 Sep 2024 18:56:26 +0200 Subject: [PATCH] reactive transform improvements (ternaries) --- datex-bindings/dom-utils.ts | 62 ++++++++++++------- datex-bindings/transform-wrapper.ts | 10 +-- datex-bindings/type-definitions.ts | 4 +- .../html-template-strings.ts | 2 +- 4 files changed, 48 insertions(+), 30 deletions(-) diff --git a/datex-bindings/dom-utils.ts b/datex-bindings/dom-utils.ts index a85b74e..15e911c 100644 --- a/datex-bindings/dom-utils.ts +++ b/datex-bindings/dom-utils.ts @@ -945,9 +945,9 @@ export class DOMUtils { newNode = value; } - // unsupported value - create text node + // unsupported value - create text/content node if (!(newNode instanceof this.context.Node || newNode instanceof this.context.DocumentFragment || newNode instanceof this.context.Comment)) { - newNode = this.getTextNode(newNode); + newNode = this.getNode(newNode); } return { @@ -956,9 +956,11 @@ export class DOMUtils { } } - getTextNode(content:any) { - const textNode = this.document.createTextNode("") as unknown as Text; - (textNode as any)[DX_VALUE] = content; + getNode(content:any) { + const contentVal = val(content); + // either use existing node or create new text node + const node = contentVal instanceof Node ? contentVal : this.document.createTextNode("") as unknown as Text; + (node as any)[DX_VALUE] = content; // lazy pointer or lazy pointer property if ( @@ -966,46 +968,62 @@ export class DOMUtils { (content instanceof PointerProperty && content.lazy_pointer) ) { content.onLoad(() => { - this.bindTextNode(textNode, content) + this.bindNode(node, content) }) } // ref else if (content instanceof Datex.ReactiveValue) { - this.bindTextNode(textNode, content) + this.bindNode(node, content) } else { - textNode.textContent = (content!=undefined && content!==false) ? (content).toString() : '' + node.textContent = (content!=undefined && content!==false) ? (content).toString() : '' } - return textNode; + return node; } - bindTextNode(textNode: Text, ref:Datex.RefLike) { - weakAction({textNode, ref}, - ({textNode, ref}) => { + bindNode(node: Node, ref:Datex.RefLike) { + + weakAction({node, ref}, + ({node, ref}) => { use (logger, Datex, isolatedScope); + + let prevNode:{node?:WeakRef} = {node}; + // TODO: dont reference 'ref' in handler, use args from handler const handler = isolatedScope((...args:any[]) => { - use (logger, ref, textNode); + use (logger, ref, prevNode); + + let prevNodeDeref = prevNode.node?.deref()!; const deref = ref.deref(); if (!deref) { logger.warn("Undetected garbage collection (uix-w0001)"); return; } - const textNodeDeref = textNode.deref(); - if (!textNodeDeref) { - logger.warn("Undetected garbage collection (uix-w0001)"); - return; - } - try { const val = deref.val; - textNodeDeref.textContent = (val!=undefined && val!==false) ? (val).toString() : '' + + // replace previous node if it is a node, otherwise update text content + if (val instanceof Node) { + prevNode.node = new WeakRef(val); + prevNodeDeref.replaceWith(val); + } + else { + if (!(prevNodeDeref instanceof Text)) { + const node = document.createTextNode(""); + prevNode.node = new WeakRef(node); + prevNodeDeref.replaceWith(node); + prevNodeDeref = node; + } + prevNodeDeref.textContent = (val!=undefined && val!==false) ? (val).toString() : '' + } + } - catch { - textNodeDeref.textContent = "" + catch (e) { + console.error(e) + prevNodeDeref.textContent = "" } }); diff --git a/datex-bindings/transform-wrapper.ts b/datex-bindings/transform-wrapper.ts index 9a4b861..fe4462c 100644 --- a/datex-bindings/transform-wrapper.ts +++ b/datex-bindings/transform-wrapper.ts @@ -18,11 +18,11 @@ function appendToFragment(domUtils: DOMUtils, context: DOMContext, fragment: HTM export function getTransformWrapper(domUtils: DOMUtils, context: DOMContext) { return { // special uix-fragment wrapper for transforms - wrap_transform(val:any) { - const fragment = context.document.createElement("uix-fragment"); - appendToFragment(domUtils, context, fragment, val); - return fragment; - }, + // wrap_transform(val:any) { + // const fragment = context.document.createElement("uix-fragment"); + // appendToFragment(domUtils, context, fragment, val); + // return fragment; + // }, allow_transform_value(type: Datex.Type) { return allDomTypes.has(type.root_type) || type.root_type.name == "uix" || "must be a DOM element" diff --git a/datex-bindings/type-definitions.ts b/datex-bindings/type-definitions.ts index a93a07d..4f0e788 100644 --- a/datex-bindings/type-definitions.ts +++ b/datex-bindings/type-definitions.ts @@ -34,7 +34,7 @@ export function loadDefinitions(context: DOMContext, domUtils: DOMUtils, options console.log(element) throw new Error("element has no dataset, todo"); } - if (!element.hasAttribute("uix-ptr")) element.setAttribute("uix-ptr", pointer.id); + if (!element.hasAttribute("uix-ptr") && client_type == "deno") element.setAttribute("uix-ptr", pointer.id); // @ts-ignore if (element[OBSERVER]) return; @@ -402,7 +402,7 @@ export function loadDefinitions(context: DOMContext, domUtils: DOMUtils, options }, create_proxy(val, pointer) { - if (!val.hasAttribute("uix-ptr")) val.setAttribute("uix-ptr", pointer.id); + if (!val.hasAttribute("uix-ptr") && client_type == "deno") val.setAttribute("uix-ptr", pointer.id); const cloneNodeOriginal = val.cloneNode.bind(val); diff --git a/html-template-strings/html-template-strings.ts b/html-template-strings/html-template-strings.ts index 4aa955d..f2273db 100644 --- a/html-template-strings/html-template-strings.ts +++ b/html-template-strings/html-template-strings.ts @@ -176,7 +176,7 @@ export function getHTMLGenerator(context: DOMContext, domUtils: DOMUtils, jsx: R const isTemplate = template?.raw instanceof Array && template instanceof Array; // non template value - convert to HTML node if (!isTemplate) { - return domUtils.getTextNode(template); + return domUtils.getNode(template); } // templatee else {