From b336faff25724d36d57a8ab9c35b2aa91f16a6a0 Mon Sep 17 00:00:00 2001 From: Tony Garnock-Jones Date: Sun, 3 Dec 2023 23:22:51 +0100 Subject: [PATCH] Tidy up --- packages/html2/src/html.ts | 102 ++++++++++++++++++++++++------------- 1 file changed, 66 insertions(+), 36 deletions(-) diff --git a/packages/html2/src/html.ts b/packages/html2/src/html.ts index cbc3e8e..934e630 100644 --- a/packages/html2/src/html.ts +++ b/packages/html2/src/html.ts @@ -57,9 +57,59 @@ function followPath(topNodes: ChildNode[], path: number[]): Node { return n; } +type PlaceholderAction = (variableParts: HtmlFragment[], topNodes: ChildNode[]) => void; + +function nodeInserter(n: number, path: number[]): PlaceholderAction { + return (vs, topNodes) => { + const node = followPath(topNodes, path); + function walk(f: HtmlFragment) { + if (Array.isArray(f)) { + f.forEach(walk); + } else { + let newNode: Node; + switch (typeof f) { + case 'string': newNode = document.createTextNode(f); break; + case 'number': newNode = document.createTextNode('' + f); break; + default: newNode = f; break; + } + node.parentNode?.insertBefore(newNode, node); + } + } + walk(vs[n]); + node.parentNode?.removeChild(node); + }; +} + +function attributesInserter(n: number, path: number[]): PlaceholderAction { + return (vs, topNodes) => { + const node = followPath(topNodes, path); + const e = document.createElement('template'); + e.innerHTML = ``; + Array.from(e.attributes).forEach(a => + (node as Element).setAttribute(a.name, a.value)); + }; +} + +function attributeValueInserter( + attrName: string, + constantParts: string[], + placeholders: number[], + path: number[], +): PlaceholderAction { + return (vs, topNodes) => { + const node = followPath(topNodes, path); + const pieces = [constantParts[0]]; + placeholders.forEach((n, i) => { + pieces.push(...renderFragment(vs[n], false)); + pieces.push(constantParts[i + 1]); + }); + (node as Element).setAttribute(attrName, pieces.join('')); + }; +} + export class HtmlFragmentBuilder { template: HTMLTemplateElement = document.createElement('template'); - placeholderActions: Array<(variableParts: HtmlFragment[], topNodes: ChildNode[]) => void> = []; + placeholderActions: PlaceholderAction[] = []; constructor(constantParts: TemplateStringsArray) { const pieces: string[] = []; @@ -81,9 +131,13 @@ export class HtmlFragmentBuilder { const n = nextN; switch (n.nodeType) { case Node.TEXT_NODE: { - const { constantParts, placeholders } = splitByPlaceholders(n.textContent ?? ''); + const { constantParts, placeholders } = + splitByPlaceholders(n.textContent ?? ''); constantParts.forEach((c, i) => { - if (i > 0) n.parentNode?.insertBefore(document.createElement('placeholder'), n); + if (i > 0) { + const placeholder = document.createElement('x-placeholder'); + n.parentNode?.insertBefore(placeholder, n); + } n.parentNode?.insertBefore(document.createTextNode(c), n); }); nextN = n.nextSibling; @@ -91,22 +145,7 @@ export class HtmlFragmentBuilder { placeholders.forEach((n, i) => { const currentPath = path.slice(); currentPath[currentPath.length - 1] = i * 2 + 1; - this.placeholderActions.push((vs, topNodes) => { - const node = followPath(topNodes, currentPath); - function walk(f: HtmlFragment) { - if (Array.isArray(f)) { - f.forEach(walk); - } else { - switch (typeof f) { - case 'string': node.parentNode?.insertBefore(document.createTextNode(f), node); break; - case 'number': node.parentNode?.insertBefore(document.createTextNode('' + f), node); break; - default: node.parentNode?.insertBefore(f, node); break; - } - } - } - walk(vs[n]); - node.parentNode?.removeChild(node); - }); + this.placeholderActions.push(nodeInserter(n, currentPath)); }); bump(constantParts.length + placeholders.length); break; @@ -123,25 +162,16 @@ export class HtmlFragmentBuilder { e.removeAttributeNode(attr); i--; const n = parseInt(nameIsPlaceholder[1], 10); - this.placeholderActions.push((vs, topNodes) => { - const node = followPath(topNodes, currentPath); - const e = document.createElement('template'); - e.innerHTML = ``; - Array.from(e.attributes).forEach(a => - (node as Element).setAttribute(a.name, a.value)); - }); + this.placeholderActions.push(attributesInserter(n, currentPath)); } else { - const { constantParts, placeholders } = splitByPlaceholders(attr.value); + const { constantParts, placeholders } = + splitByPlaceholders(attr.value); if (constantParts.length !== 1) { - this.placeholderActions.push((vs, topNodes) => { - const node = followPath(topNodes, currentPath); - const pieces = [constantParts[0]]; - placeholders.forEach((n, i) => { - pieces.push(...renderFragment(vs[n], false)); - pieces.push(constantParts[i + 1]); - }); - (node as Element).setAttribute(attrName, pieces.join('')); - }); + this.placeholderActions.push(attributeValueInserter( + attrName, + constantParts, + placeholders, + currentPath)); } } }