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));
}
}
}