hyperglue
Version:
update html elements by mapping query selectors to attributes, text, and hypertext
116 lines (99 loc) • 3.58 kB
JavaScript
var domify = require('domify');
module.exports = hyperglue;
var outer = null;
function hyperglue (src, updates) {
if (!updates) updates = {};
var dom = typeof src === 'object' ? [ src ] : domify(src);
if (!outer) outer = document.createElement('div');
forEach(objectKeys(updates), function (selector) {
var value = updates[selector];
forEach(dom, function (d) {
var parentNode = d.parentNode;
if (selector === ':first') {
bind(d, value);
}
else if (/:first$/.test(selector)) {
var k = selector.replace(/:first$/, '');
if (parentNode) parentNode.removeChild(d);
outer.appendChild(d);
var elem = outer.querySelector(k);
outer.removeChild(d);
if (parentNode) parentNode.appendChild(d);
if (elem) bind(elem, value);
}
else {
if (parentNode) parentNode.removeChild(d);
outer.appendChild(d);
var nodes = d.parentNode.querySelectorAll(selector);
outer.removeChild(d);
if (parentNode) parentNode.appendChild(d);
if (nodes.length === 0) return;
for (var i = 0; i < nodes.length; i++) {
bind(nodes[i], value);
}
}
});
});
return dom.length === 1 ? dom[0] : dom;
}
function bind (node, value) {
if (isElement(value)) {
node.innerHTML = '';
node.appendChild(value);
}
else if (isArray(value)) {
for (var i = 0; i < value.length; i++) {
var e = hyperglue(node.cloneNode(true), value[i]);
node.parentNode.insertBefore(e, node);
}
node.parentNode.removeChild(node);
}
else if (value && typeof value === 'object') {
forEach(objectKeys(value), function (key) {
if (key === '_text') {
setText(node, value[key]);
}
else if (key === '_html' && isElement(value[key])) {
node.innerHTML = '';
node.appendChild(value[key]);
}
else if (key === '_html') {
node.innerHTML = value[key];
}
else if (value[key] && typeof value[key] === 'object') {
var vk = value[key];
if (vk.append) {
node.setAttribute(key, node.getAttribute(key) + vk.append);
}
else if (vk.prepend) {
node.setAttribute(key, vk.prepend + node.getAttribute(key));
}
}
else node.setAttribute(key, value[key]);
});
}
else setText(node, value);
}
function forEach(xs, f) {
if (xs.forEach) return xs.forEach(f);
for (var i = 0; i < xs.length; i++) f(xs[i], i)
}
var objectKeys = Object.keys || function (obj) {
var res = [];
for (var key in obj) res.push(key);
return res;
};
function isElement (e) {
return e && typeof e === 'object' && e.childNodes
&& (typeof e.appendChild === 'function'
|| typeof e.appendChild === 'object')
;
}
var isArray = Array.isArray || function (xs) {
return Object.prototype.toString.call(xs) === '[object Array]';
};
function setText (e, s) {
e.innerHTML = '';
var txt = document.createTextNode(String(s));
e.appendChild(txt);
}