dombuilder.js | |||||
|---|---|---|---|---|---|
| DOMBuilder is a tiny JavaScript class for generating DOM nodes on-the-fly. It is designed around a few basic goals:
Browser SupportDOMBuilder has been tested in the following browsers:
The JavaScript used isn't all that complex, so I would expect that DOMBuilder supports other/older browsers as well. I would encourage you to run the unit tests in your browser and let me know about any failing tests and which browser/version you're running. LicenseDOMBuilder is copyright (c) 2009-2011 Ryan Parman, and released for use under the open-source 3-clause BSD License. Downloads(Right-click, and use "Save As")
| /*
## HTML to generate:
<div id="test" class="sample">
<p>This is a <a href="">sample of the code</a> that you may like.</p>
<p>And another <a href="#"><strong>complex-ish</strong></a> one.</p>
<ul class="sample">
<li><a href="http://google.com">One</a></li>
<li><em>Two</em></li>
<li><strong>Three</strong></li>
</ul>
</div>
## DOMBuilder code:
var _ = DOMBuilder,
$body = document.body;
$body.a = $body.appendChild;
$body.a(_.DOM(
_('div#test.sample')._([
_('p').H('This is a <a href="">sample of the code</a> that you may like.'),
_('p').H('And another <a href="#"><strong>complex-ish</strong></a> one.'),
_('ul.sample')._([
_('li')._(_('a', { 'href':'http://google.com' }).html('One')),
_('li')._(_('em').html('Two')),
_('li')._(_('strong').html('Three'))
])
])
));
*/ | ||||
Digging into code | | ||||
| Settings for Google Closure Compiler. | /*
==ClosureCompiler==
@compilation_level SIMPLE_OPTIMIZATIONS
==/ClosureCompiler==
*/ | ||||
| Settings for JSLint or JSHint. | /*jslint white: false, onevar: true, browser: true, undef: true, nomen: false, eqeqeq: true, plusplus: false, bitwise: true, regexp: true, strict: false, newcap: true, immed: false */
/*global window */ | ||||
| Do everything in a localized scope. We'll expose pieces to the global scope later. | (function() { | ||||
DOMBuilderAccepts a string representation of a tag name for the element parameter, and a JSON hash of key-value pairs for the attributes parameter. Returns a self-reference to this by default. Provides methods, described below. You can easily shorten this function name by assigning it to a variable.
This | var X = function(elem, attr) { | ||||
| Internally to DOMBuilder, we use very short variable names so that we can squeeze the file size down as small as possible using YUI Compressor or Google Closure Compiler. | var _ = this,
d = document,
dotHashRe = new RegExp("[.#]"),
key; | ||||
| Support CSS/jQuery-style notation for generating elements with IDs and classnames. (Internal-only!) | function notation(elem) {
var attr = { 'class': [] },
dotHashRe = new RegExp("[.#]"),
piece, pieces, elemType, pos, classes;
if (!dotHashRe.test(elem)) {
return {};
}
pieces = elem.split(dotHashRe);
elemType = pieces.shift();
pos = elemType.length;
classes = attr['class'];
for (piece in pieces) {
if (pieces.hasOwnProperty(piece)) {
if (elem[pos] === '#') {
attr.id = pieces[piece];
}
else {
classes.push(pieces[piece]);
}
pos += pieces[piece].length + 1;
}
}
attr['class'] = classes;
if (!attr['class'].length) {
delete attr['class'];
}
return attr;
} | ||||
| Merge the properties of one object with the properties of a second object. (Internal-only!) | function merge_options(o1, o2) {
var o3 = {},
attrname;
for (attrname in o1) {
if (o1.hasOwnProperty(attrname)) {
o3[attrname] = o1[attrname];
}
}
for (attrname in o2) {
if (o2.hasOwnProperty(attrname)) {
o3[attrname] = o2[attrname];
}
}
return o3;
} | ||||
| Merge options into a conglomo-hash! | attr = merge_options(attr, notation(elem)); | ||||
| Construct the element, loop through the list of attributes and add them to the node. Because of
the way that IE works, class names need to be added explicitly via the | if (dotHashRe.test(elem)) {
_.e = d.createElement(elem.split(dotHashRe).shift());
}
else {
_.e = d.createElement(elem);
}
if (attr) {
for (key in attr) {
if (attr.hasOwnProperty(key)) {
if (typeof attr[key] === 'object' && typeof attr[key].length === 'number' && typeof attr[key].splice === 'function') {
attr[key] = attr[key].join(' ');
}
if (key.toString() === 'class') {
_.e.className = attr[key];
}
else {
_.e.setAttribute(key, attr[key]);
}
}
}
} | ||||
.child() or ._()The | _.child = _._ = function(obj) { | ||||
| If the object isn't an array, convert it to an array to maintain a single codepath below. | if (typeof obj !== 'object' || typeof obj.length !== 'number' || typeof obj.splice !== 'function') {
obj = [obj];
} | ||||
| Loop through the indexed array of children. If the node is a | for (var i = 0, max = obj.length; i < max; i++) {
if (typeof obj[i] === 'undefined') {
break;
}
if (typeof obj[i].asDOM !== 'undefined') {
_.e.appendChild(obj[i].asDOM());
}
else {
_.e.appendChild(obj[i]);
}
}
return _;
}; | ||||
.html() or .H()The If you'd prefer to replace the existing Pass no parameters to read back the node as a string of HTML. | _.html = _.H = function(str, replace) { | ||||
| No parameters? Read the value instead. Alias for asHTML(). | if (arguments.length === 0) {
return _.asHTML();
} | ||||
| Determine the default value for | replace = replace || false; | ||||
| Set the value with innerHTML. | if (replace) {
_.e.innerHTML = str;
}
else {
_.e.innerHTML += str;
}
return _;
}; | ||||
.text() or .T()The If you'd prefer to replace the existing content instead, pass a boolean Pass no parameters to read back the node as a string of plain text. | _.text = _.T = function(str) { | ||||
| No parameters? Read the value instead. Alias for asText(). | if (arguments.length === 0) {
return _.asText();
} | ||||
| Set the value | if (_.e.innerText) {
_.e.innerText = str;
}
else {
var text = document.createTextNode(str);
_.e.appendChild(text);
}
return _;
}; | ||||
.asDOM() or .dom()Returns a real DOM node for use with the standard JavaScript DOM methods. When DOMBuilder objects
are passed to the child method, | _.asDOM = _.dom = function() {
return _.e;
}; | ||||
.asHTML() or .html() or .H()Returns the DOM nodes as a string of HTML. It's as simple as that. | _.asHTML = function() {
var t = d.createElement('div');
t.appendChild(_.e);
return t.innerHTML;
}; | ||||
.asText() or .text() or .T()Returns the DOM nodes as a string of plain text. It's as simple as that. | _.asText = function() {
var t = d.createElement('div');
t.appendChild(_.e);
if (t.innerText) {
return t.innerText;
}
else if (t.textContent) {
return t.textContent;
}
};
return _;
}; | ||||
Expose to the global scopePre-instantiate the class on each call so that you never need to use | window.DOMBuilder = function(elem, attr) {
return new X(elem, attr);
}; | ||||
DOM()This is the function that all other If you are passing in multiple sibling nodes without a parent, | window.DOMBuilder.DOM = function(nodes) { | ||||
| Create a document fragment. Grab and loop through the in-memory DOM nodes, and move them to the Document Fragment. | var f = document.createDocumentFragment(), i, max,
n = new X('div')._(nodes).dom().childNodes;
while (n.length) {
f.appendChild(n[0]);
} | ||||
| Return the Document Fragment to the calling method (presumably | return f;
};
})(); | ||||
Change Log1.3Added a number of shortcuts and niceties. Use This release was heavily inspired by DOMBrew. 1.2Added 1.1Simplified the code under the hood. Now runs a little faster and compresses even smaller. Removed the need to instantiate the class, making it easier to alias. Ensured that it passed JSLint. Provided a version minified by Google Closure Compiler. 1.0Made sure that it worked with Internet Explorer 6 & 7. Improved the innards of Pre-1.0Initial pre-release of DOMBuilder. | |