chaos/scripts/dom.js

144 lines
3.6 KiB
JavaScript
Raw Normal View History

'use strict';
/**
* dom.js
* A module that helps working with HTML elements in the DOM
*/
const boundaryRegex = /\s+/g;
/**
* Add a wrapping of utility methods around a Node
*
* @param {Node} el Node to wrap
* @return {Object} Utility-wrapped node
*/
const wrapNode = (el) => Object.freeze({
node: el,
// shortcuts
get: selector => wrapNode(el.querySelector(selector)),
all: selector => wrapEls(el.querySelectorAll(selector)),
parent: () => wrapNode(el.parentNode),
children: () => wrapEls(el.childNodes),
add: subEl => el.appendChild(unwrapNode(subEl)),
remove: () => el.parentNode.removeChild(el),
getAttr: name => el.getAttribute(name),
setAttr: (name, val) => el.setAttribute(name, val),
/**
* Add event listeners for all given events
*
* @param {string} events Whitespace-separated list of events
* @param {function} listener Listener to add
* @return {null}
*/
on: (events, listener) => {
events.trim().split(boundaryRegex).forEach(
event => el.addEventListener(event, listener)
);
},
/**
* Remove event listeners for all given events
*
* @param {strings} events Whitespace-separated list of events
* @param {function} listener Listener to remove
* @return {null}
*/
off: (events, listener) => {
events.trim().split(boundaryRegex).forEach(
event => el.removeEventListener(event, listener)
);
}
});
/**
* Remove a wrapping around a Node
*
* @param {Object|Node} el A node, wrapped or not
* @return {Node} Unwrapped node
*/
const unwrapNode = el => el instanceof Node ? el : el.node;
/**
* Override the methods of an Array so that it
* can easily manipulate Nodes it contains
*
* @param {Array} list A list to be wrapped
* @return {Array} Expanded list
*/
const expandList = (list) => Object.assign(list, {
// shortcuts
on: function (events, listener) {
this.forEach(node => node.on(events, listener));
},
off: function (events, listener) {
this.forEach(node => node.off(events, listener));
},
/**
* Check whether this list includes given node
*
* @param {Node|Object} el Element to check
* @return {bool} True if this list contains `el`
*/
includes: function (el) {
const length = this.length;
el = unwrapNode(el);
for (let i = 0; i < length; i += 1) {
if (el === unwrapNode(this[i])) {
return true;
}
}
return false;
},
/**
* Filter nodes in the list, removing filtered out nodes
*
* @param {function} check A function that returns true to keep given el
* @return {Array} New list of nodes after filtering
*/
filter: function (check) {
const length = this.length, newList = [];
for (let i = 0; i < length; i += 1) {
if (!check(this[i], i, this)) {
this[i].remove();
} else {
newList.push(this[i]);
}
}
return expandList(newList);
}
});
/**
* Turn a NodeList into a real Array of Nodes
*
* @param {NodeList} els List of nodes to wrap
* @return {Array} An array of nodes
*/
const wrapList = (els) => {
const result = [], length = els.length;
for (let i = 0; i < length; i += 1) {
result[i] = wrapNode(els[i]);
}
return expandList(result);
};
export const create = (name) => wrapNode(document.createElement(name));
export const html = wrapNode(document.documentElement);
export const head = wrapNode(document.head);
export const body = wrapNode(document.body);