144 lines
3.6 KiB
JavaScript
144 lines
3.6 KiB
JavaScript
|
'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);
|