Skip to content

Instantly share code, notes, and snippets.

@djalmajr
Last active April 14, 2023 16:43
Show Gist options
  • Save djalmajr/2229a401827cfbd02886f2c2de5b697b to your computer and use it in GitHub Desktop.
Save djalmajr/2229a401827cfbd02886f2c2de5b697b to your computer and use it in GitHub Desktop.
Simple HTML Renderer
const prefix = "δ";
const isAttr = /([^\s\\>"'=]+)\s*=\s*(['"]?)$/;
const hasPfx = (str) => str.search(prefix) !== -1;
const create = (tag, cfg) => Object.assign(document.createElement(tag), cfg);
export function html(strings, ...values) {
const tmpl = values.reduce((r, _, i) => {
return `${r}${isAttr.test(r) ? prefix + i : `<!--${prefix + i}-->`}${strings[i + 1]}`;
}, strings[0]);
const root = create("template", { innerHTML: tmpl }).content;
const walker = document.createTreeWalker(root, 1 | 128); // comment + element
let idx = 0, attr, node; // prettier-ignore
while (idx < values.length) {
if (!(node = walker.nextNode())) break;
if (node.nodeType === Node.ELEMENT_NODE) {
const attrs = node.getAttributeNames().filter((n) => hasPfx(node.getAttribute(n)));
for (attr of attrs) {
if (attr[0] === "@") node[`on${attr.slice(1)}`] = values[idx++];
else if (attr[0] === "?") node.toggleAttribute(attr.slice(1), !!values[idx++]);
else if (attr[0] === ".") node[attr.slice(1)] = values[idx++];
else { node.setAttribute(attr, values[idx++]); continue; } // prettier-ignore
node.removeAttribute(attr);
}
} else if (node.nodeType === Node.COMMENT_NODE && hasPfx(node.textContent)) {
const val = values[idx++];
if (val instanceof NodeList) render(node, val);
else node.parentNode.insertBefore(document.createTextNode(val), node);
}
}
return root.childNodes;
}
export function render(where, what) {
if (where.nodeType === Node.ELEMENT_NODE) where.replaceChildren(...what);
else for (const node of what) where.parentNode.insertBefore(node, where);
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment