UNPKG

superdom

Version:
202 lines (174 loc) 5.86 kB
let dom = (function nodeSelector () { // Convert a function into a property selector // It converts "(a, b) => [a, b]" but keeps "a => a" let DOM = (...sel) => DOM.api.array(DOM.api.selectors(sel.length <= 1 ? sel[0] : sel)); // The second-level SELECTOR // dom.class(X); dom.class.X; dom.class.X = 5; delete.dom.class.X // This is NOT matched though: dom.a.X const derivated = (selector, orig) => { // Allow for a function to be used as getter return new Proxy(sel => DOM(selector(sel)), { get: (orig, name) => { return selector(name); }, set: (orig, name, value) => { DOM[selector(name)] = value; return true; }, deleteProperty: (orig, name) => { delete DOM[selector(name)]; return true; } }); }; // First level SELECTOR // dom.button || dom.class let getter = (orig, key) => { if (key in orig) return orig[key]; // Allow extending the API if (key in orig.api.selectors) { return derivated(orig.api.selectors[key], orig); } return orig.api.array(orig.api.selectors(key)); }; let setter = (orig, key, value) => { let cb = DOM.api.fn(value, true); DOM[key].each(node => node.parentNode.replaceChild(cb(node)[0], node)); }; let deletter = (base, key) => { DOM[key].forEach(n => n.remove()); return true; }; DOM.api = {}; // CANNOT SIMPLIFY TO "return new Proxy()" => ERROR WTF? DOM = new Proxy(DOM, { get: getter, set: setter, deleteProperty: deletter }); return DOM; })(); // Second level selector // let a = dom.a.href; dom.a.href = '...'; delete dom.a.href; dom = (function Attributes (DOM) { // Obtain a callback from the attribute passed, whatever the type DOM.api.fn = (value, parse = false) => { let cb = node => parse ? DOM(value) : value; if (value instanceof Function) cb = value; return cb; }; // Returns something that is not a list of nodes, so keep them in reference DOM.api.proxify = (proxify, nodes, key) => { proxify._ = { ref: nodes, attr: key }; return DOM.api.values(proxify); }; DOM.api.array = nodes => { let getter = (orig, key) => { // Array original function: dom.a.map() if (key in orig) { return orig[key]; } // Nodes API function: dom.a.class, dom.a.on if (key in DOM.api.nodes) { let nodeCb = DOM.api.nodes[key]; if (nodeCb.get) nodeCb = nodeCb.get; let newNodes = nodes.map((nodes, i, all) => nodeCb(nodes, i, all)); return DOM.api.proxify(newNodes, nodes, key); } // Navigation API function: dom.a.parent if (key in DOM.api.navigate) { let cb = DOM.api.navigate[key]; // Make it into a simple array if an array of arrays was returned let newNodes = nodes.map(cb).reduce((all, one) => { return all.concat(one); }, []).filter(n => n); return DOM.api.array(newNodes); } // Defaults to the attribute: dom.a.href let newNodes = nodes.map(node => node.getAttribute(key) || ''); return DOM.api.proxify(newNodes, nodes, key); }; // Setting the array; convert to fn and then proceed let setter = (orig, key, value) => { let cb = DOM.api.fn(value); let nodeCb = DOM.api.nodes[key]; if (nodeCb) { if (nodeCb.set) nodeCb = nodeCb.set; orig.map((node, i, all) => nodeCb(cb, node, i, all)); return true; } if (value instanceof Function) { cb = (node, i, orig) => value(node.getAttribute(key) || '', i, orig); } else { cb = node => value; } orig.forEach((node, i, orig) => node.setAttribute(key, cb(node, i, orig) || '')); }; let deletter = (orig, key) => { let cb = el => el.removeAttribute(key); if (DOM.api.nodes[key] && DOM.api.nodes[key].del) { cb = DOM.api.nodes[key].del; } orig.forEach(cb); return true; }; return new Proxy(nodes, { get: getter, set: setter, deleteProperty: deletter }); }; return DOM; })(dom); // Derivated attribute (when it was Nodes and not Navigate) // let a = dom.a.class.demo; dom.a.class.demo = true; delete dom.a.class.demo dom = (function Values (DOM) { let specialAttrs = { _flat: lists => [...new Set([].concat.apply([], lists))], _text: lists => [...new Set([].concat.apply([], lists))].join(' ') }; DOM.api.values = attributes => { // dom.a.href._blank; dom.a.class.bla let getter = (orig, key) => { if (key in orig || typeof orig[key] !== 'undefined') { return orig[key]; } let nodes = orig._.ref; let cb = DOM.api.attributes[orig._.attr]; if (cb && cb.get) { cb = cb.get; orig.map((attr, i, all) => cb(attr, key, nodes[i], i, all)); } if (key in specialAttrs) { return specialAttrs[key](orig); } // TODO: personalized attr (such as in parent) return specialAttrs._flat(orig).includes(key); }; // dom.a.class.bla = false; dom.a.href._blank = false; let setter = (orig, key, value) => { let nodes = orig._.ref; let attrCb = DOM.api.attributes[orig._.attr]; if (attrCb) { if (attrCb.set) attrCb = attrCb.set; orig.map((attr, i, all) => attrCb(DOM.api.fn(value), key, nodes[i], i, all)); } return true; }; let deletter = (orig, key) => { let nodes = orig._.ref; let attrCb = DOM.api.attributes[orig._.attr].del; if (attrCb) { orig.map((attr, i, all) => attrCb(key, nodes[i], i, all)); } return true; }; return new Proxy(attributes, { get: getter, set: setter, deleteProperty: deletter }); }; return DOM; })(dom); if (typeof module !== 'undefined') { module.exports = dom; }