DomHelper.js
上传用户:dawnssy
上传日期:2022-08-06
资源大小:9345k
文件大小:17k
源码类别:

JavaScript

开发平台:

JavaScript

  1. /*!  * Ext JS Library 3.1.0  * Copyright(c) 2006-2009 Ext JS, LLC  * licensing@extjs.com  * http://www.extjs.com/license  */ /**
  2.  * @class Ext.DomHelper
  3.  * <p>The DomHelper class provides a layer of abstraction from DOM and transparently supports creating
  4.  * elements via DOM or using HTML fragments. It also has the ability to create HTML fragment templates
  5.  * from your DOM building code.</p>
  6.  *
  7.  * <p><b><u>DomHelper element specification object</u></b></p>
  8.  * <p>A specification object is used when creating elements. Attributes of this object
  9.  * are assumed to be element attributes, except for 4 special attributes:
  10.  * <div class="mdetail-params"><ul>
  11.  * <li><b><tt>tag</tt></b> : <div class="sub-desc">The tag name of the element</div></li>
  12.  * <li><b><tt>children</tt></b> : or <tt>cn</tt><div class="sub-desc">An array of the
  13.  * same kind of element definition objects to be created and appended. These can be nested
  14.  * as deep as you want.</div></li>
  15.  * <li><b><tt>cls</tt></b> : <div class="sub-desc">The class attribute of the element.
  16.  * This will end up being either the "class" attribute on a HTML fragment or className
  17.  * for a DOM node, depending on whether DomHelper is using fragments or DOM.</div></li>
  18.  * <li><b><tt>html</tt></b> : <div class="sub-desc">The innerHTML for the element</div></li>
  19.  * </ul></div></p>
  20.  *
  21.  * <p><b><u>Insertion methods</u></b></p>
  22.  * <p>Commonly used insertion methods:
  23.  * <div class="mdetail-params"><ul>
  24.  * <li><b><tt>{@link #append}</tt></b> : <div class="sub-desc"></div></li>
  25.  * <li><b><tt>{@link #insertBefore}</tt></b> : <div class="sub-desc"></div></li>
  26.  * <li><b><tt>{@link #insertAfter}</tt></b> : <div class="sub-desc"></div></li>
  27.  * <li><b><tt>{@link #overwrite}</tt></b> : <div class="sub-desc"></div></li>
  28.  * <li><b><tt>{@link #createTemplate}</tt></b> : <div class="sub-desc"></div></li>
  29.  * <li><b><tt>{@link #insertHtml}</tt></b> : <div class="sub-desc"></div></li>
  30.  * </ul></div></p>
  31.  *
  32.  * <p><b><u>Example</u></b></p>
  33.  * <p>This is an example, where an unordered list with 3 children items is appended to an existing
  34.  * element with id <tt>'my-div'</tt>:<br>
  35.  <pre><code>
  36. var dh = Ext.DomHelper; // create shorthand alias
  37. // specification object
  38. var spec = {
  39.     id: 'my-ul',
  40.     tag: 'ul',
  41.     cls: 'my-list',
  42.     // append children after creating
  43.     children: [     // may also specify 'cn' instead of 'children'
  44.         {tag: 'li', id: 'item0', html: 'List Item 0'},
  45.         {tag: 'li', id: 'item1', html: 'List Item 1'},
  46.         {tag: 'li', id: 'item2', html: 'List Item 2'}
  47.     ]
  48. };
  49. var list = dh.append(
  50.     'my-div', // the context element 'my-div' can either be the id or the actual node
  51.     spec      // the specification object
  52. );
  53.  </code></pre></p>
  54.  * <p>Element creation specification parameters in this class may also be passed as an Array of
  55.  * specification objects. This can be used to insert multiple sibling nodes into an existing
  56.  * container very efficiently. For example, to add more list items to the example above:<pre><code>
  57. dh.append('my-ul', [
  58.     {tag: 'li', id: 'item3', html: 'List Item 3'},
  59.     {tag: 'li', id: 'item4', html: 'List Item 4'}
  60. ]);
  61.  * </code></pre></p>
  62.  *
  63.  * <p><b><u>Templating</u></b></p>
  64.  * <p>The real power is in the built-in templating. Instead of creating or appending any elements,
  65.  * <tt>{@link #createTemplate}</tt> returns a Template object which can be used over and over to
  66.  * insert new elements. Revisiting the example above, we could utilize templating this time:
  67.  * <pre><code>
  68. // create the node
  69. var list = dh.append('my-div', {tag: 'ul', cls: 'my-list'});
  70. // get template
  71. var tpl = dh.createTemplate({tag: 'li', id: 'item{0}', html: 'List Item {0}'});
  72. for(var i = 0; i < 5, i++){
  73.     tpl.append(list, [i]); // use template to append to the actual node
  74. }
  75.  * </code></pre></p>
  76.  * <p>An example using a template:<pre><code>
  77. var html = '<a id="{0}" href="{1}" class="nav">{2}</a>';
  78. var tpl = new Ext.DomHelper.createTemplate(html);
  79. tpl.append('blog-roll', ['link1', 'http://www.jackslocum.com/', "Jack&#39;s Site"]);
  80. tpl.append('blog-roll', ['link2', 'http://www.dustindiaz.com/', "Dustin&#39;s Site"]);
  81.  * </code></pre></p>
  82.  *
  83.  * <p>The same example using named parameters:<pre><code>
  84. var html = '<a id="{id}" href="{url}" class="nav">{text}</a>';
  85. var tpl = new Ext.DomHelper.createTemplate(html);
  86. tpl.append('blog-roll', {
  87.     id: 'link1',
  88.     url: 'http://www.jackslocum.com/',
  89.     text: "Jack&#39;s Site"
  90. });
  91. tpl.append('blog-roll', {
  92.     id: 'link2',
  93.     url: 'http://www.dustindiaz.com/',
  94.     text: "Dustin&#39;s Site"
  95. });
  96.  * </code></pre></p>
  97.  *
  98.  * <p><b><u>Compiling Templates</u></b></p>
  99.  * <p>Templates are applied using regular expressions. The performance is great, but if
  100.  * you are adding a bunch of DOM elements using the same template, you can increase
  101.  * performance even further by {@link Ext.Template#compile "compiling"} the template.
  102.  * The way "{@link Ext.Template#compile compile()}" works is the template is parsed and
  103.  * broken up at the different variable points and a dynamic function is created and eval'ed.
  104.  * The generated function performs string concatenation of these parts and the passed
  105.  * variables instead of using regular expressions.
  106.  * <pre><code>
  107. var html = '<a id="{id}" href="{url}" class="nav">{text}</a>';
  108. var tpl = new Ext.DomHelper.createTemplate(html);
  109. tpl.compile();
  110. //... use template like normal
  111.  * </code></pre></p>
  112.  *
  113.  * <p><b><u>Performance Boost</u></b></p>
  114.  * <p>DomHelper will transparently create HTML fragments when it can. Using HTML fragments instead
  115.  * of DOM can significantly boost performance.</p>
  116.  * <p>Element creation specification parameters may also be strings. If {@link #useDom} is <tt>false</tt>,
  117.  * then the string is used as innerHTML. If {@link #useDom} is <tt>true</tt>, a string specification
  118.  * results in the creation of a text node. Usage:</p>
  119.  * <pre><code>
  120. Ext.DomHelper.useDom = true; // force it to use DOM; reduces performance
  121.  * </code></pre>
  122.  * @singleton
  123.  */
  124. Ext.DomHelper = function(){
  125.     var tempTableEl = null,
  126.         emptyTags = /^(?:br|frame|hr|img|input|link|meta|range|spacer|wbr|area|param|col)$/i,
  127.         tableRe = /^table|tbody|tr|td$/i,
  128.         pub,
  129.         // kill repeat to save bytes
  130.         afterbegin = 'afterbegin',
  131.         afterend = 'afterend',
  132.         beforebegin = 'beforebegin',
  133.         beforeend = 'beforeend',
  134.         ts = '<table>',
  135.         te = '</table>',
  136.         tbs = ts+'<tbody>',
  137.         tbe = '</tbody>'+te,
  138.         trs = tbs + '<tr>',
  139.         tre = '</tr>'+tbe;
  140.     // private
  141.     function doInsert(el, o, returnElement, pos, sibling, append){
  142.         var newNode = pub.insertHtml(pos, Ext.getDom(el), createHtml(o));
  143.         return returnElement ? Ext.get(newNode, true) : newNode;
  144.     }
  145.     // build as innerHTML where available
  146.     function createHtml(o){
  147.         var b = '',
  148.             attr,
  149.             val,
  150.             key,
  151.             keyVal,
  152.             cn;
  153.         if(Ext.isString(o)){
  154.             b = o;
  155.         } else if (Ext.isArray(o)) {
  156.             for (var i=0; i < o.length; i++) {
  157.                 if(o[i]) {
  158.                     b += createHtml(o[i]);
  159.                 }
  160.             };
  161.         } else {
  162.             b += '<' + (o.tag = o.tag || 'div');
  163.             Ext.iterate(o, function(attr, val){
  164.                 if(!/tag|children|cn|html$/i.test(attr)){
  165.                     if (Ext.isObject(val)) {
  166.                         b += ' ' + attr + '="';
  167.                         Ext.iterate(val, function(key, keyVal){
  168.                             b += key + ':' + keyVal + ';';
  169.                         });
  170.                         b += '"';
  171.                     }else{
  172.                         b += ' ' + ({cls : 'class', htmlFor : 'for'}[attr] || attr) + '="' + val + '"';
  173.                     }
  174.                 }
  175.             });
  176.             // Now either just close the tag or try to add children and close the tag.
  177.             if (emptyTags.test(o.tag)) {
  178.                 b += '/>';
  179.             } else {
  180.                 b += '>';
  181.                 if ((cn = o.children || o.cn)) {
  182.                     b += createHtml(cn);
  183.                 } else if(o.html){
  184.                     b += o.html;
  185.                 }
  186.                 b += '</' + o.tag + '>';
  187.             }
  188.         }
  189.         return b;
  190.     }
  191.     function ieTable(depth, s, h, e){
  192.         tempTableEl.innerHTML = [s, h, e].join('');
  193.         var i = -1,
  194.             el = tempTableEl,
  195.             ns;
  196.         while(++i < depth){
  197.             el = el.firstChild;
  198.         }
  199. //      If the result is multiple siblings, then encapsulate them into one fragment.
  200.         if(ns = el.nextSibling){
  201.             var df = document.createDocumentFragment();
  202.             while(el){
  203.                 ns = el.nextSibling;
  204.                 df.appendChild(el);
  205.                 el = ns;
  206.             }
  207.             el = df;
  208.         }
  209.         return el;
  210.     }
  211.     /**
  212.      * @ignore
  213.      * Nasty code for IE's broken table implementation
  214.      */
  215.     function insertIntoTable(tag, where, el, html) {
  216.         var node,
  217.             before;
  218.         tempTableEl = tempTableEl || document.createElement('div');
  219.         if(tag == 'td' && (where == afterbegin || where == beforeend) ||
  220.            !/td|tr|tbody/i.test(tag) && (where == beforebegin || where == afterend)) {
  221.             return;
  222.         }
  223.         before = where == beforebegin ? el :
  224.                  where == afterend ? el.nextSibling :
  225.                  where == afterbegin ? el.firstChild : null;
  226.         if (where == beforebegin || where == afterend) {
  227.             el = el.parentNode;
  228.         }
  229.         if (tag == 'td' || (tag == 'tr' && (where == beforeend || where == afterbegin))) {
  230.             node = ieTable(4, trs, html, tre);
  231.         } else if ((tag == 'tbody' && (where == beforeend || where == afterbegin)) ||
  232.                    (tag == 'tr' && (where == beforebegin || where == afterend))) {
  233.             node = ieTable(3, tbs, html, tbe);
  234.         } else {
  235.             node = ieTable(2, ts, html, te);
  236.         }
  237.         el.insertBefore(node, before);
  238.         return node;
  239.     }
  240.     pub = {
  241.         /**
  242.          * Returns the markup for the passed Element(s) config.
  243.          * @param {Object} o The DOM object spec (and children)
  244.          * @return {String}
  245.          */
  246.         markup : function(o){
  247.             return createHtml(o);
  248.         },
  249.         
  250.         /**
  251.          * Applies a style specification to an element.
  252.          * @param {String/HTMLElement} el The element to apply styles to
  253.          * @param {String/Object/Function} styles A style specification string e.g. 'width:100px', or object in the form {width:'100px'}, or
  254.          * a function which returns such a specification.
  255.          */
  256.         applyStyles : function(el, styles){
  257.             if(styles){
  258.                 var i = 0,
  259.                     len,
  260.                     style;
  261.                 el = Ext.fly(el);
  262.                 if(Ext.isFunction(styles)){
  263.                     styles = styles.call();
  264.                 }
  265.                 if(Ext.isString(styles)){
  266.                     styles = styles.trim().split(/s*(?::|;)s*/);
  267.                     for(len = styles.length; i < len;){
  268.                         el.setStyle(styles[i++], styles[i++]);
  269.                     }
  270.                 }else if (Ext.isObject(styles)){
  271.                     el.setStyle(styles);
  272.                 }
  273.             }
  274.         },
  275.         /**
  276.          * Inserts an HTML fragment into the DOM.
  277.          * @param {String} where Where to insert the html in relation to el - beforeBegin, afterBegin, beforeEnd, afterEnd.
  278.          * @param {HTMLElement} el The context element
  279.          * @param {String} html The HTML fragment
  280.          * @return {HTMLElement} The new node
  281.          */
  282.         insertHtml : function(where, el, html){
  283.             var hash = {},
  284.                 hashVal,
  285.                 setStart,
  286.                 range,
  287.                 frag,
  288.                 rangeEl,
  289.                 rs;
  290.             where = where.toLowerCase();
  291.             // add these here because they are used in both branches of the condition.
  292.             hash[beforebegin] = ['BeforeBegin', 'previousSibling'];
  293.             hash[afterend] = ['AfterEnd', 'nextSibling'];
  294.             if (el.insertAdjacentHTML) {
  295.                 if(tableRe.test(el.tagName) && (rs = insertIntoTable(el.tagName.toLowerCase(), where, el, html))){
  296.                     return rs;
  297.                 }
  298.                 // add these two to the hash.
  299.                 hash[afterbegin] = ['AfterBegin', 'firstChild'];
  300.                 hash[beforeend] = ['BeforeEnd', 'lastChild'];
  301.                 if ((hashVal = hash[where])) {
  302.                     el.insertAdjacentHTML(hashVal[0], html);
  303.                     return el[hashVal[1]];
  304.                 }
  305.             } else {
  306.                 range = el.ownerDocument.createRange();
  307.                 setStart = 'setStart' + (/end/i.test(where) ? 'After' : 'Before');
  308.                 if (hash[where]) {
  309.                     range[setStart](el);
  310.                     frag = range.createContextualFragment(html);
  311.                     el.parentNode.insertBefore(frag, where == beforebegin ? el : el.nextSibling);
  312.                     return el[(where == beforebegin ? 'previous' : 'next') + 'Sibling'];
  313.                 } else {
  314.                     rangeEl = (where == afterbegin ? 'first' : 'last') + 'Child';
  315.                     if (el.firstChild) {
  316.                         range[setStart](el[rangeEl]);
  317.                         frag = range.createContextualFragment(html);
  318.                         if(where == afterbegin){
  319.                             el.insertBefore(frag, el.firstChild);
  320.                         }else{
  321.                             el.appendChild(frag);
  322.                         }
  323.                     } else {
  324.                         el.innerHTML = html;
  325.                     }
  326.                     return el[rangeEl];
  327.                 }
  328.             }
  329.             throw 'Illegal insertion point -> "' + where + '"';
  330.         },
  331.         /**
  332.          * Creates new DOM element(s) and inserts them before el.
  333.          * @param {Mixed} el The context element
  334.          * @param {Object/String} o The DOM object spec (and children) or raw HTML blob
  335.          * @param {Boolean} returnElement (optional) true to return a Ext.Element
  336.          * @return {HTMLElement/Ext.Element} The new node
  337.          */
  338.         insertBefore : function(el, o, returnElement){
  339.             return doInsert(el, o, returnElement, beforebegin);
  340.         },
  341.         /**
  342.          * Creates new DOM element(s) and inserts them after el.
  343.          * @param {Mixed} el The context element
  344.          * @param {Object} o The DOM object spec (and children)
  345.          * @param {Boolean} returnElement (optional) true to return a Ext.Element
  346.          * @return {HTMLElement/Ext.Element} The new node
  347.          */
  348.         insertAfter : function(el, o, returnElement){
  349.             return doInsert(el, o, returnElement, afterend, 'nextSibling');
  350.         },
  351.         /**
  352.          * Creates new DOM element(s) and inserts them as the first child of el.
  353.          * @param {Mixed} el The context element
  354.          * @param {Object/String} o The DOM object spec (and children) or raw HTML blob
  355.          * @param {Boolean} returnElement (optional) true to return a Ext.Element
  356.          * @return {HTMLElement/Ext.Element} The new node
  357.          */
  358.         insertFirst : function(el, o, returnElement){
  359.             return doInsert(el, o, returnElement, afterbegin, 'firstChild');
  360.         },
  361.         /**
  362.          * Creates new DOM element(s) and appends them to el.
  363.          * @param {Mixed} el The context element
  364.          * @param {Object/String} o The DOM object spec (and children) or raw HTML blob
  365.          * @param {Boolean} returnElement (optional) true to return a Ext.Element
  366.          * @return {HTMLElement/Ext.Element} The new node
  367.          */
  368.         append : function(el, o, returnElement){
  369.             return doInsert(el, o, returnElement, beforeend, '', true);
  370.         },
  371.         /**
  372.          * Creates new DOM element(s) and overwrites the contents of el with them.
  373.          * @param {Mixed} el The context element
  374.          * @param {Object/String} o The DOM object spec (and children) or raw HTML blob
  375.          * @param {Boolean} returnElement (optional) true to return a Ext.Element
  376.          * @return {HTMLElement/Ext.Element} The new node
  377.          */
  378.         overwrite : function(el, o, returnElement){
  379.             el = Ext.getDom(el);
  380.             el.innerHTML = createHtml(o);
  381.             return returnElement ? Ext.get(el.firstChild) : el.firstChild;
  382.         },
  383.         createHtml : createHtml
  384.     };
  385.     return pub;
  386. }();