Last active
January 28, 2016 20:06
-
-
Save Error601/7a86fa6e34fbc98b31a6 to your computer and use it in GitHub Desktop.
Generate HTML elements, returning a jQuery object for the outermost element
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
/*! | |
* Create HTML elements from a config object | |
* https://gist.github.com/Error601/7a86fa6e34fbc98b31a6 | |
*/ | |
if (typeof jQuery == 'undefined') { | |
throw new Error('jQuery is required'); | |
} | |
(function($, undefined){ | |
function isElement(it){ | |
return it.nodeType && it.nodeType === 1; | |
} | |
function isFragment(it){ | |
return it.nodeType && it.nodeType === 11; | |
} | |
// returns first defined argument | |
// useful for retrieving 'falsey' values | |
function firstDefined() { | |
var undefined, i = -1; | |
while (++i < arguments.length) { | |
if (arguments[i] !== undefined) { | |
return arguments[i]; | |
} | |
} | |
return undefined; | |
} | |
// attach to global jQuery $ object | |
// (since it uses jQuery) | |
// usage: | |
// var $div1 = $.spawn('div|id:div1', {addClass: 'foo'}, {name: 'bar'}, [$p1, $p2, $p3]); | |
// var $div2 = $.spawn('div'), {}, {id:'div2'}, "Div2's HTML content") | |
/** | |
* Create a jQuery-wrapped DOM object | |
* @param tag - HTML tag | |
* @param opts - jQuery methods / child element(s) / HTML | |
* @param attr - native DOM attributes | |
* @param content - child element(s) / HTML | |
* @returns {object} - jQuery object | |
*/ | |
$.spawn = function(tag, opts, attr, content){ | |
var el, $el, parts, _opts={}, attrs, _attr={}; | |
// return jQuery-wrapped fragment | |
// if called with no arguments | |
if (typeof tag === 'undefined') { | |
return $(document.createDocumentFragment()); | |
} | |
// stop and return if it's | |
// already a jQuery object | |
if (tag && tag.jquery) { | |
return tag; | |
} | |
if ($.isPlainObject(tag)) { | |
opts = tag; | |
tag = firstDefined(opts.tag||undefined, null); | |
} | |
// trim outer white space and remove any trailing semicolons or commas | |
parts = tag.trim().replace(/(;|,)$/,'').split('|'); | |
tag = parts[0].trim(); | |
// pass empty string or #text as | |
// first argument to create fragment | |
if (tag === '' || tag === '#text'){ | |
el = document.createDocumentFragment(); | |
} | |
else { | |
try { | |
el = document.createElement(tag||'span'); | |
} | |
catch(e){ | |
if (console && console.log) console.log(e); | |
el = document.createDocumentFragment(); | |
el = el.appendChild(document.createTextNode(tag||'')); | |
} | |
} | |
// pass element attributes in 'tag' string, like: | |
// $.spawn('a|id="foo-link";href="foo";class="bar"'); | |
// or (colons for separators, commas for delimeters, no quotes),: | |
// $.spawn('input|type:checkbox,id:foo-ckbx'); | |
attrs = (parts[1]||'').split(/;|,/) || []; // allow ';' or ',' for attribute delimeter | |
attrs.forEach(function(att){ | |
if (!att) return; | |
var sep = /:|=/; // allow ':' or '=' for key/value separator | |
var quotes = /^('|")|('|")$/g; | |
var key = att.split(sep)[0].trim(); | |
var val = (att.split(sep)[1]||'').trim().replace(quotes, '') || key; | |
// add each attribute/property directly to DOM element | |
el[key] = val; | |
}); | |
$el = $(el); | |
if (attr) { | |
if ($.isPlainObject(attr)){ | |
// pull out the 'prop' properties | |
if (attr.prop){ | |
$el.prop(attr.prop); | |
delete attr.prop; | |
} | |
} | |
try { | |
// could be an object map of multiple attributes | |
// or could be an array for a single attribute - ['name','foo'] | |
$el.attr.apply($el, [].concat(attr)); | |
} | |
catch(e){ | |
if (console && console.log) console.log(e); | |
} | |
} | |
if (typeof opts == 'undefined') { | |
return $el; | |
} | |
opts = opts || {}; | |
// just append an HTML string, jQuery object, element, or fragment | |
if (typeof opts == 'string' || opts.jquery || isElement(opts) || isFragment(opts)){ | |
return $el.append(opts); | |
} | |
// if 'opts' is an array, they | |
// will be child elements | |
if ($.isArray(opts)) { | |
_opts.children = opts; | |
} | |
// otherwise it's a config object | |
if ($.isPlainObject(opts)) { | |
_opts = $.extend(true, {}, opts); | |
} | |
// a fourth argument can contain additional content | |
if (content){ | |
_opts.content = [].concat(_opts.content||[], content); | |
} | |
$.each(_opts, function(prop, val){ | |
// skip 'tag' property | |
if (prop === 'tag') return; | |
// special handling for 'id' property | |
if (prop === 'id'){ | |
el.id = val; | |
return; | |
} | |
// special handling for 'class', 'className', or 'classes' property | |
// accepts a className string or array of separate class names | |
if (/^(class|classes|className|classNames)$/.test(prop)){ | |
el.className = [].concat(val).join(' ').replace(/\s+/g, ' ').trim(); | |
return; | |
} | |
// 'element' (or 'el') property contains | |
// items to attach natively | |
// to the new element | |
// (without jQuery) | |
if (/^(element|el)$/.test(prop)){ | |
$.each(val, function(name, value){ | |
el[name] = value; | |
}); | |
return; | |
} | |
// 'children' property is | |
// an array of elements | |
// to be spawned | |
if (/^(children|content|contents)$/.test(prop)) { | |
$.each([].concat(val), function(i, child){ | |
try { | |
// recursively append spawns as needed | |
$el.append(child); // each child must be an 'appendable' item | |
//$.spawn(child).appendTo($el); | |
//$el.append($.spawn.apply(null, [].concat(child))); | |
} | |
catch (e) { | |
if (console && console.log) console.log(e); | |
} | |
}); | |
return; | |
} | |
// accept event handlers with varying | |
// number of arguments | |
if (/^(on|off)$/.test(prop)){ | |
$.each(val, function(evt, args){ | |
try { | |
$el[prop].apply($el, [evt].concat(args)); | |
} | |
catch(e){ | |
if (console && console.log) console.log(e); | |
} | |
}); | |
return; | |
} | |
// otherwise root property names will be | |
// treated as jQuery methods | |
try { | |
$el[prop].apply($el, [].concat(val)); | |
} | |
catch (e) { | |
if (console && console.log) console.log(e); | |
} | |
}); | |
// raw element available in the | |
// 'element' property of returned | |
// jQuery object | |
$el.element = el; | |
return $el; | |
}; | |
})(jQuery); |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment