Upgrade to ExtJS 3.2.1 - Released 04/27/2010
[extjs.git] / pkgs / ext-foundation-debug.js
1 /*!
2  * Ext JS Library 3.2.1
3  * Copyright(c) 2006-2010 Ext JS, Inc.
4  * licensing@extjs.com
5  * http://www.extjs.com/license
6  */
7 /**
8  * @class Ext.DomHelper
9  * <p>The DomHelper class provides a layer of abstraction from DOM and transparently supports creating
10  * elements via DOM or using HTML fragments. It also has the ability to create HTML fragment templates
11  * from your DOM building code.</p>
12  *
13  * <p><b><u>DomHelper element specification object</u></b></p>
14  * <p>A specification object is used when creating elements. Attributes of this object
15  * are assumed to be element attributes, except for 4 special attributes:
16  * <div class="mdetail-params"><ul>
17  * <li><b><tt>tag</tt></b> : <div class="sub-desc">The tag name of the element</div></li>
18  * <li><b><tt>children</tt></b> : or <tt>cn</tt><div class="sub-desc">An array of the
19  * same kind of element definition objects to be created and appended. These can be nested
20  * as deep as you want.</div></li>
21  * <li><b><tt>cls</tt></b> : <div class="sub-desc">The class attribute of the element.
22  * This will end up being either the "class" attribute on a HTML fragment or className
23  * for a DOM node, depending on whether DomHelper is using fragments or DOM.</div></li>
24  * <li><b><tt>html</tt></b> : <div class="sub-desc">The innerHTML for the element</div></li>
25  * </ul></div></p>
26  *
27  * <p><b><u>Insertion methods</u></b></p>
28  * <p>Commonly used insertion methods:
29  * <div class="mdetail-params"><ul>
30  * <li><b><tt>{@link #append}</tt></b> : <div class="sub-desc"></div></li>
31  * <li><b><tt>{@link #insertBefore}</tt></b> : <div class="sub-desc"></div></li>
32  * <li><b><tt>{@link #insertAfter}</tt></b> : <div class="sub-desc"></div></li>
33  * <li><b><tt>{@link #overwrite}</tt></b> : <div class="sub-desc"></div></li>
34  * <li><b><tt>{@link #createTemplate}</tt></b> : <div class="sub-desc"></div></li>
35  * <li><b><tt>{@link #insertHtml}</tt></b> : <div class="sub-desc"></div></li>
36  * </ul></div></p>
37  *
38  * <p><b><u>Example</u></b></p>
39  * <p>This is an example, where an unordered list with 3 children items is appended to an existing
40  * element with id <tt>'my-div'</tt>:<br>
41  <pre><code>
42 var dh = Ext.DomHelper; // create shorthand alias
43 // specification object
44 var spec = {
45     id: 'my-ul',
46     tag: 'ul',
47     cls: 'my-list',
48     // append children after creating
49     children: [     // may also specify 'cn' instead of 'children'
50         {tag: 'li', id: 'item0', html: 'List Item 0'},
51         {tag: 'li', id: 'item1', html: 'List Item 1'},
52         {tag: 'li', id: 'item2', html: 'List Item 2'}
53     ]
54 };
55 var list = dh.append(
56     'my-div', // the context element 'my-div' can either be the id or the actual node
57     spec      // the specification object
58 );
59  </code></pre></p>
60  * <p>Element creation specification parameters in this class may also be passed as an Array of
61  * specification objects. This can be used to insert multiple sibling nodes into an existing
62  * container very efficiently. For example, to add more list items to the example above:<pre><code>
63 dh.append('my-ul', [
64     {tag: 'li', id: 'item3', html: 'List Item 3'},
65     {tag: 'li', id: 'item4', html: 'List Item 4'}
66 ]);
67  * </code></pre></p>
68  *
69  * <p><b><u>Templating</u></b></p>
70  * <p>The real power is in the built-in templating. Instead of creating or appending any elements,
71  * <tt>{@link #createTemplate}</tt> returns a Template object which can be used over and over to
72  * insert new elements. Revisiting the example above, we could utilize templating this time:
73  * <pre><code>
74 // create the node
75 var list = dh.append('my-div', {tag: 'ul', cls: 'my-list'});
76 // get template
77 var tpl = dh.createTemplate({tag: 'li', id: 'item{0}', html: 'List Item {0}'});
78
79 for(var i = 0; i < 5, i++){
80     tpl.append(list, [i]); // use template to append to the actual node
81 }
82  * </code></pre></p>
83  * <p>An example using a template:<pre><code>
84 var html = '<a id="{0}" href="{1}" class="nav">{2}</a>';
85
86 var tpl = new Ext.DomHelper.createTemplate(html);
87 tpl.append('blog-roll', ['link1', 'http://www.jackslocum.com/', "Jack&#39;s Site"]);
88 tpl.append('blog-roll', ['link2', 'http://www.dustindiaz.com/', "Dustin&#39;s Site"]);
89  * </code></pre></p>
90  *
91  * <p>The same example using named parameters:<pre><code>
92 var html = '<a id="{id}" href="{url}" class="nav">{text}</a>';
93
94 var tpl = new Ext.DomHelper.createTemplate(html);
95 tpl.append('blog-roll', {
96     id: 'link1',
97     url: 'http://www.jackslocum.com/',
98     text: "Jack&#39;s Site"
99 });
100 tpl.append('blog-roll', {
101     id: 'link2',
102     url: 'http://www.dustindiaz.com/',
103     text: "Dustin&#39;s Site"
104 });
105  * </code></pre></p>
106  *
107  * <p><b><u>Compiling Templates</u></b></p>
108  * <p>Templates are applied using regular expressions. The performance is great, but if
109  * you are adding a bunch of DOM elements using the same template, you can increase
110  * performance even further by {@link Ext.Template#compile "compiling"} the template.
111  * The way "{@link Ext.Template#compile compile()}" works is the template is parsed and
112  * broken up at the different variable points and a dynamic function is created and eval'ed.
113  * The generated function performs string concatenation of these parts and the passed
114  * variables instead of using regular expressions.
115  * <pre><code>
116 var html = '<a id="{id}" href="{url}" class="nav">{text}</a>';
117
118 var tpl = new Ext.DomHelper.createTemplate(html);
119 tpl.compile();
120
121 //... use template like normal
122  * </code></pre></p>
123  *
124  * <p><b><u>Performance Boost</u></b></p>
125  * <p>DomHelper will transparently create HTML fragments when it can. Using HTML fragments instead
126  * of DOM can significantly boost performance.</p>
127  * <p>Element creation specification parameters may also be strings. If {@link #useDom} is <tt>false</tt>,
128  * then the string is used as innerHTML. If {@link #useDom} is <tt>true</tt>, a string specification
129  * results in the creation of a text node. Usage:</p>
130  * <pre><code>
131 Ext.DomHelper.useDom = true; // force it to use DOM; reduces performance
132  * </code></pre>
133  * @singleton
134  */
135 Ext.DomHelper = function(){
136     var tempTableEl = null,
137         emptyTags = /^(?:br|frame|hr|img|input|link|meta|range|spacer|wbr|area|param|col)$/i,
138         tableRe = /^table|tbody|tr|td$/i,
139         confRe = /tag|children|cn|html$/i,
140         tableElRe = /td|tr|tbody/i,
141         cssRe = /([a-z0-9-]+)\s*:\s*([^;\s]+(?:\s*[^;\s]+)*);?/gi,
142         endRe = /end/i,
143         pub,
144         // kill repeat to save bytes
145         afterbegin = 'afterbegin',
146         afterend = 'afterend',
147         beforebegin = 'beforebegin',
148         beforeend = 'beforeend',
149         ts = '<table>',
150         te = '</table>',
151         tbs = ts+'<tbody>',
152         tbe = '</tbody>'+te,
153         trs = tbs + '<tr>',
154         tre = '</tr>'+tbe;
155
156     // private
157     function doInsert(el, o, returnElement, pos, sibling, append){
158         var newNode = pub.insertHtml(pos, Ext.getDom(el), createHtml(o));
159         return returnElement ? Ext.get(newNode, true) : newNode;
160     }
161
162     // build as innerHTML where available
163     function createHtml(o){
164         var b = '',
165             attr,
166             val,
167             key,
168             keyVal,
169             cn;
170
171         if(typeof o == "string"){
172             b = o;
173         } else if (Ext.isArray(o)) {
174             for (var i=0; i < o.length; i++) {
175                 if(o[i]) {
176                     b += createHtml(o[i]);
177                 }
178             };
179         } else {
180             b += '<' + (o.tag = o.tag || 'div');
181             for (attr in o) {
182                 val = o[attr];
183                 if(!confRe.test(attr)){
184                     if (typeof val == "object") {
185                         b += ' ' + attr + '="';
186                         for (key in val) {
187                             b += key + ':' + val[key] + ';';
188                         };
189                         b += '"';
190                     }else{
191                         b += ' ' + ({cls : 'class', htmlFor : 'for'}[attr] || attr) + '="' + val + '"';
192                     }
193                 }
194             };
195             // Now either just close the tag or try to add children and close the tag.
196             if (emptyTags.test(o.tag)) {
197                 b += '/>';
198             } else {
199                 b += '>';
200                 if ((cn = o.children || o.cn)) {
201                     b += createHtml(cn);
202                 } else if(o.html){
203                     b += o.html;
204                 }
205                 b += '</' + o.tag + '>';
206             }
207         }
208         return b;
209     }
210
211     function ieTable(depth, s, h, e){
212         tempTableEl.innerHTML = [s, h, e].join('');
213         var i = -1,
214             el = tempTableEl,
215             ns;
216         while(++i < depth){
217             el = el.firstChild;
218         }
219 //      If the result is multiple siblings, then encapsulate them into one fragment.
220         if(ns = el.nextSibling){
221             var df = document.createDocumentFragment();
222             while(el){
223                 ns = el.nextSibling;
224                 df.appendChild(el);
225                 el = ns;
226             }
227             el = df;
228         }
229         return el;
230     }
231
232     /**
233      * @ignore
234      * Nasty code for IE's broken table implementation
235      */
236     function insertIntoTable(tag, where, el, html) {
237         var node,
238             before;
239
240         tempTableEl = tempTableEl || document.createElement('div');
241
242         if(tag == 'td' && (where == afterbegin || where == beforeend) ||
243            !tableElRe.test(tag) && (where == beforebegin || where == afterend)) {
244             return;
245         }
246         before = where == beforebegin ? el :
247                  where == afterend ? el.nextSibling :
248                  where == afterbegin ? el.firstChild : null;
249
250         if (where == beforebegin || where == afterend) {
251             el = el.parentNode;
252         }
253
254         if (tag == 'td' || (tag == 'tr' && (where == beforeend || where == afterbegin))) {
255             node = ieTable(4, trs, html, tre);
256         } else if ((tag == 'tbody' && (where == beforeend || where == afterbegin)) ||
257                    (tag == 'tr' && (where == beforebegin || where == afterend))) {
258             node = ieTable(3, tbs, html, tbe);
259         } else {
260             node = ieTable(2, ts, html, te);
261         }
262         el.insertBefore(node, before);
263         return node;
264     }
265
266
267     pub = {
268         /**
269          * Returns the markup for the passed Element(s) config.
270          * @param {Object} o The DOM object spec (and children)
271          * @return {String}
272          */
273         markup : function(o){
274             return createHtml(o);
275         },
276
277         /**
278          * Applies a style specification to an element.
279          * @param {String/HTMLElement} el The element to apply styles to
280          * @param {String/Object/Function} styles A style specification string e.g. 'width:100px', or object in the form {width:'100px'}, or
281          * a function which returns such a specification.
282          */
283         applyStyles : function(el, styles){
284             if(styles){
285                 var i = 0,
286                     len,
287                     style,
288                     matches;
289
290                 el = Ext.fly(el);
291                 if(typeof styles == "function"){
292                     styles = styles.call();
293                 }
294                 if(typeof styles == "string"){
295                     while((matches = cssRe.exec(styles))){
296                         el.setStyle(matches[1], matches[2]);
297                     }
298                 }else if (typeof styles == "object"){
299                     el.setStyle(styles);
300                 }
301             }
302         },
303
304         /**
305          * Inserts an HTML fragment into the DOM.
306          * @param {String} where Where to insert the html in relation to el - beforeBegin, afterBegin, beforeEnd, afterEnd.
307          * @param {HTMLElement} el The context element
308          * @param {String} html The HTML fragment
309          * @return {HTMLElement} The new node
310          */
311         insertHtml : function(where, el, html){
312             var hash = {},
313                 hashVal,
314                 setStart,
315                 range,
316                 frag,
317                 rangeEl,
318                 rs;
319
320             where = where.toLowerCase();
321             // add these here because they are used in both branches of the condition.
322             hash[beforebegin] = ['BeforeBegin', 'previousSibling'];
323             hash[afterend] = ['AfterEnd', 'nextSibling'];
324
325             if (el.insertAdjacentHTML) {
326                 if(tableRe.test(el.tagName) && (rs = insertIntoTable(el.tagName.toLowerCase(), where, el, html))){
327                     return rs;
328                 }
329                 // add these two to the hash.
330                 hash[afterbegin] = ['AfterBegin', 'firstChild'];
331                 hash[beforeend] = ['BeforeEnd', 'lastChild'];
332                 if ((hashVal = hash[where])) {
333                     el.insertAdjacentHTML(hashVal[0], html);
334                     return el[hashVal[1]];
335                 }
336             } else {
337                 range = el.ownerDocument.createRange();
338                 setStart = 'setStart' + (endRe.test(where) ? 'After' : 'Before');
339                 if (hash[where]) {
340                     range[setStart](el);
341                     frag = range.createContextualFragment(html);
342                     el.parentNode.insertBefore(frag, where == beforebegin ? el : el.nextSibling);
343                     return el[(where == beforebegin ? 'previous' : 'next') + 'Sibling'];
344                 } else {
345                     rangeEl = (where == afterbegin ? 'first' : 'last') + 'Child';
346                     if (el.firstChild) {
347                         range[setStart](el[rangeEl]);
348                         frag = range.createContextualFragment(html);
349                         if(where == afterbegin){
350                             el.insertBefore(frag, el.firstChild);
351                         }else{
352                             el.appendChild(frag);
353                         }
354                     } else {
355                         el.innerHTML = html;
356                     }
357                     return el[rangeEl];
358                 }
359             }
360             throw 'Illegal insertion point -> "' + where + '"';
361         },
362
363         /**
364          * Creates new DOM element(s) and inserts them before el.
365          * @param {Mixed} el The context element
366          * @param {Object/String} o The DOM object spec (and children) or raw HTML blob
367          * @param {Boolean} returnElement (optional) true to return a Ext.Element
368          * @return {HTMLElement/Ext.Element} The new node
369          */
370         insertBefore : function(el, o, returnElement){
371             return doInsert(el, o, returnElement, beforebegin);
372         },
373
374         /**
375          * Creates new DOM element(s) and inserts them after el.
376          * @param {Mixed} el The context element
377          * @param {Object} o The DOM object spec (and children)
378          * @param {Boolean} returnElement (optional) true to return a Ext.Element
379          * @return {HTMLElement/Ext.Element} The new node
380          */
381         insertAfter : function(el, o, returnElement){
382             return doInsert(el, o, returnElement, afterend, 'nextSibling');
383         },
384
385         /**
386          * Creates new DOM element(s) and inserts them as the first child of el.
387          * @param {Mixed} el The context element
388          * @param {Object/String} o The DOM object spec (and children) or raw HTML blob
389          * @param {Boolean} returnElement (optional) true to return a Ext.Element
390          * @return {HTMLElement/Ext.Element} The new node
391          */
392         insertFirst : function(el, o, returnElement){
393             return doInsert(el, o, returnElement, afterbegin, 'firstChild');
394         },
395
396         /**
397          * Creates new DOM element(s) and appends them to el.
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         append : function(el, o, returnElement){
404             return doInsert(el, o, returnElement, beforeend, '', true);
405         },
406
407         /**
408          * Creates new DOM element(s) and overwrites the contents of el with them.
409          * @param {Mixed} el The context element
410          * @param {Object/String} o The DOM object spec (and children) or raw HTML blob
411          * @param {Boolean} returnElement (optional) true to return a Ext.Element
412          * @return {HTMLElement/Ext.Element} The new node
413          */
414         overwrite : function(el, o, returnElement){
415             el = Ext.getDom(el);
416             el.innerHTML = createHtml(o);
417             return returnElement ? Ext.get(el.firstChild) : el.firstChild;
418         },
419
420         createHtml : createHtml
421     };
422     return pub;
423 }();
424 /**
425  * @class Ext.DomHelper
426  */
427 Ext.apply(Ext.DomHelper,
428 function(){
429     var pub,
430         afterbegin = 'afterbegin',
431         afterend = 'afterend',
432         beforebegin = 'beforebegin',
433         beforeend = 'beforeend',
434         confRe = /tag|children|cn|html$/i;
435
436     // private
437     function doInsert(el, o, returnElement, pos, sibling, append){
438         el = Ext.getDom(el);
439         var newNode;
440         if (pub.useDom) {
441             newNode = createDom(o, null);
442             if (append) {
443                 el.appendChild(newNode);
444             } else {
445                 (sibling == 'firstChild' ? el : el.parentNode).insertBefore(newNode, el[sibling] || el);
446             }
447         } else {
448             newNode = Ext.DomHelper.insertHtml(pos, el, Ext.DomHelper.createHtml(o));
449         }
450         return returnElement ? Ext.get(newNode, true) : newNode;
451     }
452
453     // build as dom
454     /** @ignore */
455     function createDom(o, parentNode){
456         var el,
457             doc = document,
458             useSet,
459             attr,
460             val,
461             cn;
462
463         if (Ext.isArray(o)) {                       // Allow Arrays of siblings to be inserted
464             el = doc.createDocumentFragment(); // in one shot using a DocumentFragment
465             for (var i = 0, l = o.length; i < l; i++) {
466                 createDom(o[i], el);
467             }
468         } else if (typeof o == 'string') {         // Allow a string as a child spec.
469             el = doc.createTextNode(o);
470         } else {
471             el = doc.createElement( o.tag || 'div' );
472             useSet = !!el.setAttribute; // In IE some elements don't have setAttribute
473             for (var attr in o) {
474                 if(!confRe.test(attr)){
475                     val = o[attr];
476                     if(attr == 'cls'){
477                         el.className = val;
478                     }else{
479                         if(useSet){
480                             el.setAttribute(attr, val);
481                         }else{
482                             el[attr] = val;
483                         }
484                     }
485                 }
486             }
487             Ext.DomHelper.applyStyles(el, o.style);
488
489             if ((cn = o.children || o.cn)) {
490                 createDom(cn, el);
491             } else if (o.html) {
492                 el.innerHTML = o.html;
493             }
494         }
495         if(parentNode){
496            parentNode.appendChild(el);
497         }
498         return el;
499     }
500
501     pub = {
502         /**
503          * Creates a new Ext.Template from the DOM object spec.
504          * @param {Object} o The DOM object spec (and children)
505          * @return {Ext.Template} The new template
506          */
507         createTemplate : function(o){
508             var html = Ext.DomHelper.createHtml(o);
509             return new Ext.Template(html);
510         },
511
512         /** True to force the use of DOM instead of html fragments @type Boolean */
513         useDom : false,
514
515         /**
516          * Creates new DOM element(s) and inserts them before el.
517          * @param {Mixed} el The context element
518          * @param {Object/String} o The DOM object spec (and children) or raw HTML blob
519          * @param {Boolean} returnElement (optional) true to return a Ext.Element
520          * @return {HTMLElement/Ext.Element} The new node
521          * @hide (repeat)
522          */
523         insertBefore : function(el, o, returnElement){
524             return doInsert(el, o, returnElement, beforebegin);
525         },
526
527         /**
528          * Creates new DOM element(s) and inserts them after el.
529          * @param {Mixed} el The context element
530          * @param {Object} o The DOM object spec (and children)
531          * @param {Boolean} returnElement (optional) true to return a Ext.Element
532          * @return {HTMLElement/Ext.Element} The new node
533          * @hide (repeat)
534          */
535         insertAfter : function(el, o, returnElement){
536             return doInsert(el, o, returnElement, afterend, 'nextSibling');
537         },
538
539         /**
540          * Creates new DOM element(s) and inserts them as the first child of el.
541          * @param {Mixed} el The context element
542          * @param {Object/String} o The DOM object spec (and children) or raw HTML blob
543          * @param {Boolean} returnElement (optional) true to return a Ext.Element
544          * @return {HTMLElement/Ext.Element} The new node
545          * @hide (repeat)
546          */
547         insertFirst : function(el, o, returnElement){
548             return doInsert(el, o, returnElement, afterbegin, 'firstChild');
549         },
550
551         /**
552          * Creates new DOM element(s) and appends them to el.
553          * @param {Mixed} el The context element
554          * @param {Object/String} o The DOM object spec (and children) or raw HTML blob
555          * @param {Boolean} returnElement (optional) true to return a Ext.Element
556          * @return {HTMLElement/Ext.Element} The new node
557          * @hide (repeat)
558          */
559         append: function(el, o, returnElement){
560             return doInsert(el, o, returnElement, beforeend, '', true);
561         },
562
563         /**
564          * Creates new DOM element(s) without inserting them to the document.
565          * @param {Object/String} o The DOM object spec (and children) or raw HTML blob
566          * @return {HTMLElement} The new uninserted node
567          */
568         createDom: createDom
569     };
570     return pub;
571 }());
572 /**
573  * @class Ext.Template
574  * <p>Represents an HTML fragment template. Templates may be {@link #compile precompiled}
575  * for greater performance.</p>
576  * <p>For example usage {@link #Template see the constructor}.</p>
577  *
578  * @constructor
579  * An instance of this class may be created by passing to the constructor either
580  * a single argument, or multiple arguments:
581  * <div class="mdetail-params"><ul>
582  * <li><b>single argument</b> : String/Array
583  * <div class="sub-desc">
584  * The single argument may be either a String or an Array:<ul>
585  * <li><tt>String</tt> : </li><pre><code>
586 var t = new Ext.Template("&lt;div>Hello {0}.&lt;/div>");
587 t.{@link #append}('some-element', ['foo']);
588  * </code></pre>
589  * <li><tt>Array</tt> : </li>
590  * An Array will be combined with <code>join('')</code>.
591 <pre><code>
592 var t = new Ext.Template([
593     '&lt;div name="{id}"&gt;',
594         '&lt;span class="{cls}"&gt;{name:trim} {value:ellipsis(10)}&lt;/span&gt;',
595     '&lt;/div&gt;',
596 ]);
597 t.{@link #compile}();
598 t.{@link #append}('some-element', {id: 'myid', cls: 'myclass', name: 'foo', value: 'bar'});
599 </code></pre>
600  * </ul></div></li>
601  * <li><b>multiple arguments</b> : String, Object, Array, ...
602  * <div class="sub-desc">
603  * Multiple arguments will be combined with <code>join('')</code>.
604  * <pre><code>
605 var t = new Ext.Template(
606     '&lt;div name="{id}"&gt;',
607         '&lt;span class="{cls}"&gt;{name} {value}&lt;/span&gt;',
608     '&lt;/div&gt;',
609     // a configuration object:
610     {
611         compiled: true,      // {@link #compile} immediately
612         disableFormats: true // See Notes below.
613     }
614 );
615  * </code></pre>
616  * <p><b>Notes</b>:</p>
617  * <div class="mdetail-params"><ul>
618  * <li>Formatting and <code>disableFormats</code> are not applicable for Ext Core.</li>
619  * <li>For a list of available format functions, see {@link Ext.util.Format}.</li>
620  * <li><code>disableFormats</code> reduces <code>{@link #apply}</code> time
621  * when no formatting is required.</li>
622  * </ul></div>
623  * </div></li>
624  * </ul></div>
625  * @param {Mixed} config
626  */
627 Ext.Template = function(html){
628     var me = this,
629         a = arguments,
630         buf = [],
631         v;
632
633     if (Ext.isArray(html)) {
634         html = html.join("");
635     } else if (a.length > 1) {
636         for(var i = 0, len = a.length; i < len; i++){
637             v = a[i];
638             if(typeof v == 'object'){
639                 Ext.apply(me, v);
640             } else {
641                 buf.push(v);
642             }
643         };
644         html = buf.join('');
645     }
646
647     /**@private*/
648     me.html = html;
649     /**
650      * @cfg {Boolean} compiled Specify <tt>true</tt> to compile the template
651      * immediately (see <code>{@link #compile}</code>).
652      * Defaults to <tt>false</tt>.
653      */
654     if (me.compiled) {
655         me.compile();
656     }
657 };
658 Ext.Template.prototype = {
659     /**
660      * @cfg {RegExp} re The regular expression used to match template variables.
661      * Defaults to:<pre><code>
662      * re : /\{([\w-]+)\}/g                                     // for Ext Core
663      * re : /\{([\w-]+)(?:\:([\w\.]*)(?:\((.*?)?\))?)?\}/g      // for Ext JS
664      * </code></pre>
665      */
666     re : /\{([\w-]+)\}/g,
667     /**
668      * See <code>{@link #re}</code>.
669      * @type RegExp
670      * @property re
671      */
672
673     /**
674      * Returns an HTML fragment of this template with the specified <code>values</code> applied.
675      * @param {Object/Array} values
676      * The template values. Can be an array if the params are numeric (i.e. <code>{0}</code>)
677      * or an object (i.e. <code>{foo: 'bar'}</code>).
678      * @return {String} The HTML fragment
679      */
680     applyTemplate : function(values){
681         var me = this;
682
683         return me.compiled ?
684                 me.compiled(values) :
685                 me.html.replace(me.re, function(m, name){
686                     return values[name] !== undefined ? values[name] : "";
687                 });
688     },
689
690     /**
691      * Sets the HTML used as the template and optionally compiles it.
692      * @param {String} html
693      * @param {Boolean} compile (optional) True to compile the template (defaults to undefined)
694      * @return {Ext.Template} this
695      */
696     set : function(html, compile){
697         var me = this;
698         me.html = html;
699         me.compiled = null;
700         return compile ? me.compile() : me;
701     },
702
703     /**
704      * Compiles the template into an internal function, eliminating the RegEx overhead.
705      * @return {Ext.Template} this
706      */
707     compile : function(){
708         var me = this,
709             sep = Ext.isGecko ? "+" : ",";
710
711         function fn(m, name){
712             name = "values['" + name + "']";
713             return "'"+ sep + '(' + name + " == undefined ? '' : " + name + ')' + sep + "'";
714         }
715
716         eval("this.compiled = function(values){ return " + (Ext.isGecko ? "'" : "['") +
717              me.html.replace(/\\/g, '\\\\').replace(/(\r\n|\n)/g, '\\n').replace(/'/g, "\\'").replace(this.re, fn) +
718              (Ext.isGecko ?  "';};" : "'].join('');};"));
719         return me;
720     },
721
722     /**
723      * Applies the supplied values to the template and inserts the new node(s) as the first child of el.
724      * @param {Mixed} el The context element
725      * @param {Object/Array} values The template values. Can be an array if your params are numeric (i.e. {0}) or an object (i.e. {foo: 'bar'})
726      * @param {Boolean} returnElement (optional) true to return a Ext.Element (defaults to undefined)
727      * @return {HTMLElement/Ext.Element} The new node or Element
728      */
729     insertFirst: function(el, values, returnElement){
730         return this.doInsert('afterBegin', el, values, returnElement);
731     },
732
733     /**
734      * Applies the supplied values to the template and inserts the new node(s) before el.
735      * @param {Mixed} el The context element
736      * @param {Object/Array} values The template values. Can be an array if your params are numeric (i.e. {0}) or an object (i.e. {foo: 'bar'})
737      * @param {Boolean} returnElement (optional) true to return a Ext.Element (defaults to undefined)
738      * @return {HTMLElement/Ext.Element} The new node or Element
739      */
740     insertBefore: function(el, values, returnElement){
741         return this.doInsert('beforeBegin', el, values, returnElement);
742     },
743
744     /**
745      * Applies the supplied values to the template and inserts the new node(s) after el.
746      * @param {Mixed} el The context element
747      * @param {Object/Array} values The template values. Can be an array if your params are numeric (i.e. {0}) or an object (i.e. {foo: 'bar'})
748      * @param {Boolean} returnElement (optional) true to return a Ext.Element (defaults to undefined)
749      * @return {HTMLElement/Ext.Element} The new node or Element
750      */
751     insertAfter : function(el, values, returnElement){
752         return this.doInsert('afterEnd', el, values, returnElement);
753     },
754
755     /**
756      * Applies the supplied <code>values</code> to the template and appends
757      * the new node(s) to the specified <code>el</code>.
758      * <p>For example usage {@link #Template see the constructor}.</p>
759      * @param {Mixed} el The context element
760      * @param {Object/Array} values
761      * The template values. Can be an array if the params are numeric (i.e. <code>{0}</code>)
762      * or an object (i.e. <code>{foo: 'bar'}</code>).
763      * @param {Boolean} returnElement (optional) true to return an Ext.Element (defaults to undefined)
764      * @return {HTMLElement/Ext.Element} The new node or Element
765      */
766     append : function(el, values, returnElement){
767         return this.doInsert('beforeEnd', el, values, returnElement);
768     },
769
770     doInsert : function(where, el, values, returnEl){
771         el = Ext.getDom(el);
772         var newNode = Ext.DomHelper.insertHtml(where, el, this.applyTemplate(values));
773         return returnEl ? Ext.get(newNode, true) : newNode;
774     },
775
776     /**
777      * Applies the supplied values to the template and overwrites the content of el with the new node(s).
778      * @param {Mixed} el The context element
779      * @param {Object/Array} values The template values. Can be an array if your params are numeric (i.e. {0}) or an object (i.e. {foo: 'bar'})
780      * @param {Boolean} returnElement (optional) true to return a Ext.Element (defaults to undefined)
781      * @return {HTMLElement/Ext.Element} The new node or Element
782      */
783     overwrite : function(el, values, returnElement){
784         el = Ext.getDom(el);
785         el.innerHTML = this.applyTemplate(values);
786         return returnElement ? Ext.get(el.firstChild, true) : el.firstChild;
787     }
788 };
789 /**
790  * Alias for {@link #applyTemplate}
791  * Returns an HTML fragment of this template with the specified <code>values</code> applied.
792  * @param {Object/Array} values
793  * The template values. Can be an array if the params are numeric (i.e. <code>{0}</code>)
794  * or an object (i.e. <code>{foo: 'bar'}</code>).
795  * @return {String} The HTML fragment
796  * @member Ext.Template
797  * @method apply
798  */
799 Ext.Template.prototype.apply = Ext.Template.prototype.applyTemplate;
800
801 /**
802  * Creates a template from the passed element's value (<i>display:none</i> textarea, preferred) or innerHTML.
803  * @param {String/HTMLElement} el A DOM element or its id
804  * @param {Object} config A configuration object
805  * @return {Ext.Template} The created template
806  * @static
807  */
808 Ext.Template.from = function(el, config){
809     el = Ext.getDom(el);
810     return new Ext.Template(el.value || el.innerHTML, config || '');
811 };
812 /**
813  * @class Ext.Template
814  */
815 Ext.apply(Ext.Template.prototype, {
816     /**
817      * @cfg {Boolean} disableFormats Specify <tt>true</tt> to disable format
818      * functions in the template. If the template does not contain
819      * {@link Ext.util.Format format functions}, setting <code>disableFormats</code>
820      * to true will reduce <code>{@link #apply}</code> time. Defaults to <tt>false</tt>.
821      * <pre><code>
822 var t = new Ext.Template(
823     '&lt;div name="{id}"&gt;',
824         '&lt;span class="{cls}"&gt;{name} {value}&lt;/span&gt;',
825     '&lt;/div&gt;',
826     {
827         compiled: true,      // {@link #compile} immediately
828         disableFormats: true // reduce <code>{@link #apply}</code> time since no formatting
829     }
830 );
831      * </code></pre>
832      * For a list of available format functions, see {@link Ext.util.Format}.
833      */
834     disableFormats : false,
835     /**
836      * See <code>{@link #disableFormats}</code>.
837      * @type Boolean
838      * @property disableFormats
839      */
840
841     /**
842      * The regular expression used to match template variables
843      * @type RegExp
844      * @property
845      * @hide repeat doc
846      */
847     re : /\{([\w-]+)(?:\:([\w\.]*)(?:\((.*?)?\))?)?\}/g,
848     argsRe : /^\s*['"](.*)["']\s*$/,
849     compileARe : /\\/g,
850     compileBRe : /(\r\n|\n)/g,
851     compileCRe : /'/g,
852
853     /**
854      * Returns an HTML fragment of this template with the specified values applied.
855      * @param {Object/Array} values The template values. Can be an array if your params are numeric (i.e. {0}) or an object (i.e. {foo: 'bar'})
856      * @return {String} The HTML fragment
857      * @hide repeat doc
858      */
859     applyTemplate : function(values){
860         var me = this,
861             useF = me.disableFormats !== true,
862             fm = Ext.util.Format,
863             tpl = me;
864
865         if(me.compiled){
866             return me.compiled(values);
867         }
868         function fn(m, name, format, args){
869             if (format && useF) {
870                 if (format.substr(0, 5) == "this.") {
871                     return tpl.call(format.substr(5), values[name], values);
872                 } else {
873                     if (args) {
874                         // quoted values are required for strings in compiled templates,
875                         // but for non compiled we need to strip them
876                         // quoted reversed for jsmin
877                         var re = me.argsRe;
878                         args = args.split(',');
879                         for(var i = 0, len = args.length; i < len; i++){
880                             args[i] = args[i].replace(re, "$1");
881                         }
882                         args = [values[name]].concat(args);
883                     } else {
884                         args = [values[name]];
885                     }
886                     return fm[format].apply(fm, args);
887                 }
888             } else {
889                 return values[name] !== undefined ? values[name] : "";
890             }
891         }
892         return me.html.replace(me.re, fn);
893     },
894
895     /**
896      * Compiles the template into an internal function, eliminating the RegEx overhead.
897      * @return {Ext.Template} this
898      * @hide repeat doc
899      */
900     compile : function(){
901         var me = this,
902             fm = Ext.util.Format,
903             useF = me.disableFormats !== true,
904             sep = Ext.isGecko ? "+" : ",",
905             body;
906
907         function fn(m, name, format, args){
908             if(format && useF){
909                 args = args ? ',' + args : "";
910                 if(format.substr(0, 5) != "this."){
911                     format = "fm." + format + '(';
912                 }else{
913                     format = 'this.call("'+ format.substr(5) + '", ';
914                     args = ", values";
915                 }
916             }else{
917                 args= ''; format = "(values['" + name + "'] == undefined ? '' : ";
918             }
919             return "'"+ sep + format + "values['" + name + "']" + args + ")"+sep+"'";
920         }
921
922         // branched to use + in gecko and [].join() in others
923         if(Ext.isGecko){
924             body = "this.compiled = function(values){ return '" +
925                    me.html.replace(me.compileARe, '\\\\').replace(me.compileBRe, '\\n').replace(me.compileCRe, "\\'").replace(me.re, fn) +
926                     "';};";
927         }else{
928             body = ["this.compiled = function(values){ return ['"];
929             body.push(me.html.replace(me.compileARe, '\\\\').replace(me.compileBRe, '\\n').replace(me.compileCRe, "\\'").replace(me.re, fn));
930             body.push("'].join('');};");
931             body = body.join('');
932         }
933         eval(body);
934         return me;
935     },
936
937     // private function used to call members
938     call : function(fnName, value, allValues){
939         return this[fnName](value, allValues);
940     }
941 });
942 Ext.Template.prototype.apply = Ext.Template.prototype.applyTemplate;
943 /*
944  * This is code is also distributed under MIT license for use
945  * with jQuery and prototype JavaScript libraries.
946  */
947 /**
948  * @class Ext.DomQuery
949 Provides high performance selector/xpath processing by compiling queries into reusable functions. New pseudo classes and matchers can be plugged. It works on HTML and XML documents (if a content node is passed in).
950 <p>
951 DomQuery supports most of the <a href="http://www.w3.org/TR/2005/WD-css3-selectors-20051215/#selectors">CSS3 selectors spec</a>, along with some custom selectors and basic XPath.</p>
952
953 <p>
954 All selectors, attribute filters and pseudos below can be combined infinitely in any order. For example "div.foo:nth-child(odd)[@foo=bar].bar:first" would be a perfectly valid selector. Node filters are processed in the order in which they appear, which allows you to optimize your queries for your document structure.
955 </p>
956 <h4>Element Selectors:</h4>
957 <ul class="list">
958     <li> <b>*</b> any element</li>
959     <li> <b>E</b> an element with the tag E</li>
960     <li> <b>E F</b> All descendent elements of E that have the tag F</li>
961     <li> <b>E > F</b> or <b>E/F</b> all direct children elements of E that have the tag F</li>
962     <li> <b>E + F</b> all elements with the tag F that are immediately preceded by an element with the tag E</li>
963     <li> <b>E ~ F</b> all elements with the tag F that are preceded by a sibling element with the tag E</li>
964 </ul>
965 <h4>Attribute Selectors:</h4>
966 <p>The use of &#64; and quotes are optional. For example, div[&#64;foo='bar'] is also a valid attribute selector.</p>
967 <ul class="list">
968     <li> <b>E[foo]</b> has an attribute "foo"</li>
969     <li> <b>E[foo=bar]</b> has an attribute "foo" that equals "bar"</li>
970     <li> <b>E[foo^=bar]</b> has an attribute "foo" that starts with "bar"</li>
971     <li> <b>E[foo$=bar]</b> has an attribute "foo" that ends with "bar"</li>
972     <li> <b>E[foo*=bar]</b> has an attribute "foo" that contains the substring "bar"</li>
973     <li> <b>E[foo%=2]</b> has an attribute "foo" that is evenly divisible by 2</li>
974     <li> <b>E[foo!=bar]</b> has an attribute "foo" that does not equal "bar"</li>
975 </ul>
976 <h4>Pseudo Classes:</h4>
977 <ul class="list">
978     <li> <b>E:first-child</b> E is the first child of its parent</li>
979     <li> <b>E:last-child</b> E is the last child of its parent</li>
980     <li> <b>E:nth-child(<i>n</i>)</b> E is the <i>n</i>th child of its parent (1 based as per the spec)</li>
981     <li> <b>E:nth-child(odd)</b> E is an odd child of its parent</li>
982     <li> <b>E:nth-child(even)</b> E is an even child of its parent</li>
983     <li> <b>E:only-child</b> E is the only child of its parent</li>
984     <li> <b>E:checked</b> E is an element that is has a checked attribute that is true (e.g. a radio or checkbox) </li>
985     <li> <b>E:first</b> the first E in the resultset</li>
986     <li> <b>E:last</b> the last E in the resultset</li>
987     <li> <b>E:nth(<i>n</i>)</b> the <i>n</i>th E in the resultset (1 based)</li>
988     <li> <b>E:odd</b> shortcut for :nth-child(odd)</li>
989     <li> <b>E:even</b> shortcut for :nth-child(even)</li>
990     <li> <b>E:contains(foo)</b> E's innerHTML contains the substring "foo"</li>
991     <li> <b>E:nodeValue(foo)</b> E contains a textNode with a nodeValue that equals "foo"</li>
992     <li> <b>E:not(S)</b> an E element that does not match simple selector S</li>
993     <li> <b>E:has(S)</b> an E element that has a descendent that matches simple selector S</li>
994     <li> <b>E:next(S)</b> an E element whose next sibling matches simple selector S</li>
995     <li> <b>E:prev(S)</b> an E element whose previous sibling matches simple selector S</li>
996     <li> <b>E:any(S1|S2|S2)</b> an E element which matches any of the simple selectors S1, S2 or S3//\\</li>
997 </ul>
998 <h4>CSS Value Selectors:</h4>
999 <ul class="list">
1000     <li> <b>E{display=none}</b> css value "display" that equals "none"</li>
1001     <li> <b>E{display^=none}</b> css value "display" that starts with "none"</li>
1002     <li> <b>E{display$=none}</b> css value "display" that ends with "none"</li>
1003     <li> <b>E{display*=none}</b> css value "display" that contains the substring "none"</li>
1004     <li> <b>E{display%=2}</b> css value "display" that is evenly divisible by 2</li>
1005     <li> <b>E{display!=none}</b> css value "display" that does not equal "none"</li>
1006 </ul>
1007  * @singleton
1008  */
1009 Ext.DomQuery = function(){
1010     var cache = {}, 
1011         simpleCache = {}, 
1012         valueCache = {},
1013         nonSpace = /\S/,
1014         trimRe = /^\s+|\s+$/g,
1015         tplRe = /\{(\d+)\}/g,
1016         modeRe = /^(\s?[\/>+~]\s?|\s|$)/,
1017         tagTokenRe = /^(#)?([\w-\*]+)/,
1018         nthRe = /(\d*)n\+?(\d*)/, 
1019         nthRe2 = /\D/,
1020         // This is for IE MSXML which does not support expandos.
1021         // IE runs the same speed using setAttribute, however FF slows way down
1022         // and Safari completely fails so they need to continue to use expandos.
1023         isIE = window.ActiveXObject ? true : false,
1024         key = 30803;
1025     
1026     // this eval is stop the compressor from
1027     // renaming the variable to something shorter
1028     eval("var batch = 30803;");         
1029
1030     // Retrieve the child node from a particular
1031     // parent at the specified index.
1032     function child(parent, index){
1033         var i = 0,
1034             n = parent.firstChild;
1035         while(n){
1036             if(n.nodeType == 1){
1037                if(++i == index){
1038                    return n;
1039                }
1040             }
1041             n = n.nextSibling;
1042         }
1043         return null;
1044     }
1045
1046     // retrieve the next element node
1047     function next(n){   
1048         while((n = n.nextSibling) && n.nodeType != 1);
1049         return n;
1050     }
1051
1052     // retrieve the previous element node 
1053     function prev(n){
1054         while((n = n.previousSibling) && n.nodeType != 1);
1055         return n;
1056     }
1057
1058     // Mark each child node with a nodeIndex skipping and
1059     // removing empty text nodes.
1060     function children(parent){
1061         var n = parent.firstChild,
1062             nodeIndex = -1,
1063             nextNode;
1064         while(n){
1065             nextNode = n.nextSibling;
1066             // clean worthless empty nodes.
1067             if(n.nodeType == 3 && !nonSpace.test(n.nodeValue)){
1068                 parent.removeChild(n);
1069             }else{
1070                 // add an expando nodeIndex
1071                 n.nodeIndex = ++nodeIndex;
1072             }
1073             n = nextNode;
1074         }
1075         return this;
1076     }
1077
1078
1079     // nodeSet - array of nodes
1080     // cls - CSS Class
1081     function byClassName(nodeSet, cls){
1082         if(!cls){
1083             return nodeSet;
1084         }
1085         var result = [], ri = -1;
1086         for(var i = 0, ci; ci = nodeSet[i]; i++){
1087             if((' '+ci.className+' ').indexOf(cls) != -1){
1088                 result[++ri] = ci;
1089             }
1090         }
1091         return result;
1092     };
1093
1094     function attrValue(n, attr){
1095         // if its an array, use the first node.
1096         if(!n.tagName && typeof n.length != "undefined"){
1097             n = n[0];
1098         }
1099         if(!n){
1100             return null;
1101         }
1102
1103         if(attr == "for"){
1104             return n.htmlFor;
1105         }
1106         if(attr == "class" || attr == "className"){
1107             return n.className;
1108         }
1109         return n.getAttribute(attr) || n[attr];
1110
1111     };
1112
1113
1114     // ns - nodes
1115     // mode - false, /, >, +, ~
1116     // tagName - defaults to "*"
1117     function getNodes(ns, mode, tagName){
1118         var result = [], ri = -1, cs;
1119         if(!ns){
1120             return result;
1121         }
1122         tagName = tagName || "*";
1123         // convert to array
1124         if(typeof ns.getElementsByTagName != "undefined"){
1125             ns = [ns];
1126         }
1127         
1128         // no mode specified, grab all elements by tagName
1129         // at any depth
1130         if(!mode){
1131             for(var i = 0, ni; ni = ns[i]; i++){
1132                 cs = ni.getElementsByTagName(tagName);
1133                 for(var j = 0, ci; ci = cs[j]; j++){
1134                     result[++ri] = ci;
1135                 }
1136             }
1137         // Direct Child mode (/ or >)
1138         // E > F or E/F all direct children elements of E that have the tag     
1139         } else if(mode == "/" || mode == ">"){
1140             var utag = tagName.toUpperCase();
1141             for(var i = 0, ni, cn; ni = ns[i]; i++){
1142                 cn = ni.childNodes;
1143                 for(var j = 0, cj; cj = cn[j]; j++){
1144                     if(cj.nodeName == utag || cj.nodeName == tagName  || tagName == '*'){
1145                         result[++ri] = cj;
1146                     }
1147                 }
1148             }
1149         // Immediately Preceding mode (+)
1150         // E + F all elements with the tag F that are immediately preceded by an element with the tag E
1151         }else if(mode == "+"){
1152             var utag = tagName.toUpperCase();
1153             for(var i = 0, n; n = ns[i]; i++){
1154                 while((n = n.nextSibling) && n.nodeType != 1);
1155                 if(n && (n.nodeName == utag || n.nodeName == tagName || tagName == '*')){
1156                     result[++ri] = n;
1157                 }
1158             }
1159         // Sibling mode (~)
1160         // E ~ F all elements with the tag F that are preceded by a sibling element with the tag E
1161         }else if(mode == "~"){
1162             var utag = tagName.toUpperCase();
1163             for(var i = 0, n; n = ns[i]; i++){
1164                 while((n = n.nextSibling)){
1165                     if (n.nodeName == utag || n.nodeName == tagName || tagName == '*'){
1166                         result[++ri] = n;
1167                     }
1168                 }
1169             }
1170         }
1171         return result;
1172     }
1173
1174     function concat(a, b){
1175         if(b.slice){
1176             return a.concat(b);
1177         }
1178         for(var i = 0, l = b.length; i < l; i++){
1179             a[a.length] = b[i];
1180         }
1181         return a;
1182     }
1183
1184     function byTag(cs, tagName){
1185         if(cs.tagName || cs == document){
1186             cs = [cs];
1187         }
1188         if(!tagName){
1189             return cs;
1190         }
1191         var result = [], ri = -1;
1192         tagName = tagName.toLowerCase();
1193         for(var i = 0, ci; ci = cs[i]; i++){
1194             if(ci.nodeType == 1 && ci.tagName.toLowerCase() == tagName){
1195                 result[++ri] = ci;
1196             }
1197         }
1198         return result;
1199     }
1200
1201     function byId(cs, id){
1202         if(cs.tagName || cs == document){
1203             cs = [cs];
1204         }
1205         if(!id){
1206             return cs;
1207         }
1208         var result = [], ri = -1;
1209         for(var i = 0, ci; ci = cs[i]; i++){
1210             if(ci && ci.id == id){
1211                 result[++ri] = ci;
1212                 return result;
1213             }
1214         }
1215         return result;
1216     }
1217
1218     // operators are =, !=, ^=, $=, *=, %=, |= and ~=
1219     // custom can be "{"
1220     function byAttribute(cs, attr, value, op, custom){
1221         var result = [], 
1222             ri = -1, 
1223             useGetStyle = custom == "{",            
1224             fn = Ext.DomQuery.operators[op],        
1225             a,      
1226             innerHTML;
1227         for(var i = 0, ci; ci = cs[i]; i++){
1228             // skip non-element nodes.
1229             if(ci.nodeType != 1){
1230                 continue;
1231             }
1232             
1233             innerHTML = ci.innerHTML;
1234             // we only need to change the property names if we're dealing with html nodes, not XML
1235             if(innerHTML !== null && innerHTML !== undefined){
1236                 if(useGetStyle){
1237                     a = Ext.DomQuery.getStyle(ci, attr);
1238                 } else if (attr == "class" || attr == "className"){
1239                     a = ci.className;
1240                 } else if (attr == "for"){
1241                     a = ci.htmlFor;
1242                 } else if (attr == "href"){
1243                     // getAttribute href bug
1244                     // http://www.glennjones.net/Post/809/getAttributehrefbug.htm
1245                     a = ci.getAttribute("href", 2);
1246                 } else{
1247                     a = ci.getAttribute(attr);
1248                 }
1249             }else{
1250                 a = ci.getAttribute(attr);
1251             }
1252             if((fn && fn(a, value)) || (!fn && a)){
1253                 result[++ri] = ci;
1254             }
1255         }
1256         return result;
1257     }
1258
1259     function byPseudo(cs, name, value){
1260         return Ext.DomQuery.pseudos[name](cs, value);
1261     }
1262
1263     function nodupIEXml(cs){
1264         var d = ++key, 
1265             r;
1266         cs[0].setAttribute("_nodup", d);
1267         r = [cs[0]];
1268         for(var i = 1, len = cs.length; i < len; i++){
1269             var c = cs[i];
1270             if(!c.getAttribute("_nodup") != d){
1271                 c.setAttribute("_nodup", d);
1272                 r[r.length] = c;
1273             }
1274         }
1275         for(var i = 0, len = cs.length; i < len; i++){
1276             cs[i].removeAttribute("_nodup");
1277         }
1278         return r;
1279     }
1280
1281     function nodup(cs){
1282         if(!cs){
1283             return [];
1284         }
1285         var len = cs.length, c, i, r = cs, cj, ri = -1;
1286         if(!len || typeof cs.nodeType != "undefined" || len == 1){
1287             return cs;
1288         }
1289         if(isIE && typeof cs[0].selectSingleNode != "undefined"){
1290             return nodupIEXml(cs);
1291         }
1292         var d = ++key;
1293         cs[0]._nodup = d;
1294         for(i = 1; c = cs[i]; i++){
1295             if(c._nodup != d){
1296                 c._nodup = d;
1297             }else{
1298                 r = [];
1299                 for(var j = 0; j < i; j++){
1300                     r[++ri] = cs[j];
1301                 }
1302                 for(j = i+1; cj = cs[j]; j++){
1303                     if(cj._nodup != d){
1304                         cj._nodup = d;
1305                         r[++ri] = cj;
1306                     }
1307                 }
1308                 return r;
1309             }
1310         }
1311         return r;
1312     }
1313
1314     function quickDiffIEXml(c1, c2){
1315         var d = ++key,
1316             r = [];
1317         for(var i = 0, len = c1.length; i < len; i++){
1318             c1[i].setAttribute("_qdiff", d);
1319         }        
1320         for(var i = 0, len = c2.length; i < len; i++){
1321             if(c2[i].getAttribute("_qdiff") != d){
1322                 r[r.length] = c2[i];
1323             }
1324         }
1325         for(var i = 0, len = c1.length; i < len; i++){
1326            c1[i].removeAttribute("_qdiff");
1327         }
1328         return r;
1329     }
1330
1331     function quickDiff(c1, c2){
1332         var len1 = c1.length,
1333                 d = ++key,
1334                 r = [];
1335         if(!len1){
1336             return c2;
1337         }
1338         if(isIE && typeof c1[0].selectSingleNode != "undefined"){
1339             return quickDiffIEXml(c1, c2);
1340         }        
1341         for(var i = 0; i < len1; i++){
1342             c1[i]._qdiff = d;
1343         }        
1344         for(var i = 0, len = c2.length; i < len; i++){
1345             if(c2[i]._qdiff != d){
1346                 r[r.length] = c2[i];
1347             }
1348         }
1349         return r;
1350     }
1351
1352     function quickId(ns, mode, root, id){
1353         if(ns == root){
1354            var d = root.ownerDocument || root;
1355            return d.getElementById(id);
1356         }
1357         ns = getNodes(ns, mode, "*");
1358         return byId(ns, id);
1359     }
1360
1361     return {
1362         getStyle : function(el, name){
1363             return Ext.fly(el).getStyle(name);
1364         },
1365         /**
1366          * Compiles a selector/xpath query into a reusable function. The returned function
1367          * takes one parameter "root" (optional), which is the context node from where the query should start.
1368          * @param {String} selector The selector/xpath query
1369          * @param {String} type (optional) Either "select" (the default) or "simple" for a simple selector match
1370          * @return {Function}
1371          */
1372         compile : function(path, type){
1373             type = type || "select";
1374
1375             // setup fn preamble
1376             var fn = ["var f = function(root){\n var mode; ++batch; var n = root || document;\n"],
1377                 mode,           
1378                 lastPath,
1379                 matchers = Ext.DomQuery.matchers,
1380                 matchersLn = matchers.length,
1381                 modeMatch,
1382                 // accept leading mode switch
1383                 lmode = path.match(modeRe);
1384             
1385             if(lmode && lmode[1]){
1386                 fn[fn.length] = 'mode="'+lmode[1].replace(trimRe, "")+'";';
1387                 path = path.replace(lmode[1], "");
1388             }
1389             
1390             // strip leading slashes
1391             while(path.substr(0, 1)=="/"){
1392                 path = path.substr(1);
1393             }
1394
1395             while(path && lastPath != path){
1396                 lastPath = path;
1397                 var tokenMatch = path.match(tagTokenRe);
1398                 if(type == "select"){
1399                     if(tokenMatch){
1400                         // ID Selector
1401                         if(tokenMatch[1] == "#"){
1402                             fn[fn.length] = 'n = quickId(n, mode, root, "'+tokenMatch[2]+'");';                 
1403                         }else{
1404                             fn[fn.length] = 'n = getNodes(n, mode, "'+tokenMatch[2]+'");';
1405                         }
1406                         path = path.replace(tokenMatch[0], "");
1407                     }else if(path.substr(0, 1) != '@'){
1408                         fn[fn.length] = 'n = getNodes(n, mode, "*");';
1409                     }
1410                 // type of "simple"
1411                 }else{
1412                     if(tokenMatch){
1413                         if(tokenMatch[1] == "#"){
1414                             fn[fn.length] = 'n = byId(n, "'+tokenMatch[2]+'");';
1415                         }else{
1416                             fn[fn.length] = 'n = byTag(n, "'+tokenMatch[2]+'");';
1417                         }
1418                         path = path.replace(tokenMatch[0], "");
1419                     }
1420                 }
1421                 while(!(modeMatch = path.match(modeRe))){
1422                     var matched = false;
1423                     for(var j = 0; j < matchersLn; j++){
1424                         var t = matchers[j];
1425                         var m = path.match(t.re);
1426                         if(m){
1427                             fn[fn.length] = t.select.replace(tplRe, function(x, i){
1428                                 return m[i];
1429                             });
1430                             path = path.replace(m[0], "");
1431                             matched = true;
1432                             break;
1433                         }
1434                     }
1435                     // prevent infinite loop on bad selector
1436                     if(!matched){
1437                         throw 'Error parsing selector, parsing failed at "' + path + '"';
1438                     }
1439                 }
1440                 if(modeMatch[1]){
1441                     fn[fn.length] = 'mode="'+modeMatch[1].replace(trimRe, "")+'";';
1442                     path = path.replace(modeMatch[1], "");
1443                 }
1444             }
1445             // close fn out
1446             fn[fn.length] = "return nodup(n);\n}";
1447             
1448             // eval fn and return it
1449             eval(fn.join(""));
1450             return f;
1451         },
1452
1453         /**
1454          * Selects a group of elements.
1455          * @param {String} selector The selector/xpath query (can be a comma separated list of selectors)
1456          * @param {Node/String} root (optional) The start of the query (defaults to document).
1457          * @return {Array} An Array of DOM elements which match the selector. If there are
1458          * no matches, and empty Array is returned.
1459          */
1460         jsSelect: function(path, root, type){
1461             // set root to doc if not specified.
1462             root = root || document;
1463             
1464             if(typeof root == "string"){
1465                 root = document.getElementById(root);
1466             }
1467             var paths = path.split(","),
1468                 results = [];
1469                 
1470             // loop over each selector
1471             for(var i = 0, len = paths.length; i < len; i++){           
1472                 var subPath = paths[i].replace(trimRe, "");
1473                 // compile and place in cache
1474                 if(!cache[subPath]){
1475                     cache[subPath] = Ext.DomQuery.compile(subPath);
1476                     if(!cache[subPath]){
1477                         throw subPath + " is not a valid selector";
1478                     }
1479                 }
1480                 var result = cache[subPath](root);
1481                 if(result && result != document){
1482                     results = results.concat(result);
1483                 }
1484             }
1485             
1486             // if there were multiple selectors, make sure dups
1487             // are eliminated
1488             if(paths.length > 1){
1489                 return nodup(results);
1490             }
1491             return results;
1492         },
1493         isXml: function(el) {
1494             var docEl = (el ? el.ownerDocument || el : 0).documentElement;
1495             return docEl ? docEl.nodeName !== "HTML" : false;
1496         },
1497         select : document.querySelectorAll ? function(path, root, type) {
1498             root = root || document;
1499             if (!Ext.DomQuery.isXml(root)) {
1500                 try {
1501                     var cs = root.querySelectorAll(path);
1502                     return Ext.toArray(cs);
1503                 }
1504                 catch (ex) {}           
1505             }       
1506             return Ext.DomQuery.jsSelect.call(this, path, root, type);
1507         } : function(path, root, type) {
1508             return Ext.DomQuery.jsSelect.call(this, path, root, type);
1509         },
1510
1511         /**
1512          * Selects a single element.
1513          * @param {String} selector The selector/xpath query
1514          * @param {Node} root (optional) The start of the query (defaults to document).
1515          * @return {Element} The DOM element which matched the selector.
1516          */
1517         selectNode : function(path, root){
1518             return Ext.DomQuery.select(path, root)[0];
1519         },
1520
1521         /**
1522          * Selects the value of a node, optionally replacing null with the defaultValue.
1523          * @param {String} selector The selector/xpath query
1524          * @param {Node} root (optional) The start of the query (defaults to document).
1525          * @param {String} defaultValue
1526          * @return {String}
1527          */
1528         selectValue : function(path, root, defaultValue){
1529             path = path.replace(trimRe, "");
1530             if(!valueCache[path]){
1531                 valueCache[path] = Ext.DomQuery.compile(path, "select");
1532             }
1533             var n = valueCache[path](root), v;
1534             n = n[0] ? n[0] : n;
1535                     
1536             // overcome a limitation of maximum textnode size
1537             // Rumored to potentially crash IE6 but has not been confirmed.
1538             // http://reference.sitepoint.com/javascript/Node/normalize
1539             // https://developer.mozilla.org/En/DOM/Node.normalize          
1540             if (typeof n.normalize == 'function') n.normalize();
1541             
1542             v = (n && n.firstChild ? n.firstChild.nodeValue : null);
1543             return ((v === null||v === undefined||v==='') ? defaultValue : v);
1544         },
1545
1546         /**
1547          * Selects the value of a node, parsing integers and floats. Returns the defaultValue, or 0 if none is specified.
1548          * @param {String} selector The selector/xpath query
1549          * @param {Node} root (optional) The start of the query (defaults to document).
1550          * @param {Number} defaultValue
1551          * @return {Number}
1552          */
1553         selectNumber : function(path, root, defaultValue){
1554             var v = Ext.DomQuery.selectValue(path, root, defaultValue || 0);
1555             return parseFloat(v);
1556         },
1557
1558         /**
1559          * Returns true if the passed element(s) match the passed simple selector (e.g. div.some-class or span:first-child)
1560          * @param {String/HTMLElement/Array} el An element id, element or array of elements
1561          * @param {String} selector The simple selector to test
1562          * @return {Boolean}
1563          */
1564         is : function(el, ss){
1565             if(typeof el == "string"){
1566                 el = document.getElementById(el);
1567             }
1568             var isArray = Ext.isArray(el),
1569                 result = Ext.DomQuery.filter(isArray ? el : [el], ss);
1570             return isArray ? (result.length == el.length) : (result.length > 0);
1571         },
1572
1573         /**
1574          * Filters an array of elements to only include matches of a simple selector (e.g. div.some-class or span:first-child)
1575          * @param {Array} el An array of elements to filter
1576          * @param {String} selector The simple selector to test
1577          * @param {Boolean} nonMatches If true, it returns the elements that DON'T match
1578          * the selector instead of the ones that match
1579          * @return {Array} An Array of DOM elements which match the selector. If there are
1580          * no matches, and empty Array is returned.
1581          */
1582         filter : function(els, ss, nonMatches){
1583             ss = ss.replace(trimRe, "");
1584             if(!simpleCache[ss]){
1585                 simpleCache[ss] = Ext.DomQuery.compile(ss, "simple");
1586             }
1587             var result = simpleCache[ss](els);
1588             return nonMatches ? quickDiff(result, els) : result;
1589         },
1590
1591         /**
1592          * Collection of matching regular expressions and code snippets.
1593          * Each capture group within () will be replace the {} in the select
1594          * statement as specified by their index.
1595          */
1596         matchers : [{
1597                 re: /^\.([\w-]+)/,
1598                 select: 'n = byClassName(n, " {1} ");'
1599             }, {
1600                 re: /^\:([\w-]+)(?:\(((?:[^\s>\/]*|.*?))\))?/,
1601                 select: 'n = byPseudo(n, "{1}", "{2}");'
1602             },{
1603                 re: /^(?:([\[\{])(?:@)?([\w-]+)\s?(?:(=|.=)\s?['"]?(.*?)["']?)?[\]\}])/,
1604                 select: 'n = byAttribute(n, "{2}", "{4}", "{3}", "{1}");'
1605             }, {
1606                 re: /^#([\w-]+)/,
1607                 select: 'n = byId(n, "{1}");'
1608             },{
1609                 re: /^@([\w-]+)/,
1610                 select: 'return {firstChild:{nodeValue:attrValue(n, "{1}")}};'
1611             }
1612         ],
1613
1614         /**
1615          * Collection of operator comparison functions. The default operators are =, !=, ^=, $=, *=, %=, |= and ~=.
1616          * New operators can be added as long as the match the format <i>c</i>= where <i>c</i> is any character other than space, &gt; &lt;.
1617          */
1618         operators : {
1619             "=" : function(a, v){
1620                 return a == v;
1621             },
1622             "!=" : function(a, v){
1623                 return a != v;
1624             },
1625             "^=" : function(a, v){
1626                 return a && a.substr(0, v.length) == v;
1627             },
1628             "$=" : function(a, v){
1629                 return a && a.substr(a.length-v.length) == v;
1630             },
1631             "*=" : function(a, v){
1632                 return a && a.indexOf(v) !== -1;
1633             },
1634             "%=" : function(a, v){
1635                 return (a % v) == 0;
1636             },
1637             "|=" : function(a, v){
1638                 return a && (a == v || a.substr(0, v.length+1) == v+'-');
1639             },
1640             "~=" : function(a, v){
1641                 return a && (' '+a+' ').indexOf(' '+v+' ') != -1;
1642             }
1643         },
1644
1645         /**
1646          * <p>Object hash of "pseudo class" filter functions which are used when filtering selections. Each function is passed
1647          * two parameters:</p><div class="mdetail-params"><ul>
1648          * <li><b>c</b> : Array<div class="sub-desc">An Array of DOM elements to filter.</div></li>
1649          * <li><b>v</b> : String<div class="sub-desc">The argument (if any) supplied in the selector.</div></li>
1650          * </ul></div>
1651          * <p>A filter function returns an Array of DOM elements which conform to the pseudo class.</p>
1652          * <p>In addition to the provided pseudo classes listed above such as <code>first-child</code> and <code>nth-child</code>,
1653          * developers may add additional, custom psuedo class filters to select elements according to application-specific requirements.</p>
1654          * <p>For example, to filter <code>&lt;a></code> elements to only return links to <i>external</i> resources:</p>
1655          * <code><pre>
1656 Ext.DomQuery.pseudos.external = function(c, v){
1657     var r = [], ri = -1;
1658     for(var i = 0, ci; ci = c[i]; i++){
1659 //      Include in result set only if it's a link to an external resource
1660         if(ci.hostname != location.hostname){
1661             r[++ri] = ci;
1662         }
1663     }
1664     return r;
1665 };</pre></code>
1666          * Then external links could be gathered with the following statement:<code><pre>
1667 var externalLinks = Ext.select("a:external");
1668 </code></pre>
1669          */
1670         pseudos : {
1671             "first-child" : function(c){
1672                 var r = [], ri = -1, n;
1673                 for(var i = 0, ci; ci = n = c[i]; i++){
1674                     while((n = n.previousSibling) && n.nodeType != 1);
1675                     if(!n){
1676                         r[++ri] = ci;
1677                     }
1678                 }
1679                 return r;
1680             },
1681
1682             "last-child" : function(c){
1683                 var r = [], ri = -1, n;
1684                 for(var i = 0, ci; ci = n = c[i]; i++){
1685                     while((n = n.nextSibling) && n.nodeType != 1);
1686                     if(!n){
1687                         r[++ri] = ci;
1688                     }
1689                 }
1690                 return r;
1691             },
1692
1693             "nth-child" : function(c, a) {
1694                 var r = [], ri = -1,
1695                         m = nthRe.exec(a == "even" && "2n" || a == "odd" && "2n+1" || !nthRe2.test(a) && "n+" + a || a),
1696                         f = (m[1] || 1) - 0, l = m[2] - 0;
1697                 for(var i = 0, n; n = c[i]; i++){
1698                     var pn = n.parentNode;
1699                     if (batch != pn._batch) {
1700                         var j = 0;
1701                         for(var cn = pn.firstChild; cn; cn = cn.nextSibling){
1702                             if(cn.nodeType == 1){
1703                                cn.nodeIndex = ++j;
1704                             }
1705                         }
1706                         pn._batch = batch;
1707                     }
1708                     if (f == 1) {
1709                         if (l == 0 || n.nodeIndex == l){
1710                             r[++ri] = n;
1711                         }
1712                     } else if ((n.nodeIndex + l) % f == 0){
1713                         r[++ri] = n;
1714                     }
1715                 }
1716
1717                 return r;
1718             },
1719
1720             "only-child" : function(c){
1721                 var r = [], ri = -1;;
1722                 for(var i = 0, ci; ci = c[i]; i++){
1723                     if(!prev(ci) && !next(ci)){
1724                         r[++ri] = ci;
1725                     }
1726                 }
1727                 return r;
1728             },
1729
1730             "empty" : function(c){
1731                 var r = [], ri = -1;
1732                 for(var i = 0, ci; ci = c[i]; i++){
1733                     var cns = ci.childNodes, j = 0, cn, empty = true;
1734                     while(cn = cns[j]){
1735                         ++j;
1736                         if(cn.nodeType == 1 || cn.nodeType == 3){
1737                             empty = false;
1738                             break;
1739                         }
1740                     }
1741                     if(empty){
1742                         r[++ri] = ci;
1743                     }
1744                 }
1745                 return r;
1746             },
1747
1748             "contains" : function(c, v){
1749                 var r = [], ri = -1;
1750                 for(var i = 0, ci; ci = c[i]; i++){
1751                     if((ci.textContent||ci.innerText||'').indexOf(v) != -1){
1752                         r[++ri] = ci;
1753                     }
1754                 }
1755                 return r;
1756             },
1757
1758             "nodeValue" : function(c, v){
1759                 var r = [], ri = -1;
1760                 for(var i = 0, ci; ci = c[i]; i++){
1761                     if(ci.firstChild && ci.firstChild.nodeValue == v){
1762                         r[++ri] = ci;
1763                     }
1764                 }
1765                 return r;
1766             },
1767
1768             "checked" : function(c){
1769                 var r = [], ri = -1;
1770                 for(var i = 0, ci; ci = c[i]; i++){
1771                     if(ci.checked == true){
1772                         r[++ri] = ci;
1773                     }
1774                 }
1775                 return r;
1776             },
1777
1778             "not" : function(c, ss){
1779                 return Ext.DomQuery.filter(c, ss, true);
1780             },
1781
1782             "any" : function(c, selectors){
1783                 var ss = selectors.split('|'),
1784                         r = [], ri = -1, s;
1785                 for(var i = 0, ci; ci = c[i]; i++){
1786                     for(var j = 0; s = ss[j]; j++){
1787                         if(Ext.DomQuery.is(ci, s)){
1788                             r[++ri] = ci;
1789                             break;
1790                         }
1791                     }
1792                 }
1793                 return r;
1794             },
1795
1796             "odd" : function(c){
1797                 return this["nth-child"](c, "odd");
1798             },
1799
1800             "even" : function(c){
1801                 return this["nth-child"](c, "even");
1802             },
1803
1804             "nth" : function(c, a){
1805                 return c[a-1] || [];
1806             },
1807
1808             "first" : function(c){
1809                 return c[0] || [];
1810             },
1811
1812             "last" : function(c){
1813                 return c[c.length-1] || [];
1814             },
1815
1816             "has" : function(c, ss){
1817                 var s = Ext.DomQuery.select,
1818                         r = [], ri = -1;
1819                 for(var i = 0, ci; ci = c[i]; i++){
1820                     if(s(ss, ci).length > 0){
1821                         r[++ri] = ci;
1822                     }
1823                 }
1824                 return r;
1825             },
1826
1827             "next" : function(c, ss){
1828                 var is = Ext.DomQuery.is,
1829                         r = [], ri = -1;
1830                 for(var i = 0, ci; ci = c[i]; i++){
1831                     var n = next(ci);
1832                     if(n && is(n, ss)){
1833                         r[++ri] = ci;
1834                     }
1835                 }
1836                 return r;
1837             },
1838
1839             "prev" : function(c, ss){
1840                 var is = Ext.DomQuery.is,
1841                         r = [], ri = -1;
1842                 for(var i = 0, ci; ci = c[i]; i++){
1843                     var n = prev(ci);
1844                     if(n && is(n, ss)){
1845                         r[++ri] = ci;
1846                     }
1847                 }
1848                 return r;
1849             }
1850         }
1851     };
1852 }();
1853
1854 /**
1855  * Selects an array of DOM nodes by CSS/XPath selector. Shorthand of {@link Ext.DomQuery#select}
1856  * @param {String} path The selector/xpath query
1857  * @param {Node} root (optional) The start of the query (defaults to document).
1858  * @return {Array}
1859  * @member Ext
1860  * @method query
1861  */
1862 Ext.query = Ext.DomQuery.select;
1863 /**
1864  * @class Ext.util.DelayedTask
1865  * <p> The DelayedTask class provides a convenient way to "buffer" the execution of a method,
1866  * performing setTimeout where a new timeout cancels the old timeout. When called, the
1867  * task will wait the specified time period before executing. If durng that time period,
1868  * the task is called again, the original call will be cancelled. This continues so that
1869  * the function is only called a single time for each iteration.</p>
1870  * <p>This method is especially useful for things like detecting whether a user has finished
1871  * typing in a text field. An example would be performing validation on a keypress. You can
1872  * use this class to buffer the keypress events for a certain number of milliseconds, and
1873  * perform only if they stop for that amount of time.  Usage:</p><pre><code>
1874 var task = new Ext.util.DelayedTask(function(){
1875     alert(Ext.getDom('myInputField').value.length);
1876 });
1877 // Wait 500ms before calling our function. If the user presses another key 
1878 // during that 500ms, it will be cancelled and we'll wait another 500ms.
1879 Ext.get('myInputField').on('keypress', function(){
1880     task.{@link #delay}(500); 
1881 });
1882  * </code></pre> 
1883  * <p>Note that we are using a DelayedTask here to illustrate a point. The configuration
1884  * option <tt>buffer</tt> for {@link Ext.util.Observable#addListener addListener/on} will
1885  * also setup a delayed task for you to buffer events.</p> 
1886  * @constructor The parameters to this constructor serve as defaults and are not required.
1887  * @param {Function} fn (optional) The default function to call.
1888  * @param {Object} scope The default scope (The <code><b>this</b></code> reference) in which the
1889  * function is called. If not specified, <code>this</code> will refer to the browser window.
1890  * @param {Array} args (optional) The default Array of arguments.
1891  */
1892 Ext.util.DelayedTask = function(fn, scope, args){
1893     var me = this,
1894         id,     
1895         call = function(){
1896                 clearInterval(id);
1897                 id = null;
1898                 fn.apply(scope, args || []);
1899             };
1900             
1901     /**
1902      * Cancels any pending timeout and queues a new one
1903      * @param {Number} delay The milliseconds to delay
1904      * @param {Function} newFn (optional) Overrides function passed to constructor
1905      * @param {Object} newScope (optional) Overrides scope passed to constructor. Remember that if no scope
1906      * is specified, <code>this</code> will refer to the browser window.
1907      * @param {Array} newArgs (optional) Overrides args passed to constructor
1908      */
1909     me.delay = function(delay, newFn, newScope, newArgs){
1910         me.cancel();
1911         fn = newFn || fn;
1912         scope = newScope || scope;
1913         args = newArgs || args;
1914         id = setInterval(call, delay);
1915     };
1916
1917     /**
1918      * Cancel the last queued timeout
1919      */
1920     me.cancel = function(){
1921         if(id){
1922             clearInterval(id);
1923             id = null;
1924         }
1925     };
1926 };(function(){
1927
1928 var EXTUTIL = Ext.util,
1929     EACH = Ext.each,
1930     TRUE = true,
1931     FALSE = false;
1932 /**
1933  * @class Ext.util.Observable
1934  * Base class that provides a common interface for publishing events. Subclasses are expected to
1935  * to have a property "events" with all the events defined, and, optionally, a property "listeners"
1936  * with configured listeners defined.<br>
1937  * For example:
1938  * <pre><code>
1939 Employee = Ext.extend(Ext.util.Observable, {
1940     constructor: function(config){
1941         this.name = config.name;
1942         this.addEvents({
1943             "fired" : true,
1944             "quit" : true
1945         });
1946
1947         // Copy configured listeners into *this* object so that the base class&#39;s
1948         // constructor will add them.
1949         this.listeners = config.listeners;
1950
1951         // Call our superclass constructor to complete construction process.
1952         Employee.superclass.constructor.call(this, config)
1953     }
1954 });
1955 </code></pre>
1956  * This could then be used like this:<pre><code>
1957 var newEmployee = new Employee({
1958     name: employeeName,
1959     listeners: {
1960         quit: function() {
1961             // By default, "this" will be the object that fired the event.
1962             alert(this.name + " has quit!");
1963         }
1964     }
1965 });
1966 </code></pre>
1967  */
1968 EXTUTIL.Observable = function(){
1969     /**
1970      * @cfg {Object} listeners (optional) <p>A config object containing one or more event handlers to be added to this
1971      * object during initialization.  This should be a valid listeners config object as specified in the
1972      * {@link #addListener} example for attaching multiple handlers at once.</p>
1973      * <br><p><b><u>DOM events from ExtJs {@link Ext.Component Components}</u></b></p>
1974      * <br><p>While <i>some</i> ExtJs Component classes export selected DOM events (e.g. "click", "mouseover" etc), this
1975      * is usually only done when extra value can be added. For example the {@link Ext.DataView DataView}'s
1976      * <b><code>{@link Ext.DataView#click click}</code></b> event passing the node clicked on. To access DOM
1977      * events directly from a Component's HTMLElement, listeners must be added to the <i>{@link Ext.Component#getEl Element}</i> after the Component
1978      * has been rendered. A plugin can simplify this step:<pre><code>
1979 // Plugin is configured with a listeners config object.
1980 // The Component is appended to the argument list of all handler functions.
1981 Ext.DomObserver = Ext.extend(Object, {
1982     constructor: function(config) {
1983         this.listeners = config.listeners ? config.listeners : config;
1984     },
1985
1986     // Component passes itself into plugin&#39;s init method
1987     init: function(c) {
1988         var p, l = this.listeners;
1989         for (p in l) {
1990             if (Ext.isFunction(l[p])) {
1991                 l[p] = this.createHandler(l[p], c);
1992             } else {
1993                 l[p].fn = this.createHandler(l[p].fn, c);
1994             }
1995         }
1996
1997         // Add the listeners to the Element immediately following the render call
1998         c.render = c.render.{@link Function#createSequence createSequence}(function() {
1999             var e = c.getEl();
2000             if (e) {
2001                 e.on(l);
2002             }
2003         });
2004     },
2005
2006     createHandler: function(fn, c) {
2007         return function(e) {
2008             fn.call(this, e, c);
2009         };
2010     }
2011 });
2012
2013 var combo = new Ext.form.ComboBox({
2014
2015     // Collapse combo when its element is clicked on
2016     plugins: [ new Ext.DomObserver({
2017         click: function(evt, comp) {
2018             comp.collapse();
2019         }
2020     })],
2021     store: myStore,
2022     typeAhead: true,
2023     mode: 'local',
2024     triggerAction: 'all'
2025 });
2026      * </code></pre></p>
2027      */
2028     var me = this, e = me.events;
2029     if(me.listeners){
2030         me.on(me.listeners);
2031         delete me.listeners;
2032     }
2033     me.events = e || {};
2034 };
2035
2036 EXTUTIL.Observable.prototype = {
2037     // private
2038     filterOptRe : /^(?:scope|delay|buffer|single)$/,
2039
2040     /**
2041      * <p>Fires the specified event with the passed parameters (minus the event name).</p>
2042      * <p>An event may be set to bubble up an Observable parent hierarchy (See {@link Ext.Component#getBubbleTarget})
2043      * by calling {@link #enableBubble}.</p>
2044      * @param {String} eventName The name of the event to fire.
2045      * @param {Object...} args Variable number of parameters are passed to handlers.
2046      * @return {Boolean} returns false if any of the handlers return false otherwise it returns true.
2047      */
2048     fireEvent : function(){
2049         var a = Array.prototype.slice.call(arguments, 0),
2050             ename = a[0].toLowerCase(),
2051             me = this,
2052             ret = TRUE,
2053             ce = me.events[ename],
2054             cc,
2055             q,
2056             c;
2057         if (me.eventsSuspended === TRUE) {
2058             if (q = me.eventQueue) {
2059                 q.push(a);
2060             }
2061         }
2062         else if(typeof ce == 'object') {
2063             if (ce.bubble){
2064                 if(ce.fire.apply(ce, a.slice(1)) === FALSE) {
2065                     return FALSE;
2066                 }
2067                 c = me.getBubbleTarget && me.getBubbleTarget();
2068                 if(c && c.enableBubble) {
2069                     cc = c.events[ename];
2070                     if(!cc || typeof cc != 'object' || !cc.bubble) {
2071                         c.enableBubble(ename);
2072                     }
2073                     return c.fireEvent.apply(c, a);
2074                 }
2075             }
2076             else {
2077                 a.shift();
2078                 ret = ce.fire.apply(ce, a);
2079             }
2080         }
2081         return ret;
2082     },
2083
2084     /**
2085      * Appends an event handler to this object.
2086      * @param {String}   eventName The name of the event to listen for.
2087      * @param {Function} handler The method the event invokes.
2088      * @param {Object}   scope (optional) The scope (<code><b>this</b></code> reference) in which the handler function is executed.
2089      * <b>If omitted, defaults to the object which fired the event.</b>
2090      * @param {Object}   options (optional) An object containing handler configuration.
2091      * properties. This may contain any of the following properties:<ul>
2092      * <li><b>scope</b> : Object<div class="sub-desc">The scope (<code><b>this</b></code> reference) in which the handler function is executed.
2093      * <b>If omitted, defaults to the object which fired the event.</b></div></li>
2094      * <li><b>delay</b> : Number<div class="sub-desc">The number of milliseconds to delay the invocation of the handler after the event fires.</div></li>
2095      * <li><b>single</b> : Boolean<div class="sub-desc">True to add a handler to handle just the next firing of the event, and then remove itself.</div></li>
2096      * <li><b>buffer</b> : Number<div class="sub-desc">Causes the handler to be scheduled to run in an {@link Ext.util.DelayedTask} delayed
2097      * by the specified number of milliseconds. If the event fires again within that time, the original
2098      * handler is <em>not</em> invoked, but the new handler is scheduled in its place.</div></li>
2099      * <li><b>target</b> : Observable<div class="sub-desc">Only call the handler if the event was fired on the target Observable, <i>not</i>
2100      * if the event was bubbled up from a child Observable.</div></li>
2101      * </ul><br>
2102      * <p>
2103      * <b>Combining Options</b><br>
2104      * Using the options argument, it is possible to combine different types of listeners:<br>
2105      * <br>
2106      * A delayed, one-time listener.
2107      * <pre><code>
2108 myDataView.on('click', this.onClick, this, {
2109 single: true,
2110 delay: 100
2111 });</code></pre>
2112      * <p>
2113      * <b>Attaching multiple handlers in 1 call</b><br>
2114      * The method also allows for a single argument to be passed which is a config object containing properties
2115      * which specify multiple handlers.
2116      * <p>
2117      * <pre><code>
2118 myGridPanel.on({
2119 'click' : {
2120     fn: this.onClick,
2121     scope: this,
2122     delay: 100
2123 },
2124 'mouseover' : {
2125     fn: this.onMouseOver,
2126     scope: this
2127 },
2128 'mouseout' : {
2129     fn: this.onMouseOut,
2130     scope: this
2131 }
2132 });</code></pre>
2133  * <p>
2134  * Or a shorthand syntax:<br>
2135  * <pre><code>
2136 myGridPanel.on({
2137 'click' : this.onClick,
2138 'mouseover' : this.onMouseOver,
2139 'mouseout' : this.onMouseOut,
2140  scope: this
2141 });</code></pre>
2142      */
2143     addListener : function(eventName, fn, scope, o){
2144         var me = this,
2145             e,
2146             oe,
2147             isF,
2148         ce;
2149         if (typeof eventName == 'object') {
2150             o = eventName;
2151             for (e in o){
2152                 oe = o[e];
2153                 if (!me.filterOptRe.test(e)) {
2154                     me.addListener(e, oe.fn || oe, oe.scope || o.scope, oe.fn ? oe : o);
2155                 }
2156             }
2157         } else {
2158             eventName = eventName.toLowerCase();
2159             ce = me.events[eventName] || TRUE;
2160             if (typeof ce == 'boolean') {
2161                 me.events[eventName] = ce = new EXTUTIL.Event(me, eventName);
2162             }
2163             ce.addListener(fn, scope, typeof o == 'object' ? o : {});
2164         }
2165     },
2166
2167     /**
2168      * Removes an event handler.
2169      * @param {String}   eventName The type of event the handler was associated with.
2170      * @param {Function} handler   The handler to remove. <b>This must be a reference to the function passed into the {@link #addListener} call.</b>
2171      * @param {Object}   scope     (optional) The scope originally specified for the handler.
2172      */
2173     removeListener : function(eventName, fn, scope){
2174         var ce = this.events[eventName.toLowerCase()];
2175         if (typeof ce == 'object') {
2176             ce.removeListener(fn, scope);
2177         }
2178     },
2179
2180     /**
2181      * Removes all listeners for this object
2182      */
2183     purgeListeners : function(){
2184         var events = this.events,
2185             evt,
2186             key;
2187         for(key in events){
2188             evt = events[key];
2189             if(typeof evt == 'object'){
2190                 evt.clearListeners();
2191             }
2192         }
2193     },
2194
2195     /**
2196      * Adds the specified events to the list of events which this Observable may fire.
2197      * @param {Object|String} o Either an object with event names as properties with a value of <code>true</code>
2198      * or the first event name string if multiple event names are being passed as separate parameters.
2199      * @param {string} Optional. Event name if multiple event names are being passed as separate parameters.
2200      * Usage:<pre><code>
2201 this.addEvents('storeloaded', 'storecleared');
2202 </code></pre>
2203      */
2204     addEvents : function(o){
2205         var me = this;
2206         me.events = me.events || {};
2207         if (typeof o == 'string') {
2208             var a = arguments,
2209                 i = a.length;
2210             while(i--) {
2211                 me.events[a[i]] = me.events[a[i]] || TRUE;
2212             }
2213         } else {
2214             Ext.applyIf(me.events, o);
2215         }
2216     },
2217
2218     /**
2219      * Checks to see if this object has any listeners for a specified event
2220      * @param {String} eventName The name of the event to check for
2221      * @return {Boolean} True if the event is being listened for, else false
2222      */
2223     hasListener : function(eventName){
2224         var e = this.events[eventName.toLowerCase()];
2225         return typeof e == 'object' && e.listeners.length > 0;
2226     },
2227
2228     /**
2229      * Suspend the firing of all events. (see {@link #resumeEvents})
2230      * @param {Boolean} queueSuspended Pass as true to queue up suspended events to be fired
2231      * after the {@link #resumeEvents} call instead of discarding all suspended events;
2232      */
2233     suspendEvents : function(queueSuspended){
2234         this.eventsSuspended = TRUE;
2235         if(queueSuspended && !this.eventQueue){
2236             this.eventQueue = [];
2237         }
2238     },
2239
2240     /**
2241      * Resume firing events. (see {@link #suspendEvents})
2242      * If events were suspended using the <tt><b>queueSuspended</b></tt> parameter, then all
2243      * events fired during event suspension will be sent to any listeners now.
2244      */
2245     resumeEvents : function(){
2246         var me = this,
2247             queued = me.eventQueue || [];
2248         me.eventsSuspended = FALSE;
2249         delete me.eventQueue;
2250         EACH(queued, function(e) {
2251             me.fireEvent.apply(me, e);
2252         });
2253     }
2254 };
2255
2256 var OBSERVABLE = EXTUTIL.Observable.prototype;
2257 /**
2258  * Appends an event handler to this object (shorthand for {@link #addListener}.)
2259  * @param {String}   eventName     The type of event to listen for
2260  * @param {Function} handler       The method the event invokes
2261  * @param {Object}   scope         (optional) The scope (<code><b>this</b></code> reference) in which the handler function is executed.
2262  * <b>If omitted, defaults to the object which fired the event.</b>
2263  * @param {Object}   options       (optional) An object containing handler configuration.
2264  * @method
2265  */
2266 OBSERVABLE.on = OBSERVABLE.addListener;
2267 /**
2268  * Removes an event handler (shorthand for {@link #removeListener}.)
2269  * @param {String}   eventName     The type of event the handler was associated with.
2270  * @param {Function} handler       The handler to remove. <b>This must be a reference to the function passed into the {@link #addListener} call.</b>
2271  * @param {Object}   scope         (optional) The scope originally specified for the handler.
2272  * @method
2273  */
2274 OBSERVABLE.un = OBSERVABLE.removeListener;
2275
2276 /**
2277  * Removes <b>all</b> added captures from the Observable.
2278  * @param {Observable} o The Observable to release
2279  * @static
2280  */
2281 EXTUTIL.Observable.releaseCapture = function(o){
2282     o.fireEvent = OBSERVABLE.fireEvent;
2283 };
2284
2285 function createTargeted(h, o, scope){
2286     return function(){
2287         if(o.target == arguments[0]){
2288             h.apply(scope, Array.prototype.slice.call(arguments, 0));
2289         }
2290     };
2291 };
2292
2293 function createBuffered(h, o, l, scope){
2294     l.task = new EXTUTIL.DelayedTask();
2295     return function(){
2296         l.task.delay(o.buffer, h, scope, Array.prototype.slice.call(arguments, 0));
2297     };
2298 };
2299
2300 function createSingle(h, e, fn, scope){
2301     return function(){
2302         e.removeListener(fn, scope);
2303         return h.apply(scope, arguments);
2304     };
2305 };
2306
2307 function createDelayed(h, o, l, scope){
2308     return function(){
2309         var task = new EXTUTIL.DelayedTask();
2310         if(!l.tasks) {
2311             l.tasks = [];
2312         }
2313         l.tasks.push(task);
2314         task.delay(o.delay || 10, h, scope, Array.prototype.slice.call(arguments, 0));
2315     };
2316 };
2317
2318 EXTUTIL.Event = function(obj, name){
2319     this.name = name;
2320     this.obj = obj;
2321     this.listeners = [];
2322 };
2323
2324 EXTUTIL.Event.prototype = {
2325     addListener : function(fn, scope, options){
2326         var me = this,
2327             l;
2328         scope = scope || me.obj;
2329         if(!me.isListening(fn, scope)){
2330             l = me.createListener(fn, scope, options);
2331             if(me.firing){ // if we are currently firing this event, don't disturb the listener loop
2332                 me.listeners = me.listeners.slice(0);
2333             }
2334             me.listeners.push(l);
2335         }
2336     },
2337
2338     createListener: function(fn, scope, o){
2339         o = o || {}, scope = scope || this.obj;
2340         var l = {
2341             fn: fn,
2342             scope: scope,
2343             options: o
2344         }, h = fn;
2345         if(o.target){
2346             h = createTargeted(h, o, scope);
2347         }
2348         if(o.delay){
2349             h = createDelayed(h, o, l, scope);
2350         }
2351         if(o.single){
2352             h = createSingle(h, this, fn, scope);
2353         }
2354         if(o.buffer){
2355             h = createBuffered(h, o, l, scope);
2356         }
2357         l.fireFn = h;
2358         return l;
2359     },
2360
2361     findListener : function(fn, scope){
2362         var list = this.listeners,
2363             i = list.length,
2364             l;
2365
2366         scope = scope || this.obj;
2367         while(i--){
2368             l = list[i];
2369             if(l){
2370                 if(l.fn == fn && l.scope == scope){
2371                     return i;
2372                 }
2373             }
2374         }
2375         return -1;
2376     },
2377
2378     isListening : function(fn, scope){
2379         return this.findListener(fn, scope) != -1;
2380     },
2381
2382     removeListener : function(fn, scope){
2383         var index,
2384             l,
2385             k,
2386             me = this,
2387             ret = FALSE;
2388         if((index = me.findListener(fn, scope)) != -1){
2389             if (me.firing) {
2390                 me.listeners = me.listeners.slice(0);
2391             }
2392             l = me.listeners[index];
2393             if(l.task) {
2394                 l.task.cancel();
2395                 delete l.task;
2396             }
2397             k = l.tasks && l.tasks.length;
2398             if(k) {
2399                 while(k--) {
2400                     l.tasks[k].cancel();
2401                 }
2402                 delete l.tasks;
2403             }
2404             me.listeners.splice(index, 1);
2405             ret = TRUE;
2406         }
2407         return ret;
2408     },
2409
2410     // Iterate to stop any buffered/delayed events
2411     clearListeners : function(){
2412         var me = this,
2413             l = me.listeners,
2414             i = l.length;
2415         while(i--) {
2416             me.removeListener(l[i].fn, l[i].scope);
2417         }
2418     },
2419
2420     fire : function(){
2421         var me = this,
2422             listeners = me.listeners,
2423             len = listeners.length,
2424             i = 0,
2425             l;
2426
2427         if(len > 0){
2428             me.firing = TRUE;
2429             var args = Array.prototype.slice.call(arguments, 0);
2430             for (; i < len; i++) {
2431                 l = listeners[i];
2432                 if(l && l.fireFn.apply(l.scope || me.obj || window, args) === FALSE) {
2433                     return (me.firing = FALSE);
2434                 }
2435             }
2436         }
2437         me.firing = FALSE;
2438         return TRUE;
2439     }
2440
2441 };
2442 })();
2443 /**
2444  * @class Ext.util.Observable
2445  */
2446 Ext.apply(Ext.util.Observable.prototype, function(){
2447     // this is considered experimental (along with beforeMethod, afterMethod, removeMethodListener?)
2448     // allows for easier interceptor and sequences, including cancelling and overwriting the return value of the call
2449     // private
2450     function getMethodEvent(method){
2451         var e = (this.methodEvents = this.methodEvents ||
2452         {})[method], returnValue, v, cancel, obj = this;
2453
2454         if (!e) {
2455             this.methodEvents[method] = e = {};
2456             e.originalFn = this[method];
2457             e.methodName = method;
2458             e.before = [];
2459             e.after = [];
2460
2461             var makeCall = function(fn, scope, args){
2462                 if((v = fn.apply(scope || obj, args)) !== undefined){
2463                     if (typeof v == 'object') {
2464                         if(v.returnValue !== undefined){
2465                             returnValue = v.returnValue;
2466                         }else{
2467                             returnValue = v;
2468                         }
2469                         cancel = !!v.cancel;
2470                     }
2471                     else
2472                         if (v === false) {
2473                             cancel = true;
2474                         }
2475                         else {
2476                             returnValue = v;
2477                         }
2478                 }
2479             };
2480
2481             this[method] = function(){
2482                 var args = Array.prototype.slice.call(arguments, 0),
2483                     b;
2484                 returnValue = v = undefined;
2485                 cancel = false;
2486
2487                 for(var i = 0, len = e.before.length; i < len; i++){
2488                     b = e.before[i];
2489                     makeCall(b.fn, b.scope, args);
2490                     if (cancel) {
2491                         return returnValue;
2492                     }
2493                 }
2494
2495                 if((v = e.originalFn.apply(obj, args)) !== undefined){
2496                     returnValue = v;
2497                 }
2498
2499                 for(var i = 0, len = e.after.length; i < len; i++){
2500                     b = e.after[i];
2501                     makeCall(b.fn, b.scope, args);
2502                     if (cancel) {
2503                         return returnValue;
2504                     }
2505                 }
2506                 return returnValue;
2507             };
2508         }
2509         return e;
2510     }
2511
2512     return {
2513         // these are considered experimental
2514         // allows for easier interceptor and sequences, including cancelling and overwriting the return value of the call
2515         // adds an 'interceptor' called before the original method
2516         beforeMethod : function(method, fn, scope){
2517             getMethodEvent.call(this, method).before.push({
2518                 fn: fn,
2519                 scope: scope
2520             });
2521         },
2522
2523         // adds a 'sequence' called after the original method
2524         afterMethod : function(method, fn, scope){
2525             getMethodEvent.call(this, method).after.push({
2526                 fn: fn,
2527                 scope: scope
2528             });
2529         },
2530
2531         removeMethodListener: function(method, fn, scope){
2532             var e = this.getMethodEvent(method);
2533             for(var i = 0, len = e.before.length; i < len; i++){
2534                 if(e.before[i].fn == fn && e.before[i].scope == scope){
2535                     e.before.splice(i, 1);
2536                     return;
2537                 }
2538             }
2539             for(var i = 0, len = e.after.length; i < len; i++){
2540                 if(e.after[i].fn == fn && e.after[i].scope == scope){
2541                     e.after.splice(i, 1);
2542                     return;
2543                 }
2544             }
2545         },
2546
2547         /**
2548          * Relays selected events from the specified Observable as if the events were fired by <tt><b>this</b></tt>.
2549          * @param {Object} o The Observable whose events this object is to relay.
2550          * @param {Array} events Array of event names to relay.
2551          */
2552         relayEvents : function(o, events){
2553             var me = this;
2554             function createHandler(ename){
2555                 return function(){
2556                     return me.fireEvent.apply(me, [ename].concat(Array.prototype.slice.call(arguments, 0)));
2557                 };
2558             }
2559             for(var i = 0, len = events.length; i < len; i++){
2560                 var ename = events[i];
2561                 me.events[ename] = me.events[ename] || true;
2562                 o.on(ename, createHandler(ename), me);
2563             }
2564         },
2565
2566         /**
2567          * <p>Enables events fired by this Observable to bubble up an owner hierarchy by calling
2568          * <code>this.getBubbleTarget()</code> if present. There is no implementation in the Observable base class.</p>
2569          * <p>This is commonly used by Ext.Components to bubble events to owner Containers. See {@link Ext.Component.getBubbleTarget}. The default
2570          * implementation in Ext.Component returns the Component's immediate owner. But if a known target is required, this can be overridden to
2571          * access the required target more quickly.</p>
2572          * <p>Example:</p><pre><code>
2573 Ext.override(Ext.form.Field, {
2574     //  Add functionality to Field&#39;s initComponent to enable the change event to bubble
2575     initComponent : Ext.form.Field.prototype.initComponent.createSequence(function() {
2576         this.enableBubble('change');
2577     }),
2578
2579     //  We know that we want Field&#39;s events to bubble directly to the FormPanel.
2580     getBubbleTarget : function() {
2581         if (!this.formPanel) {
2582             this.formPanel = this.findParentByType('form');
2583         }
2584         return this.formPanel;
2585     }
2586 });
2587
2588 var myForm = new Ext.formPanel({
2589     title: 'User Details',
2590     items: [{
2591         ...
2592     }],
2593     listeners: {
2594         change: function() {
2595             // Title goes red if form has been modified.
2596             myForm.header.setStyle('color', 'red');
2597         }
2598     }
2599 });
2600 </code></pre>
2601          * @param {String/Array} events The event name to bubble, or an Array of event names.
2602          */
2603         enableBubble : function(events){
2604             var me = this;
2605             if(!Ext.isEmpty(events)){
2606                 events = Ext.isArray(events) ? events : Array.prototype.slice.call(arguments, 0);
2607                 for(var i = 0, len = events.length; i < len; i++){
2608                     var ename = events[i];
2609                     ename = ename.toLowerCase();
2610                     var ce = me.events[ename] || true;
2611                     if (typeof ce == 'boolean') {
2612                         ce = new Ext.util.Event(me, ename);
2613                         me.events[ename] = ce;
2614                     }
2615                     ce.bubble = true;
2616                 }
2617             }
2618         }
2619     };
2620 }());
2621
2622
2623 /**
2624  * Starts capture on the specified Observable. All events will be passed
2625  * to the supplied function with the event name + standard signature of the event
2626  * <b>before</b> the event is fired. If the supplied function returns false,
2627  * the event will not fire.
2628  * @param {Observable} o The Observable to capture events from.
2629  * @param {Function} fn The function to call when an event is fired.
2630  * @param {Object} scope (optional) The scope (<code>this</code> reference) in which the function is executed. Defaults to the Observable firing the event.
2631  * @static
2632  */
2633 Ext.util.Observable.capture = function(o, fn, scope){
2634     o.fireEvent = o.fireEvent.createInterceptor(fn, scope);
2635 };
2636
2637
2638 /**
2639  * Sets observability on the passed class constructor.<p>
2640  * <p>This makes any event fired on any instance of the passed class also fire a single event through
2641  * the <i>class</i> allowing for central handling of events on many instances at once.</p>
2642  * <p>Usage:</p><pre><code>
2643 Ext.util.Observable.observeClass(Ext.data.Connection);
2644 Ext.data.Connection.on('beforerequest', function(con, options) {
2645     console.log('Ajax request made to ' + options.url);
2646 });</code></pre>
2647  * @param {Function} c The class constructor to make observable.
2648  * @param {Object} listeners An object containing a series of listeners to add. See {@link #addListener}.
2649  * @static
2650  */
2651 Ext.util.Observable.observeClass = function(c, listeners){
2652     if(c){
2653       if(!c.fireEvent){
2654           Ext.apply(c, new Ext.util.Observable());
2655           Ext.util.Observable.capture(c.prototype, c.fireEvent, c);
2656       }
2657       if(typeof listeners == 'object'){
2658           c.on(listeners);
2659       }
2660       return c;
2661    }
2662 };
2663 /**
2664  * @class Ext.EventManager
2665  * Registers event handlers that want to receive a normalized EventObject instead of the standard browser event and provides
2666  * several useful events directly.
2667  * See {@link Ext.EventObject} for more details on normalized event objects.
2668  * @singleton
2669  */
2670
2671 Ext.EventManager = function(){
2672     var docReadyEvent,
2673         docReadyProcId,
2674         docReadyState = false,
2675         DETECT_NATIVE = Ext.isGecko || Ext.isWebKit || Ext.isSafari,
2676         E = Ext.lib.Event,
2677         D = Ext.lib.Dom,
2678         DOC = document,
2679         WINDOW = window,
2680         DOMCONTENTLOADED = "DOMContentLoaded",
2681         COMPLETE = 'complete',
2682         propRe = /^(?:scope|delay|buffer|single|stopEvent|preventDefault|stopPropagation|normalized|args|delegate)$/,
2683         /*
2684          * This cache is used to hold special js objects, the document and window, that don't have an id. We need to keep
2685          * a reference to them so we can look them up at a later point.
2686          */
2687         specialElCache = [];
2688
2689      function getId(el){
2690         var id = false,
2691             i = 0,
2692             len = specialElCache.length,
2693             id = false,
2694             skip = false,
2695             o;
2696         if(el){
2697             if(el.getElementById || el.navigator){
2698                 // look up the id
2699                 for(; i < len; ++i){
2700                     o = specialElCache[i];
2701                     if(o.el === el){
2702                         id = o.id;
2703                         break;
2704                     }
2705                 }
2706                 if(!id){
2707                     // for browsers that support it, ensure that give the el the same id
2708                     id = Ext.id(el);
2709                     specialElCache.push({
2710                         id: id,
2711                         el: el
2712                     });
2713                     skip = true;
2714                 }
2715             }else{
2716                 id = Ext.id(el);
2717             }
2718             if(!Ext.elCache[id]){
2719                 Ext.Element.addToCache(new Ext.Element(el), id);
2720                 if(skip){
2721                     Ext.elCache[id].skipGC = true;
2722                 }
2723             }
2724         }
2725         return id;
2726      };
2727
2728     /// There is some jquery work around stuff here that isn't needed in Ext Core.
2729     function addListener(el, ename, fn, task, wrap, scope){
2730         el = Ext.getDom(el);
2731         var id = getId(el),
2732             es = Ext.elCache[id].events,
2733             wfn;
2734
2735         wfn = E.on(el, ename, wrap);
2736         es[ename] = es[ename] || [];
2737
2738         /* 0 = Original Function,
2739            1 = Event Manager Wrapped Function,
2740            2 = Scope,
2741            3 = Adapter Wrapped Function,
2742            4 = Buffered Task
2743         */
2744         es[ename].push([fn, wrap, scope, wfn, task]);
2745
2746         // this is a workaround for jQuery and should somehow be removed from Ext Core in the future
2747         // without breaking ExtJS.
2748
2749         // workaround for jQuery
2750         if(el.addEventListener && ename == "mousewheel"){
2751             var args = ["DOMMouseScroll", wrap, false];
2752             el.addEventListener.apply(el, args);
2753             Ext.EventManager.addListener(WINDOW, 'unload', function(){
2754                 el.removeEventListener.apply(el, args);
2755             });
2756         }
2757
2758         // fix stopped mousedowns on the document
2759         if(el == DOC && ename == "mousedown"){
2760             Ext.EventManager.stoppedMouseDownEvent.addListener(wrap);
2761         }
2762     };
2763
2764     function doScrollChk(){
2765         /* Notes:
2766              'doScroll' will NOT work in a IFRAME/FRAMESET.
2767              The method succeeds but, a DOM query done immediately after -- FAILS.
2768           */
2769         if(window != top){
2770             return false;
2771         }
2772
2773         try{
2774             DOC.documentElement.doScroll('left');
2775         }catch(e){
2776              return false;
2777         }
2778
2779         fireDocReady();
2780         return true;
2781     }
2782     /**
2783      * @return {Boolean} True if the document is in a 'complete' state (or was determined to
2784      * be true by other means). If false, the state is evaluated again until canceled.
2785      */
2786     function checkReadyState(e){
2787
2788         if(Ext.isIE && doScrollChk()){
2789             return true;
2790         }
2791         if(DOC.readyState == COMPLETE){
2792             fireDocReady();
2793             return true;
2794         }
2795         docReadyState || (docReadyProcId = setTimeout(arguments.callee, 2));
2796         return false;
2797     }
2798
2799     var styles;
2800     function checkStyleSheets(e){
2801         styles || (styles = Ext.query('style, link[rel=stylesheet]'));
2802         if(styles.length == DOC.styleSheets.length){
2803             fireDocReady();
2804             return true;
2805         }
2806         docReadyState || (docReadyProcId = setTimeout(arguments.callee, 2));
2807         return false;
2808     }
2809
2810     function OperaDOMContentLoaded(e){
2811         DOC.removeEventListener(DOMCONTENTLOADED, arguments.callee, false);
2812         checkStyleSheets();
2813     }
2814
2815     function fireDocReady(e){
2816         if(!docReadyState){
2817             docReadyState = true; //only attempt listener removal once
2818
2819             if(docReadyProcId){
2820                 clearTimeout(docReadyProcId);
2821             }
2822             if(DETECT_NATIVE) {
2823                 DOC.removeEventListener(DOMCONTENTLOADED, fireDocReady, false);
2824             }
2825             if(Ext.isIE && checkReadyState.bindIE){  //was this was actually set ??
2826                 DOC.detachEvent('onreadystatechange', checkReadyState);
2827             }
2828             E.un(WINDOW, "load", arguments.callee);
2829         }
2830         if(docReadyEvent && !Ext.isReady){
2831             Ext.isReady = true;
2832             docReadyEvent.fire();
2833             docReadyEvent.listeners = [];
2834         }
2835
2836     };
2837
2838     function initDocReady(){
2839         docReadyEvent || (docReadyEvent = new Ext.util.Event());
2840         if (DETECT_NATIVE) {
2841             DOC.addEventListener(DOMCONTENTLOADED, fireDocReady, false);
2842         }
2843         /*
2844          * Handle additional (exceptional) detection strategies here
2845          */
2846         if (Ext.isIE){
2847             //Use readystatechange as a backup AND primary detection mechanism for a FRAME/IFRAME
2848             //See if page is already loaded
2849             if(!checkReadyState()){
2850                 checkReadyState.bindIE = true;
2851                 DOC.attachEvent('onreadystatechange', checkReadyState);
2852             }
2853
2854         }else if(Ext.isOpera ){
2855             /* Notes:
2856                Opera needs special treatment needed here because CSS rules are NOT QUITE
2857                available after DOMContentLoaded is raised.
2858             */
2859
2860             //See if page is already loaded and all styleSheets are in place
2861             (DOC.readyState == COMPLETE && checkStyleSheets()) ||
2862                 DOC.addEventListener(DOMCONTENTLOADED, OperaDOMContentLoaded, false);
2863
2864         }else if (Ext.isWebKit){
2865             //Fallback for older Webkits without DOMCONTENTLOADED support
2866             checkReadyState();
2867         }
2868         // no matter what, make sure it fires on load
2869         E.on(WINDOW, "load", fireDocReady);
2870     };
2871
2872     function createTargeted(h, o){
2873         return function(){
2874             var args = Ext.toArray(arguments);
2875             if(o.target == Ext.EventObject.setEvent(args[0]).target){
2876                 h.apply(this, args);
2877             }
2878         };
2879     };
2880
2881     function createBuffered(h, o, task){
2882         return function(e){
2883             // create new event object impl so new events don't wipe out properties
2884             task.delay(o.buffer, h, null, [new Ext.EventObjectImpl(e)]);
2885         };
2886     };
2887
2888     function createSingle(h, el, ename, fn, scope){
2889         return function(e){
2890             Ext.EventManager.removeListener(el, ename, fn, scope);
2891             h(e);
2892         };
2893     };
2894
2895     function createDelayed(h, o, fn){
2896         return function(e){
2897             var task = new Ext.util.DelayedTask(h);
2898             if(!fn.tasks) {
2899                 fn.tasks = [];
2900             }
2901             fn.tasks.push(task);
2902             task.delay(o.delay || 10, h, null, [new Ext.EventObjectImpl(e)]);
2903         };
2904     };
2905
2906     function listen(element, ename, opt, fn, scope){
2907         var o = (!opt || typeof opt == "boolean") ? {} : opt,
2908             el = Ext.getDom(element), task;
2909
2910         fn = fn || o.fn;
2911         scope = scope || o.scope;
2912
2913         if(!el){
2914             throw "Error listening for \"" + ename + '\". Element "' + element + '" doesn\'t exist.';
2915         }
2916         function h(e){
2917             // prevent errors while unload occurring
2918             if(!Ext){// !window[xname]){  ==> can't we do this?
2919                 return;
2920             }
2921             e = Ext.EventObject.setEvent(e);
2922             var t;
2923             if (o.delegate) {
2924                 if(!(t = e.getTarget(o.delegate, el))){
2925                     return;
2926                 }
2927             } else {
2928                 t = e.target;
2929             }
2930             if (o.stopEvent) {
2931                 e.stopEvent();
2932             }
2933             if (o.preventDefault) {
2934                e.preventDefault();
2935             }
2936             if (o.stopPropagation) {
2937                 e.stopPropagation();
2938             }
2939             if (o.normalized) {
2940                 e = e.browserEvent;
2941             }
2942
2943             fn.call(scope || el, e, t, o);
2944         };
2945         if(o.target){
2946             h = createTargeted(h, o);
2947         }
2948         if(o.delay){
2949             h = createDelayed(h, o, fn);
2950         }
2951         if(o.single){
2952             h = createSingle(h, el, ename, fn, scope);
2953         }
2954         if(o.buffer){
2955             task = new Ext.util.DelayedTask(h);
2956             h = createBuffered(h, o, task);
2957         }
2958
2959         addListener(el, ename, fn, task, h, scope);
2960         return h;
2961     };
2962
2963     var pub = {
2964         /**
2965          * Appends an event handler to an element.  The shorthand version {@link #on} is equivalent.  Typically you will
2966          * use {@link Ext.Element#addListener} directly on an Element in favor of calling this version.
2967          * @param {String/HTMLElement} el The html element or id to assign the event handler to.
2968          * @param {String} eventName The name of the event to listen for.
2969          * @param {Function} handler The handler function the event invokes. This function is passed
2970          * the following parameters:<ul>
2971          * <li>evt : EventObject<div class="sub-desc">The {@link Ext.EventObject EventObject} describing the event.</div></li>
2972          * <li>t : Element<div class="sub-desc">The {@link Ext.Element Element} which was the target of the event.
2973          * Note that this may be filtered by using the <tt>delegate</tt> option.</div></li>
2974          * <li>o : Object<div class="sub-desc">The options object from the addListener call.</div></li>
2975          * </ul>
2976          * @param {Object} scope (optional) The scope (<b><code>this</code></b> reference) in which the handler function is executed. <b>Defaults to the Element</b>.
2977          * @param {Object} options (optional) An object containing handler configuration properties.
2978          * This may contain any of the following properties:<ul>
2979          * <li>scope : Object<div class="sub-desc">The scope (<b><code>this</code></b> reference) in which the handler function is executed. <b>Defaults to the Element</b>.</div></li>
2980          * <li>delegate : String<div class="sub-desc">A simple selector to filter the target or look for a descendant of the target</div></li>
2981          * <li>stopEvent : Boolean<div class="sub-desc">True to stop the event. That is stop propagation, and prevent the default action.</div></li>
2982          * <li>preventDefault : Boolean<div class="sub-desc">True to prevent the default action</div></li>
2983          * <li>stopPropagation : Boolean<div class="sub-desc">True to prevent event propagation</div></li>
2984          * <li>normalized : Boolean<div class="sub-desc">False to pass a browser event to the handler function instead of an Ext.EventObject</div></li>
2985          * <li>delay : Number<div class="sub-desc">The number of milliseconds to delay the invocation of the handler after te event fires.</div></li>
2986          * <li>single : Boolean<div class="sub-desc">True to add a handler to handle just the next firing of the event, and then remove itself.</div></li>
2987          * <li>buffer : Number<div class="sub-desc">Causes the handler to be scheduled to run in an {@link Ext.util.DelayedTask} delayed
2988          * by the specified number of milliseconds. If the event fires again within that time, the original
2989          * handler is <em>not</em> invoked, but the new handler is scheduled in its place.</div></li>
2990          * <li>target : Element<div class="sub-desc">Only call the handler if the event was fired on the target Element, <i>not</i> if the event was bubbled up from a child node.</div></li>
2991          * </ul><br>
2992          * <p>See {@link Ext.Element#addListener} for examples of how to use these options.</p>
2993          */
2994         addListener : function(element, eventName, fn, scope, options){
2995             if(typeof eventName == 'object'){
2996                 var o = eventName, e, val;
2997                 for(e in o){
2998                     val = o[e];
2999                     if(!propRe.test(e)){
3000                         if(Ext.isFunction(val)){
3001                             // shared options
3002                             listen(element, e, o, val, o.scope);
3003                         }else{
3004                             // individual options
3005                             listen(element, e, val);
3006                         }
3007                     }
3008                 }
3009             } else {
3010                 listen(element, eventName, options, fn, scope);
3011             }
3012         },
3013
3014         /**
3015          * Removes an event handler from an element.  The shorthand version {@link #un} is equivalent.  Typically
3016          * you will use {@link Ext.Element#removeListener} directly on an Element in favor of calling this version.
3017          * @param {String/HTMLElement} el The id or html element from which to remove the listener.
3018          * @param {String} eventName The name of the event.
3019          * @param {Function} fn The handler function to remove. <b>This must be a reference to the function passed into the {@link #addListener} call.</b>
3020          * @param {Object} scope If a scope (<b><code>this</code></b> reference) was specified when the listener was added,
3021          * then this must refer to the same object.
3022          */
3023         removeListener : function(el, eventName, fn, scope){
3024             el = Ext.getDom(el);
3025             var id = getId(el),
3026                 f = el && (Ext.elCache[id].events)[eventName] || [],
3027                 wrap, i, l, k, len, fnc;
3028
3029             for (i = 0, len = f.length; i < len; i++) {
3030
3031                 /* 0 = Original Function,
3032                    1 = Event Manager Wrapped Function,
3033                    2 = Scope,
3034                    3 = Adapter Wrapped Function,
3035                    4 = Buffered Task
3036                 */
3037                 if (Ext.isArray(fnc = f[i]) && fnc[0] == fn && (!scope || fnc[2] == scope)) {
3038                     if(fnc[4]) {
3039                         fnc[4].cancel();
3040                     }
3041                     k = fn.tasks && fn.tasks.length;
3042                     if(k) {
3043                         while(k--) {
3044                             fn.tasks[k].cancel();
3045                         }
3046                         delete fn.tasks;
3047                     }
3048                     wrap = fnc[1];
3049                     E.un(el, eventName, E.extAdapter ? fnc[3] : wrap);
3050
3051                     // jQuery workaround that should be removed from Ext Core
3052                     if(wrap && el.addEventListener && eventName == "mousewheel"){
3053                         el.removeEventListener("DOMMouseScroll", wrap, false);
3054                     }
3055
3056                     // fix stopped mousedowns on the document
3057                     if(wrap && el == DOC && eventName == "mousedown"){
3058                         Ext.EventManager.stoppedMouseDownEvent.removeListener(wrap);
3059                     }
3060
3061                     f.splice(i, 1);
3062                     if (f.length === 0) {
3063                         delete Ext.elCache[id].events[eventName];
3064                     }
3065                     for (k in Ext.elCache[id].events) {
3066                         return false;
3067                     }
3068                     Ext.elCache[id].events = {};
3069                     return false;
3070                 }
3071             }
3072         },
3073
3074         /**
3075          * Removes all event handers from an element.  Typically you will use {@link Ext.Element#removeAllListeners}
3076          * directly on an Element in favor of calling this version.
3077          * @param {String/HTMLElement} el The id or html element from which to remove all event handlers.
3078          */
3079         removeAll : function(el){
3080             el = Ext.getDom(el);
3081             var id = getId(el),
3082                 ec = Ext.elCache[id] || {},
3083                 es = ec.events || {},
3084                 f, i, len, ename, fn, k, wrap;
3085
3086             for(ename in es){
3087                 if(es.hasOwnProperty(ename)){
3088                     f = es[ename];
3089                     /* 0 = Original Function,
3090                        1 = Event Manager Wrapped Function,
3091                        2 = Scope,
3092                        3 = Adapter Wrapped Function,
3093                        4 = Buffered Task
3094                     */
3095                     for (i = 0, len = f.length; i < len; i++) {
3096                         fn = f[i];
3097                         if(fn[4]) {
3098                             fn[4].cancel();
3099                         }
3100                         if(fn[0].tasks && (k = fn[0].tasks.length)) {
3101                             while(k--) {
3102                                 fn[0].tasks[k].cancel();
3103                             }
3104                             delete fn.tasks;
3105                         }
3106                         wrap =  fn[1];
3107                         E.un(el, ename, E.extAdapter ? fn[3] : wrap);
3108
3109                         // jQuery workaround that should be removed from Ext Core
3110                         if(el.addEventListener && wrap && ename == "mousewheel"){
3111                             el.removeEventListener("DOMMouseScroll", wrap, false);
3112                         }
3113
3114                         // fix stopped mousedowns on the document
3115                         if(wrap && el == DOC &&  ename == "mousedown"){
3116                             Ext.EventManager.stoppedMouseDownEvent.removeListener(wrap);
3117                         }
3118                     }
3119                 }
3120             }
3121             if (Ext.elCache[id]) {
3122                 Ext.elCache[id].events = {};
3123             }
3124         },
3125
3126         getListeners : function(el, eventName) {
3127             el = Ext.getDom(el);
3128             var id = getId(el),
3129                 ec = Ext.elCache[id] || {},
3130                 es = ec.events || {},
3131                 results = [];
3132             if (es && es[eventName]) {
3133                 return es[eventName];
3134             } else {
3135                 return null;
3136             }
3137         },
3138
3139         purgeElement : function(el, recurse, eventName) {
3140             el = Ext.getDom(el);
3141             var id = getId(el),
3142                 ec = Ext.elCache[id] || {},
3143                 es = ec.events || {},
3144                 i, f, len;
3145             if (eventName) {
3146                 if (es && es.hasOwnProperty(eventName)) {
3147                     f = es[eventName];
3148                     for (i = 0, len = f.length; i < len; i++) {
3149                         Ext.EventManager.removeListener(el, eventName, f[i][0]);
3150                     }
3151                 }
3152             } else {
3153                 Ext.EventManager.removeAll(el);
3154             }
3155             if (recurse && el && el.childNodes) {
3156                 for (i = 0, len = el.childNodes.length; i < len; i++) {
3157                     Ext.EventManager.purgeElement(el.childNodes[i], recurse, eventName);
3158                 }
3159             }
3160         },
3161
3162         _unload : function() {
3163             var el;
3164             for (el in Ext.elCache) {
3165                 Ext.EventManager.removeAll(el);
3166             }
3167             delete Ext.elCache;
3168             delete Ext.Element._flyweights;
3169
3170             // Abort any outstanding Ajax requests
3171             var c,
3172                 conn,
3173                 tid,
3174                 ajax = Ext.lib.Ajax;
3175             (typeof ajax.conn == 'object') ? conn = ajax.conn : conn = {};
3176             for (tid in conn) {
3177                 c = conn[tid];
3178                 if (c) {
3179                     ajax.abort({conn: c, tId: tid});
3180                 }
3181             }
3182         },
3183         /**
3184          * Adds a listener to be notified when the document is ready (before onload and before images are loaded). Can be
3185          * accessed shorthanded as Ext.onReady().
3186          * @param {Function} fn The method the event invokes.
3187          * @param {Object} scope (optional) The scope (<code>this</code> reference) in which the handler function executes. Defaults to the browser window.
3188          * @param {boolean} options (optional) Options object as passed to {@link Ext.Element#addListener}. It is recommended that the options
3189          * <code>{single: true}</code> be used so that the handler is removed on first invocation.
3190          */
3191         onDocumentReady : function(fn, scope, options){
3192             if(Ext.isReady){ // if it already fired or document.body is present
3193                 docReadyEvent || (docReadyEvent = new Ext.util.Event());
3194                 docReadyEvent.addListener(fn, scope, options);
3195                 docReadyEvent.fire();
3196                 docReadyEvent.listeners = [];
3197             }else{
3198                 if(!docReadyEvent){
3199                     initDocReady();
3200                 }
3201                 options = options || {};
3202                 options.delay = options.delay || 1;
3203                 docReadyEvent.addListener(fn, scope, options);
3204             }
3205         },
3206
3207         /**
3208          * Forces a document ready state transition for the framework.  Used when Ext is loaded
3209          * into a DOM structure AFTER initial page load (Google API or other dynamic load scenario.
3210          * Any pending 'onDocumentReady' handlers will be fired (if not already handled).
3211          */
3212         fireDocReady  : fireDocReady
3213     };
3214      /**
3215      * Appends an event handler to an element.  Shorthand for {@link #addListener}.
3216      * @param {String/HTMLElement} el The html element or id to assign the event handler to
3217      * @param {String} eventName The name of the event to listen for.
3218      * @param {Function} handler The handler function the event invokes.
3219      * @param {Object} scope (optional) (<code>this</code> reference) in which the handler function executes. <b>Defaults to the Element</b>.
3220      * @param {Object} options (optional) An object containing standard {@link #addListener} options
3221      * @member Ext.EventManager
3222      * @method on
3223      */
3224     pub.on = pub.addListener;
3225     /**
3226      * Removes an event handler from an element.  Shorthand for {@link #removeListener}.
3227      * @param {String/HTMLElement} el The id or html element from which to remove the listener.
3228      * @param {String} eventName The name of the event.
3229      * @param {Function} fn The handler function to remove. <b>This must be a reference to the function passed into the {@link #on} call.</b>
3230      * @param {Object} scope If a scope (<b><code>this</code></b> reference) was specified when the listener was added,
3231      * then this must refer to the same object.
3232      * @member Ext.EventManager
3233      * @method un
3234      */
3235     pub.un = pub.removeListener;
3236
3237     pub.stoppedMouseDownEvent = new Ext.util.Event();
3238     return pub;
3239 }();
3240 /**
3241   * Adds a listener to be notified when the document is ready (before onload and before images are loaded). Shorthand of {@link Ext.EventManager#onDocumentReady}.
3242   * @param {Function} fn The method the event invokes.
3243   * @param {Object} scope (optional) The scope (<code>this</code> reference) in which the handler function executes. Defaults to the browser window.
3244   * @param {boolean} options (optional) Options object as passed to {@link Ext.Element#addListener}. It is recommended that the options
3245   * <code>{single: true}</code> be used so that the handler is removed on first invocation.
3246   * @member Ext
3247   * @method onReady
3248  */
3249 Ext.onReady = Ext.EventManager.onDocumentReady;
3250
3251
3252 //Initialize doc classes
3253 (function(){
3254
3255     var initExtCss = function(){
3256         // find the body element
3257         var bd = document.body || document.getElementsByTagName('body')[0];
3258         if(!bd){ return false; }
3259         var cls = [' ',
3260                 Ext.isIE ? "ext-ie " + (Ext.isIE6 ? 'ext-ie6' : (Ext.isIE7 ? 'ext-ie7' : 'ext-ie8'))
3261                 : Ext.isGecko ? "ext-gecko " + (Ext.isGecko2 ? 'ext-gecko2' : 'ext-gecko3')
3262                 : Ext.isOpera ? "ext-opera"
3263                 : Ext.isWebKit ? "ext-webkit" : ""];
3264
3265         if(Ext.isSafari){
3266             cls.push("ext-safari " + (Ext.isSafari2 ? 'ext-safari2' : (Ext.isSafari3 ? 'ext-safari3' : 'ext-safari4')));
3267         }else if(Ext.isChrome){
3268             cls.push("ext-chrome");
3269         }
3270
3271         if(Ext.isMac){
3272             cls.push("ext-mac");
3273         }
3274         if(Ext.isLinux){
3275             cls.push("ext-linux");
3276         }
3277
3278         if(Ext.isStrict || Ext.isBorderBox){ // add to the parent to allow for selectors like ".ext-strict .ext-ie"
3279             var p = bd.parentNode;
3280             if(p){
3281                 p.className += Ext.isStrict ? ' ext-strict' : ' ext-border-box';
3282             }
3283         }
3284         bd.className += cls.join(' ');
3285         return true;
3286     }
3287
3288     if(!initExtCss()){
3289         Ext.onReady(initExtCss);
3290     }
3291 })();
3292
3293
3294 /**
3295  * @class Ext.EventObject
3296  * Just as {@link Ext.Element} wraps around a native DOM node, Ext.EventObject
3297  * wraps the browser's native event-object normalizing cross-browser differences,
3298  * such as which mouse button is clicked, keys pressed, mechanisms to stop
3299  * event-propagation along with a method to prevent default actions from taking place.
3300  * <p>For example:</p>
3301  * <pre><code>
3302 function handleClick(e, t){ // e is not a standard event object, it is a Ext.EventObject
3303     e.preventDefault();
3304     var target = e.getTarget(); // same as t (the target HTMLElement)
3305     ...
3306 }
3307 var myDiv = {@link Ext#get Ext.get}("myDiv");  // get reference to an {@link Ext.Element}
3308 myDiv.on(         // 'on' is shorthand for addListener
3309     "click",      // perform an action on click of myDiv
3310     handleClick   // reference to the action handler
3311 );
3312 // other methods to do the same:
3313 Ext.EventManager.on("myDiv", 'click', handleClick);
3314 Ext.EventManager.addListener("myDiv", 'click', handleClick);
3315  </code></pre>
3316  * @singleton
3317  */
3318 Ext.EventObject = function(){
3319     var E = Ext.lib.Event,
3320         // safari keypress events for special keys return bad keycodes
3321         safariKeys = {
3322             3 : 13, // enter
3323             63234 : 37, // left
3324             63235 : 39, // right
3325             63232 : 38, // up
3326             63233 : 40, // down
3327             63276 : 33, // page up
3328             63277 : 34, // page down
3329             63272 : 46, // delete
3330             63273 : 36, // home
3331             63275 : 35  // end
3332         },
3333         // normalize button clicks
3334         btnMap = Ext.isIE ? {1:0,4:1,2:2} :
3335                 (Ext.isWebKit ? {1:0,2:1,3:2} : {0:0,1:1,2:2});
3336
3337     Ext.EventObjectImpl = function(e){
3338         if(e){
3339             this.setEvent(e.browserEvent || e);
3340         }
3341     };
3342
3343     Ext.EventObjectImpl.prototype = {
3344            /** @private */
3345         setEvent : function(e){
3346             var me = this;
3347             if(e == me || (e && e.browserEvent)){ // already wrapped
3348                 return e;
3349             }
3350             me.browserEvent = e;
3351             if(e){
3352                 // normalize buttons
3353                 me.button = e.button ? btnMap[e.button] : (e.which ? e.which - 1 : -1);
3354                 if(e.type == 'click' && me.button == -1){
3355                     me.button = 0;
3356                 }
3357                 me.type = e.type;
3358                 me.shiftKey = e.shiftKey;
3359                 // mac metaKey behaves like ctrlKey
3360                 me.ctrlKey = e.ctrlKey || e.metaKey || false;
3361                 me.altKey = e.altKey;
3362                 // in getKey these will be normalized for the mac
3363                 me.keyCode = e.keyCode;
3364                 me.charCode = e.charCode;
3365                 // cache the target for the delayed and or buffered events
3366                 me.target = E.getTarget(e);
3367                 // same for XY
3368                 me.xy = E.getXY(e);
3369             }else{
3370                 me.button = -1;
3371                 me.shiftKey = false;
3372                 me.ctrlKey = false;
3373                 me.altKey = false;
3374                 me.keyCode = 0;
3375                 me.charCode = 0;
3376                 me.target = null;
3377                 me.xy = [0, 0];
3378             }
3379             return me;
3380         },
3381
3382         /**
3383          * Stop the event (preventDefault and stopPropagation)
3384          */
3385         stopEvent : function(){
3386             var me = this;
3387             if(me.browserEvent){
3388                 if(me.browserEvent.type == 'mousedown'){
3389                     Ext.EventManager.stoppedMouseDownEvent.fire(me);
3390                 }
3391                 E.stopEvent(me.browserEvent);
3392             }
3393         },
3394
3395         /**
3396          * Prevents the browsers default handling of the event.
3397          */
3398         preventDefault : function(){
3399             if(this.browserEvent){
3400                 E.preventDefault(this.browserEvent);
3401             }
3402         },
3403
3404         /**
3405          * Cancels bubbling of the event.
3406          */
3407         stopPropagation : function(){
3408             var me = this;
3409             if(me.browserEvent){
3410                 if(me.browserEvent.type == 'mousedown'){
3411                     Ext.EventManager.stoppedMouseDownEvent.fire(me);
3412                 }
3413                 E.stopPropagation(me.browserEvent);
3414             }
3415         },
3416
3417         /**
3418          * Gets the character code for the event.
3419          * @return {Number}
3420          */
3421         getCharCode : function(){
3422             return this.charCode || this.keyCode;
3423         },
3424
3425         /**
3426          * Returns a normalized keyCode for the event.
3427          * @return {Number} The key code
3428          */
3429         getKey : function(){
3430             return this.normalizeKey(this.keyCode || this.charCode)
3431         },
3432
3433         // private
3434         normalizeKey: function(k){
3435             return Ext.isSafari ? (safariKeys[k] || k) : k;
3436         },
3437
3438         /**
3439          * Gets the x coordinate of the event.
3440          * @return {Number}
3441          */
3442         getPageX : function(){
3443             return this.xy[0];
3444         },
3445
3446         /**
3447          * Gets the y coordinate of the event.
3448          * @return {Number}
3449          */
3450         getPageY : function(){
3451             return this.xy[1];
3452         },
3453
3454         /**
3455          * Gets the page coordinates of the event.
3456          * @return {Array} The xy values like [x, y]
3457          */
3458         getXY : function(){
3459             return this.xy;
3460         },
3461
3462         /**
3463          * Gets the target for the event.
3464          * @param {String} selector (optional) A simple selector to filter the target or look for an ancestor of the target
3465          * @param {Number/Mixed} maxDepth (optional) The max depth to
3466                 search as a number or element (defaults to 10 || document.body)
3467          * @param {Boolean} returnEl (optional) True to return a Ext.Element object instead of DOM node
3468          * @return {HTMLelement}
3469          */
3470         getTarget : function(selector, maxDepth, returnEl){
3471             return selector ? Ext.fly(this.target).findParent(selector, maxDepth, returnEl) : (returnEl ? Ext.get(this.target) : this.target);
3472         },
3473
3474         /**
3475          * Gets the related target.
3476          * @return {HTMLElement}
3477          */
3478         getRelatedTarget : function(){
3479             return this.browserEvent ? E.getRelatedTarget(this.browserEvent) : null;
3480         },
3481
3482         /**
3483          * Normalizes mouse wheel delta across browsers
3484          * @return {Number} The delta
3485          */
3486         getWheelDelta : function(){
3487             var e = this.browserEvent;
3488             var delta = 0;
3489             if(e.wheelDelta){ /* IE/Opera. */
3490                 delta = e.wheelDelta/120;
3491             }else if(e.detail){ /* Mozilla case. */
3492                 delta = -e.detail/3;
3493             }
3494             return delta;
3495         },
3496
3497         /**
3498         * Returns true if the target of this event is a child of el.  Unless the allowEl parameter is set, it will return false if if the target is el.
3499         * Example usage:<pre><code>
3500         // Handle click on any child of an element
3501         Ext.getBody().on('click', function(e){
3502             if(e.within('some-el')){
3503                 alert('Clicked on a child of some-el!');
3504             }
3505         });
3506
3507         // Handle click directly on an element, ignoring clicks on child nodes
3508         Ext.getBody().on('click', function(e,t){
3509             if((t.id == 'some-el') && !e.within(t, true)){
3510                 alert('Clicked directly on some-el!');
3511             }
3512         });
3513         </code></pre>
3514          * @param {Mixed} el The id, DOM element or Ext.Element to check
3515          * @param {Boolean} related (optional) true to test if the related target is within el instead of the target
3516          * @param {Boolean} allowEl {optional} true to also check if the passed element is the target or related target
3517          * @return {Boolean}
3518          */
3519         within : function(el, related, allowEl){
3520             if(el){
3521                 var t = this[related ? "getRelatedTarget" : "getTarget"]();
3522                 return t && ((allowEl ? (t == Ext.getDom(el)) : false) || Ext.fly(el).contains(t));
3523             }
3524             return false;
3525         }
3526      };
3527
3528     return new Ext.EventObjectImpl();
3529 }();
3530 /**
3531 * @class Ext.EventManager
3532 */
3533 Ext.apply(Ext.EventManager, function(){
3534    var resizeEvent,
3535        resizeTask,
3536        textEvent,
3537        textSize,
3538        D = Ext.lib.Dom,
3539        propRe = /^(?:scope|delay|buffer|single|stopEvent|preventDefault|stopPropagation|normalized|args|delegate)$/,
3540        curWidth = 0,
3541        curHeight = 0,
3542        // note 1: IE fires ONLY the keydown event on specialkey autorepeat
3543        // note 2: Safari < 3.1, Gecko (Mac/Linux) & Opera fire only the keypress event on specialkey autorepeat
3544        // (research done by @Jan Wolter at http://unixpapa.com/js/key.html)
3545        useKeydown = Ext.isWebKit ?
3546                    Ext.num(navigator.userAgent.match(/AppleWebKit\/(\d+)/)[1]) >= 525 :
3547                    !((Ext.isGecko && !Ext.isWindows) || Ext.isOpera);
3548
3549    return {
3550        // private
3551        doResizeEvent: function(){
3552            var h = D.getViewHeight(),
3553                w = D.getViewWidth();
3554
3555             //whacky problem in IE where the resize event will fire even though the w/h are the same.
3556             if(curHeight != h || curWidth != w){
3557                resizeEvent.fire(curWidth = w, curHeight = h);
3558             }
3559        },
3560
3561        /**
3562         * Adds a listener to be notified when the browser window is resized and provides resize event buffering (100 milliseconds),
3563         * passes new viewport width and height to handlers.
3564         * @param {Function} fn      The handler function the window resize event invokes.
3565         * @param {Object}   scope   The scope (<code>this</code> reference) in which the handler function executes. Defaults to the browser window.
3566         * @param {boolean}  options Options object as passed to {@link Ext.Element#addListener}
3567         */
3568        onWindowResize : function(fn, scope, options){
3569            if(!resizeEvent){
3570                resizeEvent = new Ext.util.Event();
3571                resizeTask = new Ext.util.DelayedTask(this.doResizeEvent);
3572                Ext.EventManager.on(window, "resize", this.fireWindowResize, this);
3573            }
3574            resizeEvent.addListener(fn, scope, options);
3575        },
3576
3577        // exposed only to allow manual firing
3578        fireWindowResize : function(){
3579            if(resizeEvent){
3580                resizeTask.delay(100);
3581            }
3582        },
3583
3584        /**
3585         * Adds a listener to be notified when the user changes the active text size. Handler gets called with 2 params, the old size and the new size.
3586         * @param {Function} fn      The function the event invokes.
3587         * @param {Object}   scope   The scope (<code>this</code> reference) in which the handler function executes. Defaults to the browser window.
3588         * @param {boolean}  options Options object as passed to {@link Ext.Element#addListener}
3589         */
3590        onTextResize : function(fn, scope, options){
3591            if(!textEvent){
3592                textEvent = new Ext.util.Event();
3593                var textEl = new Ext.Element(document.createElement('div'));
3594                textEl.dom.className = 'x-text-resize';
3595                textEl.dom.innerHTML = 'X';
3596                textEl.appendTo(document.body);
3597                textSize = textEl.dom.offsetHeight;
3598                setInterval(function(){
3599                    if(textEl.dom.offsetHeight != textSize){
3600                        textEvent.fire(textSize, textSize = textEl.dom.offsetHeight);
3601                    }
3602                }, this.textResizeInterval);
3603            }
3604            textEvent.addListener(fn, scope, options);
3605        },
3606
3607        /**
3608         * Removes the passed window resize listener.
3609         * @param {Function} fn        The method the event invokes
3610         * @param {Object}   scope    The scope of handler
3611         */
3612        removeResizeListener : function(fn, scope){
3613            if(resizeEvent){
3614                resizeEvent.removeListener(fn, scope);
3615            }
3616        },
3617
3618        // private
3619        fireResize : function(){
3620            if(resizeEvent){
3621                resizeEvent.fire(D.getViewWidth(), D.getViewHeight());
3622            }
3623        },
3624
3625         /**
3626         * The frequency, in milliseconds, to check for text resize events (defaults to 50)
3627         */
3628        textResizeInterval : 50,
3629
3630        /**
3631         * Url used for onDocumentReady with using SSL (defaults to Ext.SSL_SECURE_URL)
3632         */
3633        ieDeferSrc : false,
3634
3635        // protected for use inside the framework
3636        // detects whether we should use keydown or keypress based on the browser.
3637        useKeydown: useKeydown
3638    };
3639 }());
3640
3641 Ext.EventManager.on = Ext.EventManager.addListener;
3642
3643
3644 Ext.apply(Ext.EventObjectImpl.prototype, {
3645    /** Key constant @type Number */
3646    BACKSPACE: 8,
3647    /** Key constant @type Number */
3648    TAB: 9,
3649    /** Key constant @type Number */
3650    NUM_CENTER: 12,
3651    /** Key constant @type Number */
3652    ENTER: 13,
3653    /** Key constant @type Number */
3654    RETURN: 13,
3655    /** Key constant @type Number */
3656    SHIFT: 16,
3657    /** Key constant @type Number */
3658    CTRL: 17,
3659    CONTROL : 17, // legacy
3660    /** Key constant @type Number */
3661    ALT: 18,
3662    /** Key constant @type Number */
3663    PAUSE: 19,
3664    /** Key constant @type Number */
3665    CAPS_LOCK: 20,
3666    /** Key constant @type Number */
3667    ESC: 27,
3668    /** Key constant @type Number */
3669    SPACE: 32,
3670    /** Key constant @type Number */
3671    PAGE_UP: 33,
3672    PAGEUP : 33, // legacy
3673    /** Key constant @type Number */
3674    PAGE_DOWN: 34,
3675    PAGEDOWN : 34, // legacy
3676    /** Key constant @type Number */
3677    END: 35,
3678    /** Key constant @type Number */
3679    HOME: 36,
3680    /** Key constant @type Number */
3681    LEFT: 37,
3682    /** Key constant @type Number */
3683    UP: 38,
3684    /** Key constant @type Number */
3685    RIGHT: 39,
3686    /** Key constant @type Number */
3687    DOWN: 40,
3688    /** Key constant @type Number */
3689    PRINT_SCREEN: 44,
3690    /** Key constant @type Number */
3691    INSERT: 45,
3692    /** Key constant @type Number */
3693    DELETE: 46,
3694    /** Key constant @type Number */
3695    ZERO: 48,
3696    /** Key constant @type Number */
3697    ONE: 49,
3698    /** Key constant @type Number */
3699    TWO: 50,
3700    /** Key constant @type Number */
3701    THREE: 51,
3702    /** Key constant @type Number */
3703    FOUR: 52,
3704    /** Key constant @type Number */
3705    FIVE: 53,
3706    /** Key constant @type Number */
3707    SIX: 54,
3708    /** Key constant @type Number */
3709    SEVEN: 55,
3710    /** Key constant @type Number */
3711    EIGHT: 56,
3712    /** Key constant @type Number */
3713    NINE: 57,
3714    /** Key constant @type Number */
3715    A: 65,
3716    /** Key constant @type Number */
3717    B: 66,
3718    /** Key constant @type Number */
3719    C: 67,
3720    /** Key constant @type Number */
3721    D: 68,
3722    /** Key constant @type Number */
3723    E: 69,
3724    /** Key constant @type Number */
3725    F: 70,
3726    /** Key constant @type Number */
3727    G: 71,
3728    /** Key constant @type Number */
3729    H: 72,
3730    /** Key constant @type Number */
3731    I: 73,
3732    /** Key constant @type Number */
3733    J: 74,
3734    /** Key constant @type Number */
3735    K: 75,
3736    /** Key constant @type Number */
3737    L: 76,
3738    /** Key constant @type Number */
3739    M: 77,
3740    /** Key constant @type Number */
3741    N: 78,
3742    /** Key constant @type Number */
3743    O: 79,
3744    /** Key constant @type Number */
3745    P: 80,
3746    /** Key constant @type Number */
3747    Q: 81,
3748    /** Key constant @type Number */
3749    R: 82,
3750    /** Key constant @type Number */
3751    S: 83,
3752    /** Key constant @type Number */
3753    T: 84,
3754    /** Key constant @type Number */
3755    U: 85,
3756    /** Key constant @type Number */
3757    V: 86,
3758    /** Key constant @type Number */
3759    W: 87,
3760    /** Key constant @type Number */
3761    X: 88,
3762    /** Key constant @type Number */
3763    Y: 89,
3764    /** Key constant @type Number */
3765    Z: 90,
3766    /** Key constant @type Number */
3767    CONTEXT_MENU: 93,
3768    /** Key constant @type Number */
3769    NUM_ZERO: 96,
3770    /** Key constant @type Number */
3771    NUM_ONE: 97,
3772    /** Key constant @type Number */
3773    NUM_TWO: 98,
3774    /** Key constant @type Number */
3775    NUM_THREE: 99,
3776    /** Key constant @type Number */
3777    NUM_FOUR: 100,
3778    /** Key constant @type Number */
3779    NUM_FIVE: 101,
3780    /** Key constant @type Number */
3781    NUM_SIX: 102,
3782    /** Key constant @type Number */
3783    NUM_SEVEN: 103,
3784    /** Key constant @type Number */
3785    NUM_EIGHT: 104,
3786    /** Key constant @type Number */
3787    NUM_NINE: 105,
3788    /** Key constant @type Number */
3789    NUM_MULTIPLY: 106,
3790    /** Key constant @type Number */
3791    NUM_PLUS: 107,
3792    /** Key constant @type Number */
3793    NUM_MINUS: 109,
3794    /** Key constant @type Number */
3795    NUM_PERIOD: 110,
3796    /** Key constant @type Number */
3797    NUM_DIVISION: 111,
3798    /** Key constant @type Number */
3799    F1: 112,
3800    /** Key constant @type Number */
3801    F2: 113,
3802    /** Key constant @type Number */
3803    F3: 114,
3804    /** Key constant @type Number */
3805    F4: 115,
3806    /** Key constant @type Number */
3807    F5: 116,
3808    /** Key constant @type Number */
3809    F6: 117,
3810    /** Key constant @type Number */
3811    F7: 118,
3812    /** Key constant @type Number */
3813    F8: 119,
3814    /** Key constant @type Number */
3815    F9: 120,
3816    /** Key constant @type Number */
3817    F10: 121,
3818    /** Key constant @type Number */
3819    F11: 122,
3820    /** Key constant @type Number */
3821    F12: 123,
3822
3823    /** @private */
3824    isNavKeyPress : function(){
3825        var me = this,
3826            k = this.normalizeKey(me.keyCode);
3827        return (k >= 33 && k <= 40) ||  // Page Up/Down, End, Home, Left, Up, Right, Down
3828        k == me.RETURN ||
3829        k == me.TAB ||
3830        k == me.ESC;
3831    },
3832
3833    isSpecialKey : function(){
3834        var k = this.normalizeKey(this.keyCode);
3835        return (this.type == 'keypress' && this.ctrlKey) ||
3836        this.isNavKeyPress() ||
3837        (k == this.BACKSPACE) || // Backspace
3838        (k >= 16 && k <= 20) || // Shift, Ctrl, Alt, Pause, Caps Lock
3839        (k >= 44 && k <= 46);   // Print Screen, Insert, Delete
3840    },
3841
3842    getPoint : function(){
3843        return new Ext.lib.Point(this.xy[0], this.xy[1]);
3844    },
3845
3846    /**
3847     * Returns true if the control, meta, shift or alt key was pressed during this event.
3848     * @return {Boolean}
3849     */
3850    hasModifier : function(){
3851        return ((this.ctrlKey || this.altKey) || this.shiftKey);
3852    }
3853 });/**
3854  * @class Ext.Element
3855  * <p>Encapsulates a DOM element, adding simple DOM manipulation facilities, normalizing for browser differences.</p>
3856  * <p>All instances of this class inherit the methods of {@link Ext.Fx} making visual effects easily available to all DOM elements.</p>
3857  * <p>Note that the events documented in this class are not Ext events, they encapsulate browser events. To
3858  * access the underlying browser event, see {@link Ext.EventObject#browserEvent}. Some older
3859  * browsers may not support the full range of events. Which events are supported is beyond the control of ExtJs.</p>
3860  * Usage:<br>
3861 <pre><code>
3862 // by id
3863 var el = Ext.get("my-div");
3864
3865 // by DOM element reference
3866 var el = Ext.get(myDivElement);
3867 </code></pre>
3868  * <b>Animations</b><br />
3869  * <p>When an element is manipulated, by default there is no animation.</p>
3870  * <pre><code>
3871 var el = Ext.get("my-div");
3872
3873 // no animation
3874 el.setWidth(100);
3875  * </code></pre>
3876  * <p>Many of the functions for manipulating an element have an optional "animate" parameter.  This
3877  * parameter can be specified as boolean (<tt>true</tt>) for default animation effects.</p>
3878  * <pre><code>
3879 // default animation
3880 el.setWidth(100, true);
3881  * </code></pre>
3882  *
3883  * <p>To configure the effects, an object literal with animation options to use as the Element animation
3884  * configuration object can also be specified. Note that the supported Element animation configuration
3885  * options are a subset of the {@link Ext.Fx} animation options specific to Fx effects.  The supported
3886  * Element animation configuration options are:</p>
3887 <pre>
3888 Option    Default   Description
3889 --------- --------  ---------------------------------------------
3890 {@link Ext.Fx#duration duration}  .35       The duration of the animation in seconds
3891 {@link Ext.Fx#easing easing}    easeOut   The easing method
3892 {@link Ext.Fx#callback callback}  none      A function to execute when the anim completes
3893 {@link Ext.Fx#scope scope}     this      The scope (this) of the callback function
3894 </pre>
3895  *
3896  * <pre><code>
3897 // Element animation options object
3898 var opt = {
3899     {@link Ext.Fx#duration duration}: 1,
3900     {@link Ext.Fx#easing easing}: 'elasticIn',
3901     {@link Ext.Fx#callback callback}: this.foo,
3902     {@link Ext.Fx#scope scope}: this
3903 };
3904 // animation with some options set
3905 el.setWidth(100, opt);
3906  * </code></pre>
3907  * <p>The Element animation object being used for the animation will be set on the options
3908  * object as "anim", which allows you to stop or manipulate the animation. Here is an example:</p>
3909  * <pre><code>
3910 // using the "anim" property to get the Anim object
3911 if(opt.anim.isAnimated()){
3912     opt.anim.stop();
3913 }
3914  * </code></pre>
3915  * <p>Also see the <tt>{@link #animate}</tt> method for another animation technique.</p>
3916  * <p><b> Composite (Collections of) Elements</b></p>
3917  * <p>For working with collections of Elements, see {@link Ext.CompositeElement}</p>
3918  * @constructor Create a new Element directly.
3919  * @param {String/HTMLElement} element
3920  * @param {Boolean} forceNew (optional) By default the constructor checks to see if there is already an instance of this element in the cache and if there is it returns the same instance. This will skip that check (useful for extending this class).
3921  */
3922 (function(){
3923 var DOC = document;
3924
3925 Ext.Element = function(element, forceNew){
3926     var dom = typeof element == "string" ?
3927               DOC.getElementById(element) : element,
3928         id;
3929
3930     if(!dom) return null;
3931
3932     id = dom.id;
3933
3934     if(!forceNew && id && Ext.elCache[id]){ // element object already exists
3935         return Ext.elCache[id].el;
3936     }
3937
3938     /**
3939      * The DOM element
3940      * @type HTMLElement
3941      */
3942     this.dom = dom;
3943
3944     /**
3945      * The DOM element ID
3946      * @type String
3947      */
3948     this.id = id || Ext.id(dom);
3949 };
3950
3951 var D = Ext.lib.Dom,
3952     DH = Ext.DomHelper,
3953     E = Ext.lib.Event,
3954     A = Ext.lib.Anim,
3955     El = Ext.Element,
3956     EC = Ext.elCache;
3957
3958 El.prototype = {
3959     /**
3960      * Sets the passed attributes as attributes of this element (a style attribute can be a string, object or function)
3961      * @param {Object} o The object with the attributes
3962      * @param {Boolean} useSet (optional) false to override the default setAttribute to use expandos.
3963      * @return {Ext.Element} this
3964      */
3965     set : function(o, useSet){
3966         var el = this.dom,
3967             attr,
3968             val,
3969             useSet = (useSet !== false) && !!el.setAttribute;
3970
3971         for(attr in o){
3972             if (o.hasOwnProperty(attr)) {
3973                 val = o[attr];
3974                 if (attr == 'style') {
3975                     DH.applyStyles(el, val);
3976                 } else if (attr == 'cls') {
3977                     el.className = val;
3978                 } else if (useSet) {
3979                     el.setAttribute(attr, val);
3980                 } else {
3981                     el[attr] = val;
3982                 }
3983             }
3984         }
3985         return this;
3986     },
3987
3988 //  Mouse events
3989     /**
3990      * @event click
3991      * Fires when a mouse click is detected within the element.
3992      * @param {Ext.EventObject} e The {@link Ext.EventObject} encapsulating the DOM event.
3993      * @param {HtmlElement} t The target of the event.
3994      * @param {Object} o The options configuration passed to the {@link #addListener} call.
3995      */
3996     /**
3997      * @event contextmenu
3998      * Fires when a right click is detected within the element.
3999      * @param {Ext.EventObject} e The {@link Ext.EventObject} encapsulating the DOM event.
4000      * @param {HtmlElement} t The target of the event.
4001      * @param {Object} o The options configuration passed to the {@link #addListener} call.
4002      */
4003     /**
4004      * @event dblclick
4005      * Fires when a mouse double click is detected within the element.
4006      * @param {Ext.EventObject} e The {@link Ext.EventObject} encapsulating the DOM event.
4007      * @param {HtmlElement} t The target of the event.
4008      * @param {Object} o The options configuration passed to the {@link #addListener} call.
4009      */
4010     /**
4011      * @event mousedown
4012      * Fires when a mousedown is detected within the element.
4013      * @param {Ext.EventObject} e The {@link Ext.EventObject} encapsulating the DOM event.
4014      * @param {HtmlElement} t The target of the event.
4015      * @param {Object} o The options configuration passed to the {@link #addListener} call.
4016      */
4017     /**
4018      * @event mouseup
4019      * Fires when a mouseup is detected within the element.
4020      * @param {Ext.EventObject} e The {@link Ext.EventObject} encapsulating the DOM event.
4021      * @param {HtmlElement} t The target of the event.
4022      * @param {Object} o The options configuration passed to the {@link #addListener} call.
4023      */
4024     /**
4025      * @event mouseover
4026      * Fires when a mouseover is detected within the element.
4027      * @param {Ext.EventObject} e The {@link Ext.EventObject} encapsulating the DOM event.
4028      * @param {HtmlElement} t The target of the event.
4029      * @param {Object} o The options configuration passed to the {@link #addListener} call.
4030      */
4031     /**
4032      * @event mousemove
4033      * Fires when a mousemove is detected with the element.
4034      * @param {Ext.EventObject} e The {@link Ext.EventObject} encapsulating the DOM event.
4035      * @param {HtmlElement} t The target of the event.
4036      * @param {Object} o The options configuration passed to the {@link #addListener} call.
4037      */
4038     /**
4039      * @event mouseout
4040      * Fires when a mouseout is detected with the element.
4041      * @param {Ext.EventObject} e The {@link Ext.EventObject} encapsulating the DOM event.
4042      * @param {HtmlElement} t The target of the event.
4043      * @param {Object} o The options configuration passed to the {@link #addListener} call.
4044      */
4045     /**
4046      * @event mouseenter
4047      * Fires when the mouse enters the element.
4048      * @param {Ext.EventObject} e The {@link Ext.EventObject} encapsulating the DOM event.
4049      * @param {HtmlElement} t The target of the event.
4050      * @param {Object} o The options configuration passed to the {@link #addListener} call.
4051      */
4052     /**
4053      * @event mouseleave
4054      * Fires when the mouse leaves the element.
4055      * @param {Ext.EventObject} e The {@link Ext.EventObject} encapsulating the DOM event.
4056      * @param {HtmlElement} t The target of the event.
4057      * @param {Object} o The options configuration passed to the {@link #addListener} call.
4058      */
4059
4060 //  Keyboard events
4061     /**
4062      * @event keypress
4063      * Fires when a keypress is detected within the element.
4064      * @param {Ext.EventObject} e The {@link Ext.EventObject} encapsulating the DOM event.
4065      * @param {HtmlElement} t The target of the event.
4066      * @param {Object} o The options configuration passed to the {@link #addListener} call.
4067      */
4068     /**
4069      * @event keydown
4070      * Fires when a keydown is detected within the element.
4071      * @param {Ext.EventObject} e The {@link Ext.EventObject} encapsulating the DOM event.
4072      * @param {HtmlElement} t The target of the event.
4073      * @param {Object} o The options configuration passed to the {@link #addListener} call.
4074      */
4075     /**
4076      * @event keyup
4077      * Fires when a keyup is detected within the element.
4078      * @param {Ext.EventObject} e The {@link Ext.EventObject} encapsulating the DOM event.
4079      * @param {HtmlElement} t The target of the event.
4080      * @param {Object} o The options configuration passed to the {@link #addListener} call.
4081      */
4082
4083
4084 //  HTML frame/object events
4085     /**
4086      * @event load
4087      * Fires when the user agent finishes loading all content within the element. Only supported by window, frames, objects and images.
4088      * @param {Ext.EventObject} e The {@link Ext.EventObject} encapsulating the DOM event.
4089      * @param {HtmlElement} t The target of the event.
4090      * @param {Object} o The options configuration passed to the {@link #addListener} call.
4091      */
4092     /**
4093      * @event unload
4094      * Fires when the user agent removes all content from a window or frame. For elements, it fires when the target element or any of its content has been removed.
4095      * @param {Ext.EventObject} e The {@link Ext.EventObject} encapsulating the DOM event.
4096      * @param {HtmlElement} t The target of the event.
4097      * @param {Object} o The options configuration passed to the {@link #addListener} call.
4098      */
4099     /**
4100      * @event abort
4101      * Fires when an object/image is stopped from loading before completely loaded.
4102      * @param {Ext.EventObject} e The {@link Ext.EventObject} encapsulating the DOM event.
4103      * @param {HtmlElement} t The target of the event.
4104      * @param {Object} o The options configuration passed to the {@link #addListener} call.
4105      */
4106     /**
4107      * @event error
4108      * Fires when an object/image/frame cannot be loaded properly.
4109      * @param {Ext.EventObject} e The {@link Ext.EventObject} encapsulating the DOM event.
4110      * @param {HtmlElement} t The target of the event.
4111      * @param {Object} o The options configuration passed to the {@link #addListener} call.
4112      */
4113     /**
4114      * @event resize
4115      * Fires when a document view is resized.
4116      * @param {Ext.EventObject} e The {@link Ext.EventObject} encapsulating the DOM event.
4117      * @param {HtmlElement} t The target of the event.
4118      * @param {Object} o The options configuration passed to the {@link #addListener} call.
4119      */
4120     /**
4121      * @event scroll
4122      * Fires when a document view is scrolled.
4123      * @param {Ext.EventObject} e The {@link Ext.EventObject} encapsulating the DOM event.
4124      * @param {HtmlElement} t The target of the event.
4125      * @param {Object} o The options configuration passed to the {@link #addListener} call.
4126      */
4127
4128 //  Form events
4129     /**
4130      * @event select
4131      * Fires when a user selects some text in a text field, including input and textarea.
4132      * @param {Ext.EventObject} e The {@link Ext.EventObject} encapsulating the DOM event.
4133      * @param {HtmlElement} t The target of the event.
4134      * @param {Object} o The options configuration passed to the {@link #addListener} call.
4135      */
4136     /**
4137      * @event change
4138      * Fires when a control loses the input focus and its value has been modified since gaining focus.
4139      * @param {Ext.EventObject} e The {@link Ext.EventObject} encapsulating the DOM event.
4140      * @param {HtmlElement} t The target of the event.
4141      * @param {Object} o The options configuration passed to the {@link #addListener} call.
4142      */
4143     /**
4144      * @event submit
4145      * Fires when a form is submitted.
4146      * @param {Ext.EventObject} e The {@link Ext.EventObject} encapsulating the DOM event.
4147      * @param {HtmlElement} t The target of the event.
4148      * @param {Object} o The options configuration passed to the {@link #addListener} call.
4149      */
4150     /**
4151      * @event reset
4152      * Fires when a form is reset.
4153      * @param {Ext.EventObject} e The {@link Ext.EventObject} encapsulating the DOM event.
4154      * @param {HtmlElement} t The target of the event.
4155      * @param {Object} o The options configuration passed to the {@link #addListener} call.
4156      */
4157     /**
4158      * @event focus
4159      * Fires when an element receives focus either via the pointing device or by tab navigation.
4160      * @param {Ext.EventObject} e The {@link Ext.EventObject} encapsulating the DOM event.
4161      * @param {HtmlElement} t The target of the event.
4162      * @param {Object} o The options configuration passed to the {@link #addListener} call.
4163      */
4164     /**
4165      * @event blur
4166      * Fires when an element loses focus either via the pointing device or by tabbing navigation.
4167      * @param {Ext.EventObject} e The {@link Ext.EventObject} encapsulating the DOM event.
4168      * @param {HtmlElement} t The target of the event.
4169      * @param {Object} o The options configuration passed to the {@link #addListener} call.
4170      */
4171
4172 //  User Interface events
4173     /**
4174      * @event DOMFocusIn
4175      * Where supported. Similar to HTML focus event, but can be applied to any focusable element.
4176      * @param {Ext.EventObject} e The {@link Ext.EventObject} encapsulating the DOM event.
4177      * @param {HtmlElement} t The target of the event.
4178      * @param {Object} o The options configuration passed to the {@link #addListener} call.
4179      */
4180     /**
4181      * @event DOMFocusOut
4182      * Where supported. Similar to HTML blur event, but can be applied to any focusable element.
4183      * @param {Ext.EventObject} e The {@link Ext.EventObject} encapsulating the DOM event.
4184      * @param {HtmlElement} t The target of the event.
4185      * @param {Object} o The options configuration passed to the {@link #addListener} call.
4186      */
4187     /**
4188      * @event DOMActivate
4189      * Where supported. Fires when an element is activated, for instance, through a mouse click or a keypress.
4190      * @param {Ext.EventObject} e The {@link Ext.EventObject} encapsulating the DOM event.
4191      * @param {HtmlElement} t The target of the event.
4192      * @param {Object} o The options configuration passed to the {@link #addListener} call.
4193      */
4194
4195 //  DOM Mutation events
4196     /**
4197      * @event DOMSubtreeModified
4198      * Where supported. Fires when the subtree is modified.
4199      * @param {Ext.EventObject} e The {@link Ext.EventObject} encapsulating the DOM event.
4200      * @param {HtmlElement} t The target of the event.
4201      * @param {Object} o The options configuration passed to the {@link #addListener} call.
4202      */
4203     /**
4204      * @event DOMNodeInserted
4205      * Where supported. Fires when a node has been added as a child of another node.
4206      * @param {Ext.EventObject} e The {@link Ext.EventObject} encapsulating the DOM event.
4207      * @param {HtmlElement} t The target of the event.
4208      * @param {Object} o The options configuration passed to the {@link #addListener} call.
4209      */
4210     /**
4211      * @event DOMNodeRemoved
4212      * Where supported. Fires when a descendant node of the element is removed.
4213      * @param {Ext.EventObject} e The {@link Ext.EventObject} encapsulating the DOM event.
4214      * @param {HtmlElement} t The target of the event.
4215      * @param {Object} o The options configuration passed to the {@link #addListener} call.
4216      */
4217     /**
4218      * @event DOMNodeRemovedFromDocument
4219      * Where supported. Fires when a node is being removed from a document.
4220      * @param {Ext.EventObject} e The {@link Ext.EventObject} encapsulating the DOM event.
4221      * @param {HtmlElement} t The target of the event.
4222      * @param {Object} o The options configuration passed to the {@link #addListener} call.
4223      */
4224     /**
4225      * @event DOMNodeInsertedIntoDocument
4226      * Where supported. Fires when a node is being inserted into a document.
4227      * @param {Ext.EventObject} e The {@link Ext.EventObject} encapsulating the DOM event.
4228      * @param {HtmlElement} t The target of the event.
4229      * @param {Object} o The options configuration passed to the {@link #addListener} call.
4230      */
4231     /**
4232      * @event DOMAttrModified
4233      * Where supported. Fires when an attribute has been modified.
4234      * @param {Ext.EventObject} e The {@link Ext.EventObject} encapsulating the DOM event.
4235      * @param {HtmlElement} t The target of the event.
4236      * @param {Object} o The options configuration passed to the {@link #addListener} call.
4237      */
4238     /**
4239      * @event DOMCharacterDataModified
4240      * Where supported. Fires when the character data has been modified.
4241      * @param {Ext.EventObject} e The {@link Ext.EventObject} encapsulating the DOM event.
4242      * @param {HtmlElement} t The target of the event.
4243      * @param {Object} o The options configuration passed to the {@link #addListener} call.
4244      */
4245
4246     /**
4247      * The default unit to append to CSS values where a unit isn't provided (defaults to px).
4248      * @type String
4249      */
4250     defaultUnit : "px",
4251
4252     /**
4253      * Returns true if this element matches the passed simple selector (e.g. div.some-class or span:first-child)
4254      * @param {String} selector The simple selector to test
4255      * @return {Boolean} True if this element matches the selector, else false
4256      */
4257     is : function(simpleSelector){
4258         return Ext.DomQuery.is(this.dom, simpleSelector);
4259     },
4260
4261     /**
4262      * Tries to focus the element. Any exceptions are caught and ignored.
4263      * @param {Number} defer (optional) Milliseconds to defer the focus
4264      * @return {Ext.Element} this
4265      */
4266     focus : function(defer, /* private */ dom) {
4267         var me = this,
4268             dom = dom || me.dom;
4269         try{
4270             if(Number(defer)){
4271                 me.focus.defer(defer, null, [null, dom]);
4272             }else{
4273                 dom.focus();
4274             }
4275         }catch(e){}
4276         return me;
4277     },
4278
4279     /**
4280      * Tries to blur the element. Any exceptions are caught and ignored.
4281      * @return {Ext.Element} this
4282      */
4283     blur : function() {
4284         try{
4285             this.dom.blur();
4286         }catch(e){}
4287         return this;
4288     },
4289
4290     /**
4291      * Returns the value of the "value" attribute
4292      * @param {Boolean} asNumber true to parse the value as a number
4293      * @return {String/Number}
4294      */
4295     getValue : function(asNumber){
4296         var val = this.dom.value;
4297         return asNumber ? parseInt(val, 10) : val;
4298     },
4299
4300     /**
4301      * Appends an event handler to this element.  The shorthand version {@link #on} is equivalent.
4302      * @param {String} eventName The name of event to handle.
4303      * @param {Function} fn The handler function the event invokes. This function is passed
4304      * the following parameters:<ul>
4305      * <li><b>evt</b> : EventObject<div class="sub-desc">The {@link Ext.EventObject EventObject} describing the event.</div></li>
4306      * <li><b>el</b> : HtmlElement<div class="sub-desc">The DOM element which was the target of the event.
4307      * Note that this may be filtered by using the <tt>delegate</tt> option.</div></li>
4308      * <li><b>o</b> : Object<div class="sub-desc">The options object from the addListener call.</div></li>
4309      * </ul>
4310      * @param {Object} scope (optional) The scope (<code><b>this</b></code> reference) in which the handler function is executed.
4311      * <b>If omitted, defaults to this Element.</b>.
4312      * @param {Object} options (optional) An object containing handler configuration properties.
4313      * This may contain any of the following properties:<ul>
4314      * <li><b>scope</b> Object : <div class="sub-desc">The scope (<code><b>this</b></code> reference) in which the handler function is executed.
4315      * <b>If omitted, defaults to this Element.</b></div></li>
4316      * <li><b>delegate</b> String: <div class="sub-desc">A simple selector to filter the target or look for a descendant of the target. See below for additional details.</div></li>
4317      * <li><b>stopEvent</b> Boolean: <div class="sub-desc">True to stop the event. That is stop propagation, and prevent the default action.</div></li>
4318      * <li><b>preventDefault</b> Boolean: <div class="sub-desc">True to prevent the default action</div></li>
4319      * <li><b>stopPropagation</b> Boolean: <div class="sub-desc">True to prevent event propagation</div></li>
4320      * <li><b>normalized</b> Boolean: <div class="sub-desc">False to pass a browser event to the handler function instead of an Ext.EventObject</div></li>
4321      * <li><b>target</b> Ext.Element: <div class="sub-desc">Only call the handler if the event was fired on the target Element, <i>not</i> if the event was bubbled up from a child node.</div></li>
4322      * <li><b>delay</b> Number: <div class="sub-desc">The number of milliseconds to delay the invocation of the handler after the event fires.</div></li>
4323      * <li><b>single</b> Boolean: <div class="sub-desc">True to add a handler to handle just the next firing of the event, and then remove itself.</div></li>
4324      * <li><b>buffer</b> Number: <div class="sub-desc">Causes the handler to be scheduled to run in an {@link Ext.util.DelayedTask} delayed
4325      * by the specified number of milliseconds. If the event fires again within that time, the original
4326      * handler is <em>not</em> invoked, but the new handler is scheduled in its place.</div></li>
4327      * </ul><br>
4328      * <p>
4329      * <b>Combining Options</b><br>
4330      * In the following examples, the shorthand form {@link #on} is used rather than the more verbose
4331      * addListener.  The two are equivalent.  Using the options argument, it is possible to combine different
4332      * types of listeners:<br>
4333      * <br>
4334      * A delayed, one-time listener that auto stops the event and adds a custom argument (forumId) to the
4335      * options object. The options object is available as the third parameter in the handler function.<div style="margin: 5px 20px 20px;">
4336      * Code:<pre><code>
4337 el.on('click', this.onClick, this, {
4338     single: true,
4339     delay: 100,
4340     stopEvent : true,
4341     forumId: 4
4342 });</code></pre></p>
4343      * <p>
4344      * <b>Attaching multiple handlers in 1 call</b><br>
4345      * The method also allows for a single argument to be passed which is a config object containing properties
4346      * which specify multiple handlers.</p>
4347      * <p>
4348      * Code:<pre><code>
4349 el.on({
4350     'click' : {
4351         fn: this.onClick,
4352         scope: this,
4353         delay: 100
4354     },
4355     'mouseover' : {
4356         fn: this.onMouseOver,
4357         scope: this
4358     },
4359     'mouseout' : {
4360         fn: this.onMouseOut,
4361         scope: this
4362     }
4363 });</code></pre>
4364      * <p>
4365      * Or a shorthand syntax:<br>
4366      * Code:<pre><code></p>
4367 el.on({
4368     'click' : this.onClick,
4369     'mouseover' : this.onMouseOver,
4370     'mouseout' : this.onMouseOut,
4371     scope: this
4372 });
4373      * </code></pre></p>
4374      * <p><b>delegate</b></p>
4375      * <p>This is a configuration option that you can pass along when registering a handler for
4376      * an event to assist with event delegation. Event delegation is a technique that is used to
4377      * reduce memory consumption and prevent exposure to memory-leaks. By registering an event
4378      * for a container element as opposed to each element within a container. By setting this
4379      * configuration option to a simple selector, the target element will be filtered to look for
4380      * a descendant of the target.
4381      * For example:<pre><code>
4382 // using this markup:
4383 &lt;div id='elId'>
4384     &lt;p id='p1'>paragraph one&lt;/p>
4385     &lt;p id='p2' class='clickable'>paragraph two&lt;/p>
4386     &lt;p id='p3'>paragraph three&lt;/p>
4387 &lt;/div>
4388 // utilize event delegation to registering just one handler on the container element:
4389 el = Ext.get('elId');
4390 el.on(
4391     'click',
4392     function(e,t) {
4393         // handle click
4394         console.info(t.id); // 'p2'
4395     },
4396     this,
4397     {
4398         // filter the target element to be a descendant with the class 'clickable'
4399         delegate: '.clickable'
4400     }
4401 );
4402      * </code></pre></p>
4403      * @return {Ext.Element} this
4404      */
4405     addListener : function(eventName, fn, scope, options){
4406         Ext.EventManager.on(this.dom,  eventName, fn, scope || this, options);
4407         return this;
4408     },
4409
4410     /**
4411      * Removes an event handler from this element.  The shorthand version {@link #un} is equivalent.
4412      * <b>Note</b>: if a <i>scope</i> was explicitly specified when {@link #addListener adding} the
4413      * listener, the same scope must be specified here.
4414      * Example:
4415      * <pre><code>
4416 el.removeListener('click', this.handlerFn);
4417 // or
4418 el.un('click', this.handlerFn);
4419 </code></pre>
4420      * @param {String} eventName The name of the event from which to remove the handler.
4421      * @param {Function} fn The handler function to remove. <b>This must be a reference to the function passed into the {@link #addListener} call.</b>
4422      * @param {Object} scope If a scope (<b><code>this</code></b> reference) was specified when the listener was added,
4423      * then this must refer to the same object.
4424      * @return {Ext.Element} this
4425      */
4426     removeListener : function(eventName, fn, scope){
4427         Ext.EventManager.removeListener(this.dom,  eventName, fn, scope || this);
4428         return this;
4429     },
4430
4431     /**
4432      * Removes all previous added listeners from this element
4433      * @return {Ext.Element} this
4434      */
4435     removeAllListeners : function(){
4436         Ext.EventManager.removeAll(this.dom);
4437         return this;
4438     },
4439
4440     /**
4441      * Recursively removes all previous added listeners from this element and its children
4442      * @return {Ext.Element} this
4443      */
4444     purgeAllListeners : function() {
4445         Ext.EventManager.purgeElement(this, true);
4446         return this;
4447     },
4448     /**
4449      * @private Test if size has a unit, otherwise appends the default
4450      */
4451     addUnits : function(size){
4452         if(size === "" || size == "auto" || size === undefined){
4453             size = size || '';
4454         } else if(!isNaN(size) || !unitPattern.test(size)){
4455             size = size + (this.defaultUnit || 'px');
4456         }
4457         return size;
4458     },
4459
4460     /**
4461      * <p>Updates the <a href="http://developer.mozilla.org/en/DOM/element.innerHTML">innerHTML</a> of this Element
4462      * from a specified URL. Note that this is subject to the <a href="http://en.wikipedia.org/wiki/Same_origin_policy">Same Origin Policy</a></p>
4463      * <p>Updating innerHTML of an element will <b>not</b> execute embedded <tt>&lt;script></tt> elements. This is a browser restriction.</p>
4464      * @param {Mixed} options. Either a sring containing the URL from which to load the HTML, or an {@link Ext.Ajax#request} options object specifying
4465      * exactly how to request the HTML.
4466      * @return {Ext.Element} this
4467      */
4468     load : function(url, params, cb){
4469         Ext.Ajax.request(Ext.apply({
4470             params: params,
4471             url: url.url || url,
4472             callback: cb,
4473             el: this.dom,
4474             indicatorText: url.indicatorText || ''
4475         }, Ext.isObject(url) ? url : {}));
4476         return this;
4477     },
4478
4479     /**
4480      * Tests various css rules/browsers to determine if this element uses a border box
4481      * @return {Boolean}
4482      */
4483     isBorderBox : function(){
4484         return noBoxAdjust[(this.dom.tagName || "").toLowerCase()] || Ext.isBorderBox;
4485     },
4486
4487     /**
4488      * <p>Removes this element's dom reference.  Note that event and cache removal is handled at {@link Ext#removeNode}</p>
4489      */
4490     remove : function(){
4491         var me = this,
4492             dom = me.dom;
4493
4494         if (dom) {
4495             delete me.dom;
4496             Ext.removeNode(dom);
4497         }
4498     },
4499
4500     /**
4501      * Sets up event handlers to call the passed functions when the mouse is moved into and out of the Element.
4502      * @param {Function} overFn The function to call when the mouse enters the Element.
4503      * @param {Function} outFn The function to call when the mouse leaves the Element.
4504      * @param {Object} scope (optional) The scope (<code>this</code> reference) in which the functions are executed. Defaults to the Element's DOM element.
4505      * @param {Object} options (optional) Options for the listener. See {@link Ext.util.Observable#addListener the <tt>options</tt> parameter}.
4506      * @return {Ext.Element} this
4507      */
4508     hover : function(overFn, outFn, scope, options){
4509         var me = this;
4510         me.on('mouseenter', overFn, scope || me.dom, options);
4511         me.on('mouseleave', outFn, scope || me.dom, options);
4512         return me;
4513     },
4514
4515     /**
4516      * Returns true if this element is an ancestor of the passed element
4517      * @param {HTMLElement/String} el The element to check
4518      * @return {Boolean} True if this element is an ancestor of el, else false
4519      */
4520     contains : function(el){
4521         return !el ? false : Ext.lib.Dom.isAncestor(this.dom, el.dom ? el.dom : el);
4522     },
4523
4524     /**
4525      * Returns the value of a namespaced attribute from the element's underlying DOM node.
4526      * @param {String} namespace The namespace in which to look for the attribute
4527      * @param {String} name The attribute name
4528      * @return {String} The attribute value
4529      * @deprecated
4530      */
4531     getAttributeNS : function(ns, name){
4532         return this.getAttribute(name, ns);
4533     },
4534
4535     /**
4536      * Returns the value of an attribute from the element's underlying DOM node.
4537      * @param {String} name The attribute name
4538      * @param {String} namespace (optional) The namespace in which to look for the attribute
4539      * @return {String} The attribute value
4540      */
4541     getAttribute : Ext.isIE ? function(name, ns){
4542         var d = this.dom,
4543             type = typeof d[ns + ":" + name];
4544
4545         if(['undefined', 'unknown'].indexOf(type) == -1){
4546             return d[ns + ":" + name];
4547         }
4548         return d[name];
4549     } : function(name, ns){
4550         var d = this.dom;
4551         return d.getAttributeNS(ns, name) || d.getAttribute(ns + ":" + name) || d.getAttribute(name) || d[name];
4552     },
4553
4554     /**
4555     * Update the innerHTML of this element
4556     * @param {String} html The new HTML
4557     * @return {Ext.Element} this
4558      */
4559     update : function(html) {
4560         if (this.dom) {
4561             this.dom.innerHTML = html;
4562         }
4563         return this;
4564     }
4565 };
4566
4567 var ep = El.prototype;
4568
4569 El.addMethods = function(o){
4570    Ext.apply(ep, o);
4571 };
4572
4573 /**
4574  * Appends an event handler (shorthand for {@link #addListener}).
4575  * @param {String} eventName The name of event to handle.
4576  * @param {Function} fn The handler function the event invokes.
4577  * @param {Object} scope (optional) The scope (<code>this</code> reference) in which the handler function is executed.
4578  * @param {Object} options (optional) An object containing standard {@link #addListener} options
4579  * @member Ext.Element
4580  * @method on
4581  */
4582 ep.on = ep.addListener;
4583
4584 /**
4585  * Removes an event handler from this element (see {@link #removeListener} for additional notes).
4586  * @param {String} eventName The name of the event from which to remove the handler.
4587  * @param {Function} fn The handler function to remove. <b>This must be a reference to the function passed into the {@link #addListener} call.</b>
4588  * @param {Object} scope If a scope (<b><code>this</code></b> reference) was specified when the listener was added,
4589  * then this must refer to the same object.
4590  * @return {Ext.Element} this
4591  * @member Ext.Element
4592  * @method un
4593  */
4594 ep.un = ep.removeListener;
4595
4596 /**
4597  * true to automatically adjust width and height settings for box-model issues (default to true)
4598  */
4599 ep.autoBoxAdjust = true;
4600
4601 // private
4602 var unitPattern = /\d+(px|em|%|en|ex|pt|in|cm|mm|pc)$/i,
4603     docEl;
4604
4605 /**
4606  * @private
4607  */
4608
4609 /**
4610  * Retrieves Ext.Element objects.
4611  * <p><b>This method does not retrieve {@link Ext.Component Component}s.</b> This method
4612  * retrieves Ext.Element objects which encapsulate DOM elements. To retrieve a Component by
4613  * its ID, use {@link Ext.ComponentMgr#get}.</p>
4614  * <p>Uses simple caching to consistently return the same object. Automatically fixes if an
4615  * object was recreated with the same id via AJAX or DOM.</p>
4616  * @param {Mixed} el The id of the node, a DOM Node or an existing Element.
4617  * @return {Element} The Element object (or null if no matching element was found)
4618  * @static
4619  * @member Ext.Element
4620  * @method get
4621  */
4622 El.get = function(el){
4623     var ex,
4624         elm,
4625         id;
4626     if(!el){ return null; }
4627     if (typeof el == "string") { // element id
4628         if (!(elm = DOC.getElementById(el))) {
4629             return null;
4630         }
4631         if (EC[el] && EC[el].el) {
4632             ex = EC[el].el;
4633             ex.dom = elm;
4634         } else {
4635             ex = El.addToCache(new El(elm));
4636         }
4637         return ex;
4638     } else if (el.tagName) { // dom element
4639         if(!(id = el.id)){
4640             id = Ext.id(el);
4641         }
4642         if (EC[id] && EC[id].el) {
4643             ex = EC[id].el;
4644             ex.dom = el;
4645         } else {
4646             ex = El.addToCache(new El(el));
4647         }
4648         return ex;
4649     } else if (el instanceof El) {
4650         if(el != docEl){
4651             // refresh dom element in case no longer valid,
4652             // catch case where it hasn't been appended
4653
4654             // If an el instance is passed, don't pass to getElementById without some kind of id
4655             if (Ext.isIE && (el.id == undefined || el.id == '')) {
4656                 el.dom = el.dom;
4657             } else {
4658                 el.dom = DOC.getElementById(el.id) || el.dom;
4659             }
4660         }
4661         return el;
4662     } else if(el.isComposite) {
4663         return el;
4664     } else if(Ext.isArray(el)) {
4665         return El.select(el);
4666     } else if(el == DOC) {
4667         // create a bogus element object representing the document object
4668         if(!docEl){
4669             var f = function(){};
4670             f.prototype = El.prototype;
4671             docEl = new f();
4672             docEl.dom = DOC;
4673         }
4674         return docEl;
4675     }
4676     return null;
4677 };
4678
4679 El.addToCache = function(el, id){
4680     id = id || el.id;
4681     EC[id] = {
4682         el:  el,
4683         data: {},
4684         events: {}
4685     };
4686     return el;
4687 };
4688
4689 // private method for getting and setting element data
4690 El.data = function(el, key, value){
4691     el = El.get(el);
4692     if (!el) {
4693         return null;
4694     }
4695     var c = EC[el.id].data;
4696     if(arguments.length == 2){
4697         return c[key];
4698     }else{
4699         return (c[key] = value);
4700     }
4701 };
4702
4703 // private
4704 // Garbage collection - uncache elements/purge listeners on orphaned elements
4705 // so we don't hold a reference and cause the browser to retain them
4706 function garbageCollect(){
4707     if(!Ext.enableGarbageCollector){
4708         clearInterval(El.collectorThreadId);
4709     } else {
4710         var eid,
4711             el,
4712             d,
4713             o;
4714
4715         for(eid in EC){
4716             o = EC[eid];
4717             if(o.skipGC){
4718                 continue;
4719             }
4720             el = o.el;
4721             d = el.dom;
4722             // -------------------------------------------------------
4723             // Determining what is garbage:
4724             // -------------------------------------------------------
4725             // !d
4726             // dom node is null, definitely garbage
4727             // -------------------------------------------------------
4728             // !d.parentNode
4729             // no parentNode == direct orphan, definitely garbage
4730             // -------------------------------------------------------
4731             // !d.offsetParent && !document.getElementById(eid)
4732             // display none elements have no offsetParent so we will
4733             // also try to look it up by it's id. However, check
4734             // offsetParent first so we don't do unneeded lookups.
4735             // This enables collection of elements that are not orphans
4736             // directly, but somewhere up the line they have an orphan
4737             // parent.
4738             // -------------------------------------------------------
4739             if(!d || !d.parentNode || (!d.offsetParent && !DOC.getElementById(eid))){
4740                 if(Ext.enableListenerCollection){
4741                     Ext.EventManager.removeAll(d);
4742                 }
4743                 delete EC[eid];
4744             }
4745         }
4746         // Cleanup IE Object leaks
4747         if (Ext.isIE) {
4748             var t = {};
4749             for (eid in EC) {
4750                 t[eid] = EC[eid];
4751             }
4752             EC = Ext.elCache = t;
4753         }
4754     }
4755 }
4756 El.collectorThreadId = setInterval(garbageCollect, 30000);
4757
4758 var flyFn = function(){};
4759 flyFn.prototype = El.prototype;
4760
4761 // dom is optional
4762 El.Flyweight = function(dom){
4763     this.dom = dom;
4764 };
4765
4766 El.Flyweight.prototype = new flyFn();
4767 El.Flyweight.prototype.isFlyweight = true;
4768 El._flyweights = {};
4769
4770 /**
4771  * <p>Gets the globally shared flyweight Element, with the passed node as the active element. Do not store a reference to this element -
4772  * the dom node can be overwritten by other code. Shorthand of {@link Ext.Element#fly}</p>
4773  * <p>Use this to make one-time references to DOM elements which are not going to be accessed again either by
4774  * application code, or by Ext's classes. If accessing an element which will be processed regularly, then {@link Ext#get}
4775  * will be more appropriate to take advantage of the caching provided by the Ext.Element class.</p>
4776  * @param {String/HTMLElement} el The dom node or id
4777  * @param {String} named (optional) Allows for creation of named reusable flyweights to prevent conflicts
4778  * (e.g. internally Ext uses "_global")
4779  * @return {Element} The shared Element object (or null if no matching element was found)
4780  * @member Ext.Element
4781  * @method fly
4782  */
4783 El.fly = function(el, named){
4784     var ret = null;
4785     named = named || '_global';
4786
4787     if (el = Ext.getDom(el)) {
4788         (El._flyweights[named] = El._flyweights[named] || new El.Flyweight()).dom = el;
4789         ret = El._flyweights[named];
4790     }
4791     return ret;
4792 };
4793
4794 /**
4795  * Retrieves Ext.Element objects.
4796  * <p><b>This method does not retrieve {@link Ext.Component Component}s.</b> This method
4797  * retrieves Ext.Element objects which encapsulate DOM elements. To retrieve a Component by
4798  * its ID, use {@link Ext.ComponentMgr#get}.</p>
4799  * <p>Uses simple caching to consistently return the same object. Automatically fixes if an
4800  * object was recreated with the same id via AJAX or DOM.</p>
4801  * Shorthand of {@link Ext.Element#get}
4802  * @param {Mixed} el The id of the node, a DOM Node or an existing Element.
4803  * @return {Element} The Element object (or null if no matching element was found)
4804  * @member Ext
4805  * @method get
4806  */
4807 Ext.get = El.get;
4808
4809 /**
4810  * <p>Gets the globally shared flyweight Element, with the passed node as the active element. Do not store a reference to this element -
4811  * the dom node can be overwritten by other code. Shorthand of {@link Ext.Element#fly}</p>
4812  * <p>Use this to make one-time references to DOM elements which are not going to be accessed again either by
4813  * application code, or by Ext's classes. If accessing an element which will be processed regularly, then {@link Ext#get}
4814  * will be more appropriate to take advantage of the caching provided by the Ext.Element class.</p>
4815  * @param {String/HTMLElement} el The dom node or id
4816  * @param {String} named (optional) Allows for creation of named reusable flyweights to prevent conflicts
4817  * (e.g. internally Ext uses "_global")
4818  * @return {Element} The shared Element object (or null if no matching element was found)
4819  * @member Ext
4820  * @method fly
4821  */
4822 Ext.fly = El.fly;
4823
4824 // speedy lookup for elements never to box adjust
4825 var noBoxAdjust = Ext.isStrict ? {
4826     select:1
4827 } : {
4828     input:1, select:1, textarea:1
4829 };
4830 if(Ext.isIE || Ext.isGecko){
4831     noBoxAdjust['button'] = 1;
4832 }
4833
4834 })();
4835 /**
4836  * @class Ext.Element
4837  */
4838 Ext.Element.addMethods({
4839     /**
4840      * Stops the specified event(s) from bubbling and optionally prevents the default action
4841      * @param {String/Array} eventName an event / array of events to stop from bubbling
4842      * @param {Boolean} preventDefault (optional) true to prevent the default action too
4843      * @return {Ext.Element} this
4844      */
4845     swallowEvent : function(eventName, preventDefault){
4846         var me = this;
4847         function fn(e){
4848             e.stopPropagation();
4849             if(preventDefault){
4850                 e.preventDefault();
4851             }
4852         }
4853         if(Ext.isArray(eventName)){
4854             Ext.each(eventName, function(e) {
4855                  me.on(e, fn);
4856             });
4857             return me;
4858         }
4859         me.on(eventName, fn);
4860         return me;
4861     },
4862
4863     /**
4864      * Create an event handler on this element such that when the event fires and is handled by this element,
4865      * it will be relayed to another object (i.e., fired again as if it originated from that object instead).
4866      * @param {String} eventName The type of event to relay
4867      * @param {Object} object Any object that extends {@link Ext.util.Observable} that will provide the context
4868      * for firing the relayed event
4869      */
4870     relayEvent : function(eventName, observable){
4871         this.on(eventName, function(e){
4872             observable.fireEvent(eventName, e);
4873         });
4874     },
4875
4876     /**
4877      * Removes worthless text nodes
4878      * @param {Boolean} forceReclean (optional) By default the element
4879      * keeps track if it has been cleaned already so
4880      * you can call this over and over. However, if you update the element and
4881      * need to force a reclean, you can pass true.
4882      */
4883     clean : function(forceReclean){
4884         var me = this,
4885             dom = me.dom,
4886             n = dom.firstChild,
4887             ni = -1;
4888
4889         if(Ext.Element.data(dom, 'isCleaned') && forceReclean !== true){
4890             return me;
4891         }
4892
4893         while(n){
4894             var nx = n.nextSibling;
4895             if(n.nodeType == 3 && !/\S/.test(n.nodeValue)){
4896                 dom.removeChild(n);
4897             }else{
4898                 n.nodeIndex = ++ni;
4899             }
4900             n = nx;
4901         }
4902         Ext.Element.data(dom, 'isCleaned', true);
4903         return me;
4904     },
4905
4906     /**
4907      * Direct access to the Updater {@link Ext.Updater#update} method. The method takes the same object
4908      * parameter as {@link Ext.Updater#update}
4909      * @return {Ext.Element} this
4910      */
4911     load : function(){
4912         var um = this.getUpdater();
4913         um.update.apply(um, arguments);
4914         return this;
4915     },
4916
4917     /**
4918     * Gets this element's {@link Ext.Updater Updater}
4919     * @return {Ext.Updater} The Updater
4920     */
4921     getUpdater : function(){
4922         return this.updateManager || (this.updateManager = new Ext.Updater(this));
4923     },
4924
4925     /**
4926     * Update the innerHTML of this element, optionally searching for and processing scripts
4927     * @param {String} html The new HTML
4928     * @param {Boolean} loadScripts (optional) True to look for and process scripts (defaults to false)
4929     * @param {Function} callback (optional) For async script loading you can be notified when the update completes
4930     * @return {Ext.Element} this
4931      */
4932     update : function(html, loadScripts, callback){
4933         if (!this.dom) {
4934             return this;
4935         }
4936         html = html || "";
4937
4938         if(loadScripts !== true){
4939             this.dom.innerHTML = html;
4940             if(typeof callback == 'function'){
4941                 callback();
4942             }
4943             return this;
4944         }
4945
4946         var id = Ext.id(),
4947             dom = this.dom;
4948
4949         html += '<span id="' + id + '"></span>';
4950
4951         Ext.lib.Event.onAvailable(id, function(){
4952             var DOC = document,
4953                 hd = DOC.getElementsByTagName("head")[0],
4954                 re = /(?:<script([^>]*)?>)((\n|\r|.)*?)(?:<\/script>)/ig,
4955                 srcRe = /\ssrc=([\'\"])(.*?)\1/i,
4956                 typeRe = /\stype=([\'\"])(.*?)\1/i,
4957                 match,
4958                 attrs,
4959                 srcMatch,
4960                 typeMatch,
4961                 el,
4962                 s;
4963
4964             while((match = re.exec(html))){
4965                 attrs = match[1];
4966                 srcMatch = attrs ? attrs.match(srcRe) : false;
4967                 if(srcMatch && srcMatch[2]){
4968                    s = DOC.createElement("script");
4969                    s.src = srcMatch[2];
4970                    typeMatch = attrs.match(typeRe);
4971                    if(typeMatch && typeMatch[2]){
4972                        s.type = typeMatch[2];
4973                    }
4974                    hd.appendChild(s);
4975                 }else if(match[2] && match[2].length > 0){
4976                     if(window.execScript) {
4977                        window.execScript(match[2]);
4978                     } else {
4979                        window.eval(match[2]);
4980                     }
4981                 }
4982             }
4983             el = DOC.getElementById(id);
4984             if(el){Ext.removeNode(el);}
4985             if(typeof callback == 'function'){
4986                 callback();
4987             }
4988         });
4989         dom.innerHTML = html.replace(/(?:<script.*?>)((\n|\r|.)*?)(?:<\/script>)/ig, "");
4990         return this;
4991     },
4992
4993     // inherit docs, overridden so we can add removeAnchor
4994     removeAllListeners : function(){
4995         this.removeAnchor();
4996         Ext.EventManager.removeAll(this.dom);
4997         return this;
4998     },
4999
5000     /**
5001      * Creates a proxy element of this element
5002      * @param {String/Object} config The class name of the proxy element or a DomHelper config object
5003      * @param {String/HTMLElement} renderTo (optional) The element or element id to render the proxy to (defaults to document.body)
5004      * @param {Boolean} matchBox (optional) True to align and size the proxy to this element now (defaults to false)
5005      * @return {Ext.Element} The new proxy element
5006      */
5007     createProxy : function(config, renderTo, matchBox){
5008         config = (typeof config == 'object') ? config : {tag : "div", cls: config};
5009
5010         var me = this,
5011             proxy = renderTo ? Ext.DomHelper.append(renderTo, config, true) :
5012                                Ext.DomHelper.insertBefore(me.dom, config, true);
5013
5014         if(matchBox && me.setBox && me.getBox){ // check to make sure Element.position.js is loaded
5015            proxy.setBox(me.getBox());
5016         }
5017         return proxy;
5018     }
5019 });
5020
5021 Ext.Element.prototype.getUpdateManager = Ext.Element.prototype.getUpdater;
5022 /**
5023  * @class Ext.Element
5024  */
5025 Ext.Element.addMethods({
5026     /**
5027      * Gets the x,y coordinates specified by the anchor position on the element.
5028      * @param {String} anchor (optional) The specified anchor position (defaults to "c").  See {@link #alignTo}
5029      * for details on supported anchor positions.
5030      * @param {Boolean} local (optional) True to get the local (element top/left-relative) anchor position instead
5031      * of page coordinates
5032      * @param {Object} size (optional) An object containing the size to use for calculating anchor position
5033      * {width: (target width), height: (target height)} (defaults to the element's current size)
5034      * @return {Array} [x, y] An array containing the element's x and y coordinates
5035      */
5036     getAnchorXY : function(anchor, local, s){
5037         //Passing a different size is useful for pre-calculating anchors,
5038         //especially for anchored animations that change the el size.
5039                 anchor = (anchor || "tl").toLowerCase();
5040         s = s || {};
5041         
5042         var me = this,        
5043                 vp = me.dom == document.body || me.dom == document,
5044                 w = s.width || vp ? Ext.lib.Dom.getViewWidth() : me.getWidth(),
5045                 h = s.height || vp ? Ext.lib.Dom.getViewHeight() : me.getHeight(),                              
5046                 xy,             
5047                 r = Math.round,
5048                 o = me.getXY(),
5049                 scroll = me.getScroll(),
5050                 extraX = vp ? scroll.left : !local ? o[0] : 0,
5051                 extraY = vp ? scroll.top : !local ? o[1] : 0,
5052                 hash = {
5053                         c  : [r(w * 0.5), r(h * 0.5)],
5054                         t  : [r(w * 0.5), 0],
5055                         l  : [0, r(h * 0.5)],
5056                         r  : [w, r(h * 0.5)],
5057                         b  : [r(w * 0.5), h],
5058                         tl : [0, 0],    
5059                         bl : [0, h],
5060                         br : [w, h],
5061                         tr : [w, 0]
5062                 };
5063         
5064         xy = hash[anchor];      
5065         return [xy[0] + extraX, xy[1] + extraY]; 
5066     },
5067
5068     /**
5069      * Anchors an element to another element and realigns it when the window is resized.
5070      * @param {Mixed} element The element to align to.
5071      * @param {String} position The position to align to.
5072      * @param {Array} offsets (optional) Offset the positioning by [x, y]
5073      * @param {Boolean/Object} animate (optional) True for the default animation or a standard Element animation config object
5074      * @param {Boolean/Number} monitorScroll (optional) True to monitor body scroll and reposition. If this parameter
5075      * is a number, it is used as the buffer delay (defaults to 50ms).
5076      * @param {Function} callback The function to call after the animation finishes
5077      * @return {Ext.Element} this
5078      */
5079     anchorTo : function(el, alignment, offsets, animate, monitorScroll, callback){        
5080             var me = this,
5081             dom = me.dom,
5082             scroll = !Ext.isEmpty(monitorScroll),
5083             action = function(){
5084                 Ext.fly(dom).alignTo(el, alignment, offsets, animate);
5085                 Ext.callback(callback, Ext.fly(dom));
5086             },
5087             anchor = this.getAnchor();
5088             
5089         // previous listener anchor, remove it
5090         this.removeAnchor();
5091         Ext.apply(anchor, {
5092             fn: action,
5093             scroll: scroll
5094         });
5095
5096         Ext.EventManager.onWindowResize(action, null);
5097         
5098         if(scroll){
5099             Ext.EventManager.on(window, 'scroll', action, null,
5100                 {buffer: !isNaN(monitorScroll) ? monitorScroll : 50});
5101         }
5102         action.call(me); // align immediately
5103         return me;
5104     },
5105     
5106     /**
5107      * Remove any anchor to this element. See {@link #anchorTo}.
5108      * @return {Ext.Element} this
5109      */
5110     removeAnchor : function(){
5111         var me = this,
5112             anchor = this.getAnchor();
5113             
5114         if(anchor && anchor.fn){
5115             Ext.EventManager.removeResizeListener(anchor.fn);
5116             if(anchor.scroll){
5117                 Ext.EventManager.un(window, 'scroll', anchor.fn);
5118             }
5119             delete anchor.fn;
5120         }
5121         return me;
5122     },
5123     
5124     // private
5125     getAnchor : function(){
5126         var data = Ext.Element.data,
5127             dom = this.dom;
5128             if (!dom) {
5129                 return;
5130             }
5131             var anchor = data(dom, '_anchor');
5132             
5133         if(!anchor){
5134             anchor = data(dom, '_anchor', {});
5135         }
5136         return anchor;
5137     },
5138
5139     /**
5140      * Gets the x,y coordinates to align this element with another element. See {@link #alignTo} for more info on the
5141      * supported position values.
5142      * @param {Mixed} element The element to align to.
5143      * @param {String} position (optional, defaults to "tl-bl?") The position to align to.
5144      * @param {Array} offsets (optional) Offset the positioning by [x, y]
5145      * @return {Array} [x, y]
5146      */
5147     getAlignToXY : function(el, p, o){      
5148         el = Ext.get(el);
5149         
5150         if(!el || !el.dom){
5151             throw "Element.alignToXY with an element that doesn't exist";
5152         }
5153         
5154         o = o || [0,0];
5155         p = (!p || p == "?" ? "tl-bl?" : (!/-/.test(p) && p !== "" ? "tl-" + p : p || "tl-bl")).toLowerCase();       
5156                 
5157         var me = this,
5158                 d = me.dom,
5159                 a1,
5160                 a2,
5161                 x,
5162                 y,
5163                 //constrain the aligned el to viewport if necessary
5164                 w,
5165                 h,
5166                 r,
5167                 dw = Ext.lib.Dom.getViewWidth() -10, // 10px of margin for ie
5168                 dh = Ext.lib.Dom.getViewHeight()-10, // 10px of margin for ie
5169                 p1y,
5170                 p1x,            
5171                 p2y,
5172                 p2x,
5173                 swapY,
5174                 swapX,
5175                 doc = document,
5176                 docElement = doc.documentElement,
5177                 docBody = doc.body,
5178                 scrollX = (docElement.scrollLeft || docBody.scrollLeft || 0)+5,
5179                 scrollY = (docElement.scrollTop || docBody.scrollTop || 0)+5,
5180                 c = false, //constrain to viewport
5181                 p1 = "", 
5182                 p2 = "",
5183                 m = p.match(/^([a-z]+)-([a-z]+)(\?)?$/);
5184         
5185         if(!m){
5186            throw "Element.alignTo with an invalid alignment " + p;
5187         }
5188         
5189         p1 = m[1]; 
5190         p2 = m[2]; 
5191         c = !!m[3];
5192
5193         //Subtract the aligned el's internal xy from the target's offset xy
5194         //plus custom offset to get the aligned el's new offset xy
5195         a1 = me.getAnchorXY(p1, true);
5196         a2 = el.getAnchorXY(p2, false);
5197
5198         x = a2[0] - a1[0] + o[0];
5199         y = a2[1] - a1[1] + o[1];
5200
5201         if(c){    
5202                w = me.getWidth();
5203            h = me.getHeight();
5204            r = el.getRegion();       
5205            //If we are at a viewport boundary and the aligned el is anchored on a target border that is
5206            //perpendicular to the vp border, allow the aligned el to slide on that border,
5207            //otherwise swap the aligned el to the opposite border of the target.
5208            p1y = p1.charAt(0);
5209            p1x = p1.charAt(p1.length-1);
5210            p2y = p2.charAt(0);
5211            p2x = p2.charAt(p2.length-1);
5212            swapY = ((p1y=="t" && p2y=="b") || (p1y=="b" && p2y=="t"));
5213            swapX = ((p1x=="r" && p2x=="l") || (p1x=="l" && p2x=="r"));          
5214            
5215
5216            if (x + w > dw + scrollX) {
5217                 x = swapX ? r.left-w : dw+scrollX-w;
5218            }
5219            if (x < scrollX) {
5220                x = swapX ? r.right : scrollX;
5221            }
5222            if (y + h > dh + scrollY) {
5223                 y = swapY ? r.top-h : dh+scrollY-h;
5224             }
5225            if (y < scrollY){
5226                y = swapY ? r.bottom : scrollY;
5227            }
5228         }
5229         return [x,y];
5230     },
5231
5232     /**
5233      * Aligns this element with another element relative to the specified anchor points. If the other element is the
5234      * document it aligns it to the viewport.
5235      * The position parameter is optional, and can be specified in any one of the following formats:
5236      * <ul>
5237      *   <li><b>Blank</b>: Defaults to aligning the element's top-left corner to the target's bottom-left corner ("tl-bl").</li>
5238      *   <li><b>One anchor (deprecated)</b>: The passed anchor position is used as the target element's anchor point.
5239      *       The element being aligned will position its top-left corner (tl) to that point.  <i>This method has been
5240      *       deprecated in favor of the newer two anchor syntax below</i>.</li>
5241      *   <li><b>Two anchors</b>: If two values from the table below are passed separated by a dash, the first value is used as the
5242      *       element's anchor point, and the second value is used as the target's anchor point.</li>
5243      * </ul>
5244      * In addition to the anchor points, the position parameter also supports the "?" character.  If "?" is passed at the end of
5245      * the position string, the element will attempt to align as specified, but the position will be adjusted to constrain to
5246      * the viewport if necessary.  Note that the element being aligned might be swapped to align to a different position than
5247      * that specified in order to enforce the viewport constraints.
5248      * Following are all of the supported anchor positions:
5249 <pre>
5250 Value  Description
5251 -----  -----------------------------
5252 tl     The top left corner (default)
5253 t      The center of the top edge
5254 tr     The top right corner
5255 l      The center of the left edge
5256 c      In the center of the element
5257 r      The center of the right edge
5258 bl     The bottom left corner
5259 b      The center of the bottom edge
5260 br     The bottom right corner
5261 </pre>
5262 Example Usage:
5263 <pre><code>
5264 // align el to other-el using the default positioning ("tl-bl", non-constrained)
5265 el.alignTo("other-el");
5266
5267 // align the top left corner of el with the top right corner of other-el (constrained to viewport)
5268 el.alignTo("other-el", "tr?");
5269
5270 // align the bottom right corner of el with the center left edge of other-el
5271 el.alignTo("other-el", "br-l?");
5272
5273 // align the center of el with the bottom left corner of other-el and
5274 // adjust the x position by -6 pixels (and the y position by 0)
5275 el.alignTo("other-el", "c-bl", [-6, 0]);
5276 </code></pre>
5277      * @param {Mixed} element The element to align to.
5278      * @param {String} position (optional, defaults to "tl-bl?") The position to align to.
5279      * @param {Array} offsets (optional) Offset the positioning by [x, y]
5280      * @param {Boolean/Object} animate (optional) true for the default animation or a standard Element animation config object
5281      * @return {Ext.Element} this
5282      */
5283     alignTo : function(element, position, offsets, animate){
5284             var me = this;
5285         return me.setXY(me.getAlignToXY(element, position, offsets),
5286                                 me.preanim && !!animate ? me.preanim(arguments, 3) : false);
5287     },
5288     
5289     // private ==>  used outside of core
5290     adjustForConstraints : function(xy, parent, offsets){
5291         return this.getConstrainToXY(parent || document, false, offsets, xy) ||  xy;
5292     },
5293
5294     // private ==>  used outside of core
5295     getConstrainToXY : function(el, local, offsets, proposedXY){   
5296             var os = {top:0, left:0, bottom:0, right: 0};
5297
5298         return function(el, local, offsets, proposedXY){
5299             el = Ext.get(el);
5300             offsets = offsets ? Ext.applyIf(offsets, os) : os;
5301
5302             var vw, vh, vx = 0, vy = 0;
5303             if(el.dom == document.body || el.dom == document){
5304                 vw =Ext.lib.Dom.getViewWidth();
5305                 vh = Ext.lib.Dom.getViewHeight();
5306             }else{
5307                 vw = el.dom.clientWidth;
5308                 vh = el.dom.clientHeight;
5309                 if(!local){
5310                     var vxy = el.getXY();
5311                     vx = vxy[0];
5312                     vy = vxy[1];
5313                 }
5314             }
5315
5316             var s = el.getScroll();
5317
5318             vx += offsets.left + s.left;
5319             vy += offsets.top + s.top;
5320
5321             vw -= offsets.right;
5322             vh -= offsets.bottom;
5323
5324             var vr = vx+vw;
5325             var vb = vy+vh;
5326
5327             var xy = proposedXY || (!local ? this.getXY() : [this.getLeft(true), this.getTop(true)]);
5328             var x = xy[0], y = xy[1];
5329             var w = this.dom.offsetWidth, h = this.dom.offsetHeight;
5330
5331             // only move it if it needs it
5332             var moved = false;
5333
5334             // first validate right/bottom
5335             if((x + w) > vr){
5336                 x = vr - w;
5337                 moved = true;
5338             }
5339             if((y + h) > vb){
5340                 y = vb - h;
5341                 moved = true;
5342             }
5343             // then make sure top/left isn't negative
5344             if(x < vx){
5345                 x = vx;
5346                 moved = true;
5347             }
5348             if(y < vy){
5349                 y = vy;
5350                 moved = true;
5351             }
5352             return moved ? [x, y] : false;
5353         };
5354     }(),
5355             
5356             
5357                 
5358 //         el = Ext.get(el);
5359 //         offsets = Ext.applyIf(offsets || {}, {top : 0, left : 0, bottom : 0, right : 0});
5360
5361 //         var  me = this,
5362 //              doc = document,
5363 //              s = el.getScroll(),
5364 //              vxy = el.getXY(),
5365 //              vx = offsets.left + s.left, 
5366 //              vy = offsets.top + s.top,               
5367 //              vw = -offsets.right, 
5368 //              vh = -offsets.bottom, 
5369 //              vr,
5370 //              vb,
5371 //              xy = proposedXY || (!local ? me.getXY() : [me.getLeft(true), me.getTop(true)]),
5372 //              x = xy[0],
5373 //              y = xy[1],
5374 //              w = me.dom.offsetWidth, h = me.dom.offsetHeight,
5375 //              moved = false; // only move it if it needs it
5376 //       
5377 //              
5378 //         if(el.dom == doc.body || el.dom == doc){
5379 //             vw += Ext.lib.Dom.getViewWidth();
5380 //             vh += Ext.lib.Dom.getViewHeight();
5381 //         }else{
5382 //             vw += el.dom.clientWidth;
5383 //             vh += el.dom.clientHeight;
5384 //             if(!local){                    
5385 //                 vx += vxy[0];
5386 //                 vy += vxy[1];
5387 //             }
5388 //         }
5389
5390 //         // first validate right/bottom
5391 //         if(x + w > vx + vw){
5392 //             x = vx + vw - w;
5393 //             moved = true;
5394 //         }
5395 //         if(y + h > vy + vh){
5396 //             y = vy + vh - h;
5397 //             moved = true;
5398 //         }
5399 //         // then make sure top/left isn't negative
5400 //         if(x < vx){
5401 //             x = vx;
5402 //             moved = true;
5403 //         }
5404 //         if(y < vy){
5405 //             y = vy;
5406 //             moved = true;
5407 //         }
5408 //         return moved ? [x, y] : false;
5409 //    },
5410     
5411     /**
5412     * Calculates the x, y to center this element on the screen
5413     * @return {Array} The x, y values [x, y]
5414     */
5415     getCenterXY : function(){
5416         return this.getAlignToXY(document, 'c-c');
5417     },
5418
5419     /**
5420     * Centers the Element in either the viewport, or another Element.
5421     * @param {Mixed} centerIn (optional) The element in which to center the element.
5422     */
5423     center : function(centerIn){
5424         return this.alignTo(centerIn || document, 'c-c');        
5425     }    
5426 });
5427 /**
5428  * @class Ext.Element
5429  */
5430 Ext.Element.addMethods(function(){
5431         var PARENTNODE = 'parentNode',
5432                 NEXTSIBLING = 'nextSibling',
5433                 PREVIOUSSIBLING = 'previousSibling',
5434                 DQ = Ext.DomQuery,
5435                 GET = Ext.get;
5436         
5437         return {
5438                 /**
5439              * Looks at this node and then at parent nodes for a match of the passed simple selector (e.g. div.some-class or span:first-child)
5440              * @param {String} selector The simple selector to test
5441              * @param {Number/Mixed} maxDepth (optional) The max depth to search as a number or element (defaults to 50 || document.body)
5442              * @param {Boolean} returnEl (optional) True to return a Ext.Element object instead of DOM node
5443              * @return {HTMLElement} The matching DOM node (or null if no match was found)
5444              */
5445             findParent : function(simpleSelector, maxDepth, returnEl){
5446                 var p = this.dom,
5447                         b = document.body, 
5448                         depth = 0,                      
5449                         stopEl;         
5450             if(Ext.isGecko && Object.prototype.toString.call(p) == '[object XULElement]') {
5451                 return null;
5452             }
5453                 maxDepth = maxDepth || 50;
5454                 if (isNaN(maxDepth)) {
5455                     stopEl = Ext.getDom(maxDepth);
5456                     maxDepth = Number.MAX_VALUE;
5457                 }
5458                 while(p && p.nodeType == 1 && depth < maxDepth && p != b && p != stopEl){
5459                     if(DQ.is(p, simpleSelector)){
5460                         return returnEl ? GET(p) : p;
5461                     }
5462                     depth++;
5463                     p = p.parentNode;
5464                 }
5465                 return null;
5466             },
5467         
5468             /**
5469              * Looks at parent nodes for a match of the passed simple selector (e.g. div.some-class or span:first-child)
5470              * @param {String} selector The simple selector to test
5471              * @param {Number/Mixed} maxDepth (optional) The max depth to
5472                     search as a number or element (defaults to 10 || document.body)
5473              * @param {Boolean} returnEl (optional) True to return a Ext.Element object instead of DOM node
5474              * @return {HTMLElement} The matching DOM node (or null if no match was found)
5475              */
5476             findParentNode : function(simpleSelector, maxDepth, returnEl){
5477                 var p = Ext.fly(this.dom.parentNode, '_internal');
5478                 return p ? p.findParent(simpleSelector, maxDepth, returnEl) : null;
5479             },
5480         
5481             /**
5482              * Walks up the dom looking for a parent node that matches the passed simple selector (e.g. div.some-class or span:first-child).
5483              * This is a shortcut for findParentNode() that always returns an Ext.Element.
5484              * @param {String} selector The simple selector to test
5485              * @param {Number/Mixed} maxDepth (optional) The max depth to
5486                     search as a number or element (defaults to 10 || document.body)
5487              * @return {Ext.Element} The matching DOM node (or null if no match was found)
5488              */
5489             up : function(simpleSelector, maxDepth){
5490                 return this.findParentNode(simpleSelector, maxDepth, true);
5491             },
5492         
5493             /**
5494              * Creates a {@link Ext.CompositeElement} for child nodes based on the passed CSS selector (the selector should not contain an id).
5495              * @param {String} selector The CSS selector
5496              * @return {CompositeElement/CompositeElementLite} The composite element
5497              */
5498             select : function(selector){
5499                 return Ext.Element.select(selector, this.dom);
5500             },
5501         
5502             /**
5503              * Selects child nodes based on the passed CSS selector (the selector should not contain an id).
5504              * @param {String} selector The CSS selector
5505              * @return {Array} An array of the matched nodes
5506              */
5507             query : function(selector){
5508                 return DQ.select(selector, this.dom);
5509             },
5510         
5511             /**
5512              * Selects a single child at any depth below this element based on the passed CSS selector (the selector should not contain an id).
5513              * @param {String} selector The CSS selector
5514              * @param {Boolean} returnDom (optional) True to return the DOM node instead of Ext.Element (defaults to false)
5515              * @return {HTMLElement/Ext.Element} The child Ext.Element (or DOM node if returnDom = true)
5516              */
5517             child : function(selector, returnDom){
5518                 var n = DQ.selectNode(selector, this.dom);
5519                 return returnDom ? n : GET(n);
5520             },
5521         
5522             /**
5523              * Selects a single *direct* child based on the passed CSS selector (the selector should not contain an id).
5524              * @param {String} selector The CSS selector
5525              * @param {Boolean} returnDom (optional) True to return the DOM node instead of Ext.Element (defaults to false)
5526              * @return {HTMLElement/Ext.Element} The child Ext.Element (or DOM node if returnDom = true)
5527              */
5528             down : function(selector, returnDom){
5529                 var n = DQ.selectNode(" > " + selector, this.dom);
5530                 return returnDom ? n : GET(n);
5531             },
5532         
5533                  /**
5534              * Gets the parent node for this element, optionally chaining up trying to match a selector
5535              * @param {String} selector (optional) Find a parent node that matches the passed simple selector
5536              * @param {Boolean} returnDom (optional) True to return a raw dom node instead of an Ext.Element
5537              * @return {Ext.Element/HTMLElement} The parent node or null
5538                  */
5539             parent : function(selector, returnDom){
5540                 return this.matchNode(PARENTNODE, PARENTNODE, selector, returnDom);
5541             },
5542         
5543              /**
5544              * Gets the next sibling, skipping text nodes
5545              * @param {String} selector (optional) Find the next sibling that matches the passed simple selector
5546              * @param {Boolean} returnDom (optional) True to return a raw dom node instead of an Ext.Element
5547              * @return {Ext.Element/HTMLElement} The next sibling or null
5548                  */
5549             next : function(selector, returnDom){
5550                 return this.matchNode(NEXTSIBLING, NEXTSIBLING, selector, returnDom);
5551             },
5552         
5553             /**
5554              * Gets the previous sibling, skipping text nodes
5555              * @param {String} selector (optional) Find the previous sibling that matches the passed simple selector
5556              * @param {Boolean} returnDom (optional) True to return a raw dom node instead of an Ext.Element
5557              * @return {Ext.Element/HTMLElement} The previous sibling or null
5558                  */
5559             prev : function(selector, returnDom){
5560                 return this.matchNode(PREVIOUSSIBLING, PREVIOUSSIBLING, selector, returnDom);
5561             },
5562         
5563         
5564             /**
5565              * Gets the first child, skipping text nodes
5566              * @param {String} selector (optional) Find the next sibling that matches the passed simple selector
5567              * @param {Boolean} returnDom (optional) True to return a raw dom node instead of an Ext.Element
5568              * @return {Ext.Element/HTMLElement} The first child or null
5569                  */
5570             first : function(selector, returnDom){
5571                 return this.matchNode(NEXTSIBLING, 'firstChild', selector, returnDom);
5572             },
5573         
5574             /**
5575              * Gets the last child, skipping text nodes
5576              * @param {String} selector (optional) Find the previous sibling that matches the passed simple selector
5577              * @param {Boolean} returnDom (optional) True to return a raw dom node instead of an Ext.Element
5578              * @return {Ext.Element/HTMLElement} The last child or null
5579                  */
5580             last : function(selector, returnDom){
5581                 return this.matchNode(PREVIOUSSIBLING, 'lastChild', selector, returnDom);
5582             },
5583             
5584             matchNode : function(dir, start, selector, returnDom){
5585                 var n = this.dom[start];
5586                 while(n){
5587                     if(n.nodeType == 1 && (!selector || DQ.is(n, selector))){
5588                         return !returnDom ? GET(n) : n;
5589                     }
5590                     n = n[dir];
5591                 }
5592                 return null;
5593             }   
5594     }
5595 }());/**
5596  * @class Ext.Element
5597  */
5598 Ext.Element.addMethods({
5599     /**
5600      * Creates a {@link Ext.CompositeElement} for child nodes based on the passed CSS selector (the selector should not contain an id).
5601      * @param {String} selector The CSS selector
5602      * @param {Boolean} unique (optional) True to create a unique Ext.Element for each child (defaults to false, which creates a single shared flyweight object)
5603      * @return {CompositeElement/CompositeElementLite} The composite element
5604      */
5605     select : function(selector, unique){
5606         return Ext.Element.select(selector, unique, this.dom);
5607     }
5608 });/**
5609  * @class Ext.Element
5610  */
5611 Ext.Element.addMethods(
5612 function() {
5613         var GETDOM = Ext.getDom,
5614                 GET = Ext.get,
5615                 DH = Ext.DomHelper;
5616         
5617         return {
5618             /**
5619              * Appends the passed element(s) to this element
5620              * @param {String/HTMLElement/Array/Element/CompositeElement} el
5621              * @return {Ext.Element} this
5622              */
5623             appendChild: function(el){        
5624                 return GET(el).appendTo(this);        
5625             },
5626         
5627             /**
5628              * Appends this element to the passed element
5629              * @param {Mixed} el The new parent element
5630              * @return {Ext.Element} this
5631              */
5632             appendTo: function(el){        
5633                 GETDOM(el).appendChild(this.dom);        
5634                 return this;
5635             },
5636         
5637             /**
5638              * Inserts this element before the passed element in the DOM
5639              * @param {Mixed} el The element before which this element will be inserted
5640              * @return {Ext.Element} this
5641              */
5642             insertBefore: function(el){                   
5643                 (el = GETDOM(el)).parentNode.insertBefore(this.dom, el);
5644                 return this;
5645             },
5646         
5647             /**
5648              * Inserts this element after the passed element in the DOM
5649              * @param {Mixed} el The element to insert after
5650              * @return {Ext.Element} this
5651              */
5652             insertAfter: function(el){
5653                 (el = GETDOM(el)).parentNode.insertBefore(this.dom, el.nextSibling);
5654                 return this;
5655             },
5656         
5657             /**
5658              * Inserts (or creates) an element (or DomHelper config) as the first child of this element
5659              * @param {Mixed/Object} el The id or element to insert or a DomHelper config to create and insert
5660              * @return {Ext.Element} The new child
5661              */
5662             insertFirst: function(el, returnDom){
5663             el = el || {};
5664             if(el.nodeType || el.dom || typeof el == 'string'){ // element
5665                 el = GETDOM(el);
5666                 this.dom.insertBefore(el, this.dom.firstChild);
5667                 return !returnDom ? GET(el) : el;
5668             }else{ // dh config
5669                 return this.createChild(el, this.dom.firstChild, returnDom);
5670             }
5671         },
5672         
5673             /**
5674              * Replaces the passed element with this element
5675              * @param {Mixed} el The element to replace
5676              * @return {Ext.Element} this
5677              */
5678             replace: function(el){
5679                 el = GET(el);
5680                 this.insertBefore(el);
5681                 el.remove();
5682                 return this;
5683             },
5684         
5685             /**
5686              * Replaces this element with the passed element
5687              * @param {Mixed/Object} el The new element or a DomHelper config of an element to create
5688              * @return {Ext.Element} this
5689              */
5690             replaceWith: function(el){
5691                     var me = this;
5692                 
5693             if(el.nodeType || el.dom || typeof el == 'string'){
5694                 el = GETDOM(el);
5695                 me.dom.parentNode.insertBefore(el, me.dom);
5696             }else{
5697                 el = DH.insertBefore(me.dom, el);
5698             }
5699                 
5700                 delete Ext.elCache[me.id];
5701                 Ext.removeNode(me.dom);      
5702                 me.id = Ext.id(me.dom = el);
5703                 Ext.Element.addToCache(me.isFlyweight ? new Ext.Element(me.dom) : me);     
5704             return me;
5705             },
5706             
5707                 /**
5708                  * Creates the passed DomHelper config and appends it to this element or optionally inserts it before the passed child element.
5709                  * @param {Object} config DomHelper element config object.  If no tag is specified (e.g., {tag:'input'}) then a div will be
5710                  * automatically generated with the specified attributes.
5711                  * @param {HTMLElement} insertBefore (optional) a child element of this element
5712                  * @param {Boolean} returnDom (optional) true to return the dom node instead of creating an Element
5713                  * @return {Ext.Element} The new child element
5714                  */
5715                 createChild: function(config, insertBefore, returnDom){
5716                     config = config || {tag:'div'};
5717                     return insertBefore ? 
5718                            DH.insertBefore(insertBefore, config, returnDom !== true) :  
5719                            DH[!this.dom.firstChild ? 'overwrite' : 'append'](this.dom, config,  returnDom !== true);
5720                 },
5721                 
5722                 /**
5723                  * Creates and wraps this element with another element
5724                  * @param {Object} config (optional) DomHelper element config object for the wrapper element or null for an empty div
5725                  * @param {Boolean} returnDom (optional) True to return the raw DOM element instead of Ext.Element
5726                  * @return {HTMLElement/Element} The newly created wrapper element
5727                  */
5728                 wrap: function(config, returnDom){        
5729                     var newEl = DH.insertBefore(this.dom, config || {tag: "div"}, !returnDom);
5730                     newEl.dom ? newEl.dom.appendChild(this.dom) : newEl.appendChild(this.dom);
5731                     return newEl;
5732                 },
5733                 
5734                 /**
5735                  * Inserts an html fragment into this element
5736                  * @param {String} where Where to insert the html in relation to this element - beforeBegin, afterBegin, beforeEnd, afterEnd.
5737                  * @param {String} html The HTML fragment
5738                  * @param {Boolean} returnEl (optional) True to return an Ext.Element (defaults to false)
5739                  * @return {HTMLElement/Ext.Element} The inserted node (or nearest related if more than 1 inserted)
5740                  */
5741                 insertHtml : function(where, html, returnEl){
5742                     var el = DH.insertHtml(where, this.dom, html);
5743                     return returnEl ? Ext.get(el) : el;
5744                 }
5745         }
5746 }());/**
5747  * @class Ext.Element
5748  */
5749 Ext.apply(Ext.Element.prototype, function() {
5750         var GETDOM = Ext.getDom,
5751                 GET = Ext.get,
5752                 DH = Ext.DomHelper;
5753         
5754         return {        
5755                 /**
5756              * Inserts (or creates) the passed element (or DomHelper config) as a sibling of this element
5757              * @param {Mixed/Object/Array} el The id, element to insert or a DomHelper config to create and insert *or* an array of any of those.
5758              * @param {String} where (optional) 'before' or 'after' defaults to before
5759              * @param {Boolean} returnDom (optional) True to return the raw DOM element instead of Ext.Element
5760              * @return {Ext.Element} The inserted Element. If an array is passed, the last inserted element is returned.
5761              */
5762             insertSibling: function(el, where, returnDom){
5763                 var me = this,
5764                         rt,
5765                 isAfter = (where || 'before').toLowerCase() == 'after',
5766                 insertEl;
5767                         
5768                 if(Ext.isArray(el)){
5769                 insertEl = me;
5770                     Ext.each(el, function(e) {
5771                             rt = Ext.fly(insertEl, '_internal').insertSibling(e, where, returnDom);
5772                     if(isAfter){
5773                         insertEl = rt;
5774                     }
5775                     });
5776                     return rt;
5777                 }
5778                         
5779                 el = el || {};
5780                 
5781             if(el.nodeType || el.dom){
5782                 rt = me.dom.parentNode.insertBefore(GETDOM(el), isAfter ? me.dom.nextSibling : me.dom);
5783                 if (!returnDom) {
5784                     rt = GET(rt);
5785                 }
5786             }else{
5787                 if (isAfter && !me.dom.nextSibling) {
5788                     rt = DH.append(me.dom.parentNode, el, !returnDom);
5789                 } else {                    
5790                     rt = DH[isAfter ? 'insertAfter' : 'insertBefore'](me.dom, el, !returnDom);
5791                 }
5792             }
5793                 return rt;
5794             }
5795     };
5796 }());/**
5797  * @class Ext.Element
5798  */
5799 Ext.Element.addMethods(function(){
5800     // local style camelizing for speed
5801     var propCache = {},
5802         camelRe = /(-[a-z])/gi,
5803         classReCache = {},
5804         view = document.defaultView,
5805         propFloat = Ext.isIE ? 'styleFloat' : 'cssFloat',
5806         opacityRe = /alpha\(opacity=(.*)\)/i,
5807         trimRe = /^\s+|\s+$/g,
5808         spacesRe = /\s+/,
5809         wordsRe = /\w/g,
5810         EL = Ext.Element,
5811         PADDING = "padding",
5812         MARGIN = "margin",
5813         BORDER = "border",
5814         LEFT = "-left",
5815         RIGHT = "-right",
5816         TOP = "-top",
5817         BOTTOM = "-bottom",
5818         WIDTH = "-width",
5819         MATH = Math,
5820         HIDDEN = 'hidden',
5821         ISCLIPPED = 'isClipped',
5822         OVERFLOW = 'overflow',
5823         OVERFLOWX = 'overflow-x',
5824         OVERFLOWY = 'overflow-y',
5825         ORIGINALCLIP = 'originalClip',
5826         // special markup used throughout Ext when box wrapping elements
5827         borders = {l: BORDER + LEFT + WIDTH, r: BORDER + RIGHT + WIDTH, t: BORDER + TOP + WIDTH, b: BORDER + BOTTOM + WIDTH},
5828         paddings = {l: PADDING + LEFT, r: PADDING + RIGHT, t: PADDING + TOP, b: PADDING + BOTTOM},
5829         margins = {l: MARGIN + LEFT, r: MARGIN + RIGHT, t: MARGIN + TOP, b: MARGIN + BOTTOM},
5830         data = Ext.Element.data;
5831
5832
5833     // private
5834     function camelFn(m, a) {
5835         return a.charAt(1).toUpperCase();
5836     }
5837
5838     function chkCache(prop) {
5839         return propCache[prop] || (propCache[prop] = prop == 'float' ? propFloat : prop.replace(camelRe, camelFn));
5840     }
5841
5842     return {
5843         // private  ==> used by Fx
5844         adjustWidth : function(width) {
5845             var me = this;
5846             var isNum = (typeof width == "number");
5847             if(isNum && me.autoBoxAdjust && !me.isBorderBox()){
5848                width -= (me.getBorderWidth("lr") + me.getPadding("lr"));
5849             }
5850             return (isNum && width < 0) ? 0 : width;
5851         },
5852
5853         // private   ==> used by Fx
5854         adjustHeight : function(height) {
5855             var me = this;
5856             var isNum = (typeof height == "number");
5857             if(isNum && me.autoBoxAdjust && !me.isBorderBox()){
5858                height -= (me.getBorderWidth("tb") + me.getPadding("tb"));
5859             }
5860             return (isNum && height < 0) ? 0 : height;
5861         },
5862
5863
5864         /**
5865          * Adds one or more CSS classes to the element. Duplicate classes are automatically filtered out.
5866          * @param {String/Array} className The CSS class to add, or an array of classes
5867          * @return {Ext.Element} this
5868          */
5869         addClass : function(className){
5870             var me = this,
5871                 i,
5872                 len,
5873                 v,
5874                 cls = [];
5875             // Separate case is for speed
5876             if (!Ext.isArray(className)) {
5877                 if (typeof className == 'string' && !this.hasClass(className)) {
5878                     me.dom.className += " " + className;
5879                 }
5880             }
5881             else {
5882                 for (i = 0, len = className.length; i < len; i++) {
5883                     v = className[i];
5884                     if (typeof v == 'string' && (' ' + me.dom.className + ' ').indexOf(' ' + v + ' ') == -1) {
5885                         cls.push(v);
5886                     }
5887                 }
5888                 if (cls.length) {
5889                     me.dom.className += " " + cls.join(" ");
5890                 }
5891             }
5892             return me;
5893         },
5894
5895         /**
5896          * Removes one or more CSS classes from the element.
5897          * @param {String/Array} className The CSS class to remove, or an array of classes
5898          * @return {Ext.Element} this
5899          */
5900         removeClass : function(className){
5901             var me = this,
5902                 i,
5903                 idx,
5904                 len,
5905                 cls,
5906                 elClasses;
5907             if (!Ext.isArray(className)){
5908                 className = [className];
5909             }
5910             if (me.dom && me.dom.className) {
5911                 elClasses = me.dom.className.replace(trimRe, '').split(spacesRe);
5912                 for (i = 0, len = className.length; i < len; i++) {
5913                     cls = className[i];
5914                     if (typeof cls == 'string') {
5915                         cls = cls.replace(trimRe, '');
5916                         idx = elClasses.indexOf(cls);
5917                         if (idx != -1) {
5918                             elClasses.splice(idx, 1);
5919                         }
5920                     }
5921                 }
5922                 me.dom.className = elClasses.join(" ");
5923             }
5924             return me;
5925         },
5926
5927         /**
5928          * Adds one or more CSS classes to this element and removes the same class(es) from all siblings.
5929          * @param {String/Array} className The CSS class to add, or an array of classes
5930          * @return {Ext.Element} this
5931          */
5932         radioClass : function(className){
5933             var cn = this.dom.parentNode.childNodes,
5934                 v,
5935                 i,
5936                 len;
5937             className = Ext.isArray(className) ? className : [className];
5938             for (i = 0, len = cn.length; i < len; i++) {
5939                 v = cn[i];
5940                 if (v && v.nodeType == 1) {
5941                     Ext.fly(v, '_internal').removeClass(className);
5942                 }
5943             };
5944             return this.addClass(className);
5945         },
5946
5947         /**
5948          * Toggles the specified CSS class on this element (removes it if it already exists, otherwise adds it).
5949          * @param {String} className The CSS class to toggle
5950          * @return {Ext.Element} this
5951          */
5952         toggleClass : function(className){
5953             return this.hasClass(className) ? this.removeClass(className) : this.addClass(className);
5954         },
5955
5956         /**
5957          * Checks if the specified CSS class exists on this element's DOM node.
5958          * @param {String} className The CSS class to check for
5959          * @return {Boolean} True if the class exists, else false
5960          */
5961         hasClass : function(className){
5962             return className && (' '+this.dom.className+' ').indexOf(' '+className+' ') != -1;
5963         },
5964
5965         /**
5966          * Replaces a CSS class on the element with another.  If the old name does not exist, the new name will simply be added.
5967          * @param {String} oldClassName The CSS class to replace
5968          * @param {String} newClassName The replacement CSS class
5969          * @return {Ext.Element} this
5970          */
5971         replaceClass : function(oldClassName, newClassName){
5972             return this.removeClass(oldClassName).addClass(newClassName);
5973         },
5974
5975         isStyle : function(style, val) {
5976             return this.getStyle(style) == val;
5977         },
5978
5979         /**
5980          * Normalizes currentStyle and computedStyle.
5981          * @param {String} property The style property whose value is returned.
5982          * @return {String} The current value of the style property for this element.
5983          */
5984         getStyle : function(){
5985             return view && view.getComputedStyle ?
5986                 function(prop){
5987                     var el = this.dom,
5988                         v,
5989                         cs,
5990                         out,
5991                         display,
5992                         wk = Ext.isWebKit,
5993                         display;
5994
5995                     if(el == document){
5996                         return null;
5997                     }
5998                     prop = chkCache(prop);
5999                     // Fix bug caused by this: https://bugs.webkit.org/show_bug.cgi?id=13343
6000                     if(wk && /marginRight/.test(prop)){
6001                         display = this.getStyle('display');
6002                         el.style.display = 'inline-block';
6003                     }
6004                     out = (v = el.style[prop]) ? v :
6005                            (cs = view.getComputedStyle(el, "")) ? cs[prop] : null;
6006
6007                     // Webkit returns rgb values for transparent.
6008                     if(wk){
6009                         if(out == 'rgba(0, 0, 0, 0)'){
6010                             out = 'transparent';
6011                         }else if(display){
6012                             el.style.display = display;
6013                         }
6014                     }
6015                     return out;
6016                 } :
6017                 function(prop){
6018                     var el = this.dom,
6019                         m,
6020                         cs;
6021
6022                     if(el == document) return null;
6023                     if (prop == 'opacity') {
6024                         if (el.style.filter.match) {
6025                             if(m = el.style.filter.match(opacityRe)){
6026                                 var fv = parseFloat(m[1]);
6027                                 if(!isNaN(fv)){
6028                                     return fv ? fv / 100 : 0;
6029                                 }
6030                             }
6031                         }
6032                         return 1;
6033                     }
6034                     prop = chkCache(prop);
6035                     return el.style[prop] || ((cs = el.currentStyle) ? cs[prop] : null);
6036                 };
6037         }(),
6038
6039         /**
6040          * Return the CSS color for the specified CSS attribute. rgb, 3 digit (like #fff) and valid values
6041          * are convert to standard 6 digit hex color.
6042          * @param {String} attr The css attribute
6043          * @param {String} defaultValue The default value to use when a valid color isn't found
6044          * @param {String} prefix (optional) defaults to #. Use an empty string when working with
6045          * color anims.
6046          */
6047         getColor : function(attr, defaultValue, prefix){
6048             var v = this.getStyle(attr),
6049                 color = (typeof prefix != 'undefined') ? prefix : '#',
6050                 h;
6051
6052             if(!v || /transparent|inherit/.test(v)){
6053                 return defaultValue;
6054             }
6055             if(/^r/.test(v)){
6056                 Ext.each(v.slice(4, v.length -1).split(','), function(s){
6057                     h = parseInt(s, 10);
6058                     color += (h < 16 ? '0' : '') + h.toString(16);
6059                 });
6060             }else{
6061                 v = v.replace('#', '');
6062                 color += v.length == 3 ? v.replace(/^(\w)(\w)(\w)$/, '$1$1$2$2$3$3') : v;
6063             }
6064             return(color.length > 5 ? color.toLowerCase() : defaultValue);
6065         },
6066
6067         /**
6068          * Wrapper for setting style properties, also takes single object parameter of multiple styles.
6069          * @param {String/Object} property The style property to be set, or an object of multiple styles.
6070          * @param {String} value (optional) The value to apply to the given property, or null if an object was passed.
6071          * @return {Ext.Element} this
6072          */
6073         setStyle : function(prop, value){
6074             var tmp,
6075                 style,
6076                 camel;
6077             if (typeof prop != 'object') {
6078                 tmp = {};
6079                 tmp[prop] = value;
6080                 prop = tmp;
6081             }
6082             for (style in prop) {
6083                 value = prop[style];
6084                 style == 'opacity' ?
6085                     this.setOpacity(value) :
6086                     this.dom.style[chkCache(style)] = value;
6087             }
6088             return this;
6089         },
6090
6091         /**
6092          * Set the opacity of the element
6093          * @param {Float} opacity The new opacity. 0 = transparent, .5 = 50% visibile, 1 = fully visible, etc
6094          * @param {Boolean/Object} animate (optional) a standard Element animation config object or <tt>true</tt> for
6095          * the default animation (<tt>{duration: .35, easing: 'easeIn'}</tt>)
6096          * @return {Ext.Element} this
6097          */
6098          setOpacity : function(opacity, animate){
6099             var me = this,
6100                 s = me.dom.style;
6101
6102             if(!animate || !me.anim){
6103                 if(Ext.isIE){
6104                     var opac = opacity < 1 ? 'alpha(opacity=' + opacity * 100 + ')' : '',
6105                     val = s.filter.replace(opacityRe, '').replace(trimRe, '');
6106
6107                     s.zoom = 1;
6108                     s.filter = val + (val.length > 0 ? ' ' : '') + opac;
6109                 }else{
6110                     s.opacity = opacity;
6111                 }
6112             }else{
6113                 me.anim({opacity: {to: opacity}}, me.preanim(arguments, 1), null, .35, 'easeIn');
6114             }
6115             return me;
6116         },
6117
6118         /**
6119          * Clears any opacity settings from this element. Required in some cases for IE.
6120          * @return {Ext.Element} this
6121          */
6122         clearOpacity : function(){
6123             var style = this.dom.style;
6124             if(Ext.isIE){
6125                 if(!Ext.isEmpty(style.filter)){
6126                     style.filter = style.filter.replace(opacityRe, '').replace(trimRe, '');
6127                 }
6128             }else{
6129                 style.opacity = style['-moz-opacity'] = style['-khtml-opacity'] = '';
6130             }
6131             return this;
6132         },
6133
6134         /**
6135          * Returns the offset height of the element
6136          * @param {Boolean} contentHeight (optional) true to get the height minus borders and padding
6137          * @return {Number} The element's height
6138          */
6139         getHeight : function(contentHeight){
6140             var me = this,
6141                 dom = me.dom,
6142                 hidden = Ext.isIE && me.isStyle('display', 'none'),
6143                 h = MATH.max(dom.offsetHeight, hidden ? 0 : dom.clientHeight) || 0;
6144
6145             h = !contentHeight ? h : h - me.getBorderWidth("tb") - me.getPadding("tb");
6146             return h < 0 ? 0 : h;
6147         },
6148
6149         /**
6150          * Returns the offset width of the element
6151          * @param {Boolean} contentWidth (optional) true to get the width minus borders and padding
6152          * @return {Number} The element's width
6153          */
6154         getWidth : function(contentWidth){
6155             var me = this,
6156                 dom = me.dom,
6157                 hidden = Ext.isIE && me.isStyle('display', 'none'),
6158                 w = MATH.max(dom.offsetWidth, hidden ? 0 : dom.clientWidth) || 0;
6159             w = !contentWidth ? w : w - me.getBorderWidth("lr") - me.getPadding("lr");
6160             return w < 0 ? 0 : w;
6161         },
6162
6163         /**
6164          * Set the width of this Element.
6165          * @param {Mixed} width The new width. This may be one of:<div class="mdetail-params"><ul>
6166          * <li>A Number specifying the new width in this Element's {@link #defaultUnit}s (by default, pixels).</li>
6167          * <li>A String used to set the CSS width style. Animation may <b>not</b> be used.
6168          * </ul></div>
6169          * @param {Boolean/Object} animate (optional) true for the default animation or a standard Element animation config object
6170          * @return {Ext.Element} this
6171          */
6172         setWidth : function(width, animate){
6173             var me = this;
6174             width = me.adjustWidth(width);
6175             !animate || !me.anim ?
6176                 me.dom.style.width = me.addUnits(width) :
6177                 me.anim({width : {to : width}}, me.preanim(arguments, 1));
6178             return me;
6179         },
6180
6181         /**
6182          * Set the height of this Element.
6183          * <pre><code>
6184 // change the height to 200px and animate with default configuration
6185 Ext.fly('elementId').setHeight(200, true);
6186
6187 // change the height to 150px and animate with a custom configuration
6188 Ext.fly('elId').setHeight(150, {
6189     duration : .5, // animation will have a duration of .5 seconds
6190     // will change the content to "finished"
6191     callback: function(){ this.{@link #update}("finished"); }
6192 });
6193          * </code></pre>
6194          * @param {Mixed} height The new height. This may be one of:<div class="mdetail-params"><ul>
6195          * <li>A Number specifying the new height in this Element's {@link #defaultUnit}s (by default, pixels.)</li>
6196          * <li>A String used to set the CSS height style. Animation may <b>not</b> be used.</li>
6197          * </ul></div>
6198          * @param {Boolean/Object} animate (optional) true for the default animation or a standard Element animation config object
6199          * @return {Ext.Element} this
6200          */
6201          setHeight : function(height, animate){
6202             var me = this;
6203             height = me.adjustHeight(height);
6204             !animate || !me.anim ?
6205                 me.dom.style.height = me.addUnits(height) :
6206                 me.anim({height : {to : height}}, me.preanim(arguments, 1));
6207             return me;
6208         },
6209
6210         /**
6211          * Gets the width of the border(s) for the specified side(s)
6212          * @param {String} side Can be t, l, r, b or any combination of those to add multiple values. For example,
6213          * passing <tt>'lr'</tt> would get the border <b><u>l</u></b>eft width + the border <b><u>r</u></b>ight width.
6214          * @return {Number} The width of the sides passed added together
6215          */
6216         getBorderWidth : function(side){
6217             return this.addStyles(side, borders);
6218         },
6219
6220         /**
6221          * Gets the width of the padding(s) for the specified side(s)
6222          * @param {String} side Can be t, l, r, b or any combination of those to add multiple values. For example,
6223          * passing <tt>'lr'</tt> would get the padding <b><u>l</u></b>eft + the padding <b><u>r</u></b>ight.
6224          * @return {Number} The padding of the sides passed added together
6225          */
6226         getPadding : function(side){
6227             return this.addStyles(side, paddings);
6228         },
6229
6230         /**
6231          *  Store the current overflow setting and clip overflow on the element - use <tt>{@link #unclip}</tt> to remove
6232          * @return {Ext.Element} this
6233          */
6234         clip : function(){
6235             var me = this,
6236                 dom = me.dom;
6237
6238             if(!data(dom, ISCLIPPED)){
6239                 data(dom, ISCLIPPED, true);
6240                 data(dom, ORIGINALCLIP, {
6241                     o: me.getStyle(OVERFLOW),
6242                     x: me.getStyle(OVERFLOWX),
6243                     y: me.getStyle(OVERFLOWY)
6244                 });
6245                 me.setStyle(OVERFLOW, HIDDEN);
6246                 me.setStyle(OVERFLOWX, HIDDEN);
6247                 me.setStyle(OVERFLOWY, HIDDEN);
6248             }
6249             return me;
6250         },
6251
6252         /**
6253          *  Return clipping (overflow) to original clipping before <tt>{@link #clip}</tt> was called
6254          * @return {Ext.Element} this
6255          */
6256         unclip : function(){
6257             var me = this,
6258                 dom = me.dom;
6259
6260             if(data(dom, ISCLIPPED)){
6261                 data(dom, ISCLIPPED, false);
6262                 var o = data(dom, ORIGINALCLIP);
6263                 if(o.o){
6264                     me.setStyle(OVERFLOW, o.o);
6265                 }
6266                 if(o.x){
6267                     me.setStyle(OVERFLOWX, o.x);
6268                 }
6269                 if(o.y){
6270                     me.setStyle(OVERFLOWY, o.y);
6271                 }
6272             }
6273             return me;
6274         },
6275
6276         // private
6277         addStyles : function(sides, styles){
6278             var ttlSize = 0,
6279                 sidesArr = sides.match(wordsRe),
6280                 side,
6281                 size,
6282                 i,
6283                 len = sidesArr.length;
6284             for (i = 0; i < len; i++) {
6285                 side = sidesArr[i];
6286                 size = side && parseInt(this.getStyle(styles[side]), 10);
6287                 if (size) {
6288                     ttlSize += MATH.abs(size);
6289                 }
6290             }
6291             return ttlSize;
6292         },
6293
6294         margins : margins
6295     }
6296 }()
6297 );
6298 /**
6299  * @class Ext.Element
6300  */
6301
6302 // special markup used throughout Ext when box wrapping elements
6303 Ext.Element.boxMarkup = '<div class="{0}-tl"><div class="{0}-tr"><div class="{0}-tc"></div></div></div><div class="{0}-ml"><div class="{0}-mr"><div class="{0}-mc"></div></div></div><div class="{0}-bl"><div class="{0}-br"><div class="{0}-bc"></div></div></div>';
6304
6305 Ext.Element.addMethods(function(){
6306     var INTERNAL = "_internal",
6307         pxMatch = /(\d+\.?\d+)px/;
6308     return {
6309         /**
6310          * More flexible version of {@link #setStyle} for setting style properties.
6311          * @param {String/Object/Function} styles A style specification string, e.g. "width:100px", or object in the form {width:"100px"}, or
6312          * a function which returns such a specification.
6313          * @return {Ext.Element} this
6314          */
6315         applyStyles : function(style){
6316             Ext.DomHelper.applyStyles(this.dom, style);
6317             return this;
6318         },
6319
6320         /**
6321          * Returns an object with properties matching the styles requested.
6322          * For example, el.getStyles('color', 'font-size', 'width') might return
6323          * {'color': '#FFFFFF', 'font-size': '13px', 'width': '100px'}.
6324          * @param {String} style1 A style name
6325          * @param {String} style2 A style name
6326          * @param {String} etc.
6327          * @return {Object} The style object
6328          */
6329         getStyles : function(){
6330             var ret = {};
6331             Ext.each(arguments, function(v) {
6332                ret[v] = this.getStyle(v);
6333             },
6334             this);
6335             return ret;
6336         },
6337
6338         // private  ==> used by ext full
6339         setOverflow : function(v){
6340             var dom = this.dom;
6341             if(v=='auto' && Ext.isMac && Ext.isGecko2){ // work around stupid FF 2.0/Mac scroll bar bug
6342                 dom.style.overflow = 'hidden';
6343                 (function(){dom.style.overflow = 'auto';}).defer(1);
6344             }else{
6345                 dom.style.overflow = v;
6346             }
6347         },
6348
6349        /**
6350         * <p>Wraps the specified element with a special 9 element markup/CSS block that renders by default as
6351         * a gray container with a gradient background, rounded corners and a 4-way shadow.</p>
6352         * <p>This special markup is used throughout Ext when box wrapping elements ({@link Ext.Button},
6353         * {@link Ext.Panel} when <tt>{@link Ext.Panel#frame frame=true}</tt>, {@link Ext.Window}).  The markup
6354         * is of this form:</p>
6355         * <pre><code>
6356     Ext.Element.boxMarkup =
6357     &#39;&lt;div class="{0}-tl">&lt;div class="{0}-tr">&lt;div class="{0}-tc">&lt;/div>&lt;/div>&lt;/div>
6358      &lt;div class="{0}-ml">&lt;div class="{0}-mr">&lt;div class="{0}-mc">&lt;/div>&lt;/div>&lt;/div>
6359      &lt;div class="{0}-bl">&lt;div class="{0}-br">&lt;div class="{0}-bc">&lt;/div>&lt;/div>&lt;/div>&#39;;
6360         * </code></pre>
6361         * <p>Example usage:</p>
6362         * <pre><code>
6363     // Basic box wrap
6364     Ext.get("foo").boxWrap();
6365
6366     // You can also add a custom class and use CSS inheritance rules to customize the box look.
6367     // 'x-box-blue' is a built-in alternative -- look at the related CSS definitions as an example
6368     // for how to create a custom box wrap style.
6369     Ext.get("foo").boxWrap().addClass("x-box-blue");
6370         * </code></pre>
6371         * @param {String} class (optional) A base CSS class to apply to the containing wrapper element
6372         * (defaults to <tt>'x-box'</tt>). Note that there are a number of CSS rules that are dependent on
6373         * this name to make the overall effect work, so if you supply an alternate base class, make sure you
6374         * also supply all of the necessary rules.
6375         * @return {Ext.Element} The outermost wrapping element of the created box structure.
6376         */
6377         boxWrap : function(cls){
6378             cls = cls || 'x-box';
6379             var el = Ext.get(this.insertHtml("beforeBegin", "<div class='" + cls + "'>" + String.format(Ext.Element.boxMarkup, cls) + "</div>"));        //String.format('<div class="{0}">'+Ext.Element.boxMarkup+'</div>', cls)));
6380             Ext.DomQuery.selectNode('.' + cls + '-mc', el.dom).appendChild(this.dom);
6381             return el;
6382         },
6383
6384         /**
6385          * Set the size of this Element. If animation is true, both width and height will be animated concurrently.
6386          * @param {Mixed} width The new width. This may be one of:<div class="mdetail-params"><ul>
6387          * <li>A Number specifying the new width in this Element's {@link #defaultUnit}s (by default, pixels).</li>
6388          * <li>A String used to set the CSS width style. Animation may <b>not</b> be used.
6389          * <li>A size object in the format <code>{width: widthValue, height: heightValue}</code>.</li>
6390          * </ul></div>
6391          * @param {Mixed} height The new height. This may be one of:<div class="mdetail-params"><ul>
6392          * <li>A Number specifying the new height in this Element's {@link #defaultUnit}s (by default, pixels).</li>
6393          * <li>A String used to set the CSS height style. Animation may <b>not</b> be used.</li>
6394          * </ul></div>
6395          * @param {Boolean/Object} animate (optional) true for the default animation or a standard Element animation config object
6396          * @return {Ext.Element} this
6397          */
6398         setSize : function(width, height, animate){
6399             var me = this;
6400             if(typeof width == 'object'){ // in case of object from getSize()
6401                 height = width.height;
6402                 width = width.width;
6403             }
6404             width = me.adjustWidth(width);
6405             height = me.adjustHeight(height);
6406             if(!animate || !me.anim){
6407                 me.dom.style.width = me.addUnits(width);
6408                 me.dom.style.height = me.addUnits(height);
6409             }else{
6410                 me.anim({width: {to: width}, height: {to: height}}, me.preanim(arguments, 2));
6411             }
6412             return me;
6413         },
6414
6415         /**
6416          * Returns either the offsetHeight or the height of this element based on CSS height adjusted by padding or borders
6417          * when needed to simulate offsetHeight when offsets aren't available. This may not work on display:none elements
6418          * if a height has not been set using CSS.
6419          * @return {Number}
6420          */
6421         getComputedHeight : function(){
6422             var me = this,
6423                 h = Math.max(me.dom.offsetHeight, me.dom.clientHeight);
6424             if(!h){
6425                 h = parseFloat(me.getStyle('height')) || 0;
6426                 if(!me.isBorderBox()){
6427                     h += me.getFrameWidth('tb');
6428                 }
6429             }
6430             return h;
6431         },
6432
6433         /**
6434          * Returns either the offsetWidth or the width of this element based on CSS width adjusted by padding or borders
6435          * when needed to simulate offsetWidth when offsets aren't available. This may not work on display:none elements
6436          * if a width has not been set using CSS.
6437          * @return {Number}
6438          */
6439         getComputedWidth : function(){
6440             var w = Math.max(this.dom.offsetWidth, this.dom.clientWidth);
6441             if(!w){
6442                 w = parseFloat(this.getStyle('width')) || 0;
6443                 if(!this.isBorderBox()){
6444                     w += this.getFrameWidth('lr');
6445                 }
6446             }
6447             return w;
6448         },
6449
6450         /**
6451          * Returns the sum width of the padding and borders for the passed "sides". See getBorderWidth()
6452          for more information about the sides.
6453          * @param {String} sides
6454          * @return {Number}
6455          */
6456         getFrameWidth : function(sides, onlyContentBox){
6457             return onlyContentBox && this.isBorderBox() ? 0 : (this.getPadding(sides) + this.getBorderWidth(sides));
6458         },
6459
6460         /**
6461          * Sets up event handlers to add and remove a css class when the mouse is over this element
6462          * @param {String} className
6463          * @return {Ext.Element} this
6464          */
6465         addClassOnOver : function(className){
6466             this.hover(
6467                 function(){
6468                     Ext.fly(this, INTERNAL).addClass(className);
6469                 },
6470                 function(){
6471                     Ext.fly(this, INTERNAL).removeClass(className);
6472                 }
6473             );
6474             return this;
6475         },
6476
6477         /**
6478          * Sets up event handlers to add and remove a css class when this element has the focus
6479          * @param {String} className
6480          * @return {Ext.Element} this
6481          */
6482         addClassOnFocus : function(className){
6483             this.on("focus", function(){
6484                 Ext.fly(this, INTERNAL).addClass(className);
6485             }, this.dom);
6486             this.on("blur", function(){
6487                 Ext.fly(this, INTERNAL).removeClass(className);
6488             }, this.dom);
6489             return this;
6490         },
6491
6492         /**
6493          * Sets up event handlers to add and remove a css class when the mouse is down and then up on this element (a click effect)
6494          * @param {String} className
6495          * @return {Ext.Element} this
6496          */
6497         addClassOnClick : function(className){
6498             var dom = this.dom;
6499             this.on("mousedown", function(){
6500                 Ext.fly(dom, INTERNAL).addClass(className);
6501                 var d = Ext.getDoc(),
6502                     fn = function(){
6503                         Ext.fly(dom, INTERNAL).removeClass(className);
6504                         d.removeListener("mouseup", fn);
6505                     };
6506                 d.on("mouseup", fn);
6507             });
6508             return this;
6509         },
6510
6511         /**
6512          * <p>Returns the dimensions of the element available to lay content out in.<p>
6513          * <p>If the element (or any ancestor element) has CSS style <code>display : none</code>, the dimensions will be zero.</p>
6514          * example:<pre><code>
6515         var vpSize = Ext.getBody().getViewSize();
6516
6517         // all Windows created afterwards will have a default value of 90% height and 95% width
6518         Ext.Window.override({
6519             width: vpSize.width * 0.9,
6520             height: vpSize.height * 0.95
6521         });
6522         // To handle window resizing you would have to hook onto onWindowResize.
6523         * </code></pre>
6524         *
6525         * getViewSize utilizes clientHeight/clientWidth which excludes sizing of scrollbars.
6526         * To obtain the size including scrollbars, use getStyleSize
6527         *
6528         * Sizing of the document body is handled at the adapter level which handles special cases for IE and strict modes, etc.
6529         */
6530
6531         getViewSize : function(){
6532             var doc = document,
6533                 d = this.dom,
6534                 isDoc = (d == doc || d == doc.body);
6535
6536             // If the body, use Ext.lib.Dom
6537             if (isDoc) {
6538                 var extdom = Ext.lib.Dom;
6539                 return {
6540                     width : extdom.getViewWidth(),
6541                     height : extdom.getViewHeight()
6542                 };
6543
6544             // Else use clientHeight/clientWidth
6545             } else {
6546                 return {
6547                     width : d.clientWidth,
6548                     height : d.clientHeight
6549                 }
6550             }
6551         },
6552
6553         /**
6554         * <p>Returns the dimensions of the element available to lay content out in.<p>
6555         *
6556         * getStyleSize utilizes prefers style sizing if present, otherwise it chooses the larger of offsetHeight/clientHeight and offsetWidth/clientWidth.
6557         * To obtain the size excluding scrollbars, use getViewSize
6558         *
6559         * Sizing of the document body is handled at the adapter level which handles special cases for IE and strict modes, etc.
6560         */
6561
6562         getStyleSize : function(){
6563             var me = this,
6564                 w, h,
6565                 doc = document,
6566                 d = this.dom,
6567                 isDoc = (d == doc || d == doc.body),
6568                 s = d.style;
6569
6570             // If the body, use Ext.lib.Dom
6571             if (isDoc) {
6572                 var extdom = Ext.lib.Dom;
6573                 return {
6574                     width : extdom.getViewWidth(),
6575                     height : extdom.getViewHeight()
6576                 }
6577             }
6578             // Use Styles if they are set
6579             if(s.width && s.width != 'auto'){
6580                 w = parseFloat(s.width);
6581                 if(me.isBorderBox()){
6582                    w -= me.getFrameWidth('lr');
6583                 }
6584             }
6585             // Use Styles if they are set
6586             if(s.height && s.height != 'auto'){
6587                 h = parseFloat(s.height);
6588                 if(me.isBorderBox()){
6589                    h -= me.getFrameWidth('tb');
6590                 }
6591             }
6592             // Use getWidth/getHeight if style not set.
6593             return {width: w || me.getWidth(true), height: h || me.getHeight(true)};
6594         },
6595
6596         /**
6597          * Returns the size of the element.
6598          * @param {Boolean} contentSize (optional) true to get the width/size minus borders and padding
6599          * @return {Object} An object containing the element's size {width: (element width), height: (element height)}
6600          */
6601         getSize : function(contentSize){
6602             return {width: this.getWidth(contentSize), height: this.getHeight(contentSize)};
6603         },
6604
6605         /**
6606          * Forces the browser to repaint this element
6607          * @return {Ext.Element} this
6608          */
6609         repaint : function(){
6610             var dom = this.dom;
6611             this.addClass("x-repaint");
6612             setTimeout(function(){
6613                 Ext.fly(dom).removeClass("x-repaint");
6614             }, 1);
6615             return this;
6616         },
6617
6618         /**
6619          * Disables text selection for this element (normalized across browsers)
6620          * @return {Ext.Element} this
6621          */
6622         unselectable : function(){
6623             this.dom.unselectable = "on";
6624             return this.swallowEvent("selectstart", true).
6625                         applyStyles("-moz-user-select:none;-khtml-user-select:none;").
6626                         addClass("x-unselectable");
6627         },
6628
6629         /**
6630          * Returns an object with properties top, left, right and bottom representing the margins of this element unless sides is passed,
6631          * then it returns the calculated width of the sides (see getPadding)
6632          * @param {String} sides (optional) Any combination of l, r, t, b to get the sum of those sides
6633          * @return {Object/Number}
6634          */
6635         getMargins : function(side){
6636             var me = this,
6637                 key,
6638                 hash = {t:"top", l:"left", r:"right", b: "bottom"},
6639                 o = {};
6640
6641             if (!side) {
6642                 for (key in me.margins){
6643                     o[hash[key]] = parseFloat(me.getStyle(me.margins[key])) || 0;
6644                 }
6645                 return o;
6646             } else {
6647                 return me.addStyles.call(me, side, me.margins);
6648             }
6649         }
6650     };
6651 }());
6652 /**
6653  * @class Ext.Element
6654  */
6655 (function(){
6656 var D = Ext.lib.Dom,
6657         LEFT = "left",
6658         RIGHT = "right",
6659         TOP = "top",
6660         BOTTOM = "bottom",
6661         POSITION = "position",
6662         STATIC = "static",
6663         RELATIVE = "relative",
6664         AUTO = "auto",
6665         ZINDEX = "z-index";
6666
6667 Ext.Element.addMethods({
6668         /**
6669       * Gets the current X position of the element based on page coordinates.  Element must be part of the DOM tree to have page coordinates (display:none or elements not appended return false).
6670       * @return {Number} The X position of the element
6671       */
6672     getX : function(){
6673         return D.getX(this.dom);
6674     },
6675
6676     /**
6677       * Gets the current Y position of the element based on page coordinates.  Element must be part of the DOM tree to have page coordinates (display:none or elements not appended return false).
6678       * @return {Number} The Y position of the element
6679       */
6680     getY : function(){
6681         return D.getY(this.dom);
6682     },
6683
6684     /**
6685       * Gets the current position of the element based on page coordinates.  Element must be part of the DOM tree to have page coordinates (display:none or elements not appended return false).
6686       * @return {Array} The XY position of the element
6687       */
6688     getXY : function(){
6689         return D.getXY(this.dom);
6690     },
6691
6692     /**
6693       * Returns the offsets of this element from the passed element. Both element must be part of the DOM tree and not have display:none to have page coordinates.
6694       * @param {Mixed} element The element to get the offsets from.
6695       * @return {Array} The XY page offsets (e.g. [100, -200])
6696       */
6697     getOffsetsTo : function(el){
6698         var o = this.getXY(),
6699                 e = Ext.fly(el, '_internal').getXY();
6700         return [o[0]-e[0],o[1]-e[1]];
6701     },
6702
6703     /**
6704      * Sets the X position of the element based on page coordinates.  Element must be part of the DOM tree to have page coordinates (display:none or elements not appended return false).
6705      * @param {Number} The X position of the element
6706      * @param {Boolean/Object} animate (optional) True for the default animation, or a standard Element animation config object
6707      * @return {Ext.Element} this
6708      */
6709     setX : function(x, animate){            
6710             return this.setXY([x, this.getY()], this.animTest(arguments, animate, 1));
6711     },
6712
6713     /**
6714      * Sets the Y position of the element based on page coordinates.  Element must be part of the DOM tree to have page coordinates (display:none or elements not appended return false).
6715      * @param {Number} The Y position of the element
6716      * @param {Boolean/Object} animate (optional) True for the default animation, or a standard Element animation config object
6717      * @return {Ext.Element} this
6718      */
6719     setY : function(y, animate){            
6720             return this.setXY([this.getX(), y], this.animTest(arguments, animate, 1));
6721     },
6722
6723     /**
6724      * Sets the element's left position directly using CSS style (instead of {@link #setX}).
6725      * @param {String} left The left CSS property value
6726      * @return {Ext.Element} this
6727      */
6728     setLeft : function(left){
6729         this.setStyle(LEFT, this.addUnits(left));
6730         return this;
6731     },
6732
6733     /**
6734      * Sets the element's top position directly using CSS style (instead of {@link #setY}).
6735      * @param {String} top The top CSS property value
6736      * @return {Ext.Element} this
6737      */
6738     setTop : function(top){
6739         this.setStyle(TOP, this.addUnits(top));
6740         return this;
6741     },
6742
6743     /**
6744      * Sets the element's CSS right style.
6745      * @param {String} right The right CSS property value
6746      * @return {Ext.Element} this
6747      */
6748     setRight : function(right){
6749         this.setStyle(RIGHT, this.addUnits(right));
6750         return this;
6751     },
6752
6753     /**
6754      * Sets the element's CSS bottom style.
6755      * @param {String} bottom The bottom CSS property value
6756      * @return {Ext.Element} this
6757      */
6758     setBottom : function(bottom){
6759         this.setStyle(BOTTOM, this.addUnits(bottom));
6760         return this;
6761     },
6762
6763     /**
6764      * Sets the position of the element in page coordinates, regardless of how the element is positioned.
6765      * The element must be part of the DOM tree to have page coordinates (display:none or elements not appended return false).
6766      * @param {Array} pos Contains X & Y [x, y] values for new position (coordinates are page-based)
6767      * @param {Boolean/Object} animate (optional) True for the default animation, or a standard Element animation config object
6768      * @return {Ext.Element} this
6769      */
6770     setXY : function(pos, animate){
6771             var me = this;
6772         if(!animate || !me.anim){
6773             D.setXY(me.dom, pos);
6774         }else{
6775             me.anim({points: {to: pos}}, me.preanim(arguments, 1), 'motion');
6776         }
6777         return me;
6778     },
6779
6780     /**
6781      * Sets the position of the element in page coordinates, regardless of how the element is positioned.
6782      * The element must be part of the DOM tree to have page coordinates (display:none or elements not appended return false).
6783      * @param {Number} x X value for new position (coordinates are page-based)
6784      * @param {Number} y Y value for new position (coordinates are page-based)
6785      * @param {Boolean/Object} animate (optional) True for the default animation, or a standard Element animation config object
6786      * @return {Ext.Element} this
6787      */
6788     setLocation : function(x, y, animate){
6789         return this.setXY([x, y], this.animTest(arguments, animate, 2));
6790     },
6791
6792     /**
6793      * Sets the position of the element in page coordinates, regardless of how the element is positioned.
6794      * The element must be part of the DOM tree to have page coordinates (display:none or elements not appended return false).
6795      * @param {Number} x X value for new position (coordinates are page-based)
6796      * @param {Number} y Y value for new position (coordinates are page-based)
6797      * @param {Boolean/Object} animate (optional) True for the default animation, or a standard Element animation config object
6798      * @return {Ext.Element} this
6799      */
6800     moveTo : function(x, y, animate){
6801         return this.setXY([x, y], this.animTest(arguments, animate, 2));        
6802     },    
6803     
6804     /**
6805      * Gets the left X coordinate
6806      * @param {Boolean} local True to get the local css position instead of page coordinate
6807      * @return {Number}
6808      */
6809     getLeft : function(local){
6810             return !local ? this.getX() : parseInt(this.getStyle(LEFT), 10) || 0;
6811     },
6812
6813     /**
6814      * Gets the right X coordinate of the element (element X position + element width)
6815      * @param {Boolean} local True to get the local css position instead of page coordinate
6816      * @return {Number}
6817      */
6818     getRight : function(local){
6819             var me = this;
6820             return !local ? me.getX() + me.getWidth() : (me.getLeft(true) + me.getWidth()) || 0;
6821     },
6822
6823     /**
6824      * Gets the top Y coordinate
6825      * @param {Boolean} local True to get the local css position instead of page coordinate
6826      * @return {Number}
6827      */
6828     getTop : function(local) {
6829             return !local ? this.getY() : parseInt(this.getStyle(TOP), 10) || 0;
6830     },
6831
6832     /**
6833      * Gets the bottom Y coordinate of the element (element Y position + element height)
6834      * @param {Boolean} local True to get the local css position instead of page coordinate
6835      * @return {Number}
6836      */
6837     getBottom : function(local){
6838             var me = this;
6839             return !local ? me.getY() + me.getHeight() : (me.getTop(true) + me.getHeight()) || 0;
6840     },
6841
6842     /**
6843     * Initializes positioning on this element. If a desired position is not passed, it will make the
6844     * the element positioned relative IF it is not already positioned.
6845     * @param {String} pos (optional) Positioning to use "relative", "absolute" or "fixed"
6846     * @param {Number} zIndex (optional) The zIndex to apply
6847     * @param {Number} x (optional) Set the page X position
6848     * @param {Number} y (optional) Set the page Y position
6849     */
6850     position : function(pos, zIndex, x, y){
6851             var me = this;
6852             
6853         if(!pos && me.isStyle(POSITION, STATIC)){           
6854             me.setStyle(POSITION, RELATIVE);           
6855         } else if(pos) {
6856             me.setStyle(POSITION, pos);
6857         }
6858         if(zIndex){
6859             me.setStyle(ZINDEX, zIndex);
6860         }
6861         if(x || y) me.setXY([x || false, y || false]);
6862     },
6863
6864     /**
6865     * Clear positioning back to the default when the document was loaded
6866     * @param {String} value (optional) The value to use for the left,right,top,bottom, defaults to '' (empty string). You could use 'auto'.
6867     * @return {Ext.Element} this
6868      */
6869     clearPositioning : function(value){
6870         value = value || '';
6871         this.setStyle({
6872             left : value,
6873             right : value,
6874             top : value,
6875             bottom : value,
6876             "z-index" : "",
6877             position : STATIC
6878         });
6879         return this;
6880     },
6881
6882     /**
6883     * Gets an object with all CSS positioning properties. Useful along with setPostioning to get
6884     * snapshot before performing an update and then restoring the element.
6885     * @return {Object}
6886     */
6887     getPositioning : function(){
6888         var l = this.getStyle(LEFT);
6889         var t = this.getStyle(TOP);
6890         return {
6891             "position" : this.getStyle(POSITION),
6892             "left" : l,
6893             "right" : l ? "" : this.getStyle(RIGHT),
6894             "top" : t,
6895             "bottom" : t ? "" : this.getStyle(BOTTOM),
6896             "z-index" : this.getStyle(ZINDEX)
6897         };
6898     },
6899     
6900     /**
6901     * Set positioning with an object returned by getPositioning().
6902     * @param {Object} posCfg
6903     * @return {Ext.Element} this
6904      */
6905     setPositioning : function(pc){
6906             var me = this,
6907                 style = me.dom.style;
6908                 
6909         me.setStyle(pc);
6910         
6911         if(pc.right == AUTO){
6912             style.right = "";
6913         }
6914         if(pc.bottom == AUTO){
6915             style.bottom = "";
6916         }
6917         
6918         return me;
6919     },    
6920         
6921     /**
6922      * Translates the passed page coordinates into left/top css values for this element
6923      * @param {Number/Array} x The page x or an array containing [x, y]
6924      * @param {Number} y (optional) The page y, required if x is not an array
6925      * @return {Object} An object with left and top properties. e.g. {left: (value), top: (value)}
6926      */
6927     translatePoints : function(x, y){                
6928             y = isNaN(x[1]) ? y : x[1];
6929         x = isNaN(x[0]) ? x : x[0];
6930         var me = this,
6931                 relative = me.isStyle(POSITION, RELATIVE),
6932                 o = me.getXY(),
6933                 l = parseInt(me.getStyle(LEFT), 10),
6934                 t = parseInt(me.getStyle(TOP), 10);
6935         
6936         l = !isNaN(l) ? l : (relative ? 0 : me.dom.offsetLeft);
6937         t = !isNaN(t) ? t : (relative ? 0 : me.dom.offsetTop);        
6938
6939         return {left: (x - o[0] + l), top: (y - o[1] + t)}; 
6940     },
6941     
6942     animTest : function(args, animate, i) {
6943         return !!animate && this.preanim ? this.preanim(args, i) : false;
6944     }
6945 });
6946 })();/**
6947  * @class Ext.Element
6948  */
6949 Ext.Element.addMethods({
6950     /**
6951      * Sets the element's box. Use getBox() on another element to get a box obj. If animate is true then width, height, x and y will be animated concurrently.
6952      * @param {Object} box The box to fill {x, y, width, height}
6953      * @param {Boolean} adjust (optional) Whether to adjust for box-model issues automatically
6954      * @param {Boolean/Object} animate (optional) true for the default animation or a standard Element animation config object
6955      * @return {Ext.Element} this
6956      */
6957     setBox : function(box, adjust, animate){
6958         var me = this,
6959                 w = box.width, 
6960                 h = box.height;
6961         if((adjust && !me.autoBoxAdjust) && !me.isBorderBox()){
6962            w -= (me.getBorderWidth("lr") + me.getPadding("lr"));
6963            h -= (me.getBorderWidth("tb") + me.getPadding("tb"));
6964         }
6965         me.setBounds(box.x, box.y, w, h, me.animTest.call(me, arguments, animate, 2));
6966         return me;
6967     },
6968
6969     /**
6970      * Return an object defining the area of this Element which can be passed to {@link #setBox} to
6971      * set another Element's size/location to match this element.
6972      * @param {Boolean} contentBox (optional) If true a box for the content of the element is returned.
6973      * @param {Boolean} local (optional) If true the element's left and top are returned instead of page x/y.
6974      * @return {Object} box An object in the format<pre><code>
6975 {
6976     x: &lt;Element's X position>,
6977     y: &lt;Element's Y position>,
6978     width: &lt;Element's width>,
6979     height: &lt;Element's height>,
6980     bottom: &lt;Element's lower bound>,
6981     right: &lt;Element's rightmost bound>
6982 }
6983 </code></pre>
6984      * The returned object may also be addressed as an Array where index 0 contains the X position
6985      * and index 1 contains the Y position. So the result may also be used for {@link #setXY}
6986      */
6987         getBox : function(contentBox, local) {      
6988             var me = this,
6989                 xy,
6990                 left,
6991                 top,
6992                 getBorderWidth = me.getBorderWidth,
6993                 getPadding = me.getPadding, 
6994                 l,
6995                 r,
6996                 t,
6997                 b;
6998         if(!local){
6999             xy = me.getXY();
7000         }else{
7001             left = parseInt(me.getStyle("left"), 10) || 0;
7002             top = parseInt(me.getStyle("top"), 10) || 0;
7003             xy = [left, top];
7004         }
7005         var el = me.dom, w = el.offsetWidth, h = el.offsetHeight, bx;
7006         if(!contentBox){
7007             bx = {x: xy[0], y: xy[1], 0: xy[0], 1: xy[1], width: w, height: h};
7008         }else{
7009             l = getBorderWidth.call(me, "l") + getPadding.call(me, "l");
7010             r = getBorderWidth.call(me, "r") + getPadding.call(me, "r");
7011             t = getBorderWidth.call(me, "t") + getPadding.call(me, "t");
7012             b = getBorderWidth.call(me, "b") + getPadding.call(me, "b");
7013             bx = {x: xy[0]+l, y: xy[1]+t, 0: xy[0]+l, 1: xy[1]+t, width: w-(l+r), height: h-(t+b)};
7014         }
7015         bx.right = bx.x + bx.width;
7016         bx.bottom = bx.y + bx.height;
7017         return bx;
7018         },
7019         
7020     /**
7021      * Move this element relative to its current position.
7022      * @param {String} direction Possible values are: "l" (or "left"), "r" (or "right"), "t" (or "top", or "up"), "b" (or "bottom", or "down").
7023      * @param {Number} distance How far to move the element in pixels
7024      * @param {Boolean/Object} animate (optional) true for the default animation or a standard Element animation config object
7025      * @return {Ext.Element} this
7026      */
7027      move : function(direction, distance, animate){
7028         var me = this,          
7029                 xy = me.getXY(),
7030                 x = xy[0],
7031                 y = xy[1],              
7032                 left = [x - distance, y],
7033                 right = [x + distance, y],
7034                 top = [x, y - distance],
7035                 bottom = [x, y + distance],
7036                 hash = {
7037                         l :     left,
7038                         left : left,
7039                         r : right,
7040                         right : right,
7041                         t : top,
7042                         top : top,
7043                         up : top,
7044                         b : bottom, 
7045                         bottom : bottom,
7046                         down : bottom                           
7047                 };
7048         
7049             direction = direction.toLowerCase();    
7050             me.moveTo(hash[direction][0], hash[direction][1], me.animTest.call(me, arguments, animate, 2));
7051     },
7052     
7053     /**
7054      * Quick set left and top adding default units
7055      * @param {String} left The left CSS property value
7056      * @param {String} top The top CSS property value
7057      * @return {Ext.Element} this
7058      */
7059      setLeftTop : function(left, top){
7060             var me = this,
7061                 style = me.dom.style;
7062         style.left = me.addUnits(left);
7063         style.top = me.addUnits(top);
7064         return me;
7065     },
7066     
7067     /**
7068      * Returns the region of the given element.
7069      * The element must be part of the DOM tree to have a region (display:none or elements not appended return false).
7070      * @return {Region} A Ext.lib.Region containing "top, left, bottom, right" member data.
7071      */
7072     getRegion : function(){
7073         return Ext.lib.Dom.getRegion(this.dom);
7074     },
7075     
7076     /**
7077      * Sets the element's position and size in one shot. If animation is true then width, height, x and y will be animated concurrently.
7078      * @param {Number} x X value for new position (coordinates are page-based)
7079      * @param {Number} y Y value for new position (coordinates are page-based)
7080      * @param {Mixed} width The new width. This may be one of:<div class="mdetail-params"><ul>
7081      * <li>A Number specifying the new width in this Element's {@link #defaultUnit}s (by default, pixels)</li>
7082      * <li>A String used to set the CSS width style. Animation may <b>not</b> be used.
7083      * </ul></div>
7084      * @param {Mixed} height The new height. This may be one of:<div class="mdetail-params"><ul>
7085      * <li>A Number specifying the new height in this Element's {@link #defaultUnit}s (by default, pixels)</li>
7086      * <li>A String used to set the CSS height style. Animation may <b>not</b> be used.</li>
7087      * </ul></div>
7088      * @param {Boolean/Object} animate (optional) true for the default animation or a standard Element animation config object
7089      * @return {Ext.Element} this
7090      */
7091     setBounds : function(x, y, width, height, animate){
7092             var me = this;
7093         if (!animate || !me.anim) {
7094             me.setSize(width, height);
7095             me.setLocation(x, y);
7096         } else {
7097             me.anim({points: {to: [x, y]}, 
7098                          width: {to: me.adjustWidth(width)}, 
7099                          height: {to: me.adjustHeight(height)}},
7100                      me.preanim(arguments, 4), 
7101                      'motion');
7102         }
7103         return me;
7104     },
7105
7106     /**
7107      * Sets the element's position and size the specified region. If animation is true then width, height, x and y will be animated concurrently.
7108      * @param {Ext.lib.Region} region The region to fill
7109      * @param {Boolean/Object} animate (optional) true for the default animation or a standard Element animation config object
7110      * @return {Ext.Element} this
7111      */
7112     setRegion : function(region, animate) {
7113         return this.setBounds(region.left, region.top, region.right-region.left, region.bottom-region.top, this.animTest.call(this, arguments, animate, 1));
7114     }
7115 });/**
7116  * @class Ext.Element
7117  */
7118 Ext.Element.addMethods({
7119     /**
7120      * Returns true if this element is scrollable.
7121      * @return {Boolean}
7122      */
7123     isScrollable : function(){
7124         var dom = this.dom;
7125         return dom.scrollHeight > dom.clientHeight || dom.scrollWidth > dom.clientWidth;
7126     },
7127
7128     /**
7129      * Scrolls this element the specified scroll point. It does NOT do bounds checking so if you scroll to a weird value it will try to do it. For auto bounds checking, use scroll().
7130      * @param {String} side Either "left" for scrollLeft values or "top" for scrollTop values.
7131      * @param {Number} value The new scroll value.
7132      * @return {Element} this
7133      */
7134     scrollTo : function(side, value){
7135         this.dom["scroll" + (/top/i.test(side) ? "Top" : "Left")] = value;
7136         return this;
7137     },
7138
7139     /**
7140      * Returns the current scroll position of the element.
7141      * @return {Object} An object containing the scroll position in the format {left: (scrollLeft), top: (scrollTop)}
7142      */
7143     getScroll : function(){
7144         var d = this.dom, 
7145             doc = document,
7146             body = doc.body,
7147             docElement = doc.documentElement,
7148             l,
7149             t,
7150             ret;
7151
7152         if(d == doc || d == body){
7153             if(Ext.isIE && Ext.isStrict){
7154                 l = docElement.scrollLeft; 
7155                 t = docElement.scrollTop;
7156             }else{
7157                 l = window.pageXOffset;
7158                 t = window.pageYOffset;
7159             }
7160             ret = {left: l || (body ? body.scrollLeft : 0), top: t || (body ? body.scrollTop : 0)};
7161         }else{
7162             ret = {left: d.scrollLeft, top: d.scrollTop};
7163         }
7164         return ret;
7165     }
7166 });/**
7167  * @class Ext.Element
7168  */
7169 Ext.Element.addMethods({
7170     /**
7171      * Scrolls this element the specified scroll point. It does NOT do bounds checking so if you scroll to a weird value it will try to do it. For auto bounds checking, use scroll().
7172      * @param {String} side Either "left" for scrollLeft values or "top" for scrollTop values.
7173      * @param {Number} value The new scroll value
7174      * @param {Boolean/Object} animate (optional) true for the default animation or a standard Element animation config object
7175      * @return {Element} this
7176      */
7177     scrollTo : function(side, value, animate){
7178         var top = /top/i.test(side), //check if we're scrolling top or left
7179                 me = this,
7180                 dom = me.dom,
7181             prop;
7182         if (!animate || !me.anim) {
7183             prop = 'scroll' + (top ? 'Top' : 'Left'), // just setting the value, so grab the direction
7184             dom[prop] = value;
7185         }else{
7186             prop = 'scroll' + (top ? 'Left' : 'Top'), // if scrolling top, we need to grab scrollLeft, if left, scrollTop
7187             me.anim({scroll: {to: top ? [dom[prop], value] : [value, dom[prop]]}},
7188                          me.preanim(arguments, 2), 'scroll');
7189         }
7190         return me;
7191     },
7192     
7193     /**
7194      * Scrolls this element into view within the passed container.
7195      * @param {Mixed} container (optional) The container element to scroll (defaults to document.body).  Should be a
7196      * string (id), dom node, or Ext.Element.
7197      * @param {Boolean} hscroll (optional) False to disable horizontal scroll (defaults to true)
7198      * @return {Ext.Element} this
7199      */
7200     scrollIntoView : function(container, hscroll){
7201         var c = Ext.getDom(container) || Ext.getBody().dom,
7202                 el = this.dom,
7203                 o = this.getOffsetsTo(c),
7204             l = o[0] + c.scrollLeft,
7205             t = o[1] + c.scrollTop,
7206             b = t + el.offsetHeight,
7207             r = l + el.offsetWidth,
7208                 ch = c.clientHeight,
7209                 ct = parseInt(c.scrollTop, 10),
7210                 cl = parseInt(c.scrollLeft, 10),
7211                 cb = ct + ch,
7212                 cr = cl + c.clientWidth;
7213
7214         if (el.offsetHeight > ch || t < ct) {
7215                 c.scrollTop = t;
7216         } else if (b > cb){
7217             c.scrollTop = b-ch;
7218         }
7219         c.scrollTop = c.scrollTop; // corrects IE, other browsers will ignore
7220
7221         if(hscroll !== false){
7222                         if(el.offsetWidth > c.clientWidth || l < cl){
7223                 c.scrollLeft = l;
7224             }else if(r > cr){
7225                 c.scrollLeft = r - c.clientWidth;
7226             }
7227             c.scrollLeft = c.scrollLeft;
7228         }
7229         return this;
7230     },
7231
7232     // private
7233     scrollChildIntoView : function(child, hscroll){
7234         Ext.fly(child, '_scrollChildIntoView').scrollIntoView(this, hscroll);
7235     },
7236     
7237     /**
7238      * Scrolls this element the specified direction. Does bounds checking to make sure the scroll is
7239      * within this element's scrollable range.
7240      * @param {String} direction Possible values are: "l" (or "left"), "r" (or "right"), "t" (or "top", or "up"), "b" (or "bottom", or "down").
7241      * @param {Number} distance How far to scroll the element in pixels
7242      * @param {Boolean/Object} animate (optional) true for the default animation or a standard Element animation config object
7243      * @return {Boolean} Returns true if a scroll was triggered or false if the element
7244      * was scrolled as far as it could go.
7245      */
7246      scroll : function(direction, distance, animate){
7247          if(!this.isScrollable()){
7248              return;
7249          }
7250          var el = this.dom,
7251             l = el.scrollLeft, t = el.scrollTop,
7252             w = el.scrollWidth, h = el.scrollHeight,
7253             cw = el.clientWidth, ch = el.clientHeight,
7254             scrolled = false, v,
7255             hash = {
7256                 l: Math.min(l + distance, w-cw),
7257                 r: v = Math.max(l - distance, 0),
7258                 t: Math.max(t - distance, 0),
7259                 b: Math.min(t + distance, h-ch)
7260             };
7261             hash.d = hash.b;
7262             hash.u = hash.t;
7263             
7264          direction = direction.substr(0, 1);
7265          if((v = hash[direction]) > -1){
7266             scrolled = true;
7267             this.scrollTo(direction == 'l' || direction == 'r' ? 'left' : 'top', v, this.preanim(arguments, 2));
7268          }
7269          return scrolled;
7270     }
7271 });/**
7272  * @class Ext.Element
7273  */
7274 /**
7275  * Visibility mode constant for use with {@link #setVisibilityMode}. Use visibility to hide element
7276  * @static
7277  * @type Number
7278  */
7279 Ext.Element.VISIBILITY = 1;
7280 /**
7281  * Visibility mode constant for use with {@link #setVisibilityMode}. Use display to hide element
7282  * @static
7283  * @type Number
7284  */
7285 Ext.Element.DISPLAY = 2;
7286
7287 Ext.Element.addMethods(function(){
7288     var VISIBILITY = "visibility",
7289         DISPLAY = "display",
7290         HIDDEN = "hidden",
7291         OFFSETS = "offsets",
7292         NONE = "none",
7293         ORIGINALDISPLAY = 'originalDisplay',
7294         VISMODE = 'visibilityMode',
7295         ELDISPLAY = Ext.Element.DISPLAY,
7296         data = Ext.Element.data,
7297         getDisplay = function(dom){
7298             var d = data(dom, ORIGINALDISPLAY);
7299             if(d === undefined){
7300                 data(dom, ORIGINALDISPLAY, d = '');
7301             }
7302             return d;
7303         },
7304         getVisMode = function(dom){
7305             var m = data(dom, VISMODE);
7306             if(m === undefined){
7307                 data(dom, VISMODE, m = 1);
7308             }
7309             return m;
7310         };
7311
7312     return {
7313         /**
7314          * The element's default display mode  (defaults to "")
7315          * @type String
7316          */
7317         originalDisplay : "",
7318         visibilityMode : 1,
7319
7320         /**
7321          * Sets the element's visibility mode. When setVisible() is called it
7322          * will use this to determine whether to set the visibility or the display property.
7323          * @param {Number} visMode Ext.Element.VISIBILITY or Ext.Element.DISPLAY
7324          * @return {Ext.Element} this
7325          */
7326         setVisibilityMode : function(visMode){
7327             data(this.dom, VISMODE, visMode);
7328             return this;
7329         },
7330
7331         /**
7332          * Perform custom animation on this element.
7333          * <div><ul class="mdetail-params">
7334          * <li><u>Animation Properties</u></li>
7335          *
7336          * <p>The Animation Control Object enables gradual transitions for any member of an
7337          * element's style object that takes a numeric value including but not limited to
7338          * these properties:</p><div><ul class="mdetail-params">
7339          * <li><tt>bottom, top, left, right</tt></li>
7340          * <li><tt>height, width</tt></li>
7341          * <li><tt>margin, padding</tt></li>
7342          * <li><tt>borderWidth</tt></li>
7343          * <li><tt>opacity</tt></li>
7344          * <li><tt>fontSize</tt></li>
7345          * <li><tt>lineHeight</tt></li>
7346          * </ul></div>
7347          *
7348          *
7349          * <li><u>Animation Property Attributes</u></li>
7350          *
7351          * <p>Each Animation Property is a config object with optional properties:</p>
7352          * <div><ul class="mdetail-params">
7353          * <li><tt>by</tt>*  : relative change - start at current value, change by this value</li>
7354          * <li><tt>from</tt> : ignore current value, start from this value</li>
7355          * <li><tt>to</tt>*  : start at current value, go to this value</li>
7356          * <li><tt>unit</tt> : any allowable unit specification</li>
7357          * <p>* do not specify both <tt>to</tt> and <tt>by</tt> for an animation property</p>
7358          * </ul></div>
7359          *
7360          * <li><u>Animation Types</u></li>
7361          *
7362          * <p>The supported animation types:</p><div><ul class="mdetail-params">
7363          * <li><tt>'run'</tt> : Default
7364          * <pre><code>
7365 var el = Ext.get('complexEl');
7366 el.animate(
7367     // animation control object
7368     {
7369         borderWidth: {to: 3, from: 0},
7370         opacity: {to: .3, from: 1},
7371         height: {to: 50, from: el.getHeight()},
7372         width: {to: 300, from: el.getWidth()},
7373         top  : {by: - 100, unit: 'px'},
7374     },
7375     0.35,      // animation duration
7376     null,      // callback
7377     'easeOut', // easing method
7378     'run'      // animation type ('run','color','motion','scroll')
7379 );
7380          * </code></pre>
7381          * </li>
7382          * <li><tt>'color'</tt>
7383          * <p>Animates transition of background, text, or border colors.</p>
7384          * <pre><code>
7385 el.animate(
7386     // animation control object
7387     {
7388         color: { to: '#06e' },
7389         backgroundColor: { to: '#e06' }
7390     },
7391     0.35,      // animation duration
7392     null,      // callback
7393     'easeOut', // easing method
7394     'color'    // animation type ('run','color','motion','scroll')
7395 );
7396          * </code></pre>
7397          * </li>
7398          *
7399          * <li><tt>'motion'</tt>
7400          * <p>Animates the motion of an element to/from specific points using optional bezier
7401          * way points during transit.</p>
7402          * <pre><code>
7403 el.animate(
7404     // animation control object
7405     {
7406         borderWidth: {to: 3, from: 0},
7407         opacity: {to: .3, from: 1},
7408         height: {to: 50, from: el.getHeight()},
7409         width: {to: 300, from: el.getWidth()},
7410         top  : {by: - 100, unit: 'px'},
7411         points: {
7412             to: [50, 100],  // go to this point
7413             control: [      // optional bezier way points
7414                 [ 600, 800],
7415                 [-100, 200]
7416             ]
7417         }
7418     },
7419     3000,      // animation duration (milliseconds!)
7420     null,      // callback
7421     'easeOut', // easing method
7422     'motion'   // animation type ('run','color','motion','scroll')
7423 );
7424          * </code></pre>
7425          * </li>
7426          * <li><tt>'scroll'</tt>
7427          * <p>Animate horizontal or vertical scrolling of an overflowing page element.</p>
7428          * <pre><code>
7429 el.animate(
7430     // animation control object
7431     {
7432         scroll: {to: [400, 300]}
7433     },
7434     0.35,      // animation duration
7435     null,      // callback
7436     'easeOut', // easing method
7437     'scroll'   // animation type ('run','color','motion','scroll')
7438 );
7439          * </code></pre>
7440          * </li>
7441          * </ul></div>
7442          *
7443          * </ul></div>
7444          *
7445          * @param {Object} args The animation control args
7446          * @param {Float} duration (optional) How long the animation lasts in seconds (defaults to <tt>.35</tt>)
7447          * @param {Function} onComplete (optional) Function to call when animation completes
7448          * @param {String} easing (optional) {@link Ext.Fx#easing} method to use (defaults to <tt>'easeOut'</tt>)
7449          * @param {String} animType (optional) <tt>'run'</tt> is the default. Can also be <tt>'color'</tt>,
7450          * <tt>'motion'</tt>, or <tt>'scroll'</tt>
7451          * @return {Ext.Element} this
7452          */
7453         animate : function(args, duration, onComplete, easing, animType){
7454             this.anim(args, {duration: duration, callback: onComplete, easing: easing}, animType);
7455             return this;
7456         },
7457
7458         /*
7459          * @private Internal animation call
7460          */
7461         anim : function(args, opt, animType, defaultDur, defaultEase, cb){
7462             animType = animType || 'run';
7463             opt = opt || {};
7464             var me = this,
7465                 anim = Ext.lib.Anim[animType](
7466                     me.dom,
7467                     args,
7468                     (opt.duration || defaultDur) || .35,
7469                     (opt.easing || defaultEase) || 'easeOut',
7470                     function(){
7471                         if(cb) cb.call(me);
7472                         if(opt.callback) opt.callback.call(opt.scope || me, me, opt);
7473                     },
7474                     me
7475                 );
7476             opt.anim = anim;
7477             return anim;
7478         },
7479
7480         // private legacy anim prep
7481         preanim : function(a, i){
7482             return !a[i] ? false : (typeof a[i] == 'object' ? a[i]: {duration: a[i+1], callback: a[i+2], easing: a[i+3]});
7483         },
7484
7485         /**
7486          * Checks whether the element is currently visible using both visibility and display properties.
7487          * @return {Boolean} True if the element is currently visible, else false
7488          */
7489         isVisible : function() {
7490             return !this.isStyle(VISIBILITY, HIDDEN) && !this.isStyle(DISPLAY, NONE);
7491         },
7492
7493         /**
7494          * Sets the visibility of the element (see details). If the visibilityMode is set to Element.DISPLAY, it will use
7495          * the display property to hide the element, otherwise it uses visibility. The default is to hide and show using the visibility property.
7496          * @param {Boolean} visible Whether the element is visible
7497          * @param {Boolean/Object} animate (optional) True for the default animation, or a standard Element animation config object
7498          * @return {Ext.Element} this
7499          */
7500          setVisible : function(visible, animate){
7501             var me = this, isDisplay, isVisible, isOffsets,
7502                 dom = me.dom;
7503
7504             // hideMode string override
7505             if (typeof animate == 'string'){
7506                 isDisplay = animate == DISPLAY;
7507                 isVisible = animate == VISIBILITY;
7508                 isOffsets = animate == OFFSETS;
7509                 animate = false;
7510             } else {
7511                 isDisplay = getVisMode(this.dom) == ELDISPLAY;
7512                 isVisible = !isDisplay;
7513             }
7514
7515             if (!animate || !me.anim) {
7516                 if (isDisplay){
7517                     me.setDisplayed(visible);
7518                 } else if (isOffsets){
7519                     if (!visible){
7520                         me.hideModeStyles = {
7521                             position: me.getStyle('position'),
7522                             top: me.getStyle('top'),
7523                             left: me.getStyle('left')
7524                         };
7525
7526                         me.applyStyles({position: 'absolute', top: '-10000px', left: '-10000px'});
7527                     } else {
7528                         me.applyStyles(me.hideModeStyles || {position: '', top: '', left: ''});
7529                     }
7530                 }else{
7531                     me.fixDisplay();
7532                     dom.style.visibility = visible ? "visible" : HIDDEN;
7533                 }
7534             }else{
7535                 // closure for composites
7536                 if (visible){
7537                     me.setOpacity(.01);
7538                     me.setVisible(true);
7539                 }
7540                 me.anim({opacity: { to: (visible?1:0) }},
7541                         me.preanim(arguments, 1),
7542                         null,
7543                         .35,
7544                         'easeIn',
7545                         function(){
7546                              if(!visible){
7547                                  dom.style[isDisplay ? DISPLAY : VISIBILITY] = (isDisplay) ? NONE : HIDDEN;
7548                                  Ext.fly(dom).setOpacity(1);
7549                              }
7550                         });
7551             }
7552             return me;
7553         },
7554
7555         /**
7556          * Toggles the element's visibility or display, depending on visibility mode.
7557          * @param {Boolean/Object} animate (optional) True for the default animation, or a standard Element animation config object
7558          * @return {Ext.Element} this
7559          */
7560         toggle : function(animate){
7561             var me = this;
7562             me.setVisible(!me.isVisible(), me.preanim(arguments, 0));
7563             return me;
7564         },
7565
7566         /**
7567          * Sets the CSS display property. Uses originalDisplay if the specified value is a boolean true.
7568          * @param {Mixed} value Boolean value to display the element using its default display, or a string to set the display directly.
7569          * @return {Ext.Element} this
7570          */
7571         setDisplayed : function(value) {
7572             if(typeof value == "boolean"){
7573                value = value ? getDisplay(this.dom) : NONE;
7574             }
7575             this.setStyle(DISPLAY, value);
7576             return this;
7577         },
7578
7579         // private
7580         fixDisplay : function(){
7581             var me = this;
7582             if(me.isStyle(DISPLAY, NONE)){
7583                 me.setStyle(VISIBILITY, HIDDEN);
7584                 me.setStyle(DISPLAY, getDisplay(this.dom)); // first try reverting to default
7585                 if(me.isStyle(DISPLAY, NONE)){ // if that fails, default to block
7586                     me.setStyle(DISPLAY, "block");
7587                 }
7588             }
7589         },
7590
7591         /**
7592          * Hide this element - Uses display mode to determine whether to use "display" or "visibility". See {@link #setVisible}.
7593          * @param {Boolean/Object} animate (optional) true for the default animation or a standard Element animation config object
7594          * @return {Ext.Element} this
7595          */
7596         hide : function(animate){
7597             // hideMode override
7598             if (typeof animate == 'string'){
7599                 this.setVisible(false, animate);
7600                 return this;
7601             }
7602             this.setVisible(false, this.preanim(arguments, 0));
7603             return this;
7604         },
7605
7606         /**
7607         * Show this element - Uses display mode to determine whether to use "display" or "visibility". See {@link #setVisible}.
7608         * @param {Boolean/Object} animate (optional) true for the default animation or a standard Element animation config object
7609          * @return {Ext.Element} this
7610          */
7611         show : function(animate){
7612             // hideMode override
7613             if (typeof animate == 'string'){
7614                 this.setVisible(true, animate);
7615                 return this;
7616             }
7617             this.setVisible(true, this.preanim(arguments, 0));
7618             return this;
7619         }
7620     };
7621 }());
7622 /**
7623  * @class Ext.Element
7624  */
7625 Ext.Element.addMethods(
7626 function(){
7627     var VISIBILITY = "visibility",
7628         DISPLAY = "display",
7629         HIDDEN = "hidden",
7630         NONE = "none",
7631             XMASKED = "x-masked",
7632                 XMASKEDRELATIVE = "x-masked-relative",
7633         data = Ext.Element.data;
7634
7635         return {
7636                 /**
7637              * Checks whether the element is currently visible using both visibility and display properties.
7638              * @param {Boolean} deep (optional) True to walk the dom and see if parent elements are hidden (defaults to false)
7639              * @return {Boolean} True if the element is currently visible, else false
7640              */
7641             isVisible : function(deep) {
7642                 var vis = !this.isStyle(VISIBILITY,HIDDEN) && !this.isStyle(DISPLAY,NONE),
7643                         p = this.dom.parentNode;
7644                 if(deep !== true || !vis){
7645                     return vis;
7646                 }
7647                 while(p && !/^body/i.test(p.tagName)){
7648                     if(!Ext.fly(p, '_isVisible').isVisible()){
7649                         return false;
7650                     }
7651                     p = p.parentNode;
7652                 }
7653                 return true;
7654             },
7655
7656             /**
7657              * Returns true if display is not "none"
7658              * @return {Boolean}
7659              */
7660             isDisplayed : function() {
7661                 return !this.isStyle(DISPLAY, NONE);
7662             },
7663
7664                 /**
7665              * Convenience method for setVisibilityMode(Element.DISPLAY)
7666              * @param {String} display (optional) What to set display to when visible
7667              * @return {Ext.Element} this
7668              */
7669             enableDisplayMode : function(display){
7670                 this.setVisibilityMode(Ext.Element.DISPLAY);
7671                 if(!Ext.isEmpty(display)){
7672                 data(this.dom, 'originalDisplay', display);
7673             }
7674                 return this;
7675             },
7676
7677                 /**
7678              * Puts a mask over this element to disable user interaction. Requires core.css.
7679              * This method can only be applied to elements which accept child nodes.
7680              * @param {String} msg (optional) A message to display in the mask
7681              * @param {String} msgCls (optional) A css class to apply to the msg element
7682              * @return {Element} The mask element
7683              */
7684             mask : function(msg, msgCls){
7685                     var me = this,
7686                         dom = me.dom,
7687                         dh = Ext.DomHelper,
7688                         EXTELMASKMSG = "ext-el-mask-msg",
7689                 el,
7690                 mask;
7691
7692                 if(!/^body/i.test(dom.tagName) && me.getStyle('position') == 'static'){
7693                     me.addClass(XMASKEDRELATIVE);
7694                 }
7695                 if((el = data(dom, 'maskMsg'))){
7696                     el.remove();
7697                 }
7698                 if((el = data(dom, 'mask'))){
7699                     el.remove();
7700                 }
7701
7702             mask = dh.append(dom, {cls : "ext-el-mask"}, true);
7703                 data(dom, 'mask', mask);
7704
7705                 me.addClass(XMASKED);
7706                 mask.setDisplayed(true);
7707                 if(typeof msg == 'string'){
7708                 var mm = dh.append(dom, {cls : EXTELMASKMSG, cn:{tag:'div'}}, true);
7709                 data(dom, 'maskMsg', mm);
7710                     mm.dom.className = msgCls ? EXTELMASKMSG + " " + msgCls : EXTELMASKMSG;
7711                     mm.dom.firstChild.innerHTML = msg;
7712                     mm.setDisplayed(true);
7713                     mm.center(me);
7714                 }
7715                 if(Ext.isIE && !(Ext.isIE7 && Ext.isStrict) && me.getStyle('height') == 'auto'){ // ie will not expand full height automatically
7716                     mask.setSize(undefined, me.getHeight());
7717                 }
7718                 return mask;
7719             },
7720
7721             /**
7722              * Removes a previously applied mask.
7723              */
7724             unmask : function(){
7725                     var me = this,
7726                 dom = me.dom,
7727                         mask = data(dom, 'mask'),
7728                         maskMsg = data(dom, 'maskMsg');
7729                 if(mask){
7730                     if(maskMsg){
7731                         maskMsg.remove();
7732                     data(dom, 'maskMsg', undefined);
7733                     }
7734                     mask.remove();
7735                 data(dom, 'mask', undefined);
7736                 }
7737                 me.removeClass([XMASKED, XMASKEDRELATIVE]);
7738             },
7739
7740             /**
7741              * Returns true if this element is masked
7742              * @return {Boolean}
7743              */
7744             isMasked : function(){
7745             var m = data(this.dom, 'mask');
7746                 return m && m.isVisible();
7747             },
7748
7749             /**
7750              * Creates an iframe shim for this element to keep selects and other windowed objects from
7751              * showing through.
7752              * @return {Ext.Element} The new shim element
7753              */
7754             createShim : function(){
7755                 var el = document.createElement('iframe'),
7756                         shim;
7757                 el.frameBorder = '0';
7758                 el.className = 'ext-shim';
7759                 el.src = Ext.SSL_SECURE_URL;
7760                 shim = Ext.get(this.dom.parentNode.insertBefore(el, this.dom));
7761                 shim.autoBoxAdjust = false;
7762                 return shim;
7763             }
7764     };
7765 }());/**
7766  * @class Ext.Element
7767  */
7768 Ext.Element.addMethods({
7769     /**
7770      * Convenience method for constructing a KeyMap
7771      * @param {Number/Array/Object/String} key Either a string with the keys to listen for, the numeric key code, array of key codes or an object with the following options:
7772      * <code>{key: (number or array), shift: (true/false), ctrl: (true/false), alt: (true/false)}</code>
7773      * @param {Function} fn The function to call
7774      * @param {Object} scope (optional) The scope (<code>this</code> reference) in which the specified function is executed. Defaults to this Element.
7775      * @return {Ext.KeyMap} The KeyMap created
7776      */
7777     addKeyListener : function(key, fn, scope){
7778         var config;
7779         if(typeof key != 'object' || Ext.isArray(key)){
7780             config = {
7781                 key: key,
7782                 fn: fn,
7783                 scope: scope
7784             };
7785         }else{
7786             config = {
7787                 key : key.key,
7788                 shift : key.shift,
7789                 ctrl : key.ctrl,
7790                 alt : key.alt,
7791                 fn: fn,
7792                 scope: scope
7793             };
7794         }
7795         return new Ext.KeyMap(this, config);
7796     },
7797
7798     /**
7799      * Creates a KeyMap for this element
7800      * @param {Object} config The KeyMap config. See {@link Ext.KeyMap} for more details
7801      * @return {Ext.KeyMap} The KeyMap created
7802      */
7803     addKeyMap : function(config){
7804         return new Ext.KeyMap(this, config);
7805     }
7806 });
7807 (function(){
7808     // contants
7809     var NULL = null,
7810         UNDEFINED = undefined,
7811         TRUE = true,
7812         FALSE = false,
7813         SETX = "setX",
7814         SETY = "setY",
7815         SETXY = "setXY",
7816         LEFT = "left",
7817         BOTTOM = "bottom",
7818         TOP = "top",
7819         RIGHT = "right",
7820         HEIGHT = "height",
7821         WIDTH = "width",
7822         POINTS = "points",
7823         HIDDEN = "hidden",
7824         ABSOLUTE = "absolute",
7825         VISIBLE = "visible",
7826         MOTION = "motion",
7827         POSITION = "position",
7828         EASEOUT = "easeOut",
7829         /*
7830          * Use a light flyweight here since we are using so many callbacks and are always assured a DOM element
7831          */
7832         flyEl = new Ext.Element.Flyweight(),
7833         queues = {},
7834         getObject = function(o){
7835             return o || {};
7836         },
7837         fly = function(dom){
7838             flyEl.dom = dom;
7839             flyEl.id = Ext.id(dom);
7840             return flyEl;
7841         },
7842         /*
7843          * Queueing now stored outside of the element due to closure issues
7844          */
7845         getQueue = function(id){
7846             if(!queues[id]){
7847                 queues[id] = [];
7848             }
7849             return queues[id];
7850         },
7851         setQueue = function(id, value){
7852             queues[id] = value;
7853         };
7854         
7855 //Notifies Element that fx methods are available
7856 Ext.enableFx = TRUE;
7857
7858 /**
7859  * @class Ext.Fx
7860  * <p>A class to provide basic animation and visual effects support.  <b>Note:</b> This class is automatically applied
7861  * to the {@link Ext.Element} interface when included, so all effects calls should be performed via {@link Ext.Element}.
7862  * Conversely, since the effects are not actually defined in {@link Ext.Element}, Ext.Fx <b>must</b> be
7863  * {@link Ext#enableFx included} in order for the Element effects to work.</p><br/>
7864  * 
7865  * <p><b><u>Method Chaining</u></b></p>
7866  * <p>It is important to note that although the Fx methods and many non-Fx Element methods support "method chaining" in that
7867  * they return the Element object itself as the method return value, it is not always possible to mix the two in a single
7868  * method chain.  The Fx methods use an internal effects queue so that each effect can be properly timed and sequenced.
7869  * Non-Fx methods, on the other hand, have no such internal queueing and will always execute immediately.  For this reason,
7870  * while it may be possible to mix certain Fx and non-Fx method calls in a single chain, it may not always provide the
7871  * expected results and should be done with care.  Also see <tt>{@link #callback}</tt>.</p><br/>
7872  *
7873  * <p><b><u>Anchor Options for Motion Effects</u></b></p>
7874  * <p>Motion effects support 8-way anchoring, meaning that you can choose one of 8 different anchor points on the Element
7875  * that will serve as either the start or end point of the animation.  Following are all of the supported anchor positions:</p>
7876 <pre>
7877 Value  Description
7878 -----  -----------------------------
7879 tl     The top left corner
7880 t      The center of the top edge
7881 tr     The top right corner
7882 l      The center of the left edge
7883 r      The center of the right edge
7884 bl     The bottom left corner
7885 b      The center of the bottom edge
7886 br     The bottom right corner
7887 </pre>
7888  * <b>Note</b>: some Fx methods accept specific custom config parameters.  The options shown in the Config Options
7889  * section below are common options that can be passed to any Fx method unless otherwise noted.</b>
7890  * 
7891  * @cfg {Function} callback A function called when the effect is finished.  Note that effects are queued internally by the
7892  * Fx class, so a callback is not required to specify another effect -- effects can simply be chained together
7893  * and called in sequence (see note for <b><u>Method Chaining</u></b> above), for example:<pre><code>
7894  * el.slideIn().highlight();
7895  * </code></pre>
7896  * The callback is intended for any additional code that should run once a particular effect has completed. The Element
7897  * being operated upon is passed as the first parameter.
7898  * 
7899  * @cfg {Object} scope The scope (<code>this</code> reference) in which the <tt>{@link #callback}</tt> function is executed. Defaults to the browser window.
7900  * 
7901  * @cfg {String} easing A valid Ext.lib.Easing value for the effect:</p><div class="mdetail-params"><ul>
7902  * <li><b><tt>backBoth</tt></b></li>
7903  * <li><b><tt>backIn</tt></b></li>
7904  * <li><b><tt>backOut</tt></b></li>
7905  * <li><b><tt>bounceBoth</tt></b></li>
7906  * <li><b><tt>bounceIn</tt></b></li>
7907  * <li><b><tt>bounceOut</tt></b></li>
7908  * <li><b><tt>easeBoth</tt></b></li>
7909  * <li><b><tt>easeBothStrong</tt></b></li>
7910  * <li><b><tt>easeIn</tt></b></li>
7911  * <li><b><tt>easeInStrong</tt></b></li>
7912  * <li><b><tt>easeNone</tt></b></li>
7913  * <li><b><tt>easeOut</tt></b></li>
7914  * <li><b><tt>easeOutStrong</tt></b></li>
7915  * <li><b><tt>elasticBoth</tt></b></li>
7916  * <li><b><tt>elasticIn</tt></b></li>
7917  * <li><b><tt>elasticOut</tt></b></li>
7918  * </ul></div>
7919  *
7920  * @cfg {String} afterCls A css class to apply after the effect
7921  * @cfg {Number} duration The length of time (in seconds) that the effect should last
7922  * 
7923  * @cfg {Number} endOpacity Only applicable for {@link #fadeIn} or {@link #fadeOut}, a number between
7924  * <tt>0</tt> and <tt>1</tt> inclusive to configure the ending opacity value.
7925  *  
7926  * @cfg {Boolean} remove Whether the Element should be removed from the DOM and destroyed after the effect finishes
7927  * @cfg {Boolean} useDisplay Whether to use the <i>display</i> CSS property instead of <i>visibility</i> when hiding Elements (only applies to 
7928  * effects that end with the element being visually hidden, ignored otherwise)
7929  * @cfg {String/Object/Function} afterStyle A style specification string, e.g. <tt>"width:100px"</tt>, or an object
7930  * in the form <tt>{width:"100px"}</tt>, or a function which returns such a specification that will be applied to the
7931  * Element after the effect finishes.
7932  * @cfg {Boolean} block Whether the effect should block other effects from queueing while it runs
7933  * @cfg {Boolean} concurrent Whether to allow subsequently-queued effects to run at the same time as the current effect, or to ensure that they run in sequence
7934  * @cfg {Boolean} stopFx Whether preceding effects should be stopped and removed before running current effect (only applies to non blocking effects)
7935  */
7936 Ext.Fx = {
7937     
7938     // private - calls the function taking arguments from the argHash based on the key.  Returns the return value of the function.
7939     //           this is useful for replacing switch statements (for example).
7940     switchStatements : function(key, fn, argHash){
7941         return fn.apply(this, argHash[key]);
7942     },
7943     
7944     /**
7945      * Slides the element into view.  An anchor point can be optionally passed to set the point of
7946      * origin for the slide effect.  This function automatically handles wrapping the element with
7947      * a fixed-size container if needed.  See the Fx class overview for valid anchor point options.
7948      * Usage:
7949      *<pre><code>
7950 // default: slide the element in from the top
7951 el.slideIn();
7952
7953 // custom: slide the element in from the right with a 2-second duration
7954 el.slideIn('r', { duration: 2 });
7955
7956 // common config options shown with default values
7957 el.slideIn('t', {
7958     easing: 'easeOut',
7959     duration: .5
7960 });
7961 </code></pre>
7962      * @param {String} anchor (optional) One of the valid Fx anchor positions (defaults to top: 't')
7963      * @param {Object} options (optional) Object literal with any of the Fx config options
7964      * @return {Ext.Element} The Element
7965      */
7966     slideIn : function(anchor, o){ 
7967         o = getObject(o);
7968         var me = this,
7969             dom = me.dom,
7970             st = dom.style,
7971             xy,
7972             r,
7973             b,              
7974             wrap,               
7975             after,
7976             st,
7977             args, 
7978             pt,
7979             bw,
7980             bh;
7981             
7982         anchor = anchor || "t";
7983
7984         me.queueFx(o, function(){            
7985             xy = fly(dom).getXY();
7986             // fix display to visibility
7987             fly(dom).fixDisplay();            
7988             
7989             // restore values after effect
7990             r = fly(dom).getFxRestore();      
7991             b = {x: xy[0], y: xy[1], 0: xy[0], 1: xy[1], width: dom.offsetWidth, height: dom.offsetHeight};
7992             b.right = b.x + b.width;
7993             b.bottom = b.y + b.height;
7994             
7995             // fixed size for slide
7996             fly(dom).setWidth(b.width).setHeight(b.height);            
7997             
7998             // wrap if needed
7999             wrap = fly(dom).fxWrap(r.pos, o, HIDDEN);
8000             
8001             st.visibility = VISIBLE;
8002             st.position = ABSOLUTE;
8003             
8004             // clear out temp styles after slide and unwrap
8005             function after(){
8006                  fly(dom).fxUnwrap(wrap, r.pos, o);
8007                  st.width = r.width;
8008                  st.height = r.height;
8009                  fly(dom).afterFx(o);
8010             }
8011             
8012             // time to calculate the positions        
8013             pt = {to: [b.x, b.y]}; 
8014             bw = {to: b.width};
8015             bh = {to: b.height};
8016                 
8017             function argCalc(wrap, style, ww, wh, sXY, sXYval, s1, s2, w, h, p){                    
8018                 var ret = {};
8019                 fly(wrap).setWidth(ww).setHeight(wh);
8020                 if(fly(wrap)[sXY]){
8021                     fly(wrap)[sXY](sXYval);                  
8022                 }
8023                 style[s1] = style[s2] = "0";                    
8024                 if(w){
8025                     ret.width = w
8026                 };
8027                 if(h){
8028                     ret.height = h;
8029                 }
8030                 if(p){
8031                     ret.points = p;
8032                 }
8033                 return ret;
8034             };
8035
8036             args = fly(dom).switchStatements(anchor.toLowerCase(), argCalc, {
8037                     t  : [wrap, st, b.width, 0, NULL, NULL, LEFT, BOTTOM, NULL, bh, NULL],
8038                     l  : [wrap, st, 0, b.height, NULL, NULL, RIGHT, TOP, bw, NULL, NULL],
8039                     r  : [wrap, st, b.width, b.height, SETX, b.right, LEFT, TOP, NULL, NULL, pt],
8040                     b  : [wrap, st, b.width, b.height, SETY, b.bottom, LEFT, TOP, NULL, bh, pt],
8041                     tl : [wrap, st, 0, 0, NULL, NULL, RIGHT, BOTTOM, bw, bh, pt],
8042                     bl : [wrap, st, 0, 0, SETY, b.y + b.height, RIGHT, TOP, bw, bh, pt],
8043                     br : [wrap, st, 0, 0, SETXY, [b.right, b.bottom], LEFT, TOP, bw, bh, pt],
8044                     tr : [wrap, st, 0, 0, SETX, b.x + b.width, LEFT, BOTTOM, bw, bh, pt]
8045                 });
8046             
8047             st.visibility = VISIBLE;
8048             fly(wrap).show();
8049
8050             arguments.callee.anim = fly(wrap).fxanim(args,
8051                 o,
8052                 MOTION,
8053                 .5,
8054                 EASEOUT, 
8055                 after);
8056         });
8057         return me;
8058     },
8059     
8060     /**
8061      * Slides the element out of view.  An anchor point can be optionally passed to set the end point
8062      * for the slide effect.  When the effect is completed, the element will be hidden (visibility = 
8063      * 'hidden') but block elements will still take up space in the document.  The element must be removed
8064      * from the DOM using the 'remove' config option if desired.  This function automatically handles 
8065      * wrapping the element with a fixed-size container if needed.  See the Fx class overview for valid anchor point options.
8066      * Usage:
8067      *<pre><code>
8068 // default: slide the element out to the top
8069 el.slideOut();
8070
8071 // custom: slide the element out to the right with a 2-second duration
8072 el.slideOut('r', { duration: 2 });
8073
8074 // common config options shown with default values
8075 el.slideOut('t', {
8076     easing: 'easeOut',
8077     duration: .5,
8078     remove: false,
8079     useDisplay: false
8080 });
8081 </code></pre>
8082      * @param {String} anchor (optional) One of the valid Fx anchor positions (defaults to top: 't')
8083      * @param {Object} options (optional) Object literal with any of the Fx config options
8084      * @return {Ext.Element} The Element
8085      */
8086     slideOut : function(anchor, o){
8087         o = getObject(o);
8088         var me = this,
8089             dom = me.dom,
8090             st = dom.style,
8091             xy = me.getXY(),
8092             wrap,
8093             r,
8094             b,
8095             a,
8096             zero = {to: 0}; 
8097                     
8098         anchor = anchor || "t";
8099
8100         me.queueFx(o, function(){
8101             
8102             // restore values after effect
8103             r = fly(dom).getFxRestore(); 
8104             b = {x: xy[0], y: xy[1], 0: xy[0], 1: xy[1], width: dom.offsetWidth, height: dom.offsetHeight};
8105             b.right = b.x + b.width;
8106             b.bottom = b.y + b.height;
8107                 
8108             // fixed size for slide   
8109             fly(dom).setWidth(b.width).setHeight(b.height);
8110
8111             // wrap if needed
8112             wrap = fly(dom).fxWrap(r.pos, o, VISIBLE);
8113                 
8114             st.visibility = VISIBLE;
8115             st.position = ABSOLUTE;
8116             fly(wrap).setWidth(b.width).setHeight(b.height);            
8117
8118             function after(){
8119                 o.useDisplay ? fly(dom).setDisplayed(FALSE) : fly(dom).hide();                
8120                 fly(dom).fxUnwrap(wrap, r.pos, o);
8121                 st.width = r.width;
8122                 st.height = r.height;
8123                 fly(dom).afterFx(o);
8124             }            
8125             
8126             function argCalc(style, s1, s2, p1, v1, p2, v2, p3, v3){                    
8127                 var ret = {};
8128                 
8129                 style[s1] = style[s2] = "0";
8130                 ret[p1] = v1;               
8131                 if(p2){
8132                     ret[p2] = v2;               
8133                 }
8134                 if(p3){
8135                     ret[p3] = v3;
8136                 }
8137                 
8138                 return ret;
8139             };
8140             
8141             a = fly(dom).switchStatements(anchor.toLowerCase(), argCalc, {
8142                 t  : [st, LEFT, BOTTOM, HEIGHT, zero],
8143                 l  : [st, RIGHT, TOP, WIDTH, zero],
8144                 r  : [st, LEFT, TOP, WIDTH, zero, POINTS, {to : [b.right, b.y]}],
8145                 b  : [st, LEFT, TOP, HEIGHT, zero, POINTS, {to : [b.x, b.bottom]}],
8146                 tl : [st, RIGHT, BOTTOM, WIDTH, zero, HEIGHT, zero],
8147                 bl : [st, RIGHT, TOP, WIDTH, zero, HEIGHT, zero, POINTS, {to : [b.x, b.bottom]}],
8148                 br : [st, LEFT, TOP, WIDTH, zero, HEIGHT, zero, POINTS, {to : [b.x + b.width, b.bottom]}],
8149                 tr : [st, LEFT, BOTTOM, WIDTH, zero, HEIGHT, zero, POINTS, {to : [b.right, b.y]}]
8150             });
8151             
8152             arguments.callee.anim = fly(wrap).fxanim(a,
8153                 o,
8154                 MOTION,
8155                 .5,
8156                 EASEOUT, 
8157                 after);
8158         });
8159         return me;
8160     },
8161
8162     /**
8163      * Fades the element out while slowly expanding it in all directions.  When the effect is completed, the 
8164      * element will be hidden (visibility = 'hidden') but block elements will still take up space in the document. 
8165      * The element must be removed from the DOM using the 'remove' config option if desired.
8166      * Usage:
8167      *<pre><code>
8168 // default
8169 el.puff();
8170
8171 // common config options shown with default values
8172 el.puff({
8173     easing: 'easeOut',
8174     duration: .5,
8175     remove: false,
8176     useDisplay: false
8177 });
8178 </code></pre>
8179      * @param {Object} options (optional) Object literal with any of the Fx config options
8180      * @return {Ext.Element} The Element
8181      */
8182     puff : function(o){
8183         o = getObject(o);
8184         var me = this,
8185             dom = me.dom,
8186             st = dom.style,
8187             width,
8188             height,
8189             r;
8190
8191         me.queueFx(o, function(){
8192             width = fly(dom).getWidth();
8193             height = fly(dom).getHeight();
8194             fly(dom).clearOpacity();
8195             fly(dom).show();
8196
8197             // restore values after effect
8198             r = fly(dom).getFxRestore();                   
8199             
8200             function after(){
8201                 o.useDisplay ? fly(dom).setDisplayed(FALSE) : fly(dom).hide();                  
8202                 fly(dom).clearOpacity();  
8203                 fly(dom).setPositioning(r.pos);
8204                 st.width = r.width;
8205                 st.height = r.height;
8206                 st.fontSize = '';
8207                 fly(dom).afterFx(o);
8208             }   
8209
8210             arguments.callee.anim = fly(dom).fxanim({
8211                     width : {to : fly(dom).adjustWidth(width * 2)},
8212                     height : {to : fly(dom).adjustHeight(height * 2)},
8213                     points : {by : [-width * .5, -height * .5]},
8214                     opacity : {to : 0},
8215                     fontSize: {to : 200, unit: "%"}
8216                 },
8217                 o,
8218                 MOTION,
8219                 .5,
8220                 EASEOUT,
8221                  after);
8222         });
8223         return me;
8224     },
8225
8226     /**
8227      * Blinks the element as if it was clicked and then collapses on its center (similar to switching off a television).
8228      * When the effect is completed, the element will be hidden (visibility = 'hidden') but block elements will still 
8229      * take up space in the document. The element must be removed from the DOM using the 'remove' config option if desired.
8230      * Usage:
8231      *<pre><code>
8232 // default
8233 el.switchOff();
8234
8235 // all config options shown with default values
8236 el.switchOff({
8237     easing: 'easeIn',
8238     duration: .3,
8239     remove: false,
8240     useDisplay: false
8241 });
8242 </code></pre>
8243      * @param {Object} options (optional) Object literal with any of the Fx config options
8244      * @return {Ext.Element} The Element
8245      */
8246     switchOff : function(o){
8247         o = getObject(o);
8248         var me = this,
8249             dom = me.dom,
8250             st = dom.style,
8251             r;
8252
8253         me.queueFx(o, function(){
8254             fly(dom).clearOpacity();
8255             fly(dom).clip();
8256
8257             // restore values after effect
8258             r = fly(dom).getFxRestore();
8259                 
8260             function after(){
8261                 o.useDisplay ? fly(dom).setDisplayed(FALSE) : fly(dom).hide();  
8262                 fly(dom).clearOpacity();
8263                 fly(dom).setPositioning(r.pos);
8264                 st.width = r.width;
8265                 st.height = r.height;   
8266                 fly(dom).afterFx(o);
8267             };
8268
8269             fly(dom).fxanim({opacity : {to : 0.3}}, 
8270                 NULL, 
8271                 NULL, 
8272                 .1, 
8273                 NULL, 
8274                 function(){                                 
8275                     fly(dom).clearOpacity();
8276                         (function(){                            
8277                             fly(dom).fxanim({
8278                                 height : {to : 1},
8279                                 points : {by : [0, fly(dom).getHeight() * .5]}
8280                             }, 
8281                             o, 
8282                             MOTION, 
8283                             0.3, 
8284                             'easeIn', 
8285                             after);
8286                         }).defer(100);
8287                 });
8288         });
8289         return me;
8290     },
8291
8292     /**
8293      * Highlights the Element by setting a color (applies to the background-color by default, but can be
8294      * changed using the "attr" config option) and then fading back to the original color. If no original
8295      * color is available, you should provide the "endColor" config option which will be cleared after the animation.
8296      * Usage:
8297 <pre><code>
8298 // default: highlight background to yellow
8299 el.highlight();
8300
8301 // custom: highlight foreground text to blue for 2 seconds
8302 el.highlight("0000ff", { attr: 'color', duration: 2 });
8303
8304 // common config options shown with default values
8305 el.highlight("ffff9c", {
8306     attr: "background-color", //can be any valid CSS property (attribute) that supports a color value
8307     endColor: (current color) or "ffffff",
8308     easing: 'easeIn',
8309     duration: 1
8310 });
8311 </code></pre>
8312      * @param {String} color (optional) The highlight color. Should be a 6 char hex color without the leading # (defaults to yellow: 'ffff9c')
8313      * @param {Object} options (optional) Object literal with any of the Fx config options
8314      * @return {Ext.Element} The Element
8315      */ 
8316     highlight : function(color, o){
8317         o = getObject(o);
8318         var me = this,
8319             dom = me.dom,
8320             attr = o.attr || "backgroundColor",
8321             a = {},
8322             restore;
8323
8324         me.queueFx(o, function(){
8325             fly(dom).clearOpacity();
8326             fly(dom).show();
8327
8328             function after(){
8329                 dom.style[attr] = restore;
8330                 fly(dom).afterFx(o);
8331             }            
8332             restore = dom.style[attr];
8333             a[attr] = {from: color || "ffff9c", to: o.endColor || fly(dom).getColor(attr) || "ffffff"};
8334             arguments.callee.anim = fly(dom).fxanim(a,
8335                 o,
8336                 'color',
8337                 1,
8338                 'easeIn', 
8339                 after);
8340         });
8341         return me;
8342     },
8343
8344    /**
8345     * Shows a ripple of exploding, attenuating borders to draw attention to an Element.
8346     * Usage:
8347 <pre><code>
8348 // default: a single light blue ripple
8349 el.frame();
8350
8351 // custom: 3 red ripples lasting 3 seconds total
8352 el.frame("ff0000", 3, { duration: 3 });
8353
8354 // common config options shown with default values
8355 el.frame("C3DAF9", 1, {
8356     duration: 1 //duration of each individual ripple.
8357     // Note: Easing is not configurable and will be ignored if included
8358 });
8359 </code></pre>
8360     * @param {String} color (optional) The color of the border.  Should be a 6 char hex color without the leading # (defaults to light blue: 'C3DAF9').
8361     * @param {Number} count (optional) The number of ripples to display (defaults to 1)
8362     * @param {Object} options (optional) Object literal with any of the Fx config options
8363     * @return {Ext.Element} The Element
8364     */
8365     frame : function(color, count, o){
8366         o = getObject(o);
8367         var me = this,
8368             dom = me.dom,
8369             proxy,
8370             active;
8371
8372         me.queueFx(o, function(){
8373             color = color || '#C3DAF9';
8374             if(color.length == 6){
8375                 color = '#' + color;
8376             }            
8377             count = count || 1;
8378             fly(dom).show();
8379
8380             var xy = fly(dom).getXY(),
8381                 b = {x: xy[0], y: xy[1], 0: xy[0], 1: xy[1], width: dom.offsetWidth, height: dom.offsetHeight},
8382                 queue = function(){
8383                     proxy = fly(document.body || document.documentElement).createChild({
8384                         style:{
8385                             position : ABSOLUTE,
8386                             'z-index': 35000, // yee haw
8387                             border : '0px solid ' + color
8388                         }
8389                     });
8390                     return proxy.queueFx({}, animFn);
8391                 };
8392             
8393             
8394             arguments.callee.anim = {
8395                 isAnimated: true,
8396                 stop: function() {
8397                     count = 0;
8398                     proxy.stopFx();
8399                 }
8400             };
8401             
8402             function animFn(){
8403                 var scale = Ext.isBorderBox ? 2 : 1;
8404                 active = proxy.anim({
8405                     top : {from : b.y, to : b.y - 20},
8406                     left : {from : b.x, to : b.x - 20},
8407                     borderWidth : {from : 0, to : 10},
8408                     opacity : {from : 1, to : 0},
8409                     height : {from : b.height, to : b.height + 20 * scale},
8410                     width : {from : b.width, to : b.width + 20 * scale}
8411                 },{
8412                     duration: o.duration || 1,
8413                     callback: function() {
8414                         proxy.remove();
8415                         --count > 0 ? queue() : fly(dom).afterFx(o);
8416                     }
8417                 });
8418                 arguments.callee.anim = {
8419                     isAnimated: true,
8420                     stop: function(){
8421                         active.stop();
8422                     }
8423                 };
8424             };
8425             queue();
8426         });
8427         return me;
8428     },
8429
8430    /**
8431     * Creates a pause before any subsequent queued effects begin.  If there are
8432     * no effects queued after the pause it will have no effect.
8433     * Usage:
8434 <pre><code>
8435 el.pause(1);
8436 </code></pre>
8437     * @param {Number} seconds The length of time to pause (in seconds)
8438     * @return {Ext.Element} The Element
8439     */
8440     pause : function(seconds){        
8441         var dom = this.dom,
8442             t;
8443
8444         this.queueFx({}, function(){
8445             t = setTimeout(function(){
8446                 fly(dom).afterFx({});
8447             }, seconds * 1000);
8448             arguments.callee.anim = {
8449                 isAnimated: true,
8450                 stop: function(){
8451                     clearTimeout(t);
8452                     fly(dom).afterFx({});
8453                 }
8454             };
8455         });
8456         return this;
8457     },
8458
8459    /**
8460     * Fade an element in (from transparent to opaque).  The ending opacity can be specified
8461     * using the <tt>{@link #endOpacity}</tt> config option.
8462     * Usage:
8463 <pre><code>
8464 // default: fade in from opacity 0 to 100%
8465 el.fadeIn();
8466
8467 // custom: fade in from opacity 0 to 75% over 2 seconds
8468 el.fadeIn({ endOpacity: .75, duration: 2});
8469
8470 // common config options shown with default values
8471 el.fadeIn({
8472     endOpacity: 1, //can be any value between 0 and 1 (e.g. .5)
8473     easing: 'easeOut',
8474     duration: .5
8475 });
8476 </code></pre>
8477     * @param {Object} options (optional) Object literal with any of the Fx config options
8478     * @return {Ext.Element} The Element
8479     */
8480     fadeIn : function(o){
8481         o = getObject(o);
8482         var me = this,
8483             dom = me.dom,
8484             to = o.endOpacity || 1;
8485         
8486         me.queueFx(o, function(){
8487             fly(dom).setOpacity(0);
8488             fly(dom).fixDisplay();
8489             dom.style.visibility = VISIBLE;
8490             arguments.callee.anim = fly(dom).fxanim({opacity:{to:to}},
8491                 o, NULL, .5, EASEOUT, function(){
8492                 if(to == 1){
8493                     fly(dom).clearOpacity();
8494                 }
8495                 fly(dom).afterFx(o);
8496             });
8497         });
8498         return me;
8499     },
8500
8501    /**
8502     * Fade an element out (from opaque to transparent).  The ending opacity can be specified
8503     * using the <tt>{@link #endOpacity}</tt> config option.  Note that IE may require
8504     * <tt>{@link #useDisplay}:true</tt> in order to redisplay correctly.
8505     * Usage:
8506 <pre><code>
8507 // default: fade out from the element's current opacity to 0
8508 el.fadeOut();
8509
8510 // custom: fade out from the element's current opacity to 25% over 2 seconds
8511 el.fadeOut({ endOpacity: .25, duration: 2});
8512
8513 // common config options shown with default values
8514 el.fadeOut({
8515     endOpacity: 0, //can be any value between 0 and 1 (e.g. .5)
8516     easing: 'easeOut',
8517     duration: .5,
8518     remove: false,
8519     useDisplay: false
8520 });
8521 </code></pre>
8522     * @param {Object} options (optional) Object literal with any of the Fx config options
8523     * @return {Ext.Element} The Element
8524     */
8525     fadeOut : function(o){
8526         o = getObject(o);
8527         var me = this,
8528             dom = me.dom,
8529             style = dom.style,
8530             to = o.endOpacity || 0;         
8531         
8532         me.queueFx(o, function(){  
8533             arguments.callee.anim = fly(dom).fxanim({ 
8534                 opacity : {to : to}},
8535                 o, 
8536                 NULL, 
8537                 .5, 
8538                 EASEOUT, 
8539                 function(){
8540                     if(to == 0){
8541                         Ext.Element.data(dom, 'visibilityMode') == Ext.Element.DISPLAY || o.useDisplay ? 
8542                             style.display = "none" :
8543                             style.visibility = HIDDEN;
8544                             
8545                         fly(dom).clearOpacity();
8546                     }
8547                     fly(dom).afterFx(o);
8548             });
8549         });
8550         return me;
8551     },
8552
8553    /**
8554     * Animates the transition of an element's dimensions from a starting height/width
8555     * to an ending height/width.  This method is a convenience implementation of {@link shift}.
8556     * Usage:
8557 <pre><code>
8558 // change height and width to 100x100 pixels
8559 el.scale(100, 100);
8560
8561 // common config options shown with default values.  The height and width will default to
8562 // the element&#39;s existing values if passed as null.
8563 el.scale(
8564     [element&#39;s width],
8565     [element&#39;s height], {
8566         easing: 'easeOut',
8567         duration: .35
8568     }
8569 );
8570 </code></pre>
8571     * @param {Number} width  The new width (pass undefined to keep the original width)
8572     * @param {Number} height  The new height (pass undefined to keep the original height)
8573     * @param {Object} options (optional) Object literal with any of the Fx config options
8574     * @return {Ext.Element} The Element
8575     */
8576     scale : function(w, h, o){
8577         this.shift(Ext.apply({}, o, {
8578             width: w,
8579             height: h
8580         }));
8581         return this;
8582     },
8583
8584    /**
8585     * Animates the transition of any combination of an element's dimensions, xy position and/or opacity.
8586     * Any of these properties not specified in the config object will not be changed.  This effect 
8587     * requires that at least one new dimension, position or opacity setting must be passed in on
8588     * the config object in order for the function to have any effect.
8589     * Usage:
8590 <pre><code>
8591 // slide the element horizontally to x position 200 while changing the height and opacity
8592 el.shift({ x: 200, height: 50, opacity: .8 });
8593
8594 // common config options shown with default values.
8595 el.shift({
8596     width: [element&#39;s width],
8597     height: [element&#39;s height],
8598     x: [element&#39;s x position],
8599     y: [element&#39;s y position],
8600     opacity: [element&#39;s opacity],
8601     easing: 'easeOut',
8602     duration: .35
8603 });
8604 </code></pre>
8605     * @param {Object} options  Object literal with any of the Fx config options
8606     * @return {Ext.Element} The Element
8607     */
8608     shift : function(o){
8609         o = getObject(o);
8610         var dom = this.dom,
8611             a = {};
8612                 
8613         this.queueFx(o, function(){
8614             for (var prop in o) {
8615                 if (o[prop] != UNDEFINED) {                                                 
8616                     a[prop] = {to : o[prop]};                   
8617                 }
8618             } 
8619             
8620             a.width ? a.width.to = fly(dom).adjustWidth(o.width) : a;
8621             a.height ? a.height.to = fly(dom).adjustWidth(o.height) : a;   
8622             
8623             if (a.x || a.y || a.xy) {
8624                 a.points = a.xy || 
8625                            {to : [ a.x ? a.x.to : fly(dom).getX(),
8626                                    a.y ? a.y.to : fly(dom).getY()]};                  
8627             }
8628
8629             arguments.callee.anim = fly(dom).fxanim(a,
8630                 o, 
8631                 MOTION, 
8632                 .35, 
8633                 EASEOUT, 
8634                 function(){
8635                     fly(dom).afterFx(o);
8636                 });
8637         });
8638         return this;
8639     },
8640
8641     /**
8642      * Slides the element while fading it out of view.  An anchor point can be optionally passed to set the 
8643      * ending point of the effect.
8644      * Usage:
8645      *<pre><code>
8646 // default: slide the element downward while fading out
8647 el.ghost();
8648
8649 // custom: slide the element out to the right with a 2-second duration
8650 el.ghost('r', { duration: 2 });
8651
8652 // common config options shown with default values
8653 el.ghost('b', {
8654     easing: 'easeOut',
8655     duration: .5,
8656     remove: false,
8657     useDisplay: false
8658 });
8659 </code></pre>
8660      * @param {String} anchor (optional) One of the valid Fx anchor positions (defaults to bottom: 'b')
8661      * @param {Object} options (optional) Object literal with any of the Fx config options
8662      * @return {Ext.Element} The Element
8663      */
8664     ghost : function(anchor, o){
8665         o = getObject(o);
8666         var me = this,
8667             dom = me.dom,
8668             st = dom.style,
8669             a = {opacity: {to: 0}, points: {}},
8670             pt = a.points,
8671             r,
8672             w,
8673             h;
8674             
8675         anchor = anchor || "b";
8676
8677         me.queueFx(o, function(){
8678             // restore values after effect
8679             r = fly(dom).getFxRestore();
8680             w = fly(dom).getWidth();
8681             h = fly(dom).getHeight();
8682             
8683             function after(){
8684                 o.useDisplay ? fly(dom).setDisplayed(FALSE) : fly(dom).hide();   
8685                 fly(dom).clearOpacity();
8686                 fly(dom).setPositioning(r.pos);
8687                 st.width = r.width;
8688                 st.height = r.height;
8689                 fly(dom).afterFx(o);
8690             }
8691                 
8692             pt.by = fly(dom).switchStatements(anchor.toLowerCase(), function(v1,v2){ return [v1, v2];}, {
8693                t  : [0, -h],
8694                l  : [-w, 0],
8695                r  : [w, 0],
8696                b  : [0, h],
8697                tl : [-w, -h],
8698                bl : [-w, h],
8699                br : [w, h],
8700                tr : [w, -h] 
8701             });
8702                 
8703             arguments.callee.anim = fly(dom).fxanim(a,
8704                 o,
8705                 MOTION,
8706                 .5,
8707                 EASEOUT, after);
8708         });
8709         return me;
8710     },
8711
8712     /**
8713      * Ensures that all effects queued after syncFx is called on the element are
8714      * run concurrently.  This is the opposite of {@link #sequenceFx}.
8715      * @return {Ext.Element} The Element
8716      */
8717     syncFx : function(){
8718         var me = this;
8719         me.fxDefaults = Ext.apply(me.fxDefaults || {}, {
8720             block : FALSE,
8721             concurrent : TRUE,
8722             stopFx : FALSE
8723         });
8724         return me;
8725     },
8726
8727     /**
8728      * Ensures that all effects queued after sequenceFx is called on the element are
8729      * run in sequence.  This is the opposite of {@link #syncFx}.
8730      * @return {Ext.Element} The Element
8731      */
8732     sequenceFx : function(){
8733         var me = this;
8734         me.fxDefaults = Ext.apply(me.fxDefaults || {}, {
8735             block : FALSE,
8736             concurrent : FALSE,
8737             stopFx : FALSE
8738         });
8739         return me;
8740     },
8741
8742     /* @private */
8743     nextFx : function(){        
8744         var ef = getQueue(this.dom.id)[0];
8745         if(ef){
8746             ef.call(this);
8747         }
8748     },
8749
8750     /**
8751      * Returns true if the element has any effects actively running or queued, else returns false.
8752      * @return {Boolean} True if element has active effects, else false
8753      */
8754     hasActiveFx : function(){
8755         return getQueue(this.dom.id)[0];
8756     },
8757
8758     /**
8759      * Stops any running effects and clears the element's internal effects queue if it contains
8760      * any additional effects that haven't started yet.
8761      * @return {Ext.Element} The Element
8762      */
8763     stopFx : function(finish){
8764         var me = this,
8765             id = me.dom.id;
8766         if(me.hasActiveFx()){
8767             var cur = getQueue(id)[0];
8768             if(cur && cur.anim){
8769                 if(cur.anim.isAnimated){
8770                     setQueue(id, [cur]); //clear
8771                     cur.anim.stop(finish !== undefined ? finish : TRUE);
8772                 }else{
8773                     setQueue(id, []);
8774                 }
8775             }
8776         }
8777         return me;
8778     },
8779
8780     /* @private */
8781     beforeFx : function(o){
8782         if(this.hasActiveFx() && !o.concurrent){
8783            if(o.stopFx){
8784                this.stopFx();
8785                return TRUE;
8786            }
8787            return FALSE;
8788         }
8789         return TRUE;
8790     },
8791
8792     /**
8793      * Returns true if the element is currently blocking so that no other effect can be queued
8794      * until this effect is finished, else returns false if blocking is not set.  This is commonly
8795      * used to ensure that an effect initiated by a user action runs to completion prior to the
8796      * same effect being restarted (e.g., firing only one effect even if the user clicks several times).
8797      * @return {Boolean} True if blocking, else false
8798      */
8799     hasFxBlock : function(){
8800         var q = getQueue(this.dom.id);
8801         return q && q[0] && q[0].block;
8802     },
8803
8804     /* @private */
8805     queueFx : function(o, fn){
8806         var me = fly(this.dom);
8807         if(!me.hasFxBlock()){
8808             Ext.applyIf(o, me.fxDefaults);
8809             if(!o.concurrent){
8810                 var run = me.beforeFx(o);
8811                 fn.block = o.block;
8812                 getQueue(me.dom.id).push(fn);
8813                 if(run){
8814                     me.nextFx();
8815                 }
8816             }else{
8817                 fn.call(me);
8818             }
8819         }
8820         return me;
8821     },
8822
8823     /* @private */
8824     fxWrap : function(pos, o, vis){ 
8825         var dom = this.dom,
8826             wrap,
8827             wrapXY;
8828         if(!o.wrap || !(wrap = Ext.getDom(o.wrap))){            
8829             if(o.fixPosition){
8830                 wrapXY = fly(dom).getXY();
8831             }
8832             var div = document.createElement("div");
8833             div.style.visibility = vis;
8834             wrap = dom.parentNode.insertBefore(div, dom);
8835             fly(wrap).setPositioning(pos);
8836             if(fly(wrap).isStyle(POSITION, "static")){
8837                 fly(wrap).position("relative");
8838             }
8839             fly(dom).clearPositioning('auto');
8840             fly(wrap).clip();
8841             wrap.appendChild(dom);
8842             if(wrapXY){
8843                 fly(wrap).setXY(wrapXY);
8844             }
8845         }
8846         return wrap;
8847     },
8848
8849     /* @private */
8850     fxUnwrap : function(wrap, pos, o){      
8851         var dom = this.dom;
8852         fly(dom).clearPositioning();
8853         fly(dom).setPositioning(pos);
8854         if(!o.wrap){
8855             var pn = fly(wrap).dom.parentNode;
8856             pn.insertBefore(dom, wrap); 
8857             fly(wrap).remove();
8858         }
8859     },
8860
8861     /* @private */
8862     getFxRestore : function(){
8863         var st = this.dom.style;
8864         return {pos: this.getPositioning(), width: st.width, height : st.height};
8865     },
8866
8867     /* @private */
8868     afterFx : function(o){
8869         var dom = this.dom,
8870             id = dom.id;
8871         if(o.afterStyle){
8872             fly(dom).setStyle(o.afterStyle);            
8873         }
8874         if(o.afterCls){
8875             fly(dom).addClass(o.afterCls);
8876         }
8877         if(o.remove == TRUE){
8878             fly(dom).remove();
8879         }
8880         if(o.callback){
8881             o.callback.call(o.scope, fly(dom));
8882         }
8883         if(!o.concurrent){
8884             getQueue(id).shift();
8885             fly(dom).nextFx();
8886         }
8887     },
8888
8889     /* @private */
8890     fxanim : function(args, opt, animType, defaultDur, defaultEase, cb){
8891         animType = animType || 'run';
8892         opt = opt || {};
8893         var anim = Ext.lib.Anim[animType](
8894                 this.dom, 
8895                 args,
8896                 (opt.duration || defaultDur) || .35,
8897                 (opt.easing || defaultEase) || EASEOUT,
8898                 cb,            
8899                 this
8900             );
8901         opt.anim = anim;
8902         return anim;
8903     }
8904 };
8905
8906 // backwards compat
8907 Ext.Fx.resize = Ext.Fx.scale;
8908
8909 //When included, Ext.Fx is automatically applied to Element so that all basic
8910 //effects are available directly via the Element API
8911 Ext.Element.addMethods(Ext.Fx);
8912 })();
8913 /**
8914  * @class Ext.CompositeElementLite
8915  * <p>This class encapsulates a <i>collection</i> of DOM elements, providing methods to filter
8916  * members, or to perform collective actions upon the whole set.</p>
8917  * <p>Although they are not listed, this class supports all of the methods of {@link Ext.Element} and
8918  * {@link Ext.Fx}. The methods from these classes will be performed on all the elements in this collection.</p>
8919  * Example:<pre><code>
8920 var els = Ext.select("#some-el div.some-class");
8921 // or select directly from an existing element
8922 var el = Ext.get('some-el');
8923 el.select('div.some-class');
8924
8925 els.setWidth(100); // all elements become 100 width
8926 els.hide(true); // all elements fade out and hide
8927 // or
8928 els.setWidth(100).hide(true);
8929 </code>
8930  */
8931 Ext.CompositeElementLite = function(els, root){
8932     /**
8933      * <p>The Array of DOM elements which this CompositeElement encapsulates. Read-only.</p>
8934      * <p>This will not <i>usually</i> be accessed in developers' code, but developers wishing
8935      * to augment the capabilities of the CompositeElementLite class may use it when adding
8936      * methods to the class.</p>
8937      * <p>For example to add the <code>nextAll</code> method to the class to <b>add</b> all
8938      * following siblings of selected elements, the code would be</p><code><pre>
8939 Ext.override(Ext.CompositeElementLite, {
8940     nextAll: function() {
8941         var els = this.elements, i, l = els.length, n, r = [], ri = -1;
8942
8943 //      Loop through all elements in this Composite, accumulating
8944 //      an Array of all siblings.
8945         for (i = 0; i < l; i++) {
8946             for (n = els[i].nextSibling; n; n = n.nextSibling) {
8947                 r[++ri] = n;
8948             }
8949         }
8950
8951 //      Add all found siblings to this Composite
8952         return this.add(r);
8953     }
8954 });</pre></code>
8955      * @type Array
8956      * @property elements
8957      */
8958     this.elements = [];
8959     this.add(els, root);
8960     this.el = new Ext.Element.Flyweight();
8961 };
8962
8963 Ext.CompositeElementLite.prototype = {
8964     isComposite: true,
8965
8966     // private
8967     getElement : function(el){
8968         // Set the shared flyweight dom property to the current element
8969         var e = this.el;
8970         e.dom = el;
8971         e.id = el.id;
8972         return e;
8973     },
8974
8975     // private
8976     transformElement : function(el){
8977         return Ext.getDom(el);
8978     },
8979
8980     /**
8981      * Returns the number of elements in this Composite.
8982      * @return Number
8983      */
8984     getCount : function(){
8985         return this.elements.length;
8986     },
8987     /**
8988      * Adds elements to this Composite object.
8989      * @param {Mixed} els Either an Array of DOM elements to add, or another Composite object who's elements should be added.
8990      * @return {CompositeElement} This Composite object.
8991      */
8992     add : function(els, root){
8993         var me = this,
8994             elements = me.elements;
8995         if(!els){
8996             return this;
8997         }
8998         if(typeof els == "string"){
8999             els = Ext.Element.selectorFunction(els, root);
9000         }else if(els.isComposite){
9001             els = els.elements;
9002         }else if(!Ext.isIterable(els)){
9003             els = [els];
9004         }
9005
9006         for(var i = 0, len = els.length; i < len; ++i){
9007             elements.push(me.transformElement(els[i]));
9008         }
9009         return me;
9010     },
9011
9012     invoke : function(fn, args){
9013         var me = this,
9014             els = me.elements,
9015             len = els.length,
9016             e,
9017             i;
9018
9019         for(i = 0; i < len; i++) {
9020             e = els[i];
9021             if(e){
9022                 Ext.Element.prototype[fn].apply(me.getElement(e), args);
9023             }
9024         }
9025         return me;
9026     },
9027     /**
9028      * Returns a flyweight Element of the dom element object at the specified index
9029      * @param {Number} index
9030      * @return {Ext.Element}
9031      */
9032     item : function(index){
9033         var me = this,
9034             el = me.elements[index],
9035             out = null;
9036
9037         if(el){
9038             out = me.getElement(el);
9039         }
9040         return out;
9041     },
9042
9043     // fixes scope with flyweight
9044     addListener : function(eventName, handler, scope, opt){
9045         var els = this.elements,
9046             len = els.length,
9047             i, e;
9048
9049         for(i = 0; i<len; i++) {
9050             e = els[i];
9051             if(e) {
9052                 Ext.EventManager.on(e, eventName, handler, scope || e, opt);
9053             }
9054         }
9055         return this;
9056     },
9057     /**
9058      * <p>Calls the passed function for each element in this composite.</p>
9059      * @param {Function} fn The function to call. The function is passed the following parameters:<ul>
9060      * <li><b>el</b> : Element<div class="sub-desc">The current Element in the iteration.
9061      * <b>This is the flyweight (shared) Ext.Element instance, so if you require a
9062      * a reference to the dom node, use el.dom.</b></div></li>
9063      * <li><b>c</b> : Composite<div class="sub-desc">This Composite object.</div></li>
9064      * <li><b>idx</b> : Number<div class="sub-desc">The zero-based index in the iteration.</div></li>
9065      * </ul>
9066      * @param {Object} scope (optional) The scope (<i>this</i> reference) in which the function is executed. (defaults to the Element)
9067      * @return {CompositeElement} this
9068      */
9069     each : function(fn, scope){
9070         var me = this,
9071             els = me.elements,
9072             len = els.length,
9073             i, e;
9074
9075         for(i = 0; i<len; i++) {
9076             e = els[i];
9077             if(e){
9078                 e = this.getElement(e);
9079                 if(fn.call(scope || e, e, me, i) === false){
9080                     break;
9081                 }
9082             }
9083         }
9084         return me;
9085     },
9086
9087     /**
9088     * Clears this Composite and adds the elements passed.
9089     * @param {Mixed} els Either an array of DOM elements, or another Composite from which to fill this Composite.
9090     * @return {CompositeElement} this
9091     */
9092     fill : function(els){
9093         var me = this;
9094         me.elements = [];
9095         me.add(els);
9096         return me;
9097     },
9098
9099     /**
9100      * Filters this composite to only elements that match the passed selector.
9101      * @param {String/Function} selector A string CSS selector or a comparison function.
9102      * The comparison function will be called with the following arguments:<ul>
9103      * <li><code>el</code> : Ext.Element<div class="sub-desc">The current DOM element.</div></li>
9104      * <li><code>index</code> : Number<div class="sub-desc">The current index within the collection.</div></li>
9105      * </ul>
9106      * @return {CompositeElement} this
9107      */
9108     filter : function(selector){
9109         var els = [],
9110             me = this,
9111             elements = me.elements,
9112             fn = Ext.isFunction(selector) ? selector
9113                 : function(el){
9114                     return el.is(selector);
9115                 };
9116
9117
9118         me.each(function(el, self, i){
9119             if(fn(el, i) !== false){
9120                 els[els.length] = me.transformElement(el);
9121             }
9122         });
9123         me.elements = els;
9124         return me;
9125     },
9126
9127     /**
9128      * Find the index of the passed element within the composite collection.
9129      * @param el {Mixed} The id of an element, or an Ext.Element, or an HtmlElement to find within the composite collection.
9130      * @return Number The index of the passed Ext.Element in the composite collection, or -1 if not found.
9131      */
9132     indexOf : function(el){
9133         return this.elements.indexOf(this.transformElement(el));
9134     },
9135
9136     /**
9137     * Replaces the specified element with the passed element.
9138     * @param {Mixed} el The id of an element, the Element itself, the index of the element in this composite
9139     * to replace.
9140     * @param {Mixed} replacement The id of an element or the Element itself.
9141     * @param {Boolean} domReplace (Optional) True to remove and replace the element in the document too.
9142     * @return {CompositeElement} this
9143     */
9144     replaceElement : function(el, replacement, domReplace){
9145         var index = !isNaN(el) ? el : this.indexOf(el),
9146             d;
9147         if(index > -1){
9148             replacement = Ext.getDom(replacement);
9149             if(domReplace){
9150                 d = this.elements[index];
9151                 d.parentNode.insertBefore(replacement, d);
9152                 Ext.removeNode(d);
9153             }
9154             this.elements.splice(index, 1, replacement);
9155         }
9156         return this;
9157     },
9158
9159     /**
9160      * Removes all elements.
9161      */
9162     clear : function(){
9163         this.elements = [];
9164     }
9165 };
9166
9167 Ext.CompositeElementLite.prototype.on = Ext.CompositeElementLite.prototype.addListener;
9168
9169 (function(){
9170 var fnName,
9171     ElProto = Ext.Element.prototype,
9172     CelProto = Ext.CompositeElementLite.prototype;
9173
9174 for(fnName in ElProto){
9175     if(Ext.isFunction(ElProto[fnName])){
9176         (function(fnName){
9177             CelProto[fnName] = CelProto[fnName] || function(){
9178                 return this.invoke(fnName, arguments);
9179             };
9180         }).call(CelProto, fnName);
9181
9182     }
9183 }
9184 })();
9185
9186 if(Ext.DomQuery){
9187     Ext.Element.selectorFunction = Ext.DomQuery.select;
9188 }
9189
9190 /**
9191  * Selects elements based on the passed CSS selector to enable {@link Ext.Element Element} methods
9192  * to be applied to many related elements in one statement through the returned {@link Ext.CompositeElement CompositeElement} or
9193  * {@link Ext.CompositeElementLite CompositeElementLite} object.
9194  * @param {String/Array} selector The CSS selector or an array of elements
9195  * @param {HTMLElement/String} root (optional) The root element of the query or id of the root
9196  * @return {CompositeElementLite/CompositeElement}
9197  * @member Ext.Element
9198  * @method select
9199  */
9200 Ext.Element.select = function(selector, root){
9201     var els;
9202     if(typeof selector == "string"){
9203         els = Ext.Element.selectorFunction(selector, root);
9204     }else if(selector.length !== undefined){
9205         els = selector;
9206     }else{
9207         throw "Invalid selector";
9208     }
9209     return new Ext.CompositeElementLite(els);
9210 };
9211 /**
9212  * Selects elements based on the passed CSS selector to enable {@link Ext.Element Element} methods
9213  * to be applied to many related elements in one statement through the returned {@link Ext.CompositeElement CompositeElement} or
9214  * {@link Ext.CompositeElementLite CompositeElementLite} object.
9215  * @param {String/Array} selector The CSS selector or an array of elements
9216  * @param {HTMLElement/String} root (optional) The root element of the query or id of the root
9217  * @return {CompositeElementLite/CompositeElement}
9218  * @member Ext
9219  * @method select
9220  */
9221 Ext.select = Ext.Element.select;
9222 /**
9223  * @class Ext.CompositeElementLite
9224  */
9225 Ext.apply(Ext.CompositeElementLite.prototype, {
9226     addElements : function(els, root){
9227         if(!els){
9228             return this;
9229         }
9230         if(typeof els == "string"){
9231             els = Ext.Element.selectorFunction(els, root);
9232         }
9233         var yels = this.elements;
9234         Ext.each(els, function(e) {
9235             yels.push(Ext.get(e));
9236         });
9237         return this;
9238     },
9239
9240     /**
9241      * Returns the first Element
9242      * @return {Ext.Element}
9243      */
9244     first : function(){
9245         return this.item(0);
9246     },
9247
9248     /**
9249      * Returns the last Element
9250      * @return {Ext.Element}
9251      */
9252     last : function(){
9253         return this.item(this.getCount()-1);
9254     },
9255
9256     /**
9257      * Returns true if this composite contains the passed element
9258      * @param el {Mixed} The id of an element, or an Ext.Element, or an HtmlElement to find within the composite collection.
9259      * @return Boolean
9260      */
9261     contains : function(el){
9262         return this.indexOf(el) != -1;
9263     },
9264
9265     /**
9266     * Removes the specified element(s).
9267     * @param {Mixed} el The id of an element, the Element itself, the index of the element in this composite
9268     * or an array of any of those.
9269     * @param {Boolean} removeDom (optional) True to also remove the element from the document
9270     * @return {CompositeElement} this
9271     */
9272     removeElement : function(keys, removeDom){
9273         var me = this,
9274             els = this.elements,
9275             el;
9276         Ext.each(keys, function(val){
9277             if ((el = (els[val] || els[val = me.indexOf(val)]))) {
9278                 if(removeDom){
9279                     if(el.dom){
9280                         el.remove();
9281                     }else{
9282                         Ext.removeNode(el);
9283                     }
9284                 }
9285                 els.splice(val, 1);
9286             }
9287         });
9288         return this;
9289     }
9290 });
9291 /**
9292  * @class Ext.CompositeElement
9293  * @extends Ext.CompositeElementLite
9294  * <p>This class encapsulates a <i>collection</i> of DOM elements, providing methods to filter
9295  * members, or to perform collective actions upon the whole set.</p>
9296  * <p>Although they are not listed, this class supports all of the methods of {@link Ext.Element} and
9297  * {@link Ext.Fx}. The methods from these classes will be performed on all the elements in this collection.</p>
9298  * <p>All methods return <i>this</i> and can be chained.</p>
9299  * Usage:
9300 <pre><code>
9301 var els = Ext.select("#some-el div.some-class", true);
9302 // or select directly from an existing element
9303 var el = Ext.get('some-el');
9304 el.select('div.some-class', true);
9305
9306 els.setWidth(100); // all elements become 100 width
9307 els.hide(true); // all elements fade out and hide
9308 // or
9309 els.setWidth(100).hide(true);
9310 </code></pre>
9311  */
9312 Ext.CompositeElement = Ext.extend(Ext.CompositeElementLite, {
9313     
9314     constructor : function(els, root){
9315         this.elements = [];
9316         this.add(els, root);
9317     },
9318     
9319     // private
9320     getElement : function(el){
9321         // In this case just return it, since we already have a reference to it
9322         return el;
9323     },
9324     
9325     // private
9326     transformElement : function(el){
9327         return Ext.get(el);
9328     }
9329
9330     /**
9331     * Adds elements to this composite.
9332     * @param {String/Array} els A string CSS selector, an array of elements or an element
9333     * @return {CompositeElement} this
9334     */
9335
9336     /**
9337      * Returns the Element object at the specified index
9338      * @param {Number} index
9339      * @return {Ext.Element}
9340      */
9341
9342     /**
9343      * Iterates each <code>element</code> in this <code>composite</code>
9344      * calling the supplied function using {@link Ext#each}.
9345      * @param {Function} fn The function to be called with each
9346      * <code>element</code>. If the supplied function returns <tt>false</tt>,
9347      * iteration stops. This function is called with the following arguments:
9348      * <div class="mdetail-params"><ul>
9349      * <li><code>element</code> : <i>Ext.Element</i><div class="sub-desc">The element at the current <code>index</code>
9350      * in the <code>composite</code></div></li>
9351      * <li><code>composite</code> : <i>Object</i> <div class="sub-desc">This composite.</div></li>
9352      * <li><code>index</code> : <i>Number</i> <div class="sub-desc">The current index within the <code>composite</code> </div></li>
9353      * </ul></div>
9354      * @param {Object} scope (optional) The scope (<code><this</code> reference) in which the specified function is executed.
9355      * Defaults to the <code>element</code> at the current <code>index</code>
9356      * within the composite.
9357      * @return {CompositeElement} this
9358      */
9359 });
9360
9361 /**
9362  * Selects elements based on the passed CSS selector to enable {@link Ext.Element Element} methods
9363  * to be applied to many related elements in one statement through the returned {@link Ext.CompositeElement CompositeElement} or
9364  * {@link Ext.CompositeElementLite CompositeElementLite} object.
9365  * @param {String/Array} selector The CSS selector or an array of elements
9366  * @param {Boolean} unique (optional) true to create a unique Ext.Element for each element (defaults to a shared flyweight object)
9367  * @param {HTMLElement/String} root (optional) The root element of the query or id of the root
9368  * @return {CompositeElementLite/CompositeElement}
9369  * @member Ext.Element
9370  * @method select
9371  */
9372 Ext.Element.select = function(selector, unique, root){
9373     var els;
9374     if(typeof selector == "string"){
9375         els = Ext.Element.selectorFunction(selector, root);
9376     }else if(selector.length !== undefined){
9377         els = selector;
9378     }else{
9379         throw "Invalid selector";
9380     }
9381
9382     return (unique === true) ? new Ext.CompositeElement(els) : new Ext.CompositeElementLite(els);
9383 };
9384
9385 /**
9386  * Selects elements based on the passed CSS selector to enable {@link Ext.Element Element} methods
9387  * to be applied to many related elements in one statement through the returned {@link Ext.CompositeElement CompositeElement} or
9388  * {@link Ext.CompositeElementLite CompositeElementLite} object.
9389  * @param {String/Array} selector The CSS selector or an array of elements
9390  * @param {Boolean} unique (optional) true to create a unique Ext.Element for each element (defaults to a shared flyweight object)
9391  * @param {HTMLElement/String} root (optional) The root element of the query or id of the root
9392  * @return {CompositeElementLite/CompositeElement}
9393  * @member Ext
9394  * @method select
9395  */
9396 Ext.select = Ext.Element.select;(function(){
9397     var BEFOREREQUEST = "beforerequest",
9398         REQUESTCOMPLETE = "requestcomplete",
9399         REQUESTEXCEPTION = "requestexception",
9400         UNDEFINED = undefined,
9401         LOAD = 'load',
9402         POST = 'POST',
9403         GET = 'GET',
9404         WINDOW = window;
9405
9406     /**
9407      * @class Ext.data.Connection
9408      * @extends Ext.util.Observable
9409      * <p>The class encapsulates a connection to the page's originating domain, allowing requests to be made
9410      * either to a configured URL, or to a URL specified at request time.</p>
9411      * <p>Requests made by this class are asynchronous, and will return immediately. No data from
9412      * the server will be available to the statement immediately following the {@link #request} call.
9413      * To process returned data, use a
9414      * <a href="#request-option-success" ext:member="request-option-success" ext:cls="Ext.data.Connection">success callback</a>
9415      * in the request options object,
9416      * or an {@link #requestcomplete event listener}.</p>
9417      * <p><h3>File Uploads</h3><a href="#request-option-isUpload" ext:member="request-option-isUpload" ext:cls="Ext.data.Connection">File uploads</a> are not performed using normal "Ajax" techniques, that
9418      * is they are <b>not</b> performed using XMLHttpRequests. Instead the form is submitted in the standard
9419      * manner with the DOM <tt>&lt;form></tt> element temporarily modified to have its
9420      * <a href="http://www.w3.org/TR/REC-html40/present/frames.html#adef-target">target</a> set to refer
9421      * to a dynamically generated, hidden <tt>&lt;iframe></tt> which is inserted into the document
9422      * but removed after the return data has been gathered.</p>
9423      * <p>The server response is parsed by the browser to create the document for the IFRAME. If the
9424      * server is using JSON to send the return object, then the
9425      * <a href="http://www.w3.org/Protocols/rfc2616/rfc2616-sec14.html#sec14.17">Content-Type</a> header
9426      * must be set to "text/html" in order to tell the browser to insert the text unchanged into the document body.</p>
9427      * <p>Characters which are significant to an HTML parser must be sent as HTML entities, so encode
9428      * "&lt;" as "&amp;lt;", "&amp;" as "&amp;amp;" etc.</p>
9429      * <p>The response text is retrieved from the document, and a fake XMLHttpRequest object
9430      * is created containing a <tt>responseText</tt> property in order to conform to the
9431      * requirements of event handlers and callbacks.</p>
9432      * <p>Be aware that file upload packets are sent with the content type <a href="http://www.faqs.org/rfcs/rfc2388.html">multipart/form</a>
9433      * and some server technologies (notably JEE) may require some custom processing in order to
9434      * retrieve parameter names and parameter values from the packet content.</p>
9435      * @constructor
9436      * @param {Object} config a configuration object.
9437      */
9438     Ext.data.Connection = function(config){
9439         Ext.apply(this, config);
9440         this.addEvents(
9441             /**
9442              * @event beforerequest
9443              * Fires before a network request is made to retrieve a data object.
9444              * @param {Connection} conn This Connection object.
9445              * @param {Object} options The options config object passed to the {@link #request} method.
9446              */
9447             BEFOREREQUEST,
9448             /**
9449              * @event requestcomplete
9450              * Fires if the request was successfully completed.
9451              * @param {Connection} conn This Connection object.
9452              * @param {Object} response The XHR object containing the response data.
9453              * See <a href="http://www.w3.org/TR/XMLHttpRequest/">The XMLHttpRequest Object</a>
9454              * for details.
9455              * @param {Object} options The options config object passed to the {@link #request} method.
9456              */
9457             REQUESTCOMPLETE,
9458             /**
9459              * @event requestexception
9460              * Fires if an error HTTP status was returned from the server.
9461              * See <a href="http://www.w3.org/Protocols/rfc2616/rfc2616-sec10.html">HTTP Status Code Definitions</a>
9462              * for details of HTTP status codes.
9463              * @param {Connection} conn This Connection object.
9464              * @param {Object} response The XHR object containing the response data.
9465              * See <a href="http://www.w3.org/TR/XMLHttpRequest/">The XMLHttpRequest Object</a>
9466              * for details.
9467              * @param {Object} options The options config object passed to the {@link #request} method.
9468              */
9469             REQUESTEXCEPTION
9470         );
9471         Ext.data.Connection.superclass.constructor.call(this);
9472     };
9473
9474     Ext.extend(Ext.data.Connection, Ext.util.Observable, {
9475         /**
9476          * @cfg {String} url (Optional) <p>The default URL to be used for requests to the server. Defaults to undefined.</p>
9477          * <p>The <code>url</code> config may be a function which <i>returns</i> the URL to use for the Ajax request. The scope
9478          * (<code><b>this</b></code> reference) of the function is the <code>scope</code> option passed to the {@link #request} method.</p>
9479          */
9480         /**
9481          * @cfg {Object} extraParams (Optional) An object containing properties which are used as
9482          * extra parameters to each request made by this object. (defaults to undefined)
9483          */
9484         /**
9485          * @cfg {Object} defaultHeaders (Optional) An object containing request headers which are added
9486          *  to each request made by this object. (defaults to undefined)
9487          */
9488         /**
9489          * @cfg {String} method (Optional) The default HTTP method to be used for requests.
9490          * (defaults to undefined; if not set, but {@link #request} params are present, POST will be used;
9491          * otherwise, GET will be used.)
9492          */
9493         /**
9494          * @cfg {Number} timeout (Optional) The timeout in milliseconds to be used for requests. (defaults to 30000)
9495          */
9496         timeout : 30000,
9497         /**
9498          * @cfg {Boolean} autoAbort (Optional) Whether this request should abort any pending requests. (defaults to false)
9499          * @type Boolean
9500          */
9501         autoAbort:false,
9502
9503         /**
9504          * @cfg {Boolean} disableCaching (Optional) True to add a unique cache-buster param to GET requests. (defaults to true)
9505          * @type Boolean
9506          */
9507         disableCaching: true,
9508
9509         /**
9510          * @cfg {String} disableCachingParam (Optional) Change the parameter which is sent went disabling caching
9511          * through a cache buster. Defaults to '_dc'
9512          * @type String
9513          */
9514         disableCachingParam: '_dc',
9515
9516         /**
9517          * <p>Sends an HTTP request to a remote server.</p>
9518          * <p><b>Important:</b> Ajax server requests are asynchronous, and this call will
9519          * return before the response has been received. Process any returned data
9520          * in a callback function.</p>
9521          * <pre><code>
9522 Ext.Ajax.request({
9523    url: 'ajax_demo/sample.json',
9524    success: function(response, opts) {
9525       var obj = Ext.decode(response.responseText);
9526       console.dir(obj);
9527    },
9528    failure: function(response, opts) {
9529       console.log('server-side failure with status code ' + response.status);
9530    }
9531 });
9532          * </code></pre>
9533          * <p>To execute a callback function in the correct scope, use the <tt>scope</tt> option.</p>
9534          * @param {Object} options An object which may contain the following properties:<ul>
9535          * <li><b>url</b> : String/Function (Optional)<div class="sub-desc">The URL to
9536          * which to send the request, or a function to call which returns a URL string. The scope of the
9537          * function is specified by the <tt>scope</tt> option. Defaults to the configured
9538          * <tt>{@link #url}</tt>.</div></li>
9539          * <li><b>params</b> : Object/String/Function (Optional)<div class="sub-desc">
9540          * An object containing properties which are used as parameters to the
9541          * request, a url encoded string or a function to call to get either. The scope of the function
9542          * is specified by the <tt>scope</tt> option.</div></li>
9543          * <li><b>method</b> : String (Optional)<div class="sub-desc">The HTTP method to use
9544          * for the request. Defaults to the configured method, or if no method was configured,
9545          * "GET" if no parameters are being sent, and "POST" if parameters are being sent.  Note that
9546          * the method name is case-sensitive and should be all caps.</div></li>
9547          * <li><b>callback</b> : Function (Optional)<div class="sub-desc">The
9548          * function to be called upon receipt of the HTTP response. The callback is
9549          * called regardless of success or failure and is passed the following
9550          * parameters:<ul>
9551          * <li><b>options</b> : Object<div class="sub-desc">The parameter to the request call.</div></li>
9552          * <li><b>success</b> : Boolean<div class="sub-desc">True if the request succeeded.</div></li>
9553          * <li><b>response</b> : Object<div class="sub-desc">The XMLHttpRequest object containing the response data.
9554          * See <a href="http://www.w3.org/TR/XMLHttpRequest/">http://www.w3.org/TR/XMLHttpRequest/</a> for details about
9555          * accessing elements of the response.</div></li>
9556          * </ul></div></li>
9557          * <li><a id="request-option-success"></a><b>success</b> : Function (Optional)<div class="sub-desc">The function
9558          * to be called upon success of the request. The callback is passed the following
9559          * parameters:<ul>
9560          * <li><b>response</b> : Object<div class="sub-desc">The XMLHttpRequest object containing the response data.</div></li>
9561          * <li><b>options</b> : Object<div class="sub-desc">The parameter to the request call.</div></li>
9562          * </ul></div></li>
9563          * <li><b>failure</b> : Function (Optional)<div class="sub-desc">The function
9564          * to be called upon failure of the request. The callback is passed the
9565          * following parameters:<ul>
9566          * <li><b>response</b> : Object<div class="sub-desc">The XMLHttpRequest object containing the response data.</div></li>
9567          * <li><b>options</b> : Object<div class="sub-desc">The parameter to the request call.</div></li>
9568          * </ul></div></li>
9569          * <li><b>scope</b> : Object (Optional)<div class="sub-desc">The scope in
9570          * which to execute the callbacks: The "this" object for the callback function. If the <tt>url</tt>, or <tt>params</tt> options were
9571          * specified as functions from which to draw values, then this also serves as the scope for those function calls.
9572          * Defaults to the browser window.</div></li>
9573          * <li><b>timeout</b> : Number (Optional)<div class="sub-desc">The timeout in milliseconds to be used for this request. Defaults to 30 seconds.</div></li>
9574          * <li><b>form</b> : Element/HTMLElement/String (Optional)<div class="sub-desc">The <tt>&lt;form&gt;</tt>
9575          * Element or the id of the <tt>&lt;form&gt;</tt> to pull parameters from.</div></li>
9576          * <li><a id="request-option-isUpload"></a><b>isUpload</b> : Boolean (Optional)<div class="sub-desc"><b>Only meaningful when used
9577          * with the <tt>form</tt> option</b>.
9578          * <p>True if the form object is a file upload (will be set automatically if the form was
9579          * configured with <b><tt>enctype</tt></b> "multipart/form-data").</p>
9580          * <p>File uploads are not performed using normal "Ajax" techniques, that is they are <b>not</b>
9581          * performed using XMLHttpRequests. Instead the form is submitted in the standard manner with the
9582          * DOM <tt>&lt;form></tt> element temporarily modified to have its
9583          * <a href="http://www.w3.org/TR/REC-html40/present/frames.html#adef-target">target</a> set to refer
9584          * to a dynamically generated, hidden <tt>&lt;iframe></tt> which is inserted into the document
9585          * but removed after the return data has been gathered.</p>
9586          * <p>The server response is parsed by the browser to create the document for the IFRAME. If the
9587          * server is using JSON to send the return object, then the
9588          * <a href="http://www.w3.org/Protocols/rfc2616/rfc2616-sec14.html#sec14.17">Content-Type</a> header
9589          * must be set to "text/html" in order to tell the browser to insert the text unchanged into the document body.</p>
9590          * <p>The response text is retrieved from the document, and a fake XMLHttpRequest object
9591          * is created containing a <tt>responseText</tt> property in order to conform to the
9592          * requirements of event handlers and callbacks.</p>
9593          * <p>Be aware that file upload packets are sent with the content type <a href="http://www.faqs.org/rfcs/rfc2388.html">multipart/form</a>
9594          * and some server technologies (notably JEE) may require some custom processing in order to
9595          * retrieve parameter names and parameter values from the packet content.</p>
9596          * </div></li>
9597          * <li><b>headers</b> : Object (Optional)<div class="sub-desc">Request
9598          * headers to set for the request.</div></li>
9599          * <li><b>xmlData</b> : Object (Optional)<div class="sub-desc">XML document
9600          * to use for the post. Note: This will be used instead of params for the post
9601          * data. Any params will be appended to the URL.</div></li>
9602          * <li><b>jsonData</b> : Object/String (Optional)<div class="sub-desc">JSON
9603          * data to use as the post. Note: This will be used instead of params for the post
9604          * data. Any params will be appended to the URL.</div></li>
9605          * <li><b>disableCaching</b> : Boolean (Optional)<div class="sub-desc">True
9606          * to add a unique cache-buster param to GET requests.</div></li>
9607          * </ul></p>
9608          * <p>The options object may also contain any other property which might be needed to perform
9609          * postprocessing in a callback because it is passed to callback functions.</p>
9610          * @return {Number} transactionId The id of the server transaction. This may be used
9611          * to cancel the request.
9612          */
9613         request : function(o){
9614             var me = this;
9615             if(me.fireEvent(BEFOREREQUEST, me, o)){
9616                 if (o.el) {
9617                     if(!Ext.isEmpty(o.indicatorText)){
9618                         me.indicatorText = '<div class="loading-indicator">'+o.indicatorText+"</div>";
9619                     }
9620                     if(me.indicatorText) {
9621                         Ext.getDom(o.el).innerHTML = me.indicatorText;
9622                     }
9623                     o.success = (Ext.isFunction(o.success) ? o.success : function(){}).createInterceptor(function(response) {
9624                         Ext.getDom(o.el).innerHTML = response.responseText;
9625                     });
9626                 }
9627
9628                 var p = o.params,
9629                     url = o.url || me.url,
9630                     method,
9631                     cb = {success: me.handleResponse,
9632                           failure: me.handleFailure,
9633                           scope: me,
9634                           argument: {options: o},
9635                           timeout : o.timeout || me.timeout
9636                     },
9637                     form,
9638                     serForm;
9639
9640
9641                 if (Ext.isFunction(p)) {
9642                     p = p.call(o.scope||WINDOW, o);
9643                 }
9644
9645                 p = Ext.urlEncode(me.extraParams, Ext.isObject(p) ? Ext.urlEncode(p) : p);
9646
9647                 if (Ext.isFunction(url)) {
9648                     url = url.call(o.scope || WINDOW, o);
9649                 }
9650
9651                 if((form = Ext.getDom(o.form))){
9652                     url = url || form.action;
9653                      if(o.isUpload || /multipart\/form-data/i.test(form.getAttribute("enctype"))) {
9654                          return me.doFormUpload.call(me, o, p, url);
9655                      }
9656                     serForm = Ext.lib.Ajax.serializeForm(form);
9657                     p = p ? (p + '&' + serForm) : serForm;
9658                 }
9659
9660                 method = o.method || me.method || ((p || o.xmlData || o.jsonData) ? POST : GET);
9661
9662                 if(method === GET && (me.disableCaching && o.disableCaching !== false) || o.disableCaching === true){
9663                     var dcp = o.disableCachingParam || me.disableCachingParam;
9664                     url = Ext.urlAppend(url, dcp + '=' + (new Date().getTime()));
9665                 }
9666
9667                 o.headers = Ext.apply(o.headers || {}, me.defaultHeaders || {});
9668
9669                 if(o.autoAbort === true || me.autoAbort) {
9670                     me.abort();
9671                 }
9672
9673                 if((method == GET || o.xmlData || o.jsonData) && p){
9674                     url = Ext.urlAppend(url, p);
9675                     p = '';
9676                 }
9677                 return (me.transId = Ext.lib.Ajax.request(method, url, cb, p, o));
9678             }else{
9679                 return o.callback ? o.callback.apply(o.scope, [o,UNDEFINED,UNDEFINED]) : null;
9680             }
9681         },
9682
9683         /**
9684          * Determine whether this object has a request outstanding.
9685          * @param {Number} transactionId (Optional) defaults to the last transaction
9686          * @return {Boolean} True if there is an outstanding request.
9687          */
9688         isLoading : function(transId){
9689             return transId ? Ext.lib.Ajax.isCallInProgress(transId) : !! this.transId;
9690         },
9691
9692         /**
9693          * Aborts any outstanding request.
9694          * @param {Number} transactionId (Optional) defaults to the last transaction
9695          */
9696         abort : function(transId){
9697             if(transId || this.isLoading()){
9698                 Ext.lib.Ajax.abort(transId || this.transId);
9699             }
9700         },
9701
9702         // private
9703         handleResponse : function(response){
9704             this.transId = false;
9705             var options = response.argument.options;
9706             response.argument = options ? options.argument : null;
9707             this.fireEvent(REQUESTCOMPLETE, this, response, options);
9708             if(options.success){
9709                 options.success.call(options.scope, response, options);
9710             }
9711             if(options.callback){
9712                 options.callback.call(options.scope, options, true, response);
9713             }
9714         },
9715
9716         // private
9717         handleFailure : function(response, e){
9718             this.transId = false;
9719             var options = response.argument.options;
9720             response.argument = options ? options.argument : null;
9721             this.fireEvent(REQUESTEXCEPTION, this, response, options, e);
9722             if(options.failure){
9723                 options.failure.call(options.scope, response, options);
9724             }
9725             if(options.callback){
9726                 options.callback.call(options.scope, options, false, response);
9727             }
9728         },
9729
9730         // private
9731         doFormUpload : function(o, ps, url){
9732             var id = Ext.id(),
9733                 doc = document,
9734                 frame = doc.createElement('iframe'),
9735                 form = Ext.getDom(o.form),
9736                 hiddens = [],
9737                 hd,
9738                 encoding = 'multipart/form-data',
9739                 buf = {
9740                     target: form.target,
9741                     method: form.method,
9742                     encoding: form.encoding,
9743                     enctype: form.enctype,
9744                     action: form.action
9745                 };
9746
9747             /*
9748              * Originally this behaviour was modified for Opera 10 to apply the secure URL after
9749              * the frame had been added to the document. It seems this has since been corrected in
9750              * Opera so the behaviour has been reverted, the URL will be set before being added.
9751              */
9752             Ext.fly(frame).set({
9753                 id: id,
9754                 name: id,
9755                 cls: 'x-hidden',
9756                 src: Ext.SSL_SECURE_URL
9757             }); 
9758
9759             doc.body.appendChild(frame);
9760
9761             // This is required so that IE doesn't pop the response up in a new window.
9762             if(Ext.isIE){
9763                document.frames[id].name = id;
9764             }
9765
9766
9767             Ext.fly(form).set({
9768                 target: id,
9769                 method: POST,
9770                 enctype: encoding,
9771                 encoding: encoding,
9772                 action: url || buf.action
9773             });
9774
9775             // add dynamic params
9776             Ext.iterate(Ext.urlDecode(ps, false), function(k, v){
9777                 hd = doc.createElement('input');
9778                 Ext.fly(hd).set({
9779                     type: 'hidden',
9780                     value: v,
9781                     name: k
9782                 });
9783                 form.appendChild(hd);
9784                 hiddens.push(hd);
9785             });
9786
9787             function cb(){
9788                 var me = this,
9789                     // bogus response object
9790                     r = {responseText : '',
9791                          responseXML : null,
9792                          argument : o.argument},
9793                     doc,
9794                     firstChild;
9795
9796                 try{
9797                     doc = frame.contentWindow.document || frame.contentDocument || WINDOW.frames[id].document;
9798                     if(doc){
9799                         if(doc.body){
9800                             if(/textarea/i.test((firstChild = doc.body.firstChild || {}).tagName)){ // json response wrapped in textarea
9801                                 r.responseText = firstChild.value;
9802                             }else{
9803                                 r.responseText = doc.body.innerHTML;
9804                             }
9805                         }
9806                         //in IE the document may still have a body even if returns XML.
9807                         r.responseXML = doc.XMLDocument || doc;
9808                     }
9809                 }
9810                 catch(e) {}
9811
9812                 Ext.EventManager.removeListener(frame, LOAD, cb, me);
9813
9814                 me.fireEvent(REQUESTCOMPLETE, me, r, o);
9815
9816                 function runCallback(fn, scope, args){
9817                     if(Ext.isFunction(fn)){
9818                         fn.apply(scope, args);
9819                     }
9820                 }
9821
9822                 runCallback(o.success, o.scope, [r, o]);
9823                 runCallback(o.callback, o.scope, [o, true, r]);
9824
9825                 if(!me.debugUploads){
9826                     setTimeout(function(){Ext.removeNode(frame);}, 100);
9827                 }
9828             }
9829
9830             Ext.EventManager.on(frame, LOAD, cb, this);
9831             form.submit();
9832
9833             Ext.fly(form).set(buf);
9834             Ext.each(hiddens, function(h) {
9835                 Ext.removeNode(h);
9836             });
9837         }
9838     });
9839 })();
9840
9841 /**
9842  * @class Ext.Ajax
9843  * @extends Ext.data.Connection
9844  * <p>The global Ajax request class that provides a simple way to make Ajax requests
9845  * with maximum flexibility.</p>
9846  * <p>Since Ext.Ajax is a singleton, you can set common properties/events for it once
9847  * and override them at the request function level only if necessary.</p>
9848  * <p>Common <b>Properties</b> you may want to set are:<div class="mdetail-params"><ul>
9849  * <li><b><tt>{@link #method}</tt></b><p class="sub-desc"></p></li>
9850  * <li><b><tt>{@link #extraParams}</tt></b><p class="sub-desc"></p></li>
9851  * <li><b><tt>{@link #url}</tt></b><p class="sub-desc"></p></li>
9852  * </ul></div>
9853  * <pre><code>
9854 // Default headers to pass in every request
9855 Ext.Ajax.defaultHeaders = {
9856     'Powered-By': 'Ext'
9857 };
9858  * </code></pre>
9859  * </p>
9860  * <p>Common <b>Events</b> you may want to set are:<div class="mdetail-params"><ul>
9861  * <li><b><tt>{@link Ext.data.Connection#beforerequest beforerequest}</tt></b><p class="sub-desc"></p></li>
9862  * <li><b><tt>{@link Ext.data.Connection#requestcomplete requestcomplete}</tt></b><p class="sub-desc"></p></li>
9863  * <li><b><tt>{@link Ext.data.Connection#requestexception requestexception}</tt></b><p class="sub-desc"></p></li>
9864  * </ul></div>
9865  * <pre><code>
9866 // Example: show a spinner during all Ajax requests
9867 Ext.Ajax.on('beforerequest', this.showSpinner, this);
9868 Ext.Ajax.on('requestcomplete', this.hideSpinner, this);
9869 Ext.Ajax.on('requestexception', this.hideSpinner, this);
9870  * </code></pre>
9871  * </p>
9872  * <p>An example request:</p>
9873  * <pre><code>
9874 // Basic request
9875 Ext.Ajax.{@link Ext.data.Connection#request request}({
9876    url: 'foo.php',
9877    success: someFn,
9878    failure: otherFn,
9879    headers: {
9880        'my-header': 'foo'
9881    },
9882    params: { foo: 'bar' }
9883 });
9884
9885 // Simple ajax form submission
9886 Ext.Ajax.{@link Ext.data.Connection#request request}({
9887     form: 'some-form',
9888     params: 'foo=bar'
9889 });
9890  * </code></pre>
9891  * </p>
9892  * @singleton
9893  */
9894 Ext.Ajax = new Ext.data.Connection({
9895     /**
9896      * @cfg {String} url @hide
9897      */
9898     /**
9899      * @cfg {Object} extraParams @hide
9900      */
9901     /**
9902      * @cfg {Object} defaultHeaders @hide
9903      */
9904     /**
9905      * @cfg {String} method (Optional) @hide
9906      */
9907     /**
9908      * @cfg {Number} timeout (Optional) @hide
9909      */
9910     /**
9911      * @cfg {Boolean} autoAbort (Optional) @hide
9912      */
9913
9914     /**
9915      * @cfg {Boolean} disableCaching (Optional) @hide
9916      */
9917
9918     /**
9919      * @property  disableCaching
9920      * True to add a unique cache-buster param to GET requests. (defaults to true)
9921      * @type Boolean
9922      */
9923     /**
9924      * @property  url
9925      * The default URL to be used for requests to the server. (defaults to undefined)
9926      * If the server receives all requests through one URL, setting this once is easier than
9927      * entering it on every request.
9928      * @type String
9929      */
9930     /**
9931      * @property  extraParams
9932      * An object containing properties which are used as extra parameters to each request made
9933      * by this object (defaults to undefined). Session information and other data that you need
9934      * to pass with each request are commonly put here.
9935      * @type Object
9936      */
9937     /**
9938      * @property  defaultHeaders
9939      * An object containing request headers which are added to each request made by this object
9940      * (defaults to undefined).
9941      * @type Object
9942      */
9943     /**
9944      * @property  method
9945      * The default HTTP method to be used for requests. Note that this is case-sensitive and
9946      * should be all caps (defaults to undefined; if not set but params are present will use
9947      * <tt>"POST"</tt>, otherwise will use <tt>"GET"</tt>.)
9948      * @type String
9949      */
9950     /**
9951      * @property  timeout
9952      * The timeout in milliseconds to be used for requests. (defaults to 30000)
9953      * @type Number
9954      */
9955
9956     /**
9957      * @property  autoAbort
9958      * Whether a new request should abort any pending requests. (defaults to false)
9959      * @type Boolean
9960      */
9961     autoAbort : false,
9962
9963     /**
9964      * Serialize the passed form into a url encoded string
9965      * @param {String/HTMLElement} form
9966      * @return {String}
9967      */
9968     serializeForm : function(form){
9969         return Ext.lib.Ajax.serializeForm(form);
9970     }
9971 });
9972 /**
9973  * @class Ext.Updater
9974  * @extends Ext.util.Observable
9975  * Provides AJAX-style update capabilities for Element objects.  Updater can be used to {@link #update}
9976  * an {@link Ext.Element} once, or you can use {@link #startAutoRefresh} to set up an auto-updating
9977  * {@link Ext.Element Element} on a specific interval.<br><br>
9978  * Usage:<br>
9979  * <pre><code>
9980  * var el = Ext.get("foo"); // Get Ext.Element object
9981  * var mgr = el.getUpdater();
9982  * mgr.update({
9983         url: "http://myserver.com/index.php",
9984         params: {
9985             param1: "foo",
9986             param2: "bar"
9987         }
9988  * });
9989  * ...
9990  * mgr.formUpdate("myFormId", "http://myserver.com/index.php");
9991  * <br>
9992  * // or directly (returns the same Updater instance)
9993  * var mgr = new Ext.Updater("myElementId");
9994  * mgr.startAutoRefresh(60, "http://myserver.com/index.php");
9995  * mgr.on("update", myFcnNeedsToKnow);
9996  * <br>
9997  * // short handed call directly from the element object
9998  * Ext.get("foo").load({
9999         url: "bar.php",
10000         scripts: true,
10001         params: "param1=foo&amp;param2=bar",
10002         text: "Loading Foo..."
10003  * });
10004  * </code></pre>
10005  * @constructor
10006  * Create new Updater directly.
10007  * @param {Mixed} el The element to update
10008  * @param {Boolean} forceNew (optional) By default the constructor checks to see if the passed element already
10009  * has an Updater and if it does it returns the same instance. This will skip that check (useful for extending this class).
10010  */
10011 Ext.UpdateManager = Ext.Updater = Ext.extend(Ext.util.Observable,
10012 function() {
10013     var BEFOREUPDATE = "beforeupdate",
10014         UPDATE = "update",
10015         FAILURE = "failure";
10016
10017     // private
10018     function processSuccess(response){
10019         var me = this;
10020         me.transaction = null;
10021         if (response.argument.form && response.argument.reset) {
10022             try { // put in try/catch since some older FF releases had problems with this
10023                 response.argument.form.reset();
10024             } catch(e){}
10025         }
10026         if (me.loadScripts) {
10027             me.renderer.render(me.el, response, me,
10028                updateComplete.createDelegate(me, [response]));
10029         } else {
10030             me.renderer.render(me.el, response, me);
10031             updateComplete.call(me, response);
10032         }
10033     }
10034
10035     // private
10036     function updateComplete(response, type, success){
10037         this.fireEvent(type || UPDATE, this.el, response);
10038         if(Ext.isFunction(response.argument.callback)){
10039             response.argument.callback.call(response.argument.scope, this.el, Ext.isEmpty(success) ? true : false, response, response.argument.options);
10040         }
10041     }
10042
10043     // private
10044     function processFailure(response){
10045         updateComplete.call(this, response, FAILURE, !!(this.transaction = null));
10046     }
10047
10048     return {
10049         constructor: function(el, forceNew){
10050             var me = this;
10051             el = Ext.get(el);
10052             if(!forceNew && el.updateManager){
10053                 return el.updateManager;
10054             }
10055             /**
10056              * The Element object
10057              * @type Ext.Element
10058              */
10059             me.el = el;
10060             /**
10061              * Cached url to use for refreshes. Overwritten every time update() is called unless "discardUrl" param is set to true.
10062              * @type String
10063              */
10064             me.defaultUrl = null;
10065
10066             me.addEvents(
10067                 /**
10068                  * @event beforeupdate
10069                  * Fired before an update is made, return false from your handler and the update is cancelled.
10070                  * @param {Ext.Element} el
10071                  * @param {String/Object/Function} url
10072                  * @param {String/Object} params
10073                  */
10074                 BEFOREUPDATE,
10075                 /**
10076                  * @event update
10077                  * Fired after successful update is made.
10078                  * @param {Ext.Element} el
10079                  * @param {Object} oResponseObject The response Object
10080                  */
10081                 UPDATE,
10082                 /**
10083                  * @event failure
10084                  * Fired on update failure.
10085                  * @param {Ext.Element} el
10086                  * @param {Object} oResponseObject The response Object
10087                  */
10088                 FAILURE
10089             );
10090
10091             Ext.apply(me, Ext.Updater.defaults);
10092             /**
10093              * Blank page URL to use with SSL file uploads (defaults to {@link Ext.Updater.defaults#sslBlankUrl}).
10094              * @property sslBlankUrl
10095              * @type String
10096              */
10097             /**
10098              * Whether to append unique parameter on get request to disable caching (defaults to {@link Ext.Updater.defaults#disableCaching}).
10099              * @property disableCaching
10100              * @type Boolean
10101              */
10102             /**
10103              * Text for loading indicator (defaults to {@link Ext.Updater.defaults#indicatorText}).
10104              * @property indicatorText
10105              * @type String
10106              */
10107             /**
10108              * Whether to show indicatorText when loading (defaults to {@link Ext.Updater.defaults#showLoadIndicator}).
10109              * @property showLoadIndicator
10110              * @type String
10111              */
10112             /**
10113              * Timeout for requests or form posts in seconds (defaults to {@link Ext.Updater.defaults#timeout}).
10114              * @property timeout
10115              * @type Number
10116              */
10117             /**
10118              * True to process scripts in the output (defaults to {@link Ext.Updater.defaults#loadScripts}).
10119              * @property loadScripts
10120              * @type Boolean
10121              */
10122
10123             /**
10124              * Transaction object of the current executing transaction, or null if there is no active transaction.
10125              */
10126             me.transaction = null;
10127             /**
10128              * Delegate for refresh() prebound to "this", use myUpdater.refreshDelegate.createCallback(arg1, arg2) to bind arguments
10129              * @type Function
10130              */
10131             me.refreshDelegate = me.refresh.createDelegate(me);
10132             /**
10133              * Delegate for update() prebound to "this", use myUpdater.updateDelegate.createCallback(arg1, arg2) to bind arguments
10134              * @type Function
10135              */
10136             me.updateDelegate = me.update.createDelegate(me);
10137             /**
10138              * Delegate for formUpdate() prebound to "this", use myUpdater.formUpdateDelegate.createCallback(arg1, arg2) to bind arguments
10139              * @type Function
10140              */
10141             me.formUpdateDelegate = (me.formUpdate || function(){}).createDelegate(me);
10142
10143             /**
10144              * The renderer for this Updater (defaults to {@link Ext.Updater.BasicRenderer}).
10145              */
10146             me.renderer = me.renderer || me.getDefaultRenderer();
10147
10148             Ext.Updater.superclass.constructor.call(me);
10149         },
10150
10151         /**
10152          * Sets the content renderer for this Updater. See {@link Ext.Updater.BasicRenderer#render} for more details.
10153          * @param {Object} renderer The object implementing the render() method
10154          */
10155         setRenderer : function(renderer){
10156             this.renderer = renderer;
10157         },
10158
10159         /**
10160          * Returns the current content renderer for this Updater. See {@link Ext.Updater.BasicRenderer#render} for more details.
10161          * @return {Object}
10162          */
10163         getRenderer : function(){
10164            return this.renderer;
10165         },
10166
10167         /**
10168          * This is an overrideable method which returns a reference to a default
10169          * renderer class if none is specified when creating the Ext.Updater.
10170          * Defaults to {@link Ext.Updater.BasicRenderer}
10171          */
10172         getDefaultRenderer: function() {
10173             return new Ext.Updater.BasicRenderer();
10174         },
10175
10176         /**
10177          * Sets the default URL used for updates.
10178          * @param {String/Function} defaultUrl The url or a function to call to get the url
10179          */
10180         setDefaultUrl : function(defaultUrl){
10181             this.defaultUrl = defaultUrl;
10182         },
10183
10184         /**
10185          * Get the Element this Updater is bound to
10186          * @return {Ext.Element} The element
10187          */
10188         getEl : function(){
10189             return this.el;
10190         },
10191
10192         /**
10193          * Performs an <b>asynchronous</b> request, updating this element with the response.
10194          * If params are specified it uses POST, otherwise it uses GET.<br><br>
10195          * <b>Note:</b> Due to the asynchronous nature of remote server requests, the Element
10196          * will not have been fully updated when the function returns. To post-process the returned
10197          * data, use the callback option, or an <b><code>update</code></b> event handler.
10198          * @param {Object} options A config object containing any of the following options:<ul>
10199          * <li>url : <b>String/Function</b><p class="sub-desc">The URL to request or a function which
10200          * <i>returns</i> the URL (defaults to the value of {@link Ext.Ajax#url} if not specified).</p></li>
10201          * <li>method : <b>String</b><p class="sub-desc">The HTTP method to
10202          * use. Defaults to POST if the <code>params</code> argument is present, otherwise GET.</p></li>
10203          * <li>params : <b>String/Object/Function</b><p class="sub-desc">The
10204          * parameters to pass to the server (defaults to none). These may be specified as a url-encoded
10205          * string, or as an object containing properties which represent parameters,
10206          * or as a function, which returns such an object.</p></li>
10207          * <li>scripts : <b>Boolean</b><p class="sub-desc">If <code>true</code>
10208          * any &lt;script&gt; tags embedded in the response text will be extracted
10209          * and executed (defaults to {@link Ext.Updater.defaults#loadScripts}). If this option is specified,
10210          * the callback will be called <i>after</i> the execution of the scripts.</p></li>
10211          * <li>callback : <b>Function</b><p class="sub-desc">A function to
10212          * be called when the response from the server arrives. The following
10213          * parameters are passed:<ul>
10214          * <li><b>el</b> : Ext.Element<p class="sub-desc">The Element being updated.</p></li>
10215          * <li><b>success</b> : Boolean<p class="sub-desc">True for success, false for failure.</p></li>
10216          * <li><b>response</b> : XMLHttpRequest<p class="sub-desc">The XMLHttpRequest which processed the update.</p></li>
10217          * <li><b>options</b> : Object<p class="sub-desc">The config object passed to the update call.</p></li></ul>
10218          * </p></li>
10219          * <li>scope : <b>Object</b><p class="sub-desc">The scope in which
10220          * to execute the callback (The callback's <code>this</code> reference.) If the
10221          * <code>params</code> argument is a function, this scope is used for that function also.</p></li>
10222          * <li>discardUrl : <b>Boolean</b><p class="sub-desc">By default, the URL of this request becomes
10223          * the default URL for this Updater object, and will be subsequently used in {@link #refresh}
10224          * calls.  To bypass this behavior, pass <code>discardUrl:true</code> (defaults to false).</p></li>
10225          * <li>timeout : <b>Number</b><p class="sub-desc">The number of seconds to wait for a response before
10226          * timing out (defaults to {@link Ext.Updater.defaults#timeout}).</p></li>
10227          * <li>text : <b>String</b><p class="sub-desc">The text to use as the innerHTML of the
10228          * {@link Ext.Updater.defaults#indicatorText} div (defaults to 'Loading...').  To replace the entire div, not
10229          * just the text, override {@link Ext.Updater.defaults#indicatorText} directly.</p></li>
10230          * <li>nocache : <b>Boolean</b><p class="sub-desc">Only needed for GET
10231          * requests, this option causes an extra, auto-generated parameter to be appended to the request
10232          * to defeat caching (defaults to {@link Ext.Updater.defaults#disableCaching}).</p></li></ul>
10233          * <p>
10234          * For example:
10235     <pre><code>
10236     um.update({
10237         url: "your-url.php",
10238         params: {param1: "foo", param2: "bar"}, // or a URL encoded string
10239         callback: yourFunction,
10240         scope: yourObject, //(optional scope)
10241         discardUrl: true,
10242         nocache: true,
10243         text: "Loading...",
10244         timeout: 60,
10245         scripts: false // Save time by avoiding RegExp execution.
10246     });
10247     </code></pre>
10248          */
10249         update : function(url, params, callback, discardUrl){
10250             var me = this,
10251                 cfg,
10252                 callerScope;
10253
10254             if(me.fireEvent(BEFOREUPDATE, me.el, url, params) !== false){
10255                 if(Ext.isObject(url)){ // must be config object
10256                     cfg = url;
10257                     url = cfg.url;
10258                     params = params || cfg.params;
10259                     callback = callback || cfg.callback;
10260                     discardUrl = discardUrl || cfg.discardUrl;
10261                     callerScope = cfg.scope;
10262                     if(!Ext.isEmpty(cfg.nocache)){me.disableCaching = cfg.nocache;};
10263                     if(!Ext.isEmpty(cfg.text)){me.indicatorText = '<div class="loading-indicator">'+cfg.text+"</div>";};
10264                     if(!Ext.isEmpty(cfg.scripts)){me.loadScripts = cfg.scripts;};
10265                     if(!Ext.isEmpty(cfg.timeout)){me.timeout = cfg.timeout;};
10266                 }
10267                 me.showLoading();
10268
10269                 if(!discardUrl){
10270                     me.defaultUrl = url;
10271                 }
10272                 if(Ext.isFunction(url)){
10273                     url = url.call(me);
10274                 }
10275
10276                 var o = Ext.apply({}, {
10277                     url : url,
10278                     params: (Ext.isFunction(params) && callerScope) ? params.createDelegate(callerScope) : params,
10279                     success: processSuccess,
10280                     failure: processFailure,
10281                     scope: me,
10282                     callback: undefined,
10283                     timeout: (me.timeout*1000),
10284                     disableCaching: me.disableCaching,
10285                     argument: {
10286                         "options": cfg,
10287                         "url": url,
10288                         "form": null,
10289                         "callback": callback,
10290                         "scope": callerScope || window,
10291                         "params": params
10292                     }
10293                 }, cfg);
10294
10295                 me.transaction = Ext.Ajax.request(o);
10296             }
10297         },
10298
10299         /**
10300          * <p>Performs an asynchronous form post, updating this element with the response. If the form has the attribute
10301          * enctype="<a href="http://www.faqs.org/rfcs/rfc2388.html">multipart/form-data</a>", it assumes it's a file upload.
10302          * Uses this.sslBlankUrl for SSL file uploads to prevent IE security warning.</p>
10303          * <p>File uploads are not performed using normal "Ajax" techniques, that is they are <b>not</b>
10304          * performed using XMLHttpRequests. Instead the form is submitted in the standard manner with the
10305          * DOM <code>&lt;form></code> element temporarily modified to have its
10306          * <a href="http://www.w3.org/TR/REC-html40/present/frames.html#adef-target">target</a> set to refer
10307          * to a dynamically generated, hidden <code>&lt;iframe></code> which is inserted into the document
10308          * but removed after the return data has been gathered.</p>
10309          * <p>Be aware that file upload packets, sent with the content type <a href="http://www.faqs.org/rfcs/rfc2388.html">multipart/form-data</a>
10310          * and some server technologies (notably JEE) may require some custom processing in order to
10311          * retrieve parameter names and parameter values from the packet content.</p>
10312          * @param {String/HTMLElement} form The form Id or form element
10313          * @param {String} url (optional) The url to pass the form to. If omitted the action attribute on the form will be used.
10314          * @param {Boolean} reset (optional) Whether to try to reset the form after the update
10315          * @param {Function} callback (optional) Callback when transaction is complete. The following
10316          * parameters are passed:<ul>
10317          * <li><b>el</b> : Ext.Element<p class="sub-desc">The Element being updated.</p></li>
10318          * <li><b>success</b> : Boolean<p class="sub-desc">True for success, false for failure.</p></li>
10319          * <li><b>response</b> : XMLHttpRequest<p class="sub-desc">The XMLHttpRequest which processed the update.</p></li></ul>
10320          */
10321         formUpdate : function(form, url, reset, callback){
10322             var me = this;
10323             if(me.fireEvent(BEFOREUPDATE, me.el, form, url) !== false){
10324                 if(Ext.isFunction(url)){
10325                     url = url.call(me);
10326                 }
10327                 form = Ext.getDom(form);
10328                 me.transaction = Ext.Ajax.request({
10329                     form: form,
10330                     url:url,
10331                     success: processSuccess,
10332                     failure: processFailure,
10333                     scope: me,
10334                     timeout: (me.timeout*1000),
10335                     argument: {
10336                         "url": url,
10337                         "form": form,
10338                         "callback": callback,
10339                         "reset": reset
10340                     }
10341                 });
10342                 me.showLoading.defer(1, me);
10343             }
10344         },
10345
10346         /**
10347          * Set this element to auto refresh.  Can be canceled by calling {@link #stopAutoRefresh}.
10348          * @param {Number} interval How often to update (in seconds).
10349          * @param {String/Object/Function} url (optional) The url for this request, a config object in the same format
10350          * supported by {@link #load}, or a function to call to get the url (defaults to the last used url).  Note that while
10351          * the url used in a load call can be reused by this method, other load config options will not be reused and must be
10352          * sepcified as part of a config object passed as this paramter if needed.
10353          * @param {String/Object} params (optional) The parameters to pass as either a url encoded string
10354          * "&param1=1&param2=2" or as an object {param1: 1, param2: 2}
10355          * @param {Function} callback (optional) Callback when transaction is complete - called with signature (oElement, bSuccess)
10356          * @param {Boolean} refreshNow (optional) Whether to execute the refresh now, or wait the interval
10357          */
10358         startAutoRefresh : function(interval, url, params, callback, refreshNow){
10359             var me = this;
10360             if(refreshNow){
10361                 me.update(url || me.defaultUrl, params, callback, true);
10362             }
10363             if(me.autoRefreshProcId){
10364                 clearInterval(me.autoRefreshProcId);
10365             }
10366             me.autoRefreshProcId = setInterval(me.update.createDelegate(me, [url || me.defaultUrl, params, callback, true]), interval * 1000);
10367         },
10368
10369         /**
10370          * Stop auto refresh on this element.
10371          */
10372         stopAutoRefresh : function(){
10373             if(this.autoRefreshProcId){
10374                 clearInterval(this.autoRefreshProcId);
10375                 delete this.autoRefreshProcId;
10376             }
10377         },
10378
10379         /**
10380          * Returns true if the Updater is currently set to auto refresh its content (see {@link #startAutoRefresh}), otherwise false.
10381          */
10382         isAutoRefreshing : function(){
10383            return !!this.autoRefreshProcId;
10384         },
10385
10386         /**
10387          * Display the element's "loading" state. By default, the element is updated with {@link #indicatorText}. This
10388          * method may be overridden to perform a custom action while this Updater is actively updating its contents.
10389          */
10390         showLoading : function(){
10391             if(this.showLoadIndicator){
10392                 this.el.dom.innerHTML = this.indicatorText;
10393             }
10394         },
10395
10396         /**
10397          * Aborts the currently executing transaction, if any.
10398          */
10399         abort : function(){
10400             if(this.transaction){
10401                 Ext.Ajax.abort(this.transaction);
10402             }
10403         },
10404
10405         /**
10406          * Returns true if an update is in progress, otherwise false.
10407          * @return {Boolean}
10408          */
10409         isUpdating : function(){
10410             return this.transaction ? Ext.Ajax.isLoading(this.transaction) : false;
10411         },
10412
10413         /**
10414          * Refresh the element with the last used url or defaultUrl. If there is no url, it returns immediately
10415          * @param {Function} callback (optional) Callback when transaction is complete - called with signature (oElement, bSuccess)
10416          */
10417         refresh : function(callback){
10418             if(this.defaultUrl){
10419                 this.update(this.defaultUrl, null, callback, true);
10420             }
10421         }
10422     }
10423 }());
10424
10425 /**
10426  * @class Ext.Updater.defaults
10427  * The defaults collection enables customizing the default properties of Updater
10428  */
10429 Ext.Updater.defaults = {
10430    /**
10431      * Timeout for requests or form posts in seconds (defaults to 30 seconds).
10432      * @type Number
10433      */
10434     timeout : 30,
10435     /**
10436      * True to append a unique parameter to GET requests to disable caching (defaults to false).
10437      * @type Boolean
10438      */
10439     disableCaching : false,
10440     /**
10441      * Whether or not to show {@link #indicatorText} during loading (defaults to true).
10442      * @type Boolean
10443      */
10444     showLoadIndicator : true,
10445     /**
10446      * Text for loading indicator (defaults to '&lt;div class="loading-indicator"&gt;Loading...&lt;/div&gt;').
10447      * @type String
10448      */
10449     indicatorText : '<div class="loading-indicator">Loading...</div>',
10450      /**
10451      * True to process scripts by default (defaults to false).
10452      * @type Boolean
10453      */
10454     loadScripts : false,
10455     /**
10456     * Blank page URL to use with SSL file uploads (defaults to {@link Ext#SSL_SECURE_URL} if set, or "javascript:false").
10457     * @type String
10458     */
10459     sslBlankUrl : Ext.SSL_SECURE_URL
10460 };
10461
10462
10463 /**
10464  * Static convenience method. <b>This method is deprecated in favor of el.load({url:'foo.php', ...})</b>.
10465  * Usage:
10466  * <pre><code>Ext.Updater.updateElement("my-div", "stuff.php");</code></pre>
10467  * @param {Mixed} el The element to update
10468  * @param {String} url The url
10469  * @param {String/Object} params (optional) Url encoded param string or an object of name/value pairs
10470  * @param {Object} options (optional) A config object with any of the Updater properties you want to set - for
10471  * example: {disableCaching:true, indicatorText: "Loading data..."}
10472  * @static
10473  * @deprecated
10474  * @member Ext.Updater
10475  */
10476 Ext.Updater.updateElement = function(el, url, params, options){
10477     var um = Ext.get(el).getUpdater();
10478     Ext.apply(um, options);
10479     um.update(url, params, options ? options.callback : null);
10480 };
10481
10482 /**
10483  * @class Ext.Updater.BasicRenderer
10484  * <p>This class is a base class implementing a simple render method which updates an element using results from an Ajax request.</p>
10485  * <p>The BasicRenderer updates the element's innerHTML with the responseText. To perform a custom render (i.e. XML or JSON processing),
10486  * create an object with a conforming {@link #render} method and pass it to setRenderer on the Updater.</p>
10487  */
10488 Ext.Updater.BasicRenderer = function(){};
10489
10490 Ext.Updater.BasicRenderer.prototype = {
10491     /**
10492      * This method is called when an Ajax response is received, and an Element needs updating.
10493      * @param {Ext.Element} el The element being rendered
10494      * @param {Object} xhr The XMLHttpRequest object
10495      * @param {Updater} updateManager The calling update manager
10496      * @param {Function} callback A callback that will need to be called if loadScripts is true on the Updater
10497      */
10498      render : function(el, response, updateManager, callback){
10499         el.update(response.responseText, updateManager.loadScripts, callback);
10500     }
10501 };/**
10502  * @class Date
10503  *
10504  * The date parsing and formatting syntax contains a subset of
10505  * <a href="http://www.php.net/date">PHP's date() function</a>, and the formats that are
10506  * supported will provide results equivalent to their PHP versions.
10507  *
10508  * The following is a list of all currently supported formats:
10509  * <pre>
10510 Format  Description                                                               Example returned values
10511 ------  -----------------------------------------------------------------------   -----------------------
10512   d     Day of the month, 2 digits with leading zeros                             01 to 31
10513   D     A short textual representation of the day of the week                     Mon to Sun
10514   j     Day of the month without leading zeros                                    1 to 31
10515   l     A full textual representation of the day of the week                      Sunday to Saturday
10516   N     ISO-8601 numeric representation of the day of the week                    1 (for Monday) through 7 (for Sunday)
10517   S     English ordinal suffix for the day of the month, 2 characters             st, nd, rd or th. Works well with j
10518   w     Numeric representation of the day of the week                             0 (for Sunday) to 6 (for Saturday)
10519   z     The day of the year (starting from 0)                                     0 to 364 (365 in leap years)
10520   W     ISO-8601 week number of year, weeks starting on Monday                    01 to 53
10521   F     A full textual representation of a month, such as January or March        January to December
10522   m     Numeric representation of a month, with leading zeros                     01 to 12
10523   M     A short textual representation of a month                                 Jan to Dec
10524   n     Numeric representation of a month, without leading zeros                  1 to 12
10525   t     Number of days in the given month                                         28 to 31
10526   L     Whether it's a leap year                                                  1 if it is a leap year, 0 otherwise.
10527   o     ISO-8601 year number (identical to (Y), but if the ISO week number (W)    Examples: 1998 or 2004
10528         belongs to the previous or next year, that year is used instead)
10529   Y     A full numeric representation of a year, 4 digits                         Examples: 1999 or 2003
10530   y     A two digit representation of a year                                      Examples: 99 or 03
10531   a     Lowercase Ante meridiem and Post meridiem                                 am or pm
10532   A     Uppercase Ante meridiem and Post meridiem                                 AM or PM
10533   g     12-hour format of an hour without leading zeros                           1 to 12
10534   G     24-hour format of an hour without leading zeros                           0 to 23
10535   h     12-hour format of an hour with leading zeros                              01 to 12
10536   H     24-hour format of an hour with leading zeros                              00 to 23
10537   i     Minutes, with leading zeros                                               00 to 59
10538   s     Seconds, with leading zeros                                               00 to 59
10539   u     Decimal fraction of a second                                              Examples:
10540         (minimum 1 digit, arbitrary number of digits allowed)                     001 (i.e. 0.001s) or
10541                                                                                   100 (i.e. 0.100s) or
10542                                                                                   999 (i.e. 0.999s) or
10543                                                                                   999876543210 (i.e. 0.999876543210s)
10544   O     Difference to Greenwich time (GMT) in hours and minutes                   Example: +1030
10545   P     Difference to Greenwich time (GMT) with colon between hours and minutes   Example: -08:00
10546   T     Timezone abbreviation of the machine running the code                     Examples: EST, MDT, PDT ...
10547   Z     Timezone offset in seconds (negative if west of UTC, positive if east)    -43200 to 50400
10548   c     ISO 8601 date
10549         Notes:                                                                    Examples:
10550         1) If unspecified, the month / day defaults to the current month / day,   1991 or
10551            the time defaults to midnight, while the timezone defaults to the      1992-10 or
10552            browser's timezone. If a time is specified, it must include both hours 1993-09-20 or
10553            and minutes. The "T" delimiter, seconds, milliseconds and timezone     1994-08-19T16:20+01:00 or
10554            are optional.                                                          1995-07-18T17:21:28-02:00 or
10555         2) The decimal fraction of a second, if specified, must contain at        1996-06-17T18:22:29.98765+03:00 or
10556            least 1 digit (there is no limit to the maximum number                 1997-05-16T19:23:30,12345-0400 or
10557            of digits allowed), and may be delimited by either a '.' or a ','      1998-04-15T20:24:31.2468Z or
10558         Refer to the examples on the right for the various levels of              1999-03-14T20:24:32Z or
10559         date-time granularity which are supported, or see                         2000-02-13T21:25:33
10560         http://www.w3.org/TR/NOTE-datetime for more info.                         2001-01-12 22:26:34
10561   U     Seconds since the Unix Epoch (January 1 1970 00:00:00 GMT)                1193432466 or -2138434463
10562   M$    Microsoft AJAX serialized dates                                           \/Date(1238606590509)\/ (i.e. UTC milliseconds since epoch) or
10563                                                                                   \/Date(1238606590509+0800)\/
10564 </pre>
10565  *
10566  * Example usage (note that you must escape format specifiers with '\\' to render them as character literals):
10567  * <pre><code>
10568 // Sample date:
10569 // 'Wed Jan 10 2007 15:05:01 GMT-0600 (Central Standard Time)'
10570
10571 var dt = new Date('1/10/2007 03:05:01 PM GMT-0600');
10572 document.write(dt.format('Y-m-d'));                           // 2007-01-10
10573 document.write(dt.format('F j, Y, g:i a'));                   // January 10, 2007, 3:05 pm
10574 document.write(dt.format('l, \\t\\he jS \\of F Y h:i:s A'));  // Wednesday, the 10th of January 2007 03:05:01 PM
10575 </code></pre>
10576  *
10577  * Here are some standard date/time patterns that you might find helpful.  They
10578  * are not part of the source of Date.js, but to use them you can simply copy this
10579  * block of code into any script that is included after Date.js and they will also become
10580  * globally available on the Date object.  Feel free to add or remove patterns as needed in your code.
10581  * <pre><code>
10582 Date.patterns = {
10583     ISO8601Long:"Y-m-d H:i:s",
10584     ISO8601Short:"Y-m-d",
10585     ShortDate: "n/j/Y",
10586     LongDate: "l, F d, Y",
10587     FullDateTime: "l, F d, Y g:i:s A",
10588     MonthDay: "F d",
10589     ShortTime: "g:i A",
10590     LongTime: "g:i:s A",
10591     SortableDateTime: "Y-m-d\\TH:i:s",
10592     UniversalSortableDateTime: "Y-m-d H:i:sO",
10593     YearMonth: "F, Y"
10594 };
10595 </code></pre>
10596  *
10597  * Example usage:
10598  * <pre><code>
10599 var dt = new Date();
10600 document.write(dt.format(Date.patterns.ShortDate));
10601 </code></pre>
10602  * <p>Developer-written, custom formats may be used by supplying both a formatting and a parsing function
10603  * which perform to specialized requirements. The functions are stored in {@link #parseFunctions} and {@link #formatFunctions}.</p>
10604  */
10605
10606 /*
10607  * Most of the date-formatting functions below are the excellent work of Baron Schwartz.
10608  * (see http://www.xaprb.com/blog/2005/12/12/javascript-closures-for-runtime-efficiency/)
10609  * They generate precompiled functions from format patterns instead of parsing and
10610  * processing each pattern every time a date is formatted. These functions are available
10611  * on every Date object.
10612  */
10613
10614 (function() {
10615
10616 /**
10617  * Global flag which determines if strict date parsing should be used.
10618  * Strict date parsing will not roll-over invalid dates, which is the
10619  * default behaviour of javascript Date objects.
10620  * (see {@link #parseDate} for more information)
10621  * Defaults to <tt>false</tt>.
10622  * @static
10623  * @type Boolean
10624 */
10625 Date.useStrict = false;
10626
10627
10628 // create private copy of Ext's String.format() method
10629 // - to remove unnecessary dependency
10630 // - to resolve namespace conflict with M$-Ajax's implementation
10631 function xf(format) {
10632     var args = Array.prototype.slice.call(arguments, 1);
10633     return format.replace(/\{(\d+)\}/g, function(m, i) {
10634         return args[i];
10635     });
10636 }
10637
10638
10639 // private
10640 Date.formatCodeToRegex = function(character, currentGroup) {
10641     // Note: currentGroup - position in regex result array (see notes for Date.parseCodes below)
10642     var p = Date.parseCodes[character];
10643
10644     if (p) {
10645       p = typeof p == 'function'? p() : p;
10646       Date.parseCodes[character] = p; // reassign function result to prevent repeated execution
10647     }
10648
10649     return p ? Ext.applyIf({
10650       c: p.c ? xf(p.c, currentGroup || "{0}") : p.c
10651     }, p) : {
10652         g:0,
10653         c:null,
10654         s:Ext.escapeRe(character) // treat unrecognised characters as literals
10655     }
10656 };
10657
10658 // private shorthand for Date.formatCodeToRegex since we'll be using it fairly often
10659 var $f = Date.formatCodeToRegex;
10660
10661 Ext.apply(Date, {
10662     /**
10663      * <p>An object hash in which each property is a date parsing function. The property name is the
10664      * format string which that function parses.</p>
10665      * <p>This object is automatically populated with date parsing functions as
10666      * date formats are requested for Ext standard formatting strings.</p>
10667      * <p>Custom parsing functions may be inserted into this object, keyed by a name which from then on
10668      * may be used as a format string to {@link #parseDate}.<p>
10669      * <p>Example:</p><pre><code>
10670 Date.parseFunctions['x-date-format'] = myDateParser;
10671 </code></pre>
10672      * <p>A parsing function should return a Date object, and is passed the following parameters:<div class="mdetail-params"><ul>
10673      * <li><code>date</code> : String<div class="sub-desc">The date string to parse.</div></li>
10674      * <li><code>strict</code> : Boolean<div class="sub-desc">True to validate date strings while parsing
10675      * (i.e. prevent javascript Date "rollover") (The default must be false).
10676      * Invalid date strings should return null when parsed.</div></li>
10677      * </ul></div></p>
10678      * <p>To enable Dates to also be <i>formatted</i> according to that format, a corresponding
10679      * formatting function must be placed into the {@link #formatFunctions} property.
10680      * @property parseFunctions
10681      * @static
10682      * @type Object
10683      */
10684     parseFunctions: {
10685         "M$": function(input, strict) {
10686             // note: the timezone offset is ignored since the M$ Ajax server sends
10687             // a UTC milliseconds-since-Unix-epoch value (negative values are allowed)
10688             var re = new RegExp('\\/Date\\(([-+])?(\\d+)(?:[+-]\\d{4})?\\)\\/');
10689             var r = (input || '').match(re);
10690             return r? new Date(((r[1] || '') + r[2]) * 1) : null;
10691         }
10692     },
10693     parseRegexes: [],
10694
10695     /**
10696      * <p>An object hash in which each property is a date formatting function. The property name is the
10697      * format string which corresponds to the produced formatted date string.</p>
10698      * <p>This object is automatically populated with date formatting functions as
10699      * date formats are requested for Ext standard formatting strings.</p>
10700      * <p>Custom formatting functions may be inserted into this object, keyed by a name which from then on
10701      * may be used as a format string to {@link #format}. Example:</p><pre><code>
10702 Date.formatFunctions['x-date-format'] = myDateFormatter;
10703 </code></pre>
10704      * <p>A formatting function should return a string representation of the passed Date object, and is passed the following parameters:<div class="mdetail-params"><ul>
10705      * <li><code>date</code> : Date<div class="sub-desc">The Date to format.</div></li>
10706      * </ul></div></p>
10707      * <p>To enable date strings to also be <i>parsed</i> according to that format, a corresponding
10708      * parsing function must be placed into the {@link #parseFunctions} property.
10709      * @property formatFunctions
10710      * @static
10711      * @type Object
10712      */
10713     formatFunctions: {
10714         "M$": function() {
10715             // UTC milliseconds since Unix epoch (M$-AJAX serialized date format (MRSF))
10716             return '\\/Date(' + this.getTime() + ')\\/';
10717         }
10718     },
10719
10720     y2kYear : 50,
10721
10722     /**
10723      * Date interval constant
10724      * @static
10725      * @type String
10726      */
10727     MILLI : "ms",
10728
10729     /**
10730      * Date interval constant
10731      * @static
10732      * @type String
10733      */
10734     SECOND : "s",
10735
10736     /**
10737      * Date interval constant
10738      * @static
10739      * @type String
10740      */
10741     MINUTE : "mi",
10742
10743     /** Date interval constant
10744      * @static
10745      * @type String
10746      */
10747     HOUR : "h",
10748
10749     /**
10750      * Date interval constant
10751      * @static
10752      * @type String
10753      */
10754     DAY : "d",
10755
10756     /**
10757      * Date interval constant
10758      * @static
10759      * @type String
10760      */
10761     MONTH : "mo",
10762
10763     /**
10764      * Date interval constant
10765      * @static
10766      * @type String
10767      */
10768     YEAR : "y",
10769
10770     /**
10771      * <p>An object hash containing default date values used during date parsing.</p>
10772      * <p>The following properties are available:<div class="mdetail-params"><ul>
10773      * <li><code>y</code> : Number<div class="sub-desc">The default year value. (defaults to undefined)</div></li>
10774      * <li><code>m</code> : Number<div class="sub-desc">The default 1-based month value. (defaults to undefined)</div></li>
10775      * <li><code>d</code> : Number<div class="sub-desc">The default day value. (defaults to undefined)</div></li>
10776      * <li><code>h</code> : Number<div class="sub-desc">The default hour value. (defaults to undefined)</div></li>
10777      * <li><code>i</code> : Number<div class="sub-desc">The default minute value. (defaults to undefined)</div></li>
10778      * <li><code>s</code> : Number<div class="sub-desc">The default second value. (defaults to undefined)</div></li>
10779      * <li><code>ms</code> : Number<div class="sub-desc">The default millisecond value. (defaults to undefined)</div></li>
10780      * </ul></div></p>
10781      * <p>Override these properties to customize the default date values used by the {@link #parseDate} method.</p>
10782      * <p><b>Note: In countries which experience Daylight Saving Time (i.e. DST), the <tt>h</tt>, <tt>i</tt>, <tt>s</tt>
10783      * and <tt>ms</tt> properties may coincide with the exact time in which DST takes effect.
10784      * It is the responsiblity of the developer to account for this.</b></p>
10785      * Example Usage:
10786      * <pre><code>
10787 // set default day value to the first day of the month
10788 Date.defaults.d = 1;
10789
10790 // parse a February date string containing only year and month values.
10791 // setting the default day value to 1 prevents weird date rollover issues
10792 // when attempting to parse the following date string on, for example, March 31st 2009.
10793 Date.parseDate('2009-02', 'Y-m'); // returns a Date object representing February 1st 2009
10794 </code></pre>
10795      * @property defaults
10796      * @static
10797      * @type Object
10798      */
10799     defaults: {},
10800
10801     /**
10802      * An array of textual day names.
10803      * Override these values for international dates.
10804      * Example:
10805      * <pre><code>
10806 Date.dayNames = [
10807     'SundayInYourLang',
10808     'MondayInYourLang',
10809     ...
10810 ];
10811 </code></pre>
10812      * @type Array
10813      * @static
10814      */
10815     dayNames : [
10816         "Sunday",
10817         "Monday",
10818         "Tuesday",
10819         "Wednesday",
10820         "Thursday",
10821         "Friday",
10822         "Saturday"
10823     ],
10824
10825     /**
10826      * An array of textual month names.
10827      * Override these values for international dates.
10828      * Example:
10829      * <pre><code>
10830 Date.monthNames = [
10831     'JanInYourLang',
10832     'FebInYourLang',
10833     ...
10834 ];
10835 </code></pre>
10836      * @type Array
10837      * @static
10838      */
10839     monthNames : [
10840         "January",
10841         "February",
10842         "March",
10843         "April",
10844         "May",
10845         "June",
10846         "July",
10847         "August",
10848         "September",
10849         "October",
10850         "November",
10851         "December"
10852     ],
10853
10854     /**
10855      * An object hash of zero-based javascript month numbers (with short month names as keys. note: keys are case-sensitive).
10856      * Override these values for international dates.
10857      * Example:
10858      * <pre><code>
10859 Date.monthNumbers = {
10860     'ShortJanNameInYourLang':0,
10861     'ShortFebNameInYourLang':1,
10862     ...
10863 };
10864 </code></pre>
10865      * @type Object
10866      * @static
10867      */
10868     monthNumbers : {
10869         Jan:0,
10870         Feb:1,
10871         Mar:2,
10872         Apr:3,
10873         May:4,
10874         Jun:5,
10875         Jul:6,
10876         Aug:7,
10877         Sep:8,
10878         Oct:9,
10879         Nov:10,
10880         Dec:11
10881     },
10882
10883     /**
10884      * Get the short month name for the given month number.
10885      * Override this function for international dates.
10886      * @param {Number} month A zero-based javascript month number.
10887      * @return {String} The short month name.
10888      * @static
10889      */
10890     getShortMonthName : function(month) {
10891         return Date.monthNames[month].substring(0, 3);
10892     },
10893
10894     /**
10895      * Get the short day name for the given day number.
10896      * Override this function for international dates.
10897      * @param {Number} day A zero-based javascript day number.
10898      * @return {String} The short day name.
10899      * @static
10900      */
10901     getShortDayName : function(day) {
10902         return Date.dayNames[day].substring(0, 3);
10903     },
10904
10905     /**
10906      * Get the zero-based javascript month number for the given short/full month name.
10907      * Override this function for international dates.
10908      * @param {String} name The short/full month name.
10909      * @return {Number} The zero-based javascript month number.
10910      * @static
10911      */
10912     getMonthNumber : function(name) {
10913         // handle camel casing for english month names (since the keys for the Date.monthNumbers hash are case sensitive)
10914         return Date.monthNumbers[name.substring(0, 1).toUpperCase() + name.substring(1, 3).toLowerCase()];
10915     },
10916
10917     /**
10918      * The base format-code to formatting-function hashmap used by the {@link #format} method.
10919      * Formatting functions are strings (or functions which return strings) which
10920      * will return the appropriate value when evaluated in the context of the Date object
10921      * from which the {@link #format} method is called.
10922      * Add to / override these mappings for custom date formatting.
10923      * Note: Date.format() treats characters as literals if an appropriate mapping cannot be found.
10924      * Example:
10925      * <pre><code>
10926 Date.formatCodes.x = "String.leftPad(this.getDate(), 2, '0')";
10927 (new Date()).format("X"); // returns the current day of the month
10928 </code></pre>
10929      * @type Object
10930      * @static
10931      */
10932     formatCodes : {
10933         d: "String.leftPad(this.getDate(), 2, '0')",
10934         D: "Date.getShortDayName(this.getDay())", // get localised short day name
10935         j: "this.getDate()",
10936         l: "Date.dayNames[this.getDay()]",
10937         N: "(this.getDay() ? this.getDay() : 7)",
10938         S: "this.getSuffix()",
10939         w: "this.getDay()",
10940         z: "this.getDayOfYear()",
10941         W: "String.leftPad(this.getWeekOfYear(), 2, '0')",
10942         F: "Date.monthNames[this.getMonth()]",
10943         m: "String.leftPad(this.getMonth() + 1, 2, '0')",
10944         M: "Date.getShortMonthName(this.getMonth())", // get localised short month name
10945         n: "(this.getMonth() + 1)",
10946         t: "this.getDaysInMonth()",
10947         L: "(this.isLeapYear() ? 1 : 0)",
10948         o: "(this.getFullYear() + (this.getWeekOfYear() == 1 && this.getMonth() > 0 ? +1 : (this.getWeekOfYear() >= 52 && this.getMonth() < 11 ? -1 : 0)))",
10949         Y: "this.getFullYear()",
10950         y: "('' + this.getFullYear()).substring(2, 4)",
10951         a: "(this.getHours() < 12 ? 'am' : 'pm')",
10952         A: "(this.getHours() < 12 ? 'AM' : 'PM')",
10953         g: "((this.getHours() % 12) ? this.getHours() % 12 : 12)",
10954         G: "this.getHours()",
10955         h: "String.leftPad((this.getHours() % 12) ? this.getHours() % 12 : 12, 2, '0')",
10956         H: "String.leftPad(this.getHours(), 2, '0')",
10957         i: "String.leftPad(this.getMinutes(), 2, '0')",
10958         s: "String.leftPad(this.getSeconds(), 2, '0')",
10959         u: "String.leftPad(this.getMilliseconds(), 3, '0')",
10960         O: "this.getGMTOffset()",
10961         P: "this.getGMTOffset(true)",
10962         T: "this.getTimezone()",
10963         Z: "(this.getTimezoneOffset() * -60)",
10964
10965         c: function() { // ISO-8601 -- GMT format
10966             for (var c = "Y-m-dTH:i:sP", code = [], i = 0, l = c.length; i < l; ++i) {
10967                 var e = c.charAt(i);
10968                 code.push(e == "T" ? "'T'" : Date.getFormatCode(e)); // treat T as a character literal
10969             }
10970             return code.join(" + ");
10971         },
10972         /*
10973         c: function() { // ISO-8601 -- UTC format
10974             return [
10975               "this.getUTCFullYear()", "'-'",
10976               "String.leftPad(this.getUTCMonth() + 1, 2, '0')", "'-'",
10977               "String.leftPad(this.getUTCDate(), 2, '0')",
10978               "'T'",
10979               "String.leftPad(this.getUTCHours(), 2, '0')", "':'",
10980               "String.leftPad(this.getUTCMinutes(), 2, '0')", "':'",
10981               "String.leftPad(this.getUTCSeconds(), 2, '0')",
10982               "'Z'"
10983             ].join(" + ");
10984         },
10985         */
10986
10987         U: "Math.round(this.getTime() / 1000)"
10988     },
10989
10990     /**
10991      * Checks if the passed Date parameters will cause a javascript Date "rollover".
10992      * @param {Number} year 4-digit year
10993      * @param {Number} month 1-based month-of-year
10994      * @param {Number} day Day of month
10995      * @param {Number} hour (optional) Hour
10996      * @param {Number} minute (optional) Minute
10997      * @param {Number} second (optional) Second
10998      * @param {Number} millisecond (optional) Millisecond
10999      * @return {Boolean} true if the passed parameters do not cause a Date "rollover", false otherwise.
11000      * @static
11001      */
11002     isValid : function(y, m, d, h, i, s, ms) {
11003         // setup defaults
11004         h = h || 0;
11005         i = i || 0;
11006         s = s || 0;
11007         ms = ms || 0;
11008
11009         var dt = new Date(y, m - 1, d, h, i, s, ms);
11010
11011         return y == dt.getFullYear() &&
11012             m == dt.getMonth() + 1 &&
11013             d == dt.getDate() &&
11014             h == dt.getHours() &&
11015             i == dt.getMinutes() &&
11016             s == dt.getSeconds() &&
11017             ms == dt.getMilliseconds();
11018     },
11019
11020     /**
11021      * Parses the passed string using the specified date format.
11022      * Note that this function expects normal calendar dates, meaning that months are 1-based (i.e. 1 = January).
11023      * The {@link #defaults} hash will be used for any date value (i.e. year, month, day, hour, minute, second or millisecond)
11024      * which cannot be found in the passed string. If a corresponding default date value has not been specified in the {@link #defaults} hash,
11025      * the current date's year, month, day or DST-adjusted zero-hour time value will be used instead.
11026      * Keep in mind that the input date string must precisely match the specified format string
11027      * in order for the parse operation to be successful (failed parse operations return a null value).
11028      * <p>Example:</p><pre><code>
11029 //dt = Fri May 25 2007 (current date)
11030 var dt = new Date();
11031
11032 //dt = Thu May 25 2006 (today&#39;s month/day in 2006)
11033 dt = Date.parseDate("2006", "Y");
11034
11035 //dt = Sun Jan 15 2006 (all date parts specified)
11036 dt = Date.parseDate("2006-01-15", "Y-m-d");
11037
11038 //dt = Sun Jan 15 2006 15:20:01
11039 dt = Date.parseDate("2006-01-15 3:20:01 PM", "Y-m-d g:i:s A");
11040
11041 // attempt to parse Sun Feb 29 2006 03:20:01 in strict mode
11042 dt = Date.parseDate("2006-02-29 03:20:01", "Y-m-d H:i:s", true); // returns null
11043 </code></pre>
11044      * @param {String} input The raw date string.
11045      * @param {String} format The expected date string format.
11046      * @param {Boolean} strict (optional) True to validate date strings while parsing (i.e. prevents javascript Date "rollover")
11047                         (defaults to false). Invalid date strings will return null when parsed.
11048      * @return {Date} The parsed Date.
11049      * @static
11050      */
11051     parseDate : function(input, format, strict) {
11052         var p = Date.parseFunctions;
11053         if (p[format] == null) {
11054             Date.createParser(format);
11055         }
11056         return p[format](input, Ext.isDefined(strict) ? strict : Date.useStrict);
11057     },
11058
11059     // private
11060     getFormatCode : function(character) {
11061         var f = Date.formatCodes[character];
11062
11063         if (f) {
11064           f = typeof f == 'function'? f() : f;
11065           Date.formatCodes[character] = f; // reassign function result to prevent repeated execution
11066         }
11067
11068         // note: unknown characters are treated as literals
11069         return f || ("'" + String.escape(character) + "'");
11070     },
11071
11072     // private
11073     createFormat : function(format) {
11074         var code = [],
11075             special = false,
11076             ch = '';
11077
11078         for (var i = 0; i < format.length; ++i) {
11079             ch = format.charAt(i);
11080             if (!special && ch == "\\") {
11081                 special = true;
11082             } else if (special) {
11083                 special = false;
11084                 code.push("'" + String.escape(ch) + "'");
11085             } else {
11086                 code.push(Date.getFormatCode(ch))
11087             }
11088         }
11089         Date.formatFunctions[format] = new Function("return " + code.join('+'));
11090     },
11091
11092     // private
11093     createParser : function() {
11094         var code = [
11095             "var dt, y, m, d, h, i, s, ms, o, z, zz, u, v,",
11096                 "def = Date.defaults,",
11097                 "results = String(input).match(Date.parseRegexes[{0}]);", // either null, or an array of matched strings
11098
11099             "if(results){",
11100                 "{1}",
11101
11102                 "if(u != null){", // i.e. unix time is defined
11103                     "v = new Date(u * 1000);", // give top priority to UNIX time
11104                 "}else{",
11105                     // create Date object representing midnight of the current day;
11106                     // this will provide us with our date defaults
11107                     // (note: clearTime() handles Daylight Saving Time automatically)
11108                     "dt = (new Date()).clearTime();",
11109
11110                     // date calculations (note: these calculations create a dependency on Ext.num())
11111                     "y = Ext.num(y, Ext.num(def.y, dt.getFullYear()));",
11112                     "m = Ext.num(m, Ext.num(def.m - 1, dt.getMonth()));",
11113                     "d = Ext.num(d, Ext.num(def.d, dt.getDate()));",
11114
11115                     // time calculations (note: these calculations create a dependency on Ext.num())
11116                     "h  = Ext.num(h, Ext.num(def.h, dt.getHours()));",
11117                     "i  = Ext.num(i, Ext.num(def.i, dt.getMinutes()));",
11118                     "s  = Ext.num(s, Ext.num(def.s, dt.getSeconds()));",
11119                     "ms = Ext.num(ms, Ext.num(def.ms, dt.getMilliseconds()));",
11120
11121                     "if(z >= 0 && y >= 0){",
11122                         // both the year and zero-based day of year are defined and >= 0.
11123                         // these 2 values alone provide sufficient info to create a full date object
11124
11125                         // create Date object representing January 1st for the given year
11126                         "v = new Date(y, 0, 1, h, i, s, ms);",
11127
11128                         // then add day of year, checking for Date "rollover" if necessary
11129                         "v = !strict? v : (strict === true && (z <= 364 || (v.isLeapYear() && z <= 365))? v.add(Date.DAY, z) : null);",
11130                     "}else if(strict === true && !Date.isValid(y, m + 1, d, h, i, s, ms)){", // check for Date "rollover"
11131                         "v = null;", // invalid date, so return null
11132                     "}else{",
11133                         // plain old Date object
11134                         "v = new Date(y, m, d, h, i, s, ms);",
11135                     "}",
11136                 "}",
11137             "}",
11138
11139             "if(v){",
11140                 // favour UTC offset over GMT offset
11141                 "if(zz != null){",
11142                     // reset to UTC, then add offset
11143                     "v = v.add(Date.SECOND, -v.getTimezoneOffset() * 60 - zz);",
11144                 "}else if(o){",
11145                     // reset to GMT, then add offset
11146                     "v = v.add(Date.MINUTE, -v.getTimezoneOffset() + (sn == '+'? -1 : 1) * (hr * 60 + mn));",
11147                 "}",
11148             "}",
11149
11150             "return v;"
11151         ].join('\n');
11152
11153         return function(format) {
11154             var regexNum = Date.parseRegexes.length,
11155                 currentGroup = 1,
11156                 calc = [],
11157                 regex = [],
11158                 special = false,
11159                 ch = "";
11160
11161             for (var i = 0; i < format.length; ++i) {
11162                 ch = format.charAt(i);
11163                 if (!special && ch == "\\") {
11164                     special = true;
11165                 } else if (special) {
11166                     special = false;
11167                     regex.push(String.escape(ch));
11168                 } else {
11169                     var obj = $f(ch, currentGroup);
11170                     currentGroup += obj.g;
11171                     regex.push(obj.s);
11172                     if (obj.g && obj.c) {
11173                         calc.push(obj.c);
11174                     }
11175                 }
11176             }
11177
11178             Date.parseRegexes[regexNum] = new RegExp("^" + regex.join('') + "$");
11179             Date.parseFunctions[format] = new Function("input", "strict", xf(code, regexNum, calc.join('')));
11180         }
11181     }(),
11182
11183     // private
11184     parseCodes : {
11185         /*
11186          * Notes:
11187          * g = {Number} calculation group (0 or 1. only group 1 contributes to date calculations.)
11188          * c = {String} calculation method (required for group 1. null for group 0. {0} = currentGroup - position in regex result array)
11189          * s = {String} regex pattern. all matches are stored in results[], and are accessible by the calculation mapped to 'c'
11190          */
11191         d: {
11192             g:1,
11193             c:"d = parseInt(results[{0}], 10);\n",
11194             s:"(\\d{2})" // day of month with leading zeroes (01 - 31)
11195         },
11196         j: {
11197             g:1,
11198             c:"d = parseInt(results[{0}], 10);\n",
11199             s:"(\\d{1,2})" // day of month without leading zeroes (1 - 31)
11200         },
11201         D: function() {
11202             for (var a = [], i = 0; i < 7; a.push(Date.getShortDayName(i)), ++i); // get localised short day names
11203             return {
11204                 g:0,
11205                 c:null,
11206                 s:"(?:" + a.join("|") +")"
11207             }
11208         },
11209         l: function() {
11210             return {
11211                 g:0,
11212                 c:null,
11213                 s:"(?:" + Date.dayNames.join("|") + ")"
11214             }
11215         },
11216         N: {
11217             g:0,
11218             c:null,
11219             s:"[1-7]" // ISO-8601 day number (1 (monday) - 7 (sunday))
11220         },
11221         S: {
11222             g:0,
11223             c:null,
11224             s:"(?:st|nd|rd|th)"
11225         },
11226         w: {
11227             g:0,
11228             c:null,
11229             s:"[0-6]" // javascript day number (0 (sunday) - 6 (saturday))
11230         },
11231         z: {
11232             g:1,
11233             c:"z = parseInt(results[{0}], 10);\n",
11234             s:"(\\d{1,3})" // day of the year (0 - 364 (365 in leap years))
11235         },
11236         W: {
11237             g:0,
11238             c:null,
11239             s:"(?:\\d{2})" // ISO-8601 week number (with leading zero)
11240         },
11241         F: function() {
11242             return {
11243                 g:1,
11244                 c:"m = parseInt(Date.getMonthNumber(results[{0}]), 10);\n", // get localised month number
11245                 s:"(" + Date.monthNames.join("|") + ")"
11246             }
11247         },
11248         M: function() {
11249             for (var a = [], i = 0; i < 12; a.push(Date.getShortMonthName(i)), ++i); // get localised short month names
11250             return Ext.applyIf({
11251                 s:"(" + a.join("|") + ")"
11252             }, $f("F"));
11253         },
11254         m: {
11255             g:1,
11256             c:"m = parseInt(results[{0}], 10) - 1;\n",
11257             s:"(\\d{2})" // month number with leading zeros (01 - 12)
11258         },
11259         n: {
11260             g:1,
11261             c:"m = parseInt(results[{0}], 10) - 1;\n",
11262             s:"(\\d{1,2})" // month number without leading zeros (1 - 12)
11263         },
11264         t: {
11265             g:0,
11266             c:null,
11267             s:"(?:\\d{2})" // no. of days in the month (28 - 31)
11268         },
11269         L: {
11270             g:0,
11271             c:null,
11272             s:"(?:1|0)"
11273         },
11274         o: function() {
11275             return $f("Y");
11276         },
11277         Y: {
11278             g:1,
11279             c:"y = parseInt(results[{0}], 10);\n",
11280             s:"(\\d{4})" // 4-digit year
11281         },
11282         y: {
11283             g:1,
11284             c:"var ty = parseInt(results[{0}], 10);\n"
11285                 + "y = ty > Date.y2kYear ? 1900 + ty : 2000 + ty;\n", // 2-digit year
11286             s:"(\\d{1,2})"
11287         },
11288         a: {
11289             g:1,
11290             c:"if (results[{0}] == 'am') {\n"
11291                 + "if (!h || h == 12) { h = 0; }\n"
11292                 + "} else { if (!h || h < 12) { h = (h || 0) + 12; }}",
11293             s:"(am|pm)"
11294         },
11295         A: {
11296             g:1,
11297             c:"if (results[{0}] == 'AM') {\n"
11298                 + "if (!h || h == 12) { h = 0; }\n"
11299                 + "} else { if (!h || h < 12) { h = (h || 0) + 12; }}",
11300             s:"(AM|PM)"
11301         },
11302         g: function() {
11303             return $f("G");
11304         },
11305         G: {
11306             g:1,
11307             c:"h = parseInt(results[{0}], 10);\n",
11308             s:"(\\d{1,2})" // 24-hr format of an hour without leading zeroes (0 - 23)
11309         },
11310         h: function() {
11311             return $f("H");
11312         },
11313         H: {
11314             g:1,
11315             c:"h = parseInt(results[{0}], 10);\n",
11316             s:"(\\d{2})" //  24-hr format of an hour with leading zeroes (00 - 23)
11317         },
11318         i: {
11319             g:1,
11320             c:"i = parseInt(results[{0}], 10);\n",
11321             s:"(\\d{2})" // minutes with leading zeros (00 - 59)
11322         },
11323         s: {
11324             g:1,
11325             c:"s = parseInt(results[{0}], 10);\n",
11326             s:"(\\d{2})" // seconds with leading zeros (00 - 59)
11327         },
11328         u: {
11329             g:1,
11330             c:"ms = results[{0}]; ms = parseInt(ms, 10)/Math.pow(10, ms.length - 3);\n",
11331             s:"(\\d+)" // decimal fraction of a second (minimum = 1 digit, maximum = unlimited)
11332         },
11333         O: {
11334             g:1,
11335             c:[
11336                 "o = results[{0}];",
11337                 "var sn = o.substring(0,1),", // get + / - sign
11338                     "hr = o.substring(1,3)*1 + Math.floor(o.substring(3,5) / 60),", // get hours (performs minutes-to-hour conversion also, just in case)
11339                     "mn = o.substring(3,5) % 60;", // get minutes
11340                 "o = ((-12 <= (hr*60 + mn)/60) && ((hr*60 + mn)/60 <= 14))? (sn + String.leftPad(hr, 2, '0') + String.leftPad(mn, 2, '0')) : null;\n" // -12hrs <= GMT offset <= 14hrs
11341             ].join("\n"),
11342             s: "([+\-]\\d{4})" // GMT offset in hrs and mins
11343         },
11344         P: {
11345             g:1,
11346             c:[
11347                 "o = results[{0}];",
11348                 "var sn = o.substring(0,1),", // get + / - sign
11349                     "hr = o.substring(1,3)*1 + Math.floor(o.substring(4,6) / 60),", // get hours (performs minutes-to-hour conversion also, just in case)
11350                     "mn = o.substring(4,6) % 60;", // get minutes
11351                 "o = ((-12 <= (hr*60 + mn)/60) && ((hr*60 + mn)/60 <= 14))? (sn + String.leftPad(hr, 2, '0') + String.leftPad(mn, 2, '0')) : null;\n" // -12hrs <= GMT offset <= 14hrs
11352             ].join("\n"),
11353             s: "([+\-]\\d{2}:\\d{2})" // GMT offset in hrs and mins (with colon separator)
11354         },
11355         T: {
11356             g:0,
11357             c:null,
11358             s:"[A-Z]{1,4}" // timezone abbrev. may be between 1 - 4 chars
11359         },
11360         Z: {
11361             g:1,
11362             c:"zz = results[{0}] * 1;\n" // -43200 <= UTC offset <= 50400
11363                   + "zz = (-43200 <= zz && zz <= 50400)? zz : null;\n",
11364             s:"([+\-]?\\d{1,5})" // leading '+' sign is optional for UTC offset
11365         },
11366         c: function() {
11367             var calc = [],
11368                 arr = [
11369                     $f("Y", 1), // year
11370                     $f("m", 2), // month
11371                     $f("d", 3), // day
11372                     $f("h", 4), // hour
11373                     $f("i", 5), // minute
11374                     $f("s", 6), // second
11375                     {c:"ms = results[7] || '0'; ms = parseInt(ms, 10)/Math.pow(10, ms.length - 3);\n"}, // decimal fraction of a second (minimum = 1 digit, maximum = unlimited)
11376                     {c:[ // allow either "Z" (i.e. UTC) or "-0530" or "+08:00" (i.e. UTC offset) timezone delimiters. assumes local timezone if no timezone is specified
11377                         "if(results[8]) {", // timezone specified
11378                             "if(results[8] == 'Z'){",
11379                                 "zz = 0;", // UTC
11380                             "}else if (results[8].indexOf(':') > -1){",
11381                                 $f("P", 8).c, // timezone offset with colon separator
11382                             "}else{",
11383                                 $f("O", 8).c, // timezone offset without colon separator
11384                             "}",
11385                         "}"
11386                     ].join('\n')}
11387                 ];
11388
11389             for (var i = 0, l = arr.length; i < l; ++i) {
11390                 calc.push(arr[i].c);
11391             }
11392
11393             return {
11394                 g:1,
11395                 c:calc.join(""),
11396                 s:[
11397                     arr[0].s, // year (required)
11398                     "(?:", "-", arr[1].s, // month (optional)
11399                         "(?:", "-", arr[2].s, // day (optional)
11400                             "(?:",
11401                                 "(?:T| )?", // time delimiter -- either a "T" or a single blank space
11402                                 arr[3].s, ":", arr[4].s,  // hour AND minute, delimited by a single colon (optional). MUST be preceded by either a "T" or a single blank space
11403                                 "(?::", arr[5].s, ")?", // seconds (optional)
11404                                 "(?:(?:\\.|,)(\\d+))?", // decimal fraction of a second (e.g. ",12345" or ".98765") (optional)
11405                                 "(Z|(?:[-+]\\d{2}(?::)?\\d{2}))?", // "Z" (UTC) or "-0530" (UTC offset without colon delimiter) or "+08:00" (UTC offset with colon delimiter) (optional)
11406                             ")?",
11407                         ")?",
11408                     ")?"
11409                 ].join("")
11410             }
11411         },
11412         U: {
11413             g:1,
11414             c:"u = parseInt(results[{0}], 10);\n",
11415             s:"(-?\\d+)" // leading minus sign indicates seconds before UNIX epoch
11416         }
11417     }
11418 });
11419
11420 }());
11421
11422 Ext.apply(Date.prototype, {
11423     // private
11424     dateFormat : function(format) {
11425         if (Date.formatFunctions[format] == null) {
11426             Date.createFormat(format);
11427         }
11428         return Date.formatFunctions[format].call(this);
11429     },
11430
11431     /**
11432      * Get the timezone abbreviation of the current date (equivalent to the format specifier 'T').
11433      *
11434      * Note: The date string returned by the javascript Date object's toString() method varies
11435      * between browsers (e.g. FF vs IE) and system region settings (e.g. IE in Asia vs IE in America).
11436      * For a given date string e.g. "Thu Oct 25 2007 22:55:35 GMT+0800 (Malay Peninsula Standard Time)",
11437      * getTimezone() first tries to get the timezone abbreviation from between a pair of parentheses
11438      * (which may or may not be present), failing which it proceeds to get the timezone abbreviation
11439      * from the GMT offset portion of the date string.
11440      * @return {String} The abbreviated timezone name (e.g. 'CST', 'PDT', 'EDT', 'MPST' ...).
11441      */
11442     getTimezone : function() {
11443         // the following list shows the differences between date strings from different browsers on a WinXP SP2 machine from an Asian locale:
11444         //
11445         // Opera  : "Thu, 25 Oct 2007 22:53:45 GMT+0800" -- shortest (weirdest) date string of the lot
11446         // Safari : "Thu Oct 25 2007 22:55:35 GMT+0800 (Malay Peninsula Standard Time)" -- value in parentheses always gives the correct timezone (same as FF)
11447         // FF     : "Thu Oct 25 2007 22:55:35 GMT+0800 (Malay Peninsula Standard Time)" -- value in parentheses always gives the correct timezone
11448         // IE     : "Thu Oct 25 22:54:35 UTC+0800 2007" -- (Asian system setting) look for 3-4 letter timezone abbrev
11449         // IE     : "Thu Oct 25 17:06:37 PDT 2007" -- (American system setting) look for 3-4 letter timezone abbrev
11450         //
11451         // this crazy regex attempts to guess the correct timezone abbreviation despite these differences.
11452         // step 1: (?:\((.*)\) -- find timezone in parentheses
11453         // step 2: ([A-Z]{1,4})(?:[\-+][0-9]{4})?(?: -?\d+)?) -- if nothing was found in step 1, find timezone from timezone offset portion of date string
11454         // step 3: remove all non uppercase characters found in step 1 and 2
11455         return this.toString().replace(/^.* (?:\((.*)\)|([A-Z]{1,4})(?:[\-+][0-9]{4})?(?: -?\d+)?)$/, "$1$2").replace(/[^A-Z]/g, "");
11456     },
11457
11458     /**
11459      * Get the offset from GMT of the current date (equivalent to the format specifier 'O').
11460      * @param {Boolean} colon (optional) true to separate the hours and minutes with a colon (defaults to false).
11461      * @return {String} The 4-character offset string prefixed with + or - (e.g. '-0600').
11462      */
11463     getGMTOffset : function(colon) {
11464         return (this.getTimezoneOffset() > 0 ? "-" : "+")
11465             + String.leftPad(Math.floor(Math.abs(this.getTimezoneOffset()) / 60), 2, "0")
11466             + (colon ? ":" : "")
11467             + String.leftPad(Math.abs(this.getTimezoneOffset() % 60), 2, "0");
11468     },
11469
11470     /**
11471      * Get the numeric day number of the year, adjusted for leap year.
11472      * @return {Number} 0 to 364 (365 in leap years).
11473      */
11474     getDayOfYear: function() {
11475         var num = 0,
11476             d = this.clone(),
11477             m = this.getMonth(),
11478             i;
11479
11480         for (i = 0, d.setDate(1), d.setMonth(0); i < m; d.setMonth(++i)) {
11481             num += d.getDaysInMonth();
11482         }
11483         return num + this.getDate() - 1;
11484     },
11485
11486     /**
11487      * Get the numeric ISO-8601 week number of the year.
11488      * (equivalent to the format specifier 'W', but without a leading zero).
11489      * @return {Number} 1 to 53
11490      */
11491     getWeekOfYear : function() {
11492         // adapted from http://www.merlyn.demon.co.uk/weekcalc.htm
11493         var ms1d = 864e5, // milliseconds in a day
11494             ms7d = 7 * ms1d; // milliseconds in a week
11495
11496         return function() { // return a closure so constants get calculated only once
11497             var DC3 = Date.UTC(this.getFullYear(), this.getMonth(), this.getDate() + 3) / ms1d, // an Absolute Day Number
11498                 AWN = Math.floor(DC3 / 7), // an Absolute Week Number
11499                 Wyr = new Date(AWN * ms7d).getUTCFullYear();
11500
11501             return AWN - Math.floor(Date.UTC(Wyr, 0, 7) / ms7d) + 1;
11502         }
11503     }(),
11504
11505     /**
11506      * Checks if the current date falls within a leap year.
11507      * @return {Boolean} True if the current date falls within a leap year, false otherwise.
11508      */
11509     isLeapYear : function() {
11510         var year = this.getFullYear();
11511         return !!((year & 3) == 0 && (year % 100 || (year % 400 == 0 && year)));
11512     },
11513
11514     /**
11515      * Get the first day of the current month, adjusted for leap year.  The returned value
11516      * is the numeric day index within the week (0-6) which can be used in conjunction with
11517      * the {@link #monthNames} array to retrieve the textual day name.
11518      * Example:
11519      * <pre><code>
11520 var dt = new Date('1/10/2007');
11521 document.write(Date.dayNames[dt.getFirstDayOfMonth()]); //output: 'Monday'
11522 </code></pre>
11523      * @return {Number} The day number (0-6).
11524      */
11525     getFirstDayOfMonth : function() {
11526         var day = (this.getDay() - (this.getDate() - 1)) % 7;
11527         return (day < 0) ? (day + 7) : day;
11528     },
11529
11530     /**
11531      * Get the last day of the current month, adjusted for leap year.  The returned value
11532      * is the numeric day index within the week (0-6) which can be used in conjunction with
11533      * the {@link #monthNames} array to retrieve the textual day name.
11534      * Example:
11535      * <pre><code>
11536 var dt = new Date('1/10/2007');
11537 document.write(Date.dayNames[dt.getLastDayOfMonth()]); //output: 'Wednesday'
11538 </code></pre>
11539      * @return {Number} The day number (0-6).
11540      */
11541     getLastDayOfMonth : function() {
11542         return this.getLastDateOfMonth().getDay();
11543     },
11544
11545
11546     /**
11547      * Get the date of the first day of the month in which this date resides.
11548      * @return {Date}
11549      */
11550     getFirstDateOfMonth : function() {
11551         return new Date(this.getFullYear(), this.getMonth(), 1);
11552     },
11553
11554     /**
11555      * Get the date of the last day of the month in which this date resides.
11556      * @return {Date}
11557      */
11558     getLastDateOfMonth : function() {
11559         return new Date(this.getFullYear(), this.getMonth(), this.getDaysInMonth());
11560     },
11561
11562     /**
11563      * Get the number of days in the current month, adjusted for leap year.
11564      * @return {Number} The number of days in the month.
11565      */
11566     getDaysInMonth: function() {
11567         var daysInMonth = [31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31];
11568
11569         return function() { // return a closure for efficiency
11570             var m = this.getMonth();
11571
11572             return m == 1 && this.isLeapYear() ? 29 : daysInMonth[m];
11573         }
11574     }(),
11575
11576     /**
11577      * Get the English ordinal suffix of the current day (equivalent to the format specifier 'S').
11578      * @return {String} 'st, 'nd', 'rd' or 'th'.
11579      */
11580     getSuffix : function() {
11581         switch (this.getDate()) {
11582             case 1:
11583             case 21:
11584             case 31:
11585                 return "st";
11586             case 2:
11587             case 22:
11588                 return "nd";
11589             case 3:
11590             case 23:
11591                 return "rd";
11592             default:
11593                 return "th";
11594         }
11595     },
11596
11597     /**
11598      * Creates and returns a new Date instance with the exact same date value as the called instance.
11599      * Dates are copied and passed by reference, so if a copied date variable is modified later, the original
11600      * variable will also be changed.  When the intention is to create a new variable that will not
11601      * modify the original instance, you should create a clone.
11602      *
11603      * Example of correctly cloning a date:
11604      * <pre><code>
11605 //wrong way:
11606 var orig = new Date('10/1/2006');
11607 var copy = orig;
11608 copy.setDate(5);
11609 document.write(orig);  //returns 'Thu Oct 05 2006'!
11610
11611 //correct way:
11612 var orig = new Date('10/1/2006');
11613 var copy = orig.clone();
11614 copy.setDate(5);
11615 document.write(orig);  //returns 'Thu Oct 01 2006'
11616 </code></pre>
11617      * @return {Date} The new Date instance.
11618      */
11619     clone : function() {
11620         return new Date(this.getTime());
11621     },
11622
11623     /**
11624      * Checks if the current date is affected by Daylight Saving Time (DST).
11625      * @return {Boolean} True if the current date is affected by DST.
11626      */
11627     isDST : function() {
11628         // adapted from http://extjs.com/forum/showthread.php?p=247172#post247172
11629         // courtesy of @geoffrey.mcgill
11630         return new Date(this.getFullYear(), 0, 1).getTimezoneOffset() != this.getTimezoneOffset();
11631     },
11632
11633     /**
11634      * Attempts to clear all time information from this Date by setting the time to midnight of the same day,
11635      * automatically adjusting for Daylight Saving Time (DST) where applicable.
11636      * (note: DST timezone information for the browser's host operating system is assumed to be up-to-date)
11637      * @param {Boolean} clone true to create a clone of this date, clear the time and return it (defaults to false).
11638      * @return {Date} this or the clone.
11639      */
11640     clearTime : function(clone) {
11641         if (clone) {
11642             return this.clone().clearTime();
11643         }
11644
11645         // get current date before clearing time
11646         var d = this.getDate();
11647
11648         // clear time
11649         this.setHours(0);
11650         this.setMinutes(0);
11651         this.setSeconds(0);
11652         this.setMilliseconds(0);
11653
11654         if (this.getDate() != d) { // account for DST (i.e. day of month changed when setting hour = 0)
11655             // note: DST adjustments are assumed to occur in multiples of 1 hour (this is almost always the case)
11656             // refer to http://www.timeanddate.com/time/aboutdst.html for the (rare) exceptions to this rule
11657
11658             // increment hour until cloned date == current date
11659             for (var hr = 1, c = this.add(Date.HOUR, hr); c.getDate() != d; hr++, c = this.add(Date.HOUR, hr));
11660
11661             this.setDate(d);
11662             this.setHours(c.getHours());
11663         }
11664
11665         return this;
11666     },
11667
11668     /**
11669      * Provides a convenient method for performing basic date arithmetic. This method
11670      * does not modify the Date instance being called - it creates and returns
11671      * a new Date instance containing the resulting date value.
11672      *
11673      * Examples:
11674      * <pre><code>
11675 // Basic usage:
11676 var dt = new Date('10/29/2006').add(Date.DAY, 5);
11677 document.write(dt); //returns 'Fri Nov 03 2006 00:00:00'
11678
11679 // Negative values will be subtracted:
11680 var dt2 = new Date('10/1/2006').add(Date.DAY, -5);
11681 document.write(dt2); //returns 'Tue Sep 26 2006 00:00:00'
11682
11683 // You can even chain several calls together in one line:
11684 var dt3 = new Date('10/1/2006').add(Date.DAY, 5).add(Date.HOUR, 8).add(Date.MINUTE, -30);
11685 document.write(dt3); //returns 'Fri Oct 06 2006 07:30:00'
11686 </code></pre>
11687      *
11688      * @param {String} interval A valid date interval enum value.
11689      * @param {Number} value The amount to add to the current date.
11690      * @return {Date} The new Date instance.
11691      */
11692     add : function(interval, value) {
11693         var d = this.clone();
11694         if (!interval || value === 0) return d;
11695
11696         switch(interval.toLowerCase()) {
11697             case Date.MILLI:
11698                 d.setMilliseconds(this.getMilliseconds() + value);
11699                 break;
11700             case Date.SECOND:
11701                 d.setSeconds(this.getSeconds() + value);
11702                 break;
11703             case Date.MINUTE:
11704                 d.setMinutes(this.getMinutes() + value);
11705                 break;
11706             case Date.HOUR:
11707                 d.setHours(this.getHours() + value);
11708                 break;
11709             case Date.DAY:
11710                 d.setDate(this.getDate() + value);
11711                 break;
11712             case Date.MONTH:
11713                 var day = this.getDate();
11714                 if (day > 28) {
11715                     day = Math.min(day, this.getFirstDateOfMonth().add('mo', value).getLastDateOfMonth().getDate());
11716                 }
11717                 d.setDate(day);
11718                 d.setMonth(this.getMonth() + value);
11719                 break;
11720             case Date.YEAR:
11721                 d.setFullYear(this.getFullYear() + value);
11722                 break;
11723         }
11724         return d;
11725     },
11726
11727     /**
11728      * Checks if this date falls on or between the given start and end dates.
11729      * @param {Date} start Start date
11730      * @param {Date} end End date
11731      * @return {Boolean} true if this date falls on or between the given start and end dates.
11732      */
11733     between : function(start, end) {
11734         var t = this.getTime();
11735         return start.getTime() <= t && t <= end.getTime();
11736     }
11737 });
11738
11739
11740 /**
11741  * Formats a date given the supplied format string.
11742  * @param {String} format The format string.
11743  * @return {String} The formatted date.
11744  * @method format
11745  */
11746 Date.prototype.format = Date.prototype.dateFormat;
11747
11748
11749 // private
11750 if (Ext.isSafari && (navigator.userAgent.match(/WebKit\/(\d+)/)[1] || NaN) < 420) {
11751     Ext.apply(Date.prototype, {
11752         _xMonth : Date.prototype.setMonth,
11753         _xDate  : Date.prototype.setDate,
11754
11755         // Bug in Safari 1.3, 2.0 (WebKit build < 420)
11756         // Date.setMonth does not work consistently if iMonth is not 0-11
11757         setMonth : function(num) {
11758             if (num <= -1) {
11759                 var n = Math.ceil(-num),
11760                     back_year = Math.ceil(n / 12),
11761                     month = (n % 12) ? 12 - n % 12 : 0;
11762
11763                 this.setFullYear(this.getFullYear() - back_year);
11764
11765                 return this._xMonth(month);
11766             } else {
11767                 return this._xMonth(num);
11768             }
11769         },
11770
11771         // Bug in setDate() method (resolved in WebKit build 419.3, so to be safe we target Webkit builds < 420)
11772         // The parameter for Date.setDate() is converted to a signed byte integer in Safari
11773         // http://brianary.blogspot.com/2006/03/safari-date-bug.html
11774         setDate : function(d) {
11775             // use setTime() to workaround setDate() bug
11776             // subtract current day of month in milliseconds, then add desired day of month in milliseconds
11777             return this.setTime(this.getTime() - (this.getDate() - d) * 864e5);
11778         }
11779     });
11780 }
11781
11782
11783
11784 /* Some basic Date tests... (requires Firebug)
11785
11786 Date.parseDate('', 'c'); // call Date.parseDate() once to force computation of regex string so we can console.log() it
11787 console.log('Insane Regex for "c" format: %o', Date.parseCodes.c.s); // view the insane regex for the "c" format specifier
11788
11789 // standard tests
11790 console.group('Standard Date.parseDate() Tests');
11791     console.log('Date.parseDate("2009-01-05T11:38:56", "c")               = %o', Date.parseDate("2009-01-05T11:38:56", "c")); // assumes browser's timezone setting
11792     console.log('Date.parseDate("2009-02-04T12:37:55.001000", "c")        = %o', Date.parseDate("2009-02-04T12:37:55.001000", "c")); // assumes browser's timezone setting
11793     console.log('Date.parseDate("2009-03-03T13:36:54,101000Z", "c")       = %o', Date.parseDate("2009-03-03T13:36:54,101000Z", "c")); // UTC
11794     console.log('Date.parseDate("2009-04-02T14:35:53.901000-0530", "c")   = %o', Date.parseDate("2009-04-02T14:35:53.901000-0530", "c")); // GMT-0530
11795     console.log('Date.parseDate("2009-05-01T15:34:52,9876000+08:00", "c") = %o', Date.parseDate("2009-05-01T15:34:52,987600+08:00", "c")); // GMT+08:00
11796 console.groupEnd();
11797
11798 // ISO-8601 format as specified in http://www.w3.org/TR/NOTE-datetime
11799 // -- accepts ALL 6 levels of date-time granularity
11800 console.group('ISO-8601 Granularity Test (see http://www.w3.org/TR/NOTE-datetime)');
11801     console.log('Date.parseDate("1997", "c")                              = %o', Date.parseDate("1997", "c")); // YYYY (e.g. 1997)
11802     console.log('Date.parseDate("1997-07", "c")                           = %o', Date.parseDate("1997-07", "c")); // YYYY-MM (e.g. 1997-07)
11803     console.log('Date.parseDate("1997-07-16", "c")                        = %o', Date.parseDate("1997-07-16", "c")); // YYYY-MM-DD (e.g. 1997-07-16)
11804     console.log('Date.parseDate("1997-07-16T19:20+01:00", "c")            = %o', Date.parseDate("1997-07-16T19:20+01:00", "c")); // YYYY-MM-DDThh:mmTZD (e.g. 1997-07-16T19:20+01:00)
11805     console.log('Date.parseDate("1997-07-16T19:20:30+01:00", "c")         = %o', Date.parseDate("1997-07-16T19:20:30+01:00", "c")); // YYYY-MM-DDThh:mm:ssTZD (e.g. 1997-07-16T19:20:30+01:00)
11806     console.log('Date.parseDate("1997-07-16T19:20:30.45+01:00", "c")      = %o', Date.parseDate("1997-07-16T19:20:30.45+01:00", "c")); // YYYY-MM-DDThh:mm:ss.sTZD (e.g. 1997-07-16T19:20:30.45+01:00)
11807     console.log('Date.parseDate("1997-07-16 19:20:30.45+01:00", "c")      = %o', Date.parseDate("1997-07-16 19:20:30.45+01:00", "c")); // YYYY-MM-DD hh:mm:ss.sTZD (e.g. 1997-07-16T19:20:30.45+01:00)
11808     console.log('Date.parseDate("1997-13-16T19:20:30.45+01:00", "c", true)= %o', Date.parseDate("1997-13-16T19:20:30.45+01:00", "c", true)); // strict date parsing with invalid month value
11809 console.groupEnd();
11810
11811 //*/
11812 /**
11813  * @class Ext.util.MixedCollection
11814  * @extends Ext.util.Observable
11815  * A Collection class that maintains both numeric indexes and keys and exposes events.
11816  * @constructor
11817  * @param {Boolean} allowFunctions Specify <tt>true</tt> if the {@link #addAll}
11818  * function should add function references to the collection. Defaults to
11819  * <tt>false</tt>.
11820  * @param {Function} keyFn A function that can accept an item of the type(s) stored in this MixedCollection
11821  * and return the key value for that item.  This is used when available to look up the key on items that
11822  * were passed without an explicit key parameter to a MixedCollection method.  Passing this parameter is
11823  * equivalent to providing an implementation for the {@link #getKey} method.
11824  */
11825 Ext.util.MixedCollection = function(allowFunctions, keyFn){
11826     this.items = [];
11827     this.map = {};
11828     this.keys = [];
11829     this.length = 0;
11830     this.addEvents(
11831         /**
11832          * @event clear
11833          * Fires when the collection is cleared.
11834          */
11835         'clear',
11836         /**
11837          * @event add
11838          * Fires when an item is added to the collection.
11839          * @param {Number} index The index at which the item was added.
11840          * @param {Object} o The item added.
11841          * @param {String} key The key associated with the added item.
11842          */
11843         'add',
11844         /**
11845          * @event replace
11846          * Fires when an item is replaced in the collection.
11847          * @param {String} key he key associated with the new added.
11848          * @param {Object} old The item being replaced.
11849          * @param {Object} new The new item.
11850          */
11851         'replace',
11852         /**
11853          * @event remove
11854          * Fires when an item is removed from the collection.
11855          * @param {Object} o The item being removed.
11856          * @param {String} key (optional) The key associated with the removed item.
11857          */
11858         'remove',
11859         'sort'
11860     );
11861     this.allowFunctions = allowFunctions === true;
11862     if(keyFn){
11863         this.getKey = keyFn;
11864     }
11865     Ext.util.MixedCollection.superclass.constructor.call(this);
11866 };
11867
11868 Ext.extend(Ext.util.MixedCollection, Ext.util.Observable, {
11869
11870     /**
11871      * @cfg {Boolean} allowFunctions Specify <tt>true</tt> if the {@link #addAll}
11872      * function should add function references to the collection. Defaults to
11873      * <tt>false</tt>.
11874      */
11875     allowFunctions : false,
11876
11877     /**
11878      * Adds an item to the collection. Fires the {@link #add} event when complete.
11879      * @param {String} key <p>The key to associate with the item, or the new item.</p>
11880      * <p>If a {@link #getKey} implementation was specified for this MixedCollection,
11881      * or if the key of the stored items is in a property called <tt><b>id</b></tt>,
11882      * the MixedCollection will be able to <i>derive</i> the key for the new item.
11883      * In this case just pass the new item in this parameter.</p>
11884      * @param {Object} o The item to add.
11885      * @return {Object} The item added.
11886      */
11887     add : function(key, o){
11888         if(arguments.length == 1){
11889             o = arguments[0];
11890             key = this.getKey(o);
11891         }
11892         if(typeof key != 'undefined' && key !== null){
11893             var old = this.map[key];
11894             if(typeof old != 'undefined'){
11895                 return this.replace(key, o);
11896             }
11897             this.map[key] = o;
11898         }
11899         this.length++;
11900         this.items.push(o);
11901         this.keys.push(key);
11902         this.fireEvent('add', this.length-1, o, key);
11903         return o;
11904     },
11905
11906     /**
11907       * MixedCollection has a generic way to fetch keys if you implement getKey.  The default implementation
11908       * simply returns <b><code>item.id</code></b> but you can provide your own implementation
11909       * to return a different value as in the following examples:<pre><code>
11910 // normal way
11911 var mc = new Ext.util.MixedCollection();
11912 mc.add(someEl.dom.id, someEl);
11913 mc.add(otherEl.dom.id, otherEl);
11914 //and so on
11915
11916 // using getKey
11917 var mc = new Ext.util.MixedCollection();
11918 mc.getKey = function(el){
11919    return el.dom.id;
11920 };
11921 mc.add(someEl);
11922 mc.add(otherEl);
11923
11924 // or via the constructor
11925 var mc = new Ext.util.MixedCollection(false, function(el){
11926    return el.dom.id;
11927 });
11928 mc.add(someEl);
11929 mc.add(otherEl);
11930      * </code></pre>
11931      * @param {Object} item The item for which to find the key.
11932      * @return {Object} The key for the passed item.
11933      */
11934     getKey : function(o){
11935          return o.id;
11936     },
11937
11938     /**
11939      * Replaces an item in the collection. Fires the {@link #replace} event when complete.
11940      * @param {String} key <p>The key associated with the item to replace, or the replacement item.</p>
11941      * <p>If you supplied a {@link #getKey} implementation for this MixedCollection, or if the key
11942      * of your stored items is in a property called <tt><b>id</b></tt>, then the MixedCollection
11943      * will be able to <i>derive</i> the key of the replacement item. If you want to replace an item
11944      * with one having the same key value, then just pass the replacement item in this parameter.</p>
11945      * @param o {Object} o (optional) If the first parameter passed was a key, the item to associate
11946      * with that key.
11947      * @return {Object}  The new item.
11948      */
11949     replace : function(key, o){
11950         if(arguments.length == 1){
11951             o = arguments[0];
11952             key = this.getKey(o);
11953         }
11954         var old = this.map[key];
11955         if(typeof key == 'undefined' || key === null || typeof old == 'undefined'){
11956              return this.add(key, o);
11957         }
11958         var index = this.indexOfKey(key);
11959         this.items[index] = o;
11960         this.map[key] = o;
11961         this.fireEvent('replace', key, old, o);
11962         return o;
11963     },
11964
11965     /**
11966      * Adds all elements of an Array or an Object to the collection.
11967      * @param {Object/Array} objs An Object containing properties which will be added
11968      * to the collection, or an Array of values, each of which are added to the collection.
11969      * Functions references will be added to the collection if <code>{@link #allowFunctions}</code>
11970      * has been set to <tt>true</tt>.
11971      */
11972     addAll : function(objs){
11973         if(arguments.length > 1 || Ext.isArray(objs)){
11974             var args = arguments.length > 1 ? arguments : objs;
11975             for(var i = 0, len = args.length; i < len; i++){
11976                 this.add(args[i]);
11977             }
11978         }else{
11979             for(var key in objs){
11980                 if(this.allowFunctions || typeof objs[key] != 'function'){
11981                     this.add(key, objs[key]);
11982                 }
11983             }
11984         }
11985     },
11986
11987     /**
11988      * Executes the specified function once for every item in the collection, passing the following arguments:
11989      * <div class="mdetail-params"><ul>
11990      * <li><b>item</b> : Mixed<p class="sub-desc">The collection item</p></li>
11991      * <li><b>index</b> : Number<p class="sub-desc">The item's index</p></li>
11992      * <li><b>length</b> : Number<p class="sub-desc">The total number of items in the collection</p></li>
11993      * </ul></div>
11994      * The function should return a boolean value. Returning false from the function will stop the iteration.
11995      * @param {Function} fn The function to execute for each item.
11996      * @param {Object} scope (optional) The scope (<code>this</code> reference) in which the function is executed. Defaults to the current item in the iteration.
11997      */
11998     each : function(fn, scope){
11999         var items = [].concat(this.items); // each safe for removal
12000         for(var i = 0, len = items.length; i < len; i++){
12001             if(fn.call(scope || items[i], items[i], i, len) === false){
12002                 break;
12003             }
12004         }
12005     },
12006
12007     /**
12008      * Executes the specified function once for every key in the collection, passing each
12009      * key, and its associated item as the first two parameters.
12010      * @param {Function} fn The function to execute for each item.
12011      * @param {Object} scope (optional) The scope (<code>this</code> reference) in which the function is executed. Defaults to the browser window.
12012      */
12013     eachKey : function(fn, scope){
12014         for(var i = 0, len = this.keys.length; i < len; i++){
12015             fn.call(scope || window, this.keys[i], this.items[i], i, len);
12016         }
12017     },
12018
12019     /**
12020      * Returns the first item in the collection which elicits a true return value from the
12021      * passed selection function.
12022      * @param {Function} fn The selection function to execute for each item.
12023      * @param {Object} scope (optional) The scope (<code>this</code> reference) in which the function is executed. Defaults to the browser window.
12024      * @return {Object} The first item in the collection which returned true from the selection function.
12025      */
12026     find : function(fn, scope){
12027         for(var i = 0, len = this.items.length; i < len; i++){
12028             if(fn.call(scope || window, this.items[i], this.keys[i])){
12029                 return this.items[i];
12030             }
12031         }
12032         return null;
12033     },
12034
12035     /**
12036      * Inserts an item at the specified index in the collection. Fires the {@link #add} event when complete.
12037      * @param {Number} index The index to insert the item at.
12038      * @param {String} key The key to associate with the new item, or the item itself.
12039      * @param {Object} o (optional) If the second parameter was a key, the new item.
12040      * @return {Object} The item inserted.
12041      */
12042     insert : function(index, key, o){
12043         if(arguments.length == 2){
12044             o = arguments[1];
12045             key = this.getKey(o);
12046         }
12047         if(this.containsKey(key)){
12048             this.suspendEvents();
12049             this.removeKey(key);
12050             this.resumeEvents();
12051         }
12052         if(index >= this.length){
12053             return this.add(key, o);
12054         }
12055         this.length++;
12056         this.items.splice(index, 0, o);
12057         if(typeof key != 'undefined' && key !== null){
12058             this.map[key] = o;
12059         }
12060         this.keys.splice(index, 0, key);
12061         this.fireEvent('add', index, o, key);
12062         return o;
12063     },
12064
12065     /**
12066      * Remove an item from the collection.
12067      * @param {Object} o The item to remove.
12068      * @return {Object} The item removed or false if no item was removed.
12069      */
12070     remove : function(o){
12071         return this.removeAt(this.indexOf(o));
12072     },
12073
12074     /**
12075      * Remove an item from a specified index in the collection. Fires the {@link #remove} event when complete.
12076      * @param {Number} index The index within the collection of the item to remove.
12077      * @return {Object} The item removed or false if no item was removed.
12078      */
12079     removeAt : function(index){
12080         if(index < this.length && index >= 0){
12081             this.length--;
12082             var o = this.items[index];
12083             this.items.splice(index, 1);
12084             var key = this.keys[index];
12085             if(typeof key != 'undefined'){
12086                 delete this.map[key];
12087             }
12088             this.keys.splice(index, 1);
12089             this.fireEvent('remove', o, key);
12090             return o;
12091         }
12092         return false;
12093     },
12094
12095     /**
12096      * Removed an item associated with the passed key fom the collection.
12097      * @param {String} key The key of the item to remove.
12098      * @return {Object} The item removed or false if no item was removed.
12099      */
12100     removeKey : function(key){
12101         return this.removeAt(this.indexOfKey(key));
12102     },
12103
12104     /**
12105      * Returns the number of items in the collection.
12106      * @return {Number} the number of items in the collection.
12107      */
12108     getCount : function(){
12109         return this.length;
12110     },
12111
12112     /**
12113      * Returns index within the collection of the passed Object.
12114      * @param {Object} o The item to find the index of.
12115      * @return {Number} index of the item. Returns -1 if not found.
12116      */
12117     indexOf : function(o){
12118         return this.items.indexOf(o);
12119     },
12120
12121     /**
12122      * Returns index within the collection of the passed key.
12123      * @param {String} key The key to find the index of.
12124      * @return {Number} index of the key.
12125      */
12126     indexOfKey : function(key){
12127         return this.keys.indexOf(key);
12128     },
12129
12130     /**
12131      * Returns the item associated with the passed key OR index.
12132      * Key has priority over index.  This is the equivalent
12133      * of calling {@link #key} first, then if nothing matched calling {@link #itemAt}.
12134      * @param {String/Number} key The key or index of the item.
12135      * @return {Object} If the item is found, returns the item.  If the item was not found, returns <tt>undefined</tt>.
12136      * If an item was found, but is a Class, returns <tt>null</tt>.
12137      */
12138     item : function(key){
12139         var mk = this.map[key],
12140             item = mk !== undefined ? mk : (typeof key == 'number') ? this.items[key] : undefined;
12141         return typeof item != 'function' || this.allowFunctions ? item : null; // for prototype!
12142     },
12143
12144     /**
12145      * Returns the item at the specified index.
12146      * @param {Number} index The index of the item.
12147      * @return {Object} The item at the specified index.
12148      */
12149     itemAt : function(index){
12150         return this.items[index];
12151     },
12152
12153     /**
12154      * Returns the item associated with the passed key.
12155      * @param {String/Number} key The key of the item.
12156      * @return {Object} The item associated with the passed key.
12157      */
12158     key : function(key){
12159         return this.map[key];
12160     },
12161
12162     /**
12163      * Returns true if the collection contains the passed Object as an item.
12164      * @param {Object} o  The Object to look for in the collection.
12165      * @return {Boolean} True if the collection contains the Object as an item.
12166      */
12167     contains : function(o){
12168         return this.indexOf(o) != -1;
12169     },
12170
12171     /**
12172      * Returns true if the collection contains the passed Object as a key.
12173      * @param {String} key The key to look for in the collection.
12174      * @return {Boolean} True if the collection contains the Object as a key.
12175      */
12176     containsKey : function(key){
12177         return typeof this.map[key] != 'undefined';
12178     },
12179
12180     /**
12181      * Removes all items from the collection.  Fires the {@link #clear} event when complete.
12182      */
12183     clear : function(){
12184         this.length = 0;
12185         this.items = [];
12186         this.keys = [];
12187         this.map = {};
12188         this.fireEvent('clear');
12189     },
12190
12191     /**
12192      * Returns the first item in the collection.
12193      * @return {Object} the first item in the collection..
12194      */
12195     first : function(){
12196         return this.items[0];
12197     },
12198
12199     /**
12200      * Returns the last item in the collection.
12201      * @return {Object} the last item in the collection..
12202      */
12203     last : function(){
12204         return this.items[this.length-1];
12205     },
12206
12207     /**
12208      * @private
12209      * Performs the actual sorting based on a direction and a sorting function. Internally,
12210      * this creates a temporary array of all items in the MixedCollection, sorts it and then writes
12211      * the sorted array data back into this.items and this.keys
12212      * @param {String} property Property to sort by ('key', 'value', or 'index')
12213      * @param {String} dir (optional) Direction to sort 'ASC' or 'DESC'. Defaults to 'ASC'.
12214      * @param {Function} fn (optional) Comparison function that defines the sort order.
12215      * Defaults to sorting by numeric value.
12216      */
12217     _sort : function(property, dir, fn){
12218         var i, len,
12219             dsc   = String(dir).toUpperCase() == 'DESC' ? -1 : 1,
12220
12221             //this is a temporary array used to apply the sorting function
12222             c     = [],
12223             keys  = this.keys,
12224             items = this.items;
12225
12226         //default to a simple sorter function if one is not provided
12227         fn = fn || function(a, b) {
12228             return a - b;
12229         };
12230
12231         //copy all the items into a temporary array, which we will sort
12232         for(i = 0, len = items.length; i < len; i++){
12233             c[c.length] = {
12234                 key  : keys[i],
12235                 value: items[i],
12236                 index: i
12237             };
12238         }
12239
12240         //sort the temporary array
12241         c.sort(function(a, b){
12242             var v = fn(a[property], b[property]) * dsc;
12243             if(v === 0){
12244                 v = (a.index < b.index ? -1 : 1);
12245             }
12246             return v;
12247         });
12248
12249         //copy the temporary array back into the main this.items and this.keys objects
12250         for(i = 0, len = c.length; i < len; i++){
12251             items[i] = c[i].value;
12252             keys[i]  = c[i].key;
12253         }
12254
12255         this.fireEvent('sort', this);
12256     },
12257
12258     /**
12259      * Sorts this collection by <b>item</b> value with the passed comparison function.
12260      * @param {String} direction (optional) 'ASC' or 'DESC'. Defaults to 'ASC'.
12261      * @param {Function} fn (optional) Comparison function that defines the sort order.
12262      * Defaults to sorting by numeric value.
12263      */
12264     sort : function(dir, fn){
12265         this._sort('value', dir, fn);
12266     },
12267
12268     /**
12269      * Reorders each of the items based on a mapping from old index to new index. Internally this
12270      * just translates into a sort. The 'sort' event is fired whenever reordering has occured.
12271      * @param {Object} mapping Mapping from old item index to new item index
12272      */
12273     reorder: function(mapping) {
12274         this.suspendEvents();
12275
12276         var items     = this.items,
12277             index     = 0,
12278             length    = items.length,
12279             order     = [],
12280             remaining = [];
12281
12282         //object of {oldPosition: newPosition} reversed to {newPosition: oldPosition}
12283         for (oldIndex in mapping) {
12284             order[mapping[oldIndex]] = items[oldIndex];
12285         }
12286
12287         for (index = 0; index < length; index++) {
12288             if (mapping[index] == undefined) {
12289                 remaining.push(items[index]);
12290             }
12291         }
12292
12293         for (index = 0; index < length; index++) {
12294             if (order[index] == undefined) {
12295                 order[index] = remaining.shift();
12296             }
12297         }
12298
12299         this.clear();
12300         this.addAll(order);
12301
12302         this.resumeEvents();
12303         this.fireEvent('sort', this);
12304     },
12305
12306     /**
12307      * Sorts this collection by <b>key</b>s.
12308      * @param {String} direction (optional) 'ASC' or 'DESC'. Defaults to 'ASC'.
12309      * @param {Function} fn (optional) Comparison function that defines the sort order.
12310      * Defaults to sorting by case insensitive string.
12311      */
12312     keySort : function(dir, fn){
12313         this._sort('key', dir, fn || function(a, b){
12314             var v1 = String(a).toUpperCase(), v2 = String(b).toUpperCase();
12315             return v1 > v2 ? 1 : (v1 < v2 ? -1 : 0);
12316         });
12317     },
12318
12319     /**
12320      * Returns a range of items in this collection
12321      * @param {Number} startIndex (optional) The starting index. Defaults to 0.
12322      * @param {Number} endIndex (optional) The ending index. Defaults to the last item.
12323      * @return {Array} An array of items
12324      */
12325     getRange : function(start, end){
12326         var items = this.items;
12327         if(items.length < 1){
12328             return [];
12329         }
12330         start = start || 0;
12331         end = Math.min(typeof end == 'undefined' ? this.length-1 : end, this.length-1);
12332         var i, r = [];
12333         if(start <= end){
12334             for(i = start; i <= end; i++) {
12335                 r[r.length] = items[i];
12336             }
12337         }else{
12338             for(i = start; i >= end; i--) {
12339                 r[r.length] = items[i];
12340             }
12341         }
12342         return r;
12343     },
12344
12345     /**
12346      * Filter the <i>objects</i> in this collection by a specific property.
12347      * Returns a new collection that has been filtered.
12348      * @param {String} property A property on your objects
12349      * @param {String/RegExp} value Either string that the property values
12350      * should start with or a RegExp to test against the property
12351      * @param {Boolean} anyMatch (optional) True to match any part of the string, not just the beginning
12352      * @param {Boolean} caseSensitive (optional) True for case sensitive comparison (defaults to False).
12353      * @return {MixedCollection} The new filtered collection
12354      */
12355     filter : function(property, value, anyMatch, caseSensitive){
12356         if(Ext.isEmpty(value, false)){
12357             return this.clone();
12358         }
12359         value = this.createValueMatcher(value, anyMatch, caseSensitive);
12360         return this.filterBy(function(o){
12361             return o && value.test(o[property]);
12362         });
12363     },
12364
12365     /**
12366      * Filter by a function. Returns a <i>new</i> collection that has been filtered.
12367      * The passed function will be called with each object in the collection.
12368      * If the function returns true, the value is included otherwise it is filtered.
12369      * @param {Function} fn The function to be called, it will receive the args o (the object), k (the key)
12370      * @param {Object} scope (optional) The scope (<code>this</code> reference) in which the function is executed. Defaults to this MixedCollection.
12371      * @return {MixedCollection} The new filtered collection
12372      */
12373     filterBy : function(fn, scope){
12374         var r = new Ext.util.MixedCollection();
12375         r.getKey = this.getKey;
12376         var k = this.keys, it = this.items;
12377         for(var i = 0, len = it.length; i < len; i++){
12378             if(fn.call(scope||this, it[i], k[i])){
12379                 r.add(k[i], it[i]);
12380             }
12381         }
12382         return r;
12383     },
12384
12385     /**
12386      * Finds the index of the first matching object in this collection by a specific property/value.
12387      * @param {String} property The name of a property on your objects.
12388      * @param {String/RegExp} value A string that the property values
12389      * should start with or a RegExp to test against the property.
12390      * @param {Number} start (optional) The index to start searching at (defaults to 0).
12391      * @param {Boolean} anyMatch (optional) True to match any part of the string, not just the beginning.
12392      * @param {Boolean} caseSensitive (optional) True for case sensitive comparison.
12393      * @return {Number} The matched index or -1
12394      */
12395     findIndex : function(property, value, start, anyMatch, caseSensitive){
12396         if(Ext.isEmpty(value, false)){
12397             return -1;
12398         }
12399         value = this.createValueMatcher(value, anyMatch, caseSensitive);
12400         return this.findIndexBy(function(o){
12401             return o && value.test(o[property]);
12402         }, null, start);
12403     },
12404
12405     /**
12406      * Find the index of the first matching object in this collection by a function.
12407      * If the function returns <i>true</i> it is considered a match.
12408      * @param {Function} fn The function to be called, it will receive the args o (the object), k (the key).
12409      * @param {Object} scope (optional) The scope (<code>this</code> reference) in which the function is executed. Defaults to this MixedCollection.
12410      * @param {Number} start (optional) The index to start searching at (defaults to 0).
12411      * @return {Number} The matched index or -1
12412      */
12413     findIndexBy : function(fn, scope, start){
12414         var k = this.keys, it = this.items;
12415         for(var i = (start||0), len = it.length; i < len; i++){
12416             if(fn.call(scope||this, it[i], k[i])){
12417                 return i;
12418             }
12419         }
12420         return -1;
12421     },
12422
12423     /**
12424      * Returns a regular expression based on the given value and matching options. This is used internally for finding and filtering,
12425      * and by Ext.data.Store#filter
12426      * @private
12427      * @param {String} value The value to create the regex for. This is escaped using Ext.escapeRe
12428      * @param {Boolean} anyMatch True to allow any match - no regex start/end line anchors will be added. Defaults to false
12429      * @param {Boolean} caseSensitive True to make the regex case sensitive (adds 'i' switch to regex). Defaults to false.
12430      * @param {Boolean} exactMatch True to force exact match (^ and $ characters added to the regex). Defaults to false. Ignored if anyMatch is true.
12431      */
12432     createValueMatcher : function(value, anyMatch, caseSensitive, exactMatch) {
12433         if (!value.exec) { // not a regex
12434             var er = Ext.escapeRe;
12435             value = String(value);
12436
12437             if (anyMatch === true) {
12438                 value = er(value);
12439             } else {
12440                 value = '^' + er(value);
12441                 if (exactMatch === true) {
12442                     value += '$';
12443                 }
12444             }
12445             value = new RegExp(value, caseSensitive ? '' : 'i');
12446          }
12447          return value;
12448     },
12449
12450     /**
12451      * Creates a shallow copy of this collection
12452      * @return {MixedCollection}
12453      */
12454     clone : function(){
12455         var r = new Ext.util.MixedCollection();
12456         var k = this.keys, it = this.items;
12457         for(var i = 0, len = it.length; i < len; i++){
12458             r.add(k[i], it[i]);
12459         }
12460         r.getKey = this.getKey;
12461         return r;
12462     }
12463 });
12464 /**
12465  * This method calls {@link #item item()}.
12466  * Returns the item associated with the passed key OR index. Key has priority
12467  * over index.  This is the equivalent of calling {@link #key} first, then if
12468  * nothing matched calling {@link #itemAt}.
12469  * @param {String/Number} key The key or index of the item.
12470  * @return {Object} If the item is found, returns the item.  If the item was
12471  * not found, returns <tt>undefined</tt>. If an item was found, but is a Class,
12472  * returns <tt>null</tt>.
12473  */
12474 Ext.util.MixedCollection.prototype.get = Ext.util.MixedCollection.prototype.item;
12475 /**
12476  * @class Ext.util.JSON
12477  * Modified version of Douglas Crockford"s json.js that doesn"t
12478  * mess with the Object prototype
12479  * http://www.json.org/js.html
12480  * @singleton
12481  */
12482 Ext.util.JSON = new (function(){
12483     var useHasOwn = !!{}.hasOwnProperty,
12484         isNative = function() {
12485             var useNative = null;
12486
12487             return function() {
12488                 if (useNative === null) {
12489                     useNative = Ext.USE_NATIVE_JSON && window.JSON && JSON.toString() == '[object JSON]';
12490                 }
12491         
12492                 return useNative;
12493             };
12494         }(),
12495         pad = function(n) {
12496             return n < 10 ? "0" + n : n;
12497         },
12498         doDecode = function(json){
12499             return eval("(" + json + ')');    
12500         },
12501         doEncode = function(o){
12502             if(!Ext.isDefined(o) || o === null){
12503                 return "null";
12504             }else if(Ext.isArray(o)){
12505                 return encodeArray(o);
12506             }else if(Ext.isDate(o)){
12507                 return Ext.util.JSON.encodeDate(o);
12508             }else if(Ext.isString(o)){
12509                 return encodeString(o);
12510             }else if(typeof o == "number"){
12511                 //don't use isNumber here, since finite checks happen inside isNumber
12512                 return isFinite(o) ? String(o) : "null";
12513             }else if(Ext.isBoolean(o)){
12514                 return String(o);
12515             }else {
12516                 var a = ["{"], b, i, v;
12517                 for (i in o) {
12518                     // don't encode DOM objects
12519                     if(!o.getElementsByTagName){
12520                         if(!useHasOwn || o.hasOwnProperty(i)) {
12521                             v = o[i];
12522                             switch (typeof v) {
12523                             case "undefined":
12524                             case "function":
12525                             case "unknown":
12526                                 break;
12527                             default:
12528                                 if(b){
12529                                     a.push(',');
12530                                 }
12531                                 a.push(doEncode(i), ":",
12532                                         v === null ? "null" : doEncode(v));
12533                                 b = true;
12534                             }
12535                         }
12536                     }
12537                 }
12538                 a.push("}");
12539                 return a.join("");
12540             }    
12541         },
12542         m = {
12543             "\b": '\\b',
12544             "\t": '\\t',
12545             "\n": '\\n',
12546             "\f": '\\f',
12547             "\r": '\\r',
12548             '"' : '\\"',
12549             "\\": '\\\\'
12550         },
12551         encodeString = function(s){
12552             if (/["\\\x00-\x1f]/.test(s)) {
12553                 return '"' + s.replace(/([\x00-\x1f\\"])/g, function(a, b) {
12554                     var c = m[b];
12555                     if(c){
12556                         return c;
12557                     }
12558                     c = b.charCodeAt();
12559                     return "\\u00" +
12560                         Math.floor(c / 16).toString(16) +
12561                         (c % 16).toString(16);
12562                 }) + '"';
12563             }
12564             return '"' + s + '"';
12565         },
12566         encodeArray = function(o){
12567             var a = ["["], b, i, l = o.length, v;
12568                 for (i = 0; i < l; i += 1) {
12569                     v = o[i];
12570                     switch (typeof v) {
12571                         case "undefined":
12572                         case "function":
12573                         case "unknown":
12574                             break;
12575                         default:
12576                             if (b) {
12577                                 a.push(',');
12578                             }
12579                             a.push(v === null ? "null" : Ext.util.JSON.encode(v));
12580                             b = true;
12581                     }
12582                 }
12583                 a.push("]");
12584                 return a.join("");
12585         };
12586
12587     /**
12588      * <p>Encodes a Date. This returns the actual string which is inserted into the JSON string as the literal expression.
12589      * <b>The returned value includes enclosing double quotation marks.</b></p>
12590      * <p>The default return format is "yyyy-mm-ddThh:mm:ss".</p>
12591      * <p>To override this:</p><pre><code>
12592 Ext.util.JSON.encodeDate = function(d) {
12593     return d.format('"Y-m-d"');
12594 };
12595 </code></pre>
12596      * @param {Date} d The Date to encode
12597      * @return {String} The string literal to use in a JSON string.
12598      */
12599     this.encodeDate = function(o){
12600         return '"' + o.getFullYear() + "-" +
12601                 pad(o.getMonth() + 1) + "-" +
12602                 pad(o.getDate()) + "T" +
12603                 pad(o.getHours()) + ":" +
12604                 pad(o.getMinutes()) + ":" +
12605                 pad(o.getSeconds()) + '"';
12606     };
12607
12608     /**
12609      * Encodes an Object, Array or other value
12610      * @param {Mixed} o The variable to encode
12611      * @return {String} The JSON string
12612      */
12613     this.encode = function() {
12614         var ec;
12615         return function(o) {
12616             if (!ec) {
12617                 // setup encoding function on first access
12618                 ec = isNative() ? JSON.stringify : doEncode;
12619             }
12620             return ec(o);
12621         };
12622     }();
12623
12624
12625     /**
12626      * Decodes (parses) a JSON string to an object. If the JSON is invalid, this function throws a SyntaxError unless the safe option is set.
12627      * @param {String} json The JSON string
12628      * @return {Object} The resulting object
12629      */
12630     this.decode = function() {
12631         var dc;
12632         return function(json) {
12633             if (!dc) {
12634                 // setup decoding function on first access
12635                 dc = isNative() ? JSON.parse : doDecode;
12636             }
12637             return dc(json);
12638         };
12639     }();
12640
12641 })();
12642 /**
12643  * Shorthand for {@link Ext.util.JSON#encode}
12644  * @param {Mixed} o The variable to encode
12645  * @return {String} The JSON string
12646  * @member Ext
12647  * @method encode
12648  */
12649 Ext.encode = Ext.util.JSON.encode;
12650 /**
12651  * Shorthand for {@link Ext.util.JSON#decode}
12652  * @param {String} json The JSON string
12653  * @param {Boolean} safe (optional) Whether to return null or throw an exception if the JSON is invalid.
12654  * @return {Object} The resulting object
12655  * @member Ext
12656  * @method decode
12657  */
12658 Ext.decode = Ext.util.JSON.decode;
12659 /**
12660  * @class Ext.util.Format
12661  * Reusable data formatting functions
12662  * @singleton
12663  */
12664 Ext.util.Format = function(){
12665     var trimRe = /^\s+|\s+$/g,
12666         stripTagsRE = /<\/?[^>]+>/gi,
12667         stripScriptsRe = /(?:<script.*?>)((\n|\r|.)*?)(?:<\/script>)/ig,
12668         nl2brRe = /\r?\n/g;
12669
12670     return {
12671         /**
12672          * Truncate a string and add an ellipsis ('...') to the end if it exceeds the specified length
12673          * @param {String} value The string to truncate
12674          * @param {Number} length The maximum length to allow before truncating
12675          * @param {Boolean} word True to try to find a common work break
12676          * @return {String} The converted text
12677          */
12678         ellipsis : function(value, len, word){
12679             if(value && value.length > len){
12680                 if(word){
12681                     var vs = value.substr(0, len - 2),
12682                         index = Math.max(vs.lastIndexOf(' '), vs.lastIndexOf('.'), vs.lastIndexOf('!'), vs.lastIndexOf('?'));
12683                     if(index == -1 || index < (len - 15)){
12684                         return value.substr(0, len - 3) + "...";
12685                     }else{
12686                         return vs.substr(0, index) + "...";
12687                     }
12688                 } else{
12689                     return value.substr(0, len - 3) + "...";
12690                 }
12691             }
12692             return value;
12693         },
12694
12695         /**
12696          * Checks a reference and converts it to empty string if it is undefined
12697          * @param {Mixed} value Reference to check
12698          * @return {Mixed} Empty string if converted, otherwise the original value
12699          */
12700         undef : function(value){
12701             return value !== undefined ? value : "";
12702         },
12703
12704         /**
12705          * Checks a reference and converts it to the default value if it's empty
12706          * @param {Mixed} value Reference to check
12707          * @param {String} defaultValue The value to insert of it's undefined (defaults to "")
12708          * @return {String}
12709          */
12710         defaultValue : function(value, defaultValue){
12711             return value !== undefined && value !== '' ? value : defaultValue;
12712         },
12713
12714         /**
12715          * Convert certain characters (&, <, >, and ') to their HTML character equivalents for literal display in web pages.
12716          * @param {String} value The string to encode
12717          * @return {String} The encoded text
12718          */
12719         htmlEncode : function(value){
12720             return !value ? value : String(value).replace(/&/g, "&amp;").replace(/>/g, "&gt;").replace(/</g, "&lt;").replace(/"/g, "&quot;");
12721         },
12722
12723         /**
12724          * Convert certain characters (&, <, >, and ') from their HTML character equivalents.
12725          * @param {String} value The string to decode
12726          * @return {String} The decoded text
12727          */
12728         htmlDecode : function(value){
12729             return !value ? value : String(value).replace(/&gt;/g, ">").replace(/&lt;/g, "<").replace(/&quot;/g, '"').replace(/&amp;/g, "&");
12730         },
12731
12732         /**
12733          * Trims any whitespace from either side of a string
12734          * @param {String} value The text to trim
12735          * @return {String} The trimmed text
12736          */
12737         trim : function(value){
12738             return String(value).replace(trimRe, "");
12739         },
12740
12741         /**
12742          * Returns a substring from within an original string
12743          * @param {String} value The original text
12744          * @param {Number} start The start index of the substring
12745          * @param {Number} length The length of the substring
12746          * @return {String} The substring
12747          */
12748         substr : function(value, start, length){
12749             return String(value).substr(start, length);
12750         },
12751
12752         /**
12753          * Converts a string to all lower case letters
12754          * @param {String} value The text to convert
12755          * @return {String} The converted text
12756          */
12757         lowercase : function(value){
12758             return String(value).toLowerCase();
12759         },
12760
12761         /**
12762          * Converts a string to all upper case letters
12763          * @param {String} value The text to convert
12764          * @return {String} The converted text
12765          */
12766         uppercase : function(value){
12767             return String(value).toUpperCase();
12768         },
12769
12770         /**
12771          * Converts the first character only of a string to upper case
12772          * @param {String} value The text to convert
12773          * @return {String} The converted text
12774          */
12775         capitalize : function(value){
12776             return !value ? value : value.charAt(0).toUpperCase() + value.substr(1).toLowerCase();
12777         },
12778
12779         // private
12780         call : function(value, fn){
12781             if(arguments.length > 2){
12782                 var args = Array.prototype.slice.call(arguments, 2);
12783                 args.unshift(value);
12784                 return eval(fn).apply(window, args);
12785             }else{
12786                 return eval(fn).call(window, value);
12787             }
12788         },
12789
12790         /**
12791          * Format a number as US currency
12792          * @param {Number/String} value The numeric value to format
12793          * @return {String} The formatted currency string
12794          */
12795         usMoney : function(v){
12796             v = (Math.round((v-0)*100))/100;
12797             v = (v == Math.floor(v)) ? v + ".00" : ((v*10 == Math.floor(v*10)) ? v + "0" : v);
12798             v = String(v);
12799             var ps = v.split('.'),
12800                 whole = ps[0],
12801                 sub = ps[1] ? '.'+ ps[1] : '.00',
12802                 r = /(\d+)(\d{3})/;
12803             while (r.test(whole)) {
12804                 whole = whole.replace(r, '$1' + ',' + '$2');
12805             }
12806             v = whole + sub;
12807             if(v.charAt(0) == '-'){
12808                 return '-$' + v.substr(1);
12809             }
12810             return "$" +  v;
12811         },
12812
12813         /**
12814          * Parse a value into a formatted date using the specified format pattern.
12815          * @param {String/Date} value The value to format (Strings must conform to the format expected by the javascript Date object's <a href="http://www.w3schools.com/jsref/jsref_parse.asp">parse()</a> method)
12816          * @param {String} format (optional) Any valid date format string (defaults to 'm/d/Y')
12817          * @return {String} The formatted date string
12818          */
12819         date : function(v, format){
12820             if(!v){
12821                 return "";
12822             }
12823             if(!Ext.isDate(v)){
12824                 v = new Date(Date.parse(v));
12825             }
12826             return v.dateFormat(format || "m/d/Y");
12827         },
12828
12829         /**
12830          * Returns a date rendering function that can be reused to apply a date format multiple times efficiently
12831          * @param {String} format Any valid date format string
12832          * @return {Function} The date formatting function
12833          */
12834         dateRenderer : function(format){
12835             return function(v){
12836                 return Ext.util.Format.date(v, format);
12837             };
12838         },
12839
12840         /**
12841          * Strips all HTML tags
12842          * @param {Mixed} value The text from which to strip tags
12843          * @return {String} The stripped text
12844          */
12845         stripTags : function(v){
12846             return !v ? v : String(v).replace(stripTagsRE, "");
12847         },
12848
12849         /**
12850          * Strips all script tags
12851          * @param {Mixed} value The text from which to strip script tags
12852          * @return {String} The stripped text
12853          */
12854         stripScripts : function(v){
12855             return !v ? v : String(v).replace(stripScriptsRe, "");
12856         },
12857
12858         /**
12859          * Simple format for a file size (xxx bytes, xxx KB, xxx MB)
12860          * @param {Number/String} size The numeric value to format
12861          * @return {String} The formatted file size
12862          */
12863         fileSize : function(size){
12864             if(size < 1024) {
12865                 return size + " bytes";
12866             } else if(size < 1048576) {
12867                 return (Math.round(((size*10) / 1024))/10) + " KB";
12868             } else {
12869                 return (Math.round(((size*10) / 1048576))/10) + " MB";
12870             }
12871         },
12872
12873         /**
12874          * It does simple math for use in a template, for example:<pre><code>
12875          * var tpl = new Ext.Template('{value} * 10 = {value:math("* 10")}');
12876          * </code></pre>
12877          * @return {Function} A function that operates on the passed value.
12878          */
12879         math : function(){
12880             var fns = {};
12881             return function(v, a){
12882                 if(!fns[a]){
12883                     fns[a] = new Function('v', 'return v ' + a + ';');
12884                 }
12885                 return fns[a](v);
12886             }
12887         }(),
12888
12889         /**
12890          * Rounds the passed number to the required decimal precision.
12891          * @param {Number/String} value The numeric value to round.
12892          * @param {Number} precision The number of decimal places to which to round the first parameter's value.
12893          * @return {Number} The rounded value.
12894          */
12895         round : function(value, precision) {
12896             var result = Number(value);
12897             if (typeof precision == 'number') {
12898                 precision = Math.pow(10, precision);
12899                 result = Math.round(value * precision) / precision;
12900             }
12901             return result;
12902         },
12903
12904         /**
12905          * Formats the number according to the format string.
12906          * <div style="margin-left:40px">examples (123456.789):
12907          * <div style="margin-left:10px">
12908          * 0 - (123456) show only digits, no precision<br>
12909          * 0.00 - (123456.78) show only digits, 2 precision<br>
12910          * 0.0000 - (123456.7890) show only digits, 4 precision<br>
12911          * 0,000 - (123,456) show comma and digits, no precision<br>
12912          * 0,000.00 - (123,456.78) show comma and digits, 2 precision<br>
12913          * 0,0.00 - (123,456.78) shortcut method, show comma and digits, 2 precision<br>
12914          * To reverse the grouping (,) and decimal (.) for international numbers, add /i to the end.
12915          * For example: 0.000,00/i
12916          * </div></div>
12917          * @param {Number} v The number to format.
12918          * @param {String} format The way you would like to format this text.
12919          * @return {String} The formatted number.
12920          */
12921         number: function(v, format) {
12922             if(!format){
12923                 return v;
12924             }
12925             v = Ext.num(v, NaN);
12926             if (isNaN(v)){
12927                 return '';
12928             }
12929             var comma = ',',
12930                 dec = '.',
12931                 i18n = false,
12932                 neg = v < 0;
12933
12934             v = Math.abs(v);
12935             if(format.substr(format.length - 2) == '/i'){
12936                 format = format.substr(0, format.length - 2);
12937                 i18n = true;
12938                 comma = '.';
12939                 dec = ',';
12940             }
12941
12942             var hasComma = format.indexOf(comma) != -1,
12943                 psplit = (i18n ? format.replace(/[^\d\,]/g, '') : format.replace(/[^\d\.]/g, '')).split(dec);
12944
12945             if(1 < psplit.length){
12946                 v = v.toFixed(psplit[1].length);
12947             }else if(2 < psplit.length){
12948                 throw ('NumberFormatException: invalid format, formats should have no more than 1 period: ' + format);
12949             }else{
12950                 v = v.toFixed(0);
12951             }
12952
12953             var fnum = v.toString();
12954
12955             psplit = fnum.split('.');
12956
12957             if (hasComma) {
12958                 var cnum = psplit[0], parr = [], j = cnum.length, m = Math.floor(j / 3), n = cnum.length % 3 || 3;
12959
12960                 for (var i = 0; i < j; i += n) {
12961                     if (i != 0) {
12962                         n = 3;
12963                     }
12964                     parr[parr.length] = cnum.substr(i, n);
12965                     m -= 1;
12966                 }
12967                 fnum = parr.join(comma);
12968                 if (psplit[1]) {
12969                     fnum += dec + psplit[1];
12970                 }
12971             } else {
12972                 if (psplit[1]) {
12973                     fnum = psplit[0] + dec + psplit[1];
12974                 }
12975             }
12976
12977             return (neg ? '-' : '') + format.replace(/[\d,?\.?]+/, fnum);
12978         },
12979
12980         /**
12981          * Returns a number rendering function that can be reused to apply a number format multiple times efficiently
12982          * @param {String} format Any valid number format string for {@link #number}
12983          * @return {Function} The number formatting function
12984          */
12985         numberRenderer : function(format){
12986             return function(v){
12987                 return Ext.util.Format.number(v, format);
12988             };
12989         },
12990
12991         /**
12992          * Selectively do a plural form of a word based on a numeric value. For example, in a template,
12993          * {commentCount:plural("Comment")}  would result in "1 Comment" if commentCount was 1 or would be "x Comments"
12994          * if the value is 0 or greater than 1.
12995          * @param {Number} value The value to compare against
12996          * @param {String} singular The singular form of the word
12997          * @param {String} plural (optional) The plural form of the word (defaults to the singular with an "s")
12998          */
12999         plural : function(v, s, p){
13000             return v +' ' + (v == 1 ? s : (p ? p : s+'s'));
13001         },
13002
13003         /**
13004          * Converts newline characters to the HTML tag &lt;br/>
13005          * @param {String} The string value to format.
13006          * @return {String} The string with embedded &lt;br/> tags in place of newlines.
13007          */
13008         nl2br : function(v){
13009             return Ext.isEmpty(v) ? '' : v.replace(nl2brRe, '<br/>');
13010         }
13011     }
13012 }();
13013 /**
13014  * @class Ext.XTemplate
13015  * @extends Ext.Template
13016  * <p>A template class that supports advanced functionality like:<div class="mdetail-params"><ul>
13017  * <li>Autofilling arrays using templates and sub-templates</li>
13018  * <li>Conditional processing with basic comparison operators</li>
13019  * <li>Basic math function support</li>
13020  * <li>Execute arbitrary inline code with special built-in template variables</li>
13021  * <li>Custom member functions</li>
13022  * <li>Many special tags and built-in operators that aren't defined as part of
13023  * the API, but are supported in the templates that can be created</li>
13024  * </ul></div></p>
13025  * <p>XTemplate provides the templating mechanism built into:<div class="mdetail-params"><ul>
13026  * <li>{@link Ext.DataView}</li>
13027  * <li>{@link Ext.ListView}</li>
13028  * <li>{@link Ext.form.ComboBox}</li>
13029  * <li>{@link Ext.grid.TemplateColumn}</li>
13030  * <li>{@link Ext.grid.GroupingView}</li>
13031  * <li>{@link Ext.menu.Item}</li>
13032  * <li>{@link Ext.layout.MenuLayout}</li>
13033  * <li>{@link Ext.ColorPalette}</li>
13034  * </ul></div></p>
13035  *
13036  * <p>For example usage {@link #XTemplate see the constructor}.</p>
13037  *
13038  * @constructor
13039  * The {@link Ext.Template#Template Ext.Template constructor} describes
13040  * the acceptable parameters to pass to the constructor. The following
13041  * examples demonstrate all of the supported features.</p>
13042  *
13043  * <div class="mdetail-params"><ul>
13044  *
13045  * <li><b><u>Sample Data</u></b>
13046  * <div class="sub-desc">
13047  * <p>This is the data object used for reference in each code example:</p>
13048  * <pre><code>
13049 var data = {
13050     name: 'Jack Slocum',
13051     title: 'Lead Developer',
13052     company: 'Ext JS, LLC',
13053     email: 'jack@extjs.com',
13054     address: '4 Red Bulls Drive',
13055     city: 'Cleveland',
13056     state: 'Ohio',
13057     zip: '44102',
13058     drinks: ['Red Bull', 'Coffee', 'Water'],
13059     kids: [{
13060         name: 'Sara Grace',
13061         age:3
13062     },{
13063         name: 'Zachary',
13064         age:2
13065     },{
13066         name: 'John James',
13067         age:0
13068     }]
13069 };
13070  * </code></pre>
13071  * </div>
13072  * </li>
13073  *
13074  *
13075  * <li><b><u>Auto filling of arrays</u></b>
13076  * <div class="sub-desc">
13077  * <p>The <b><tt>tpl</tt></b> tag and the <b><tt>for</tt></b> operator are used
13078  * to process the provided data object:
13079  * <ul>
13080  * <li>If the value specified in <tt>for</tt> is an array, it will auto-fill,
13081  * repeating the template block inside the <tt>tpl</tt> tag for each item in the
13082  * array.</li>
13083  * <li>If <tt>for="."</tt> is specified, the data object provided is examined.</li>
13084  * <li>While processing an array, the special variable <tt>{#}</tt>
13085  * will provide the current array index + 1 (starts at 1, not 0).</li>
13086  * </ul>
13087  * </p>
13088  * <pre><code>
13089 &lt;tpl <b>for</b>=".">...&lt;/tpl>       // loop through array at root node
13090 &lt;tpl <b>for</b>="foo">...&lt;/tpl>     // loop through array at foo node
13091 &lt;tpl <b>for</b>="foo.bar">...&lt;/tpl> // loop through array at foo.bar node
13092  * </code></pre>
13093  * Using the sample data above:
13094  * <pre><code>
13095 var tpl = new Ext.XTemplate(
13096     '&lt;p>Kids: ',
13097     '&lt;tpl <b>for</b>=".">',       // process the data.kids node
13098         '&lt;p>{#}. {name}&lt;/p>',  // use current array index to autonumber
13099     '&lt;/tpl>&lt;/p>'
13100 );
13101 tpl.overwrite(panel.body, data.kids); // pass the kids property of the data object
13102  * </code></pre>
13103  * <p>An example illustrating how the <b><tt>for</tt></b> property can be leveraged
13104  * to access specified members of the provided data object to populate the template:</p>
13105  * <pre><code>
13106 var tpl = new Ext.XTemplate(
13107     '&lt;p>Name: {name}&lt;/p>',
13108     '&lt;p>Title: {title}&lt;/p>',
13109     '&lt;p>Company: {company}&lt;/p>',
13110     '&lt;p>Kids: ',
13111     '&lt;tpl <b>for="kids"</b>>',     // interrogate the kids property within the data
13112         '&lt;p>{name}&lt;/p>',
13113     '&lt;/tpl>&lt;/p>'
13114 );
13115 tpl.overwrite(panel.body, data);  // pass the root node of the data object
13116  * </code></pre>
13117  * <p>Flat arrays that contain values (and not objects) can be auto-rendered
13118  * using the special <b><tt>{.}</tt></b> variable inside a loop.  This variable
13119  * will represent the value of the array at the current index:</p>
13120  * <pre><code>
13121 var tpl = new Ext.XTemplate(
13122     '&lt;p>{name}\&#39;s favorite beverages:&lt;/p>',
13123     '&lt;tpl for="drinks">',
13124        '&lt;div> - {.}&lt;/div>',
13125     '&lt;/tpl>'
13126 );
13127 tpl.overwrite(panel.body, data);
13128  * </code></pre>
13129  * <p>When processing a sub-template, for example while looping through a child array,
13130  * you can access the parent object's members via the <b><tt>parent</tt></b> object:</p>
13131  * <pre><code>
13132 var tpl = new Ext.XTemplate(
13133     '&lt;p>Name: {name}&lt;/p>',
13134     '&lt;p>Kids: ',
13135     '&lt;tpl for="kids">',
13136         '&lt;tpl if="age > 1">',
13137             '&lt;p>{name}&lt;/p>',
13138             '&lt;p>Dad: {<b>parent</b>.name}&lt;/p>',
13139         '&lt;/tpl>',
13140     '&lt;/tpl>&lt;/p>'
13141 );
13142 tpl.overwrite(panel.body, data);
13143  * </code></pre>
13144  * </div>
13145  * </li>
13146  *
13147  *
13148  * <li><b><u>Conditional processing with basic comparison operators</u></b>
13149  * <div class="sub-desc">
13150  * <p>The <b><tt>tpl</tt></b> tag and the <b><tt>if</tt></b> operator are used
13151  * to provide conditional checks for deciding whether or not to render specific
13152  * parts of the template. Notes:<div class="sub-desc"><ul>
13153  * <li>Double quotes must be encoded if used within the conditional</li>
13154  * <li>There is no <tt>else</tt> operator &mdash; if needed, two opposite
13155  * <tt>if</tt> statements should be used.</li>
13156  * </ul></div>
13157  * <pre><code>
13158 &lt;tpl if="age &gt; 1 &amp;&amp; age &lt; 10">Child&lt;/tpl>
13159 &lt;tpl if="age >= 10 && age < 18">Teenager&lt;/tpl>
13160 &lt;tpl <b>if</b>="this.isGirl(name)">...&lt;/tpl>
13161 &lt;tpl <b>if</b>="id==\'download\'">...&lt;/tpl>
13162 &lt;tpl <b>if</b>="needsIcon">&lt;img src="{icon}" class="{iconCls}"/>&lt;/tpl>
13163 // no good:
13164 &lt;tpl if="name == "Jack"">Hello&lt;/tpl>
13165 // encode &#34; if it is part of the condition, e.g.
13166 &lt;tpl if="name == &#38;quot;Jack&#38;quot;">Hello&lt;/tpl>
13167  * </code></pre>
13168  * Using the sample data above:
13169  * <pre><code>
13170 var tpl = new Ext.XTemplate(
13171     '&lt;p>Name: {name}&lt;/p>',
13172     '&lt;p>Kids: ',
13173     '&lt;tpl for="kids">',
13174         '&lt;tpl if="age > 1">',
13175             '&lt;p>{name}&lt;/p>',
13176         '&lt;/tpl>',
13177     '&lt;/tpl>&lt;/p>'
13178 );
13179 tpl.overwrite(panel.body, data);
13180  * </code></pre>
13181  * </div>
13182  * </li>
13183  *
13184  *
13185  * <li><b><u>Basic math support</u></b>
13186  * <div class="sub-desc">
13187  * <p>The following basic math operators may be applied directly on numeric
13188  * data values:</p><pre>
13189  * + - * /
13190  * </pre>
13191  * For example:
13192  * <pre><code>
13193 var tpl = new Ext.XTemplate(
13194     '&lt;p>Name: {name}&lt;/p>',
13195     '&lt;p>Kids: ',
13196     '&lt;tpl for="kids">',
13197         '&lt;tpl if="age &amp;gt; 1">',  // <-- Note that the &gt; is encoded
13198             '&lt;p>{#}: {name}&lt;/p>',  // <-- Auto-number each item
13199             '&lt;p>In 5 Years: {age+5}&lt;/p>',  // <-- Basic math
13200             '&lt;p>Dad: {parent.name}&lt;/p>',
13201         '&lt;/tpl>',
13202     '&lt;/tpl>&lt;/p>'
13203 );
13204 tpl.overwrite(panel.body, data);
13205 </code></pre>
13206  * </div>
13207  * </li>
13208  *
13209  *
13210  * <li><b><u>Execute arbitrary inline code with special built-in template variables</u></b>
13211  * <div class="sub-desc">
13212  * <p>Anything between <code>{[ ... ]}</code> is considered code to be executed
13213  * in the scope of the template. There are some special variables available in that code:
13214  * <ul>
13215  * <li><b><tt>values</tt></b>: The values in the current scope. If you are using
13216  * scope changing sub-templates, you can change what <tt>values</tt> is.</li>
13217  * <li><b><tt>parent</tt></b>: The scope (values) of the ancestor template.</li>
13218  * <li><b><tt>xindex</tt></b>: If you are in a looping template, the index of the
13219  * loop you are in (1-based).</li>
13220  * <li><b><tt>xcount</tt></b>: If you are in a looping template, the total length
13221  * of the array you are looping.</li>
13222  * <li><b><tt>fm</tt></b>: An alias for <tt>Ext.util.Format</tt>.</li>
13223  * </ul>
13224  * This example demonstrates basic row striping using an inline code block and the
13225  * <tt>xindex</tt> variable:</p>
13226  * <pre><code>
13227 var tpl = new Ext.XTemplate(
13228     '&lt;p>Name: {name}&lt;/p>',
13229     '&lt;p>Company: {[values.company.toUpperCase() + ", " + values.title]}&lt;/p>',
13230     '&lt;p>Kids: ',
13231     '&lt;tpl for="kids">',
13232        '&lt;div class="{[xindex % 2 === 0 ? "even" : "odd"]}">',
13233         '{name}',
13234         '&lt;/div>',
13235     '&lt;/tpl>&lt;/p>'
13236 );
13237 tpl.overwrite(panel.body, data);
13238  * </code></pre>
13239  * </div>
13240  * </li>
13241  *
13242  * <li><b><u>Template member functions</u></b>
13243  * <div class="sub-desc">
13244  * <p>One or more member functions can be specified in a configuration
13245  * object passed into the XTemplate constructor for more complex processing:</p>
13246  * <pre><code>
13247 var tpl = new Ext.XTemplate(
13248     '&lt;p>Name: {name}&lt;/p>',
13249     '&lt;p>Kids: ',
13250     '&lt;tpl for="kids">',
13251         '&lt;tpl if="this.isGirl(name)">',
13252             '&lt;p>Girl: {name} - {age}&lt;/p>',
13253         '&lt;/tpl>',
13254         // use opposite if statement to simulate 'else' processing:
13255         '&lt;tpl if="this.isGirl(name) == false">',
13256             '&lt;p>Boy: {name} - {age}&lt;/p>',
13257         '&lt;/tpl>',
13258         '&lt;tpl if="this.isBaby(age)">',
13259             '&lt;p>{name} is a baby!&lt;/p>',
13260         '&lt;/tpl>',
13261     '&lt;/tpl>&lt;/p>',
13262     {
13263         // XTemplate configuration:
13264         compiled: true,
13265         disableFormats: true,
13266         // member functions:
13267         isGirl: function(name){
13268             return name == 'Sara Grace';
13269         },
13270         isBaby: function(age){
13271             return age < 1;
13272         }
13273     }
13274 );
13275 tpl.overwrite(panel.body, data);
13276  * </code></pre>
13277  * </div>
13278  * </li>
13279  *
13280  * </ul></div>
13281  *
13282  * @param {Mixed} config
13283  */
13284 Ext.XTemplate = function(){
13285     Ext.XTemplate.superclass.constructor.apply(this, arguments);
13286
13287     var me = this,
13288         s = me.html,
13289         re = /<tpl\b[^>]*>((?:(?=([^<]+))\2|<(?!tpl\b[^>]*>))*?)<\/tpl>/,
13290         nameRe = /^<tpl\b[^>]*?for="(.*?)"/,
13291         ifRe = /^<tpl\b[^>]*?if="(.*?)"/,
13292         execRe = /^<tpl\b[^>]*?exec="(.*?)"/,
13293         m,
13294         id = 0,
13295         tpls = [],
13296         VALUES = 'values',
13297         PARENT = 'parent',
13298         XINDEX = 'xindex',
13299         XCOUNT = 'xcount',
13300         RETURN = 'return ',
13301         WITHVALUES = 'with(values){ ';
13302
13303     s = ['<tpl>', s, '</tpl>'].join('');
13304
13305     while((m = s.match(re))){
13306         var m2 = m[0].match(nameRe),
13307             m3 = m[0].match(ifRe),
13308             m4 = m[0].match(execRe),
13309             exp = null,
13310             fn = null,
13311             exec = null,
13312             name = m2 && m2[1] ? m2[1] : '';
13313
13314        if (m3) {
13315            exp = m3 && m3[1] ? m3[1] : null;
13316            if(exp){
13317                fn = new Function(VALUES, PARENT, XINDEX, XCOUNT, WITHVALUES + RETURN +(Ext.util.Format.htmlDecode(exp))+'; }');
13318            }
13319        }
13320        if (m4) {
13321            exp = m4 && m4[1] ? m4[1] : null;
13322            if(exp){
13323                exec = new Function(VALUES, PARENT, XINDEX, XCOUNT, WITHVALUES +(Ext.util.Format.htmlDecode(exp))+'; }');
13324            }
13325        }
13326        if(name){
13327            switch(name){
13328                case '.': name = new Function(VALUES, PARENT, WITHVALUES + RETURN + VALUES + '; }'); break;
13329                case '..': name = new Function(VALUES, PARENT, WITHVALUES + RETURN + PARENT + '; }'); break;
13330                default: name = new Function(VALUES, PARENT, WITHVALUES + RETURN + name + '; }');
13331            }
13332        }
13333        tpls.push({
13334             id: id,
13335             target: name,
13336             exec: exec,
13337             test: fn,
13338             body: m[1]||''
13339         });
13340        s = s.replace(m[0], '{xtpl'+ id + '}');
13341        ++id;
13342     }
13343     for(var i = tpls.length-1; i >= 0; --i){
13344         me.compileTpl(tpls[i]);
13345     }
13346     me.master = tpls[tpls.length-1];
13347     me.tpls = tpls;
13348 };
13349 Ext.extend(Ext.XTemplate, Ext.Template, {
13350     // private
13351     re : /\{([\w-\.\#]+)(?:\:([\w\.]*)(?:\((.*?)?\))?)?(\s?[\+\-\*\\]\s?[\d\.\+\-\*\\\(\)]+)?\}/g,
13352     // private
13353     codeRe : /\{\[((?:\\\]|.|\n)*?)\]\}/g,
13354
13355     // private
13356     applySubTemplate : function(id, values, parent, xindex, xcount){
13357         var me = this,
13358             len,
13359             t = me.tpls[id],
13360             vs,
13361             buf = [];
13362         if ((t.test && !t.test.call(me, values, parent, xindex, xcount)) ||
13363             (t.exec && t.exec.call(me, values, parent, xindex, xcount))) {
13364             return '';
13365         }
13366         vs = t.target ? t.target.call(me, values, parent) : values;
13367         len = vs.length;
13368         parent = t.target ? values : parent;
13369         if(t.target && Ext.isArray(vs)){
13370             for(var i = 0, len = vs.length; i < len; i++){
13371                 buf[buf.length] = t.compiled.call(me, vs[i], parent, i+1, len);
13372             }
13373             return buf.join('');
13374         }
13375         return t.compiled.call(me, vs, parent, xindex, xcount);
13376     },
13377
13378     // private
13379     compileTpl : function(tpl){
13380         var fm = Ext.util.Format,
13381             useF = this.disableFormats !== true,
13382             sep = Ext.isGecko ? "+" : ",",
13383             body;
13384
13385         function fn(m, name, format, args, math){
13386             if(name.substr(0, 4) == 'xtpl'){
13387                 return "'"+ sep +'this.applySubTemplate('+name.substr(4)+', values, parent, xindex, xcount)'+sep+"'";
13388             }
13389             var v;
13390             if(name === '.'){
13391                 v = 'values';
13392             }else if(name === '#'){
13393                 v = 'xindex';
13394             }else if(name.indexOf('.') != -1){
13395                 v = name;
13396             }else{
13397                 v = "values['" + name + "']";
13398             }
13399             if(math){
13400                 v = '(' + v + math + ')';
13401             }
13402             if (format && useF) {
13403                 args = args ? ',' + args : "";
13404                 if(format.substr(0, 5) != "this."){
13405                     format = "fm." + format + '(';
13406                 }else{
13407                     format = 'this.call("'+ format.substr(5) + '", ';
13408                     args = ", values";
13409                 }
13410             } else {
13411                 args= ''; format = "("+v+" === undefined ? '' : ";
13412             }
13413             return "'"+ sep + format + v + args + ")"+sep+"'";
13414         }
13415
13416         function codeFn(m, code){
13417             // Single quotes get escaped when the template is compiled, however we want to undo this when running code.
13418             return "'" + sep + '(' + code.replace(/\\'/g, "'") + ')' + sep + "'";
13419         }
13420
13421         // branched to use + in gecko and [].join() in others
13422         if(Ext.isGecko){
13423             body = "tpl.compiled = function(values, parent, xindex, xcount){ return '" +
13424                    tpl.body.replace(/(\r\n|\n)/g, '\\n').replace(/'/g, "\\'").replace(this.re, fn).replace(this.codeRe, codeFn) +
13425                     "';};";
13426         }else{
13427             body = ["tpl.compiled = function(values, parent, xindex, xcount){ return ['"];
13428             body.push(tpl.body.replace(/(\r\n|\n)/g, '\\n').replace(/'/g, "\\'").replace(this.re, fn).replace(this.codeRe, codeFn));
13429             body.push("'].join('');};");
13430             body = body.join('');
13431         }
13432         eval(body);
13433         return this;
13434     },
13435
13436     /**
13437      * Returns an HTML fragment of this template with the specified values applied.
13438      * @param {Object} values The template values. Can be an array if your params are numeric (i.e. {0}) or an object (i.e. {foo: 'bar'})
13439      * @return {String} The HTML fragment
13440      */
13441     applyTemplate : function(values){
13442         return this.master.compiled.call(this, values, {}, 1, 1);
13443     },
13444
13445     /**
13446      * Compile the template to a function for optimized performance.  Recommended if the template will be used frequently.
13447      * @return {Function} The compiled function
13448      */
13449     compile : function(){return this;}
13450
13451     /**
13452      * @property re
13453      * @hide
13454      */
13455     /**
13456      * @property disableFormats
13457      * @hide
13458      */
13459     /**
13460      * @method set
13461      * @hide
13462      */
13463
13464 });
13465 /**
13466  * Alias for {@link #applyTemplate}
13467  * Returns an HTML fragment of this template with the specified values applied.
13468  * @param {Object/Array} values The template values. Can be an array if your params are numeric (i.e. {0}) or an object (i.e. {foo: 'bar'})
13469  * @return {String} The HTML fragment
13470  * @member Ext.XTemplate
13471  * @method apply
13472  */
13473 Ext.XTemplate.prototype.apply = Ext.XTemplate.prototype.applyTemplate;
13474
13475 /**
13476  * Creates a template from the passed element's value (<i>display:none</i> textarea, preferred) or innerHTML.
13477  * @param {String/HTMLElement} el A DOM element or its id
13478  * @return {Ext.Template} The created template
13479  * @static
13480  */
13481 Ext.XTemplate.from = function(el){
13482     el = Ext.getDom(el);
13483     return new Ext.XTemplate(el.value || el.innerHTML);
13484 };
13485 /**
13486  * @class Ext.util.CSS
13487  * Utility class for manipulating CSS rules
13488  * @singleton
13489  */
13490 Ext.util.CSS = function(){
13491         var rules = null;
13492         var doc = document;
13493
13494     var camelRe = /(-[a-z])/gi;
13495     var camelFn = function(m, a){ return a.charAt(1).toUpperCase(); };
13496
13497    return {
13498    /**
13499     * Creates a stylesheet from a text blob of rules.
13500     * These rules will be wrapped in a STYLE tag and appended to the HEAD of the document.
13501     * @param {String} cssText The text containing the css rules
13502     * @param {String} id An id to add to the stylesheet for later removal
13503     * @return {StyleSheet}
13504     */
13505    createStyleSheet : function(cssText, id){
13506        var ss;
13507        var head = doc.getElementsByTagName("head")[0];
13508        var rules = doc.createElement("style");
13509        rules.setAttribute("type", "text/css");
13510        if(id){
13511            rules.setAttribute("id", id);
13512        }
13513        if(Ext.isIE){
13514            head.appendChild(rules);
13515            ss = rules.styleSheet;
13516            ss.cssText = cssText;
13517        }else{
13518            try{
13519                 rules.appendChild(doc.createTextNode(cssText));
13520            }catch(e){
13521                rules.cssText = cssText;
13522            }
13523            head.appendChild(rules);
13524            ss = rules.styleSheet ? rules.styleSheet : (rules.sheet || doc.styleSheets[doc.styleSheets.length-1]);
13525        }
13526        this.cacheStyleSheet(ss);
13527        return ss;
13528    },
13529
13530    /**
13531     * Removes a style or link tag by id
13532     * @param {String} id The id of the tag
13533     */
13534    removeStyleSheet : function(id){
13535        var existing = doc.getElementById(id);
13536        if(existing){
13537            existing.parentNode.removeChild(existing);
13538        }
13539    },
13540
13541    /**
13542     * Dynamically swaps an existing stylesheet reference for a new one
13543     * @param {String} id The id of an existing link tag to remove
13544     * @param {String} url The href of the new stylesheet to include
13545     */
13546    swapStyleSheet : function(id, url){
13547        this.removeStyleSheet(id);
13548        var ss = doc.createElement("link");
13549        ss.setAttribute("rel", "stylesheet");
13550        ss.setAttribute("type", "text/css");
13551        ss.setAttribute("id", id);
13552        ss.setAttribute("href", url);
13553        doc.getElementsByTagName("head")[0].appendChild(ss);
13554    },
13555    
13556    /**
13557     * Refresh the rule cache if you have dynamically added stylesheets
13558     * @return {Object} An object (hash) of rules indexed by selector
13559     */
13560    refreshCache : function(){
13561        return this.getRules(true);
13562    },
13563
13564    // private
13565    cacheStyleSheet : function(ss){
13566        if(!rules){
13567            rules = {};
13568        }
13569        try{// try catch for cross domain access issue
13570            var ssRules = ss.cssRules || ss.rules;
13571            for(var j = ssRules.length-1; j >= 0; --j){
13572                rules[ssRules[j].selectorText.toLowerCase()] = ssRules[j];
13573            }
13574        }catch(e){}
13575    },
13576    
13577    /**
13578     * Gets all css rules for the document
13579     * @param {Boolean} refreshCache true to refresh the internal cache
13580     * @return {Object} An object (hash) of rules indexed by selector
13581     */
13582    getRules : function(refreshCache){
13583                 if(rules === null || refreshCache){
13584                         rules = {};
13585                         var ds = doc.styleSheets;
13586                         for(var i =0, len = ds.length; i < len; i++){
13587                             try{
13588                         this.cacheStyleSheet(ds[i]);
13589                     }catch(e){} 
13590                 }
13591                 }
13592                 return rules;
13593         },
13594         
13595         /**
13596     * Gets an an individual CSS rule by selector(s)
13597     * @param {String/Array} selector The CSS selector or an array of selectors to try. The first selector that is found is returned.
13598     * @param {Boolean} refreshCache true to refresh the internal cache if you have recently updated any rules or added styles dynamically
13599     * @return {CSSRule} The CSS rule or null if one is not found
13600     */
13601    getRule : function(selector, refreshCache){
13602                 var rs = this.getRules(refreshCache);
13603                 if(!Ext.isArray(selector)){
13604                     return rs[selector.toLowerCase()];
13605                 }
13606                 for(var i = 0; i < selector.length; i++){
13607                         if(rs[selector[i]]){
13608                                 return rs[selector[i].toLowerCase()];
13609                         }
13610                 }
13611                 return null;
13612         },
13613         
13614         
13615         /**
13616     * Updates a rule property
13617     * @param {String/Array} selector If it's an array it tries each selector until it finds one. Stops immediately once one is found.
13618     * @param {String} property The css property
13619     * @param {String} value The new value for the property
13620     * @return {Boolean} true If a rule was found and updated
13621     */
13622    updateRule : function(selector, property, value){
13623                 if(!Ext.isArray(selector)){
13624                         var rule = this.getRule(selector);
13625                         if(rule){
13626                                 rule.style[property.replace(camelRe, camelFn)] = value;
13627                                 return true;
13628                         }
13629                 }else{
13630                         for(var i = 0; i < selector.length; i++){
13631                                 if(this.updateRule(selector[i], property, value)){
13632                                         return true;
13633                                 }
13634                         }
13635                 }
13636                 return false;
13637         }
13638    };   
13639 }();/**
13640  @class Ext.util.ClickRepeater
13641  @extends Ext.util.Observable
13642
13643  A wrapper class which can be applied to any element. Fires a "click" event while the
13644  mouse is pressed. The interval between firings may be specified in the config but
13645  defaults to 20 milliseconds.
13646
13647  Optionally, a CSS class may be applied to the element during the time it is pressed.
13648
13649  @cfg {Mixed} el The element to act as a button.
13650  @cfg {Number} delay The initial delay before the repeating event begins firing.
13651  Similar to an autorepeat key delay.
13652  @cfg {Number} interval The interval between firings of the "click" event. Default 20 ms.
13653  @cfg {String} pressClass A CSS class name to be applied to the element while pressed.
13654  @cfg {Boolean} accelerate True if autorepeating should start slowly and accelerate.
13655            "interval" and "delay" are ignored.
13656  @cfg {Boolean} preventDefault True to prevent the default click event
13657  @cfg {Boolean} stopDefault True to stop the default click event
13658
13659  @history
13660     2007-02-02 jvs Original code contributed by Nige "Animal" White
13661     2007-02-02 jvs Renamed to ClickRepeater
13662     2007-02-03 jvs Modifications for FF Mac and Safari
13663
13664  @constructor
13665  @param {Mixed} el The element to listen on
13666  @param {Object} config
13667  */
13668 Ext.util.ClickRepeater = function(el, config)
13669 {
13670     this.el = Ext.get(el);
13671     this.el.unselectable();
13672
13673     Ext.apply(this, config);
13674
13675     this.addEvents(
13676     /**
13677      * @event mousedown
13678      * Fires when the mouse button is depressed.
13679      * @param {Ext.util.ClickRepeater} this
13680      */
13681         "mousedown",
13682     /**
13683      * @event click
13684      * Fires on a specified interval during the time the element is pressed.
13685      * @param {Ext.util.ClickRepeater} this
13686      */
13687         "click",
13688     /**
13689      * @event mouseup
13690      * Fires when the mouse key is released.
13691      * @param {Ext.util.ClickRepeater} this
13692      */
13693         "mouseup"
13694     );
13695
13696     if(!this.disabled){
13697         this.disabled = true;
13698         this.enable();
13699     }
13700
13701     // allow inline handler
13702     if(this.handler){
13703         this.on("click", this.handler,  this.scope || this);
13704     }
13705
13706     Ext.util.ClickRepeater.superclass.constructor.call(this);
13707 };
13708
13709 Ext.extend(Ext.util.ClickRepeater, Ext.util.Observable, {
13710     interval : 20,
13711     delay: 250,
13712     preventDefault : true,
13713     stopDefault : false,
13714     timer : 0,
13715
13716     /**
13717      * Enables the repeater and allows events to fire.
13718      */
13719     enable: function(){
13720         if(this.disabled){
13721             this.el.on('mousedown', this.handleMouseDown, this);
13722             if (Ext.isIE){
13723                 this.el.on('dblclick', this.handleDblClick, this);
13724             }
13725             if(this.preventDefault || this.stopDefault){
13726                 this.el.on('click', this.eventOptions, this);
13727             }
13728         }
13729         this.disabled = false;
13730     },
13731
13732     /**
13733      * Disables the repeater and stops events from firing.
13734      */
13735     disable: function(/* private */ force){
13736         if(force || !this.disabled){
13737             clearTimeout(this.timer);
13738             if(this.pressClass){
13739                 this.el.removeClass(this.pressClass);
13740             }
13741             Ext.getDoc().un('mouseup', this.handleMouseUp, this);
13742             this.el.removeAllListeners();
13743         }
13744         this.disabled = true;
13745     },
13746
13747     /**
13748      * Convenience function for setting disabled/enabled by boolean.
13749      * @param {Boolean} disabled
13750      */
13751     setDisabled: function(disabled){
13752         this[disabled ? 'disable' : 'enable']();
13753     },
13754
13755     eventOptions: function(e){
13756         if(this.preventDefault){
13757             e.preventDefault();
13758         }
13759         if(this.stopDefault){
13760             e.stopEvent();
13761         }
13762     },
13763
13764     // private
13765     destroy : function() {
13766         this.disable(true);
13767         Ext.destroy(this.el);
13768         this.purgeListeners();
13769     },
13770
13771     handleDblClick : function(){
13772         clearTimeout(this.timer);
13773         this.el.blur();
13774
13775         this.fireEvent("mousedown", this);
13776         this.fireEvent("click", this);
13777     },
13778
13779     // private
13780     handleMouseDown : function(){
13781         clearTimeout(this.timer);
13782         this.el.blur();
13783         if(this.pressClass){
13784             this.el.addClass(this.pressClass);
13785         }
13786         this.mousedownTime = new Date();
13787
13788         Ext.getDoc().on("mouseup", this.handleMouseUp, this);
13789         this.el.on("mouseout", this.handleMouseOut, this);
13790
13791         this.fireEvent("mousedown", this);
13792         this.fireEvent("click", this);
13793
13794         // Do not honor delay or interval if acceleration wanted.
13795         if (this.accelerate) {
13796             this.delay = 400;
13797         }
13798         this.timer = this.click.defer(this.delay || this.interval, this);
13799     },
13800
13801     // private
13802     click : function(){
13803         this.fireEvent("click", this);
13804         this.timer = this.click.defer(this.accelerate ?
13805             this.easeOutExpo(this.mousedownTime.getElapsed(),
13806                 400,
13807                 -390,
13808                 12000) :
13809             this.interval, this);
13810     },
13811
13812     easeOutExpo : function (t, b, c, d) {
13813         return (t==d) ? b+c : c * (-Math.pow(2, -10 * t/d) + 1) + b;
13814     },
13815
13816     // private
13817     handleMouseOut : function(){
13818         clearTimeout(this.timer);
13819         if(this.pressClass){
13820             this.el.removeClass(this.pressClass);
13821         }
13822         this.el.on("mouseover", this.handleMouseReturn, this);
13823     },
13824
13825     // private
13826     handleMouseReturn : function(){
13827         this.el.un("mouseover", this.handleMouseReturn, this);
13828         if(this.pressClass){
13829             this.el.addClass(this.pressClass);
13830         }
13831         this.click();
13832     },
13833
13834     // private
13835     handleMouseUp : function(){
13836         clearTimeout(this.timer);
13837         this.el.un("mouseover", this.handleMouseReturn, this);
13838         this.el.un("mouseout", this.handleMouseOut, this);
13839         Ext.getDoc().un("mouseup", this.handleMouseUp, this);
13840         this.el.removeClass(this.pressClass);
13841         this.fireEvent("mouseup", this);
13842     }
13843 });/**
13844  * @class Ext.KeyNav
13845  * <p>Provides a convenient wrapper for normalized keyboard navigation.  KeyNav allows you to bind
13846  * navigation keys to function calls that will get called when the keys are pressed, providing an easy
13847  * way to implement custom navigation schemes for any UI component.</p>
13848  * <p>The following are all of the possible keys that can be implemented: enter, left, right, up, down, tab, esc,
13849  * pageUp, pageDown, del, home, end.  Usage:</p>
13850  <pre><code>
13851 var nav = new Ext.KeyNav("my-element", {
13852     "left" : function(e){
13853         this.moveLeft(e.ctrlKey);
13854     },
13855     "right" : function(e){
13856         this.moveRight(e.ctrlKey);
13857     },
13858     "enter" : function(e){
13859         this.save();
13860     },
13861     scope : this
13862 });
13863 </code></pre>
13864  * @constructor
13865  * @param {Mixed} el The element to bind to
13866  * @param {Object} config The config
13867  */
13868 Ext.KeyNav = function(el, config){
13869     this.el = Ext.get(el);
13870     Ext.apply(this, config);
13871     if(!this.disabled){
13872         this.disabled = true;
13873         this.enable();
13874     }
13875 };
13876
13877 Ext.KeyNav.prototype = {
13878     /**
13879      * @cfg {Boolean} disabled
13880      * True to disable this KeyNav instance (defaults to false)
13881      */
13882     disabled : false,
13883     /**
13884      * @cfg {String} defaultEventAction
13885      * The method to call on the {@link Ext.EventObject} after this KeyNav intercepts a key.  Valid values are
13886      * {@link Ext.EventObject#stopEvent}, {@link Ext.EventObject#preventDefault} and
13887      * {@link Ext.EventObject#stopPropagation} (defaults to 'stopEvent')
13888      */
13889     defaultEventAction: "stopEvent",
13890     /**
13891      * @cfg {Boolean} forceKeyDown
13892      * Handle the keydown event instead of keypress (defaults to false).  KeyNav automatically does this for IE since
13893      * IE does not propagate special keys on keypress, but setting this to true will force other browsers to also
13894      * handle keydown instead of keypress.
13895      */
13896     forceKeyDown : false,
13897
13898     // private
13899     relay : function(e){
13900         var k = e.getKey();
13901         var h = this.keyToHandler[k];
13902         if(h && this[h]){
13903             if(this.doRelay(e, this[h], h) !== true){
13904                 e[this.defaultEventAction]();
13905             }
13906         }
13907     },
13908
13909     // private
13910     doRelay : function(e, h, hname){
13911         return h.call(this.scope || this, e);
13912     },
13913
13914     // possible handlers
13915     enter : false,
13916     left : false,
13917     right : false,
13918     up : false,
13919     down : false,
13920     tab : false,
13921     esc : false,
13922     pageUp : false,
13923     pageDown : false,
13924     del : false,
13925     home : false,
13926     end : false,
13927
13928     // quick lookup hash
13929     keyToHandler : {
13930         37 : "left",
13931         39 : "right",
13932         38 : "up",
13933         40 : "down",
13934         33 : "pageUp",
13935         34 : "pageDown",
13936         46 : "del",
13937         36 : "home",
13938         35 : "end",
13939         13 : "enter",
13940         27 : "esc",
13941         9  : "tab"
13942     },
13943     
13944     stopKeyUp: function(e) {
13945         var k = e.getKey();
13946
13947         if (k >= 37 && k <= 40) {
13948             // *** bugfix - safari 2.x fires 2 keyup events on cursor keys
13949             // *** (note: this bugfix sacrifices the "keyup" event originating from keyNav elements in Safari 2)
13950             e.stopEvent();
13951         }
13952     },
13953     
13954     /**
13955      * Destroy this KeyNav (this is the same as calling disable).
13956      */
13957     destroy: function(){
13958         this.disable();    
13959     },
13960
13961         /**
13962          * Enable this KeyNav
13963          */
13964         enable: function() {
13965         if (this.disabled) {
13966             if (Ext.isSafari2) {
13967                 // call stopKeyUp() on "keyup" event
13968                 this.el.on('keyup', this.stopKeyUp, this);
13969             }
13970
13971             this.el.on(this.isKeydown()? 'keydown' : 'keypress', this.relay, this);
13972             this.disabled = false;
13973         }
13974     },
13975
13976         /**
13977          * Disable this KeyNav
13978          */
13979         disable: function() {
13980         if (!this.disabled) {
13981             if (Ext.isSafari2) {
13982                 // remove "keyup" event handler
13983                 this.el.un('keyup', this.stopKeyUp, this);
13984             }
13985
13986             this.el.un(this.isKeydown()? 'keydown' : 'keypress', this.relay, this);
13987             this.disabled = true;
13988         }
13989     },
13990     
13991     /**
13992      * Convenience function for setting disabled/enabled by boolean.
13993      * @param {Boolean} disabled
13994      */
13995     setDisabled : function(disabled){
13996         this[disabled ? "disable" : "enable"]();
13997     },
13998     
13999     // private
14000     isKeydown: function(){
14001         return this.forceKeyDown || Ext.EventManager.useKeydown;
14002     }
14003 };
14004 /**
14005  * @class Ext.KeyMap
14006  * Handles mapping keys to actions for an element. One key map can be used for multiple actions.
14007  * The constructor accepts the same config object as defined by {@link #addBinding}.
14008  * If you bind a callback function to a KeyMap, anytime the KeyMap handles an expected key
14009  * combination it will call the function with this signature (if the match is a multi-key
14010  * combination the callback will still be called only once): (String key, Ext.EventObject e)
14011  * A KeyMap can also handle a string representation of keys.<br />
14012  * Usage:
14013  <pre><code>
14014 // map one key by key code
14015 var map = new Ext.KeyMap("my-element", {
14016     key: 13, // or Ext.EventObject.ENTER
14017     fn: myHandler,
14018     scope: myObject
14019 });
14020
14021 // map multiple keys to one action by string
14022 var map = new Ext.KeyMap("my-element", {
14023     key: "a\r\n\t",
14024     fn: myHandler,
14025     scope: myObject
14026 });
14027
14028 // map multiple keys to multiple actions by strings and array of codes
14029 var map = new Ext.KeyMap("my-element", [
14030     {
14031         key: [10,13],
14032         fn: function(){ alert("Return was pressed"); }
14033     }, {
14034         key: "abc",
14035         fn: function(){ alert('a, b or c was pressed'); }
14036     }, {
14037         key: "\t",
14038         ctrl:true,
14039         shift:true,
14040         fn: function(){ alert('Control + shift + tab was pressed.'); }
14041     }
14042 ]);
14043 </code></pre>
14044  * <b>Note: A KeyMap starts enabled</b>
14045  * @constructor
14046  * @param {Mixed} el The element to bind to
14047  * @param {Object} config The config (see {@link #addBinding})
14048  * @param {String} eventName (optional) The event to bind to (defaults to "keydown")
14049  */
14050 Ext.KeyMap = function(el, config, eventName){
14051     this.el  = Ext.get(el);
14052     this.eventName = eventName || "keydown";
14053     this.bindings = [];
14054     if(config){
14055         this.addBinding(config);
14056     }
14057     this.enable();
14058 };
14059
14060 Ext.KeyMap.prototype = {
14061     /**
14062      * True to stop the event from bubbling and prevent the default browser action if the
14063      * key was handled by the KeyMap (defaults to false)
14064      * @type Boolean
14065      */
14066     stopEvent : false,
14067
14068     /**
14069      * Add a new binding to this KeyMap. The following config object properties are supported:
14070      * <pre>
14071 Property    Type             Description
14072 ----------  ---------------  ----------------------------------------------------------------------
14073 key         String/Array     A single keycode or an array of keycodes to handle
14074 shift       Boolean          True to handle key only when shift is pressed, False to handle the key only when shift is not pressed (defaults to undefined)
14075 ctrl        Boolean          True to handle key only when ctrl is pressed, False to handle the key only when ctrl is not pressed (defaults to undefined)
14076 alt         Boolean          True to handle key only when alt is pressed, False to handle the key only when alt is not pressed (defaults to undefined)
14077 handler     Function         The function to call when KeyMap finds the expected key combination
14078 fn          Function         Alias of handler (for backwards-compatibility)
14079 scope       Object           The scope of the callback function
14080 stopEvent   Boolean          True to stop the event from bubbling and prevent the default browser action if the key was handled by the KeyMap (defaults to false)
14081 </pre>
14082      *
14083      * Usage:
14084      * <pre><code>
14085 // Create a KeyMap
14086 var map = new Ext.KeyMap(document, {
14087     key: Ext.EventObject.ENTER,
14088     fn: handleKey,
14089     scope: this
14090 });
14091
14092 //Add a new binding to the existing KeyMap later
14093 map.addBinding({
14094     key: 'abc',
14095     shift: true,
14096     fn: handleKey,
14097     scope: this
14098 });
14099 </code></pre>
14100      * @param {Object/Array} config A single KeyMap config or an array of configs
14101      */
14102         addBinding : function(config){
14103         if(Ext.isArray(config)){
14104             Ext.each(config, function(c){
14105                 this.addBinding(c);
14106             }, this);
14107             return;
14108         }
14109         var keyCode = config.key,
14110             fn = config.fn || config.handler,
14111             scope = config.scope;
14112
14113         if (config.stopEvent) {
14114             this.stopEvent = config.stopEvent;    
14115         }       
14116
14117         if(typeof keyCode == "string"){
14118             var ks = [];
14119             var keyString = keyCode.toUpperCase();
14120             for(var j = 0, len = keyString.length; j < len; j++){
14121                 ks.push(keyString.charCodeAt(j));
14122             }
14123             keyCode = ks;
14124         }
14125         var keyArray = Ext.isArray(keyCode);
14126         
14127         var handler = function(e){
14128             if(this.checkModifiers(config, e)){
14129                 var k = e.getKey();
14130                 if(keyArray){
14131                     for(var i = 0, len = keyCode.length; i < len; i++){
14132                         if(keyCode[i] == k){
14133                           if(this.stopEvent){
14134                               e.stopEvent();
14135                           }
14136                           fn.call(scope || window, k, e);
14137                           return;
14138                         }
14139                     }
14140                 }else{
14141                     if(k == keyCode){
14142                         if(this.stopEvent){
14143                            e.stopEvent();
14144                         }
14145                         fn.call(scope || window, k, e);
14146                     }
14147                 }
14148             }
14149         };
14150         this.bindings.push(handler);
14151         },
14152     
14153     // private
14154     checkModifiers: function(config, e){
14155         var val, key, keys = ['shift', 'ctrl', 'alt'];
14156         for (var i = 0, len = keys.length; i < len; ++i){
14157             key = keys[i];
14158             val = config[key];
14159             if(!(val === undefined || (val === e[key + 'Key']))){
14160                 return false;
14161             }
14162         }
14163         return true;
14164     },
14165
14166     /**
14167      * Shorthand for adding a single key listener
14168      * @param {Number/Array/Object} key Either the numeric key code, array of key codes or an object with the
14169      * following options:
14170      * {key: (number or array), shift: (true/false), ctrl: (true/false), alt: (true/false)}
14171      * @param {Function} fn The function to call
14172      * @param {Object} scope (optional) The scope (<code>this</code> reference) in which the function is executed. Defaults to the browser window.
14173      */
14174     on : function(key, fn, scope){
14175         var keyCode, shift, ctrl, alt;
14176         if(typeof key == "object" && !Ext.isArray(key)){
14177             keyCode = key.key;
14178             shift = key.shift;
14179             ctrl = key.ctrl;
14180             alt = key.alt;
14181         }else{
14182             keyCode = key;
14183         }
14184         this.addBinding({
14185             key: keyCode,
14186             shift: shift,
14187             ctrl: ctrl,
14188             alt: alt,
14189             fn: fn,
14190             scope: scope
14191         });
14192     },
14193
14194     // private
14195     handleKeyDown : function(e){
14196             if(this.enabled){ //just in case
14197             var b = this.bindings;
14198             for(var i = 0, len = b.length; i < len; i++){
14199                 b[i].call(this, e);
14200             }
14201             }
14202         },
14203
14204         /**
14205          * Returns true if this KeyMap is enabled
14206          * @return {Boolean}
14207          */
14208         isEnabled : function(){
14209             return this.enabled;
14210         },
14211
14212         /**
14213          * Enables this KeyMap
14214          */
14215         enable: function(){
14216                 if(!this.enabled){
14217                     this.el.on(this.eventName, this.handleKeyDown, this);
14218                     this.enabled = true;
14219                 }
14220         },
14221
14222         /**
14223          * Disable this KeyMap
14224          */
14225         disable: function(){
14226                 if(this.enabled){
14227                     this.el.removeListener(this.eventName, this.handleKeyDown, this);
14228                     this.enabled = false;
14229                 }
14230         },
14231     
14232     /**
14233      * Convenience function for setting disabled/enabled by boolean.
14234      * @param {Boolean} disabled
14235      */
14236     setDisabled : function(disabled){
14237         this[disabled ? "disable" : "enable"]();
14238     }
14239 };/**
14240  * @class Ext.util.TextMetrics
14241  * Provides precise pixel measurements for blocks of text so that you can determine exactly how high and
14242  * wide, in pixels, a given block of text will be. Note that when measuring text, it should be plain text and
14243  * should not contain any HTML, otherwise it may not be measured correctly.
14244  * @singleton
14245  */
14246 Ext.util.TextMetrics = function(){
14247     var shared;
14248     return {
14249         /**
14250          * Measures the size of the specified text
14251          * @param {String/HTMLElement} el The element, dom node or id from which to copy existing CSS styles
14252          * that can affect the size of the rendered text
14253          * @param {String} text The text to measure
14254          * @param {Number} fixedWidth (optional) If the text will be multiline, you have to set a fixed width
14255          * in order to accurately measure the text height
14256          * @return {Object} An object containing the text's size {width: (width), height: (height)}
14257          */
14258         measure : function(el, text, fixedWidth){
14259             if(!shared){
14260                 shared = Ext.util.TextMetrics.Instance(el, fixedWidth);
14261             }
14262             shared.bind(el);
14263             shared.setFixedWidth(fixedWidth || 'auto');
14264             return shared.getSize(text);
14265         },
14266
14267         /**
14268          * Return a unique TextMetrics instance that can be bound directly to an element and reused.  This reduces
14269          * the overhead of multiple calls to initialize the style properties on each measurement.
14270          * @param {String/HTMLElement} el The element, dom node or id that the instance will be bound to
14271          * @param {Number} fixedWidth (optional) If the text will be multiline, you have to set a fixed width
14272          * in order to accurately measure the text height
14273          * @return {Ext.util.TextMetrics.Instance} instance The new instance
14274          */
14275         createInstance : function(el, fixedWidth){
14276             return Ext.util.TextMetrics.Instance(el, fixedWidth);
14277         }
14278     };
14279 }();
14280
14281 Ext.util.TextMetrics.Instance = function(bindTo, fixedWidth){
14282     var ml = new Ext.Element(document.createElement('div'));
14283     document.body.appendChild(ml.dom);
14284     ml.position('absolute');
14285     ml.setLeftTop(-1000, -1000);
14286     ml.hide();
14287
14288     if(fixedWidth){
14289         ml.setWidth(fixedWidth);
14290     }
14291
14292     var instance = {
14293         /**
14294          * <p><b>Only available on the instance returned from {@link #createInstance}, <u>not</u> on the singleton.</b></p>
14295          * Returns the size of the specified text based on the internal element's style and width properties
14296          * @param {String} text The text to measure
14297          * @return {Object} An object containing the text's size {width: (width), height: (height)}
14298          */
14299         getSize : function(text){
14300             ml.update(text);
14301             var s = ml.getSize();
14302             ml.update('');
14303             return s;
14304         },
14305
14306         /**
14307          * <p><b>Only available on the instance returned from {@link #createInstance}, <u>not</u> on the singleton.</b></p>
14308          * Binds this TextMetrics instance to an element from which to copy existing CSS styles
14309          * that can affect the size of the rendered text
14310          * @param {String/HTMLElement} el The element, dom node or id
14311          */
14312         bind : function(el){
14313             ml.setStyle(
14314                 Ext.fly(el).getStyles('font-size','font-style', 'font-weight', 'font-family','line-height', 'text-transform', 'letter-spacing')
14315             );
14316         },
14317
14318         /**
14319          * <p><b>Only available on the instance returned from {@link #createInstance}, <u>not</u> on the singleton.</b></p>
14320          * Sets a fixed width on the internal measurement element.  If the text will be multiline, you have
14321          * to set a fixed width in order to accurately measure the text height.
14322          * @param {Number} width The width to set on the element
14323          */
14324         setFixedWidth : function(width){
14325             ml.setWidth(width);
14326         },
14327
14328         /**
14329          * <p><b>Only available on the instance returned from {@link #createInstance}, <u>not</u> on the singleton.</b></p>
14330          * Returns the measured width of the specified text
14331          * @param {String} text The text to measure
14332          * @return {Number} width The width in pixels
14333          */
14334         getWidth : function(text){
14335             ml.dom.style.width = 'auto';
14336             return this.getSize(text).width;
14337         },
14338
14339         /**
14340          * <p><b>Only available on the instance returned from {@link #createInstance}, <u>not</u> on the singleton.</b></p>
14341          * Returns the measured height of the specified text.  For multiline text, be sure to call
14342          * {@link #setFixedWidth} if necessary.
14343          * @param {String} text The text to measure
14344          * @return {Number} height The height in pixels
14345          */
14346         getHeight : function(text){
14347             return this.getSize(text).height;
14348         }
14349     };
14350
14351     instance.bind(bindTo);
14352
14353     return instance;
14354 };
14355
14356 Ext.Element.addMethods({
14357     /**
14358      * Returns the width in pixels of the passed text, or the width of the text in this Element.
14359      * @param {String} text The text to measure. Defaults to the innerHTML of the element.
14360      * @param {Number} min (Optional) The minumum value to return.
14361      * @param {Number} max (Optional) The maximum value to return.
14362      * @return {Number} The text width in pixels.
14363      * @member Ext.Element getTextWidth
14364      */
14365     getTextWidth : function(text, min, max){
14366         return (Ext.util.TextMetrics.measure(this.dom, Ext.value(text, this.dom.innerHTML, true)).width).constrain(min || 0, max || 1000000);
14367     }
14368 });
14369 /**
14370  * @class Ext.util.Cookies
14371  * Utility class for managing and interacting with cookies.
14372  * @singleton
14373  */
14374 Ext.util.Cookies = {
14375     /**
14376      * Create a cookie with the specified name and value. Additional settings
14377      * for the cookie may be optionally specified (for example: expiration,
14378      * access restriction, SSL).
14379      * @param {String} name The name of the cookie to set. 
14380      * @param {Mixed} value The value to set for the cookie.
14381      * @param {Object} expires (Optional) Specify an expiration date the
14382      * cookie is to persist until.  Note that the specified Date object will
14383      * be converted to Greenwich Mean Time (GMT). 
14384      * @param {String} path (Optional) Setting a path on the cookie restricts
14385      * access to pages that match that path. Defaults to all pages (<tt>'/'</tt>). 
14386      * @param {String} domain (Optional) Setting a domain restricts access to
14387      * pages on a given domain (typically used to allow cookie access across
14388      * subdomains). For example, "extjs.com" will create a cookie that can be
14389      * accessed from any subdomain of extjs.com, including www.extjs.com,
14390      * support.extjs.com, etc.
14391      * @param {Boolean} secure (Optional) Specify true to indicate that the cookie
14392      * should only be accessible via SSL on a page using the HTTPS protocol.
14393      * Defaults to <tt>false</tt>. Note that this will only work if the page
14394      * calling this code uses the HTTPS protocol, otherwise the cookie will be
14395      * created with default options.
14396      */
14397     set : function(name, value){
14398         var argv = arguments;
14399         var argc = arguments.length;
14400         var expires = (argc > 2) ? argv[2] : null;
14401         var path = (argc > 3) ? argv[3] : '/';
14402         var domain = (argc > 4) ? argv[4] : null;
14403         var secure = (argc > 5) ? argv[5] : false;
14404         document.cookie = name + "=" + escape(value) + ((expires === null) ? "" : ("; expires=" + expires.toGMTString())) + ((path === null) ? "" : ("; path=" + path)) + ((domain === null) ? "" : ("; domain=" + domain)) + ((secure === true) ? "; secure" : "");
14405     },
14406
14407     /**
14408      * Retrieves cookies that are accessible by the current page. If a cookie
14409      * does not exist, <code>get()</code> returns <tt>null</tt>.  The following
14410      * example retrieves the cookie called "valid" and stores the String value
14411      * in the variable <tt>validStatus</tt>.
14412      * <pre><code>
14413      * var validStatus = Ext.util.Cookies.get("valid");
14414      * </code></pre>
14415      * @param {String} name The name of the cookie to get
14416      * @return {Mixed} Returns the cookie value for the specified name;
14417      * null if the cookie name does not exist.
14418      */
14419     get : function(name){
14420         var arg = name + "=";
14421         var alen = arg.length;
14422         var clen = document.cookie.length;
14423         var i = 0;
14424         var j = 0;
14425         while(i < clen){
14426             j = i + alen;
14427             if(document.cookie.substring(i, j) == arg){
14428                 return Ext.util.Cookies.getCookieVal(j);
14429             }
14430             i = document.cookie.indexOf(" ", i) + 1;
14431             if(i === 0){
14432                 break;
14433             }
14434         }
14435         return null;
14436     },
14437
14438     /**
14439      * Removes a cookie with the provided name from the browser
14440      * if found by setting its expiration date to sometime in the past. 
14441      * @param {String} name The name of the cookie to remove
14442      */
14443     clear : function(name){
14444         if(Ext.util.Cookies.get(name)){
14445             document.cookie = name + "=" + "; expires=Thu, 01-Jan-70 00:00:01 GMT";
14446         }
14447     },
14448     /**
14449      * @private
14450      */
14451     getCookieVal : function(offset){
14452         var endstr = document.cookie.indexOf(";", offset);
14453         if(endstr == -1){
14454             endstr = document.cookie.length;
14455         }
14456         return unescape(document.cookie.substring(offset, endstr));
14457     }
14458 };/**
14459  * Framework-wide error-handler.  Developers can override this method to provide
14460  * custom exception-handling.  Framework errors will often extend from the base
14461  * Ext.Error class.
14462  * @param {Object/Error} e The thrown exception object.
14463  */
14464 Ext.handleError = function(e) {
14465     throw e;
14466 };
14467
14468 /**
14469  * @class Ext.Error
14470  * @extends Error
14471  * <p>A base error class. Future implementations are intended to provide more
14472  * robust error handling throughout the framework (<b>in the debug build only</b>)
14473  * to check for common errors and problems. The messages issued by this class
14474  * will aid error checking. Error checks will be automatically removed in the
14475  * production build so that performance is not negatively impacted.</p>
14476  * <p>Some sample messages currently implemented:</p><pre>
14477 "DataProxy attempted to execute an API-action but found an undefined
14478 url / function. Please review your Proxy url/api-configuration."
14479  * </pre><pre>
14480 "Could not locate your "root" property in your server response.
14481 Please review your JsonReader config to ensure the config-property
14482 "root" matches the property your server-response.  See the JsonReader
14483 docs for additional assistance."
14484  * </pre>
14485  * <p>An example of the code used for generating error messages:</p><pre><code>
14486 try {
14487     generateError({
14488         foo: 'bar'
14489     });
14490 }
14491 catch (e) {
14492     console.error(e);
14493 }
14494 function generateError(data) {
14495     throw new Ext.Error('foo-error', data);
14496 }
14497  * </code></pre>
14498  * @param {String} message
14499  */
14500 Ext.Error = function(message) {
14501     // Try to read the message from Ext.Error.lang
14502     this.message = (this.lang[message]) ? this.lang[message] : message;
14503 };
14504
14505 Ext.Error.prototype = new Error();
14506 Ext.apply(Ext.Error.prototype, {
14507     // protected.  Extensions place their error-strings here.
14508     lang: {},
14509
14510     name: 'Ext.Error',
14511     /**
14512      * getName
14513      * @return {String}
14514      */
14515     getName : function() {
14516         return this.name;
14517     },
14518     /**
14519      * getMessage
14520      * @return {String}
14521      */
14522     getMessage : function() {
14523         return this.message;
14524     },
14525     /**
14526      * toJson
14527      * @return {String}
14528      */
14529     toJson : function() {
14530         return Ext.encode(this);
14531     }
14532 });