/** @module NodeEnhancer */
import {
appendChildren,
wrapNode,
addListeners,
removeListeners,
setAttributes,
setClasses,
setStyles,
setProperties,
removeAttributes,
removeClasses,
removeStyles,
removeProperties,
findElements,
setDataAttributes,
removeDataAttributes,
hasAttributes,
hasClasses,
moveNode,
getAttributes,
} from '../DOMUtils.js'
const utils = {
appendChildren,
wrapNode,
addListeners,
removeListeners,
setAttributes,
removeAttributes,
setClasses,
removeClasses,
setStyles,
removeStyles,
setProperties,
removeProperties,
setDataAttributes,
removeDataAttributes,
}
/**
* @typedef {Array} ExtraElementsArray
* @description array with extra props set
* @deprecated
*
* @property {Function} appendChildren
* @property {Function} wrapNode
* @property {Function} addListeners
* @property {Function} removeListeners
* @property {Function} setAttributes
* @property {Function} removeAttributes
* @property {Function} setClasses
* @property {Function} removeClasses
* @property {Function} setStyles
* @property {Function} removeStyles
* @property {Function} setProperties
* @property {Function} removeProperties
* @property {Function} setDataAttributes
* @property {Function} removeDataAttributes
*/
/**
* @type {Object.<string, function>}
* @description created to later be assigned through Object.setProperties
* @private
* @constant
* @deprecated
*/
const extraElementDescriptor = {};
for (let util in utils) {
extraElementDescriptor[util] = {
value: function (...args) {
callForEachElem(this, utils[util], ...args)
return this
}
}
}
/**
* @function callForEachElem
* @private
* @constant
* @description Call a function for each elements in an array
*
* @param {Element[]} array array of element for which to call func
* @param {Function} func this function receive an array element as first parameter, then ...args
* @param {...any} args additional parameters to pass to func
*
* @returns {Array} array parameter
*/
const callForEachElem = (array, func, ...args) => {
for (let i = 0, n = array.length; i < n; i++) {
func(array[i], ...args)
}
return array
}
/**
* @function extra
* @description Create an Instance of Extra
* @public
* @constant
* @param {Element|Element[]|String} nodes can either be a selector string or a/some Element type object
*
* @returns {Extra} Extra Wrapper Instance
* @example
* // with selector string
* // return ExtraInstance
* extra('.menu .link')
*/
export const extra = nodes => {
if (typeof nodes == 'string') {
nodes = document.querySelectorAll(nodes)
}
if (!Array.isArray(nodes)) nodes = Array.from(nodes)
return new Extra(nodes)
}
/**
* @function e
* @constant
* @public
* @description alias of {@link #extra} function
*
*/
export const e = extra
export default e
/**
* @description Extra is a wrapper a la jQuery that allows to modify dom element through DOMUtils superset of the DOM API
*/
export class Extra extends Array {
/**
* @constructor
* @param {...Element} [elements] Initial selection of Elements
* @example
* new Extra(document.querySelectorAll('.menu .link'))
*/
constructor(...elements) {
super(...elements)
this.appendChildren = this.appendChildren.bind(this)
this.wrapNode = this.wrapNode.bind(this)
this.addListeners = this.addListeners.bind(this)
this.removeListeners = this.removeListeners.bind(this)
this.setAttributes = this.setAttributes.bind(this)
this.removeAttributes = this.removeAttributes.bind(this)
this.setClasses = this.setClasses.bind(this)
this.removeClasses = this.removeClasses.bind(this)
this.setStyles = this.setStyles.bind(this)
this.removeStyles = this.removeStyles.bind(this)
this.setProperties = this.setProperties.bind(this)
this.removeProperties = this.removeProperties.bind(this)
this.setDataAttributes = this.setDataAttributes.bind(this)
this.removeDataAttributes = this.removeDataAttributes.bind(this)
}
/**
* @description Adds children to the FIRST selected Elements.
* @param {...Element} args
*
* @returns {Extra} Extra Wrapper Instance
*/
appendChildren(...args) { appendChildren(this[0], ...args); return this }
/**
* @description Wraps selected Elements in a new Element.
*
* @param {import('../DOMUtils.js').createElementOptions} options options object for the freshly created wrappers
* @param {module:DOMUtils.createElementOptions} options options object for the freshly created wrappers
*/
wrapNode(options) { callForEachElem(this, wrapNode, options); return this }
/**
* @description Adds listeners to each selected Elements.
*
* @param {Function} fun handler function
* @param {String|String[]} events
* @param {Boolean} bubble
*
* @returns {Extra} Extra Wrapper Instance
*/
addListeners(fun, events, bubble) { callForEachElem(this, addListeners, fun, events, bubble); return this }
/**
* @description Removes listeners from each selected Elements.
*
* @param {Function} fun
* @param {String|String[]} events
* @param {Boolean} bubble
*
* @returns {Extra} Extra Wrapper Instance
*/
removeListeners(fun, events, bubble) { callForEachElem(this, removeListeners, fun, events, bubble); return this }
/**
* @description Set attributes of each selected Elements.
*
* @param {Object.<string, (String|Number)>} attributes
*
* @returns {Extra} Extra Wrapper Instance
*/
setAttributes(attributes) { callForEachElem(this, setAttributes, attributes); return this }
/**
* @description Removes attributes of each selected Elements.
*
* @param {String[]} attributes
*
* @returns {Extra} Extra Wrapper Instance
*/
removeAttributes(attributes) { callForEachElem(this, removeAttributes, attributes); return this }
/**
* @param {String[]} classes
*
* @returns {Extra} Extra Wrapper Instance
*/
setClasses(classes) { callForEachElem(this, setClasses, classes); return this }
/**
* @param {String[]} classes
*
* @returns {Extra} Extra Wrapper Instance
*/
removeClasses(classes) { callForEachElem(this, removeClasses, classes); return this }
/**
* @param {Object.<string, (String|Number)>} styles
*
* @returns {Extra} Extra Wrapper Instance
*/
setStyles(styles) { callForEachElem(this, setStyles, styles); return this }
/**
* @param {Object.<string, (String|Number)>} styles
*
* @returns {Extra} Extra Wrapper Instance
*/
removeStyles(styles) { callForEachElem(this, removeStyles, styles); return this }
/**
* @param {Object.<string, (String|Number)>} customProperties
*
* @returns {Extra} Extra Wrapper Instance
*/
setProperties(customProperties) { callForEachElem(this, setProperties, customProperties); return this }
/**
* @param {Object.<string, (String|Number)>} customProperties
*
* @returns {Extra} Extra Wrapper Instance
*/
removeProperties(customProperties) { callForEachElem(this, removeProperties, customProperties); return this }
/**
* @param {Object.<string, (String|Number)>} attributes
*
* @returns {Extra} Extra Wrapper Instance
*/
setDataAttributes(attributes) { callForEachElem(this, setDataAttributes, attributes); return this }
/**
* @param {String[]} attributes
*
* @returns {Extra} Extra Wrapper Instance
*/
removeDataAttributes(attributes) { callForEachElem(this, removeDataAttributes, attributes); return this }
/**
* @description Return an object with attributes set on the FIRST selected Element
* @param {String[]} attributes
*
* @returns {Object.<string, (string|null)>} attributes set as key/values
*/
getAttributes(attributes) { return getAttributes(this[0], attributes) }
}