Skip to content

Instantly share code, notes, and snippets.

@straker
Last active October 20, 2022 11:31
Show Gist options
  • Star 4 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save straker/bae267cd33bf3cf75e72 to your computer and use it in GitHub Desktop.
Save straker/bae267cd33bf3cf75e72 to your computer and use it in GitHub Desktop.
Simple wrapper around DOM functions to make DOM interactions a bit easier to work with
(function(Node, Element, HTMLCollection, Array) {
/**
* Wrap addEventListener to handle multiple event types and be chainable.
* @param {string} types - Space-separated event types.
* @param {function} listener
* @param {boolean} useCapture
* @returns {Node}
*
* @example
* document.querySelector('a')
* .addEventListener('click blur', function(e) {
* // ...
* })
* .setAttribute('class', 'activated');
*
* EventTarget does not exist in Safari, and the only prototype the document and an element
* share is Node. Not really the best place to attach it, but there's not much we can do
* about it.
*/
Node.prototype._addEventListener = Node.prototype.addEventListener;
Node.prototype.addEventListener = function addEventListener(types, listener, useCapture) {
if (typeof types !== 'string') return;
types.split(' ').forEach(function(type) {
this._addEventListener(type, listener, useCapture);
}.bind(this));
return this;
};
/**
* Wrap setAttribute to handle multiple attributes and be chainable.
* @param {string|object} name - Object of name-value pairs or a string of the attribute name.
* @param {string} [value] - Value of the attribute if name was a string.
* @returns {Element}
*
* @example
* document.createElement('div')
* .setAttribute({'class': 'myClass', 'id': 'myId'})
* .addEventListener('click', function(e) {
* // ...
* })
*/
Element.prototype._setAttribute = Element.prototype.setAttribute;
Element.prototype.setAttribute = function setAttribute(name, value) {
// backward compatibility
if (arguments.length === 2) {
this._setAttribute(name, value);
}
// new object syntax
else {
for (var prop in name) {
if (!name.hasOwnProperty(prop)) continue;
this._setAttribute(prop, name[prop]);
}
}
return this;
};
/**
* Wrap getAttribute to parse attributes to convert it back to it's original type.
* @param {string} name - Name of the attribute.
* @returns {*}
*
* @example
* document.createElement('div')
* .setAttribute('test', 1)
* .getAttribute('test'); //=> 1
*
* document.createElement('div')
* .setAttribute('obj', {foo: 'bar'})
* .getAttribute('obj'); //=> {foo: 'bar'}
*/
Element.prototype._getAttribute = Element.prototype.getAttribute;
Element.prototype.getAttribute = function getAttribute(name) {
var value = this._getAttribute(name);
try {
value = JSON.parse(value);
}
catch(e) {}
return value;
};
/**
* Allow innerHTML to be chainable.
* @param {string} content - Content to set as element's descendants.
* @returns {Element}
*
* @example
* document.createElement('div')
* .setInnerHTML('<span><button>click me</button></span>')
* .setAttribute({'class': 'myClass', 'id': 'myId'})
*/
Element.prototype.setInnerHTML = function setInnerHTML(content) {
this.innerHTML = content;
return this;
};
/**
* Allow style to handle multiple styles and be chainable.
* @param {string|object} name - Object of name-value pairs or a string of the attribute name.
* @param {string} [value] - Value of the attribute if name was a string.
* @returns {Element}
*
* @example
* document.createElement('div')
* .setStyle('width', '120px')
* .setStyle({'height': '120px'})
*/
Element.prototype.setStyle = function setStyle(name, value) {
// single style
if (arguments.length === 2) {
this.style[name] = value;
}
// multiple styles
else {
for (var prop in name) {
if (!name.hasOwnProperty(prop)) continue;
this.style[prop] = name[prop];
}
}
return this;
};
/**
* Allow appendChild to be chainable.
* @param {Node} node - Node to append.
* @returns {Node}
*
* @example
* document.createElement('div')
* .append(document.createElement('span'))
* .setAttribute({'class': 'myClass', 'id': 'myId'})
*/
Node.prototype.append = function append(node) {
this.appendChild(node);
return this;
};
/**
* Allow NodeList and HTMLCollection to have forEach.
*
* @example
* document.querySelectorAll('div').forEach(function(node) {
* // ...
* });
*
* document.body.children.forEach(function(node) {
* // ...
* });
*/
NodeList.prototype.forEach = HTMLCollection.prototype.forEach = Array.prototype.forEach;
/**
* Shortcut for removing the attribute 'hidden' from a node.
* @returns {Element}
*/
Element.prototype.show = function(show) {
this.removeAttribute('hidden');
return this;
};
/**
* Shortcut for adding the attribute 'hidden' to a node.
* @returns {Element}
*/
Element.prototype.hide = function() {
this.setAttribute('hidden', true);
return this;
};
})(Node, Element, HTMLCollection, Array);
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment