~dongpo-deng/sahana-eden/test

« back to all changes in this revision

Viewing changes to static/scripts/ext-2.2.1/source/core/DomHelper.js

  • Committer: Deng Dongpo
  • Date: 2010-08-01 09:29:44 UTC
  • Revision ID: dongpo@dhcp-21193.iis.sinica.edu.tw-20100801092944-8t9obt4xtl7otesb
initial

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
/*
 
2
 * Ext JS Library 2.2.1
 
3
 * Copyright(c) 2006-2009, Ext JS, LLC.
 
4
 * licensing@extjs.com
 
5
 * 
 
6
 * http://extjs.com/license
 
7
 */
 
8
 
 
9
/**
 
10
 * @class Ext.DomHelper
 
11
 * Utility class for working with DOM and/or Templates. It transparently supports using HTML fragments or DOM.<br>
 
12
 * This is an example, where an unordered list with 5 children items is appended to an existing element with id 'my-div':<br>
 
13
 <pre><code>
 
14
var dh = Ext.DomHelper;
 
15
var list = dh.append('my-div', {
 
16
    id: 'my-ul', tag: 'ul', cls: 'my-list', children: [
 
17
        {tag: 'li', id: 'item0', html: 'List Item 0'},
 
18
        {tag: 'li', id: 'item1', html: 'List Item 1'},
 
19
        {tag: 'li', id: 'item2', html: 'List Item 2'},
 
20
        {tag: 'li', id: 'item3', html: 'List Item 3'},
 
21
        {tag: 'li', id: 'item4', html: 'List Item 4'}
 
22
    ]
 
23
});
 
24
 </code></pre>
 
25
 * <p>Element creation specification parameters in this class may also be passed as an Array of
 
26
 * specification objects. This can be used to insert multiple sibling nodes into an existing
 
27
 * container very efficiently. For example, to add more list items to the example above:<pre><code>
 
28
dh.append('my-ul', [
 
29
    {tag: 'li', id: 'item5', html: 'List Item 5'},
 
30
    {tag: 'li', id: 'item6', html: 'List Item 6'} ]);
 
31
</code></pre></p>
 
32
 * <p>Element creation specification parameters may also be strings. If {@link useDom} is false, then the string is used
 
33
 * as innerHTML. If {@link useDom} is true, a string specification results in the creation of a text node.</p>
 
34
 * For more information and examples, see <a href="http://www.jackslocum.com/blog/2006/10/06/domhelper-create-elements-using-dom-html-fragments-or-templates/">the original blog post</a>.
 
35
 * @singleton
 
36
 */
 
37
Ext.DomHelper = function(){
 
38
    var tempTableEl = null;
 
39
    var emptyTags = /^(?:br|frame|hr|img|input|link|meta|range|spacer|wbr|area|param|col)$/i;
 
40
    var tableRe = /^table|tbody|tr|td$/i;
 
41
 
 
42
    // build as innerHTML where available
 
43
    var createHtml = function(o){
 
44
        if(typeof o == 'string'){
 
45
            return o;
 
46
        }
 
47
        var b = "";
 
48
        if (Ext.isArray(o)) {
 
49
            for (var i = 0, l = o.length; i < l; i++) {
 
50
                b += createHtml(o[i]);
 
51
            }
 
52
            return b;
 
53
        }
 
54
        if(!o.tag){
 
55
            o.tag = "div";
 
56
        }
 
57
        b += "<" + o.tag;
 
58
        for(var attr in o){
 
59
            if(attr == "tag" || attr == "children" || attr == "cn" || attr == "html" || typeof o[attr] == "function") continue;
 
60
            if(attr == "style"){
 
61
                var s = o["style"];
 
62
                if(typeof s == "function"){
 
63
                    s = s.call();
 
64
                }
 
65
                if(typeof s == "string"){
 
66
                    b += ' style="' + s + '"';
 
67
                }else if(typeof s == "object"){
 
68
                    b += ' style="';
 
69
                    for(var key in s){
 
70
                        if(typeof s[key] != "function"){
 
71
                            b += key + ":" + s[key] + ";";
 
72
                        }
 
73
                    }
 
74
                    b += '"';
 
75
                }
 
76
            }else{
 
77
                if(attr == "cls"){
 
78
                    b += ' class="' + o["cls"] + '"';
 
79
                }else if(attr == "htmlFor"){
 
80
                    b += ' for="' + o["htmlFor"] + '"';
 
81
                }else{
 
82
                    b += " " + attr + '="' + o[attr] + '"';
 
83
                }
 
84
            }
 
85
        }
 
86
        if(emptyTags.test(o.tag)){
 
87
            b += "/>";
 
88
        }else{
 
89
            b += ">";
 
90
            var cn = o.children || o.cn;
 
91
            if(cn){
 
92
                b += createHtml(cn);
 
93
            } else if(o.html){
 
94
                b += o.html;
 
95
            }
 
96
            b += "</" + o.tag + ">";
 
97
        }
 
98
        return b;
 
99
    };
 
100
 
 
101
    // build as dom
 
102
    /** @ignore */
 
103
    var createDom = function(o, parentNode){
 
104
        var el;
 
105
        if (Ext.isArray(o)) {                       // Allow Arrays of siblings to be inserted
 
106
            el = document.createDocumentFragment(); // in one shot using a DocumentFragment
 
107
            for(var i = 0, l = o.length; i < l; i++) {
 
108
                createDom(o[i], el);
 
109
            }
 
110
        } else if (typeof o == "string") {         // Allow a string as a child spec.
 
111
            el = document.createTextNode(o);
 
112
        } else {
 
113
            el = document.createElement(o.tag||'div');
 
114
            var useSet = !!el.setAttribute; // In IE some elements don't have setAttribute
 
115
            for(var attr in o){
 
116
                if(attr == "tag" || attr == "children" || attr == "cn" || attr == "html" || attr == "style" || typeof o[attr] == "function") continue;
 
117
                if(attr=="cls"){
 
118
                    el.className = o["cls"];
 
119
                }else{
 
120
                    if(useSet) el.setAttribute(attr, o[attr]);
 
121
                    else el[attr] = o[attr];
 
122
                }
 
123
            }
 
124
            Ext.DomHelper.applyStyles(el, o.style);
 
125
            var cn = o.children || o.cn;
 
126
            if(cn){
 
127
                createDom(cn, el);
 
128
            } else if(o.html){
 
129
                el.innerHTML = o.html;
 
130
            }
 
131
        }
 
132
        if(parentNode){
 
133
           parentNode.appendChild(el);
 
134
        }
 
135
        return el;
 
136
    };
 
137
 
 
138
    var ieTable = function(depth, s, h, e){
 
139
        tempTableEl.innerHTML = [s, h, e].join('');
 
140
        var i = -1, el = tempTableEl;
 
141
        while(++i < depth){
 
142
            el = el.firstChild;
 
143
        }
 
144
        return el;
 
145
    };
 
146
 
 
147
    // kill repeat to save bytes
 
148
    var ts = '<table>',
 
149
        te = '</table>',
 
150
        tbs = ts+'<tbody>',
 
151
        tbe = '</tbody>'+te,
 
152
        trs = tbs + '<tr>',
 
153
        tre = '</tr>'+tbe;
 
154
 
 
155
    /**
 
156
     * @ignore
 
157
     * Nasty code for IE's broken table implementation
 
158
     */
 
159
    var insertIntoTable = function(tag, where, el, html){
 
160
        if(!tempTableEl){
 
161
            tempTableEl = document.createElement('div');
 
162
        }
 
163
        var node;
 
164
        var before = null;
 
165
        if(tag == 'td'){
 
166
            if(where == 'afterbegin' || where == 'beforeend'){ // INTO a TD
 
167
                return;
 
168
            }
 
169
            if(where == 'beforebegin'){
 
170
                before = el;
 
171
                el = el.parentNode;
 
172
            } else{
 
173
                before = el.nextSibling;
 
174
                el = el.parentNode;
 
175
            }
 
176
            node = ieTable(4, trs, html, tre);
 
177
        }
 
178
        else if(tag == 'tr'){
 
179
            if(where == 'beforebegin'){
 
180
                before = el;
 
181
                el = el.parentNode;
 
182
                node = ieTable(3, tbs, html, tbe);
 
183
            } else if(where == 'afterend'){
 
184
                before = el.nextSibling;
 
185
                el = el.parentNode;
 
186
                node = ieTable(3, tbs, html, tbe);
 
187
            } else{ // INTO a TR
 
188
                if(where == 'afterbegin'){
 
189
                    before = el.firstChild;
 
190
                }
 
191
                node = ieTable(4, trs, html, tre);
 
192
            }
 
193
        } else if(tag == 'tbody'){
 
194
            if(where == 'beforebegin'){
 
195
                before = el;
 
196
                el = el.parentNode;
 
197
                node = ieTable(2, ts, html, te);
 
198
            } else if(where == 'afterend'){
 
199
                before = el.nextSibling;
 
200
                el = el.parentNode;
 
201
                node = ieTable(2, ts, html, te);
 
202
            } else{
 
203
                if(where == 'afterbegin'){
 
204
                    before = el.firstChild;
 
205
                }
 
206
                node = ieTable(3, tbs, html, tbe);
 
207
            }
 
208
        } else{ // TABLE
 
209
            if(where == 'beforebegin' || where == 'afterend'){ // OUTSIDE the table
 
210
                return;
 
211
            }
 
212
            if(where == 'afterbegin'){
 
213
                before = el.firstChild;
 
214
            }
 
215
            node = ieTable(2, ts, html, te);
 
216
        }
 
217
        el.insertBefore(node, before);
 
218
        return node;
 
219
    };
 
220
 
 
221
 
 
222
    return {
 
223
    /** True to force the use of DOM instead of html fragments @type Boolean */
 
224
    useDom : false,
 
225
 
 
226
    /**
 
227
     * Returns the markup for the passed Element(s) config.
 
228
     * @param {Object} o The DOM object spec (and children)
 
229
     * @return {String}
 
230
     */
 
231
    markup : function(o){
 
232
        return createHtml(o);
 
233
    },
 
234
 
 
235
    /**
 
236
     * Applies a style specification to an element.
 
237
     * @param {String/HTMLElement} el The element to apply styles to
 
238
     * @param {String/Object/Function} styles A style specification string eg "width:100px", or object in the form {width:"100px"}, or
 
239
     * a function which returns such a specification.
 
240
     */
 
241
    applyStyles : function(el, styles){
 
242
        if(styles){
 
243
           el = Ext.fly(el);
 
244
           if(typeof styles == "string"){
 
245
               var re = /\s?([a-z\-]*)\:\s?([^;]*);?/gi;
 
246
               var matches;
 
247
               while ((matches = re.exec(styles)) != null){
 
248
                   el.setStyle(matches[1], matches[2]);
 
249
               }
 
250
           }else if (typeof styles == "object"){
 
251
               for (var style in styles){
 
252
                  el.setStyle(style, styles[style]);
 
253
               }
 
254
           }else if (typeof styles == "function"){
 
255
                Ext.DomHelper.applyStyles(el, styles.call());
 
256
           }
 
257
        }
 
258
    },
 
259
 
 
260
    /**
 
261
     * Inserts an HTML fragment into the DOM.
 
262
     * @param {String} where Where to insert the html in relation to el - beforeBegin, afterBegin, beforeEnd, afterEnd.
 
263
     * @param {HTMLElement} el The context element
 
264
     * @param {String} html The HTML fragmenet
 
265
     * @return {HTMLElement} The new node
 
266
     */
 
267
    insertHtml : function(where, el, html){
 
268
        where = where.toLowerCase();
 
269
        if(el.insertAdjacentHTML){
 
270
            if(tableRe.test(el.tagName)){
 
271
                var rs;
 
272
                if(rs = insertIntoTable(el.tagName.toLowerCase(), where, el, html)){
 
273
                    return rs;
 
274
                }
 
275
            }
 
276
            switch(where){
 
277
                case "beforebegin":
 
278
                    el.insertAdjacentHTML('BeforeBegin', html);
 
279
                    return el.previousSibling;
 
280
                case "afterbegin":
 
281
                    el.insertAdjacentHTML('AfterBegin', html);
 
282
                    return el.firstChild;
 
283
                case "beforeend":
 
284
                    el.insertAdjacentHTML('BeforeEnd', html);
 
285
                    return el.lastChild;
 
286
                case "afterend":
 
287
                    el.insertAdjacentHTML('AfterEnd', html);
 
288
                    return el.nextSibling;
 
289
            }
 
290
            throw 'Illegal insertion point -> "' + where + '"';
 
291
        }
 
292
        var range = el.ownerDocument.createRange();
 
293
        var frag;
 
294
        switch(where){
 
295
             case "beforebegin":
 
296
                range.setStartBefore(el);
 
297
                frag = range.createContextualFragment(html);
 
298
                el.parentNode.insertBefore(frag, el);
 
299
                return el.previousSibling;
 
300
             case "afterbegin":
 
301
                if(el.firstChild){
 
302
                    range.setStartBefore(el.firstChild);
 
303
                    frag = range.createContextualFragment(html);
 
304
                    el.insertBefore(frag, el.firstChild);
 
305
                    return el.firstChild;
 
306
                }else{
 
307
                    el.innerHTML = html;
 
308
                    return el.firstChild;
 
309
                }
 
310
            case "beforeend":
 
311
                if(el.lastChild){
 
312
                    range.setStartAfter(el.lastChild);
 
313
                    frag = range.createContextualFragment(html);
 
314
                    el.appendChild(frag);
 
315
                    return el.lastChild;
 
316
                }else{
 
317
                    el.innerHTML = html;
 
318
                    return el.lastChild;
 
319
                }
 
320
            case "afterend":
 
321
                range.setStartAfter(el);
 
322
                frag = range.createContextualFragment(html);
 
323
                el.parentNode.insertBefore(frag, el.nextSibling);
 
324
                return el.nextSibling;
 
325
            }
 
326
            throw 'Illegal insertion point -> "' + where + '"';
 
327
    },
 
328
 
 
329
    /**
 
330
     * Creates new DOM element(s) and inserts them before el.
 
331
     * @param {Mixed} el The context element
 
332
     * @param {Object/String} o The DOM object spec (and children) or raw HTML blob
 
333
     * @param {Boolean} returnElement (optional) true to return a Ext.Element
 
334
     * @return {HTMLElement/Ext.Element} The new node
 
335
     */
 
336
    insertBefore : function(el, o, returnElement){
 
337
        return this.doInsert(el, o, returnElement, "beforeBegin");
 
338
    },
 
339
 
 
340
    /**
 
341
     * Creates new DOM element(s) and inserts them after el.
 
342
     * @param {Mixed} el The context element
 
343
     * @param {Object} o The DOM object spec (and children)
 
344
     * @param {Boolean} returnElement (optional) true to return a Ext.Element
 
345
     * @return {HTMLElement/Ext.Element} The new node
 
346
     */
 
347
    insertAfter : function(el, o, returnElement){
 
348
        return this.doInsert(el, o, returnElement, "afterEnd", "nextSibling");
 
349
    },
 
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 this.doInsert(el, o, returnElement, "afterBegin", "firstChild");
 
360
    },
 
361
 
 
362
    // private
 
363
    doInsert : function(el, o, returnElement, pos, sibling){
 
364
        el = Ext.getDom(el);
 
365
        var newNode;
 
366
        if(this.useDom){
 
367
            newNode = createDom(o, null);
 
368
            (sibling === "firstChild" ? el : el.parentNode).insertBefore(newNode, sibling ? el[sibling] : el);
 
369
        }else{
 
370
            var html = createHtml(o);
 
371
            newNode = this.insertHtml(pos, el, html);
 
372
        }
 
373
        return returnElement ? Ext.get(newNode, true) : newNode;
 
374
    },
 
375
 
 
376
    /**
 
377
     * Creates new DOM element(s) and appends them to el.
 
378
     * @param {Mixed} el The context element
 
379
     * @param {Object/String} o The DOM object spec (and children) or raw HTML blob
 
380
     * @param {Boolean} returnElement (optional) true to return a Ext.Element
 
381
     * @return {HTMLElement/Ext.Element} The new node
 
382
     */
 
383
    append : function(el, o, returnElement){
 
384
        el = Ext.getDom(el);
 
385
        var newNode;
 
386
        if(this.useDom){
 
387
            newNode = createDom(o, null);
 
388
            el.appendChild(newNode);
 
389
        }else{
 
390
            var html = createHtml(o);
 
391
            newNode = this.insertHtml("beforeEnd", el, html);
 
392
        }
 
393
        return returnElement ? Ext.get(newNode, true) : newNode;
 
394
    },
 
395
 
 
396
    /**
 
397
     * Creates new DOM element(s) and overwrites the contents of el with them.
 
398
     * @param {Mixed} el The context element
 
399
     * @param {Object/String} o The DOM object spec (and children) or raw HTML blob
 
400
     * @param {Boolean} returnElement (optional) true to return a Ext.Element
 
401
     * @return {HTMLElement/Ext.Element} The new node
 
402
     */
 
403
    overwrite : function(el, o, returnElement){
 
404
        el = Ext.getDom(el);
 
405
        el.innerHTML = createHtml(o);
 
406
        return returnElement ? Ext.get(el.firstChild, true) : el.firstChild;
 
407
    },
 
408
 
 
409
    /**
 
410
     * Creates a new Ext.Template from the DOM object spec.
 
411
     * @param {Object} o The DOM object spec (and children)
 
412
     * @return {Ext.Template} The new template
 
413
     */
 
414
    createTemplate : function(o){
 
415
        var html = createHtml(o);
 
416
        return new Ext.Template(html);
 
417
    }
 
418
    };
 
419
}();