'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);