Skip to content

Instantly share code, notes, and snippets.

@spiralx
Last active February 23, 2018 11:06
Show Gist options
  • Save spiralx/773bac30884db9028313758c0621f14a to your computer and use it in GitHub Desktop.
Save spiralx/773bac30884db9028313758c0621f14a to your computer and use it in GitHub Desktop.
Simple element builder function
/**
* A simple HTML element builder function.
* @module EL
* @license MIT
* @author James Skinner <spiralx@gmail>
* @see {@link https://github.com/spiralx My GitHub profile}
*/
// UMD wrapper to support CommonJS and AMD as well as the browser
(function(root, factory) {
if (typeof define === 'function' && define.amd) {
define(factory)
}
else if (typeof exports === 'object') {
module.exports = factory()
}
else {
root.EL = factory()
}
})(this, function factory() {
'use strict'
/**
* Function to generate HTML elements.
*
* @example
* // returns "<div id="main"><div class="container"><section class="comment body"></section></div></div>"
* EL('#main', [ '.container', [ 'section.comment.body' ] ]).outerHTML
*
* @example
* // returns "<div class="panel"><div class="panel-header"><a href="/"><h1 id="title">TITLE</h1><br>Subtitle</a></div></div>"
* EL('.panel', [ '.panel-header', [ 'a', { href: '/' }, [ 'h1#title', 'TITLE' ], [ 'br' ], 'Subtitle' ] ]).outerHTML
*
* @example
* // returns "<a id="home" class="button raised" href="/" style="font-weight: bold;">Link</a>"
* EL('a#home.button.raised', { href: '/', style: { 'font-weight': 'bold' } }, 'Link').outerHTML
*
* @example
* // returns "<div class="content"><div class="section">Lorem ipsum</div><hr class="thick width50"><div class="section">dolor est</div></div>"
* let hr = document.createElement('hr')
* hr.className = 'thick width50'
* EL('.content', [ '.section', 'Lorem ipsum' ], hr, [ '.section', 'dolor est' ]).outerHTML
*
* @example
* // returns "<li><form><label id="qt">Loading search... please wait.</label><br><input id="qh" type="hidden"><input id="qh2" type="hidden"><input id="q" disabled="" size="20"><input id="qb" type="button" value="Search" disabled=""></form></li>"
* EL('li', [
* 'form',
* [ 'label#qt', 'Loading search... please wait.' ],
* [ 'br' ],
* [ 'input#qh', { type: 'hidden' } ],
* [ 'input#qh2', { type: 'hidden' } ],
* [ 'input#q', { disabled: true, size: 20 } ],
* [ 'input#qb', { type: 'button', value: 'Search', disabled: true } ],
* ]).outerHTML
*
* @param {string} [defn=div] Defines the element and optionally its ID and class(es), format is:
* [TAG_NAME=div]?[#ID]?[.CLASS_NAME]*[#ID]?
*
* @param {Object} [properties] For each name, value pair set the property name of the element to value
* to set properties on the `dataset` and `style` properties respectively
* @param {Object} [properties.data] Each name and value pair is applied to the element's dataset property
* @param {Object} [properties.style] Each name and value pair is applied to the element's style property
*
* @param {...(string|Array|HTMLElement)} children Each param defines a child of the constructed element, as either a text node or
* HTML element for string and HTMLElement parameters respectively, or for an
* array parameter, it's items are used as the arguments to EL, and the result
* then used as the child.
* @returns {HTMLElement}
*/
function EL(defn = 'div', properties = {}, ...children) {
const m = defn.split(/\b(?=[\.#])/g)
const tag = m[0].startsWith('#') || m[0].startsWith('.')
? 'div'
: m.shift()
const element = document.createElement(tag || 'div')
m.forEach(v => {
if (v[0] === '.') {
element.classList.add(v.substr(1))
}
else if (v[0] === '#') {
element.id = v.substr(1)
}
})
if (Object.getPrototypeOf(properties) === Object.prototype) {
const { data = {}, style = {}, ...props } = properties
Object.assign(element.dataset, data)
Object.assign(element.style, style)
Object.assign(element, props)
} else {
children.unshift(properties)
}
for (let child of children) {
if (typeof child === 'string') {
child = document.createTextNode(child)
} else if (Array.isArray(child)) {
child = EL(...child)
} else if (!(child instanceof HTMLElement)) {
throw new TypeError(`Unknown child type`)
}
element.appendChild(child)
}
return element
}
return EL
})
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment