/** * @class Ext.DomHelper *

The DomHelper class provides a layer of abstraction from DOM and transparently supports creating * elements via DOM or using HTML fragments. It also has the ability to create HTML fragment templates * from your DOM building code.

* *

DomHelper element specification object

*

A specification object is used when creating elements. Attributes of this object * are assumed to be element attributes, except for 4 special attributes: *

* *

Insertion methods

*

Commonly used insertion methods: *

* *

Example

*

This is an example, where an unordered list with 3 children items is appended to an existing * element with id 'my-div':


var dh = Ext.DomHelper; // create shorthand alias
// specification object
var spec = {
    id: 'my-ul',
    tag: 'ul',
    cls: 'my-list',
    // append children after creating
    children: [     // may also specify 'cn' instead of 'children'
        {tag: 'li', id: 'item0', html: 'List Item 0'},
        {tag: 'li', id: 'item1', html: 'List Item 1'},
        {tag: 'li', id: 'item2', html: 'List Item 2'}
    ]
};
var list = dh.append(
    'my-div', // the context element 'my-div' can either be the id or the actual node
    spec      // the specification object
);
 

*

Element creation specification parameters in this class may also be passed as an Array of * specification objects. This can be used to insert multiple sibling nodes into an existing * container very efficiently. For example, to add more list items to the example above:


dh.append('my-ul', [
    {tag: 'li', id: 'item3', html: 'List Item 3'},
    {tag: 'li', id: 'item4', html: 'List Item 4'}
]);
 * 

* *

Templating

*

The real power is in the built-in templating. Instead of creating or appending any elements, * {@link #createTemplate} returns a Template object which can be used over and over to * insert new elements. Revisiting the example above, we could utilize templating this time: *


// create the node
var list = dh.append('my-div', {tag: 'ul', cls: 'my-list'});
// get template
var tpl = dh.createTemplate({tag: 'li', id: 'item{0}', html: 'List Item {0}'});

for(var i = 0; i < 5, i++){
    tpl.append(list, [i]); // use template to append to the actual node
}
 * 

*

An example using a template:


var html = '{2}';

var tpl = new Ext.DomHelper.createTemplate(html);
tpl.append('blog-roll', ['link1', 'http://www.tommymaintz.com/', "Tommy's Site"]);
tpl.append('blog-roll', ['link2', 'http://www.avins.org/', "Jamie's Site"]);
 * 

* *

The same example using named parameters:


var html = '{text}';

var tpl = new Ext.DomHelper.createTemplate(html);
tpl.append('blog-roll', {
    id: 'link1',
    url: 'http://www.tommymaintz.com/',
    text: "Tommy's Site"
});
tpl.append('blog-roll', {
    id: 'link2',
    url: 'http://www.avins.org/',
    text: "Jamie's Site"
});
 * 

* *

Compiling Templates

*

Templates are applied using regular expressions. The performance is great, but if * you are adding a bunch of DOM elements using the same template, you can increase * performance even further by {@link Ext.Template#compile "compiling"} the template. * The way "{@link Ext.Template#compile compile()}" works is the template is parsed and * broken up at the different variable points and a dynamic function is created and eval'ed. * The generated function performs string concatenation of these parts and the passed * variables instead of using regular expressions. *


var html = '{text}';

var tpl = new Ext.DomHelper.createTemplate(html);
tpl.compile();

//... use template like normal
 * 

* *

Performance Boost

*

DomHelper will transparently create HTML fragments when it can. Using HTML fragments instead * of DOM can significantly boost performance.

*

Element creation specification parameters may also be strings. If {@link #useDom} is false, * then the string is used as innerHTML. If {@link #useDom} is true, a string specification * results in the creation of a text node. Usage:

*

Ext.DomHelper.useDom = true; // force it to use DOM; reduces performance
 * 
* @singleton */ Ext.DomHelper = { emptyTags : /^(?:br|frame|hr|img|input|link|meta|range|spacer|wbr|area|param|col)$/i, confRe : /tag|children|cn|html$/i, endRe : /end/i,
/** * Returns the markup for the passed Element(s) config. * @param {Object} o The DOM object spec (and children) * @return {String} */ markup : function(o) { var b = '', attr, val, key, keyVal, cn; if (typeof o == "string") { b = o; } else if (Ext.isArray(o)) { for (var i=0; i < o.length; i++) { if (o[i]) { b += this.markup(o[i]); } }; } else { b += '<' + (o.tag = o.tag || 'div'); for (attr in o) { if (!o.hasOwnProperty(attr)) { continue; } val = o[attr]; if (!this.confRe.test(attr)) { if (typeof val == "object") { b += ' ' + attr + '="'; for (key in val) { if (!val.hasOwnProperty(key)) { continue; } b += key + ':' + val[key] + ';'; }; b += '"'; } else { b += ' ' + ({cls : 'class', htmlFor : 'for'}[attr] || attr) + '="' + val + '"'; } } }; // Now either just close the tag or try to add children and close the tag. if (this.emptyTags.test(o.tag)) { b += '/>'; } else { b += '>'; if ((cn = o.children || o.cn)) { b += this.markup(cn); } else if (o.html) { b += o.html; } b += ''; } } return b; },
/** * Applies a style specification to an element. * @param {String/HTMLElement} el The element to apply styles to * @param {String/Object/Function} styles A style specification string e.g. 'width:100px', or object in the form {width:'100px'}, or * a function which returns such a specification. */ applyStyles : function(el, styles) { if (styles) { var i = 0, len, style; el = Ext.fly(el); if (typeof styles == 'function') { styles = styles.call(); } if (typeof styles == 'string'){ styles = Ext.util.Format.trim(styles).split(/\s*(?::|;)\s*/); for(len = styles.length; i < len;){ el.setStyle(styles[i++], styles[i++]); } } else if (Ext.isObject(styles)) { el.setStyle(styles); } } },
/** * Inserts an HTML fragment into the DOM. * @param {String} where Where to insert the html in relation to el - beforeBegin, afterBegin, beforeEnd, afterEnd. * @param {HTMLElement} el The context element * @param {String} html The HTML fragment * @return {HTMLElement} The new node */ insertHtml : function(where, el, html) { var hash = {}, hashVal, setStart, range, frag, rangeEl, rs; where = where.toLowerCase(); // add these here because they are used in both branches of the condition. hash['beforebegin'] = ['BeforeBegin', 'previousSibling']; hash['afterend'] = ['AfterEnd', 'nextSibling']; range = el.ownerDocument.createRange(); setStart = 'setStart' + (this.endRe.test(where) ? 'After' : 'Before'); if (hash[where]) { range[setStart](el); frag = range.createContextualFragment(html); el.parentNode.insertBefore(frag, where == 'beforebegin' ? el : el.nextSibling); return el[(where == 'beforebegin' ? 'previous' : 'next') + 'Sibling']; } else { rangeEl = (where == 'afterbegin' ? 'first' : 'last') + 'Child'; if (el.firstChild) { range[setStart](el[rangeEl]); frag = range.createContextualFragment(html); if (where == 'afterbegin') { el.insertBefore(frag, el.firstChild); } else { el.appendChild(frag); } } else { el.innerHTML = html; } return el[rangeEl]; } throw 'Illegal insertion point -> "' + where + '"'; },
/** * Creates new DOM element(s) and inserts them before el. * @param {Mixed} el The context element * @param {Object/String} o The DOM object spec (and children) or raw HTML blob * @param {Boolean} returnElement (optional) true to return a Ext.Element * @return {HTMLElement/Ext.Element} The new node */ insertBefore : function(el, o, returnElement) { return this.doInsert(el, o, returnElement, 'beforebegin'); },
/** * Creates new DOM element(s) and inserts them after el. * @param {Mixed} el The context element * @param {Object} o The DOM object spec (and children) * @param {Boolean} returnElement (optional) true to return a Ext.Element * @return {HTMLElement/Ext.Element} The new node */ insertAfter : function(el, o, returnElement) { return this.doInsert(el, o, returnElement, 'afterend', 'nextSibling'); },
/** * Creates new DOM element(s) and inserts them as the first child of el. * @param {Mixed} el The context element * @param {Object/String} o The DOM object spec (and children) or raw HTML blob * @param {Boolean} returnElement (optional) true to return a Ext.Element * @return {HTMLElement/Ext.Element} The new node */ insertFirst : function(el, o, returnElement) { return this.doInsert(el, o, returnElement, 'afterbegin', 'firstChild'); },
/** * Creates new DOM element(s) and appends them to el. * @param {Mixed} el The context element * @param {Object/String} o The DOM object spec (and children) or raw HTML blob * @param {Boolean} returnElement (optional) true to return a Ext.Element * @return {HTMLElement/Ext.Element} The new node */ append : function(el, o, returnElement) { return this.doInsert(el, o, returnElement, 'beforeend', '', true); },
/** * Creates new DOM element(s) and overwrites the contents of el with them. * @param {Mixed} el The context element * @param {Object/String} o The DOM object spec (and children) or raw HTML blob * @param {Boolean} returnElement (optional) true to return a Ext.Element * @return {HTMLElement/Ext.Element} The new node */ overwrite : function(el, o, returnElement) { el = Ext.getDom(el); el.innerHTML = this.markup(o); return returnElement ? Ext.get(el.firstChild) : el.firstChild; }, doInsert : function(el, o, returnElement, pos, sibling, append) { var newNode = this.insertHtml(pos, Ext.getDom(el), this.markup(o)); return returnElement ? Ext.get(newNode, true) : newNode; } };