Skip to content

Instantly share code, notes, and snippets.

@bjconlan
Last active August 28, 2018 01:07
Show Gist options
  • Save bjconlan/32387c957da8deb52b2cb0e8268b709f to your computer and use it in GitHub Desktop.
Save bjconlan/32387c957da8deb52b2cb0e8268b709f to your computer and use it in GitHub Desktop.
Simple dom builder using tuple of [node, children]
// node = {}
// children are a key;
class DOMBuilder {
constructor(document, options = {uri: 'http://www.w3.org/1999/xhtml', tag: 'div'}) {
this.document = document;
this.options = options;
}
buildNode(node) {
if (node.tag === "text" && node.value) {
return this.document.createTextNode(node.value);
} else {
let el = this.document.createElementNS(node.uri || this.options.uri, node.tag || this.options.tag);
for (var k in node) {
var v = node[k];
switch (k) {
case "uri": case "tag": case "children": break;
case "style": el.setAttribute(k, (typeof(v) === "string") ? v : Object.entries(v).reduce((r, style) => r.push(style.join(":")) && r, []).join(';'); break;
case "class": el.setAttribute(k, (typeof(v) === "string") ? v : v.join(' ')); break;
default: el.setAttribute(k, v);
}
}
return el;
}
}
build(tree) {
let node = this.buildNode(tree);
for (var i in tree.children) {
node.nodeType !== Node.TEXT_NODE && node.appendChild(this.build(tree.children[i]));
}
return node;
}
}
let dom =
{tag: "body", children: [
{tag: "head", children: [
{tag: "script", src: "js/ts.js"},
{tag: "meta", value: "content"}]},
{tag: "i", children: [
{class: ["header","active"], style: {height:"100px", width:"20px"}},
{tag: "text", value: "first line"},
{tag: "text", value: "second line with markup"},
{tag: "span", children: [
{tag: "text", value: "content"}]},
{tag: "text", value: "last line"}]}]};
console.log(new DOMBuilder(document).build(dom));
// special case 'text' node' ["text"] = "text" (NOTE you cannot have children with this node)
// node = [map|string]
// tree = [leaf]|[leaf [leaf]]
let style = {
stringify :function (obj) {
r = "";
for (var k in obj) {
r += k + ":" + obj[k] + ";";
}
return r;
}
};
function buildNode(node) {
if (typeof(node) === "string") {
return document.createTextNode(node);
} else {
var el = document.createElementNS(node.uri || 'http://www.w3.org/1999/xhtml', node.tag || 'div');
for (var k in node) {
var v = node[k];
switch (k) {
case "uri":
case "tag":
break;
case "style":
el.setAttribute(k, (typeof(v) === "string") ? v : style.stringify(v));
break;
case "class":
el.setAttribute(k, (typeof(v) === "string") ? v : v.join(' '));
break;
default:
el.setAttribute(k, v);
}
}
return el;
}
}
function build([nodeDef, children]) {
var node = buildNode(nodeDef);
for (var i in children) {
var childNode = build(children[i]);
if (node.nodeType !== Node.TEXT_NODE) {// prevent child nodes on text nodes
node.appendChild(childNode);
}
}
return node;
}
let dom =
[{tag: "body"}, [
[{tag: "head"}, [
[{tag: "script", src: "js/ts.js"}],
[{tag: "meta"}, [
["content"]]]]],
[{tag: "i"}, [
[{class: ["header","active"], style: {height: "100px", width:"20px"}}, [
["first line"],
["second line with markup"],
[{tag: "span"}, [["content"]]],
["last line"]]]]]]]
console.log(build(dom));
@bjconlan
Copy link
Author

I think i prefer [tag, {attributes}, [children]] structure now that destructuring is available in js

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment