Upgrade to ExtJS 3.0.0 - Released 07/06/2009
[extjs.git] / pkgs / ext-foundation-debug.js
1 /*!
2  * Ext JS Library 3.0.0
3  * Copyright(c) 2006-2009 Ext JS, LLC
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         pub,
140         // kill repeat to save bytes
141         afterbegin = "afterbegin",
142         afterend = "afterend",
143         beforebegin = "beforebegin",
144         beforeend = "beforeend",
145         ts = '<table>',
146         te = '</table>',
147         tbs = ts+'<tbody>',
148         tbe = '</tbody>'+te,
149         trs = tbs + '<tr>',
150         tre = '</tr>'+tbe;
151
152     // private
153     function doInsert(el, o, returnElement, pos, sibling, append){
154         var newNode = pub.insertHtml(pos, Ext.getDom(el), createHtml(o));
155         return returnElement ? Ext.get(newNode, true) : newNode;
156     }
157
158     // build as innerHTML where available
159     function createHtml(o){
160             var b = "",
161                 attr,
162                 val,
163                 key,
164                 keyVal,
165                 cn;
166
167         if(typeof o == 'string'){
168             b = o;
169         } else if (Ext.isArray(o)) {
170                 Ext.each(o, function(v) {
171                 b += createHtml(v);
172             });
173         } else {
174                 b += "<" + (o.tag = o.tag || "div");
175             Ext.iterate(o, function(attr, val){
176                 if(!/tag|children|cn|html$/i.test(attr)){
177                     if (Ext.isObject(val)) {
178                         b += " " + attr + "='";
179                         Ext.iterate(val, function(key, keyVal){
180                             b += key + ":" + keyVal + ";";
181                         });
182                         b += "'";
183                     }else{
184                         b += " " + ({cls : "class", htmlFor : "for"}[attr] || attr) + "='" + val + "'";
185                     }
186                 }
187             });
188                 // Now either just close the tag or try to add children and close the tag.
189                 if (emptyTags.test(o.tag)) {
190                     b += "/>";
191                 } else {
192                     b += ">";
193                     if ((cn = o.children || o.cn)) {
194                         b += createHtml(cn);
195                     } else if(o.html){
196                         b += o.html;
197                     }
198                     b += "</" + o.tag + ">";
199                 }
200         }
201         return b;
202     }
203
204     function ieTable(depth, s, h, e){
205         tempTableEl.innerHTML = [s, h, e].join('');
206         var i = -1,
207                 el = tempTableEl;
208         while(++i < depth){
209             el = el.firstChild;
210         }
211         return el;
212     }
213
214     /**
215      * @ignore
216      * Nasty code for IE's broken table implementation
217      */
218     function insertIntoTable(tag, where, el, html) {
219             var node,
220                 before;
221
222         tempTableEl = tempTableEl || document.createElement('div');
223
224             if(tag == 'td' && (where == afterbegin || where == beforeend) ||
225                !/td|tr|tbody/i.test(tag) && (where == beforebegin || where == afterend)) {
226             return;
227         }
228         before = where == beforebegin ? el :
229                                  where == afterend ? el.nextSibling :
230                                  where == afterbegin ? el.firstChild : null;
231
232         if (where == beforebegin || where == afterend) {
233                 el = el.parentNode;
234         }
235
236         if (tag == 'td' || (tag == "tr" && (where == beforeend || where == afterbegin))) {
237                 node = ieTable(4, trs, html, tre);
238         } else if ((tag == "tbody" && (where == beforeend || where == afterbegin)) ||
239                            (tag == "tr" && (where == beforebegin || where == afterend))) {
240                 node = ieTable(3, tbs, html, tbe);
241         } else {
242                 node = ieTable(2, ts, html, te);
243         }
244         el.insertBefore(node, before);
245         return node;
246     }
247
248
249     pub = {
250             /**
251              * Returns the markup for the passed Element(s) config.
252              * @param {Object} o The DOM object spec (and children)
253              * @return {String}
254              */
255             markup : function(o){
256                 return createHtml(o);
257             },
258
259             /**
260              * Inserts an HTML fragment into the DOM.
261              * @param {String} where Where to insert the html in relation to el - beforeBegin, afterBegin, beforeEnd, afterEnd.
262              * @param {HTMLElement} el The context element
263              * @param {String} html The HTML fragmenet
264              * @return {HTMLElement} The new node
265              */
266             insertHtml : function(where, el, html){
267                 var hash = {},
268                         hashVal,
269                         setStart,
270                         range,
271                         frag,
272                         rangeEl,
273                         rs;
274
275                 where = where.toLowerCase();
276                 // add these here because they are used in both branches of the condition.
277                 hash[beforebegin] = ['BeforeBegin', 'previousSibling'];
278                 hash[afterend] = ['AfterEnd', 'nextSibling'];
279
280                 if (el.insertAdjacentHTML) {
281                     if(tableRe.test(el.tagName) && (rs = insertIntoTable(el.tagName.toLowerCase(), where, el, html))){
282                         return rs;
283                     }
284                     // add these two to the hash.
285                     hash[afterbegin] = ['AfterBegin', 'firstChild'];
286                     hash[beforeend] = ['BeforeEnd', 'lastChild'];
287                     if ((hashVal = hash[where])) {
288                                 el.insertAdjacentHTML(hashVal[0], html);
289                         return el[hashVal[1]];
290                     }
291                 } else {
292                         range = el.ownerDocument.createRange();
293                         setStart = "setStart" + (/end/i.test(where) ? "After" : "Before");
294                         if (hash[where]) {
295                                 range[setStart](el);
296                                 frag = range.createContextualFragment(html);
297                                 el.parentNode.insertBefore(frag, where == beforebegin ? el : el.nextSibling);
298                                 return el[(where == beforebegin ? "previous" : "next") + "Sibling"];
299                         } else {
300                                 rangeEl = (where == afterbegin ? "first" : "last") + "Child";
301                                 if (el.firstChild) {
302                                         range[setStart](el[rangeEl]);
303                                         frag = range.createContextualFragment(html);
304                         if(where == afterbegin){
305                             el.insertBefore(frag, el.firstChild);
306                         }else{
307                             el.appendChild(frag);
308                         }
309                                 } else {
310                                     el.innerHTML = html;
311                             }
312                             return el[rangeEl];
313                         }
314                 }
315                 throw 'Illegal insertion point -> "' + where + '"';
316             },
317
318             /**
319              * Creates new DOM element(s) and inserts them before el.
320              * @param {Mixed} el The context element
321              * @param {Object/String} o The DOM object spec (and children) or raw HTML blob
322              * @param {Boolean} returnElement (optional) true to return a Ext.Element
323              * @return {HTMLElement/Ext.Element} The new node
324              */
325             insertBefore : function(el, o, returnElement){
326                 return doInsert(el, o, returnElement, beforebegin);
327             },
328
329             /**
330              * Creates new DOM element(s) and inserts them after el.
331              * @param {Mixed} el The context element
332              * @param {Object} o The DOM object spec (and children)
333              * @param {Boolean} returnElement (optional) true to return a Ext.Element
334              * @return {HTMLElement/Ext.Element} The new node
335              */
336             insertAfter : function(el, o, returnElement){
337                 return doInsert(el, o, returnElement, afterend, "nextSibling");
338             },
339
340             /**
341              * Creates new DOM element(s) and inserts them as the first child of el.
342              * @param {Mixed} el The context element
343              * @param {Object/String} o The DOM object spec (and children) or raw HTML blob
344              * @param {Boolean} returnElement (optional) true to return a Ext.Element
345              * @return {HTMLElement/Ext.Element} The new node
346              */
347             insertFirst : function(el, o, returnElement){
348                 return doInsert(el, o, returnElement, afterbegin, "firstChild");
349             },
350
351             /**
352              * Creates new DOM element(s) and appends them to el.
353              * @param {Mixed} el The context element
354              * @param {Object/String} o The DOM object spec (and children) or raw HTML blob
355              * @param {Boolean} returnElement (optional) true to return a Ext.Element
356              * @return {HTMLElement/Ext.Element} The new node
357              */
358             append : function(el, o, returnElement){
359                     return doInsert(el, o, returnElement, beforeend, "", true);
360             },
361
362             /**
363              * Creates new DOM element(s) and overwrites the contents of el with them.
364              * @param {Mixed} el The context element
365              * @param {Object/String} o The DOM object spec (and children) or raw HTML blob
366              * @param {Boolean} returnElement (optional) true to return a Ext.Element
367              * @return {HTMLElement/Ext.Element} The new node
368              */
369             overwrite : function(el, o, returnElement){
370                 el = Ext.getDom(el);
371                 el.innerHTML = createHtml(o);
372                 return returnElement ? Ext.get(el.firstChild) : el.firstChild;
373             },
374
375             createHtml : createHtml
376     };
377     return pub;
378 }();/**\r
379  * @class Ext.DomHelper\r
380  */\r
381 Ext.apply(Ext.DomHelper,\r
382 function(){\r
383         var pub,\r
384                 afterbegin = 'afterbegin',\r
385         afterend = 'afterend',\r
386         beforebegin = 'beforebegin',\r
387         beforeend = 'beforeend';\r
388 \r
389         // private\r
390     function doInsert(el, o, returnElement, pos, sibling, append){\r
391         el = Ext.getDom(el);\r
392         var newNode;\r
393         if (pub.useDom) {\r
394             newNode = createDom(o, null);\r
395             if (append) {\r
396                     el.appendChild(newNode);\r
397             } else {\r
398                         (sibling == 'firstChild' ? el : el.parentNode).insertBefore(newNode, el[sibling] || el);\r
399             }\r
400         } else {\r
401             newNode = Ext.DomHelper.insertHtml(pos, el, Ext.DomHelper.createHtml(o));\r
402         }\r
403         return returnElement ? Ext.get(newNode, true) : newNode;\r
404     }\r
405 \r
406         // build as dom\r
407     /** @ignore */\r
408     function createDom(o, parentNode){\r
409         var el,\r
410                 doc = document,\r
411                 useSet,\r
412                 attr,\r
413                 val,\r
414                 cn;\r
415 \r
416         if (Ext.isArray(o)) {                       // Allow Arrays of siblings to be inserted\r
417             el = doc.createDocumentFragment(); // in one shot using a DocumentFragment\r
418                 Ext.each(o, function(v) {\r
419                 createDom(v, el);\r
420             });\r
421         } else if (Ext.isString(o)) {         // Allow a string as a child spec.\r
422             el = doc.createTextNode(o);\r
423         } else {\r
424             el = doc.createElement( o.tag || 'div' );\r
425             useSet = !!el.setAttribute; // In IE some elements don't have setAttribute\r
426             Ext.iterate(o, function(attr, val){\r
427                 if(!/tag|children|cn|html|style/.test(attr)){\r
428                         if(attr == 'cls'){\r
429                             el.className = val;\r
430                         }else{\r
431                         if(useSet){\r
432                             el.setAttribute(attr, val);\r
433                         }else{\r
434                             el[attr] = val;\r
435                         }\r
436                         }\r
437                 }\r
438             });\r
439             pub.applyStyles(el, o.style);\r
440 \r
441             if ((cn = o.children || o.cn)) {\r
442                 createDom(cn, el);\r
443             } else if (o.html) {\r
444                 el.innerHTML = o.html;\r
445             }\r
446         }\r
447         if(parentNode){\r
448            parentNode.appendChild(el);\r
449         }\r
450         return el;\r
451     }\r
452 \r
453         pub = {\r
454                 /**\r
455              * Creates a new Ext.Template from the DOM object spec.\r
456              * @param {Object} o The DOM object spec (and children)\r
457              * @return {Ext.Template} The new template\r
458              */\r
459             createTemplate : function(o){\r
460                 var html = Ext.DomHelper.createHtml(o);\r
461                 return new Ext.Template(html);\r
462             },\r
463 \r
464                 /** True to force the use of DOM instead of html fragments @type Boolean */\r
465             useDom : false,\r
466 \r
467             /**\r
468              * Applies a style specification to an element.\r
469              * @param {String/HTMLElement} el The element to apply styles to\r
470              * @param {String/Object/Function} styles A style specification string e.g. 'width:100px', or object in the form {width:'100px'}, or\r
471              * a function which returns such a specification.\r
472              */\r
473             applyStyles : function(el, styles){\r
474                     if(styles){\r
475                                 var i = 0,\r
476                                 len,\r
477                                 style;\r
478 \r
479                         el = Ext.fly(el);\r
480                                 if(Ext.isFunction(styles)){\r
481                                         styles = styles.call();\r
482                                 }\r
483                                 if(Ext.isString(styles)){\r
484                                         styles = styles.trim().split(/\s*(?::|;)\s*/);\r
485                                         for(len = styles.length; i < len;){\r
486                                                 el.setStyle(styles[i++], styles[i++]);\r
487                                         }\r
488                                 }else if (Ext.isObject(styles)){\r
489                                         el.setStyle(styles);\r
490                                 }\r
491                         }\r
492             },\r
493 \r
494             /**\r
495              * Creates new DOM element(s) and inserts them before el.\r
496              * @param {Mixed} el The context element\r
497              * @param {Object/String} o The DOM object spec (and children) or raw HTML blob\r
498              * @param {Boolean} returnElement (optional) true to return a Ext.Element\r
499              * @return {HTMLElement/Ext.Element} The new node\r
500          * @hide (repeat)\r
501              */\r
502             insertBefore : function(el, o, returnElement){\r
503                 return doInsert(el, o, returnElement, beforebegin);\r
504             },\r
505 \r
506             /**\r
507              * Creates new DOM element(s) and inserts them after el.\r
508              * @param {Mixed} el The context element\r
509              * @param {Object} o The DOM object spec (and children)\r
510              * @param {Boolean} returnElement (optional) true to return a Ext.Element\r
511              * @return {HTMLElement/Ext.Element} The new node\r
512          * @hide (repeat)\r
513              */\r
514             insertAfter : function(el, o, returnElement){\r
515                 return doInsert(el, o, returnElement, afterend, 'nextSibling');\r
516             },\r
517 \r
518             /**\r
519              * Creates new DOM element(s) and inserts them as the first child of el.\r
520              * @param {Mixed} el The context element\r
521              * @param {Object/String} o The DOM object spec (and children) or raw HTML blob\r
522              * @param {Boolean} returnElement (optional) true to return a Ext.Element\r
523              * @return {HTMLElement/Ext.Element} The new node\r
524          * @hide (repeat)\r
525              */\r
526             insertFirst : function(el, o, returnElement){\r
527                 return doInsert(el, o, returnElement, afterbegin, 'firstChild');\r
528             },\r
529 \r
530             /**\r
531              * Creates new DOM element(s) and appends them to el.\r
532              * @param {Mixed} el The context element\r
533              * @param {Object/String} o The DOM object spec (and children) or raw HTML blob\r
534              * @param {Boolean} returnElement (optional) true to return a Ext.Element\r
535              * @return {HTMLElement/Ext.Element} The new node\r
536          * @hide (repeat)\r
537              */\r
538             append: function(el, o, returnElement){\r
539             return doInsert(el, o, returnElement, beforeend, '', true);\r
540         },\r
541 \r
542             /**\r
543              * Creates new DOM element(s) without inserting them to the document.\r
544              * @param {Object/String} o The DOM object spec (and children) or raw HTML blob\r
545              * @return {HTMLElement} The new uninserted node\r
546              */\r
547         createDom: createDom\r
548         };\r
549         return pub;\r
550 }());/**
551  * @class Ext.Template
552  * Represents an HTML fragment template. Templates can be precompiled for greater performance.
553  * For a list of available format functions, see {@link Ext.util.Format}.<br />
554  * Usage:
555 <pre><code>
556 var t = new Ext.Template(
557     '&lt;div name="{id}"&gt;',
558         '&lt;span class="{cls}"&gt;{name:trim} {value:ellipsis(10)}&lt;/span&gt;',
559     '&lt;/div&gt;'
560 );
561 t.append('some-element', {id: 'myid', cls: 'myclass', name: 'foo', value: 'bar'});
562 </code></pre>
563  * @constructor
564  * @param {String/Array} html The HTML fragment or an array of fragments to join("") or multiple arguments to join("")
565  */
566 Ext.Template = function(html){
567     var me = this,
568         a = arguments,
569         buf = [];
570
571     if (Ext.isArray(html)) {
572         html = html.join("");
573     } else if (a.length > 1) {
574             Ext.each(a, function(v) {
575             if (Ext.isObject(v)) {
576                 Ext.apply(me, v);
577             } else {
578                 buf.push(v);
579             }
580         });
581         html = buf.join('');
582     }
583
584     /**@private*/
585     me.html = html;
586     if (me.compiled) {
587         me.compile();
588     }
589 };
590 Ext.Template.prototype = {
591     /**
592      * Returns an HTML fragment of this template with the specified values applied.
593      * @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'})
594      * @return {String} The HTML fragment
595      */
596     applyTemplate : function(values){
597                 var me = this;
598
599         return me.compiled ?
600                         me.compiled(values) :
601                                 me.html.replace(me.re, function(m, name){
602                                 return values[name] !== undefined ? values[name] : "";
603                         });
604         },
605
606     /**
607      * Sets the HTML used as the template and optionally compiles it.
608      * @param {String} html
609      * @param {Boolean} compile (optional) True to compile the template (defaults to undefined)
610      * @return {Ext.Template} this
611      */
612     set : function(html, compile){
613             var me = this;
614         me.html = html;
615         me.compiled = null;
616         return compile ? me.compile() : me;
617     },
618
619     /**
620     * The regular expression used to match template variables
621     * @type RegExp
622     * @property
623     */
624     re : /\{([\w-]+)\}/g,
625
626     /**
627      * Compiles the template into an internal function, eliminating the RegEx overhead.
628      * @return {Ext.Template} this
629      */
630     compile : function(){
631         var me = this,
632                 sep = Ext.isGecko ? "+" : ",";
633
634         function fn(m, name){                        
635                 name = "values['" + name + "']";
636                 return "'"+ sep + '(' + name + " == undefined ? '' : " + name + ')' + sep + "'";
637         }
638                 
639         eval("this.compiled = function(values){ return " + (Ext.isGecko ? "'" : "['") +
640              me.html.replace(/\\/g, '\\\\').replace(/(\r\n|\n)/g, '\\n').replace(/'/g, "\\'").replace(this.re, fn) +
641              (Ext.isGecko ?  "';};" : "'].join('');};"));
642         return me;
643     },
644
645     /**
646      * Applies the supplied values to the template and inserts the new node(s) as the first child of el.
647      * @param {Mixed} el The context element
648      * @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'})
649      * @param {Boolean} returnElement (optional) true to return a Ext.Element (defaults to undefined)
650      * @return {HTMLElement/Ext.Element} The new node or Element
651      */
652     insertFirst: function(el, values, returnElement){
653         return this.doInsert('afterBegin', el, values, returnElement);
654     },
655
656     /**
657      * Applies the supplied values to the template and inserts the new node(s) before el.
658      * @param {Mixed} el The context element
659      * @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'})
660      * @param {Boolean} returnElement (optional) true to return a Ext.Element (defaults to undefined)
661      * @return {HTMLElement/Ext.Element} The new node or Element
662      */
663     insertBefore: function(el, values, returnElement){
664         return this.doInsert('beforeBegin', el, values, returnElement);
665     },
666
667     /**
668      * Applies the supplied values to the template and inserts the new node(s) after el.
669      * @param {Mixed} el The context element
670      * @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'})
671      * @param {Boolean} returnElement (optional) true to return a Ext.Element (defaults to undefined)
672      * @return {HTMLElement/Ext.Element} The new node or Element
673      */
674     insertAfter : function(el, values, returnElement){
675         return this.doInsert('afterEnd', el, values, returnElement);
676     },
677
678     /**
679      * Applies the supplied values to the template and appends the new node(s) to el.
680      * @param {Mixed} el The context element
681      * @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'})
682      * @param {Boolean} returnElement (optional) true to return a Ext.Element (defaults to undefined)
683      * @return {HTMLElement/Ext.Element} The new node or Element
684      */
685     append : function(el, values, returnElement){
686         return this.doInsert('beforeEnd', el, values, returnElement);
687     },
688
689     doInsert : function(where, el, values, returnEl){
690         el = Ext.getDom(el);
691         var newNode = Ext.DomHelper.insertHtml(where, el, this.applyTemplate(values));
692         return returnEl ? Ext.get(newNode, true) : newNode;
693     },
694
695     /**
696      * Applies the supplied values to the template and overwrites the content of el with the new node(s).
697      * @param {Mixed} el The context element
698      * @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'})
699      * @param {Boolean} returnElement (optional) true to return a Ext.Element (defaults to undefined)
700      * @return {HTMLElement/Ext.Element} The new node or Element
701      */
702     overwrite : function(el, values, returnElement){
703         el = Ext.getDom(el);
704         el.innerHTML = this.applyTemplate(values);
705         return returnElement ? Ext.get(el.firstChild, true) : el.firstChild;
706     }
707 };
708 /**
709  * Alias for {@link #applyTemplate}
710  * Returns an HTML fragment of this template with the specified values applied.
711  * @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'})
712  * @return {String} The HTML fragment
713  * @member Ext.Template
714  * @method apply
715  */
716 Ext.Template.prototype.apply = Ext.Template.prototype.applyTemplate;
717
718 /**
719  * Creates a template from the passed element's value (<i>display:none</i> textarea, preferred) or innerHTML.
720  * @param {String/HTMLElement} el A DOM element or its id
721  * @param {Object} config A configuration object
722  * @return {Ext.Template} The created template
723  * @static
724  */
725 Ext.Template.from = function(el, config){
726     el = Ext.getDom(el);
727     return new Ext.Template(el.value || el.innerHTML, config || '');
728 };/**\r
729  * @class Ext.Template\r
730  */\r
731 Ext.apply(Ext.Template.prototype, {\r
732     /**\r
733      * Returns an HTML fragment of this template with the specified values applied.\r
734      * @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'})\r
735      * @return {String} The HTML fragment\r
736      * @hide repeat doc\r
737      */\r
738     applyTemplate : function(values){\r
739                 var me = this,\r
740                         useF = me.disableFormats !== true,\r
741                 fm = Ext.util.Format, \r
742                 tpl = me;           \r
743             \r
744         if(me.compiled){\r
745             return me.compiled(values);\r
746         }\r
747         function fn(m, name, format, args){\r
748             if (format && useF) {\r
749                 if (format.substr(0, 5) == "this.") {\r
750                     return tpl.call(format.substr(5), values[name], values);\r
751                 } else {\r
752                     if (args) {\r
753                         // quoted values are required for strings in compiled templates,\r
754                         // but for non compiled we need to strip them\r
755                         // quoted reversed for jsmin\r
756                         var re = /^\s*['"](.*)["']\s*$/;\r
757                         args = args.split(',');\r
758                         for(var i = 0, len = args.length; i < len; i++){\r
759                             args[i] = args[i].replace(re, "$1");\r
760                         }\r
761                         args = [values[name]].concat(args);\r
762                     } else {\r
763                         args = [values[name]];\r
764                     }\r
765                     return fm[format].apply(fm, args);\r
766                 }\r
767             } else {\r
768                 return values[name] !== undefined ? values[name] : "";\r
769             }\r
770         }\r
771         return me.html.replace(me.re, fn);\r
772     },\r
773                 \r
774     /**\r
775      * <tt>true</tt> to disable format functions (defaults to <tt>false</tt>)\r
776      * @type Boolean\r
777      * @property\r
778      */\r
779     disableFormats : false,                             \r
780         \r
781     /**\r
782      * The regular expression used to match template variables\r
783      * @type RegExp\r
784      * @property\r
785      * @hide repeat doc\r
786      */\r
787     re : /\{([\w-]+)(?:\:([\w\.]*)(?:\((.*?)?\))?)?\}/g,\r
788     \r
789     /**\r
790      * Compiles the template into an internal function, eliminating the RegEx overhead.\r
791      * @return {Ext.Template} this\r
792      * @hide repeat doc\r
793      */\r
794     compile : function(){\r
795         var me = this,\r
796                 fm = Ext.util.Format,\r
797                 useF = me.disableFormats !== true,\r
798                 sep = Ext.isGecko ? "+" : ",",\r
799                 body;\r
800         \r
801         function fn(m, name, format, args){\r
802             if(format && useF){\r
803                 args = args ? ',' + args : "";\r
804                 if(format.substr(0, 5) != "this."){\r
805                     format = "fm." + format + '(';\r
806                 }else{\r
807                     format = 'this.call("'+ format.substr(5) + '", ';\r
808                     args = ", values";\r
809                 }\r
810             }else{\r
811                 args= ''; format = "(values['" + name + "'] == undefined ? '' : ";\r
812             }\r
813             return "'"+ sep + format + "values['" + name + "']" + args + ")"+sep+"'";\r
814         }\r
815         \r
816         // branched to use + in gecko and [].join() in others\r
817         if(Ext.isGecko){\r
818             body = "this.compiled = function(values){ return '" +\r
819                    me.html.replace(/\\/g, '\\\\').replace(/(\r\n|\n)/g, '\\n').replace(/'/g, "\\'").replace(this.re, fn) +\r
820                     "';};";\r
821         }else{\r
822             body = ["this.compiled = function(values){ return ['"];\r
823             body.push(me.html.replace(/\\/g, '\\\\').replace(/(\r\n|\n)/g, '\\n').replace(/'/g, "\\'").replace(this.re, fn));\r
824             body.push("'].join('');};");\r
825             body = body.join('');\r
826         }\r
827         eval(body);\r
828         return me;\r
829     },\r
830     \r
831     // private function used to call members\r
832     call : function(fnName, value, allValues){\r
833         return this[fnName](value, allValues);\r
834     }\r
835 });\r
836 Ext.Template.prototype.apply = Ext.Template.prototype.applyTemplate; /*\r
837  * This is code is also distributed under MIT license for use\r
838  * with jQuery and prototype JavaScript libraries.\r
839  */\r
840 /**\r
841  * @class Ext.DomQuery\r
842 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).\r
843 <p>\r
844 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>\r
845 \r
846 <p>\r
847 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.\r
848 </p>\r
849 <h4>Element Selectors:</h4>\r
850 <ul class="list">\r
851     <li> <b>*</b> any element</li>\r
852     <li> <b>E</b> an element with the tag E</li>\r
853     <li> <b>E F</b> All descendent elements of E that have the tag F</li>\r
854     <li> <b>E > F</b> or <b>E/F</b> all direct children elements of E that have the tag F</li>\r
855     <li> <b>E + F</b> all elements with the tag F that are immediately preceded by an element with the tag E</li>\r
856     <li> <b>E ~ F</b> all elements with the tag F that are preceded by a sibling element with the tag E</li>\r
857 </ul>\r
858 <h4>Attribute Selectors:</h4>\r
859 <p>The use of &#64; and quotes are optional. For example, div[&#64;foo='bar'] is also a valid attribute selector.</p>\r
860 <ul class="list">\r
861     <li> <b>E[foo]</b> has an attribute "foo"</li>\r
862     <li> <b>E[foo=bar]</b> has an attribute "foo" that equals "bar"</li>\r
863     <li> <b>E[foo^=bar]</b> has an attribute "foo" that starts with "bar"</li>\r
864     <li> <b>E[foo$=bar]</b> has an attribute "foo" that ends with "bar"</li>\r
865     <li> <b>E[foo*=bar]</b> has an attribute "foo" that contains the substring "bar"</li>\r
866     <li> <b>E[foo%=2]</b> has an attribute "foo" that is evenly divisible by 2</li>\r
867     <li> <b>E[foo!=bar]</b> has an attribute "foo" that does not equal "bar"</li>\r
868 </ul>\r
869 <h4>Pseudo Classes:</h4>\r
870 <ul class="list">\r
871     <li> <b>E:first-child</b> E is the first child of its parent</li>\r
872     <li> <b>E:last-child</b> E is the last child of its parent</li>\r
873     <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>\r
874     <li> <b>E:nth-child(odd)</b> E is an odd child of its parent</li>\r
875     <li> <b>E:nth-child(even)</b> E is an even child of its parent</li>\r
876     <li> <b>E:only-child</b> E is the only child of its parent</li>\r
877     <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>\r
878     <li> <b>E:first</b> the first E in the resultset</li>\r
879     <li> <b>E:last</b> the last E in the resultset</li>\r
880     <li> <b>E:nth(<i>n</i>)</b> the <i>n</i>th E in the resultset (1 based)</li>\r
881     <li> <b>E:odd</b> shortcut for :nth-child(odd)</li>\r
882     <li> <b>E:even</b> shortcut for :nth-child(even)</li>\r
883     <li> <b>E:contains(foo)</b> E's innerHTML contains the substring "foo"</li>\r
884     <li> <b>E:nodeValue(foo)</b> E contains a textNode with a nodeValue that equals "foo"</li>\r
885     <li> <b>E:not(S)</b> an E element that does not match simple selector S</li>\r
886     <li> <b>E:has(S)</b> an E element that has a descendent that matches simple selector S</li>\r
887     <li> <b>E:next(S)</b> an E element whose next sibling matches simple selector S</li>\r
888     <li> <b>E:prev(S)</b> an E element whose previous sibling matches simple selector S</li>\r
889 </ul>\r
890 <h4>CSS Value Selectors:</h4>\r
891 <ul class="list">\r
892     <li> <b>E{display=none}</b> css value "display" that equals "none"</li>\r
893     <li> <b>E{display^=none}</b> css value "display" that starts with "none"</li>\r
894     <li> <b>E{display$=none}</b> css value "display" that ends with "none"</li>\r
895     <li> <b>E{display*=none}</b> css value "display" that contains the substring "none"</li>\r
896     <li> <b>E{display%=2}</b> css value "display" that is evenly divisible by 2</li>\r
897     <li> <b>E{display!=none}</b> css value "display" that does not equal "none"</li>\r
898 </ul>\r
899  * @singleton\r
900  */\r
901 Ext.DomQuery = function(){\r
902     var cache = {}, \r
903         simpleCache = {}, \r
904         valueCache = {},\r
905         nonSpace = /\S/,\r
906         trimRe = /^\s+|\s+$/g,\r
907         tplRe = /\{(\d+)\}/g,\r
908         modeRe = /^(\s?[\/>+~]\s?|\s|$)/,\r
909         tagTokenRe = /^(#)?([\w-\*]+)/,\r
910         nthRe = /(\d*)n\+?(\d*)/, \r
911         nthRe2 = /\D/,\r
912         // This is for IE MSXML which does not support expandos.\r
913             // IE runs the same speed using setAttribute, however FF slows way down\r
914             // and Safari completely fails so they need to continue to use expandos.\r
915             isIE = window.ActiveXObject ? true : false,\r
916         isOpera = Ext.isOpera,\r
917             key = 30803;\r
918             \r
919     // this eval is stop the compressor from\r
920         // renaming the variable to something shorter\r
921         eval("var batch = 30803;");     \r
922 \r
923     function child(p, index){\r
924         var i = 0,\r
925                 n = p.firstChild;\r
926         while(n){\r
927             if(n.nodeType == 1){\r
928                if(++i == index){\r
929                    return n;\r
930                }\r
931             }\r
932             n = n.nextSibling;\r
933         }\r
934         return null;\r
935     };\r
936 \r
937     function next(n){\r
938         while((n = n.nextSibling) && n.nodeType != 1);\r
939         return n;\r
940     };\r
941 \r
942     function prev(n){\r
943         while((n = n.previousSibling) && n.nodeType != 1);\r
944         return n;\r
945     };\r
946 \r
947     function children(d){\r
948         var n = d.firstChild, ni = -1,\r
949                 nx;\r
950             while(n){\r
951                 nx = n.nextSibling;\r
952                 if(n.nodeType == 3 && !nonSpace.test(n.nodeValue)){\r
953                     d.removeChild(n);\r
954                 }else{\r
955                     n.nodeIndex = ++ni;\r
956                 }\r
957                 n = nx;\r
958             }\r
959             return this;\r
960         };\r
961 \r
962     function byClassName(c, a, v){\r
963         if(!v){\r
964             return c;\r
965         }\r
966         var r = [], ri = -1, cn;\r
967         for(var i = 0, ci; ci = c[i]; i++){\r
968             if((' '+ci.className+' ').indexOf(v) != -1){\r
969                 r[++ri] = ci;\r
970             }\r
971         }\r
972         return r;\r
973     };\r
974 \r
975     function attrValue(n, attr){\r
976         if(!n.tagName && typeof n.length != "undefined"){\r
977             n = n[0];\r
978         }\r
979         if(!n){\r
980             return null;\r
981         }\r
982         if(attr == "for"){\r
983             return n.htmlFor;\r
984         }\r
985         if(attr == "class" || attr == "className"){\r
986             return n.className;\r
987         }\r
988         return n.getAttribute(attr) || n[attr];\r
989 \r
990     };\r
991 \r
992     function getNodes(ns, mode, tagName){\r
993         var result = [], ri = -1, cs;\r
994         if(!ns){\r
995             return result;\r
996         }\r
997         tagName = tagName || "*";\r
998         if(typeof ns.getElementsByTagName != "undefined"){\r
999             ns = [ns];\r
1000         }\r
1001         if(!mode){\r
1002             for(var i = 0, ni; ni = ns[i]; i++){\r
1003                 cs = ni.getElementsByTagName(tagName);\r
1004                 for(var j = 0, ci; ci = cs[j]; j++){\r
1005                     result[++ri] = ci;\r
1006                 }\r
1007             }\r
1008         }else if(mode == "/" || mode == ">"){\r
1009             var utag = tagName.toUpperCase();\r
1010             for(var i = 0, ni, cn; ni = ns[i]; i++){\r
1011                 cn = isOpera ? ni.childNodes : (ni.children || ni.childNodes);\r
1012                 for(var j = 0, cj; cj = cn[j]; j++){\r
1013                     if(cj.nodeName == utag || cj.nodeName == tagName  || tagName == '*'){\r
1014                         result[++ri] = cj;\r
1015                     }\r
1016                 }\r
1017             }\r
1018         }else if(mode == "+"){\r
1019             var utag = tagName.toUpperCase();\r
1020             for(var i = 0, n; n = ns[i]; i++){\r
1021                 while((n = n.nextSibling) && n.nodeType != 1);\r
1022                 if(n && (n.nodeName == utag || n.nodeName == tagName || tagName == '*')){\r
1023                     result[++ri] = n;\r
1024                 }\r
1025             }\r
1026         }else if(mode == "~"){\r
1027             var utag = tagName.toUpperCase();\r
1028             for(var i = 0, n; n = ns[i]; i++){\r
1029                 while((n = n.nextSibling)){\r
1030                     if (n.nodeName == utag || n.nodeName == tagName || tagName == '*'){\r
1031                         result[++ri] = n;\r
1032                     }\r
1033                 }\r
1034             }\r
1035         }\r
1036         return result;\r
1037     };\r
1038 \r
1039     function concat(a, b){\r
1040         if(b.slice){\r
1041             return a.concat(b);\r
1042         }\r
1043         for(var i = 0, l = b.length; i < l; i++){\r
1044             a[a.length] = b[i];\r
1045         }\r
1046         return a;\r
1047     }\r
1048 \r
1049     function byTag(cs, tagName){\r
1050         if(cs.tagName || cs == document){\r
1051             cs = [cs];\r
1052         }\r
1053         if(!tagName){\r
1054             return cs;\r
1055         }\r
1056         var r = [], ri = -1;\r
1057         tagName = tagName.toLowerCase();\r
1058         for(var i = 0, ci; ci = cs[i]; i++){\r
1059             if(ci.nodeType == 1 && ci.tagName.toLowerCase()==tagName){\r
1060                 r[++ri] = ci;\r
1061             }\r
1062         }\r
1063         return r;\r
1064     };\r
1065 \r
1066     function byId(cs, attr, id){\r
1067         if(cs.tagName || cs == document){\r
1068             cs = [cs];\r
1069         }\r
1070         if(!id){\r
1071             return cs;\r
1072         }\r
1073         var r = [], ri = -1;\r
1074         for(var i = 0,ci; ci = cs[i]; i++){\r
1075             if(ci && ci.id == id){\r
1076                 r[++ri] = ci;\r
1077                 return r;\r
1078             }\r
1079         }\r
1080         return r;\r
1081     };\r
1082 \r
1083     function byAttribute(cs, attr, value, op, custom){\r
1084         var r = [], \r
1085                 ri = -1, \r
1086                 st = custom=="{",\r
1087                 f = Ext.DomQuery.operators[op];\r
1088         for(var i = 0, ci; ci = cs[i]; i++){\r
1089             if(ci.nodeType != 1){\r
1090                 continue;\r
1091             }\r
1092             var a;\r
1093             if(st){\r
1094                 a = Ext.DomQuery.getStyle(ci, attr);\r
1095             }\r
1096             else if(attr == "class" || attr == "className"){\r
1097                 a = ci.className;\r
1098             }else if(attr == "for"){\r
1099                 a = ci.htmlFor;\r
1100             }else if(attr == "href"){\r
1101                 a = ci.getAttribute("href", 2);\r
1102             }else{\r
1103                 a = ci.getAttribute(attr);\r
1104             }\r
1105             if((f && f(a, value)) || (!f && a)){\r
1106                 r[++ri] = ci;\r
1107             }\r
1108         }\r
1109         return r;\r
1110     };\r
1111 \r
1112     function byPseudo(cs, name, value){\r
1113         return Ext.DomQuery.pseudos[name](cs, value);\r
1114     };\r
1115 \r
1116     function nodupIEXml(cs){\r
1117         var d = ++key, \r
1118                 r;\r
1119         cs[0].setAttribute("_nodup", d);\r
1120         r = [cs[0]];\r
1121         for(var i = 1, len = cs.length; i < len; i++){\r
1122             var c = cs[i];\r
1123             if(!c.getAttribute("_nodup") != d){\r
1124                 c.setAttribute("_nodup", d);\r
1125                 r[r.length] = c;\r
1126             }\r
1127         }\r
1128         for(var i = 0, len = cs.length; i < len; i++){\r
1129             cs[i].removeAttribute("_nodup");\r
1130         }\r
1131         return r;\r
1132     }\r
1133 \r
1134     function nodup(cs){\r
1135         if(!cs){\r
1136             return [];\r
1137         }\r
1138         var len = cs.length, c, i, r = cs, cj, ri = -1;\r
1139         if(!len || typeof cs.nodeType != "undefined" || len == 1){\r
1140             return cs;\r
1141         }\r
1142         if(isIE && typeof cs[0].selectSingleNode != "undefined"){\r
1143             return nodupIEXml(cs);\r
1144         }\r
1145         var d = ++key;\r
1146         cs[0]._nodup = d;\r
1147         for(i = 1; c = cs[i]; i++){\r
1148             if(c._nodup != d){\r
1149                 c._nodup = d;\r
1150             }else{\r
1151                 r = [];\r
1152                 for(var j = 0; j < i; j++){\r
1153                     r[++ri] = cs[j];\r
1154                 }\r
1155                 for(j = i+1; cj = cs[j]; j++){\r
1156                     if(cj._nodup != d){\r
1157                         cj._nodup = d;\r
1158                         r[++ri] = cj;\r
1159                     }\r
1160                 }\r
1161                 return r;\r
1162             }\r
1163         }\r
1164         return r;\r
1165     }\r
1166 \r
1167     function quickDiffIEXml(c1, c2){\r
1168         var d = ++key,\r
1169                 r = [];\r
1170         for(var i = 0, len = c1.length; i < len; i++){\r
1171             c1[i].setAttribute("_qdiff", d);\r
1172         }        \r
1173         for(var i = 0, len = c2.length; i < len; i++){\r
1174             if(c2[i].getAttribute("_qdiff") != d){\r
1175                 r[r.length] = c2[i];\r
1176             }\r
1177         }\r
1178         for(var i = 0, len = c1.length; i < len; i++){\r
1179            c1[i].removeAttribute("_qdiff");\r
1180         }\r
1181         return r;\r
1182     }\r
1183 \r
1184     function quickDiff(c1, c2){\r
1185         var len1 = c1.length,\r
1186                 d = ++key,\r
1187                 r = [];\r
1188         if(!len1){\r
1189             return c2;\r
1190         }\r
1191         if(isIE && c1[0].selectSingleNode){\r
1192             return quickDiffIEXml(c1, c2);\r
1193         }        \r
1194         for(var i = 0; i < len1; i++){\r
1195             c1[i]._qdiff = d;\r
1196         }        \r
1197         for(var i = 0, len = c2.length; i < len; i++){\r
1198             if(c2[i]._qdiff != d){\r
1199                 r[r.length] = c2[i];\r
1200             }\r
1201         }\r
1202         return r;\r
1203     }\r
1204 \r
1205     function quickId(ns, mode, root, id){\r
1206         if(ns == root){\r
1207            var d = root.ownerDocument || root;\r
1208            return d.getElementById(id);\r
1209         }\r
1210         ns = getNodes(ns, mode, "*");\r
1211         return byId(ns, null, id);\r
1212     }\r
1213 \r
1214     return {\r
1215         getStyle : function(el, name){\r
1216             return Ext.fly(el).getStyle(name);\r
1217         },\r
1218         /**\r
1219          * Compiles a selector/xpath query into a reusable function. The returned function\r
1220          * takes one parameter "root" (optional), which is the context node from where the query should start.\r
1221          * @param {String} selector The selector/xpath query\r
1222          * @param {String} type (optional) Either "select" (the default) or "simple" for a simple selector match\r
1223          * @return {Function}\r
1224          */\r
1225         compile : function(path, type){\r
1226             type = type || "select";\r
1227 \r
1228             var fn = ["var f = function(root){\n var mode; ++batch; var n = root || document;\n"],\r
1229                 q = path, mode, lq,\r
1230                 tk = Ext.DomQuery.matchers,\r
1231                 tklen = tk.length,\r
1232                 mm,\r
1233                 // accept leading mode switch\r
1234                 lmode = q.match(modeRe);\r
1235             \r
1236             if(lmode && lmode[1]){\r
1237                 fn[fn.length] = 'mode="'+lmode[1].replace(trimRe, "")+'";';\r
1238                 q = q.replace(lmode[1], "");\r
1239             }\r
1240             // strip leading slashes\r
1241             while(path.substr(0, 1)=="/"){\r
1242                 path = path.substr(1);\r
1243             }\r
1244 \r
1245             while(q && lq != q){\r
1246                 lq = q;\r
1247                 var tm = q.match(tagTokenRe);\r
1248                 if(type == "select"){\r
1249                     if(tm){\r
1250                         if(tm[1] == "#"){\r
1251                             fn[fn.length] = 'n = quickId(n, mode, root, "'+tm[2]+'");';\r
1252                         }else{\r
1253                             fn[fn.length] = 'n = getNodes(n, mode, "'+tm[2]+'");';\r
1254                         }\r
1255                         q = q.replace(tm[0], "");\r
1256                     }else if(q.substr(0, 1) != '@'){\r
1257                         fn[fn.length] = 'n = getNodes(n, mode, "*");';\r
1258                     }\r
1259                 }else{\r
1260                     if(tm){\r
1261                         if(tm[1] == "#"){\r
1262                             fn[fn.length] = 'n = byId(n, null, "'+tm[2]+'");';\r
1263                         }else{\r
1264                             fn[fn.length] = 'n = byTag(n, "'+tm[2]+'");';\r
1265                         }\r
1266                         q = q.replace(tm[0], "");\r
1267                     }\r
1268                 }\r
1269                 while(!(mm = q.match(modeRe))){\r
1270                     var matched = false;\r
1271                     for(var j = 0; j < tklen; j++){\r
1272                         var t = tk[j];\r
1273                         var m = q.match(t.re);\r
1274                         if(m){\r
1275                             fn[fn.length] = t.select.replace(tplRe, function(x, i){\r
1276                                                     return m[i];\r
1277                                                 });\r
1278                             q = q.replace(m[0], "");\r
1279                             matched = true;\r
1280                             break;\r
1281                         }\r
1282                     }\r
1283                     // prevent infinite loop on bad selector\r
1284                     if(!matched){\r
1285                         throw 'Error parsing selector, parsing failed at "' + q + '"';\r
1286                     }\r
1287                 }\r
1288                 if(mm[1]){\r
1289                     fn[fn.length] = 'mode="'+mm[1].replace(trimRe, "")+'";';\r
1290                     q = q.replace(mm[1], "");\r
1291                 }\r
1292             }\r
1293             fn[fn.length] = "return nodup(n);\n}";\r
1294             eval(fn.join(""));\r
1295             return f;\r
1296         },\r
1297 \r
1298         /**\r
1299          * Selects a group of elements.\r
1300          * @param {String} selector The selector/xpath query (can be a comma separated list of selectors)\r
1301          * @param {Node} root (optional) The start of the query (defaults to document).\r
1302          * @return {Array} An Array of DOM elements which match the selector. If there are\r
1303          * no matches, and empty Array is returned.\r
1304          */\r
1305         select : function(path, root, type){\r
1306             if(!root || root == document){\r
1307                 root = document;\r
1308             }\r
1309             if(typeof root == "string"){\r
1310                 root = document.getElementById(root);\r
1311             }\r
1312             var paths = path.split(","),\r
1313                 results = [];\r
1314             for(var i = 0, len = paths.length; i < len; i++){\r
1315                 var p = paths[i].replace(trimRe, "");\r
1316                 if(!cache[p]){\r
1317                     cache[p] = Ext.DomQuery.compile(p);\r
1318                     if(!cache[p]){\r
1319                         throw p + " is not a valid selector";\r
1320                     }\r
1321                 }\r
1322                 var result = cache[p](root);\r
1323                 if(result && result != document){\r
1324                     results = results.concat(result);\r
1325                 }\r
1326             }\r
1327             if(paths.length > 1){\r
1328                 return nodup(results);\r
1329             }\r
1330             return results;\r
1331         },\r
1332 \r
1333         /**\r
1334          * Selects a single element.\r
1335          * @param {String} selector The selector/xpath query\r
1336          * @param {Node} root (optional) The start of the query (defaults to document).\r
1337          * @return {Element} The DOM element which matched the selector.\r
1338          */\r
1339         selectNode : function(path, root){\r
1340             return Ext.DomQuery.select(path, root)[0];\r
1341         },\r
1342 \r
1343         /**\r
1344          * Selects the value of a node, optionally replacing null with the defaultValue.\r
1345          * @param {String} selector The selector/xpath query\r
1346          * @param {Node} root (optional) The start of the query (defaults to document).\r
1347          * @param {String} defaultValue\r
1348          * @return {String}\r
1349          */\r
1350         selectValue : function(path, root, defaultValue){\r
1351             path = path.replace(trimRe, "");\r
1352             if(!valueCache[path]){\r
1353                 valueCache[path] = Ext.DomQuery.compile(path, "select");\r
1354             }\r
1355             var n = valueCache[path](root),\r
1356                 v;\r
1357             n = n[0] ? n[0] : n;\r
1358             v = (n && n.firstChild ? n.firstChild.nodeValue : null);\r
1359             return ((v === null||v === undefined||v==='') ? defaultValue : v);\r
1360         },\r
1361 \r
1362         /**\r
1363          * Selects the value of a node, parsing integers and floats. Returns the defaultValue, or 0 if none is specified.\r
1364          * @param {String} selector The selector/xpath query\r
1365          * @param {Node} root (optional) The start of the query (defaults to document).\r
1366          * @param {Number} defaultValue\r
1367          * @return {Number}\r
1368          */\r
1369         selectNumber : function(path, root, defaultValue){\r
1370             var v = Ext.DomQuery.selectValue(path, root, defaultValue || 0);\r
1371             return parseFloat(v);\r
1372         },\r
1373 \r
1374         /**\r
1375          * Returns true if the passed element(s) match the passed simple selector (e.g. div.some-class or span:first-child)\r
1376          * @param {String/HTMLElement/Array} el An element id, element or array of elements\r
1377          * @param {String} selector The simple selector to test\r
1378          * @return {Boolean}\r
1379          */\r
1380         is : function(el, ss){\r
1381             if(typeof el == "string"){\r
1382                 el = document.getElementById(el);\r
1383             }\r
1384             var isArray = Ext.isArray(el),\r
1385                 result = Ext.DomQuery.filter(isArray ? el : [el], ss);\r
1386             return isArray ? (result.length == el.length) : (result.length > 0);\r
1387         },\r
1388 \r
1389         /**\r
1390          * Filters an array of elements to only include matches of a simple selector (e.g. div.some-class or span:first-child)\r
1391          * @param {Array} el An array of elements to filter\r
1392          * @param {String} selector The simple selector to test\r
1393          * @param {Boolean} nonMatches If true, it returns the elements that DON'T match\r
1394          * the selector instead of the ones that match\r
1395          * @return {Array} An Array of DOM elements which match the selector. If there are\r
1396          * no matches, and empty Array is returned.\r
1397          */\r
1398         filter : function(els, ss, nonMatches){\r
1399             ss = ss.replace(trimRe, "");\r
1400             if(!simpleCache[ss]){\r
1401                 simpleCache[ss] = Ext.DomQuery.compile(ss, "simple");\r
1402             }\r
1403             var result = simpleCache[ss](els);\r
1404             return nonMatches ? quickDiff(result, els) : result;\r
1405         },\r
1406 \r
1407         /**\r
1408          * Collection of matching regular expressions and code snippets.\r
1409          */\r
1410         matchers : [{\r
1411                 re: /^\.([\w-]+)/,\r
1412                 select: 'n = byClassName(n, null, " {1} ");'\r
1413             }, {\r
1414                 re: /^\:([\w-]+)(?:\(((?:[^\s>\/]*|.*?))\))?/,\r
1415                 select: 'n = byPseudo(n, "{1}", "{2}");'\r
1416             },{\r
1417                 re: /^(?:([\[\{])(?:@)?([\w-]+)\s?(?:(=|.=)\s?['"]?(.*?)["']?)?[\]\}])/,\r
1418                 select: 'n = byAttribute(n, "{2}", "{4}", "{3}", "{1}");'\r
1419             }, {\r
1420                 re: /^#([\w-]+)/,\r
1421                 select: 'n = byId(n, null, "{1}");'\r
1422             },{\r
1423                 re: /^@([\w-]+)/,\r
1424                 select: 'return {firstChild:{nodeValue:attrValue(n, "{1}")}};'\r
1425             }\r
1426         ],\r
1427 \r
1428         /**\r
1429          * Collection of operator comparison functions. The default operators are =, !=, ^=, $=, *=, %=, |= and ~=.\r
1430          * 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;.\r
1431          */\r
1432         operators : {\r
1433             "=" : function(a, v){\r
1434                 return a == v;\r
1435             },\r
1436             "!=" : function(a, v){\r
1437                 return a != v;\r
1438             },\r
1439             "^=" : function(a, v){\r
1440                 return a && a.substr(0, v.length) == v;\r
1441             },\r
1442             "$=" : function(a, v){\r
1443                 return a && a.substr(a.length-v.length) == v;\r
1444             },\r
1445             "*=" : function(a, v){\r
1446                 return a && a.indexOf(v) !== -1;\r
1447             },\r
1448             "%=" : function(a, v){\r
1449                 return (a % v) == 0;\r
1450             },\r
1451             "|=" : function(a, v){\r
1452                 return a && (a == v || a.substr(0, v.length+1) == v+'-');\r
1453             },\r
1454             "~=" : function(a, v){\r
1455                 return a && (' '+a+' ').indexOf(' '+v+' ') != -1;\r
1456             }\r
1457         },\r
1458 \r
1459         /**\r
1460          * Collection of "pseudo class" processors. Each processor is passed the current nodeset (array)\r
1461          * and the argument (if any) supplied in the selector.\r
1462          */\r
1463         pseudos : {\r
1464             "first-child" : function(c){\r
1465                 var r = [], ri = -1, n;\r
1466                 for(var i = 0, ci; ci = n = c[i]; i++){\r
1467                     while((n = n.previousSibling) && n.nodeType != 1);\r
1468                     if(!n){\r
1469                         r[++ri] = ci;\r
1470                     }\r
1471                 }\r
1472                 return r;\r
1473             },\r
1474 \r
1475             "last-child" : function(c){\r
1476                 var r = [], ri = -1, n;\r
1477                 for(var i = 0, ci; ci = n = c[i]; i++){\r
1478                     while((n = n.nextSibling) && n.nodeType != 1);\r
1479                     if(!n){\r
1480                         r[++ri] = ci;\r
1481                     }\r
1482                 }\r
1483                 return r;\r
1484             },\r
1485 \r
1486             "nth-child" : function(c, a) {\r
1487                 var r = [], ri = -1,\r
1488                         m = nthRe.exec(a == "even" && "2n" || a == "odd" && "2n+1" || !nthRe2.test(a) && "n+" + a || a),\r
1489                         f = (m[1] || 1) - 0, l = m[2] - 0;\r
1490                 for(var i = 0, n; n = c[i]; i++){\r
1491                     var pn = n.parentNode;\r
1492                     if (batch != pn._batch) {\r
1493                         var j = 0;\r
1494                         for(var cn = pn.firstChild; cn; cn = cn.nextSibling){\r
1495                             if(cn.nodeType == 1){\r
1496                                cn.nodeIndex = ++j;\r
1497                             }\r
1498                         }\r
1499                         pn._batch = batch;\r
1500                     }\r
1501                     if (f == 1) {\r
1502                         if (l == 0 || n.nodeIndex == l){\r
1503                             r[++ri] = n;\r
1504                         }\r
1505                     } else if ((n.nodeIndex + l) % f == 0){\r
1506                         r[++ri] = n;\r
1507                     }\r
1508                 }\r
1509 \r
1510                 return r;\r
1511             },\r
1512 \r
1513             "only-child" : function(c){\r
1514                 var r = [], ri = -1;;\r
1515                 for(var i = 0, ci; ci = c[i]; i++){\r
1516                     if(!prev(ci) && !next(ci)){\r
1517                         r[++ri] = ci;\r
1518                     }\r
1519                 }\r
1520                 return r;\r
1521             },\r
1522 \r
1523             "empty" : function(c){\r
1524                 var r = [], ri = -1;\r
1525                 for(var i = 0, ci; ci = c[i]; i++){\r
1526                     var cns = ci.childNodes, j = 0, cn, empty = true;\r
1527                     while(cn = cns[j]){\r
1528                         ++j;\r
1529                         if(cn.nodeType == 1 || cn.nodeType == 3){\r
1530                             empty = false;\r
1531                             break;\r
1532                         }\r
1533                     }\r
1534                     if(empty){\r
1535                         r[++ri] = ci;\r
1536                     }\r
1537                 }\r
1538                 return r;\r
1539             },\r
1540 \r
1541             "contains" : function(c, v){\r
1542                 var r = [], ri = -1;\r
1543                 for(var i = 0, ci; ci = c[i]; i++){\r
1544                     if((ci.textContent||ci.innerText||'').indexOf(v) != -1){\r
1545                         r[++ri] = ci;\r
1546                     }\r
1547                 }\r
1548                 return r;\r
1549             },\r
1550 \r
1551             "nodeValue" : function(c, v){\r
1552                 var r = [], ri = -1;\r
1553                 for(var i = 0, ci; ci = c[i]; i++){\r
1554                     if(ci.firstChild && ci.firstChild.nodeValue == v){\r
1555                         r[++ri] = ci;\r
1556                     }\r
1557                 }\r
1558                 return r;\r
1559             },\r
1560 \r
1561             "checked" : function(c){\r
1562                 var r = [], ri = -1;\r
1563                 for(var i = 0, ci; ci = c[i]; i++){\r
1564                     if(ci.checked == true){\r
1565                         r[++ri] = ci;\r
1566                     }\r
1567                 }\r
1568                 return r;\r
1569             },\r
1570 \r
1571             "not" : function(c, ss){\r
1572                 return Ext.DomQuery.filter(c, ss, true);\r
1573             },\r
1574 \r
1575             "any" : function(c, selectors){\r
1576                 var ss = selectors.split('|'),\r
1577                         r = [], ri = -1, s;\r
1578                 for(var i = 0, ci; ci = c[i]; i++){\r
1579                     for(var j = 0; s = ss[j]; j++){\r
1580                         if(Ext.DomQuery.is(ci, s)){\r
1581                             r[++ri] = ci;\r
1582                             break;\r
1583                         }\r
1584                     }\r
1585                 }\r
1586                 return r;\r
1587             },\r
1588 \r
1589             "odd" : function(c){\r
1590                 return this["nth-child"](c, "odd");\r
1591             },\r
1592 \r
1593             "even" : function(c){\r
1594                 return this["nth-child"](c, "even");\r
1595             },\r
1596 \r
1597             "nth" : function(c, a){\r
1598                 return c[a-1] || [];\r
1599             },\r
1600 \r
1601             "first" : function(c){\r
1602                 return c[0] || [];\r
1603             },\r
1604 \r
1605             "last" : function(c){\r
1606                 return c[c.length-1] || [];\r
1607             },\r
1608 \r
1609             "has" : function(c, ss){\r
1610                 var s = Ext.DomQuery.select,\r
1611                         r = [], ri = -1;\r
1612                 for(var i = 0, ci; ci = c[i]; i++){\r
1613                     if(s(ss, ci).length > 0){\r
1614                         r[++ri] = ci;\r
1615                     }\r
1616                 }\r
1617                 return r;\r
1618             },\r
1619 \r
1620             "next" : function(c, ss){\r
1621                 var is = Ext.DomQuery.is,\r
1622                         r = [], ri = -1;\r
1623                 for(var i = 0, ci; ci = c[i]; i++){\r
1624                     var n = next(ci);\r
1625                     if(n && is(n, ss)){\r
1626                         r[++ri] = ci;\r
1627                     }\r
1628                 }\r
1629                 return r;\r
1630             },\r
1631 \r
1632             "prev" : function(c, ss){\r
1633                 var is = Ext.DomQuery.is,\r
1634                         r = [], ri = -1;\r
1635                 for(var i = 0, ci; ci = c[i]; i++){\r
1636                     var n = prev(ci);\r
1637                     if(n && is(n, ss)){\r
1638                         r[++ri] = ci;\r
1639                     }\r
1640                 }\r
1641                 return r;\r
1642             }\r
1643         }\r
1644     };\r
1645 }();\r
1646 \r
1647 /**\r
1648  * Selects an array of DOM nodes by CSS/XPath selector. Shorthand of {@link Ext.DomQuery#select}\r
1649  * @param {String} path The selector/xpath query\r
1650  * @param {Node} root (optional) The start of the query (defaults to document).\r
1651  * @return {Array}\r
1652  * @member Ext\r
1653  * @method query\r
1654  */\r
1655 Ext.query = Ext.DomQuery.select;\r
1656 (function(){
1657
1658 var EXTUTIL = Ext.util,
1659     TOARRAY = Ext.toArray,
1660     EACH = Ext.each,
1661     ISOBJECT = Ext.isObject,
1662     TRUE = true,
1663     FALSE = false;
1664 /**
1665  * @class Ext.util.Observable
1666  * Base class that provides a common interface for publishing events. Subclasses are expected to
1667  * to have a property "events" with all the events defined, and, optionally, a property "listeners"
1668  * with configured listeners defined.<br>
1669  * For example:
1670  * <pre><code>
1671 Employee = Ext.extend(Ext.util.Observable, {
1672     constructor: function(config){
1673         this.name = config.name;
1674         this.addEvents({
1675             "fired" : true,
1676             "quit" : true
1677         });
1678
1679         // Copy configured listeners into *this* object so that the base class&#39;s
1680         // constructor will add them.
1681         this.listeners = config.listeners;
1682
1683         // Call our superclass constructor to complete construction process.
1684         Employee.superclass.constructor.call(config)
1685     }
1686 });
1687 </code></pre>
1688  * This could then be used like this:<pre><code>
1689 var newEmployee = new Employee({
1690     name: employeeName,
1691     listeners: {
1692         quit: function() {
1693             // By default, "this" will be the object that fired the event.
1694             alert(this.name + " has quit!");
1695         }
1696     }
1697 });
1698 </code></pre>
1699  */
1700 EXTUTIL.Observable = function(){
1701     /**
1702      * @cfg {Object} listeners (optional) <p>A config object containing one or more event handlers to be added to this
1703      * object during initialization.  This should be a valid listeners config object as specified in the
1704      * {@link #addListener} example for attaching multiple handlers at once.</p>
1705      * <br><p><b><u>DOM events from ExtJs {@link Ext.Component Components}</u></b></p>
1706      * <br><p>While <i>some</i> ExtJs Component classes export selected DOM events (e.g. "click", "mouseover" etc), this
1707      * is usually only done when extra value can be added. For example the {@link Ext.DataView DataView}'s
1708      * <b><code>{@link Ext.DataView#click click}</code></b> event passing the node clicked on. To access DOM
1709      * events directly from a Component's HTMLElement, listeners must be added to the <i>{@link Ext.Component#getEl Element}</i> after the Component
1710      * has been rendered. A plugin can simplify this step:<pre><code>
1711 // Plugin is configured with a listeners config object.
1712 // The Component is appended to the argument list of all handler functions.
1713 Ext.DomObserver = Ext.extend(Object, {
1714     constructor: function(config) {
1715         this.listeners = config.listeners ? config.listeners : config;
1716     },
1717
1718     // Component passes itself into plugin&#39;s init method
1719     init: function(c) {
1720         var p, l = this.listeners;
1721         for (p in l) {
1722             if (Ext.isFunction(l[p])) {
1723                 l[p] = this.createHandler(l[p], c);
1724             } else {
1725                 l[p].fn = this.createHandler(l[p].fn, c);
1726             }
1727         }
1728
1729         // Add the listeners to the Element immediately following the render call
1730         c.render = c.render.{@link Function#createSequence createSequence}(function() {
1731             var e = c.getEl();
1732             if (e) {
1733                 e.on(l);
1734             }
1735         });
1736     },
1737
1738     createHandler: function(fn, c) {
1739         return function(e) {
1740             fn.call(this, e, c);
1741         };
1742     }
1743 });
1744
1745 var combo = new Ext.form.ComboBox({
1746
1747     // Collapse combo when its element is clicked on
1748     plugins: [ new Ext.DomObserver({
1749         click: function(evt, comp) {
1750             comp.collapse();
1751         }
1752     })],
1753     store: myStore,
1754     typeAhead: true,
1755     mode: 'local',
1756     triggerAction: 'all'
1757 });
1758      * </code></pre></p>
1759      */
1760     var me = this, e = me.events;
1761     if(me.listeners){
1762         me.on(me.listeners);
1763         delete me.listeners;
1764     }
1765     me.events = e || {};
1766 };
1767
1768 EXTUTIL.Observable.prototype = function(){
1769     var filterOptRe = /^(?:scope|delay|buffer|single)$/, toLower = function(s){
1770         return s.toLowerCase();
1771     };
1772
1773     return {
1774         /**
1775          * <p>Fires the specified event with the passed parameters (minus the event name).</p>
1776          * <p>An event may be set to bubble up an Observable parent hierarchy (See {@link Ext.Component#getBubbleTarget})
1777          * by calling {@link #enableBubble}.</p>
1778          * @param {String} eventName The name of the event to fire.
1779          * @param {Object...} args Variable number of parameters are passed to handlers.
1780          * @return {Boolean} returns false if any of the handlers return false otherwise it returns true.
1781          */
1782
1783         fireEvent : function(){
1784             var a = TOARRAY(arguments),
1785                 ename = toLower(a[0]),
1786                 me = this,
1787                 ret = TRUE,
1788                 ce = me.events[ename],
1789                 q,
1790                 c;
1791             if (me.eventsSuspended === TRUE) {
1792                 if (q = me.suspendedEventsQueue) {
1793                     q.push(a);
1794                 }
1795             }
1796             else if(ISOBJECT(ce) && ce.bubble){
1797                 if(ce.fire.apply(ce, a.slice(1)) === FALSE) {
1798                     return FALSE;
1799                 }
1800                 c = me.getBubbleTarget && me.getBubbleTarget();
1801                 if(c && c.enableBubble) {
1802                     c.enableBubble(ename);
1803                     return c.fireEvent.apply(c, a);
1804                 }
1805             }
1806             else {
1807                 if (ISOBJECT(ce)) {
1808                     a.shift();
1809                     ret = ce.fire.apply(ce, a);
1810                 }
1811             }
1812             return ret;
1813         },
1814
1815         /**
1816          * Appends an event handler to this object.
1817          * @param {String}   eventName The name of the event to listen for.
1818          * @param {Function} handler The method the event invokes.
1819          * @param {Object}   scope (optional) The scope (<code><b>this</b></code> reference) in which the handler function is executed.
1820          * <b>If omitted, defaults to the object which fired the event.</b>
1821          * @param {Object}   options (optional) An object containing handler configuration.
1822          * properties. This may contain any of the following properties:<ul>
1823          * <li><b>scope</b> : Object<div class="sub-desc">The scope (<code><b>this</b></code> reference) in which the handler function is executed.
1824          * <b>If omitted, defaults to the object which fired the event.</b></div></li>
1825          * <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>
1826          * <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>
1827          * <li><b>buffer</b> : Number<div class="sub-desc">Causes the handler to be scheduled to run in an {@link Ext.util.DelayedTask} delayed
1828          * by the specified number of milliseconds. If the event fires again within that time, the original
1829          * handler is <em>not</em> invoked, but the new handler is scheduled in its place.</div></li>
1830          * <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>
1831          * if the event was bubbled up from a child Observable.</div></li>
1832          * </ul><br>
1833          * <p>
1834          * <b>Combining Options</b><br>
1835          * Using the options argument, it is possible to combine different types of listeners:<br>
1836          * <br>
1837          * A delayed, one-time listener.
1838          * <pre><code>
1839 myDataView.on('click', this.onClick, this, {
1840     single: true,
1841     delay: 100
1842 });</code></pre>
1843          * <p>
1844          * <b>Attaching multiple handlers in 1 call</b><br>
1845          * The method also allows for a single argument to be passed which is a config object containing properties
1846          * which specify multiple handlers.
1847          * <p>
1848          * <pre><code>
1849 myGridPanel.on({
1850     'click' : {
1851         fn: this.onClick,
1852         scope: this,
1853         delay: 100
1854     },
1855     'mouseover' : {
1856         fn: this.onMouseOver,
1857         scope: this
1858     },
1859     'mouseout' : {
1860         fn: this.onMouseOut,
1861         scope: this
1862     }
1863 });</code></pre>
1864      * <p>
1865      * Or a shorthand syntax:<br>
1866      * <pre><code>
1867 myGridPanel.on({
1868     'click' : this.onClick,
1869     'mouseover' : this.onMouseOver,
1870     'mouseout' : this.onMouseOut,
1871      scope: this
1872 });</code></pre>
1873          */
1874         addListener : function(eventName, fn, scope, o){
1875             var me = this,
1876                 e,
1877                 oe,
1878                 isF,
1879             ce;
1880             if (ISOBJECT(eventName)) {
1881                 o = eventName;
1882                 for (e in o){
1883                     oe = o[e];
1884                     if (!filterOptRe.test(e)) {
1885                         me.addListener(e, oe.fn || oe, oe.scope || o.scope, oe.fn ? oe : o);
1886                     }
1887                 }
1888             } else {
1889                 eventName = toLower(eventName);
1890                 ce = me.events[eventName] || TRUE;
1891                 if (typeof ce == "boolean") {
1892                     me.events[eventName] = ce = new EXTUTIL.Event(me, eventName);
1893                 }
1894                 ce.addListener(fn, scope, ISOBJECT(o) ? o : {});
1895             }
1896         },
1897
1898         /**
1899          * Removes an event handler.
1900          * @param {String}   eventName The type of event the handler was associated with.
1901          * @param {Function} handler   The handler to remove. <b>This must be a reference to the function passed into the {@link #addListener} call.</b>
1902          * @param {Object}   scope     (optional) The scope originally specified for the handler.
1903          */
1904         removeListener : function(eventName, fn, scope){
1905             var ce = this.events[toLower(eventName)];
1906             if (ISOBJECT(ce)) {
1907                 ce.removeListener(fn, scope);
1908             }
1909         },
1910
1911         /**
1912          * Removes all listeners for this object
1913          */
1914         purgeListeners : function(){
1915             var events = this.events,
1916                 evt,
1917                 key;
1918             for(key in events){
1919                 evt = events[key];
1920                 if(ISOBJECT(evt)){
1921                     evt.clearListeners();
1922                 }
1923             }
1924         },
1925
1926         /**
1927          * Used to define events on this Observable
1928          * @param {Object} object The object with the events defined
1929          */
1930         addEvents : function(o){
1931             var me = this;
1932             me.events = me.events || {};
1933             if (typeof o == 'string') {
1934                 EACH(arguments, function(a) {
1935                     me.events[a] = me.events[a] || TRUE;
1936                 });
1937             } else {
1938                 Ext.applyIf(me.events, o);
1939             }
1940         },
1941
1942         /**
1943          * Checks to see if this object has any listeners for a specified event
1944          * @param {String} eventName The name of the event to check for
1945          * @return {Boolean} True if the event is being listened for, else false
1946          */
1947         hasListener : function(eventName){
1948             var e = this.events[eventName];
1949             return ISOBJECT(e) && e.listeners.length > 0;
1950         },
1951
1952         /**
1953          * Suspend the firing of all events. (see {@link #resumeEvents})
1954          * @param {Boolean} queueSuspended Pass as true to queue up suspended events to be fired
1955          * after the {@link #resumeEvents} call instead of discarding all suspended events;
1956          */
1957         suspendEvents : function(queueSuspended){
1958             this.eventsSuspended = TRUE;
1959             if (queueSuspended){
1960                 this.suspendedEventsQueue = [];
1961             }
1962         },
1963
1964         /**
1965          * Resume firing events. (see {@link #suspendEvents})
1966          * If events were suspended using the <tt><b>queueSuspended</b></tt> parameter, then all
1967          * events fired during event suspension will be sent to any listeners now.
1968          */
1969         resumeEvents : function(){
1970             var me = this;
1971             me.eventsSuspended = !delete me.suspendedEventQueue;
1972             EACH(me.suspendedEventsQueue, function(e) {
1973                 me.fireEvent.apply(me, e);
1974             });
1975         }
1976     }
1977 }();
1978
1979 var OBSERVABLE = EXTUTIL.Observable.prototype;
1980 /**
1981  * Appends an event handler to this object (shorthand for {@link #addListener}.)
1982  * @param {String}   eventName     The type of event to listen for
1983  * @param {Function} handler       The method the event invokes
1984  * @param {Object}   scope         (optional) The scope (<code><b>this</b></code> reference) in which the handler function is executed.
1985  * <b>If omitted, defaults to the object which fired the event.</b>
1986  * @param {Object}   options       (optional) An object containing handler configuration.
1987  * @method
1988  */
1989 OBSERVABLE.on = OBSERVABLE.addListener;
1990 /**
1991  * Removes an event handler (shorthand for {@link #removeListener}.)
1992  * @param {String}   eventName     The type of event the handler was associated with.
1993  * @param {Function} handler       The handler to remove. <b>This must be a reference to the function passed into the {@link #addListener} call.</b>
1994  * @param {Object}   scope         (optional) The scope originally specified for the handler.
1995  * @method
1996  */
1997 OBSERVABLE.un = OBSERVABLE.removeListener;
1998
1999 /**
2000  * Removes <b>all</b> added captures from the Observable.
2001  * @param {Observable} o The Observable to release
2002  * @static
2003  */
2004 EXTUTIL.Observable.releaseCapture = function(o){
2005     o.fireEvent = OBSERVABLE.fireEvent;
2006 };
2007
2008 function createTargeted(h, o, scope){
2009     return function(){
2010         if(o.target == arguments[0]){
2011             h.apply(scope, TOARRAY(arguments));
2012         }
2013     };
2014 };
2015
2016 function createBuffered(h, o, scope){
2017     var task = new EXTUTIL.DelayedTask();
2018     return function(){
2019         task.delay(o.buffer, h, scope, TOARRAY(arguments));
2020     };
2021 }
2022
2023 function createSingle(h, e, fn, scope){
2024     return function(){
2025         e.removeListener(fn, scope);
2026         return h.apply(scope, arguments);
2027     };
2028 }
2029
2030 function createDelayed(h, o, scope){
2031     return function(){
2032         var args = TOARRAY(arguments);
2033         (function(){
2034             h.apply(scope, args);
2035         }).defer(o.delay || 10);
2036     };
2037 };
2038
2039 EXTUTIL.Event = function(obj, name){
2040     this.name = name;
2041     this.obj = obj;
2042     this.listeners = [];
2043 };
2044
2045 EXTUTIL.Event.prototype = {
2046     addListener : function(fn, scope, options){
2047         var me = this,
2048             l;
2049         scope = scope || me.obj;
2050         if(!me.isListening(fn, scope)){
2051             l = me.createListener(fn, scope, options);
2052             if(me.firing){ // if we are currently firing this event, don't disturb the listener loop
2053                 me.listeners = me.listeners.slice(0);
2054             }
2055             me.listeners.push(l);
2056         }
2057     },
2058
2059     createListener: function(fn, scope, o){
2060         o = o || {}, scope = scope || this.obj;
2061         var l = {
2062             fn: fn,
2063             scope: scope,
2064             options: o
2065         }, h = fn;
2066         if(o.target){
2067             h = createTargeted(h, o, scope);
2068         }
2069         if(o.delay){
2070             h = createDelayed(h, o, scope);
2071         }
2072         if(o.single){
2073             h = createSingle(h, this, fn, scope);
2074         }
2075         if(o.buffer){
2076             h = createBuffered(h, o, scope);
2077         }
2078         l.fireFn = h;
2079         return l;
2080     },
2081
2082     findListener : function(fn, scope){
2083         var s, ret = -1;
2084         EACH(this.listeners, function(l, i) {
2085             s = l.scope;
2086             if(l.fn == fn && (s == scope || s == this.obj)){
2087                 ret = i;
2088                 return FALSE;
2089             }
2090         },
2091         this);
2092         return ret;
2093     },
2094
2095     isListening : function(fn, scope){
2096         return this.findListener(fn, scope) != -1;
2097     },
2098
2099     removeListener : function(fn, scope){
2100         var index,
2101             me = this,
2102             ret = FALSE;
2103         if((index = me.findListener(fn, scope)) != -1){
2104             if (me.firing) {
2105                 me.listeners = me.listeners.slice(0);
2106             }
2107             me.listeners.splice(index, 1);
2108             ret = TRUE;
2109         }
2110         return ret;
2111     },
2112
2113     clearListeners : function(){
2114         this.listeners = [];
2115     },
2116
2117     fire : function(){
2118         var me = this,
2119             args = TOARRAY(arguments),
2120             ret = TRUE;
2121
2122         EACH(me.listeners, function(l) {
2123             me.firing = TRUE;
2124             if (l.fireFn.apply(l.scope || me.obj || window, args) === FALSE) {
2125                 return ret = me.firing = FALSE;
2126             }
2127         });
2128         me.firing = FALSE;
2129         return ret;
2130     }
2131 };
2132 })();/**\r
2133  * @class Ext.util.Observable\r
2134  */\r
2135 Ext.apply(Ext.util.Observable.prototype, function(){    \r
2136     // this is considered experimental (along with beforeMethod, afterMethod, removeMethodListener?)\r
2137     // allows for easier interceptor and sequences, including cancelling and overwriting the return value of the call\r
2138     // private\r
2139     function getMethodEvent(method){\r
2140         var e = (this.methodEvents = this.methodEvents ||\r
2141         {})[method], returnValue, v, cancel, obj = this;\r
2142         \r
2143         if (!e) {\r
2144             this.methodEvents[method] = e = {};\r
2145             e.originalFn = this[method];\r
2146             e.methodName = method;\r
2147             e.before = [];\r
2148             e.after = [];\r
2149             \r
2150             var makeCall = function(fn, scope, args){\r
2151                 if (!Ext.isEmpty(v = fn.apply(scope || obj, args))) {\r
2152                     if (Ext.isObject(v)) {\r
2153                         returnValue = !Ext.isEmpty(v.returnValue) ? v.returnValue : v;\r
2154                         cancel = !!v.cancel;\r
2155                     }\r
2156                     else \r
2157                         if (v === false) {\r
2158                             cancel = true;\r
2159                         }\r
2160                         else {\r
2161                             returnValue = v;\r
2162                         }\r
2163                 }\r
2164             };\r
2165             \r
2166             this[method] = function(){\r
2167                 var args = Ext.toArray(arguments);\r
2168                 returnValue = v = undefined;\r
2169                 cancel = false;\r
2170                 \r
2171                 Ext.each(e.before, function(b){\r
2172                     makeCall(b.fn, b.scope, args);\r
2173                     if (cancel) {\r
2174                         return returnValue;\r
2175                     }\r
2176                 });\r
2177                 \r
2178                 if (!Ext.isEmpty(v = e.originalFn.apply(obj, args))) {\r
2179                     returnValue = v;\r
2180                 }\r
2181                 Ext.each(e.after, function(a){\r
2182                     makeCall(a.fn, a.scope, args);\r
2183                     if (cancel) {\r
2184                         return returnValue;\r
2185                     }\r
2186                 });\r
2187                 return returnValue;\r
2188             };\r
2189         }\r
2190         return e;\r
2191     }\r
2192     \r
2193     return {\r
2194         // these are considered experimental\r
2195         // allows for easier interceptor and sequences, including cancelling and overwriting the return value of the call\r
2196         // adds an "interceptor" called before the original method\r
2197         beforeMethod: function(method, fn, scope){\r
2198             getMethodEvent.call(this, method).before.push({\r
2199                 fn: fn,\r
2200                 scope: scope\r
2201             });\r
2202         },\r
2203         \r
2204         // adds a "sequence" called after the original method\r
2205         afterMethod: function(method, fn, scope){\r
2206             getMethodEvent.call(this, method).after.push({\r
2207                 fn: fn,\r
2208                 scope: scope\r
2209             });\r
2210         },\r
2211         \r
2212         removeMethodListener: function(method, fn, scope){\r
2213             var e = getMethodEvent.call(this, method), found = false;\r
2214             Ext.each(e.before, function(b, i, arr){\r
2215                 if (b.fn == fn && b.scope == scope) {\r
2216                     arr.splice(i, 1);\r
2217                     found = true;\r
2218                     return false;\r
2219                 }\r
2220             });\r
2221             if (!found) {\r
2222                 Ext.each(e.after, function(a, i, arr){\r
2223                     if (a.fn == fn && a.scope == scope) {\r
2224                         arr.splice(i, 1);\r
2225                         return false;\r
2226                     }\r
2227                 });\r
2228             }\r
2229         },\r
2230         \r
2231         /**\r
2232          * Relays selected events from the specified Observable as if the events were fired by <tt><b>this</b></tt>.\r
2233          * @param {Object} o The Observable whose events this object is to relay.\r
2234          * @param {Array} events Array of event names to relay.\r
2235          */\r
2236         relayEvents: function(o, events){\r
2237             var me = this;\r
2238             function createHandler(ename){\r
2239                 return function(){\r
2240                     return me.fireEvent.apply(me, [ename].concat(Ext.toArray(arguments)));\r
2241                 };\r
2242             }\r
2243             Ext.each(events, function(ename){\r
2244                 me.events[ename] = me.events[ename] || true;\r
2245                 o.on(ename, createHandler(ename), me);\r
2246             });\r
2247         },\r
2248         \r
2249         /**\r
2250          * Used to enable bubbling of events\r
2251          * @param {Object} events\r
2252          */\r
2253         enableBubble: function(events){\r
2254             var me = this;\r
2255             events = Ext.isArray(events) ? events : Ext.toArray(arguments);\r
2256             Ext.each(events, function(ename){\r
2257                 ename = ename.toLowerCase();\r
2258                 var ce = me.events[ename] || true;\r
2259                 if (typeof ce == "boolean") {\r
2260                     ce = new Ext.util.Event(me, ename);\r
2261                     me.events[ename] = ce;\r
2262                 }\r
2263                 ce.bubble = true;\r
2264             });\r
2265         }\r
2266     };\r
2267 }());\r
2268 \r
2269 \r
2270 /**\r
2271  * Starts capture on the specified Observable. All events will be passed\r
2272  * to the supplied function with the event name + standard signature of the event\r
2273  * <b>before</b> the event is fired. If the supplied function returns false,\r
2274  * the event will not fire.\r
2275  * @param {Observable} o The Observable to capture\r
2276  * @param {Function} fn The function to call\r
2277  * @param {Object} scope (optional) The scope (this object) for the fn\r
2278  * @static\r
2279  */\r
2280 Ext.util.Observable.capture = function(o, fn, scope){\r
2281     o.fireEvent = o.fireEvent.createInterceptor(fn, scope);\r
2282 };\r
2283 \r
2284 \r
2285 /**\r
2286  * Sets observability on the passed class constructor.<p>\r
2287  * <p>This makes any event fired on any instance of the passed class also fire a single event through\r
2288  * the <i>class</i> allowing for central handling of events on many instances at once.</p>\r
2289  * <p>Usage:</p><pre><code>\r
2290 Ext.util.Observable.observeClass(Ext.data.Connection);\r
2291 Ext.data.Connection.on('beforerequest', function(con, options) {\r
2292     console.log("Ajax request made to " + options.url);\r
2293 });</code></pre>\r
2294  * @param {Function} c The class constructor to make observable.\r
2295  * @static\r
2296  */\r
2297 Ext.util.Observable.observeClass = function(c){\r
2298     Ext.apply(c, new Ext.util.Observable());\r
2299     c.prototype.fireEvent = function(){\r
2300         return (c.fireEvent.apply(c, arguments) !== false) &&\r
2301         (Ext.util.Observable.prototype.fireEvent.apply(this, arguments) !== false);\r
2302     };\r
2303 };/**
2304  * @class Ext.EventManager
2305  * Registers event handlers that want to receive a normalized EventObject instead of the standard browser event and provides
2306  * several useful events directly.
2307  * See {@link Ext.EventObject} for more details on normalized event objects.
2308  * @singleton
2309  */
2310 Ext.EventManager = function(){
2311     var docReadyEvent, 
2312         docReadyProcId, 
2313         docReadyState = false,          
2314         E = Ext.lib.Event,
2315         D = Ext.lib.Dom,
2316         DOC = document,
2317         WINDOW = window,
2318         IEDEFERED = "ie-deferred-loader",
2319         DOMCONTENTLOADED = "DOMContentLoaded",
2320         elHash = {},
2321         propRe = /^(?:scope|delay|buffer|single|stopEvent|preventDefault|stopPropagation|normalized|args|delegate)$/;
2322
2323     /// There is some jquery work around stuff here that isn't needed in Ext Core.
2324     function addListener(el, ename, fn, wrap, scope){       
2325         var id = Ext.id(el),
2326                 es = elHash[id] = elHash[id] || {};             
2327        
2328         (es[ename] = es[ename] || []).push([fn, wrap, scope]);
2329         E.on(el, ename, wrap);
2330
2331         // this is a workaround for jQuery and should somehow be removed from Ext Core in the future
2332         // without breaking ExtJS.
2333         if(ename == "mousewheel" && el.addEventListener){ // workaround for jQuery
2334                 var args = ["DOMMouseScroll", wrap, false];
2335                 el.addEventListener.apply(el, args);
2336             E.on(window, 'unload', function(){
2337                     el.removeEventListener.apply(el, args);                
2338             });
2339         }
2340         if(ename == "mousedown" && el == document){ // fix stopped mousedowns on the document
2341             Ext.EventManager.stoppedMouseDownEvent.addListener(wrap);
2342         }
2343     };
2344     
2345     function fireDocReady(){
2346         if(!docReadyState){            
2347             Ext.isReady = docReadyState = true;
2348             if(docReadyProcId){
2349                 clearInterval(docReadyProcId);
2350             }
2351             if(Ext.isGecko || Ext.isOpera) {
2352                 DOC.removeEventListener(DOMCONTENTLOADED, fireDocReady, false);
2353             }
2354             if(Ext.isIE){
2355                 var defer = DOC.getElementById(IEDEFERED);
2356                 if(defer){
2357                     defer.onreadystatechange = null;
2358                     defer.parentNode.removeChild(defer);
2359                 }
2360             }
2361             if(docReadyEvent){
2362                 docReadyEvent.fire();
2363                 docReadyEvent.clearListeners();
2364             }
2365         }
2366     };
2367
2368     function initDocReady(){
2369             var COMPLETE = "complete";
2370                 
2371         docReadyEvent = new Ext.util.Event();
2372         if (Ext.isGecko || Ext.isOpera) {
2373             DOC.addEventListener(DOMCONTENTLOADED, fireDocReady, false);
2374         } else if (Ext.isIE){
2375             DOC.write("<s"+'cript id=' + IEDEFERED + ' defer="defer" src="/'+'/:"></s'+"cript>");            
2376             DOC.getElementById(IEDEFERED).onreadystatechange = function(){
2377                 if(this.readyState == COMPLETE){
2378                     fireDocReady();
2379                 }
2380             };
2381         } else if (Ext.isWebKit){
2382             docReadyProcId = setInterval(function(){                
2383                 if(DOC.readyState == COMPLETE) {
2384                     fireDocReady();
2385                  }
2386             }, 10);
2387         }
2388         // no matter what, make sure it fires on load
2389         E.on(WINDOW, "load", fireDocReady);
2390     };
2391
2392     function createTargeted(h, o){
2393         return function(){
2394                 var args = Ext.toArray(arguments);
2395             if(o.target == Ext.EventObject.setEvent(args[0]).target){
2396                 h.apply(this, args);
2397             }
2398         };
2399     };    
2400     
2401     function createBuffered(h, o){
2402         var task = new Ext.util.DelayedTask(h);
2403         return function(e){
2404             // create new event object impl so new events don't wipe out properties            
2405             task.delay(o.buffer, h, null, [new Ext.EventObjectImpl(e)]);
2406         };
2407     };
2408
2409     function createSingle(h, el, ename, fn, scope){
2410         return function(e){
2411             Ext.EventManager.removeListener(el, ename, fn, scope);
2412             h(e);
2413         };
2414     };
2415
2416     function createDelayed(h, o){
2417         return function(e){
2418             // create new event object impl so new events don't wipe out properties   
2419             e = new Ext.EventObjectImpl(e);
2420             setTimeout(function(){
2421                 h(e);
2422             }, o.delay || 10);
2423         };
2424     };
2425
2426     function listen(element, ename, opt, fn, scope){
2427         var o = !Ext.isObject(opt) ? {} : opt,
2428                 el = Ext.getDom(element);
2429                 
2430         fn = fn || o.fn; 
2431         scope = scope || o.scope;
2432         
2433         if(!el){
2434             throw "Error listening for \"" + ename + '\". Element "' + element + '" doesn\'t exist.';
2435         }
2436         function h(e){
2437             // prevent errors while unload occurring
2438             if(!Ext){// !window[xname]){  ==> can't we do this? 
2439                 return;
2440             }
2441             e = Ext.EventObject.setEvent(e);
2442             var t;
2443             if (o.delegate) {
2444                 if(!(t = e.getTarget(o.delegate, el))){
2445                     return;
2446                 }
2447             } else {
2448                 t = e.target;
2449             }            
2450             if (o.stopEvent) {
2451                 e.stopEvent();
2452             }
2453             if (o.preventDefault) {
2454                e.preventDefault();
2455             }
2456             if (o.stopPropagation) {
2457                 e.stopPropagation();
2458             }
2459             if (o.normalized) {
2460                 e = e.browserEvent;
2461             }
2462             
2463             fn.call(scope || el, e, t, o);
2464         };
2465         if(o.target){
2466             h = createTargeted(h, o);
2467         }
2468         if(o.delay){
2469             h = createDelayed(h, o);
2470         }
2471         if(o.single){
2472             h = createSingle(h, el, ename, fn, scope);
2473         }
2474         if(o.buffer){
2475             h = createBuffered(h, o);
2476         }
2477
2478         addListener(el, ename, fn, h, scope);
2479         return h;
2480     };
2481
2482     var pub = {
2483             /**
2484              * Appends an event handler to an element.  The shorthand version {@link #on} is equivalent.  Typically you will
2485              * use {@link Ext.Element#addListener} directly on an Element in favor of calling this version.
2486              * @param {String/HTMLElement} el The html element or id to assign the event handler to
2487              * @param {String} eventName The type of event to listen for
2488              * @param {Function} handler The handler function the event invokes This function is passed
2489              * the following parameters:<ul>
2490              * <li>evt : EventObject<div class="sub-desc">The {@link Ext.EventObject EventObject} describing the event.</div></li>
2491              * <li>t : Element<div class="sub-desc">The {@link Ext.Element Element} which was the target of the event.
2492              * Note that this may be filtered by using the <tt>delegate</tt> option.</div></li>
2493              * <li>o : Object<div class="sub-desc">The options object from the addListener call.</div></li>
2494              * </ul>
2495              * @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>.
2496              * @param {Object} options (optional) An object containing handler configuration properties.
2497              * This may contain any of the following properties:<ul>
2498              * <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>
2499              * <li>delegate : String<div class="sub-desc">A simple selector to filter the target or look for a descendant of the target</div></li>
2500              * <li>stopEvent : Boolean<div class="sub-desc">True to stop the event. That is stop propagation, and prevent the default action.</div></li>
2501              * <li>preventDefault : Boolean<div class="sub-desc">True to prevent the default action</div></li>
2502              * <li>stopPropagation : Boolean<div class="sub-desc">True to prevent event propagation</div></li>
2503              * <li>normalized : Boolean<div class="sub-desc">False to pass a browser event to the handler function instead of an Ext.EventObject</div></li>
2504              * <li>delay : Number<div class="sub-desc">The number of milliseconds to delay the invocation of the handler after te event fires.</div></li>
2505              * <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>
2506              * <li>buffer : Number<div class="sub-desc">Causes the handler to be scheduled to run in an {@link Ext.util.DelayedTask} delayed
2507              * by the specified number of milliseconds. If the event fires again within that time, the original
2508              * handler is <em>not</em> invoked, but the new handler is scheduled in its place.</div></li>
2509              * <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>
2510              * </ul><br>
2511              * <p>See {@link Ext.Element#addListener} for examples of how to use these options.</p>
2512              */
2513                 addListener : function(element, eventName, fn, scope, options){                                              
2514             if(Ext.isObject(eventName)){                
2515                     var o = eventName, e, val;
2516                 for(e in o){
2517                         val = o[e];
2518                     if(!propRe.test(e)){                                                 
2519                             if(Ext.isFunction(val)){
2520                                 // shared options
2521                                 listen(element, e, o, val, o.scope);
2522                             }else{
2523                                 // individual options
2524                                 listen(element, e, val);
2525                             }
2526                     }
2527                 }
2528             } else {
2529                 listen(element, eventName, options, fn, scope);
2530                 }
2531         },
2532         
2533         /**
2534          * Removes an event handler from an element.  The shorthand version {@link #un} is equivalent.  Typically
2535          * you will use {@link Ext.Element#removeListener} directly on an Element in favor of calling this version.
2536          * @param {String/HTMLElement} el The id or html element from which to remove the event
2537          * @param {String} eventName The type of event
2538          * @param {Function} fn The handler function to remove
2539          */
2540         removeListener : function(element, eventName, fn, scope){            
2541             var el = Ext.getDom(element),
2542                 id = Ext.id(el),
2543                     wrap;      
2544                 
2545                 Ext.each((elHash[id] || {})[eventName], function (v,i,a) {
2546                             if (Ext.isArray(v) && v[0] == fn && (!scope || v[2] == scope)) {                                                    
2547                                 E.un(el, eventName, wrap = v[1]);
2548                                 a.splice(i,1);
2549                                 return false;                           
2550                         }
2551                 });     
2552
2553             // jQuery workaround that should be removed from Ext Core
2554                 if(eventName == "mousewheel" && el.addEventListener && wrap){
2555                     el.removeEventListener("DOMMouseScroll", wrap, false);
2556                 }
2557                         
2558                 if(eventName == "mousedown" && el == DOC && wrap){ // fix stopped mousedowns on the document
2559                     Ext.EventManager.stoppedMouseDownEvent.removeListener(wrap);
2560                 }
2561         },
2562         
2563         /**
2564          * Removes all event handers from an element.  Typically you will use {@link Ext.Element#removeAllListeners}
2565          * directly on an Element in favor of calling this version.
2566          * @param {String/HTMLElement} el The id or html element from which to remove the event
2567          */
2568         removeAll : function(el){
2569                 var id = Ext.id(el = Ext.getDom(el)), 
2570                                 es = elHash[id],                                
2571                                 ename;
2572                
2573                 for(ename in es){
2574                     if(es.hasOwnProperty(ename)){                           
2575                         Ext.each(es[ename], function(v) {
2576                             E.un(el, ename, v.wrap);                    
2577                         });
2578                     }            
2579                 }
2580                 elHash[id] = null;       
2581         },
2582
2583         /**
2584          * Fires when the document is ready (before onload and before images are loaded). Can be
2585          * accessed shorthanded as Ext.onReady().
2586          * @param {Function} fn The method the event invokes
2587          * @param {Object} scope (optional) An object that becomes the scope of the handler
2588          * @param {boolean} options (optional) An object containing standard {@link #addListener} options
2589          */
2590         onDocumentReady : function(fn, scope, options){
2591             if(docReadyState){ // if it already fired
2592                 docReadyEvent.addListener(fn, scope, options);
2593                 docReadyEvent.fire();
2594                 docReadyEvent.clearListeners();               
2595             } else {
2596                 if(!docReadyEvent) initDocReady();
2597                 options = options || {};
2598                     options.delay = options.delay || 1;             
2599                     docReadyEvent.addListener(fn, scope, options);
2600             }
2601         },
2602         
2603         elHash : elHash   
2604     };
2605      /**
2606      * Appends an event handler to an element.  Shorthand for {@link #addListener}.
2607      * @param {String/HTMLElement} el The html element or id to assign the event handler to
2608      * @param {String} eventName The type of event to listen for
2609      * @param {Function} handler The handler function the event invokes
2610      * @param {Object} scope (optional) The scope in which to execute the handler
2611      * function (the handler function's "this" context)
2612      * @param {Object} options (optional) An object containing standard {@link #addListener} options
2613      * @member Ext.EventManager
2614      * @method on
2615      */
2616     pub.on = pub.addListener;
2617     /**
2618      * Removes an event handler from an element.  Shorthand for {@link #removeListener}.
2619      * @param {String/HTMLElement} el The id or html element from which to remove the event
2620      * @param {String} eventName The type of event
2621      * @param {Function} fn The handler function to remove
2622      * @return {Boolean} True if a listener was actually removed, else false
2623      * @member Ext.EventManager
2624      * @method un
2625      */
2626     pub.un = pub.removeListener;
2627
2628     pub.stoppedMouseDownEvent = new Ext.util.Event();
2629     return pub;
2630 }();
2631 /**
2632   * Fires when the document is ready (before onload and before images are loaded).  Shorthand of {@link Ext.EventManager#onDocumentReady}.
2633   * @param {Function} fn The method the event invokes
2634   * @param {Object} scope An object that becomes the scope of the handler
2635   * @param {boolean} options (optional) An object containing standard {@link #addListener} options
2636   * @member Ext
2637   * @method onReady
2638  */
2639 Ext.onReady = Ext.EventManager.onDocumentReady;
2640
2641
2642 //Initialize doc classes
2643 (function(){
2644     
2645     var initExtCss = function(){
2646         // find the body element
2647         var bd = document.body || document.getElementsByTagName('body')[0];
2648         if(!bd){ return false; }
2649         var cls = [' ',
2650                 Ext.isIE ? "ext-ie " + (Ext.isIE6 ? 'ext-ie6' : (Ext.isIE7 ? 'ext-ie7' : 'ext-ie8'))
2651                 : Ext.isGecko ? "ext-gecko " + (Ext.isGecko2 ? 'ext-gecko2' : 'ext-gecko3')
2652                 : Ext.isOpera ? "ext-opera"
2653                 : Ext.isWebKit ? "ext-webkit" : ""];
2654
2655         if(Ext.isSafari){
2656             cls.push("ext-safari " + (Ext.isSafari2 ? 'ext-safari2' : (Ext.isSafari3 ? 'ext-safari3' : 'ext-safari4')));
2657         }else if(Ext.isChrome){
2658             cls.push("ext-chrome");
2659         }
2660
2661         if(Ext.isMac){
2662             cls.push("ext-mac");
2663         }
2664         if(Ext.isLinux){
2665             cls.push("ext-linux");
2666         }
2667
2668         if(Ext.isStrict || Ext.isBorderBox){ // add to the parent to allow for selectors like ".ext-strict .ext-ie"
2669             var p = bd.parentNode;
2670             if(p){
2671                 p.className += Ext.isStrict ? ' ext-strict' : ' ext-border-box';
2672             }
2673         }
2674         bd.className += cls.join(' ');
2675         return true;
2676     }
2677
2678     if(!initExtCss()){
2679         Ext.onReady(initExtCss);
2680     }
2681 })();
2682
2683
2684 /**
2685  * @class Ext.EventObject
2686  * Just as {@link Ext.Element} wraps around a native DOM node, Ext.EventObject 
2687  * wraps the browser's native event-object normalizing cross-browser differences,
2688  * such as which mouse button is clicked, keys pressed, mechanisms to stop
2689  * event-propagation along with a method to prevent default actions from taking place.
2690  * <p>For example:</p>
2691  * <pre><code>
2692 function handleClick(e, t){ // e is not a standard event object, it is a Ext.EventObject
2693     e.preventDefault();
2694     var target = e.getTarget(); // same as t (the target HTMLElement)
2695     ...
2696 }
2697 var myDiv = {@link Ext#get Ext.get}("myDiv");  // get reference to an {@link Ext.Element}
2698 myDiv.on(         // 'on' is shorthand for addListener
2699     "click",      // perform an action on click of myDiv
2700     handleClick   // reference to the action handler
2701 );  
2702 // other methods to do the same:
2703 Ext.EventManager.on("myDiv", 'click', handleClick);
2704 Ext.EventManager.addListener("myDiv", 'click', handleClick);
2705  </code></pre>
2706  * @singleton
2707  */
2708 Ext.EventObject = function(){
2709     var E = Ext.lib.Event,
2710         // safari keypress events for special keys return bad keycodes
2711         safariKeys = {
2712                 3 : 13, // enter
2713                 63234 : 37, // left
2714                 63235 : 39, // right
2715                 63232 : 38, // up
2716                 63233 : 40, // down
2717                 63276 : 33, // page up
2718                 63277 : 34, // page down
2719                 63272 : 46, // delete
2720                 63273 : 36, // home
2721                 63275 : 35  // end
2722         },
2723         // normalize button clicks
2724         btnMap = Ext.isIE ? {1:0,4:1,2:2} :
2725                 (Ext.isWebKit ? {1:0,2:1,3:2} : {0:0,1:1,2:2});
2726
2727     Ext.EventObjectImpl = function(e){
2728         if(e){
2729             this.setEvent(e.browserEvent || e);
2730         }
2731     };
2732
2733     Ext.EventObjectImpl.prototype = {
2734            /** @private */
2735         setEvent : function(e){
2736                 var me = this;
2737             if(e == me || (e && e.browserEvent)){ // already wrapped
2738                 return e;
2739             }
2740             me.browserEvent = e;
2741             if(e){
2742                 // normalize buttons
2743                 me.button = e.button ? btnMap[e.button] : (e.which ? e.which - 1 : -1);
2744                 if(e.type == 'click' && me.button == -1){
2745                     me.button = 0;
2746                 }
2747                 me.type = e.type;
2748                 me.shiftKey = e.shiftKey;
2749                 // mac metaKey behaves like ctrlKey
2750                 me.ctrlKey = e.ctrlKey || e.metaKey || false;
2751                 me.altKey = e.altKey;
2752                 // in getKey these will be normalized for the mac
2753                 me.keyCode = e.keyCode;
2754                 me.charCode = e.charCode;
2755                 // cache the target for the delayed and or buffered events
2756                 me.target = E.getTarget(e);
2757                 // same for XY
2758                 me.xy = E.getXY(e);
2759             }else{
2760                 me.button = -1;
2761                 me.shiftKey = false;
2762                 me.ctrlKey = false;
2763                 me.altKey = false;
2764                 me.keyCode = 0;
2765                 me.charCode = 0;
2766                 me.target = null;
2767                 me.xy = [0, 0];
2768             }
2769             return me;
2770         },
2771
2772         /**
2773          * Stop the event (preventDefault and stopPropagation)
2774          */
2775         stopEvent : function(){
2776                 var me = this;
2777             if(me.browserEvent){
2778                 if(me.browserEvent.type == 'mousedown'){
2779                     Ext.EventManager.stoppedMouseDownEvent.fire(me);
2780                 }
2781                 E.stopEvent(me.browserEvent);
2782             }
2783         },
2784
2785         /**
2786          * Prevents the browsers default handling of the event.
2787          */
2788         preventDefault : function(){
2789             if(this.browserEvent){
2790                 E.preventDefault(this.browserEvent);
2791             }
2792         },        
2793
2794         /**
2795          * Cancels bubbling of the event.
2796          */
2797         stopPropagation : function(){
2798                 var me = this;
2799             if(me.browserEvent){
2800                 if(me.browserEvent.type == 'mousedown'){
2801                     Ext.EventManager.stoppedMouseDownEvent.fire(me);
2802                 }
2803                 E.stopPropagation(me.browserEvent);
2804             }
2805         },
2806
2807         /**
2808          * Gets the character code for the event.
2809          * @return {Number}
2810          */
2811         getCharCode : function(){
2812             return this.charCode || this.keyCode;
2813         },
2814
2815         /**
2816          * Returns a normalized keyCode for the event.
2817          * @return {Number} The key code
2818          */
2819         getKey : function(){
2820             return this.normalizeKey(this.keyCode || this.charCode)
2821         },
2822                 
2823                 // private
2824                 normalizeKey: function(k){
2825                         return Ext.isSafari ? (safariKeys[k] || k) : k; 
2826                 },
2827
2828         /**
2829          * Gets the x coordinate of the event.
2830          * @return {Number}
2831          */
2832         getPageX : function(){
2833             return this.xy[0];
2834         },
2835
2836         /**
2837          * Gets the y coordinate of the event.
2838          * @return {Number}
2839          */
2840         getPageY : function(){
2841             return this.xy[1];
2842         },
2843
2844         /**
2845          * Gets the page coordinates of the event.
2846          * @return {Array} The xy values like [x, y]
2847          */
2848         getXY : function(){
2849             return this.xy;
2850         },
2851
2852         /**
2853          * Gets the target for the event.
2854          * @param {String} selector (optional) A simple selector to filter the target or look for an ancestor of the target
2855          * @param {Number/Mixed} maxDepth (optional) The max depth to
2856                 search as a number or element (defaults to 10 || document.body)
2857          * @param {Boolean} returnEl (optional) True to return a Ext.Element object instead of DOM node
2858          * @return {HTMLelement}
2859          */
2860         getTarget : function(selector, maxDepth, returnEl){
2861             return selector ? Ext.fly(this.target).findParent(selector, maxDepth, returnEl) : (returnEl ? Ext.get(this.target) : this.target);
2862         },
2863
2864         /**
2865          * Gets the related target.
2866          * @return {HTMLElement}
2867          */
2868         getRelatedTarget : function(){
2869             return this.browserEvent ? E.getRelatedTarget(this.browserEvent) : null;
2870         },
2871
2872         /**
2873          * Normalizes mouse wheel delta across browsers
2874          * @return {Number} The delta
2875          */
2876         getWheelDelta : function(){
2877             var e = this.browserEvent;
2878             var delta = 0;
2879             if(e.wheelDelta){ /* IE/Opera. */
2880                 delta = e.wheelDelta/120;
2881             }else if(e.detail){ /* Mozilla case. */
2882                 delta = -e.detail/3;
2883             }
2884             return delta;
2885         },
2886                 
2887                 /**
2888                 * 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.
2889                 * Example usage:<pre><code>
2890                 // Handle click on any child of an element
2891                 Ext.getBody().on('click', function(e){
2892                         if(e.within('some-el')){
2893                                 alert('Clicked on a child of some-el!');
2894                         }
2895                 });
2896                 
2897                 // Handle click directly on an element, ignoring clicks on child nodes
2898                 Ext.getBody().on('click', function(e,t){
2899                         if((t.id == 'some-el') && !e.within(t, true)){
2900                                 alert('Clicked directly on some-el!');
2901                         }
2902                 });
2903                 </code></pre>
2904                  * @param {Mixed} el The id, DOM element or Ext.Element to check
2905                  * @param {Boolean} related (optional) true to test if the related target is within el instead of the target
2906                  * @param {Boolean} allowEl {optional} true to also check if the passed element is the target or related target
2907                  * @return {Boolean}
2908                  */
2909                 within : function(el, related, allowEl){
2910             if(el){
2911                             var t = this[related ? "getRelatedTarget" : "getTarget"]();
2912                             return t && ((allowEl ? (t == Ext.getDom(el)) : false) || Ext.fly(el).contains(t));
2913             }
2914             return false;
2915                 }
2916          };
2917
2918     return new Ext.EventObjectImpl();
2919 }();/**\r
2920  * @class Ext.EventManager\r
2921  */\r
2922 Ext.apply(Ext.EventManager, function(){\r
2923         var resizeEvent, \r
2924         resizeTask, \r
2925         textEvent, \r
2926         textSize,\r
2927         D = Ext.lib.Dom,\r
2928         E = Ext.lib.Event,\r
2929         propRe = /^(?:scope|delay|buffer|single|stopEvent|preventDefault|stopPropagation|normalized|args|delegate)$/,\r
2930         curWidth = 0,\r
2931         curHeight = 0,\r
2932         // note 1: IE fires ONLY the keydown event on specialkey autorepeat\r
2933         // note 2: Safari < 3.1, Gecko (Mac/Linux) & Opera fire only the keypress event on specialkey autorepeat\r
2934         // (research done by @Jan Wolter at http://unixpapa.com/js/key.html)\r
2935         useKeydown = Ext.isSafari ? \r
2936                     Ext.num(navigator.userAgent.toLowerCase().match(/version\/(\d+\.\d)/)[1] || 2) >= 3.1 :\r
2937                     !((Ext.isGecko && !Ext.isWindows) || Ext.isOpera);\r
2938         \r
2939         return { \r
2940                 // private\r
2941             doResizeEvent: function(){\r
2942             var h = D.getViewHeight(),\r
2943                 w = D.getViewWidth();\r
2944             \r
2945             //whacky problem in IE where the resize event will fire even though the w/h are the same.\r
2946             if(curHeight != h || curWidth != w){\r
2947                 resizeEvent.fire(curWidth = w, curHeight = h);\r
2948             }\r
2949             },\r
2950             \r
2951             /**\r
2952              * Fires when the window is resized and provides resize event buffering (50 milliseconds), passes new viewport width and height to handlers.\r
2953              * @param {Function} fn        The method the event invokes\r
2954              * @param {Object}   scope    An object that becomes the scope of the handler\r
2955              * @param {boolean}  options\r
2956              */\r
2957             onWindowResize : function(fn, scope, options){\r
2958                 if(!resizeEvent){\r
2959                     resizeEvent = new Ext.util.Event();\r
2960                     resizeTask = new Ext.util.DelayedTask(this.doResizeEvent);\r
2961                     E.on(window, "resize", this.fireWindowResize, this);\r
2962                 }\r
2963                 resizeEvent.addListener(fn, scope, options);\r
2964             },\r
2965         \r
2966             // exposed only to allow manual firing\r
2967             fireWindowResize : function(){\r
2968                 if(resizeEvent){\r
2969                     if((Ext.isIE||Ext.isAir) && resizeTask){\r
2970                         resizeTask.delay(50);\r
2971                     }else{\r
2972                         resizeEvent.fire(D.getViewWidth(), D.getViewHeight());\r
2973                     }\r
2974                 }\r
2975             },\r
2976         \r
2977             /**\r
2978              * Fires when the user changes the active text size. Handler gets called with 2 params, the old size and the new size.\r
2979              * @param {Function} fn        The method the event invokes\r
2980              * @param {Object}   scope    An object that becomes the scope of the handler\r
2981              * @param {boolean}  options\r
2982              */\r
2983             onTextResize : function(fn, scope, options){\r
2984                 if(!textEvent){\r
2985                     textEvent = new Ext.util.Event();\r
2986                     var textEl = new Ext.Element(document.createElement('div'));\r
2987                     textEl.dom.className = 'x-text-resize';\r
2988                     textEl.dom.innerHTML = 'X';\r
2989                     textEl.appendTo(document.body);\r
2990                     textSize = textEl.dom.offsetHeight;\r
2991                     setInterval(function(){\r
2992                         if(textEl.dom.offsetHeight != textSize){\r
2993                             textEvent.fire(textSize, textSize = textEl.dom.offsetHeight);\r
2994                         }\r
2995                     }, this.textResizeInterval);\r
2996                 }\r
2997                 textEvent.addListener(fn, scope, options);\r
2998             },\r
2999         \r
3000             /**\r
3001              * Removes the passed window resize listener.\r
3002              * @param {Function} fn        The method the event invokes\r
3003              * @param {Object}   scope    The scope of handler\r
3004              */\r
3005             removeResizeListener : function(fn, scope){\r
3006                 if(resizeEvent){\r
3007                     resizeEvent.removeListener(fn, scope);\r
3008                 }\r
3009             },\r
3010         \r
3011             // private\r
3012             fireResize : function(){\r
3013                 if(resizeEvent){\r
3014                     resizeEvent.fire(D.getViewWidth(), D.getViewHeight());\r
3015                 }\r
3016             },\r
3017             \r
3018              /**\r
3019              * The frequency, in milliseconds, to check for text resize events (defaults to 50)\r
3020              */\r
3021             textResizeInterval : 50,\r
3022             \r
3023             /**\r
3024          * Url used for onDocumentReady with using SSL (defaults to Ext.SSL_SECURE_URL)\r
3025          */\r
3026         ieDeferSrc : false,\r
3027         \r
3028         // protected for use inside the framework\r
3029         // detects whether we should use keydown or keypress based on the browser.\r
3030         useKeydown: useKeydown\r
3031     };\r
3032 }());\r
3033 \r
3034 Ext.EventManager.on = Ext.EventManager.addListener;\r
3035 \r
3036 \r
3037 Ext.apply(Ext.EventObjectImpl.prototype, {\r
3038     /** Key constant @type Number */\r
3039     BACKSPACE: 8,\r
3040     /** Key constant @type Number */\r
3041     TAB: 9,\r
3042     /** Key constant @type Number */\r
3043     NUM_CENTER: 12,\r
3044     /** Key constant @type Number */\r
3045     ENTER: 13,\r
3046     /** Key constant @type Number */\r
3047     RETURN: 13,\r
3048     /** Key constant @type Number */\r
3049     SHIFT: 16,\r
3050     /** Key constant @type Number */\r
3051     CTRL: 17,\r
3052     CONTROL : 17, // legacy\r
3053     /** Key constant @type Number */\r
3054     ALT: 18,\r
3055     /** Key constant @type Number */\r
3056     PAUSE: 19,\r
3057     /** Key constant @type Number */\r
3058     CAPS_LOCK: 20,\r
3059     /** Key constant @type Number */\r
3060     ESC: 27,\r
3061     /** Key constant @type Number */\r
3062     SPACE: 32,\r
3063     /** Key constant @type Number */\r
3064     PAGE_UP: 33,\r
3065     PAGEUP : 33, // legacy\r
3066     /** Key constant @type Number */\r
3067     PAGE_DOWN: 34,\r
3068     PAGEDOWN : 34, // legacy\r
3069     /** Key constant @type Number */\r
3070     END: 35,\r
3071     /** Key constant @type Number */\r
3072     HOME: 36,\r
3073     /** Key constant @type Number */\r
3074     LEFT: 37,\r
3075     /** Key constant @type Number */\r
3076     UP: 38,\r
3077     /** Key constant @type Number */\r
3078     RIGHT: 39,\r
3079     /** Key constant @type Number */\r
3080     DOWN: 40,\r
3081     /** Key constant @type Number */\r
3082     PRINT_SCREEN: 44,\r
3083     /** Key constant @type Number */\r
3084     INSERT: 45,\r
3085     /** Key constant @type Number */\r
3086     DELETE: 46,\r
3087     /** Key constant @type Number */\r
3088     ZERO: 48,\r
3089     /** Key constant @type Number */\r
3090     ONE: 49,\r
3091     /** Key constant @type Number */\r
3092     TWO: 50,\r
3093     /** Key constant @type Number */\r
3094     THREE: 51,\r
3095     /** Key constant @type Number */\r
3096     FOUR: 52,\r
3097     /** Key constant @type Number */\r
3098     FIVE: 53,\r
3099     /** Key constant @type Number */\r
3100     SIX: 54,\r
3101     /** Key constant @type Number */\r
3102     SEVEN: 55,\r
3103     /** Key constant @type Number */\r
3104     EIGHT: 56,\r
3105     /** Key constant @type Number */\r
3106     NINE: 57,\r
3107     /** Key constant @type Number */\r
3108     A: 65,\r
3109     /** Key constant @type Number */\r
3110     B: 66,\r
3111     /** Key constant @type Number */\r
3112     C: 67,\r
3113     /** Key constant @type Number */\r
3114     D: 68,\r
3115     /** Key constant @type Number */\r
3116     E: 69,\r
3117     /** Key constant @type Number */\r
3118     F: 70,\r
3119     /** Key constant @type Number */\r
3120     G: 71,\r
3121     /** Key constant @type Number */\r
3122     H: 72,\r
3123     /** Key constant @type Number */\r
3124     I: 73,\r
3125     /** Key constant @type Number */\r
3126     J: 74,\r
3127     /** Key constant @type Number */\r
3128     K: 75,\r
3129     /** Key constant @type Number */\r
3130     L: 76,\r
3131     /** Key constant @type Number */\r
3132     M: 77,\r
3133     /** Key constant @type Number */\r
3134     N: 78,\r
3135     /** Key constant @type Number */\r
3136     O: 79,\r
3137     /** Key constant @type Number */\r
3138     P: 80,\r
3139     /** Key constant @type Number */\r
3140     Q: 81,\r
3141     /** Key constant @type Number */\r
3142     R: 82,\r
3143     /** Key constant @type Number */\r
3144     S: 83,\r
3145     /** Key constant @type Number */\r
3146     T: 84,\r
3147     /** Key constant @type Number */\r
3148     U: 85,\r
3149     /** Key constant @type Number */\r
3150     V: 86,\r
3151     /** Key constant @type Number */\r
3152     W: 87,\r
3153     /** Key constant @type Number */\r
3154     X: 88,\r
3155     /** Key constant @type Number */\r
3156     Y: 89,\r
3157     /** Key constant @type Number */\r
3158     Z: 90,\r
3159     /** Key constant @type Number */\r
3160     CONTEXT_MENU: 93,\r
3161     /** Key constant @type Number */\r
3162     NUM_ZERO: 96,\r
3163     /** Key constant @type Number */\r
3164     NUM_ONE: 97,\r
3165     /** Key constant @type Number */\r
3166     NUM_TWO: 98,\r
3167     /** Key constant @type Number */\r
3168     NUM_THREE: 99,\r
3169     /** Key constant @type Number */\r
3170     NUM_FOUR: 100,\r
3171     /** Key constant @type Number */\r
3172     NUM_FIVE: 101,\r
3173     /** Key constant @type Number */\r
3174     NUM_SIX: 102,\r
3175     /** Key constant @type Number */\r
3176     NUM_SEVEN: 103,\r
3177     /** Key constant @type Number */\r
3178     NUM_EIGHT: 104,\r
3179     /** Key constant @type Number */\r
3180     NUM_NINE: 105,\r
3181     /** Key constant @type Number */\r
3182     NUM_MULTIPLY: 106,\r
3183     /** Key constant @type Number */\r
3184     NUM_PLUS: 107,\r
3185     /** Key constant @type Number */\r
3186     NUM_MINUS: 109,\r
3187     /** Key constant @type Number */\r
3188     NUM_PERIOD: 110,\r
3189     /** Key constant @type Number */\r
3190     NUM_DIVISION: 111,\r
3191     /** Key constant @type Number */\r
3192     F1: 112,\r
3193     /** Key constant @type Number */\r
3194     F2: 113,\r
3195     /** Key constant @type Number */\r
3196     F3: 114,\r
3197     /** Key constant @type Number */\r
3198     F4: 115,\r
3199     /** Key constant @type Number */\r
3200     F5: 116,\r
3201     /** Key constant @type Number */\r
3202     F6: 117,\r
3203     /** Key constant @type Number */\r
3204     F7: 118,\r
3205     /** Key constant @type Number */\r
3206     F8: 119,\r
3207     /** Key constant @type Number */\r
3208     F9: 120,\r
3209     /** Key constant @type Number */\r
3210     F10: 121,\r
3211     /** Key constant @type Number */\r
3212     F11: 122,\r
3213     /** Key constant @type Number */\r
3214     F12: 123,   \r
3215     \r
3216     /** @private */\r
3217     isNavKeyPress : function(){\r
3218         var me = this,\r
3219                 k = this.normalizeKey(me.keyCode);              \r
3220         return (k >= 33 && k <= 40) ||  // Page Up/Down, End, Home, Left, Up, Right, Down\r
3221                 k == me.RETURN ||\r
3222                 k == me.TAB ||\r
3223                 k == me.ESC;\r
3224     },\r
3225 \r
3226     isSpecialKey : function(){\r
3227         var k = this.normalizeKey(this.keyCode);\r
3228         return (this.type == 'keypress' && this.ctrlKey) ||\r
3229                 this.isNavKeyPress() ||\r
3230         (k == this.BACKSPACE) || // Backspace\r
3231                 (k >= 16 && k <= 20) || // Shift, Ctrl, Alt, Pause, Caps Lock\r
3232                 (k >= 44 && k <= 45);   // Print Screen, Insert\r
3233     },\r
3234         \r
3235         getPoint : function(){\r
3236             return new Ext.lib.Point(this.xy[0], this.xy[1]);\r
3237         },\r
3238 \r
3239     /**\r
3240      * Returns true if the control, meta, shift or alt key was pressed during this event.\r
3241      * @return {Boolean}\r
3242      */\r
3243     hasModifier : function(){\r
3244         return ((this.ctrlKey || this.altKey) || this.shiftKey);\r
3245     }\r
3246 });/**\r
3247  * @class Ext.Element\r
3248  * <p>Encapsulates a DOM element, adding simple DOM manipulation facilities, normalizing for browser differences.</p>\r
3249  * <p>All instances of this class inherit the methods of {@link Ext.Fx} making visual effects easily available to all DOM elements.</p>\r
3250  * <p>Note that the events documented in this class are not Ext events, they encapsulate browser events. To\r
3251  * access the underlying browser event, see {@link Ext.EventObject#browserEvent}. Some older\r
3252  * browsers may not support the full range of events. Which events are supported is beyond the control of ExtJs.</p>\r
3253  * Usage:<br>\r
3254 <pre><code>\r
3255 // by id\r
3256 var el = Ext.get("my-div");\r
3257 \r
3258 // by DOM element reference\r
3259 var el = Ext.get(myDivElement);\r
3260 </code></pre>\r
3261  * <b>Animations</b><br />\r
3262  * <p>When an element is manipulated, by default there is no animation.</p>\r
3263  * <pre><code>\r
3264 var el = Ext.get("my-div");\r
3265 \r
3266 // no animation\r
3267 el.setWidth(100);\r
3268  * </code></pre>\r
3269  * <p>Many of the functions for manipulating an element have an optional "animate" parameter.  This\r
3270  * parameter can be specified as boolean (<tt>true</tt>) for default animation effects.</p>\r
3271  * <pre><code>\r
3272 // default animation\r
3273 el.setWidth(100, true);\r
3274  * </code></pre>\r
3275  * \r
3276  * <p>To configure the effects, an object literal with animation options to use as the Element animation\r
3277  * configuration object can also be specified. Note that the supported Element animation configuration\r
3278  * options are a subset of the {@link Ext.Fx} animation options specific to Fx effects.  The supported\r
3279  * Element animation configuration options are:</p>\r
3280 <pre>\r
3281 Option    Default   Description\r
3282 --------- --------  ---------------------------------------------\r
3283 {@link Ext.Fx#duration duration}  .35       The duration of the animation in seconds\r
3284 {@link Ext.Fx#easing easing}    easeOut   The easing method\r
3285 {@link Ext.Fx#callback callback}  none      A function to execute when the anim completes\r
3286 {@link Ext.Fx#scope scope}     this      The scope (this) of the callback function\r
3287 </pre>\r
3288  * \r
3289  * <pre><code>\r
3290 // Element animation options object\r
3291 var opt = {\r
3292     {@link Ext.Fx#duration duration}: 1,\r
3293     {@link Ext.Fx#easing easing}: 'elasticIn',\r
3294     {@link Ext.Fx#callback callback}: this.foo,\r
3295     {@link Ext.Fx#scope scope}: this\r
3296 };\r
3297 // animation with some options set\r
3298 el.setWidth(100, opt);\r
3299  * </code></pre>\r
3300  * <p>The Element animation object being used for the animation will be set on the options\r
3301  * object as "anim", which allows you to stop or manipulate the animation. Here is an example:</p>\r
3302  * <pre><code>\r
3303 // using the "anim" property to get the Anim object\r
3304 if(opt.anim.isAnimated()){\r
3305     opt.anim.stop();\r
3306 }\r
3307  * </code></pre>\r
3308  * <p>Also see the <tt>{@link #animate}</tt> method for another animation technique.</p>\r
3309  * <p><b> Composite (Collections of) Elements</b></p>\r
3310  * <p>For working with collections of Elements, see {@link Ext.CompositeElement}</p>\r
3311  * @constructor Create a new Element directly.\r
3312  * @param {String/HTMLElement} element\r
3313  * @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).\r
3314  */\r
3315 (function(){\r
3316 var DOC = document;\r
3317 \r
3318 Ext.Element = function(element, forceNew){\r
3319     var dom = typeof element == "string" ?\r
3320               DOC.getElementById(element) : element,\r
3321         id;\r
3322 \r
3323     if(!dom) return null;\r
3324 \r
3325     id = dom.id;\r
3326 \r
3327     if(!forceNew && id && Ext.Element.cache[id]){ // element object already exists\r
3328         return Ext.Element.cache[id];\r
3329     }\r
3330 \r
3331     /**\r
3332      * The DOM element\r
3333      * @type HTMLElement\r
3334      */\r
3335     this.dom = dom;\r
3336 \r
3337     /**\r
3338      * The DOM element ID\r
3339      * @type String\r
3340      */\r
3341     this.id = id || Ext.id(dom);\r
3342 };\r
3343 \r
3344 var D = Ext.lib.Dom,\r
3345     DH = Ext.DomHelper,\r
3346     E = Ext.lib.Event,\r
3347     A = Ext.lib.Anim,\r
3348     El = Ext.Element;\r
3349 \r
3350 El.prototype = {\r
3351     /**\r
3352      * Sets the passed attributes as attributes of this element (a style attribute can be a string, object or function)\r
3353      * @param {Object} o The object with the attributes\r
3354      * @param {Boolean} useSet (optional) false to override the default setAttribute to use expandos.\r
3355      * @return {Ext.Element} this\r
3356      */\r
3357     set : function(o, useSet){\r
3358         var el = this.dom,\r
3359             attr,\r
3360             val;        \r
3361        \r
3362         for(attr in o){\r
3363             val = o[attr];\r
3364             if (attr != "style" && !Ext.isFunction(val)) {\r
3365                 if (attr == "cls" ) {\r
3366                     el.className = val;\r
3367                 } else if (o.hasOwnProperty(attr)) {\r
3368                     if (useSet || !!el.setAttribute) el.setAttribute(attr, val);\r
3369                     else el[attr] = val;\r
3370                 }\r
3371             }\r
3372         }\r
3373         if(o.style){\r
3374             Ext.DomHelper.applyStyles(el, o.style);\r
3375         }\r
3376         return this;\r
3377     },\r
3378     \r
3379 //  Mouse events\r
3380     /**\r
3381      * @event click\r
3382      * Fires when a mouse click is detected within the element.\r
3383      * @param {Ext.EventObject} e The {@link Ext.EventObject} encapsulating the DOM event.\r
3384      * @param {HtmlElement} t The target of the event.\r
3385      * @param {Object} o The options configuration passed to the {@link #addListener} call.\r
3386      */\r
3387     /**\r
3388      * @event dblclick\r
3389      * Fires when a mouse double click is detected within the element.\r
3390      * @param {Ext.EventObject} e The {@link Ext.EventObject} encapsulating the DOM event.\r
3391      * @param {HtmlElement} t The target of the event.\r
3392      * @param {Object} o The options configuration passed to the {@link #addListener} call.\r
3393      */\r
3394     /**\r
3395      * @event mousedown\r
3396      * Fires when a mousedown is detected within the element.\r
3397      * @param {Ext.EventObject} e The {@link Ext.EventObject} encapsulating the DOM event.\r
3398      * @param {HtmlElement} t The target of the event.\r
3399      * @param {Object} o The options configuration passed to the {@link #addListener} call.\r
3400      */\r
3401     /**\r
3402      * @event mouseup\r
3403      * Fires when a mouseup is detected within the element.\r
3404      * @param {Ext.EventObject} e The {@link Ext.EventObject} encapsulating the DOM event.\r
3405      * @param {HtmlElement} t The target of the event.\r
3406      * @param {Object} o The options configuration passed to the {@link #addListener} call.\r
3407      */\r
3408     /**\r
3409      * @event mouseover\r
3410      * Fires when a mouseover is detected within the element.\r
3411      * @param {Ext.EventObject} e The {@link Ext.EventObject} encapsulating the DOM event.\r
3412      * @param {HtmlElement} t The target of the event.\r
3413      * @param {Object} o The options configuration passed to the {@link #addListener} call.\r
3414      */\r
3415     /**\r
3416      * @event mousemove\r
3417      * Fires when a mousemove is detected with the element.\r
3418      * @param {Ext.EventObject} e The {@link Ext.EventObject} encapsulating the DOM event.\r
3419      * @param {HtmlElement} t The target of the event.\r
3420      * @param {Object} o The options configuration passed to the {@link #addListener} call.\r
3421      */\r
3422     /**\r
3423      * @event mouseout\r
3424      * Fires when a mouseout is detected with the element.\r
3425      * @param {Ext.EventObject} e The {@link Ext.EventObject} encapsulating the DOM event.\r
3426      * @param {HtmlElement} t The target of the event.\r
3427      * @param {Object} o The options configuration passed to the {@link #addListener} call.\r
3428      */\r
3429     /**\r
3430      * @event mouseenter\r
3431      * Fires when the mouse enters the element.\r
3432      * @param {Ext.EventObject} e The {@link Ext.EventObject} encapsulating the DOM event.\r
3433      * @param {HtmlElement} t The target of the event.\r
3434      * @param {Object} o The options configuration passed to the {@link #addListener} call.\r
3435      */\r
3436     /**\r
3437      * @event mouseleave\r
3438      * Fires when the mouse leaves the element.\r
3439      * @param {Ext.EventObject} e The {@link Ext.EventObject} encapsulating the DOM event.\r
3440      * @param {HtmlElement} t The target of the event.\r
3441      * @param {Object} o The options configuration passed to the {@link #addListener} call.\r
3442      */\r
3443     \r
3444 //  Keyboard events\r
3445     /**\r
3446      * @event keypress\r
3447      * Fires when a keypress is detected within the element.\r
3448      * @param {Ext.EventObject} e The {@link Ext.EventObject} encapsulating the DOM event.\r
3449      * @param {HtmlElement} t The target of the event.\r
3450      * @param {Object} o The options configuration passed to the {@link #addListener} call.\r
3451      */\r
3452     /**\r
3453      * @event keydown\r
3454      * Fires when a keydown is detected within the element.\r
3455      * @param {Ext.EventObject} e The {@link Ext.EventObject} encapsulating the DOM event.\r
3456      * @param {HtmlElement} t The target of the event.\r
3457      * @param {Object} o The options configuration passed to the {@link #addListener} call.\r
3458      */\r
3459     /**\r
3460      * @event keyup\r
3461      * Fires when a keyup is detected within the element.\r
3462      * @param {Ext.EventObject} e The {@link Ext.EventObject} encapsulating the DOM event.\r
3463      * @param {HtmlElement} t The target of the event.\r
3464      * @param {Object} o The options configuration passed to the {@link #addListener} call.\r
3465      */\r
3466 \r
3467 \r
3468 //  HTML frame/object events\r
3469     /**\r
3470      * @event load\r
3471      * Fires when the user agent finishes loading all content within the element. Only supported by window, frames, objects and images.\r
3472      * @param {Ext.EventObject} e The {@link Ext.EventObject} encapsulating the DOM event.\r
3473      * @param {HtmlElement} t The target of the event.\r
3474      * @param {Object} o The options configuration passed to the {@link #addListener} call.\r
3475      */\r
3476     /**\r
3477      * @event unload\r
3478      * 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.\r
3479      * @param {Ext.EventObject} e The {@link Ext.EventObject} encapsulating the DOM event.\r
3480      * @param {HtmlElement} t The target of the event.\r
3481      * @param {Object} o The options configuration passed to the {@link #addListener} call.\r
3482      */\r
3483     /**\r
3484      * @event abort\r
3485      * Fires when an object/image is stopped from loading before completely loaded.\r
3486      * @param {Ext.EventObject} e The {@link Ext.EventObject} encapsulating the DOM event.\r
3487      * @param {HtmlElement} t The target of the event.\r
3488      * @param {Object} o The options configuration passed to the {@link #addListener} call.\r
3489      */\r
3490     /**\r
3491      * @event error\r
3492      * Fires when an object/image/frame cannot be loaded properly.\r
3493      * @param {Ext.EventObject} e The {@link Ext.EventObject} encapsulating the DOM event.\r
3494      * @param {HtmlElement} t The target of the event.\r
3495      * @param {Object} o The options configuration passed to the {@link #addListener} call.\r
3496      */\r
3497     /**\r
3498      * @event resize\r
3499      * Fires when a document view is resized.\r
3500      * @param {Ext.EventObject} e The {@link Ext.EventObject} encapsulating the DOM event.\r
3501      * @param {HtmlElement} t The target of the event.\r
3502      * @param {Object} o The options configuration passed to the {@link #addListener} call.\r
3503      */\r
3504     /**\r
3505      * @event scroll\r
3506      * Fires when a document view is scrolled.\r
3507      * @param {Ext.EventObject} e The {@link Ext.EventObject} encapsulating the DOM event.\r
3508      * @param {HtmlElement} t The target of the event.\r
3509      * @param {Object} o The options configuration passed to the {@link #addListener} call.\r
3510      */\r
3511 \r
3512 //  Form events\r
3513     /**\r
3514      * @event select\r
3515      * Fires when a user selects some text in a text field, including input and textarea.\r
3516      * @param {Ext.EventObject} e The {@link Ext.EventObject} encapsulating the DOM event.\r
3517      * @param {HtmlElement} t The target of the event.\r
3518      * @param {Object} o The options configuration passed to the {@link #addListener} call.\r
3519      */\r
3520     /**\r
3521      * @event change\r
3522      * Fires when a control loses the input focus and its value has been modified since gaining focus.\r
3523      * @param {Ext.EventObject} e The {@link Ext.EventObject} encapsulating the DOM event.\r
3524      * @param {HtmlElement} t The target of the event.\r
3525      * @param {Object} o The options configuration passed to the {@link #addListener} call.\r
3526      */\r
3527     /**\r
3528      * @event submit\r
3529      * Fires when a form is submitted.\r
3530      * @param {Ext.EventObject} e The {@link Ext.EventObject} encapsulating the DOM event.\r
3531      * @param {HtmlElement} t The target of the event.\r
3532      * @param {Object} o The options configuration passed to the {@link #addListener} call.\r
3533      */\r
3534     /**\r
3535      * @event reset\r
3536      * Fires when a form is reset.\r
3537      * @param {Ext.EventObject} e The {@link Ext.EventObject} encapsulating the DOM event.\r
3538      * @param {HtmlElement} t The target of the event.\r
3539      * @param {Object} o The options configuration passed to the {@link #addListener} call.\r
3540      */\r
3541     /**\r
3542      * @event focus\r
3543      * Fires when an element receives focus either via the pointing device or by tab navigation.\r
3544      * @param {Ext.EventObject} e The {@link Ext.EventObject} encapsulating the DOM event.\r
3545      * @param {HtmlElement} t The target of the event.\r
3546      * @param {Object} o The options configuration passed to the {@link #addListener} call.\r
3547      */\r
3548     /**\r
3549      * @event blur\r
3550      * Fires when an element loses focus either via the pointing device or by tabbing navigation.\r
3551      * @param {Ext.EventObject} e The {@link Ext.EventObject} encapsulating the DOM event.\r
3552      * @param {HtmlElement} t The target of the event.\r
3553      * @param {Object} o The options configuration passed to the {@link #addListener} call.\r
3554      */\r
3555 \r
3556 //  User Interface events\r
3557     /**\r
3558      * @event DOMFocusIn\r
3559      * Where supported. Similar to HTML focus event, but can be applied to any focusable element.\r
3560      * @param {Ext.EventObject} e The {@link Ext.EventObject} encapsulating the DOM event.\r
3561      * @param {HtmlElement} t The target of the event.\r
3562      * @param {Object} o The options configuration passed to the {@link #addListener} call.\r
3563      */\r
3564     /**\r
3565      * @event DOMFocusOut\r
3566      * Where supported. Similar to HTML blur event, but can be applied to any focusable element.\r
3567      * @param {Ext.EventObject} e The {@link Ext.EventObject} encapsulating the DOM event.\r
3568      * @param {HtmlElement} t The target of the event.\r
3569      * @param {Object} o The options configuration passed to the {@link #addListener} call.\r
3570      */\r
3571     /**\r
3572      * @event DOMActivate\r
3573      * Where supported. Fires when an element is activated, for instance, through a mouse click or a keypress.\r
3574      * @param {Ext.EventObject} e The {@link Ext.EventObject} encapsulating the DOM event.\r
3575      * @param {HtmlElement} t The target of the event.\r
3576      * @param {Object} o The options configuration passed to the {@link #addListener} call.\r
3577      */\r
3578 \r
3579 //  DOM Mutation events\r
3580     /**\r
3581      * @event DOMSubtreeModified\r
3582      * Where supported. Fires when the subtree is modified.\r
3583      * @param {Ext.EventObject} e The {@link Ext.EventObject} encapsulating the DOM event.\r
3584      * @param {HtmlElement} t The target of the event.\r
3585      * @param {Object} o The options configuration passed to the {@link #addListener} call.\r
3586      */\r
3587     /**\r
3588      * @event DOMNodeInserted\r
3589      * Where supported. Fires when a node has been added as a child of another node.\r
3590      * @param {Ext.EventObject} e The {@link Ext.EventObject} encapsulating the DOM event.\r
3591      * @param {HtmlElement} t The target of the event.\r
3592      * @param {Object} o The options configuration passed to the {@link #addListener} call.\r
3593      */\r
3594     /**\r
3595      * @event DOMNodeRemoved\r
3596      * Where supported. Fires when a descendant node of the element is removed.\r
3597      * @param {Ext.EventObject} e The {@link Ext.EventObject} encapsulating the DOM event.\r
3598      * @param {HtmlElement} t The target of the event.\r
3599      * @param {Object} o The options configuration passed to the {@link #addListener} call.\r
3600      */\r
3601     /**\r
3602      * @event DOMNodeRemovedFromDocument\r
3603      * Where supported. Fires when a node is being removed from a document.\r
3604      * @param {Ext.EventObject} e The {@link Ext.EventObject} encapsulating the DOM event.\r
3605      * @param {HtmlElement} t The target of the event.\r
3606      * @param {Object} o The options configuration passed to the {@link #addListener} call.\r
3607      */\r
3608     /**\r
3609      * @event DOMNodeInsertedIntoDocument\r
3610      * Where supported. Fires when a node is being inserted into a document.\r
3611      * @param {Ext.EventObject} e The {@link Ext.EventObject} encapsulating the DOM event.\r
3612      * @param {HtmlElement} t The target of the event.\r
3613      * @param {Object} o The options configuration passed to the {@link #addListener} call.\r
3614      */\r
3615     /**\r
3616      * @event DOMAttrModified\r
3617      * Where supported. Fires when an attribute has been modified.\r
3618      * @param {Ext.EventObject} e The {@link Ext.EventObject} encapsulating the DOM event.\r
3619      * @param {HtmlElement} t The target of the event.\r
3620      * @param {Object} o The options configuration passed to the {@link #addListener} call.\r
3621      */\r
3622     /**\r
3623      * @event DOMCharacterDataModified\r
3624      * Where supported. Fires when the character data has been modified.\r
3625      * @param {Ext.EventObject} e The {@link Ext.EventObject} encapsulating the DOM event.\r
3626      * @param {HtmlElement} t The target of the event.\r
3627      * @param {Object} o The options configuration passed to the {@link #addListener} call.\r
3628      */\r
3629 \r
3630     /**\r
3631      * The default unit to append to CSS values where a unit isn't provided (defaults to px).\r
3632      * @type String\r
3633      */\r
3634     defaultUnit : "px",\r
3635 \r
3636     /**\r
3637      * Returns true if this element matches the passed simple selector (e.g. div.some-class or span:first-child)\r
3638      * @param {String} selector The simple selector to test\r
3639      * @return {Boolean} True if this element matches the selector, else false\r
3640      */\r
3641     is : function(simpleSelector){\r
3642         return Ext.DomQuery.is(this.dom, simpleSelector);\r
3643     },\r
3644 \r
3645     /**\r
3646      * Tries to focus the element. Any exceptions are caught and ignored.\r
3647      * @param {Number} defer (optional) Milliseconds to defer the focus\r
3648      * @return {Ext.Element} this\r
3649      */\r
3650     focus : function(defer, /* private */ dom) {\r
3651         var me = this,\r
3652             dom = dom || me.dom;\r
3653         try{\r
3654             if(Number(defer)){\r
3655                 me.focus.defer(defer, null, [null, dom]);\r
3656             }else{\r
3657                 dom.focus();\r
3658             }\r
3659         }catch(e){}\r
3660         return me;\r
3661     },\r
3662 \r
3663     /**\r
3664      * Tries to blur the element. Any exceptions are caught and ignored.\r
3665      * @return {Ext.Element} this\r
3666      */\r
3667     blur : function() {\r
3668         try{\r
3669             this.dom.blur();\r
3670         }catch(e){}\r
3671         return this;\r
3672     },\r
3673 \r
3674     /**\r
3675      * Returns the value of the "value" attribute\r
3676      * @param {Boolean} asNumber true to parse the value as a number\r
3677      * @return {String/Number}\r
3678      */\r
3679     getValue : function(asNumber){\r
3680         var val = this.dom.value;\r
3681         return asNumber ? parseInt(val, 10) : val;\r
3682     },\r
3683 \r
3684     /**\r
3685      * Appends an event handler to this element.  The shorthand version {@link #on} is equivalent.\r
3686      * @param {String} eventName The type of event to handle\r
3687      * @param {Function} fn The handler function the event invokes. This function is passed\r
3688      * the following parameters:<ul>\r
3689      * <li><b>evt</b> : EventObject<div class="sub-desc">The {@link Ext.EventObject EventObject} describing the event.</div></li>\r
3690      * <li><b>el</b> : Element<div class="sub-desc">The {@link Ext.Element Element} which was the target of the event.\r
3691      * Note that this may be filtered by using the <tt>delegate</tt> option.</div></li>\r
3692      * <li><b>o</b> : Object<div class="sub-desc">The options object from the addListener call.</div></li>\r
3693      * </ul>\r
3694      * @param {Object} scope (optional) The scope (<code><b>this</b></code> reference) in which the handler function is executed.\r
3695      * <b>If omitted, defaults to this Element.</b>.\r
3696      * @param {Object} options (optional) An object containing handler configuration properties.\r
3697      * This may contain any of the following properties:<ul>\r
3698      * <li><b>scope</b> Object : <div class="sub-desc">The scope (<code><b>this</b></code> reference) in which the handler function is executed.\r
3699      * <b>If omitted, defaults to this Element.</b></div></li>\r
3700      * <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>\r
3701      * <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>\r
3702      * <li><b>preventDefault</b> Boolean: <div class="sub-desc">True to prevent the default action</div></li>\r
3703      * <li><b>stopPropagation</b> Boolean: <div class="sub-desc">True to prevent event propagation</div></li>\r
3704      * <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>\r
3705      * <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>\r
3706      * <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>\r
3707      * <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>\r
3708      * <li><b>buffer</b> Number: <div class="sub-desc">Causes the handler to be scheduled to run in an {@link Ext.util.DelayedTask} delayed\r
3709      * by the specified number of milliseconds. If the event fires again within that time, the original\r
3710      * handler is <em>not</em> invoked, but the new handler is scheduled in its place.</div></li>\r
3711      * </ul><br>\r
3712      * <p>\r
3713      * <b>Combining Options</b><br>\r
3714      * In the following examples, the shorthand form {@link #on} is used rather than the more verbose\r
3715      * addListener.  The two are equivalent.  Using the options argument, it is possible to combine different\r
3716      * types of listeners:<br>\r
3717      * <br>\r
3718      * A delayed, one-time listener that auto stops the event and adds a custom argument (forumId) to the\r
3719      * options object. The options object is available as the third parameter in the handler function.<div style="margin: 5px 20px 20px;">\r
3720      * Code:<pre><code>\r
3721 el.on('click', this.onClick, this, {\r
3722     single: true,\r
3723     delay: 100,\r
3724     stopEvent : true,\r
3725     forumId: 4\r
3726 });</code></pre></p>\r
3727      * <p>\r
3728      * <b>Attaching multiple handlers in 1 call</b><br>\r
3729      * The method also allows for a single argument to be passed which is a config object containing properties\r
3730      * which specify multiple handlers.</p>\r
3731      * <p>\r
3732      * Code:<pre><code>\r
3733 el.on({\r
3734     'click' : {\r
3735         fn: this.onClick,\r
3736         scope: this,\r
3737         delay: 100\r
3738     },\r
3739     'mouseover' : {\r
3740         fn: this.onMouseOver,\r
3741         scope: this\r
3742     },\r
3743     'mouseout' : {\r
3744         fn: this.onMouseOut,\r
3745         scope: this\r
3746     }\r
3747 });</code></pre>\r
3748      * <p>\r
3749      * Or a shorthand syntax:<br>\r
3750      * Code:<pre><code></p>\r
3751 el.on({\r
3752     'click' : this.onClick,\r
3753     'mouseover' : this.onMouseOver,\r
3754     'mouseout' : this.onMouseOut,\r
3755     scope: this\r
3756 });\r
3757      * </code></pre></p>\r
3758      * <p><b>delegate</b></p>\r
3759      * <p>This is a configuration option that you can pass along when registering a handler for\r
3760      * an event to assist with event delegation. Event delegation is a technique that is used to\r
3761      * reduce memory consumption and prevent exposure to memory-leaks. By registering an event\r
3762      * for a container element as opposed to each element within a container. By setting this\r
3763      * configuration option to a simple selector, the target element will be filtered to look for\r
3764      * a descendant of the target.\r
3765      * For example:<pre><code>\r
3766 // using this markup:\r
3767 &lt;div id='elId'>\r
3768     &lt;p id='p1'>paragraph one&lt;/p>\r
3769     &lt;p id='p2' class='clickable'>paragraph two&lt;/p>\r
3770     &lt;p id='p3'>paragraph three&lt;/p>\r
3771 &lt;/div>\r
3772 // utilize event delegation to registering just one handler on the container element: \r
3773 el = Ext.get('elId');\r
3774 el.on(\r
3775     'click',\r
3776     function(e,t) {\r
3777         // handle click\r
3778         console.info(t.id); // 'p2'\r
3779     },\r
3780     this,\r
3781     {\r
3782         // filter the target element to be a descendant with the class 'clickable'\r
3783         delegate: '.clickable' \r
3784     }\r
3785 );\r
3786      * </code></pre></p>\r
3787      * @return {Ext.Element} this\r
3788      */\r
3789     addListener : function(eventName, fn, scope, options){\r
3790         Ext.EventManager.on(this.dom,  eventName, fn, scope || this, options);\r
3791         return this;\r
3792     },\r
3793 \r
3794     /**\r
3795      * Removes an event handler from this element.  The shorthand version {@link #un} is equivalent.\r
3796      * <b>Note</b>: if a <i>scope</i> was explicitly specified when {@link #addListener adding} the\r
3797      * listener, the same scope must be specified here.\r
3798      * Example:\r
3799      * <pre><code>\r
3800 el.removeListener('click', this.handlerFn);\r
3801 // or\r
3802 el.un('click', this.handlerFn);\r
3803 </code></pre>\r
3804      * @param {String} eventName the type of event to remove\r
3805      * @param {Function} fn the method the event invokes\r
3806      * @param {Object} scope (optional) The scope (The <tt>this</tt> reference) of the handler function. Defaults\r
3807      * to this Element.\r
3808      * @return {Ext.Element} this\r
3809      */\r
3810     removeListener : function(eventName, fn, scope){\r
3811         Ext.EventManager.removeListener(this.dom,  eventName, fn, scope || this);\r
3812         return this;\r
3813     },\r
3814 \r
3815     /**\r
3816      * Removes all previous added listeners from this element\r
3817      * @return {Ext.Element} this\r
3818      */\r
3819     removeAllListeners : function(){\r
3820         Ext.EventManager.removeAll(this.dom);\r
3821         return this;\r
3822     },\r
3823 \r
3824     /**\r
3825      * @private Test if size has a unit, otherwise appends the default\r
3826      */\r
3827     addUnits : function(size){\r
3828         if(size === "" || size == "auto" || size === undefined){\r
3829             size = size || '';\r
3830         } else if(!isNaN(size) || !unitPattern.test(size)){\r
3831             size = size + (this.defaultUnit || 'px');\r
3832         }\r
3833         return size;\r
3834     },\r
3835 \r
3836     /**\r
3837      * <p>Updates the <a href="http://developer.mozilla.org/en/DOM/element.innerHTML">innerHTML</a> of this Element\r
3838      * 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>\r
3839      * <p>Updating innerHTML of an element will <b>not</b> execute embedded <tt>&lt;script></tt> elements. This is a browser restriction.</p>\r
3840      * @param {Mixed} options. Either a sring containing the URL from which to load the HTML, or an {@link Ext.Ajax#request} options object specifying\r
3841      * exactly how to request the HTML.\r
3842      * @return {Ext.Element} this\r
3843      */\r
3844     load : function(url, params, cb){\r
3845         Ext.Ajax.request(Ext.apply({\r
3846             params: params,\r
3847             url: url.url || url,\r
3848             callback: cb,\r
3849             el: this.dom,\r
3850             indicatorText: url.indicatorText || ''\r
3851         }, Ext.isObject(url) ? url : {}));\r
3852         return this;\r
3853     },\r
3854 \r
3855     /**\r
3856      * Tests various css rules/browsers to determine if this element uses a border box\r
3857      * @return {Boolean}\r
3858      */\r
3859     isBorderBox : function(){\r
3860         return noBoxAdjust[(this.dom.tagName || "").toLowerCase()] || Ext.isBorderBox;\r
3861     },\r
3862 \r
3863     /**\r
3864      * Removes this element from the DOM and deletes it from the cache\r
3865      */\r
3866     remove : function(){\r
3867         var me = this,\r
3868             dom = me.dom;\r
3869         \r
3870         me.removeAllListeners();\r
3871         delete El.cache[dom.id];\r
3872         delete El.dataCache[dom.id]\r
3873         Ext.removeNode(dom);\r
3874     },\r
3875 \r
3876     /**\r
3877      * Sets up event handlers to call the passed functions when the mouse is moved into and out of the Element.\r
3878      * @param {Function} overFn The function to call when the mouse enters the Element.\r
3879      * @param {Function} outFn The function to call when the mouse leaves the Element.\r
3880      * @param {Object} scope (optional) The scope (<tt>this</tt> reference) in which the functions are executed. Defaults to the Element's DOM element.\r
3881      * @param {Object} options (optional) Options for the listener. See {@link Ext.util.Observable#addListener the <tt>options</tt> parameter}.\r
3882      * @return {Ext.Element} this\r
3883      */\r
3884     hover : function(overFn, outFn, scope, options){\r
3885         var me = this;\r
3886         me.on('mouseenter', overFn, scope || me.dom, options);\r
3887         me.on('mouseleave', outFn, scope || me.dom, options);\r
3888         return me;\r
3889     },\r
3890 \r
3891     /**\r
3892      * Returns true if this element is an ancestor of the passed element\r
3893      * @param {HTMLElement/String} el The element to check\r
3894      * @return {Boolean} True if this element is an ancestor of el, else false\r
3895      */\r
3896     contains : function(el){\r
3897         return !el ? false : Ext.lib.Dom.isAncestor(this.dom, el.dom ? el.dom : el);\r
3898     },\r
3899 \r
3900     /**\r
3901      * Returns the value of a namespaced attribute from the element's underlying DOM node.\r
3902      * @param {String} namespace The namespace in which to look for the attribute\r
3903      * @param {String} name The attribute name\r
3904      * @return {String} The attribute value\r
3905      * @deprecated\r
3906      */\r
3907     getAttributeNS : function(ns, name){\r
3908         return this.getAttribute(name, ns); \r
3909     },\r
3910     \r
3911     /**\r
3912      * Returns the value of an attribute from the element's underlying DOM node.\r
3913      * @param {String} name The attribute name\r
3914      * @param {String} namespace (optional) The namespace in which to look for the attribute\r
3915      * @return {String} The attribute value\r
3916      */\r
3917     getAttribute : Ext.isIE ? function(name, ns){\r
3918         var d = this.dom,\r
3919             type = typeof d[ns + ":" + name];\r
3920 \r
3921         if(['undefined', 'unknown'].indexOf(type) == -1){\r
3922             return d[ns + ":" + name];\r
3923         }\r
3924         return d[name];\r
3925     } : function(name, ns){\r
3926         var d = this.dom;\r
3927         return d.getAttributeNS(ns, name) || d.getAttribute(ns + ":" + name) || d.getAttribute(name) || d[name];\r
3928     },\r
3929     \r
3930     /**\r
3931     * Update the innerHTML of this element\r
3932     * @param {String} html The new HTML\r
3933     * @return {Ext.Element} this\r
3934      */\r
3935     update : function(html) {\r
3936         this.dom.innerHTML = html;\r
3937         return this;\r
3938     }\r
3939 };\r
3940 \r
3941 var ep = El.prototype;\r
3942 \r
3943 El.addMethods = function(o){\r
3944    Ext.apply(ep, o);\r
3945 };\r
3946 \r
3947 /**\r
3948  * Appends an event handler (shorthand for {@link #addListener}).\r
3949  * @param {String} eventName The type of event to handle\r
3950  * @param {Function} fn The handler function the event invokes\r
3951  * @param {Object} scope (optional) The scope (this element) of the handler function\r
3952  * @param {Object} options (optional) An object containing standard {@link #addListener} options\r
3953  * @member Ext.Element\r
3954  * @method on\r
3955  */\r
3956 ep.on = ep.addListener;\r
3957 \r
3958 /**\r
3959  * Removes an event handler from this element (see {@link #removeListener} for additional notes).\r
3960  * @param {String} eventName the type of event to remove\r
3961  * @param {Function} fn the method the event invokes\r
3962  * @param {Object} scope (optional) The scope (The <tt>this</tt> reference) of the handler function. Defaults\r
3963  * to this Element.\r
3964  * @return {Ext.Element} this\r
3965  * @member Ext.Element\r
3966  * @method un\r
3967  */\r
3968 ep.un = ep.removeListener;\r
3969 \r
3970 /**\r
3971  * true to automatically adjust width and height settings for box-model issues (default to true)\r
3972  */\r
3973 ep.autoBoxAdjust = true;\r
3974 \r
3975 // private\r
3976 var unitPattern = /\d+(px|em|%|en|ex|pt|in|cm|mm|pc)$/i,\r
3977     docEl;\r
3978 \r
3979 /**\r
3980  * @private\r
3981  */\r
3982 El.cache = {};\r
3983 El.dataCache = {};\r
3984 \r
3985 /**\r
3986  * Retrieves Ext.Element objects.\r
3987  * <p><b>This method does not retrieve {@link Ext.Component Component}s.</b> This method\r
3988  * retrieves Ext.Element objects which encapsulate DOM elements. To retrieve a Component by\r
3989  * its ID, use {@link Ext.ComponentMgr#get}.</p>\r
3990  * <p>Uses simple caching to consistently return the same object. Automatically fixes if an\r
3991  * object was recreated with the same id via AJAX or DOM.</p>\r
3992  * @param {Mixed} el The id of the node, a DOM Node or an existing Element.\r
3993  * @return {Element} The Element object (or null if no matching element was found)\r
3994  * @static\r
3995  * @member Ext.Element\r
3996  * @method get\r
3997  */\r
3998 El.get = function(el){\r
3999     var ex,\r
4000         elm,\r
4001         id;\r
4002     if(!el){ return null; }\r
4003     if (typeof el == "string") { // element id\r
4004         if (!(elm = DOC.getElementById(el))) {\r
4005             return null;\r
4006         }\r
4007         if (ex = El.cache[el]) {\r
4008             ex.dom = elm;\r
4009         } else {\r
4010             ex = El.cache[el] = new El(elm);\r
4011         }\r
4012         return ex;\r
4013     } else if (el.tagName) { // dom element\r
4014         if(!(id = el.id)){\r
4015             id = Ext.id(el);\r
4016         }\r
4017         if(ex = El.cache[id]){\r
4018             ex.dom = el;\r
4019         }else{\r
4020             ex = El.cache[id] = new El(el);\r
4021         }\r
4022         return ex;\r
4023     } else if (el instanceof El) {\r
4024         if(el != docEl){\r
4025             el.dom = DOC.getElementById(el.id) || el.dom; // refresh dom element in case no longer valid,\r
4026                                                           // catch case where it hasn't been appended\r
4027             El.cache[el.id] = el; // in case it was created directly with Element(), let's cache it\r
4028         }\r
4029         return el;\r
4030     } else if(el.isComposite) {\r
4031         return el;\r
4032     } else if(Ext.isArray(el)) {\r
4033         return El.select(el);\r
4034     } else if(el == DOC) {\r
4035         // create a bogus element object representing the document object\r
4036         if(!docEl){\r
4037             var f = function(){};\r
4038             f.prototype = El.prototype;\r
4039             docEl = new f();\r
4040             docEl.dom = DOC;\r
4041         }\r
4042         return docEl;\r
4043     }\r
4044     return null;\r
4045 };\r
4046 \r
4047 // private method for getting and setting element data\r
4048 El.data = function(el, key, value){\r
4049     var c = El.dataCache[el.id];\r
4050     if(!c){\r
4051         c = El.dataCache[el.id] = {};\r
4052     }\r
4053     if(arguments.length == 2){\r
4054         return c[key];    \r
4055     }else{\r
4056         c[key] = value;\r
4057     }\r
4058 };\r
4059 \r
4060 // private\r
4061 // Garbage collection - uncache elements/purge listeners on orphaned elements\r
4062 // so we don't hold a reference and cause the browser to retain them\r
4063 function garbageCollect(){\r
4064     if(!Ext.enableGarbageCollector){\r
4065         clearInterval(El.collectorThread);\r
4066     } else {\r
4067         var eid,\r
4068             el,\r
4069             d;\r
4070 \r
4071         for(eid in El.cache){\r
4072             el = El.cache[eid];\r
4073             d = el.dom;\r
4074             // -------------------------------------------------------\r
4075             // Determining what is garbage:\r
4076             // -------------------------------------------------------\r
4077             // !d\r
4078             // dom node is null, definitely garbage\r
4079             // -------------------------------------------------------\r
4080             // !d.parentNode\r
4081             // no parentNode == direct orphan, definitely garbage\r
4082             // -------------------------------------------------------\r
4083             // !d.offsetParent && !document.getElementById(eid)\r
4084             // display none elements have no offsetParent so we will\r
4085             // also try to look it up by it's id. However, check\r
4086             // offsetParent first so we don't do unneeded lookups.\r
4087             // This enables collection of elements that are not orphans\r
4088             // directly, but somewhere up the line they have an orphan\r
4089             // parent.\r
4090             // -------------------------------------------------------\r
4091             if(!d || !d.parentNode || (!d.offsetParent && !DOC.getElementById(eid))){\r
4092                 delete El.cache[eid];\r
4093                 if(d && Ext.enableListenerCollection){\r
4094                     Ext.EventManager.removeAll(d);\r
4095                 }\r
4096             }\r
4097         }\r
4098     }\r
4099 }\r
4100 El.collectorThreadId = setInterval(garbageCollect, 30000);\r
4101 \r
4102 var flyFn = function(){};\r
4103 flyFn.prototype = El.prototype;\r
4104 \r
4105 // dom is optional\r
4106 El.Flyweight = function(dom){\r
4107     this.dom = dom;\r
4108 };\r
4109 \r
4110 El.Flyweight.prototype = new flyFn();\r
4111 El.Flyweight.prototype.isFlyweight = true;\r
4112 El._flyweights = {};\r
4113 \r
4114 /**\r
4115  * <p>Gets the globally shared flyweight Element, with the passed node as the active element. Do not store a reference to this element -\r
4116  * the dom node can be overwritten by other code. Shorthand of {@link Ext.Element#fly}</p>\r
4117  * <p>Use this to make one-time references to DOM elements which are not going to be accessed again either by\r
4118  * application code, or by Ext's classes. If accessing an element which will be processed regularly, then {@link Ext#get}\r
4119  * will be more appropriate to take advantage of the caching provided by the Ext.Element class.</p>\r
4120  * @param {String/HTMLElement} el The dom node or id\r
4121  * @param {String} named (optional) Allows for creation of named reusable flyweights to prevent conflicts\r
4122  * (e.g. internally Ext uses "_global")\r
4123  * @return {Element} The shared Element object (or null if no matching element was found)\r
4124  * @member Ext.Element\r
4125  * @method fly\r
4126  */\r
4127 El.fly = function(el, named){\r
4128     var ret = null;\r
4129     named = named || '_global';\r
4130 \r
4131     if (el = Ext.getDom(el)) {\r
4132         (El._flyweights[named] = El._flyweights[named] || new El.Flyweight()).dom = el;\r
4133         ret = El._flyweights[named];\r
4134     }\r
4135     return ret;\r
4136 };\r
4137 \r
4138 /**\r
4139  * Retrieves Ext.Element objects.\r
4140  * <p><b>This method does not retrieve {@link Ext.Component Component}s.</b> This method\r
4141  * retrieves Ext.Element objects which encapsulate DOM elements. To retrieve a Component by\r
4142  * its ID, use {@link Ext.ComponentMgr#get}.</p>\r
4143  * <p>Uses simple caching to consistently return the same object. Automatically fixes if an\r
4144  * object was recreated with the same id via AJAX or DOM.</p>\r
4145  * Shorthand of {@link Ext.Element#get}\r
4146  * @param {Mixed} el The id of the node, a DOM Node or an existing Element.\r
4147  * @return {Element} The Element object (or null if no matching element was found)\r
4148  * @member Ext\r
4149  * @method get\r
4150  */\r
4151 Ext.get = El.get;\r
4152 \r
4153 /**\r
4154  * <p>Gets the globally shared flyweight Element, with the passed node as the active element. Do not store a reference to this element -\r
4155  * the dom node can be overwritten by other code. Shorthand of {@link Ext.Element#fly}</p>\r
4156  * <p>Use this to make one-time references to DOM elements which are not going to be accessed again either by\r
4157  * application code, or by Ext's classes. If accessing an element which will be processed regularly, then {@link Ext#get}\r
4158  * will be more appropriate to take advantage of the caching provided by the Ext.Element class.</p>\r
4159  * @param {String/HTMLElement} el The dom node or id\r
4160  * @param {String} named (optional) Allows for creation of named reusable flyweights to prevent conflicts\r
4161  * (e.g. internally Ext uses "_global")\r
4162  * @return {Element} The shared Element object (or null if no matching element was found)\r
4163  * @member Ext\r
4164  * @method fly\r
4165  */\r
4166 Ext.fly = El.fly;\r
4167 \r
4168 // speedy lookup for elements never to box adjust\r
4169 var noBoxAdjust = Ext.isStrict ? {\r
4170     select:1\r
4171 } : {\r
4172     input:1, select:1, textarea:1\r
4173 };\r
4174 if(Ext.isIE || Ext.isGecko){\r
4175     noBoxAdjust['button'] = 1;\r
4176 }\r
4177 \r
4178 \r
4179 Ext.EventManager.on(window, 'unload', function(){\r
4180     delete El.cache;\r
4181     delete El.dataCache;\r
4182     delete El._flyweights;\r
4183 });\r
4184 })();\r
4185 /**\r
4186  * @class Ext.Element\r
4187  */\r
4188 Ext.Element.addMethods({    \r
4189     /**\r
4190      * Stops the specified event(s) from bubbling and optionally prevents the default action\r
4191      * @param {String/Array} eventName an event / array of events to stop from bubbling\r
4192      * @param {Boolean} preventDefault (optional) true to prevent the default action too\r
4193      * @return {Ext.Element} this\r
4194      */\r
4195     swallowEvent : function(eventName, preventDefault){\r
4196             var me = this;\r
4197         function fn(e){\r
4198             e.stopPropagation();\r
4199             if(preventDefault){\r
4200                 e.preventDefault();\r
4201             }\r
4202         }\r
4203         if(Ext.isArray(eventName)){            \r
4204                 Ext.each(eventName, function(e) {\r
4205                  me.on(e, fn);\r
4206             });\r
4207             return me;\r
4208         }\r
4209         me.on(eventName, fn);\r
4210         return me;\r
4211     },\r
4212     \r
4213     /**\r
4214      * Create an event handler on this element such that when the event fires and is handled by this element,\r
4215      * it will be relayed to another object (i.e., fired again as if it originated from that object instead).\r
4216      * @param {String} eventName The type of event to relay\r
4217      * @param {Object} object Any object that extends {@link Ext.util.Observable} that will provide the context\r
4218      * for firing the relayed event\r
4219      */\r
4220     relayEvent : function(eventName, observable){\r
4221         this.on(eventName, function(e){\r
4222             observable.fireEvent(eventName, e);\r
4223         });\r
4224     },\r
4225     \r
4226         /**\r
4227      * Removes worthless text nodes\r
4228      * @param {Boolean} forceReclean (optional) By default the element\r
4229      * keeps track if it has been cleaned already so\r
4230      * you can call this over and over. However, if you update the element and\r
4231      * need to force a reclean, you can pass true.\r
4232      */\r
4233     clean : function(forceReclean){\r
4234         var me = this, \r
4235             dom = me.dom,\r
4236                 n = dom.firstChild, \r
4237                 ni = -1;\r
4238                 \r
4239             if(Ext.Element.data(dom, 'isCleaned') && forceReclean !== true){\r
4240             return me;\r
4241         }      \r
4242                 \r
4243             while(n){\r
4244                 var nx = n.nextSibling;\r
4245             if(n.nodeType == 3 && !/\S/.test(n.nodeValue)){\r
4246                 dom.removeChild(n);\r
4247             }else{\r
4248                 n.nodeIndex = ++ni;\r
4249             }\r
4250                 n = nx;\r
4251             }\r
4252         Ext.Element.data(dom, 'isCleaned', true);\r
4253             return me;\r
4254         },\r
4255     \r
4256     /**\r
4257      * Direct access to the Updater {@link Ext.Updater#update} method. The method takes the same object\r
4258      * parameter as {@link Ext.Updater#update}\r
4259      * @return {Ext.Element} this\r
4260      */\r
4261     load : function(){\r
4262         var um = this.getUpdater();\r
4263         um.update.apply(um, arguments);\r
4264         return this;\r
4265     },\r
4266 \r
4267     /**\r
4268     * Gets this element's {@link Ext.Updater Updater}\r
4269     * @return {Ext.Updater} The Updater\r
4270     */\r
4271     getUpdater : function(){\r
4272         return this.updateManager || (this.updateManager = new Ext.Updater(this));\r
4273     },\r
4274     \r
4275         /**\r
4276     * Update the innerHTML of this element, optionally searching for and processing scripts\r
4277     * @param {String} html The new HTML\r
4278     * @param {Boolean} loadScripts (optional) True to look for and process scripts (defaults to false)\r
4279     * @param {Function} callback (optional) For async script loading you can be notified when the update completes\r
4280     * @return {Ext.Element} this\r
4281      */\r
4282     update : function(html, loadScripts, callback){\r
4283         html = html || "";\r
4284             \r
4285         if(loadScripts !== true){\r
4286             this.dom.innerHTML = html;\r
4287             if(Ext.isFunction(callback)){\r
4288                 callback();\r
4289             }\r
4290             return this;\r
4291         }\r
4292         \r
4293         var id = Ext.id(),\r
4294                 dom = this.dom;\r
4295 \r
4296         html += '<span id="' + id + '"></span>';\r
4297 \r
4298         Ext.lib.Event.onAvailable(id, function(){\r
4299             var DOC = document,\r
4300                 hd = DOC.getElementsByTagName("head")[0],\r
4301                 re = /(?:<script([^>]*)?>)((\n|\r|.)*?)(?:<\/script>)/ig,\r
4302                 srcRe = /\ssrc=([\'\"])(.*?)\1/i,\r
4303                 typeRe = /\stype=([\'\"])(.*?)\1/i,\r
4304                 match,\r
4305                 attrs,\r
4306                 srcMatch,\r
4307                 typeMatch,\r
4308                 el,\r
4309                 s;\r
4310 \r
4311             while((match = re.exec(html))){\r
4312                 attrs = match[1];\r
4313                 srcMatch = attrs ? attrs.match(srcRe) : false;\r
4314                 if(srcMatch && srcMatch[2]){\r
4315                    s = DOC.createElement("script");\r
4316                    s.src = srcMatch[2];\r
4317                    typeMatch = attrs.match(typeRe);\r
4318                    if(typeMatch && typeMatch[2]){\r
4319                        s.type = typeMatch[2];\r
4320                    }\r
4321                    hd.appendChild(s);\r
4322                 }else if(match[2] && match[2].length > 0){\r
4323                     if(window.execScript) {\r
4324                        window.execScript(match[2]);\r
4325                     } else {\r
4326                        window.eval(match[2]);\r
4327                     }\r
4328                 }\r
4329             }\r
4330             el = DOC.getElementById(id);\r
4331             if(el){Ext.removeNode(el);}\r
4332             if(Ext.isFunction(callback)){\r
4333                 callback();\r
4334             }\r
4335         });\r
4336         dom.innerHTML = html.replace(/(?:<script.*?>)((\n|\r|.)*?)(?:<\/script>)/ig, "");\r
4337         return this;\r
4338     },\r
4339     \r
4340     /**\r
4341      * Creates a proxy element of this element\r
4342      * @param {String/Object} config The class name of the proxy element or a DomHelper config object\r
4343      * @param {String/HTMLElement} renderTo (optional) The element or element id to render the proxy to (defaults to document.body)\r
4344      * @param {Boolean} matchBox (optional) True to align and size the proxy to this element now (defaults to false)\r
4345      * @return {Ext.Element} The new proxy element\r
4346      */\r
4347     createProxy : function(config, renderTo, matchBox){\r
4348         config = Ext.isObject(config) ? config : {tag : "div", cls: config};\r
4349 \r
4350         var me = this,\r
4351                 proxy = renderTo ? Ext.DomHelper.append(renderTo, config, true) :\r
4352                                                    Ext.DomHelper.insertBefore(me.dom, config, true);        \r
4353         \r
4354         if(matchBox && me.setBox && me.getBox){ // check to make sure Element.position.js is loaded\r
4355            proxy.setBox(me.getBox());\r
4356         }\r
4357         return proxy;\r
4358     }\r
4359 });\r
4360 \r
4361 Ext.Element.prototype.getUpdateManager = Ext.Element.prototype.getUpdater;\r
4362 \r
4363 // private\r
4364 Ext.Element.uncache = function(el){\r
4365     for(var i = 0, a = arguments, len = a.length; i < len; i++) {\r
4366         if(a[i]){\r
4367             delete Ext.Element.cache[a[i].id || a[i]];\r
4368         }\r
4369     }\r
4370 };/**\r
4371  * @class Ext.Element\r
4372  */\r
4373 Ext.Element.addMethods({\r
4374     /**\r
4375      * Gets the x,y coordinates specified by the anchor position on the element.\r
4376      * @param {String} anchor (optional) The specified anchor position (defaults to "c").  See {@link #alignTo}\r
4377      * for details on supported anchor positions.\r
4378      * @param {Boolean} local (optional) True to get the local (element top/left-relative) anchor position instead\r
4379      * of page coordinates\r
4380      * @param {Object} size (optional) An object containing the size to use for calculating anchor position\r
4381      * {width: (target width), height: (target height)} (defaults to the element's current size)\r
4382      * @return {Array} [x, y] An array containing the element's x and y coordinates\r
4383      */\r
4384     getAnchorXY : function(anchor, local, s){\r
4385         //Passing a different size is useful for pre-calculating anchors,\r
4386         //especially for anchored animations that change the el size.\r
4387                 anchor = (anchor || "tl").toLowerCase();\r
4388         s = s || {};\r
4389         \r
4390         var me = this,        \r
4391                 vp = me.dom == document.body || me.dom == document,\r
4392                 w = s.width || vp ? Ext.lib.Dom.getViewWidth() : me.getWidth(),\r
4393                 h = s.height || vp ? Ext.lib.Dom.getViewHeight() : me.getHeight(),                              \r
4394                 xy,             \r
4395                 r = Math.round,\r
4396                 o = me.getXY(),\r
4397                 scroll = me.getScroll(),\r
4398                 extraX = vp ? scroll.left : !local ? o[0] : 0,\r
4399                 extraY = vp ? scroll.top : !local ? o[1] : 0,\r
4400                 hash = {\r
4401                         c  : [r(w * 0.5), r(h * 0.5)],\r
4402                         t  : [r(w * 0.5), 0],\r
4403                         l  : [0, r(h * 0.5)],\r
4404                         r  : [w, r(h * 0.5)],\r
4405                         b  : [r(w * 0.5), h],\r
4406                         tl : [0, 0],    \r
4407                         bl : [0, h],\r
4408                         br : [w, h],\r
4409                         tr : [w, 0]\r
4410                 };\r
4411         \r
4412         xy = hash[anchor];      \r
4413         return [xy[0] + extraX, xy[1] + extraY]; \r
4414     },\r
4415 \r
4416     /**\r
4417      * Anchors an element to another element and realigns it when the window is resized.\r
4418      * @param {Mixed} element The element to align to.\r
4419      * @param {String} position The position to align to.\r
4420      * @param {Array} offsets (optional) Offset the positioning by [x, y]\r
4421      * @param {Boolean/Object} animate (optional) True for the default animation or a standard Element animation config object\r
4422      * @param {Boolean/Number} monitorScroll (optional) True to monitor body scroll and reposition. If this parameter\r
4423      * is a number, it is used as the buffer delay (defaults to 50ms).\r
4424      * @param {Function} callback The function to call after the animation finishes\r
4425      * @return {Ext.Element} this\r
4426      */\r
4427     anchorTo : function(el, alignment, offsets, animate, monitorScroll, callback){        \r
4428             var me = this,\r
4429             dom = me.dom;\r
4430             \r
4431             function action(){\r
4432             Ext.fly(dom).alignTo(el, alignment, offsets, animate);\r
4433             Ext.callback(callback, Ext.fly(dom));\r
4434         }\r
4435         \r
4436         Ext.EventManager.onWindowResize(action, me);\r
4437         \r
4438         if(!Ext.isEmpty(monitorScroll)){\r
4439             Ext.EventManager.on(window, 'scroll', action, me,\r
4440                 {buffer: !isNaN(monitorScroll) ? monitorScroll : 50});\r
4441         }\r
4442         action.call(me); // align immediately\r
4443         return me;\r
4444     },\r
4445 \r
4446     /**\r
4447      * Gets the x,y coordinates to align this element with another element. See {@link #alignTo} for more info on the\r
4448      * supported position values.\r
4449      * @param {Mixed} element The element to align to.\r
4450      * @param {String} position The position to align to.\r
4451      * @param {Array} offsets (optional) Offset the positioning by [x, y]\r
4452      * @return {Array} [x, y]\r
4453      */\r
4454     getAlignToXY : function(el, p, o){      \r
4455         el = Ext.get(el);\r
4456         \r
4457         if(!el || !el.dom){\r
4458             throw "Element.alignToXY with an element that doesn't exist";\r
4459         }\r
4460         \r
4461         o = o || [0,0];\r
4462         p = (p == "?" ? "tl-bl?" : (!/-/.test(p) && p !== "" ? "tl-" + p : p || "tl-bl")).toLowerCase();       \r
4463                 \r
4464         var me = this,\r
4465                 d = me.dom,\r
4466                 a1,\r
4467                 a2,\r
4468                 x,\r
4469                 y,\r
4470                 //constrain the aligned el to viewport if necessary\r
4471                 w,\r
4472                 h,\r
4473                 r,\r
4474                 dw = Ext.lib.Dom.getViewWidth() -10, // 10px of margin for ie\r
4475                 dh = Ext.lib.Dom.getViewHeight()-10, // 10px of margin for ie\r
4476                 p1y,\r
4477                 p1x,            \r
4478                 p2y,\r
4479                 p2x,\r
4480                 swapY,\r
4481                 swapX,\r
4482                 doc = document,\r
4483                 docElement = doc.documentElement,\r
4484                 docBody = doc.body,\r
4485                 scrollX = (docElement.scrollLeft || docBody.scrollLeft || 0)+5,\r
4486                 scrollY = (docElement.scrollTop || docBody.scrollTop || 0)+5,\r
4487                 c = false, //constrain to viewport\r
4488                 p1 = "", \r
4489                 p2 = "",\r
4490                 m = p.match(/^([a-z]+)-([a-z]+)(\?)?$/);\r
4491         \r
4492         if(!m){\r
4493            throw "Element.alignTo with an invalid alignment " + p;\r
4494         }\r
4495         \r
4496         p1 = m[1]; \r
4497         p2 = m[2]; \r
4498         c = !!m[3];\r
4499 \r
4500         //Subtract the aligned el's internal xy from the target's offset xy\r
4501         //plus custom offset to get the aligned el's new offset xy\r
4502         a1 = me.getAnchorXY(p1, true);\r
4503         a2 = el.getAnchorXY(p2, false);\r
4504 \r
4505         x = a2[0] - a1[0] + o[0];\r
4506         y = a2[1] - a1[1] + o[1];\r
4507 \r
4508         if(c){    \r
4509                w = me.getWidth();\r
4510            h = me.getHeight();\r
4511            r = el.getRegion();       \r
4512            //If we are at a viewport boundary and the aligned el is anchored on a target border that is\r
4513            //perpendicular to the vp border, allow the aligned el to slide on that border,\r
4514            //otherwise swap the aligned el to the opposite border of the target.\r
4515            p1y = p1.charAt(0);\r
4516            p1x = p1.charAt(p1.length-1);\r
4517            p2y = p2.charAt(0);\r
4518            p2x = p2.charAt(p2.length-1);\r
4519            swapY = ((p1y=="t" && p2y=="b") || (p1y=="b" && p2y=="t"));\r
4520            swapX = ((p1x=="r" && p2x=="l") || (p1x=="l" && p2x=="r"));          \r
4521            \r
4522 \r
4523            if (x + w > dw + scrollX) {\r
4524                 x = swapX ? r.left-w : dw+scrollX-w;\r
4525            }\r
4526            if (x < scrollX) {\r
4527                x = swapX ? r.right : scrollX;\r
4528            }\r
4529            if (y + h > dh + scrollY) {\r
4530                 y = swapY ? r.top-h : dh+scrollY-h;\r
4531             }\r
4532            if (y < scrollY){\r
4533                y = swapY ? r.bottom : scrollY;\r
4534            }\r
4535         }\r
4536         return [x,y];\r
4537     },\r
4538 \r
4539     /**\r
4540      * Aligns this element with another element relative to the specified anchor points. If the other element is the\r
4541      * document it aligns it to the viewport.\r
4542      * The position parameter is optional, and can be specified in any one of the following formats:\r
4543      * <ul>\r
4544      *   <li><b>Blank</b>: Defaults to aligning the element's top-left corner to the target's bottom-left corner ("tl-bl").</li>\r
4545      *   <li><b>One anchor (deprecated)</b>: The passed anchor position is used as the target element's anchor point.\r
4546      *       The element being aligned will position its top-left corner (tl) to that point.  <i>This method has been\r
4547      *       deprecated in favor of the newer two anchor syntax below</i>.</li>\r
4548      *   <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\r
4549      *       element's anchor point, and the second value is used as the target's anchor point.</li>\r
4550      * </ul>\r
4551      * In addition to the anchor points, the position parameter also supports the "?" character.  If "?" is passed at the end of\r
4552      * the position string, the element will attempt to align as specified, but the position will be adjusted to constrain to\r
4553      * the viewport if necessary.  Note that the element being aligned might be swapped to align to a different position than\r
4554      * that specified in order to enforce the viewport constraints.\r
4555      * Following are all of the supported anchor positions:\r
4556 <pre>\r
4557 Value  Description\r
4558 -----  -----------------------------\r
4559 tl     The top left corner (default)\r
4560 t      The center of the top edge\r
4561 tr     The top right corner\r
4562 l      The center of the left edge\r
4563 c      In the center of the element\r
4564 r      The center of the right edge\r
4565 bl     The bottom left corner\r
4566 b      The center of the bottom edge\r
4567 br     The bottom right corner\r
4568 </pre>\r
4569 Example Usage:\r
4570 <pre><code>\r
4571 // align el to other-el using the default positioning ("tl-bl", non-constrained)\r
4572 el.alignTo("other-el");\r
4573 \r
4574 // align the top left corner of el with the top right corner of other-el (constrained to viewport)\r
4575 el.alignTo("other-el", "tr?");\r
4576 \r
4577 // align the bottom right corner of el with the center left edge of other-el\r
4578 el.alignTo("other-el", "br-l?");\r
4579 \r
4580 // align the center of el with the bottom left corner of other-el and\r
4581 // adjust the x position by -6 pixels (and the y position by 0)\r
4582 el.alignTo("other-el", "c-bl", [-6, 0]);\r
4583 </code></pre>\r
4584      * @param {Mixed} element The element to align to.\r
4585      * @param {String} position The position to align to.\r
4586      * @param {Array} offsets (optional) Offset the positioning by [x, y]\r
4587      * @param {Boolean/Object} animate (optional) true for the default animation or a standard Element animation config object\r
4588      * @return {Ext.Element} this\r
4589      */\r
4590     alignTo : function(element, position, offsets, animate){\r
4591             var me = this;\r
4592         return me.setXY(me.getAlignToXY(element, position, offsets),\r
4593                                 me.preanim && !!animate ? me.preanim(arguments, 3) : false);\r
4594     },\r
4595     \r
4596     // private ==>  used outside of core\r
4597     adjustForConstraints : function(xy, parent, offsets){\r
4598         return this.getConstrainToXY(parent || document, false, offsets, xy) ||  xy;\r
4599     },\r
4600 \r
4601     // private ==>  used outside of core\r
4602     getConstrainToXY : function(el, local, offsets, proposedXY){   \r
4603             var os = {top:0, left:0, bottom:0, right: 0};\r
4604 \r
4605         return function(el, local, offsets, proposedXY){\r
4606             el = Ext.get(el);\r
4607             offsets = offsets ? Ext.applyIf(offsets, os) : os;\r
4608 \r
4609             var vw, vh, vx = 0, vy = 0;\r
4610             if(el.dom == document.body || el.dom == document){\r
4611                 vw =Ext.lib.Dom.getViewWidth();\r
4612                 vh = Ext.lib.Dom.getViewHeight();\r
4613             }else{\r
4614                 vw = el.dom.clientWidth;\r
4615                 vh = el.dom.clientHeight;\r
4616                 if(!local){\r
4617                     var vxy = el.getXY();\r
4618                     vx = vxy[0];\r
4619                     vy = vxy[1];\r
4620                 }\r
4621             }\r
4622 \r
4623             var s = el.getScroll();\r
4624 \r
4625             vx += offsets.left + s.left;\r
4626             vy += offsets.top + s.top;\r
4627 \r
4628             vw -= offsets.right;\r
4629             vh -= offsets.bottom;\r
4630 \r
4631             var vr = vx+vw;\r
4632             var vb = vy+vh;\r
4633 \r
4634             var xy = proposedXY || (!local ? this.getXY() : [this.getLeft(true), this.getTop(true)]);\r
4635             var x = xy[0], y = xy[1];\r
4636             var w = this.dom.offsetWidth, h = this.dom.offsetHeight;\r
4637 \r
4638             // only move it if it needs it\r
4639             var moved = false;\r
4640 \r
4641             // first validate right/bottom\r
4642             if((x + w) > vr){\r
4643                 x = vr - w;\r
4644                 moved = true;\r
4645             }\r
4646             if((y + h) > vb){\r
4647                 y = vb - h;\r
4648                 moved = true;\r
4649             }\r
4650             // then make sure top/left isn't negative\r
4651             if(x < vx){\r
4652                 x = vx;\r
4653                 moved = true;\r
4654             }\r
4655             if(y < vy){\r
4656                 y = vy;\r
4657                 moved = true;\r
4658             }\r
4659             return moved ? [x, y] : false;\r
4660         };\r
4661     }(),\r
4662             \r
4663             \r
4664                 \r
4665 //         el = Ext.get(el);\r
4666 //         offsets = Ext.applyIf(offsets || {}, {top : 0, left : 0, bottom : 0, right : 0});\r
4667 \r
4668 //         var  me = this,\r
4669 //              doc = document,\r
4670 //              s = el.getScroll(),\r
4671 //              vxy = el.getXY(),\r
4672 //              vx = offsets.left + s.left, \r
4673 //              vy = offsets.top + s.top,               \r
4674 //              vw = -offsets.right, \r
4675 //              vh = -offsets.bottom, \r
4676 //              vr,\r
4677 //              vb,\r
4678 //              xy = proposedXY || (!local ? me.getXY() : [me.getLeft(true), me.getTop(true)]),\r
4679 //              x = xy[0],\r
4680 //              y = xy[1],\r
4681 //              w = me.dom.offsetWidth, h = me.dom.offsetHeight,\r
4682 //              moved = false; // only move it if it needs it\r
4683 //       \r
4684 //              \r
4685 //         if(el.dom == doc.body || el.dom == doc){\r
4686 //             vw += Ext.lib.Dom.getViewWidth();\r
4687 //             vh += Ext.lib.Dom.getViewHeight();\r
4688 //         }else{\r
4689 //             vw += el.dom.clientWidth;\r
4690 //             vh += el.dom.clientHeight;\r
4691 //             if(!local){                    \r
4692 //                 vx += vxy[0];\r
4693 //                 vy += vxy[1];\r
4694 //             }\r
4695 //         }\r
4696 \r
4697 //         // first validate right/bottom\r
4698 //         if(x + w > vx + vw){\r
4699 //             x = vx + vw - w;\r
4700 //             moved = true;\r
4701 //         }\r
4702 //         if(y + h > vy + vh){\r
4703 //             y = vy + vh - h;\r
4704 //             moved = true;\r
4705 //         }\r
4706 //         // then make sure top/left isn't negative\r
4707 //         if(x < vx){\r
4708 //             x = vx;\r
4709 //             moved = true;\r
4710 //         }\r
4711 //         if(y < vy){\r
4712 //             y = vy;\r
4713 //             moved = true;\r
4714 //         }\r
4715 //         return moved ? [x, y] : false;\r
4716 //    },\r
4717     \r
4718     /**\r
4719     * Calculates the x, y to center this element on the screen\r
4720     * @return {Array} The x, y values [x, y]\r
4721     */\r
4722     getCenterXY : function(){\r
4723         return this.getAlignToXY(document, 'c-c');\r
4724     },\r
4725 \r
4726     /**\r
4727     * Centers the Element in either the viewport, or another Element.\r
4728     * @param {Mixed} centerIn (optional) The element in which to center the element.\r
4729     */\r
4730     center : function(centerIn){\r
4731         return this.alignTo(centerIn || document, 'c-c');        \r
4732     }    \r
4733 });\r
4734 /**\r
4735  * @class Ext.Element\r
4736  */\r
4737 Ext.Element.addMethods(function(){\r
4738         var PARENTNODE = 'parentNode',\r
4739                 NEXTSIBLING = 'nextSibling',\r
4740                 PREVIOUSSIBLING = 'previousSibling',\r
4741                 DQ = Ext.DomQuery,\r
4742                 GET = Ext.get;\r
4743         \r
4744         return {\r
4745                 /**\r
4746              * 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)\r
4747              * @param {String} selector The simple selector to test\r
4748              * @param {Number/Mixed} maxDepth (optional) The max depth to search as a number or element (defaults to 50 || document.body)\r
4749              * @param {Boolean} returnEl (optional) True to return a Ext.Element object instead of DOM node\r
4750              * @return {HTMLElement} The matching DOM node (or null if no match was found)\r
4751              */\r
4752             findParent : function(simpleSelector, maxDepth, returnEl){\r
4753                 var p = this.dom,\r
4754                         b = document.body, \r
4755                         depth = 0,                      \r
4756                         stopEl;         \r
4757             if(Ext.isGecko && Object.prototype.toString.call(p) == '[object XULElement]') {\r
4758                 return null;\r
4759             }\r
4760                 maxDepth = maxDepth || 50;\r
4761                 if (isNaN(maxDepth)) {\r
4762                     stopEl = Ext.getDom(maxDepth);\r
4763                     maxDepth = Number.MAX_VALUE;\r
4764                 }\r
4765                 while(p && p.nodeType == 1 && depth < maxDepth && p != b && p != stopEl){\r
4766                     if(DQ.is(p, simpleSelector)){\r
4767                         return returnEl ? GET(p) : p;\r
4768                     }\r
4769                     depth++;\r
4770                     p = p.parentNode;\r
4771                 }\r
4772                 return null;\r
4773             },\r
4774         \r
4775             /**\r
4776              * Looks at parent nodes for a match of the passed simple selector (e.g. div.some-class or span:first-child)\r
4777              * @param {String} selector The simple selector to test\r
4778              * @param {Number/Mixed} maxDepth (optional) The max depth to\r
4779                     search as a number or element (defaults to 10 || document.body)\r
4780              * @param {Boolean} returnEl (optional) True to return a Ext.Element object instead of DOM node\r
4781              * @return {HTMLElement} The matching DOM node (or null if no match was found)\r
4782              */\r
4783             findParentNode : function(simpleSelector, maxDepth, returnEl){\r
4784                 var p = Ext.fly(this.dom.parentNode, '_internal');\r
4785                 return p ? p.findParent(simpleSelector, maxDepth, returnEl) : null;\r
4786             },\r
4787         \r
4788             /**\r
4789              * Walks up the dom looking for a parent node that matches the passed simple selector (e.g. div.some-class or span:first-child).\r
4790              * This is a shortcut for findParentNode() that always returns an Ext.Element.\r
4791              * @param {String} selector The simple selector to test\r
4792              * @param {Number/Mixed} maxDepth (optional) The max depth to\r
4793                     search as a number or element (defaults to 10 || document.body)\r
4794              * @return {Ext.Element} The matching DOM node (or null if no match was found)\r
4795              */\r
4796             up : function(simpleSelector, maxDepth){\r
4797                 return this.findParentNode(simpleSelector, maxDepth, true);\r
4798             },\r
4799         \r
4800             /**\r
4801              * Creates a {@link Ext.CompositeElement} for child nodes based on the passed CSS selector (the selector should not contain an id).\r
4802              * @param {String} selector The CSS selector\r
4803              * @param {Boolean} unique (optional) True to create a unique Ext.Element for each child (defaults to false, which creates a single shared flyweight object)\r
4804              * @return {CompositeElement/CompositeElementLite} The composite element\r
4805              */\r
4806             select : function(selector, unique){\r
4807                 return Ext.Element.select(selector, unique, this.dom);\r
4808             },\r
4809         \r
4810             /**\r
4811              * Selects child nodes based on the passed CSS selector (the selector should not contain an id).\r
4812              * @param {String} selector The CSS selector\r
4813              * @return {Array} An array of the matched nodes\r
4814              */\r
4815             query : function(selector, unique){\r
4816                 return DQ.select(selector, this.dom);\r
4817             },\r
4818         \r
4819             /**\r
4820              * Selects a single child at any depth below this element based on the passed CSS selector (the selector should not contain an id).\r
4821              * @param {String} selector The CSS selector\r
4822              * @param {Boolean} returnDom (optional) True to return the DOM node instead of Ext.Element (defaults to false)\r
4823              * @return {HTMLElement/Ext.Element} The child Ext.Element (or DOM node if returnDom = true)\r
4824              */\r
4825             child : function(selector, returnDom){\r
4826                 var n = DQ.selectNode(selector, this.dom);\r
4827                 return returnDom ? n : GET(n);\r
4828             },\r
4829         \r
4830             /**\r
4831              * Selects a single *direct* child based on the passed CSS selector (the selector should not contain an id).\r
4832              * @param {String} selector The CSS selector\r
4833              * @param {Boolean} returnDom (optional) True to return the DOM node instead of Ext.Element (defaults to false)\r
4834              * @return {HTMLElement/Ext.Element} The child Ext.Element (or DOM node if returnDom = true)\r
4835              */\r
4836             down : function(selector, returnDom){\r
4837                 var n = DQ.selectNode(" > " + selector, this.dom);\r
4838                 return returnDom ? n : GET(n);\r
4839             },\r
4840         \r
4841                  /**\r
4842              * Gets the parent node for this element, optionally chaining up trying to match a selector\r
4843              * @param {String} selector (optional) Find a parent node that matches the passed simple selector\r
4844              * @param {Boolean} returnDom (optional) True to return a raw dom node instead of an Ext.Element\r
4845              * @return {Ext.Element/HTMLElement} The parent node or null\r
4846                  */\r
4847             parent : function(selector, returnDom){\r
4848                 return this.matchNode(PARENTNODE, PARENTNODE, selector, returnDom);\r
4849             },\r
4850         \r
4851              /**\r
4852              * Gets the next sibling, skipping text nodes\r
4853              * @param {String} selector (optional) Find the next sibling that matches the passed simple selector\r
4854              * @param {Boolean} returnDom (optional) True to return a raw dom node instead of an Ext.Element\r
4855              * @return {Ext.Element/HTMLElement} The next sibling or null\r
4856                  */\r
4857             next : function(selector, returnDom){\r
4858                 return this.matchNode(NEXTSIBLING, NEXTSIBLING, selector, returnDom);\r
4859             },\r
4860         \r
4861             /**\r
4862              * Gets the previous sibling, skipping text nodes\r
4863              * @param {String} selector (optional) Find the previous sibling that matches the passed simple selector\r
4864              * @param {Boolean} returnDom (optional) True to return a raw dom node instead of an Ext.Element\r
4865              * @return {Ext.Element/HTMLElement} The previous sibling or null\r
4866                  */\r
4867             prev : function(selector, returnDom){\r
4868                 return this.matchNode(PREVIOUSSIBLING, PREVIOUSSIBLING, selector, returnDom);\r
4869             },\r
4870         \r
4871         \r
4872             /**\r
4873              * Gets the first child, skipping text nodes\r
4874              * @param {String} selector (optional) Find the next sibling that matches the passed simple selector\r
4875              * @param {Boolean} returnDom (optional) True to return a raw dom node instead of an Ext.Element\r
4876              * @return {Ext.Element/HTMLElement} The first child or null\r
4877                  */\r
4878             first : function(selector, returnDom){\r
4879                 return this.matchNode(NEXTSIBLING, 'firstChild', selector, returnDom);\r
4880             },\r
4881         \r
4882             /**\r
4883              * Gets the last child, skipping text nodes\r
4884              * @param {String} selector (optional) Find the previous sibling that matches the passed simple selector\r
4885              * @param {Boolean} returnDom (optional) True to return a raw dom node instead of an Ext.Element\r
4886              * @return {Ext.Element/HTMLElement} The last child or null\r
4887                  */\r
4888             last : function(selector, returnDom){\r
4889                 return this.matchNode(PREVIOUSSIBLING, 'lastChild', selector, returnDom);\r
4890             },\r
4891             \r
4892             matchNode : function(dir, start, selector, returnDom){\r
4893                 var n = this.dom[start];\r
4894                 while(n){\r
4895                     if(n.nodeType == 1 && (!selector || DQ.is(n, selector))){\r
4896                         return !returnDom ? GET(n) : n;\r
4897                     }\r
4898                     n = n[dir];\r
4899                 }\r
4900                 return null;\r
4901             }   \r
4902     }\r
4903 }());/**\r
4904  * @class Ext.Element\r
4905  */\r
4906 Ext.Element.addMethods(\r
4907 function() {\r
4908         var GETDOM = Ext.getDom,\r
4909                 GET = Ext.get,\r
4910                 DH = Ext.DomHelper,\r
4911         isEl = function(el){\r
4912             return  (el.nodeType || el.dom || typeof el == 'string');  \r
4913         };\r
4914         \r
4915         return {\r
4916             /**\r
4917              * Appends the passed element(s) to this element\r
4918              * @param {String/HTMLElement/Array/Element/CompositeElement} el\r
4919              * @return {Ext.Element} this\r
4920              */\r
4921             appendChild: function(el){        \r
4922                 return GET(el).appendTo(this);        \r
4923             },\r
4924         \r
4925             /**\r
4926              * Appends this element to the passed element\r
4927              * @param {Mixed} el The new parent element\r
4928              * @return {Ext.Element} this\r
4929              */\r
4930             appendTo: function(el){        \r
4931                 GETDOM(el).appendChild(this.dom);        \r
4932                 return this;\r
4933             },\r
4934         \r
4935             /**\r
4936              * Inserts this element before the passed element in the DOM\r
4937              * @param {Mixed} el The element before which this element will be inserted\r
4938              * @return {Ext.Element} this\r
4939              */\r
4940             insertBefore: function(el){                   \r
4941                 (el = GETDOM(el)).parentNode.insertBefore(this.dom, el);\r
4942                 return this;\r
4943             },\r
4944         \r
4945             /**\r
4946              * Inserts this element after the passed element in the DOM\r
4947              * @param {Mixed} el The element to insert after\r
4948              * @return {Ext.Element} this\r
4949              */\r
4950             insertAfter: function(el){\r
4951                 (el = GETDOM(el)).parentNode.insertBefore(this.dom, el.nextSibling);\r
4952                 return this;\r
4953             },\r
4954         \r
4955             /**\r
4956              * Inserts (or creates) an element (or DomHelper config) as the first child of this element\r
4957              * @param {Mixed/Object} el The id or element to insert or a DomHelper config to create and insert\r
4958              * @return {Ext.Element} The new child\r
4959              */\r
4960             insertFirst: function(el, returnDom){\r
4961             el = el || {};\r
4962             if(isEl(el)){ // element\r
4963                 el = GETDOM(el);\r
4964                 this.dom.insertBefore(el, this.dom.firstChild);\r
4965                 return !returnDom ? GET(el) : el;\r
4966             }else{ // dh config\r
4967                 return this.createChild(el, this.dom.firstChild, returnDom);\r
4968             }\r
4969     },\r
4970         \r
4971             /**\r
4972              * Replaces the passed element with this element\r
4973              * @param {Mixed} el The element to replace\r
4974              * @return {Ext.Element} this\r
4975              */\r
4976             replace: function(el){\r
4977                 el = GET(el);\r
4978                 this.insertBefore(el);\r
4979                 el.remove();\r
4980                 return this;\r
4981             },\r
4982         \r
4983             /**\r
4984              * Replaces this element with the passed element\r
4985              * @param {Mixed/Object} el The new element or a DomHelper config of an element to create\r
4986              * @return {Ext.Element} this\r
4987              */\r
4988             replaceWith: function(el){\r
4989                     var me = this,\r
4990                         Element = Ext.Element;\r
4991             if(isEl(el)){\r
4992                 el = GETDOM(el);\r
4993                 me.dom.parentNode.insertBefore(el, me.dom);\r
4994             }else{\r
4995                 el = DH.insertBefore(me.dom, el);\r
4996             }\r
4997                 \r
4998                 delete Element.cache[me.id];\r
4999                 Ext.removeNode(me.dom);      \r
5000                 me.id = Ext.id(me.dom = el);\r
5001                 return Element.cache[me.id] = me;        \r
5002             },\r
5003             \r
5004                 /**\r
5005                  * Creates the passed DomHelper config and appends it to this element or optionally inserts it before the passed child element.\r
5006                  * @param {Object} config DomHelper element config object.  If no tag is specified (e.g., {tag:'input'}) then a div will be\r
5007                  * automatically generated with the specified attributes.\r
5008                  * @param {HTMLElement} insertBefore (optional) a child element of this element\r
5009                  * @param {Boolean} returnDom (optional) true to return the dom node instead of creating an Element\r
5010                  * @return {Ext.Element} The new child element\r
5011                  */\r
5012                 createChild: function(config, insertBefore, returnDom){\r
5013                     config = config || {tag:'div'};\r
5014                     return insertBefore ? \r
5015                            DH.insertBefore(insertBefore, config, returnDom !== true) :  \r
5016                            DH[!this.dom.firstChild ? 'overwrite' : 'append'](this.dom, config,  returnDom !== true);\r
5017                 },\r
5018                 \r
5019                 /**\r
5020                  * Creates and wraps this element with another element\r
5021                  * @param {Object} config (optional) DomHelper element config object for the wrapper element or null for an empty div\r
5022                  * @param {Boolean} returnDom (optional) True to return the raw DOM element instead of Ext.Element\r
5023                  * @return {HTMLElement/Element} The newly created wrapper element\r
5024                  */\r
5025                 wrap: function(config, returnDom){        \r
5026                     var newEl = DH.insertBefore(this.dom, config || {tag: "div"}, !returnDom);\r
5027                     newEl.dom ? newEl.dom.appendChild(this.dom) : newEl.appendChild(this.dom);\r
5028                     return newEl;\r
5029                 },\r
5030                 \r
5031                 /**\r
5032                  * Inserts an html fragment into this element\r
5033                  * @param {String} where Where to insert the html in relation to this element - beforeBegin, afterBegin, beforeEnd, afterEnd.\r
5034                  * @param {String} html The HTML fragment\r
5035                  * @param {Boolean} returnEl (optional) True to return an Ext.Element (defaults to false)\r
5036                  * @return {HTMLElement/Ext.Element} The inserted node (or nearest related if more than 1 inserted)\r
5037                  */\r
5038                 insertHtml : function(where, html, returnEl){\r
5039                     var el = DH.insertHtml(where, this.dom, html);\r
5040                     return returnEl ? Ext.get(el) : el;\r
5041                 }\r
5042         }\r
5043 }());/**\r
5044  * @class Ext.Element\r
5045  */\r
5046 Ext.apply(Ext.Element.prototype, function() {\r
5047         var GETDOM = Ext.getDom,\r
5048                 GET = Ext.get,\r
5049                 DH = Ext.DomHelper;\r
5050         \r
5051         return {        \r
5052                 /**\r
5053              * Inserts (or creates) the passed element (or DomHelper config) as a sibling of this element\r
5054              * @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.\r
5055              * @param {String} where (optional) 'before' or 'after' defaults to before\r
5056              * @param {Boolean} returnDom (optional) True to return the raw DOM element instead of Ext.Element\r
5057              * @return {Ext.Element} the inserted Element\r
5058              */\r
5059             insertSibling: function(el, where, returnDom){\r
5060                 var me = this,\r
5061                         rt;\r
5062                         \r
5063                 if(Ext.isArray(el)){            \r
5064                     Ext.each(el, function(e) {\r
5065                             rt = me.insertSibling(e, where, returnDom);\r
5066                     });\r
5067                     return rt;\r
5068                 }\r
5069                         \r
5070                 where = (where || 'before').toLowerCase();\r
5071                 el = el || {};\r
5072                 \r
5073             if(el.nodeType || el.dom){\r
5074                 rt = me.dom.parentNode.insertBefore(GETDOM(el), where == 'before' ? me.dom : me.dom.nextSibling);\r
5075                 if (!returnDom) {\r
5076                     rt = GET(rt);\r
5077                 }\r
5078             }else{\r
5079                 if (where == 'after' && !me.dom.nextSibling) {\r
5080                     rt = DH.append(me.dom.parentNode, el, !returnDom);\r
5081                 } else {                    \r
5082                     rt = DH[where == 'after' ? 'insertAfter' : 'insertBefore'](me.dom, el, !returnDom);\r
5083                 }\r
5084             }\r
5085                 return rt;\r
5086             }\r
5087     };\r
5088 }());/**\r
5089  * @class Ext.Element\r
5090  */\r
5091 Ext.Element.addMethods(function(){  \r
5092     // local style camelizing for speed\r
5093     var propCache = {},\r
5094         camelRe = /(-[a-z])/gi,\r
5095         classReCache = {},\r
5096         view = document.defaultView,\r
5097         propFloat = Ext.isIE ? 'styleFloat' : 'cssFloat',\r
5098         opacityRe = /alpha\(opacity=(.*)\)/i,\r
5099         trimRe = /^\s+|\s+$/g,\r
5100         EL = Ext.Element,   \r
5101         PADDING = "padding",\r
5102         MARGIN = "margin",\r
5103         BORDER = "border",\r
5104         LEFT = "-left",\r
5105         RIGHT = "-right",\r
5106         TOP = "-top",\r
5107         BOTTOM = "-bottom",\r
5108         WIDTH = "-width",    \r
5109         MATH = Math,\r
5110         HIDDEN = 'hidden',\r
5111         ISCLIPPED = 'isClipped',\r
5112         OVERFLOW = 'overflow',\r
5113         OVERFLOWX = 'overflow-x',\r
5114         OVERFLOWY = 'overflow-y',\r
5115         ORIGINALCLIP = 'originalClip',\r
5116         // special markup used throughout Ext when box wrapping elements    \r
5117         borders = {l: BORDER + LEFT + WIDTH, r: BORDER + RIGHT + WIDTH, t: BORDER + TOP + WIDTH, b: BORDER + BOTTOM + WIDTH},\r
5118         paddings = {l: PADDING + LEFT, r: PADDING + RIGHT, t: PADDING + TOP, b: PADDING + BOTTOM},\r
5119         margins = {l: MARGIN + LEFT, r: MARGIN + RIGHT, t: MARGIN + TOP, b: MARGIN + BOTTOM},\r
5120         data = Ext.Element.data;\r
5121         \r
5122     \r
5123     // private  \r
5124     function camelFn(m, a) {\r
5125         return a.charAt(1).toUpperCase();\r
5126     }\r
5127     \r
5128     // private (needs to be called => addStyles.call(this, sides, styles))\r
5129     function addStyles(sides, styles){\r
5130         var val = 0;    \r
5131         \r
5132         Ext.each(sides.match(/\w/g), function(s) {\r
5133             if (s = parseInt(this.getStyle(styles[s]), 10)) {\r
5134                 val += MATH.abs(s);      \r
5135             }\r
5136         },\r
5137         this);\r
5138         return val;\r
5139     }\r
5140 \r
5141     function chkCache(prop) {\r
5142         return propCache[prop] || (propCache[prop] = prop == 'float' ? propFloat : prop.replace(camelRe, camelFn));\r
5143 \r
5144     }\r
5145             \r
5146     return {    \r
5147         // private  ==> used by Fx  \r
5148         adjustWidth : function(width) {\r
5149             var me = this;\r
5150             var isNum = (typeof width == "number");\r
5151             if(isNum && me.autoBoxAdjust && !me.isBorderBox()){\r
5152                width -= (me.getBorderWidth("lr") + me.getPadding("lr"));\r
5153             }\r
5154             return (isNum && width < 0) ? 0 : width;\r
5155         },\r
5156         \r
5157         // private   ==> used by Fx \r
5158         adjustHeight : function(height) {\r
5159             var me = this;\r
5160             var isNum = (typeof height == "number");\r
5161             if(isNum && me.autoBoxAdjust && !me.isBorderBox()){\r
5162                height -= (me.getBorderWidth("tb") + me.getPadding("tb"));               \r
5163             }\r
5164             return (isNum && height < 0) ? 0 : height;\r
5165         },\r
5166     \r
5167     \r
5168         /**\r
5169          * Adds one or more CSS classes to the element. Duplicate classes are automatically filtered out.\r
5170          * @param {String/Array} className The CSS class to add, or an array of classes\r
5171          * @return {Ext.Element} this\r
5172          */\r
5173         addClass : function(className){\r
5174             var me = this;\r
5175             Ext.each(className, function(v) {\r
5176                 me.dom.className += (!me.hasClass(v) && v ? " " + v : "");  \r
5177             });\r
5178             return me;\r
5179         },\r
5180     \r
5181         /**\r
5182          * Adds one or more CSS classes to this element and removes the same class(es) from all siblings.\r
5183          * @param {String/Array} className The CSS class to add, or an array of classes\r
5184          * @return {Ext.Element} this\r
5185          */\r
5186         radioClass : function(className){\r
5187             Ext.each(this.dom.parentNode.childNodes, function(v) {\r
5188                 if(v.nodeType == 1) {\r
5189                     Ext.fly(v, '_internal').removeClass(className);          \r
5190                 }\r
5191             });\r
5192             return this.addClass(className);\r
5193         },\r
5194     \r
5195         /**\r
5196          * Removes one or more CSS classes from the element.\r
5197          * @param {String/Array} className The CSS class to remove, or an array of classes\r
5198          * @return {Ext.Element} this\r
5199          */\r
5200         removeClass : function(className){\r
5201             var me = this;\r
5202             if (me.dom.className) {\r
5203                 Ext.each(className, function(v) {               \r
5204                     me.dom.className = me.dom.className.replace(\r
5205                         classReCache[v] = classReCache[v] || new RegExp('(?:^|\\s+)' + v + '(?:\\s+|$)', "g"), \r
5206                         " ");               \r
5207                 });    \r
5208             }\r
5209             return me;\r
5210         },\r
5211     \r
5212         /**\r
5213          * Toggles the specified CSS class on this element (removes it if it already exists, otherwise adds it).\r
5214          * @param {String} className The CSS class to toggle\r
5215          * @return {Ext.Element} this\r
5216          */\r
5217         toggleClass : function(className){\r
5218             return this.hasClass(className) ? this.removeClass(className) : this.addClass(className);\r
5219         },\r
5220     \r
5221         /**\r
5222          * Checks if the specified CSS class exists on this element's DOM node.\r
5223          * @param {String} className The CSS class to check for\r
5224          * @return {Boolean} True if the class exists, else false\r
5225          */\r
5226         hasClass : function(className){\r
5227             return className && (' '+this.dom.className+' ').indexOf(' '+className+' ') != -1;\r
5228         },\r
5229     \r
5230         /**\r
5231          * Replaces a CSS class on the element with another.  If the old name does not exist, the new name will simply be added.\r
5232          * @param {String} oldClassName The CSS class to replace\r
5233          * @param {String} newClassName The replacement CSS class\r
5234          * @return {Ext.Element} this\r
5235          */\r
5236         replaceClass : function(oldClassName, newClassName){\r
5237             return this.removeClass(oldClassName).addClass(newClassName);\r
5238         },\r
5239         \r
5240         isStyle : function(style, val) {\r
5241             return this.getStyle(style) == val;  \r
5242         },\r
5243     \r
5244         /**\r
5245          * Normalizes currentStyle and computedStyle.\r
5246          * @param {String} property The style property whose value is returned.\r
5247          * @return {String} The current value of the style property for this element.\r
5248          */\r
5249         getStyle : function(){         \r
5250             return view && view.getComputedStyle ?\r
5251                 function(prop){\r
5252                     var el = this.dom,\r
5253                         v,                  \r
5254                         cs;\r
5255                     if(el == document) return null;\r
5256                     prop = chkCache(prop);\r
5257                     return (v = el.style[prop]) ? v : \r
5258                            (cs = view.getComputedStyle(el, "")) ? cs[prop] : null;\r
5259                 } :\r
5260                 function(prop){      \r
5261                     var el = this.dom, \r
5262                         m, \r
5263                         cs;     \r
5264                         \r
5265                     if(el == document) return null;      \r
5266                     if (prop == 'opacity') {\r
5267                         if (el.style.filter.match) {                       \r
5268                             if(m = el.style.filter.match(opacityRe)){\r
5269                                 var fv = parseFloat(m[1]);\r
5270                                 if(!isNaN(fv)){\r
5271                                     return fv ? fv / 100 : 0;\r
5272                                 }\r
5273                             }\r
5274                         }\r
5275                         return 1;\r
5276                     }\r
5277                     prop = chkCache(prop);  \r
5278                     return el.style[prop] || ((cs = el.currentStyle) ? cs[prop] : null);\r
5279                 };\r
5280         }(),\r
5281         \r
5282         /**\r
5283          * Return the CSS color for the specified CSS attribute. rgb, 3 digit (like #fff) and valid values\r
5284          * are convert to standard 6 digit hex color.\r
5285          * @param {String} attr The css attribute\r
5286          * @param {String} defaultValue The default value to use when a valid color isn't found\r
5287          * @param {String} prefix (optional) defaults to #. Use an empty string when working with\r
5288          * color anims.\r
5289          */\r
5290         getColor : function(attr, defaultValue, prefix){\r
5291             var v = this.getStyle(attr),\r
5292                 color = prefix || '#',\r
5293                 h;\r
5294                 \r
5295             if(!v || /transparent|inherit/.test(v)){\r
5296                 return defaultValue;\r
5297             }\r
5298             if(/^r/.test(v)){\r
5299                 Ext.each(v.slice(4, v.length -1).split(','), function(s){\r
5300                     h = parseInt(s, 10);\r
5301                     color += (h < 16 ? '0' : '') + h.toString(16); \r
5302                 });\r
5303             }else{\r
5304                 v = v.replace('#', '');\r
5305                 color += v.length == 3 ? v.replace(/^(\w)(\w)(\w)$/, '$1$1$2$2$3$3') : v;\r
5306             }\r
5307             return(color.length > 5 ? color.toLowerCase() : defaultValue);\r
5308         },\r
5309     \r
5310         /**\r
5311          * Wrapper for setting style properties, also takes single object parameter of multiple styles.\r
5312          * @param {String/Object} property The style property to be set, or an object of multiple styles.\r
5313          * @param {String} value (optional) The value to apply to the given property, or null if an object was passed.\r
5314          * @return {Ext.Element} this\r
5315          */\r
5316         setStyle : function(prop, value){\r
5317             var tmp, \r
5318                 style,\r
5319                 camel;\r
5320             if (!Ext.isObject(prop)) {\r
5321                 tmp = {};\r
5322                 tmp[prop] = value;          \r
5323                 prop = tmp;\r
5324             }\r
5325             for (style in prop) {\r
5326                 value = prop[style];            \r
5327                 style == 'opacity' ? \r
5328                     this.setOpacity(value) : \r
5329                     this.dom.style[chkCache(style)] = value;\r
5330             }\r
5331             return this;\r
5332         },\r
5333         \r
5334         /**\r
5335          * Set the opacity of the element\r
5336          * @param {Float} opacity The new opacity. 0 = transparent, .5 = 50% visibile, 1 = fully visible, etc\r
5337          * @param {Boolean/Object} animate (optional) a standard Element animation config object or <tt>true</tt> for\r
5338          * the default animation (<tt>{duration: .35, easing: 'easeIn'}</tt>)\r
5339          * @return {Ext.Element} this\r
5340          */\r
5341          setOpacity : function(opacity, animate){\r
5342             var me = this,\r
5343                 s = me.dom.style;\r
5344                 \r
5345             if(!animate || !me.anim){            \r
5346                 if(Ext.isIE){\r
5347                     var opac = opacity < 1 ? 'alpha(opacity=' + opacity * 100 + ')' : '', \r
5348                     val = s.filter.replace(opacityRe, '').replace(trimRe, '');\r
5349 \r
5350                     s.zoom = 1;\r
5351                     s.filter = val + (val.length > 0 ? ' ' : '') + opac;\r
5352                 }else{\r
5353                     s.opacity = opacity;\r
5354                 }\r
5355             }else{\r
5356                 me.anim({opacity: {to: opacity}}, me.preanim(arguments, 1), null, .35, 'easeIn');\r
5357             }\r
5358             return me;\r
5359         },\r
5360         \r
5361         /**\r
5362          * Clears any opacity settings from this element. Required in some cases for IE.\r
5363          * @return {Ext.Element} this\r
5364          */\r
5365         clearOpacity : function(){\r
5366             var style = this.dom.style;\r
5367             if(Ext.isIE){\r
5368                 if(!Ext.isEmpty(style.filter)){\r
5369                     style.filter = style.filter.replace(opacityRe, '').replace(trimRe, '');\r
5370                 }\r
5371             }else{\r
5372                 style.opacity = style['-moz-opacity'] = style['-khtml-opacity'] = '';\r
5373             }\r
5374             return this;\r
5375         },\r
5376     \r
5377         /**\r
5378          * Returns the offset height of the element\r
5379          * @param {Boolean} contentHeight (optional) true to get the height minus borders and padding\r
5380          * @return {Number} The element's height\r
5381          */\r
5382         getHeight : function(contentHeight){\r
5383             var me = this,\r
5384                 dom = me.dom,\r
5385                 h = MATH.max(dom.offsetHeight, dom.clientHeight) || 0;\r
5386             h = !contentHeight ? h : h - me.getBorderWidth("tb") - me.getPadding("tb");\r
5387             return h < 0 ? 0 : h;\r
5388         },\r
5389     \r
5390         /**\r
5391          * Returns the offset width of the element\r
5392          * @param {Boolean} contentWidth (optional) true to get the width minus borders and padding\r
5393          * @return {Number} The element's width\r
5394          */\r
5395         getWidth : function(contentWidth){\r
5396             var me = this,\r
5397                 dom = me.dom,\r
5398                 w = MATH.max(dom.offsetWidth, dom.clientWidth) || 0;\r
5399             w = !contentWidth ? w : w - me.getBorderWidth("lr") - me.getPadding("lr");\r
5400             return w < 0 ? 0 : w;\r
5401         },\r
5402     \r
5403         /**\r
5404          * Set the width of this Element.\r
5405          * @param {Mixed} width The new width. This may be one of:<div class="mdetail-params"><ul>\r
5406          * <li>A Number specifying the new width in this Element's {@link #defaultUnit}s (by default, pixels).</li>\r
5407          * <li>A String used to set the CSS width style. Animation may <b>not</b> be used.\r
5408          * </ul></div>\r
5409          * @param {Boolean/Object} animate (optional) true for the default animation or a standard Element animation config object\r
5410          * @return {Ext.Element} this\r
5411          */\r
5412         setWidth : function(width, animate){\r
5413             var me = this;\r
5414             width = me.adjustWidth(width);\r
5415             !animate || !me.anim ? \r
5416                 me.dom.style.width = me.addUnits(width) :\r
5417                 me.anim({width : {to : width}}, me.preanim(arguments, 1));\r
5418             return me;\r
5419         },\r
5420     \r
5421         /**\r
5422          * Set the height of this Element.\r
5423          * <pre><code>\r
5424 // change the height to 200px and animate with default configuration\r
5425 Ext.fly('elementId').setHeight(200, true);\r
5426 \r
5427 // change the height to 150px and animate with a custom configuration\r
5428 Ext.fly('elId').setHeight(150, {\r
5429     duration : .5, // animation will have a duration of .5 seconds\r
5430     // will change the content to "finished"\r
5431     callback: function(){ this.{@link #update}("finished"); } \r
5432 });\r
5433          * </code></pre>\r
5434          * @param {Mixed} height The new height. This may be one of:<div class="mdetail-params"><ul>\r
5435          * <li>A Number specifying the new height in this Element's {@link #defaultUnit}s (by default, pixels.)</li>\r
5436          * <li>A String used to set the CSS height style. Animation may <b>not</b> be used.</li>\r
5437          * </ul></div>\r
5438          * @param {Boolean/Object} animate (optional) true for the default animation or a standard Element animation config object\r
5439          * @return {Ext.Element} this\r
5440          */\r
5441          setHeight : function(height, animate){\r
5442             var me = this;\r
5443             height = me.adjustHeight(height);\r
5444             !animate || !me.anim ? \r
5445                 me.dom.style.height = me.addUnits(height) :\r
5446                 me.anim({height : {to : height}}, me.preanim(arguments, 1));\r
5447             return me;\r
5448         },\r
5449         \r
5450         /**\r
5451          * Gets the width of the border(s) for the specified side(s)\r
5452          * @param {String} side Can be t, l, r, b or any combination of those to add multiple values. For example,\r
5453          * passing <tt>'lr'</tt> would get the border <b><u>l</u></b>eft width + the border <b><u>r</u></b>ight width.\r
5454          * @return {Number} The width of the sides passed added together\r
5455          */\r
5456         getBorderWidth : function(side){\r
5457             return addStyles.call(this, side, borders);\r
5458         },\r
5459     \r
5460         /**\r
5461          * Gets the width of the padding(s) for the specified side(s)\r
5462          * @param {String} side Can be t, l, r, b or any combination of those to add multiple values. For example,\r
5463          * passing <tt>'lr'</tt> would get the padding <b><u>l</u></b>eft + the padding <b><u>r</u></b>ight.\r
5464          * @return {Number} The padding of the sides passed added together\r
5465          */\r
5466         getPadding : function(side){\r
5467             return addStyles.call(this, side, paddings);\r
5468         },\r
5469     \r
5470         /**\r
5471          *  Store the current overflow setting and clip overflow on the element - use <tt>{@link #unclip}</tt> to remove\r
5472          * @return {Ext.Element} this\r
5473          */\r
5474         clip : function(){\r
5475             var me = this,\r
5476                 dom = me.dom;\r
5477                 \r
5478             if(!data(dom, ISCLIPPED)){\r
5479                 data(dom, ISCLIPPED, true);\r
5480                 data(dom, ORIGINALCLIP, {\r
5481                     o: me.getStyle(OVERFLOW),\r
5482                     x: me.getStyle(OVERFLOWX),\r
5483                     y: me.getStyle(OVERFLOWY)\r
5484                 });\r
5485                 me.setStyle(OVERFLOW, HIDDEN);\r
5486                 me.setStyle(OVERFLOWX, HIDDEN);\r
5487                 me.setStyle(OVERFLOWY, HIDDEN);\r
5488             }\r
5489             return me;\r
5490         },\r
5491     \r
5492         /**\r
5493          *  Return clipping (overflow) to original clipping before <tt>{@link #clip}</tt> was called\r
5494          * @return {Ext.Element} this\r
5495          */\r
5496         unclip : function(){\r
5497             var me = this,\r
5498                 dom = me.dom;\r
5499                 \r
5500             if(data(dom, ISCLIPPED)){\r
5501                 data(dom, ISCLIPPED, false);\r
5502                 var o = data(dom, ORIGINALCLIP);\r
5503                 if(o.o){\r
5504                     me.setStyle(OVERFLOW, o.o);\r
5505                 }\r
5506                 if(o.x){\r
5507                     me.setStyle(OVERFLOWX, o.x);\r
5508                 }\r
5509                 if(o.y){\r
5510                     me.setStyle(OVERFLOWY, o.y);\r
5511                 }\r
5512             }\r
5513             return me;\r
5514         },\r
5515         \r
5516         addStyles : addStyles,\r
5517         margins : margins\r
5518     }\r
5519 }()         \r
5520 );/**\r
5521  * @class Ext.Element\r
5522  */\r
5523 \r
5524 // special markup used throughout Ext when box wrapping elements\r
5525 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>';\r
5526 \r
5527 Ext.Element.addMethods(function(){\r
5528         var INTERNAL = "_internal";\r
5529         return {\r
5530             /**\r
5531              * More flexible version of {@link #setStyle} for setting style properties.\r
5532              * @param {String/Object/Function} styles A style specification string, e.g. "width:100px", or object in the form {width:"100px"}, or\r
5533              * a function which returns such a specification.\r
5534              * @return {Ext.Element} this\r
5535              */\r
5536             applyStyles : function(style){\r
5537                 Ext.DomHelper.applyStyles(this.dom, style);\r
5538                 return this;\r
5539             },\r
5540 \r
5541                 /**\r
5542              * Returns an object with properties matching the styles requested.\r
5543              * For example, el.getStyles('color', 'font-size', 'width') might return\r
5544              * {'color': '#FFFFFF', 'font-size': '13px', 'width': '100px'}.\r
5545              * @param {String} style1 A style name\r
5546              * @param {String} style2 A style name\r
5547              * @param {String} etc.\r
5548              * @return {Object} The style object\r
5549              */\r
5550             getStyles : function(){\r
5551                     var ret = {};\r
5552                     Ext.each(arguments, function(v) {\r
5553                            ret[v] = this.getStyle(v);\r
5554                     },\r
5555                     this);\r
5556                     return ret;\r
5557             },\r
5558 \r
5559                 getStyleSize : function(){\r
5560                 var me = this,\r
5561                         w,\r
5562                         h,\r
5563                         d = this.dom,\r
5564                         s = d.style;\r
5565                 if(s.width && s.width != 'auto'){\r
5566                     w = parseInt(s.width, 10);\r
5567                     if(me.isBorderBox()){\r
5568                        w -= me.getFrameWidth('lr');\r
5569                     }\r
5570                 }\r
5571                 if(s.height && s.height != 'auto'){\r
5572                     h = parseInt(s.height, 10);\r
5573                     if(me.isBorderBox()){\r
5574                        h -= me.getFrameWidth('tb');\r
5575                     }\r
5576                 }\r
5577                 return {width: w || me.getWidth(true), height: h || me.getHeight(true)};\r
5578             },\r
5579 \r
5580             // private  ==> used by ext full\r
5581                 setOverflow : function(v){\r
5582                         var dom = this.dom;\r
5583                 if(v=='auto' && Ext.isMac && Ext.isGecko2){ // work around stupid FF 2.0/Mac scroll bar bug\r
5584                         dom.style.overflow = 'hidden';\r
5585                         (function(){dom.style.overflow = 'auto';}).defer(1);\r
5586                 }else{\r
5587                         dom.style.overflow = v;\r
5588                 }\r
5589                 },\r
5590 \r
5591            /**\r
5592                 * <p>Wraps the specified element with a special 9 element markup/CSS block that renders by default as\r
5593                 * a gray container with a gradient background, rounded corners and a 4-way shadow.</p>\r
5594                 * <p>This special markup is used throughout Ext when box wrapping elements ({@link Ext.Button},\r
5595                 * {@link Ext.Panel} when <tt>{@link Ext.Panel#frame frame=true}</tt>, {@link Ext.Window}).  The markup\r
5596                 * is of this form:</p>\r
5597                 * <pre><code>\r
5598 Ext.Element.boxMarkup =\r
5599     &#39;&lt;div class="{0}-tl">&lt;div class="{0}-tr">&lt;div class="{0}-tc">&lt;/div>&lt;/div>&lt;/div>\r
5600      &lt;div class="{0}-ml">&lt;div class="{0}-mr">&lt;div class="{0}-mc">&lt;/div>&lt;/div>&lt;/div>\r
5601      &lt;div class="{0}-bl">&lt;div class="{0}-br">&lt;div class="{0}-bc">&lt;/div>&lt;/div>&lt;/div>&#39;;\r
5602                 * </code></pre>\r
5603                 * <p>Example usage:</p>\r
5604                 * <pre><code>\r
5605 // Basic box wrap\r
5606 Ext.get("foo").boxWrap();\r
5607 \r
5608 // You can also add a custom class and use CSS inheritance rules to customize the box look.\r
5609 // 'x-box-blue' is a built-in alternative -- look at the related CSS definitions as an example\r
5610 // for how to create a custom box wrap style.\r
5611 Ext.get("foo").boxWrap().addClass("x-box-blue");\r
5612                 * </code></pre>\r
5613                 * @param {String} class (optional) A base CSS class to apply to the containing wrapper element\r
5614                 * (defaults to <tt>'x-box'</tt>). Note that there are a number of CSS rules that are dependent on\r
5615                 * this name to make the overall effect work, so if you supply an alternate base class, make sure you\r
5616                 * also supply all of the necessary rules.\r
5617                 * @return {Ext.Element} this\r
5618                 */\r
5619             boxWrap : function(cls){\r
5620                 cls = cls || 'x-box';\r
5621                 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)));\r
5622                 Ext.DomQuery.selectNode('.' + cls + '-mc', el.dom).appendChild(this.dom);\r
5623                 return el;\r
5624             },\r
5625 \r
5626         /**\r
5627          * Set the size of this Element. If animation is true, both width and height will be animated concurrently.\r
5628          * @param {Mixed} width The new width. This may be one of:<div class="mdetail-params"><ul>\r
5629          * <li>A Number specifying the new width in this Element's {@link #defaultUnit}s (by default, pixels).</li>\r
5630          * <li>A String used to set the CSS width style. Animation may <b>not</b> be used.\r
5631          * <li>A size object in the format <code>{width: widthValue, height: heightValue}</code>.</li>\r
5632          * </ul></div>\r
5633          * @param {Mixed} height The new height. This may be one of:<div class="mdetail-params"><ul>\r
5634          * <li>A Number specifying the new height in this Element's {@link #defaultUnit}s (by default, pixels).</li>\r
5635          * <li>A String used to set the CSS height style. Animation may <b>not</b> be used.</li>\r
5636          * </ul></div>\r
5637          * @param {Boolean/Object} animate (optional) true for the default animation or a standard Element animation config object\r
5638          * @return {Ext.Element} this\r
5639          */\r
5640             setSize : function(width, height, animate){\r
5641                         var me = this;\r
5642                         if(Ext.isObject(width)){ // in case of object from getSize()\r
5643                             height = width.height;\r
5644                             width = width.width;\r
5645                         }\r
5646                         width = me.adjustWidth(width);\r
5647                         height = me.adjustHeight(height);\r
5648                         if(!animate || !me.anim){\r
5649                             me.dom.style.width = me.addUnits(width);\r
5650                             me.dom.style.height = me.addUnits(height);\r
5651                         }else{\r
5652                             me.anim({width: {to: width}, height: {to: height}}, me.preanim(arguments, 2));\r
5653                         }\r
5654                         return me;\r
5655             },\r
5656 \r
5657             /**\r
5658              * Returns either the offsetHeight or the height of this element based on CSS height adjusted by padding or borders\r
5659              * when needed to simulate offsetHeight when offsets aren't available. This may not work on display:none elements\r
5660              * if a height has not been set using CSS.\r
5661              * @return {Number}\r
5662              */\r
5663             getComputedHeight : function(){\r
5664                     var me = this,\r
5665                         h = Math.max(me.dom.offsetHeight, me.dom.clientHeight);\r
5666                 if(!h){\r
5667                     h = parseInt(me.getStyle('height'), 10) || 0;\r
5668                     if(!me.isBorderBox()){\r
5669                         h += me.getFrameWidth('tb');\r
5670                     }\r
5671                 }\r
5672                 return h;\r
5673             },\r
5674 \r
5675             /**\r
5676              * Returns either the offsetWidth or the width of this element based on CSS width adjusted by padding or borders\r
5677              * when needed to simulate offsetWidth when offsets aren't available. This may not work on display:none elements\r
5678              * if a width has not been set using CSS.\r
5679              * @return {Number}\r
5680              */\r
5681             getComputedWidth : function(){\r
5682                 var w = Math.max(this.dom.offsetWidth, this.dom.clientWidth);\r
5683                 if(!w){\r
5684                     w = parseInt(this.getStyle('width'), 10) || 0;\r
5685                     if(!this.isBorderBox()){\r
5686                         w += this.getFrameWidth('lr');\r
5687                     }\r
5688                 }\r
5689                 return w;\r
5690             },\r
5691 \r
5692             /**\r
5693              * Returns the sum width of the padding and borders for the passed "sides". See getBorderWidth()\r
5694              for more information about the sides.\r
5695              * @param {String} sides\r
5696              * @return {Number}\r
5697              */\r
5698             getFrameWidth : function(sides, onlyContentBox){\r
5699                 return onlyContentBox && this.isBorderBox() ? 0 : (this.getPadding(sides) + this.getBorderWidth(sides));\r
5700             },\r
5701 \r
5702             /**\r
5703              * Sets up event handlers to add and remove a css class when the mouse is over this element\r
5704              * @param {String} className\r
5705              * @return {Ext.Element} this\r
5706              */\r
5707             addClassOnOver : function(className){\r
5708                 this.hover(\r
5709                     function(){\r
5710                         Ext.fly(this, INTERNAL).addClass(className);\r
5711                     },\r
5712                     function(){\r
5713                         Ext.fly(this, INTERNAL).removeClass(className);\r
5714                     }\r
5715                 );\r
5716                 return this;\r
5717             },\r
5718 \r
5719             /**\r
5720              * Sets up event handlers to add and remove a css class when this element has the focus\r
5721              * @param {String} className\r
5722              * @return {Ext.Element} this\r
5723              */\r
5724             addClassOnFocus : function(className){\r
5725                     this.on("focus", function(){\r
5726                         Ext.fly(this, INTERNAL).addClass(className);\r
5727                     }, this.dom);\r
5728                     this.on("blur", function(){\r
5729                         Ext.fly(this, INTERNAL).removeClass(className);\r
5730                     }, this.dom);\r
5731                     return this;\r
5732             },\r
5733 \r
5734             /**\r
5735              * 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)\r
5736              * @param {String} className\r
5737              * @return {Ext.Element} this\r
5738              */\r
5739             addClassOnClick : function(className){\r
5740                 var dom = this.dom;\r
5741                 this.on("mousedown", function(){\r
5742                     Ext.fly(dom, INTERNAL).addClass(className);\r
5743                     var d = Ext.getDoc(),\r
5744                         fn = function(){\r
5745                                 Ext.fly(dom, INTERNAL).removeClass(className);\r
5746                                 d.removeListener("mouseup", fn);\r
5747                             };\r
5748                     d.on("mouseup", fn);\r
5749                 });\r
5750                 return this;\r
5751             },\r
5752 \r
5753             /**\r
5754              * Returns the width and height of the viewport.\r
5755         * <pre><code>\r
5756         var vpSize = Ext.getBody().getViewSize();\r
5757 \r
5758         // all Windows created afterwards will have a default value of 90% height and 95% width\r
5759         Ext.Window.override({\r
5760             width: vpSize.width * 0.9,\r
5761             height: vpSize.height * 0.95\r
5762         });\r
5763         // To handle window resizing you would have to hook onto onWindowResize.\r
5764         </code></pre>\r
5765              * @return {Object} An object containing the viewport's size {width: (viewport width), height: (viewport height)}\r
5766              */\r
5767             getViewSize : function(){\r
5768                 var doc = document,\r
5769                         d = this.dom,\r
5770                         extdom = Ext.lib.Dom,\r
5771                         isDoc = (d == doc || d == doc.body);\r
5772                 return { width : (isDoc ? extdom.getViewWidth() : d.clientWidth),\r
5773                                  height : (isDoc ? extdom.getViewHeight() : d.clientHeight) };\r
5774             },\r
5775 \r
5776             /**\r
5777              * Returns the size of the element.\r
5778              * @param {Boolean} contentSize (optional) true to get the width/size minus borders and padding\r
5779              * @return {Object} An object containing the element's size {width: (element width), height: (element height)}\r
5780              */\r
5781             getSize : function(contentSize){\r
5782                 return {width: this.getWidth(contentSize), height: this.getHeight(contentSize)};\r
5783             },\r
5784 \r
5785             /**\r
5786              * Forces the browser to repaint this element\r
5787              * @return {Ext.Element} this\r
5788              */\r
5789             repaint : function(){\r
5790                 var dom = this.dom;\r
5791                 this.addClass("x-repaint");\r
5792                 setTimeout(function(){\r
5793                     Ext.fly(dom).removeClass("x-repaint");\r
5794                 }, 1);\r
5795                 return this;\r
5796             },\r
5797 \r
5798             /**\r
5799              * Disables text selection for this element (normalized across browsers)\r
5800              * @return {Ext.Element} this\r
5801              */\r
5802             unselectable : function(){\r
5803                 this.dom.unselectable = "on";\r
5804                 return this.swallowEvent("selectstart", true).\r
5805                                     applyStyles("-moz-user-select:none;-khtml-user-select:none;").\r
5806                                     addClass("x-unselectable");\r
5807             },\r
5808 \r
5809             /**\r
5810              * Returns an object with properties top, left, right and bottom representing the margins of this element unless sides is passed,\r
5811              * then it returns the calculated width of the sides (see getPadding)\r
5812              * @param {String} sides (optional) Any combination of l, r, t, b to get the sum of those sides\r
5813              * @return {Object/Number}\r
5814              */\r
5815             getMargins : function(side){\r
5816                     var me = this,\r
5817                         key,\r
5818                         hash = {t:"top", l:"left", r:"right", b: "bottom"},\r
5819                         o = {};\r
5820 \r
5821                     if (!side) {\r
5822                         for (key in me.margins){\r
5823                                 o[hash[key]] = parseInt(me.getStyle(me.margins[key]), 10) || 0;\r
5824                 }\r
5825                         return o;\r
5826                 } else {\r
5827                     return me.addStyles.call(me, side, me.margins);\r
5828                 }\r
5829             }\r
5830     };\r
5831 }());/**\r
5832  * @class Ext.Element\r
5833  */\r
5834 (function(){\r
5835 var D = Ext.lib.Dom,\r
5836         LEFT = "left",\r
5837         RIGHT = "right",\r
5838         TOP = "top",\r
5839         BOTTOM = "bottom",\r
5840         POSITION = "position",\r
5841         STATIC = "static",\r
5842         RELATIVE = "relative",\r
5843         AUTO = "auto",\r
5844         ZINDEX = "z-index";\r
5845 \r
5846 function animTest(args, animate, i) {\r
5847         return this.preanim && !!animate ? this.preanim(args, i) : false        \r
5848 }\r
5849 \r
5850 Ext.Element.addMethods({\r
5851         /**\r
5852       * 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).\r
5853       * @return {Number} The X position of the element\r
5854       */\r
5855     getX : function(){\r
5856         return D.getX(this.dom);\r
5857     },\r
5858 \r
5859     /**\r
5860       * 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).\r
5861       * @return {Number} The Y position of the element\r
5862       */\r
5863     getY : function(){\r
5864         return D.getY(this.dom);\r
5865     },\r
5866 \r
5867     /**\r
5868       * 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).\r
5869       * @return {Array} The XY position of the element\r
5870       */\r
5871     getXY : function(){\r
5872         return D.getXY(this.dom);\r
5873     },\r
5874 \r
5875     /**\r
5876       * 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.\r
5877       * @param {Mixed} element The element to get the offsets from.\r
5878       * @return {Array} The XY page offsets (e.g. [100, -200])\r
5879       */\r
5880     getOffsetsTo : function(el){\r
5881         var o = this.getXY(),\r
5882                 e = Ext.fly(el, '_internal').getXY();\r
5883         return [o[0]-e[0],o[1]-e[1]];\r
5884     },\r
5885 \r
5886     /**\r
5887      * 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).\r
5888      * @param {Number} The X position of the element\r
5889      * @param {Boolean/Object} animate (optional) True for the default animation, or a standard Element animation config object\r
5890      * @return {Ext.Element} this\r
5891      */\r
5892     setX : function(x, animate){            \r
5893             return this.setXY([x, this.getY()], animTest.call(this, arguments, animate, 1));\r
5894     },\r
5895 \r
5896     /**\r
5897      * 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).\r
5898      * @param {Number} The Y position of the element\r
5899      * @param {Boolean/Object} animate (optional) True for the default animation, or a standard Element animation config object\r
5900      * @return {Ext.Element} this\r
5901      */\r
5902     setY : function(y, animate){            \r
5903             return this.setXY([this.getX(), y], animTest.call(this, arguments, animate, 1));\r
5904     },\r
5905 \r
5906     /**\r
5907      * Sets the element's left position directly using CSS style (instead of {@link #setX}).\r
5908      * @param {String} left The left CSS property value\r
5909      * @return {Ext.Element} this\r
5910      */\r
5911     setLeft : function(left){\r
5912         this.setStyle(LEFT, this.addUnits(left));\r
5913         return this;\r
5914     },\r
5915 \r
5916     /**\r
5917      * Sets the element's top position directly using CSS style (instead of {@link #setY}).\r
5918      * @param {String} top The top CSS property value\r
5919      * @return {Ext.Element} this\r
5920      */\r
5921     setTop : function(top){\r
5922         this.setStyle(TOP, this.addUnits(top));\r
5923         return this;\r
5924     },\r
5925 \r
5926     /**\r
5927      * Sets the element's CSS right style.\r
5928      * @param {String} right The right CSS property value\r
5929      * @return {Ext.Element} this\r
5930      */\r
5931     setRight : function(right){\r
5932         this.setStyle(RIGHT, this.addUnits(right));\r
5933         return this;\r
5934     },\r
5935 \r
5936     /**\r
5937      * Sets the element's CSS bottom style.\r
5938      * @param {String} bottom The bottom CSS property value\r
5939      * @return {Ext.Element} this\r
5940      */\r
5941     setBottom : function(bottom){\r
5942         this.setStyle(BOTTOM, this.addUnits(bottom));\r
5943         return this;\r
5944     },\r
5945 \r
5946     /**\r
5947      * Sets the position of the element in page coordinates, regardless of how the element is positioned.\r
5948      * The element must be part of the DOM tree to have page coordinates (display:none or elements not appended return false).\r
5949      * @param {Array} pos Contains X & Y [x, y] values for new position (coordinates are page-based)\r
5950      * @param {Boolean/Object} animate (optional) True for the default animation, or a standard Element animation config object\r
5951      * @return {Ext.Element} this\r
5952      */\r
5953     setXY : function(pos, animate){\r
5954             var me = this;\r
5955         if(!animate || !me.anim){\r
5956             D.setXY(me.dom, pos);\r
5957         }else{\r
5958             me.anim({points: {to: pos}}, me.preanim(arguments, 1), 'motion');\r
5959         }\r
5960         return me;\r
5961     },\r
5962 \r
5963     /**\r
5964      * Sets the position of the element in page coordinates, regardless of how the element is positioned.\r
5965      * The element must be part of the DOM tree to have page coordinates (display:none or elements not appended return false).\r
5966      * @param {Number} x X value for new position (coordinates are page-based)\r
5967      * @param {Number} y Y value for new position (coordinates are page-based)\r
5968      * @param {Boolean/Object} animate (optional) True for the default animation, or a standard Element animation config object\r
5969      * @return {Ext.Element} this\r
5970      */\r
5971     setLocation : function(x, y, animate){\r
5972         return this.setXY([x, y], animTest.call(this, arguments, animate, 2));\r
5973     },\r
5974 \r
5975     /**\r
5976      * Sets the position of the element in page coordinates, regardless of how the element is positioned.\r
5977      * The element must be part of the DOM tree to have page coordinates (display:none or elements not appended return false).\r
5978      * @param {Number} x X value for new position (coordinates are page-based)\r
5979      * @param {Number} y Y value for new position (coordinates are page-based)\r
5980      * @param {Boolean/Object} animate (optional) True for the default animation, or a standard Element animation config object\r
5981      * @return {Ext.Element} this\r
5982      */\r
5983     moveTo : function(x, y, animate){\r
5984         return this.setXY([x, y], animTest.call(this, arguments, animate, 2));        \r
5985     },    \r
5986     \r
5987     /**\r
5988      * Gets the left X coordinate\r
5989      * @param {Boolean} local True to get the local css position instead of page coordinate\r
5990      * @return {Number}\r
5991      */\r
5992     getLeft : function(local){\r
5993             return !local ? this.getX() : parseInt(this.getStyle(LEFT), 10) || 0;\r
5994     },\r
5995 \r
5996     /**\r
5997      * Gets the right X coordinate of the element (element X position + element width)\r
5998      * @param {Boolean} local True to get the local css position instead of page coordinate\r
5999      * @return {Number}\r
6000      */\r
6001     getRight : function(local){\r
6002             var me = this;\r
6003             return !local ? me.getX() + me.getWidth() : (me.getLeft(true) + me.getWidth()) || 0;\r
6004     },\r
6005 \r
6006     /**\r
6007      * Gets the top Y coordinate\r
6008      * @param {Boolean} local True to get the local css position instead of page coordinate\r
6009      * @return {Number}\r
6010      */\r
6011     getTop : function(local) {\r
6012             return !local ? this.getY() : parseInt(this.getStyle(TOP), 10) || 0;\r
6013     },\r
6014 \r
6015     /**\r
6016      * Gets the bottom Y coordinate of the element (element Y position + element height)\r
6017      * @param {Boolean} local True to get the local css position instead of page coordinate\r
6018      * @return {Number}\r
6019      */\r
6020     getBottom : function(local){\r
6021             var me = this;\r
6022             return !local ? me.getY() + me.getHeight() : (me.getTop(true) + me.getHeight()) || 0;\r
6023     },\r
6024 \r
6025     /**\r
6026     * Initializes positioning on this element. If a desired position is not passed, it will make the\r
6027     * the element positioned relative IF it is not already positioned.\r
6028     * @param {String} pos (optional) Positioning to use "relative", "absolute" or "fixed"\r
6029     * @param {Number} zIndex (optional) The zIndex to apply\r
6030     * @param {Number} x (optional) Set the page X position\r
6031     * @param {Number} y (optional) Set the page Y position\r
6032     */\r
6033     position : function(pos, zIndex, x, y){\r
6034             var me = this;\r
6035             \r
6036         if(!pos && me.isStyle(POSITION, STATIC)){           \r
6037             me.setStyle(POSITION, RELATIVE);           \r
6038         } else if(pos) {\r
6039             me.setStyle(POSITION, pos);\r
6040         }\r
6041         if(zIndex){\r
6042             me.setStyle(ZINDEX, zIndex);\r
6043         }\r
6044         if(x || y) me.setXY([x || false, y || false]);\r
6045     },\r
6046 \r
6047     /**\r
6048     * Clear positioning back to the default when the document was loaded\r
6049     * @param {String} value (optional) The value to use for the left,right,top,bottom, defaults to '' (empty string). You could use 'auto'.\r
6050     * @return {Ext.Element} this\r
6051      */\r
6052     clearPositioning : function(value){\r
6053         value = value || '';\r
6054         this.setStyle({\r
6055             left : value,\r
6056             right : value,\r
6057             top : value,\r
6058             bottom : value,\r
6059             "z-index" : "",\r
6060             position : STATIC\r
6061         });\r
6062         return this;\r
6063     },\r
6064 \r
6065     /**\r
6066     * Gets an object with all CSS positioning properties. Useful along with setPostioning to get\r
6067     * snapshot before performing an update and then restoring the element.\r
6068     * @return {Object}\r
6069     */\r
6070     getPositioning : function(){\r
6071         var l = this.getStyle(LEFT);\r
6072         var t = this.getStyle(TOP);\r
6073         return {\r
6074             "position" : this.getStyle(POSITION),\r
6075             "left" : l,\r
6076             "right" : l ? "" : this.getStyle(RIGHT),\r
6077             "top" : t,\r
6078             "bottom" : t ? "" : this.getStyle(BOTTOM),\r
6079             "z-index" : this.getStyle(ZINDEX)\r
6080         };\r
6081     },\r
6082     \r
6083     /**\r
6084     * Set positioning with an object returned by getPositioning().\r
6085     * @param {Object} posCfg\r
6086     * @return {Ext.Element} this\r
6087      */\r
6088     setPositioning : function(pc){\r
6089             var me = this,\r
6090                 style = me.dom.style;\r
6091                 \r
6092         me.setStyle(pc);\r
6093         \r
6094         if(pc.right == AUTO){\r
6095             style.right = "";\r
6096         }\r
6097         if(pc.bottom == AUTO){\r
6098             style.bottom = "";\r
6099         }\r
6100         \r
6101         return me;\r
6102     },    \r
6103         \r
6104     /**\r
6105      * Translates the passed page coordinates into left/top css values for this element\r
6106      * @param {Number/Array} x The page x or an array containing [x, y]\r
6107      * @param {Number} y (optional) The page y, required if x is not an array\r
6108      * @return {Object} An object with left and top properties. e.g. {left: (value), top: (value)}\r
6109      */\r
6110     translatePoints : function(x, y){                \r
6111             y = isNaN(x[1]) ? y : x[1];\r
6112         x = isNaN(x[0]) ? x : x[0];\r
6113         var me = this,\r
6114                 relative = me.isStyle(POSITION, RELATIVE),\r
6115                 o = me.getXY(),\r
6116                 l = parseInt(me.getStyle(LEFT), 10),\r
6117                 t = parseInt(me.getStyle(TOP), 10);\r
6118         \r
6119         l = !isNaN(l) ? l : (relative ? 0 : me.dom.offsetLeft);\r
6120         t = !isNaN(t) ? t : (relative ? 0 : me.dom.offsetTop);        \r
6121 \r
6122         return {left: (x - o[0] + l), top: (y - o[1] + t)}; \r
6123     },\r
6124     \r
6125     animTest : animTest\r
6126 });\r
6127 })();/**\r
6128  * @class Ext.Element\r
6129  */\r
6130 Ext.Element.addMethods({\r
6131     /**\r
6132      * 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.\r
6133      * @param {Object} box The box to fill {x, y, width, height}\r
6134      * @param {Boolean} adjust (optional) Whether to adjust for box-model issues automatically\r
6135      * @param {Boolean/Object} animate (optional) true for the default animation or a standard Element animation config object\r
6136      * @return {Ext.Element} this\r
6137      */\r
6138     setBox : function(box, adjust, animate){\r
6139         var me = this,\r
6140                 w = box.width, \r
6141                 h = box.height;\r
6142         if((adjust && !me.autoBoxAdjust) && !me.isBorderBox()){\r
6143            w -= (me.getBorderWidth("lr") + me.getPadding("lr"));\r
6144            h -= (me.getBorderWidth("tb") + me.getPadding("tb"));\r
6145         }\r
6146         me.setBounds(box.x, box.y, w, h, me.animTest.call(me, arguments, animate, 2));\r
6147         return me;\r
6148     },\r
6149     \r
6150     /**\r
6151      * Return a box {x, y, width, height} that can be used to set another elements\r
6152      * size/location to match this element.\r
6153      * @param {Boolean} contentBox (optional) If true a box for the content of the element is returned.\r
6154      * @param {Boolean} local (optional) If true the element's left and top are returned instead of page x/y.\r
6155      * @return {Object} box An object in the format {x, y, width, height}\r
6156      */\r
6157         getBox : function(contentBox, local) {      \r
6158             var me = this,\r
6159                 xy,\r
6160                 left,\r
6161                 top,\r
6162                 getBorderWidth = me.getBorderWidth,\r
6163                 getPadding = me.getPadding, \r
6164                 l,\r
6165                 r,\r
6166                 t,\r
6167                 b;\r
6168         if(!local){\r
6169             xy = me.getXY();\r
6170         }else{\r
6171             left = parseInt(me.getStyle("left"), 10) || 0;\r
6172             top = parseInt(me.getStyle("top"), 10) || 0;\r
6173             xy = [left, top];\r
6174         }\r
6175         var el = me.dom, w = el.offsetWidth, h = el.offsetHeight, bx;\r
6176         if(!contentBox){\r
6177             bx = {x: xy[0], y: xy[1], 0: xy[0], 1: xy[1], width: w, height: h};\r
6178         }else{\r
6179             l = getBorderWidth.call(me, "l") + getPadding.call(me, "l");\r
6180             r = getBorderWidth.call(me, "r") + getPadding.call(me, "r");\r
6181             t = getBorderWidth.call(me, "t") + getPadding.call(me, "t");\r
6182             b = getBorderWidth.call(me, "b") + getPadding.call(me, "b");\r
6183             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)};\r
6184         }\r
6185         bx.right = bx.x + bx.width;\r
6186         bx.bottom = bx.y + bx.height;\r
6187         return bx;\r
6188         },\r
6189         \r
6190     /**\r
6191      * Move this element relative to its current position.\r
6192      * @param {String} direction Possible values are: "l" (or "left"), "r" (or "right"), "t" (or "top", or "up"), "b" (or "bottom", or "down").\r
6193      * @param {Number} distance How far to move the element in pixels\r
6194      * @param {Boolean/Object} animate (optional) true for the default animation or a standard Element animation config object\r
6195      * @return {Ext.Element} this\r
6196      */\r
6197      move : function(direction, distance, animate){\r
6198         var me = this,          \r
6199                 xy = me.getXY(),\r
6200                 x = xy[0],\r
6201                 y = xy[1],              \r
6202                 left = [x - distance, y],\r
6203                 right = [x + distance, y],\r
6204                 top = [x, y - distance],\r
6205                 bottom = [x, y + distance],\r
6206                 hash = {\r
6207                         l :     left,\r
6208                         left : left,\r
6209                         r : right,\r
6210                         right : right,\r
6211                         t : top,\r
6212                         top : top,\r
6213                         up : top,\r
6214                         b : bottom, \r
6215                         bottom : bottom,\r
6216                         down : bottom                           \r
6217                 };\r
6218         \r
6219             direction = direction.toLowerCase();    \r
6220             me.moveTo(hash[direction][0], hash[direction][1], me.animTest.call(me, arguments, animate, 2));\r
6221     },\r
6222     \r
6223     /**\r
6224      * Quick set left and top adding default units\r
6225      * @param {String} left The left CSS property value\r
6226      * @param {String} top The top CSS property value\r
6227      * @return {Ext.Element} this\r
6228      */\r
6229      setLeftTop : function(left, top){\r
6230             var me = this,\r
6231                 style = me.dom.style;\r
6232         style.left = me.addUnits(left);\r
6233         style.top = me.addUnits(top);\r
6234         return me;\r
6235     },\r
6236     \r
6237     /**\r
6238      * Returns the region of the given element.\r
6239      * The element must be part of the DOM tree to have a region (display:none or elements not appended return false).\r
6240      * @return {Region} A Ext.lib.Region containing "top, left, bottom, right" member data.\r
6241      */\r
6242     getRegion : function(){\r
6243         return Ext.lib.Dom.getRegion(this.dom);\r
6244     },\r
6245     \r
6246     /**\r
6247      * Sets the element's position and size in one shot. If animation is true then width, height, x and y will be animated concurrently.\r
6248      * @param {Number} x X value for new position (coordinates are page-based)\r
6249      * @param {Number} y Y value for new position (coordinates are page-based)\r
6250      * @param {Mixed} width The new width. This may be one of:<div class="mdetail-params"><ul>\r
6251      * <li>A Number specifying the new width in this Element's {@link #defaultUnit}s (by default, pixels)</li>\r
6252      * <li>A String used to set the CSS width style. Animation may <b>not</b> be used.\r
6253      * </ul></div>\r
6254      * @param {Mixed} height The new height. This may be one of:<div class="mdetail-params"><ul>\r
6255      * <li>A Number specifying the new height in this Element's {@link #defaultUnit}s (by default, pixels)</li>\r
6256      * <li>A String used to set the CSS height style. Animation may <b>not</b> be used.</li>\r
6257      * </ul></div>\r
6258      * @param {Boolean/Object} animate (optional) true for the default animation or a standard Element animation config object\r
6259      * @return {Ext.Element} this\r
6260      */\r
6261     setBounds : function(x, y, width, height, animate){\r
6262             var me = this;\r
6263         if (!animate || !me.anim) {\r
6264             me.setSize(width, height);\r
6265             me.setLocation(x, y);\r
6266         } else {\r
6267             me.anim({points: {to: [x, y]}, \r
6268                          width: {to: me.adjustWidth(width)}, \r
6269                          height: {to: me.adjustHeight(height)}},\r
6270                      me.preanim(arguments, 4), \r
6271                      'motion');\r
6272         }\r
6273         return me;\r
6274     },\r
6275 \r
6276     /**\r
6277      * Sets the element's position and size the specified region. If animation is true then width, height, x and y will be animated concurrently.\r
6278      * @param {Ext.lib.Region} region The region to fill\r
6279      * @param {Boolean/Object} animate (optional) true for the default animation or a standard Element animation config object\r
6280      * @return {Ext.Element} this\r
6281      */\r
6282     setRegion : function(region, animate) {\r
6283         return this.setBounds(region.left, region.top, region.right-region.left, region.bottom-region.top, this.animTest.call(this, arguments, animate, 1));\r
6284     }\r
6285 });/**\r
6286  * @class Ext.Element\r
6287  */\r
6288 Ext.Element.addMethods({\r
6289     /**\r
6290      * Returns true if this element is scrollable.\r
6291      * @return {Boolean}\r
6292      */\r
6293     isScrollable : function(){\r
6294         var dom = this.dom;\r
6295         return dom.scrollHeight > dom.clientHeight || dom.scrollWidth > dom.clientWidth;\r
6296     },\r
6297 \r
6298     /**\r
6299      * 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().\r
6300      * @param {String} side Either "left" for scrollLeft values or "top" for scrollTop values.\r
6301      * @param {Number} value The new scroll value.\r
6302      * @return {Element} this\r
6303      */\r
6304     scrollTo : function(side, value){\r
6305         this.dom["scroll" + (/top/i.test(side) ? "Top" : "Left")] = value;\r
6306         return this;\r
6307     },\r
6308 \r
6309     /**\r
6310      * Returns the current scroll position of the element.\r
6311      * @return {Object} An object containing the scroll position in the format {left: (scrollLeft), top: (scrollTop)}\r
6312      */\r
6313     getScroll : function(){\r
6314         var d = this.dom, \r
6315             doc = document,\r
6316             body = doc.body,\r
6317             docElement = doc.documentElement,\r
6318             l,\r
6319             t,\r
6320             ret;\r
6321 \r
6322         if(d == doc || d == body){\r
6323             if(Ext.isIE && Ext.isStrict){\r
6324                 l = docElement.scrollLeft; \r
6325                 t = docElement.scrollTop;\r
6326             }else{\r
6327                 l = window.pageXOffset;\r
6328                 t = window.pageYOffset;\r
6329             }\r
6330             ret = {left: l || (body ? body.scrollLeft : 0), top: t || (body ? body.scrollTop : 0)};\r
6331         }else{\r
6332             ret = {left: d.scrollLeft, top: d.scrollTop};\r
6333         }\r
6334         return ret;\r
6335     }\r
6336 });/**\r
6337  * @class Ext.Element\r
6338  */\r
6339 Ext.Element.addMethods({\r
6340     /**\r
6341      * 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().\r
6342      * @param {String} side Either "left" for scrollLeft values or "top" for scrollTop values.\r
6343      * @param {Number} value The new scroll value\r
6344      * @param {Boolean/Object} animate (optional) true for the default animation or a standard Element animation config object\r
6345      * @return {Element} this\r
6346      */\r
6347     scrollTo : function(side, value, animate){\r
6348         var tester = /top/i,\r
6349                 prop = "scroll" + (tester.test(side) ? "Top" : "Left"),\r
6350                 me = this,\r
6351                 dom = me.dom;\r
6352         if (!animate || !me.anim) {\r
6353             dom[prop] = value;\r
6354         } else {\r
6355             me.anim({scroll: {to: tester.test(prop) ? [dom[prop], value] : [value, dom[prop]]}},\r
6356                          me.preanim(arguments, 2), 'scroll');\r
6357         }\r
6358         return me;\r
6359     },\r
6360     \r
6361     /**\r
6362      * Scrolls this element into view within the passed container.\r
6363      * @param {Mixed} container (optional) The container element to scroll (defaults to document.body).  Should be a\r
6364      * string (id), dom node, or Ext.Element.\r
6365      * @param {Boolean} hscroll (optional) False to disable horizontal scroll (defaults to true)\r
6366      * @return {Ext.Element} this\r
6367      */\r
6368     scrollIntoView : function(container, hscroll){\r
6369         var c = Ext.getDom(container) || Ext.getBody().dom,\r
6370                 el = this.dom,\r
6371                 o = this.getOffsetsTo(c),\r
6372             l = o[0] + c.scrollLeft,\r
6373             t = o[1] + c.scrollTop,\r
6374             b = t + el.offsetHeight,\r
6375             r = l + el.offsetWidth,\r
6376                 ch = c.clientHeight,\r
6377                 ct = parseInt(c.scrollTop, 10),\r
6378                 cl = parseInt(c.scrollLeft, 10),\r
6379                 cb = ct + ch,\r
6380                 cr = cl + c.clientWidth;\r
6381 \r
6382         if (el.offsetHeight > ch || t < ct) {\r
6383                 c.scrollTop = t;\r
6384         } else if (b > cb){\r
6385             c.scrollTop = b-ch;\r
6386         }\r
6387         c.scrollTop = c.scrollTop; // corrects IE, other browsers will ignore\r
6388 \r
6389         if(hscroll !== false){\r
6390                         if(el.offsetWidth > c.clientWidth || l < cl){\r
6391                 c.scrollLeft = l;\r
6392             }else if(r > cr){\r
6393                 c.scrollLeft = r - c.clientWidth;\r
6394             }\r
6395             c.scrollLeft = c.scrollLeft;\r
6396         }\r
6397         return this;\r
6398     },\r
6399 \r
6400     // private\r
6401     scrollChildIntoView : function(child, hscroll){\r
6402         Ext.fly(child, '_scrollChildIntoView').scrollIntoView(this, hscroll);\r
6403     },\r
6404     \r
6405     /**\r
6406      * Scrolls this element the specified direction. Does bounds checking to make sure the scroll is\r
6407      * within this element's scrollable range.\r
6408      * @param {String} direction Possible values are: "l" (or "left"), "r" (or "right"), "t" (or "top", or "up"), "b" (or "bottom", or "down").\r
6409      * @param {Number} distance How far to scroll the element in pixels\r
6410      * @param {Boolean/Object} animate (optional) true for the default animation or a standard Element animation config object\r
6411      * @return {Boolean} Returns true if a scroll was triggered or false if the element\r
6412      * was scrolled as far as it could go.\r
6413      */\r
6414      scroll : function(direction, distance, animate){\r
6415          if(!this.isScrollable()){\r
6416              return;\r
6417          }\r
6418          var el = this.dom,\r
6419             l = el.scrollLeft, t = el.scrollTop,\r
6420             w = el.scrollWidth, h = el.scrollHeight,\r
6421             cw = el.clientWidth, ch = el.clientHeight,\r
6422             scrolled = false, v,\r
6423             hash = {\r
6424                 l: Math.min(l + distance, w-cw),\r
6425                 r: v = Math.max(l - distance, 0),\r
6426                 t: Math.max(t - distance, 0),\r
6427                 b: Math.min(t + distance, h-ch)\r
6428             };\r
6429             hash.d = hash.b;\r
6430             hash.u = hash.t;\r
6431             \r
6432          direction = direction.substr(0, 1);\r
6433          if((v = hash[direction]) > -1){\r
6434             scrolled = true;\r
6435             this.scrollTo(direction == 'l' || direction == 'r' ? 'left' : 'top', v, this.preanim(arguments, 2));\r
6436          }\r
6437          return scrolled;\r
6438     }\r
6439 });/**\r
6440  * @class Ext.Element\r
6441  */\r
6442 /**\r
6443  * Visibility mode constant for use with {@link #setVisibilityMode}. Use visibility to hide element\r
6444  * @static\r
6445  * @type Number\r
6446  */\r
6447 Ext.Element.VISIBILITY = 1;\r
6448 /**\r
6449  * Visibility mode constant for use with {@link #setVisibilityMode}. Use display to hide element\r
6450  * @static\r
6451  * @type Number\r
6452  */\r
6453 Ext.Element.DISPLAY = 2;\r
6454 \r
6455 Ext.Element.addMethods(function(){\r
6456     var VISIBILITY = "visibility",\r
6457         DISPLAY = "display",\r
6458         HIDDEN = "hidden",\r
6459         NONE = "none",      \r
6460         ORIGINALDISPLAY = 'originalDisplay',\r
6461         VISMODE = 'visibilityMode',\r
6462         ELDISPLAY = Ext.Element.DISPLAY,\r
6463         data = Ext.Element.data,\r
6464         getDisplay = function(dom){\r
6465             var d = data(dom, ORIGINALDISPLAY);\r
6466             if(d === undefined){\r
6467                 data(dom, ORIGINALDISPLAY, d = '');\r
6468             }\r
6469             return d;\r
6470         },\r
6471         getVisMode = function(dom){\r
6472             var m = data(dom, VISMODE);\r
6473             if(m === undefined){\r
6474                 data(dom, VISMODE, m = 1)\r
6475             }\r
6476             return m;\r
6477         };\r
6478     \r
6479     return {\r
6480         /**\r
6481          * The element's default display mode  (defaults to "")\r
6482          * @type String\r
6483          */\r
6484         originalDisplay : "",\r
6485         visibilityMode : 1,\r
6486         \r
6487         /**\r
6488          * Sets the element's visibility mode. When setVisible() is called it\r
6489          * will use this to determine whether to set the visibility or the display property.\r
6490          * @param visMode Ext.Element.VISIBILITY or Ext.Element.DISPLAY\r
6491          * @return {Ext.Element} this\r
6492          */\r
6493         setVisibilityMode : function(visMode){  \r
6494             data(this.dom, VISMODE, visMode);\r
6495             return this;\r
6496         },\r
6497         \r
6498         /**\r
6499          * Perform custom animation on this element.\r
6500          * <div><ul class="mdetail-params">\r
6501          * <li><u>Animation Properties</u></li>\r
6502          * \r
6503          * <p>The Animation Control Object enables gradual transitions for any member of an\r
6504          * element's style object that takes a numeric value including but not limited to\r
6505          * these properties:</p><div><ul class="mdetail-params">\r
6506          * <li><tt>bottom, top, left, right</tt></li>\r
6507          * <li><tt>height, width</tt></li>\r
6508          * <li><tt>margin, padding</tt></li>\r
6509          * <li><tt>borderWidth</tt></li>\r
6510          * <li><tt>opacity</tt></li>\r
6511          * <li><tt>fontSize</tt></li>\r
6512          * <li><tt>lineHeight</tt></li>\r
6513          * </ul></div>\r
6514          * \r
6515          * \r
6516          * <li><u>Animation Property Attributes</u></li>\r
6517          * \r
6518          * <p>Each Animation Property is a config object with optional properties:</p>\r
6519          * <div><ul class="mdetail-params">\r
6520          * <li><tt>by</tt>*  : relative change - start at current value, change by this value</li>\r
6521          * <li><tt>from</tt> : ignore current value, start from this value</li>\r
6522          * <li><tt>to</tt>*  : start at current value, go to this value</li>\r
6523          * <li><tt>unit</tt> : any allowable unit specification</li>\r
6524          * <p>* do not specify both <tt>to</tt> and <tt>by</tt> for an animation property</p>\r
6525          * </ul></div>\r
6526          * \r
6527          * <li><u>Animation Types</u></li>\r
6528          * \r
6529          * <p>The supported animation types:</p><div><ul class="mdetail-params">\r
6530          * <li><tt>'run'</tt> : Default\r
6531          * <pre><code>\r
6532 var el = Ext.get('complexEl');\r
6533 el.animate(\r
6534     // animation control object\r
6535     {\r
6536         borderWidth: {to: 3, from: 0},\r
6537         opacity: {to: .3, from: 1},\r
6538         height: {to: 50, from: el.getHeight()},\r
6539         width: {to: 300, from: el.getWidth()},\r
6540         top  : {by: - 100, unit: 'px'},\r
6541     },\r
6542     0.35,      // animation duration\r
6543     null,      // callback\r
6544     'easeOut', // easing method\r
6545     'run'      // animation type ('run','color','motion','scroll')    \r
6546 );\r
6547          * </code></pre>\r
6548          * </li>\r
6549          * <li><tt>'color'</tt>\r
6550          * <p>Animates transition of background, text, or border colors.</p>\r
6551          * <pre><code>\r
6552 el.animate(\r
6553     // animation control object\r
6554     {\r
6555         color: { to: '#06e' },\r
6556         backgroundColor: { to: '#e06' }\r
6557     },\r
6558     0.35,      // animation duration\r
6559     null,      // callback\r
6560     'easeOut', // easing method\r
6561     'color'    // animation type ('run','color','motion','scroll')    \r
6562 );\r
6563          * </code></pre> \r
6564          * </li>\r
6565          * \r
6566          * <li><tt>'motion'</tt>\r
6567          * <p>Animates the motion of an element to/from specific points using optional bezier\r
6568          * way points during transit.</p>\r
6569          * <pre><code>\r
6570 el.animate(\r
6571     // animation control object\r
6572     {\r
6573         borderWidth: {to: 3, from: 0},\r
6574         opacity: {to: .3, from: 1},\r
6575         height: {to: 50, from: el.getHeight()},\r
6576         width: {to: 300, from: el.getWidth()},\r
6577         top  : {by: - 100, unit: 'px'},\r
6578         points: {\r
6579             to: [50, 100],  // go to this point\r
6580             control: [      // optional bezier way points\r
6581                 [ 600, 800],\r
6582                 [-100, 200]\r
6583             ]\r
6584         }\r
6585     },\r
6586     3000,      // animation duration (milliseconds!)\r
6587     null,      // callback\r
6588     'easeOut', // easing method\r
6589     'motion'   // animation type ('run','color','motion','scroll')    \r
6590 );\r
6591          * </code></pre> \r
6592          * </li>\r
6593          * <li><tt>'scroll'</tt>\r
6594          * <p>Animate horizontal or vertical scrolling of an overflowing page element.</p>\r
6595          * <pre><code>\r
6596 el.animate(\r
6597     // animation control object\r
6598     {\r
6599         scroll: {to: [400, 300]}\r
6600     },\r
6601     0.35,      // animation duration\r
6602     null,      // callback\r
6603     'easeOut', // easing method\r
6604     'scroll'   // animation type ('run','color','motion','scroll')    \r
6605 );\r
6606          * </code></pre> \r
6607          * </li>\r
6608          * </ul></div>\r
6609          * \r
6610          * </ul></div>\r
6611          * \r
6612          * @param {Object} args The animation control args\r
6613          * @param {Float} duration (optional) How long the animation lasts in seconds (defaults to <tt>.35</tt>)\r
6614          * @param {Function} onComplete (optional) Function to call when animation completes\r
6615          * @param {String} easing (optional) {@link Ext.Fx#easing} method to use (defaults to <tt>'easeOut'</tt>)\r
6616          * @param {String} animType (optional) <tt>'run'</tt> is the default. Can also be <tt>'color'</tt>,\r
6617          * <tt>'motion'</tt>, or <tt>'scroll'</tt>\r
6618          * @return {Ext.Element} this\r
6619          */\r
6620         animate : function(args, duration, onComplete, easing, animType){       \r
6621             this.anim(args, {duration: duration, callback: onComplete, easing: easing}, animType);\r
6622             return this;\r
6623         },\r
6624     \r
6625         /*\r
6626          * @private Internal animation call\r
6627          */\r
6628         anim : function(args, opt, animType, defaultDur, defaultEase, cb){\r
6629             animType = animType || 'run';\r
6630             opt = opt || {};\r
6631             var me = this,              \r
6632                 anim = Ext.lib.Anim[animType](\r
6633                     me.dom, \r
6634                     args,\r
6635                     (opt.duration || defaultDur) || .35,\r
6636                     (opt.easing || defaultEase) || 'easeOut',\r
6637                     function(){\r
6638                         if(cb) cb.call(me);\r
6639                         if(opt.callback) opt.callback.call(opt.scope || me, me, opt);\r
6640                     },\r
6641                     me\r
6642                 );\r
6643             opt.anim = anim;\r
6644             return anim;\r
6645         },\r
6646     \r
6647         // private legacy anim prep\r
6648         preanim : function(a, i){\r
6649             return !a[i] ? false : (Ext.isObject(a[i]) ? a[i]: {duration: a[i+1], callback: a[i+2], easing: a[i+3]});\r
6650         },\r
6651         \r
6652         /**\r
6653          * Checks whether the element is currently visible using both visibility and display properties.         \r
6654          * @return {Boolean} True if the element is currently visible, else false\r
6655          */\r
6656         isVisible : function() {\r
6657             return !this.isStyle(VISIBILITY, HIDDEN) && !this.isStyle(DISPLAY, NONE);\r
6658         },\r
6659         \r
6660         /**\r
6661          * Sets the visibility of the element (see details). If the visibilityMode is set to Element.DISPLAY, it will use\r
6662          * the display property to hide the element, otherwise it uses visibility. The default is to hide and show using the visibility property.\r
6663          * @param {Boolean} visible Whether the element is visible\r
6664          * @param {Boolean/Object} animate (optional) True for the default animation, or a standard Element animation config object\r
6665          * @return {Ext.Element} this\r
6666          */\r
6667          setVisible : function(visible, animate){\r
6668             var me = this,\r
6669                 dom = me.dom,\r
6670                 isDisplay = getVisMode(this.dom) == ELDISPLAY;\r
6671                 \r
6672             if (!animate || !me.anim) {\r
6673                 if(isDisplay){\r
6674                     me.setDisplayed(visible);\r
6675                 }else{\r
6676                     me.fixDisplay();\r
6677                     dom.style.visibility = visible ? "visible" : HIDDEN;\r
6678                 }\r
6679             }else{\r
6680                 // closure for composites            \r
6681                 if(visible){\r
6682                     me.setOpacity(.01);\r
6683                     me.setVisible(true);\r
6684                 }\r
6685                 me.anim({opacity: { to: (visible?1:0) }},\r
6686                         me.preanim(arguments, 1),\r
6687                         null,\r
6688                         .35,\r
6689                         'easeIn',\r
6690                         function(){\r
6691                              if(!visible){\r
6692                                  dom.style[isDisplay ? DISPLAY : VISIBILITY] = (isDisplay) ? NONE : HIDDEN;                     \r
6693                                  Ext.fly(dom).setOpacity(1);\r
6694                              }\r
6695                         });\r
6696             }\r
6697             return me;\r
6698         },\r
6699     \r
6700         /**\r
6701          * Toggles the element's visibility or display, depending on visibility mode.\r
6702          * @param {Boolean/Object} animate (optional) True for the default animation, or a standard Element animation config object\r
6703          * @return {Ext.Element} this\r
6704          */\r
6705         toggle : function(animate){\r
6706             var me = this;\r
6707             me.setVisible(!me.isVisible(), me.preanim(arguments, 0));\r
6708             return me;\r
6709         },\r
6710     \r
6711         /**\r
6712          * Sets the CSS display property. Uses originalDisplay if the specified value is a boolean true.\r
6713          * @param {Mixed} value Boolean value to display the element using its default display, or a string to set the display directly.\r
6714          * @return {Ext.Element} this\r
6715          */\r
6716         setDisplayed : function(value) {            \r
6717             if(typeof value == "boolean"){\r
6718                value = value ? getDisplay(this.dom) : NONE;\r
6719             }\r
6720             this.setStyle(DISPLAY, value);\r
6721             return this;\r
6722         },\r
6723         \r
6724         // private\r
6725         fixDisplay : function(){\r
6726             var me = this;\r
6727             if(me.isStyle(DISPLAY, NONE)){\r
6728                 me.setStyle(VISIBILITY, HIDDEN);\r
6729                 me.setStyle(DISPLAY, getDisplay(this.dom)); // first try reverting to default\r
6730                 if(me.isStyle(DISPLAY, NONE)){ // if that fails, default to block\r
6731                     me.setStyle(DISPLAY, "block");\r
6732                 }\r
6733             }\r
6734         },\r
6735     \r
6736         /**\r
6737          * Hide this element - Uses display mode to determine whether to use "display" or "visibility". See {@link #setVisible}.\r
6738          * @param {Boolean/Object} animate (optional) true for the default animation or a standard Element animation config object\r
6739          * @return {Ext.Element} this\r
6740          */\r
6741         hide : function(animate){\r
6742             this.setVisible(false, this.preanim(arguments, 0));\r
6743             return this;\r
6744         },\r
6745     \r
6746         /**\r
6747         * Show this element - Uses display mode to determine whether to use "display" or "visibility". See {@link #setVisible}.\r
6748         * @param {Boolean/Object} animate (optional) true for the default animation or a standard Element animation config object\r
6749          * @return {Ext.Element} this\r
6750          */\r
6751         show : function(animate){\r
6752             this.setVisible(true, this.preanim(arguments, 0));\r
6753             return this;\r
6754         }\r
6755     }\r
6756 }());/**\r
6757  * @class Ext.Element\r
6758  */\r
6759 Ext.Element.addMethods(\r
6760 function(){\r
6761     var VISIBILITY = "visibility",\r
6762         DISPLAY = "display",\r
6763         HIDDEN = "hidden",\r
6764         NONE = "none",\r
6765             XMASKED = "x-masked",\r
6766                 XMASKEDRELATIVE = "x-masked-relative",\r
6767         data = Ext.Element.data;\r
6768                 \r
6769         return {\r
6770                 /**\r
6771              * Checks whether the element is currently visible using both visibility and display properties.\r
6772              * @param {Boolean} deep (optional) True to walk the dom and see if parent elements are hidden (defaults to false)\r
6773              * @return {Boolean} True if the element is currently visible, else false\r
6774              */\r
6775             isVisible : function(deep) {\r
6776                 var vis = !this.isStyle(VISIBILITY,HIDDEN) && !this.isStyle(DISPLAY,NONE),\r
6777                         p = this.dom.parentNode;\r
6778                 if(deep !== true || !vis){\r
6779                     return vis;\r
6780                 }               \r
6781                 while(p && !/body/i.test(p.tagName)){\r
6782                     if(!Ext.fly(p, '_isVisible').isVisible()){\r
6783                         return false;\r
6784                     }\r
6785                     p = p.parentNode;\r
6786                 }\r
6787                 return true;\r
6788             },\r
6789             \r
6790             /**\r
6791              * Returns true if display is not "none"\r
6792              * @return {Boolean}\r
6793              */\r
6794             isDisplayed : function() {\r
6795                 return !this.isStyle(DISPLAY, NONE);\r
6796             },\r
6797             \r
6798                 /**\r
6799              * Convenience method for setVisibilityMode(Element.DISPLAY)\r
6800              * @param {String} display (optional) What to set display to when visible\r
6801              * @return {Ext.Element} this\r
6802              */\r
6803             enableDisplayMode : function(display){          \r
6804                 this.setVisibilityMode(Ext.Element.DISPLAY);\r
6805                 if(!Ext.isEmpty(display)){\r
6806                 data(this.dom, 'originalDisplay', display);\r
6807             }\r
6808                 return this;\r
6809             },\r
6810             \r
6811                 /**\r
6812              * Puts a mask over this element to disable user interaction. Requires core.css.\r
6813              * This method can only be applied to elements which accept child nodes.\r
6814              * @param {String} msg (optional) A message to display in the mask\r
6815              * @param {String} msgCls (optional) A css class to apply to the msg element\r
6816              * @return {Element} The mask element\r
6817              */\r
6818             mask : function(msg, msgCls){\r
6819                     var me = this,\r
6820                         dom = me.dom,\r
6821                         dh = Ext.DomHelper,\r
6822                         EXTELMASKMSG = "ext-el-mask-msg",\r
6823                 el, \r
6824                 mask;\r
6825                         \r
6826                 if(me.getStyle("position") == "static"){\r
6827                     me.addClass(XMASKEDRELATIVE);\r
6828                 }\r
6829                 if((el = data(dom, 'maskMsg'))){\r
6830                     el.remove();\r
6831                 }\r
6832                 if((el = data(dom, 'mask'))){\r
6833                     el.remove();\r
6834                 }\r
6835         \r
6836             mask = dh.append(dom, {cls : "ext-el-mask"}, true);\r
6837                 data(dom, 'mask', mask);\r
6838         \r
6839                 me.addClass(XMASKED);\r
6840                 mask.setDisplayed(true);\r
6841                 if(typeof msg == 'string'){\r
6842                 var mm = dh.append(dom, {cls : EXTELMASKMSG, cn:{tag:'div'}}, true);\r
6843                 data(dom, 'maskMsg', mm);\r
6844                     mm.dom.className = msgCls ? EXTELMASKMSG + " " + msgCls : EXTELMASKMSG;\r
6845                     mm.dom.firstChild.innerHTML = msg;\r
6846                     mm.setDisplayed(true);\r
6847                     mm.center(me);\r
6848                 }\r
6849                 if(Ext.isIE && !(Ext.isIE7 && Ext.isStrict) && me.getStyle('height') == 'auto'){ // ie will not expand full height automatically\r
6850                     mask.setSize(undefined, me.getHeight());\r
6851                 }\r
6852                 return mask;\r
6853             },\r
6854         \r
6855             /**\r
6856              * Removes a previously applied mask.\r
6857              */\r
6858             unmask : function(){\r
6859                     var me = this,\r
6860                 dom = me.dom,\r
6861                         mask = data(dom, 'mask'),\r
6862                         maskMsg = data(dom, 'maskMsg');\r
6863                 if(mask){\r
6864                     if(maskMsg){\r
6865                         maskMsg.remove();\r
6866                     data(dom, 'maskMsg', undefined);\r
6867                     }\r
6868                     mask.remove();\r
6869                 data(dom, 'mask', undefined);\r
6870                 }\r
6871                 me.removeClass([XMASKED, XMASKEDRELATIVE]);\r
6872             },\r
6873         \r
6874             /**\r
6875              * Returns true if this element is masked\r
6876              * @return {Boolean}\r
6877              */\r
6878             isMasked : function(){\r
6879             var m = data(this.dom, 'mask');\r
6880                 return m && m.isVisible();\r
6881             },\r
6882             \r
6883             /**\r
6884              * Creates an iframe shim for this element to keep selects and other windowed objects from\r
6885              * showing through.\r
6886              * @return {Ext.Element} The new shim element\r
6887              */\r
6888             createShim : function(){\r
6889                 var el = document.createElement('iframe'),              \r
6890                         shim;\r
6891                 el.frameBorder = '0';\r
6892                 el.className = 'ext-shim';\r
6893                 if(Ext.isIE && Ext.isSecure){\r
6894                     el.src = Ext.SSL_SECURE_URL;\r
6895                 }\r
6896                 shim = Ext.get(this.dom.parentNode.insertBefore(el, this.dom));\r
6897                 shim.autoBoxAdjust = false;\r
6898                 return shim;\r
6899             }\r
6900     };\r
6901 }());/**\r
6902  * @class Ext.Element\r
6903  */\r
6904 Ext.Element.addMethods({\r
6905     /**\r
6906      * Convenience method for constructing a KeyMap\r
6907      * @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:\r
6908      *                                  {key: (number or array), shift: (true/false), ctrl: (true/false), alt: (true/false)}\r
6909      * @param {Function} fn The function to call\r
6910      * @param {Object} scope (optional) The scope of the function\r
6911      * @return {Ext.KeyMap} The KeyMap created\r
6912      */\r
6913     addKeyListener : function(key, fn, scope){\r
6914         var config;\r
6915         if(!Ext.isObject(key) || Ext.isArray(key)){\r
6916             config = {\r
6917                 key: key,\r
6918                 fn: fn,\r
6919                 scope: scope\r
6920             };\r
6921         }else{\r
6922             config = {\r
6923                 key : key.key,\r
6924                 shift : key.shift,\r
6925                 ctrl : key.ctrl,\r
6926                 alt : key.alt,\r
6927                 fn: fn,\r
6928                 scope: scope\r
6929             };\r
6930         }\r
6931         return new Ext.KeyMap(this, config);\r
6932     },\r
6933 \r
6934     /**\r
6935      * Creates a KeyMap for this element\r
6936      * @param {Object} config The KeyMap config. See {@link Ext.KeyMap} for more details\r
6937      * @return {Ext.KeyMap} The KeyMap created\r
6938      */\r
6939     addKeyMap : function(config){\r
6940         return new Ext.KeyMap(this, config);\r
6941     }\r
6942 });(function(){\r
6943     // contants\r
6944     var NULL = null,\r
6945         UNDEFINED = undefined,\r
6946         TRUE = true,\r
6947         FALSE = false,\r
6948         SETX = "setX",\r
6949         SETY = "setY",\r
6950         SETXY = "setXY",\r
6951         LEFT = "left",\r
6952         BOTTOM = "bottom",\r
6953         TOP = "top",\r
6954         RIGHT = "right",\r
6955         HEIGHT = "height",\r
6956         WIDTH = "width",\r
6957         POINTS = "points",\r
6958         HIDDEN = "hidden",\r
6959         ABSOLUTE = "absolute",\r
6960         VISIBLE = "visible",\r
6961         MOTION = "motion",\r
6962         POSITION = "position",\r
6963         EASEOUT = "easeOut",\r
6964         /*\r
6965          * Use a light flyweight here since we are using so many callbacks and are always assured a DOM element\r
6966          */\r
6967         flyEl = new Ext.Element.Flyweight(),\r
6968         queues = {},\r
6969         getObject = function(o){\r
6970             return o || {};\r
6971         },\r
6972         fly = function(dom){\r
6973             flyEl.dom = dom;\r
6974             flyEl.id = Ext.id(dom);\r
6975             return flyEl;\r
6976         },\r
6977         /*\r
6978          * Queueing now stored outside of the element due to closure issues\r
6979          */\r
6980         getQueue = function(id){\r
6981             if(!queues[id]){\r
6982                 queues[id] = [];\r
6983             }\r
6984             return queues[id];\r
6985         },\r
6986         setQueue = function(id, value){\r
6987             queues[id] = value;\r
6988         };\r
6989         \r
6990 //Notifies Element that fx methods are available\r
6991 Ext.enableFx = TRUE;\r
6992 \r
6993 /**\r
6994  * @class Ext.Fx\r
6995  * <p>A class to provide basic animation and visual effects support.  <b>Note:</b> This class is automatically applied\r
6996  * to the {@link Ext.Element} interface when included, so all effects calls should be performed via {@link Ext.Element}.\r
6997  * Conversely, since the effects are not actually defined in {@link Ext.Element}, Ext.Fx <b>must</b> be\r
6998  * {@link Ext#enableFx included} in order for the Element effects to work.</p><br/>\r
6999  * \r
7000  * <p><b><u>Method Chaining</u></b></p>\r
7001  * <p>It is important to note that although the Fx methods and many non-Fx Element methods support "method chaining" in that\r
7002  * they return the Element object itself as the method return value, it is not always possible to mix the two in a single\r
7003  * method chain.  The Fx methods use an internal effects queue so that each effect can be properly timed and sequenced.\r
7004  * Non-Fx methods, on the other hand, have no such internal queueing and will always execute immediately.  For this reason,\r
7005  * while it may be possible to mix certain Fx and non-Fx method calls in a single chain, it may not always provide the\r
7006  * expected results and should be done with care.  Also see <tt>{@link #callback}</tt>.</p><br/>\r
7007  *\r
7008  * <p><b><u>Anchor Options for Motion Effects</u></b></p>\r
7009  * <p>Motion effects support 8-way anchoring, meaning that you can choose one of 8 different anchor points on the Element\r
7010  * that will serve as either the start or end point of the animation.  Following are all of the supported anchor positions:</p>\r
7011 <pre>\r
7012 Value  Description\r
7013 -----  -----------------------------\r
7014 tl     The top left corner\r
7015 t      The center of the top edge\r
7016 tr     The top right corner\r
7017 l      The center of the left edge\r
7018 r      The center of the right edge\r
7019 bl     The bottom left corner\r
7020 b      The center of the bottom edge\r
7021 br     The bottom right corner\r
7022 </pre>\r
7023  * <b>Note</b>: some Fx methods accept specific custom config parameters.  The options shown in the Config Options\r
7024  * section below are common options that can be passed to any Fx method unless otherwise noted.</b>\r
7025  * \r
7026  * @cfg {Function} callback A function called when the effect is finished.  Note that effects are queued internally by the\r
7027  * Fx class, so a callback is not required to specify another effect -- effects can simply be chained together\r
7028  * and called in sequence (see note for <b><u>Method Chaining</u></b> above), for example:<pre><code>\r
7029  * el.slideIn().highlight();\r
7030  * </code></pre>\r
7031  * The callback is intended for any additional code that should run once a particular effect has completed. The Element\r
7032  * being operated upon is passed as the first parameter.\r
7033  * \r
7034  * @cfg {Object} scope The scope of the <tt>{@link #callback}</tt> function\r
7035  * \r
7036  * @cfg {String} easing A valid Ext.lib.Easing value for the effect:</p><div class="mdetail-params"><ul>\r
7037  * <li><b><tt>backBoth</tt></b></li>\r
7038  * <li><b><tt>backIn</tt></b></li>\r
7039  * <li><b><tt>backOut</tt></b></li>\r
7040  * <li><b><tt>bounceBoth</tt></b></li>\r
7041  * <li><b><tt>bounceIn</tt></b></li>\r
7042  * <li><b><tt>bounceOut</tt></b></li>\r
7043  * <li><b><tt>easeBoth</tt></b></li>\r
7044  * <li><b><tt>easeBothStrong</tt></b></li>\r
7045  * <li><b><tt>easeIn</tt></b></li>\r
7046  * <li><b><tt>easeInStrong</tt></b></li>\r
7047  * <li><b><tt>easeNone</tt></b></li>\r
7048  * <li><b><tt>easeOut</tt></b></li>\r
7049  * <li><b><tt>easeOutStrong</tt></b></li>\r
7050  * <li><b><tt>elasticBoth</tt></b></li>\r
7051  * <li><b><tt>elasticIn</tt></b></li>\r
7052  * <li><b><tt>elasticOut</tt></b></li>\r
7053  * </ul></div>\r
7054  *\r
7055  * @cfg {String} afterCls A css class to apply after the effect\r
7056  * @cfg {Number} duration The length of time (in seconds) that the effect should last\r
7057  * \r
7058  * @cfg {Number} endOpacity Only applicable for {@link #fadeIn} or {@link #fadeOut}, a number between\r
7059  * <tt>0</tt> and <tt>1</tt> inclusive to configure the ending opacity value.\r
7060  *  \r
7061  * @cfg {Boolean} remove Whether the Element should be removed from the DOM and destroyed after the effect finishes\r
7062  * @cfg {Boolean} useDisplay Whether to use the <i>display</i> CSS property instead of <i>visibility</i> when hiding Elements (only applies to \r
7063  * effects that end with the element being visually hidden, ignored otherwise)\r
7064  * @cfg {String/Object/Function} afterStyle A style specification string, e.g. <tt>"width:100px"</tt>, or an object\r
7065  * in the form <tt>{width:"100px"}</tt>, or a function which returns such a specification that will be applied to the\r
7066  * Element after the effect finishes.\r
7067  * @cfg {Boolean} block Whether the effect should block other effects from queueing while it runs\r
7068  * @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\r
7069  * @cfg {Boolean} stopFx Whether preceding effects should be stopped and removed before running current effect (only applies to non blocking effects)\r
7070  */\r
7071 Ext.Fx = {\r
7072     \r
7073     // private - calls the function taking arguments from the argHash based on the key.  Returns the return value of the function.\r
7074     //           this is useful for replacing switch statements (for example).\r
7075     switchStatements : function(key, fn, argHash){\r
7076         return fn.apply(this, argHash[key]);\r
7077     },\r
7078     \r
7079     /**\r
7080      * Slides the element into view.  An anchor point can be optionally passed to set the point of\r
7081      * origin for the slide effect.  This function automatically handles wrapping the element with\r
7082      * a fixed-size container if needed.  See the Fx class overview for valid anchor point options.\r
7083      * Usage:\r
7084      *<pre><code>\r
7085 // default: slide the element in from the top\r
7086 el.slideIn();\r
7087 \r
7088 // custom: slide the element in from the right with a 2-second duration\r
7089 el.slideIn('r', { duration: 2 });\r
7090 \r
7091 // common config options shown with default values\r
7092 el.slideIn('t', {\r
7093     easing: 'easeOut',\r
7094     duration: .5\r
7095 });\r
7096 </code></pre>\r
7097      * @param {String} anchor (optional) One of the valid Fx anchor positions (defaults to top: 't')\r
7098      * @param {Object} options (optional) Object literal with any of the Fx config options\r
7099      * @return {Ext.Element} The Element\r
7100      */\r
7101     slideIn : function(anchor, o){ \r
7102         o = getObject(o);\r
7103         var me = this,\r
7104             dom = me.dom,\r
7105             st = dom.style,\r
7106             xy,\r
7107             r,\r
7108             b,              \r
7109             wrap,               \r
7110             after,\r
7111             st,\r
7112             args, \r
7113             pt,\r
7114             bw,\r
7115             bh;\r
7116             \r
7117         anchor = anchor || "t";\r
7118 \r
7119         me.queueFx(o, function(){            \r
7120             xy = fly(dom).getXY();\r
7121             // fix display to visibility\r
7122             fly(dom).fixDisplay();            \r
7123             \r
7124             // restore values after effect\r
7125             r = fly(dom).getFxRestore();      \r
7126             b = {x: xy[0], y: xy[1], 0: xy[0], 1: xy[1], width: dom.offsetWidth, height: dom.offsetHeight};\r
7127             b.right = b.x + b.width;\r
7128             b.bottom = b.y + b.height;\r
7129             \r
7130             // fixed size for slide\r
7131             fly(dom).setWidth(b.width).setHeight(b.height);            \r
7132             \r
7133             // wrap if needed\r
7134             wrap = fly(dom).fxWrap(r.pos, o, HIDDEN);\r
7135             \r
7136             st.visibility = VISIBLE;\r
7137             st.position = ABSOLUTE;\r
7138             \r
7139             // clear out temp styles after slide and unwrap\r
7140             function after(){\r
7141                  fly(dom).fxUnwrap(wrap, r.pos, o);\r
7142                  st.width = r.width;\r
7143                  st.height = r.height;\r
7144                  fly(dom).afterFx(o);\r
7145             }\r
7146             \r
7147             // time to calculate the positions        \r
7148             pt = {to: [b.x, b.y]}; \r
7149             bw = {to: b.width};\r
7150             bh = {to: b.height};\r
7151                 \r
7152             function argCalc(wrap, style, ww, wh, sXY, sXYval, s1, s2, w, h, p){                    \r
7153                 var ret = {};\r
7154                 fly(wrap).setWidth(ww).setHeight(wh);\r
7155                 if(fly(wrap)[sXY]){\r
7156                     fly(wrap)[sXY](sXYval);                  \r
7157                 }\r
7158                 style[s1] = style[s2] = "0";                    \r
7159                 if(w){\r
7160                     ret.width = w\r
7161                 };\r
7162                 if(h){\r
7163                     ret.height = h;\r
7164                 }\r
7165                 if(p){\r
7166                     ret.points = p;\r
7167                 }\r
7168                 return ret;\r
7169             };\r
7170 \r
7171             args = fly(dom).switchStatements(anchor.toLowerCase(), argCalc, {\r
7172                     t  : [wrap, st, b.width, 0, NULL, NULL, LEFT, BOTTOM, NULL, bh, NULL],\r
7173                     l  : [wrap, st, 0, b.height, NULL, NULL, RIGHT, TOP, bw, NULL, NULL],\r
7174                     r  : [wrap, st, b.width, b.height, SETX, b.right, LEFT, TOP, NULL, NULL, pt],\r
7175                     b  : [wrap, st, b.width, b.height, SETY, b.bottom, LEFT, TOP, NULL, bh, pt],\r
7176                     tl : [wrap, st, 0, 0, NULL, NULL, RIGHT, BOTTOM, bw, bh, pt],\r
7177                     bl : [wrap, st, 0, 0, SETY, b.y + b.height, RIGHT, TOP, bw, bh, pt],\r
7178                     br : [wrap, st, 0, 0, SETXY, [b.right, b.bottom], LEFT, TOP, bw, bh, pt],\r
7179                     tr : [wrap, st, 0, 0, SETX, b.x + b.width, LEFT, BOTTOM, bw, bh, pt]\r
7180                 });\r
7181             \r
7182             st.visibility = VISIBLE;\r
7183             fly(wrap).show();\r
7184 \r
7185             arguments.callee.anim = fly(wrap).fxanim(args,\r
7186                 o,\r
7187                 MOTION,\r
7188                 .5,\r
7189                 EASEOUT, \r
7190                 after);\r
7191         });\r
7192         return me;\r
7193     },\r
7194     \r
7195     /**\r
7196      * Slides the element out of view.  An anchor point can be optionally passed to set the end point\r
7197      * for the slide effect.  When the effect is completed, the element will be hidden (visibility = \r
7198      * 'hidden') but block elements will still take up space in the document.  The element must be removed\r
7199      * from the DOM using the 'remove' config option if desired.  This function automatically handles \r
7200      * wrapping the element with a fixed-size container if needed.  See the Fx class overview for valid anchor point options.\r
7201      * Usage:\r
7202      *<pre><code>\r
7203 // default: slide the element out to the top\r
7204 el.slideOut();\r
7205 \r
7206 // custom: slide the element out to the right with a 2-second duration\r
7207 el.slideOut('r', { duration: 2 });\r
7208 \r
7209 // common config options shown with default values\r
7210 el.slideOut('t', {\r
7211     easing: 'easeOut',\r
7212     duration: .5,\r
7213     remove: false,\r
7214     useDisplay: false\r
7215 });\r
7216 </code></pre>\r
7217      * @param {String} anchor (optional) One of the valid Fx anchor positions (defaults to top: 't')\r
7218      * @param {Object} options (optional) Object literal with any of the Fx config options\r
7219      * @return {Ext.Element} The Element\r
7220      */\r
7221     slideOut : function(anchor, o){\r
7222         o = getObject(o);\r
7223         var me = this,\r
7224             dom = me.dom,\r
7225             st = dom.style,\r
7226             xy = me.getXY(),\r
7227             wrap,\r
7228             r,\r
7229             b,\r
7230             a,\r
7231             zero = {to: 0}; \r
7232                     \r
7233         anchor = anchor || "t";\r
7234 \r
7235         me.queueFx(o, function(){\r
7236             \r
7237             // restore values after effect\r
7238             r = fly(dom).getFxRestore(); \r
7239             b = {x: xy[0], y: xy[1], 0: xy[0], 1: xy[1], width: dom.offsetWidth, height: dom.offsetHeight};\r
7240             b.right = b.x + b.width;\r
7241             b.bottom = b.y + b.height;\r
7242                 \r
7243             // fixed size for slide   \r
7244             fly(dom).setWidth(b.width).setHeight(b.height);\r
7245 \r
7246             // wrap if needed\r
7247             wrap = fly(dom).fxWrap(r.pos, o, VISIBLE);\r
7248                 \r
7249             st.visibility = VISIBLE;\r
7250             st.position = ABSOLUTE;\r
7251             fly(wrap).setWidth(b.width).setHeight(b.height);            \r
7252 \r
7253             function after(){\r
7254                 o.useDisplay ? fly(dom).setDisplayed(FALSE) : fly(dom).hide();                \r
7255                 fly(dom).fxUnwrap(wrap, r.pos, o);\r
7256                 st.width = r.width;\r
7257                 st.height = r.height;\r
7258                 fly(dom).afterFx(o);\r
7259             }            \r
7260             \r
7261             function argCalc(style, s1, s2, p1, v1, p2, v2, p3, v3){                    \r
7262                 var ret = {};\r
7263                 \r
7264                 style[s1] = style[s2] = "0";\r
7265                 ret[p1] = v1;               \r
7266                 if(p2){\r
7267                     ret[p2] = v2;               \r
7268                 }\r
7269                 if(p3){\r
7270                     ret[p3] = v3;\r
7271                 }\r
7272                 \r
7273                 return ret;\r
7274             };\r
7275             \r
7276             a = fly(dom).switchStatements(anchor.toLowerCase(), argCalc, {\r
7277                 t  : [st, LEFT, BOTTOM, HEIGHT, zero],\r
7278                 l  : [st, RIGHT, TOP, WIDTH, zero],\r
7279                 r  : [st, LEFT, TOP, WIDTH, zero, POINTS, {to : [b.right, b.y]}],\r
7280                 b  : [st, LEFT, TOP, HEIGHT, zero, POINTS, {to : [b.x, b.bottom]}],\r
7281                 tl : [st, RIGHT, BOTTOM, WIDTH, zero, HEIGHT, zero],\r
7282                 bl : [st, RIGHT, TOP, WIDTH, zero, HEIGHT, zero, POINTS, {to : [b.x, b.bottom]}],\r
7283                 br : [st, LEFT, TOP, WIDTH, zero, HEIGHT, zero, POINTS, {to : [b.x + b.width, b.bottom]}],\r
7284                 tr : [st, LEFT, BOTTOM, WIDTH, zero, HEIGHT, zero, POINTS, {to : [b.right, b.y]}]\r
7285             });\r
7286             \r
7287             arguments.callee.anim = fly(wrap).fxanim(a,\r
7288                 o,\r
7289                 MOTION,\r
7290                 .5,\r
7291                 EASEOUT, \r
7292                 after);\r
7293         });\r
7294         return me;\r
7295     },\r
7296 \r
7297     /**\r
7298      * Fades the element out while slowly expanding it in all directions.  When the effect is completed, the \r
7299      * element will be hidden (visibility = 'hidden') but block elements will still take up space in the document. \r
7300      * The element must be removed from the DOM using the 'remove' config option if desired.\r
7301      * Usage:\r
7302      *<pre><code>\r
7303 // default\r
7304 el.puff();\r
7305 \r
7306 // common config options shown with default values\r
7307 el.puff({\r
7308     easing: 'easeOut',\r
7309     duration: .5,\r
7310     remove: false,\r
7311     useDisplay: false\r
7312 });\r
7313 </code></pre>\r
7314      * @param {Object} options (optional) Object literal with any of the Fx config options\r
7315      * @return {Ext.Element} The Element\r
7316      */\r
7317     puff : function(o){\r
7318         o = getObject(o);\r
7319         var me = this,\r
7320             dom = me.dom,\r
7321             st = dom.style,\r
7322             width,\r
7323             height,\r
7324             r;\r
7325 \r
7326         me.queueFx(o, function(){\r
7327             width = fly(dom).getWidth();\r
7328             height = fly(dom).getHeight();\r
7329             fly(dom).clearOpacity();\r
7330             fly(dom).show();\r
7331 \r
7332             // restore values after effect\r
7333             r = fly(dom).getFxRestore();                   \r
7334             \r
7335             function after(){\r
7336                 o.useDisplay ? fly(dom).setDisplayed(FALSE) : fly(dom).hide();                  \r
7337                 fly(dom).clearOpacity();  \r
7338                 fly(dom).setPositioning(r.pos);\r
7339                 st.width = r.width;\r
7340                 st.height = r.height;\r
7341                 st.fontSize = '';\r
7342                 fly(dom).afterFx(o);\r
7343             }   \r
7344 \r
7345             arguments.callee.anim = fly(dom).fxanim({\r
7346                     width : {to : fly(dom).adjustWidth(width * 2)},\r
7347                     height : {to : fly(dom).adjustHeight(height * 2)},\r
7348                     points : {by : [-width * .5, -height * .5]},\r
7349                     opacity : {to : 0},\r
7350                     fontSize: {to : 200, unit: "%"}\r
7351                 },\r
7352                 o,\r
7353                 MOTION,\r
7354                 .5,\r
7355                 EASEOUT,\r
7356                  after);\r
7357         });\r
7358         return me;\r
7359     },\r
7360 \r
7361     /**\r
7362      * Blinks the element as if it was clicked and then collapses on its center (similar to switching off a television).\r
7363      * When the effect is completed, the element will be hidden (visibility = 'hidden') but block elements will still \r
7364      * take up space in the document. The element must be removed from the DOM using the 'remove' config option if desired.\r
7365      * Usage:\r
7366      *<pre><code>\r
7367 // default\r
7368 el.switchOff();\r
7369 \r
7370 // all config options shown with default values\r
7371 el.switchOff({\r
7372     easing: 'easeIn',\r
7373     duration: .3,\r
7374     remove: false,\r
7375     useDisplay: false\r
7376 });\r
7377 </code></pre>\r
7378      * @param {Object} options (optional) Object literal with any of the Fx config options\r
7379      * @return {Ext.Element} The Element\r
7380      */\r
7381     switchOff : function(o){\r
7382         o = getObject(o);\r
7383         var me = this,\r
7384             dom = me.dom,\r
7385             st = dom.style,\r
7386             r;\r
7387 \r
7388         me.queueFx(o, function(){\r
7389             fly(dom).clearOpacity();\r
7390             fly(dom).clip();\r
7391 \r
7392             // restore values after effect\r
7393             r = fly(dom).getFxRestore();\r
7394                 \r
7395             function after(){\r
7396                 o.useDisplay ? fly(dom).setDisplayed(FALSE) : fly(dom).hide();  \r
7397                 fly(dom).clearOpacity();\r
7398                 fly(dom).setPositioning(r.pos);\r
7399                 st.width = r.width;\r
7400                 st.height = r.height;   \r
7401                 fly(dom).afterFx(o);\r
7402             };\r
7403 \r
7404             fly(dom).fxanim({opacity : {to : 0.3}}, \r
7405                 NULL, \r
7406                 NULL, \r
7407                 .1, \r
7408                 NULL, \r
7409                 function(){                                 \r
7410                     fly(dom).clearOpacity();\r
7411                         (function(){                            \r
7412                             fly(dom).fxanim({\r
7413                                 height : {to : 1},\r
7414                                 points : {by : [0, fly(dom).getHeight() * .5]}\r
7415                             }, \r
7416                             o, \r
7417                             MOTION, \r
7418                             0.3, \r
7419                             'easeIn', \r
7420                             after);\r
7421                         }).defer(100);\r
7422                 });\r
7423         });\r
7424         return me;\r
7425     },\r
7426 \r
7427     /**\r
7428      * Highlights the Element by setting a color (applies to the background-color by default, but can be\r
7429      * changed using the "attr" config option) and then fading back to the original color. If no original\r
7430      * color is available, you should provide the "endColor" config option which will be cleared after the animation.\r
7431      * Usage:\r
7432 <pre><code>\r
7433 // default: highlight background to yellow\r
7434 el.highlight();\r
7435 \r
7436 // custom: highlight foreground text to blue for 2 seconds\r
7437 el.highlight("0000ff", { attr: 'color', duration: 2 });\r
7438 \r
7439 // common config options shown with default values\r
7440 el.highlight("ffff9c", {\r
7441     attr: "background-color", //can be any valid CSS property (attribute) that supports a color value\r
7442     endColor: (current color) or "ffffff",\r
7443     easing: 'easeIn',\r
7444     duration: 1\r
7445 });\r
7446 </code></pre>\r
7447      * @param {String} color (optional) The highlight color. Should be a 6 char hex color without the leading # (defaults to yellow: 'ffff9c')\r
7448      * @param {Object} options (optional) Object literal with any of the Fx config options\r
7449      * @return {Ext.Element} The Element\r
7450      */ \r
7451     highlight : function(color, o){\r
7452         o = getObject(o);\r
7453         var me = this,\r
7454             dom = me.dom,\r
7455             attr = o.attr || "backgroundColor",\r
7456             a = {},\r
7457             restore;\r
7458 \r
7459         me.queueFx(o, function(){\r
7460             fly(dom).clearOpacity();\r
7461             fly(dom).show();\r
7462 \r
7463             function after(){\r
7464                 dom.style[attr] = restore;\r
7465                 fly(dom).afterFx(o);\r
7466             }            \r
7467             restore = dom.style[attr];\r
7468             a[attr] = {from: color || "ffff9c", to: o.endColor || fly(dom).getColor(attr) || "ffffff"};\r
7469             arguments.callee.anim = fly(dom).fxanim(a,\r
7470                 o,\r
7471                 'color',\r
7472                 1,\r
7473                 'easeIn', \r
7474                 after);\r
7475         });\r
7476         return me;\r
7477     },\r
7478 \r
7479    /**\r
7480     * Shows a ripple of exploding, attenuating borders to draw attention to an Element.\r
7481     * Usage:\r
7482 <pre><code>\r
7483 // default: a single light blue ripple\r
7484 el.frame();\r
7485 \r
7486 // custom: 3 red ripples lasting 3 seconds total\r
7487 el.frame("ff0000", 3, { duration: 3 });\r
7488 \r
7489 // common config options shown with default values\r
7490 el.frame("C3DAF9", 1, {\r
7491     duration: 1 //duration of each individual ripple.\r
7492     // Note: Easing is not configurable and will be ignored if included\r
7493 });\r
7494 </code></pre>\r
7495     * @param {String} color (optional) The color of the border.  Should be a 6 char hex color without the leading # (defaults to light blue: 'C3DAF9').\r
7496     * @param {Number} count (optional) The number of ripples to display (defaults to 1)\r
7497     * @param {Object} options (optional) Object literal with any of the Fx config options\r
7498     * @return {Ext.Element} The Element\r
7499     */\r
7500     frame : function(color, count, o){\r
7501         o = getObject(o);\r
7502         var me = this,\r
7503             dom = me.dom,\r
7504             proxy,\r
7505             active;\r
7506 \r
7507         me.queueFx(o, function(){\r
7508             color = color || "#C3DAF9"\r
7509             if(color.length == 6){\r
7510                 color = "#" + color;\r
7511             }            \r
7512             count = count || 1;\r
7513             fly(dom).show();\r
7514 \r
7515             var xy = fly(dom).getXY(),\r
7516                 b = {x: xy[0], y: xy[1], 0: xy[0], 1: xy[1], width: dom.offsetWidth, height: dom.offsetHeight},\r
7517                 queue = function(){\r
7518                     proxy = fly(document.body || document.documentElement).createChild({\r
7519                         style:{\r
7520                             visbility: HIDDEN,\r
7521                             position : ABSOLUTE,\r
7522                             "z-index": 35000, // yee haw\r
7523                             border : "0px solid " + color\r
7524                         }\r
7525                     });\r
7526                     return proxy.queueFx({}, animFn);\r
7527                 };\r
7528             \r
7529             \r
7530             arguments.callee.anim = {\r
7531                 isAnimated: true,\r
7532                 stop: function() {\r
7533                     count = 0;\r
7534                     proxy.stopFx();\r
7535                 }\r
7536             };\r
7537             \r
7538             function animFn(){\r
7539                 var scale = Ext.isBorderBox ? 2 : 1;\r
7540                 active = proxy.anim({\r
7541                     top : {from : b.y, to : b.y - 20},\r
7542                     left : {from : b.x, to : b.x - 20},\r
7543                     borderWidth : {from : 0, to : 10},\r
7544                     opacity : {from : 1, to : 0},\r
7545                     height : {from : b.height, to : b.height + 20 * scale},\r
7546                     width : {from : b.width, to : b.width + 20 * scale}\r
7547                 },{\r
7548                     duration: o.duration || 1,\r
7549                     callback: function() {\r
7550                         proxy.remove();\r
7551                         --count > 0 ? queue() : fly(dom).afterFx(o);\r
7552                     }\r
7553                 });\r
7554                 arguments.callee.anim = {\r
7555                     isAnimated: true,\r
7556                     stop: function(){\r
7557                         active.stop();\r
7558                     }\r
7559                 };\r
7560             };\r
7561             queue();\r
7562         });\r
7563         return me;\r
7564     },\r
7565 \r
7566    /**\r
7567     * Creates a pause before any subsequent queued effects begin.  If there are\r
7568     * no effects queued after the pause it will have no effect.\r
7569     * Usage:\r
7570 <pre><code>\r
7571 el.pause(1);\r
7572 </code></pre>\r
7573     * @param {Number} seconds The length of time to pause (in seconds)\r
7574     * @return {Ext.Element} The Element\r
7575     */\r
7576     pause : function(seconds){        \r
7577         var dom = this.dom,\r
7578             t;\r
7579 \r
7580         this.queueFx({}, function(){\r
7581             t = setTimeout(function(){\r
7582                 fly(dom).afterFx({});\r
7583             }, seconds * 1000);\r
7584             arguments.callee.anim = {\r
7585                 isAnimated: true,\r
7586                 stop: function(){\r
7587                     clearTimeout(t);\r
7588                     fly(dom).afterFx({});\r
7589                 }\r
7590             };\r
7591         });\r
7592         return this;\r
7593     },\r
7594 \r
7595    /**\r
7596     * Fade an element in (from transparent to opaque).  The ending opacity can be specified\r
7597     * using the <tt>{@link #endOpacity}</tt> config option.\r
7598     * Usage:\r
7599 <pre><code>\r
7600 // default: fade in from opacity 0 to 100%\r
7601 el.fadeIn();\r
7602 \r
7603 // custom: fade in from opacity 0 to 75% over 2 seconds\r
7604 el.fadeIn({ endOpacity: .75, duration: 2});\r
7605 \r
7606 // common config options shown with default values\r
7607 el.fadeIn({\r
7608     endOpacity: 1, //can be any value between 0 and 1 (e.g. .5)\r
7609     easing: 'easeOut',\r
7610     duration: .5\r
7611 });\r
7612 </code></pre>\r
7613     * @param {Object} options (optional) Object literal with any of the Fx config options\r
7614     * @return {Ext.Element} The Element\r
7615     */\r
7616     fadeIn : function(o){\r
7617         o = getObject(o);\r
7618         var me = this,\r
7619             dom = me.dom,\r
7620             to = o.endOpacity || 1;\r
7621         \r
7622         me.queueFx(o, function(){\r
7623             fly(dom).setOpacity(0);\r
7624             fly(dom).fixDisplay();\r
7625             dom.style.visibility = VISIBLE;\r
7626             arguments.callee.anim = fly(dom).fxanim({opacity:{to:to}},\r
7627                 o, NULL, .5, EASEOUT, function(){\r
7628                 if(to == 1){\r
7629                     fly(dom).clearOpacity();\r
7630                 }\r
7631                 fly(dom).afterFx(o);\r
7632             });\r
7633         });\r
7634         return me;\r
7635     },\r
7636 \r
7637    /**\r
7638     * Fade an element out (from opaque to transparent).  The ending opacity can be specified\r
7639     * using the <tt>{@link #endOpacity}</tt> config option.  Note that IE may require\r
7640     * <tt>{@link #useDisplay}:true</tt> in order to redisplay correctly.\r
7641     * Usage:\r
7642 <pre><code>\r
7643 // default: fade out from the element's current opacity to 0\r
7644 el.fadeOut();\r
7645 \r
7646 // custom: fade out from the element's current opacity to 25% over 2 seconds\r
7647 el.fadeOut({ endOpacity: .25, duration: 2});\r
7648 \r
7649 // common config options shown with default values\r
7650 el.fadeOut({\r
7651     endOpacity: 0, //can be any value between 0 and 1 (e.g. .5)\r
7652     easing: 'easeOut',\r
7653     duration: .5,\r
7654     remove: false,\r
7655     useDisplay: false\r
7656 });\r
7657 </code></pre>\r
7658     * @param {Object} options (optional) Object literal with any of the Fx config options\r
7659     * @return {Ext.Element} The Element\r
7660     */\r
7661     fadeOut : function(o){\r
7662         o = getObject(o);\r
7663         var me = this,\r
7664             dom = me.dom,\r
7665             style = dom.style,\r
7666             to = o.endOpacity || 0;         \r
7667         \r
7668         me.queueFx(o, function(){  \r
7669             arguments.callee.anim = fly(dom).fxanim({ \r
7670                 opacity : {to : to}},\r
7671                 o, \r
7672                 NULL, \r
7673                 .5, \r
7674                 EASEOUT, \r
7675                 function(){\r
7676                     if(to == 0){\r
7677                         Ext.Element.data(dom, 'visibilityMode') == Ext.Element.DISPLAY || o.useDisplay ? \r
7678                             style.display = "none" :\r
7679                             style.visibility = HIDDEN;\r
7680                             \r
7681                         fly(dom).clearOpacity();\r
7682                     }\r
7683                     fly(dom).afterFx(o);\r
7684             });\r
7685         });\r
7686         return me;\r
7687     },\r
7688 \r
7689    /**\r
7690     * Animates the transition of an element's dimensions from a starting height/width\r
7691     * to an ending height/width.  This method is a convenience implementation of {@link shift}.\r
7692     * Usage:\r
7693 <pre><code>\r
7694 // change height and width to 100x100 pixels\r
7695 el.scale(100, 100);\r
7696 \r
7697 // common config options shown with default values.  The height and width will default to\r
7698 // the element&#39;s existing values if passed as null.\r
7699 el.scale(\r
7700     [element&#39;s width],\r
7701     [element&#39;s height], {\r
7702         easing: 'easeOut',\r
7703         duration: .35\r
7704     }\r
7705 );\r
7706 </code></pre>\r
7707     * @param {Number} width  The new width (pass undefined to keep the original width)\r
7708     * @param {Number} height  The new height (pass undefined to keep the original height)\r
7709     * @param {Object} options (optional) Object literal with any of the Fx config options\r
7710     * @return {Ext.Element} The Element\r
7711     */\r
7712     scale : function(w, h, o){\r
7713         this.shift(Ext.apply({}, o, {\r
7714             width: w,\r
7715             height: h\r
7716         }));\r
7717         return this;\r
7718     },\r
7719 \r
7720    /**\r
7721     * Animates the transition of any combination of an element's dimensions, xy position and/or opacity.\r
7722     * Any of these properties not specified in the config object will not be changed.  This effect \r
7723     * requires that at least one new dimension, position or opacity setting must be passed in on\r
7724     * the config object in order for the function to have any effect.\r
7725     * Usage:\r
7726 <pre><code>\r
7727 // slide the element horizontally to x position 200 while changing the height and opacity\r
7728 el.shift({ x: 200, height: 50, opacity: .8 });\r
7729 \r
7730 // common config options shown with default values.\r
7731 el.shift({\r
7732     width: [element&#39;s width],\r
7733     height: [element&#39;s height],\r
7734     x: [element&#39;s x position],\r
7735     y: [element&#39;s y position],\r
7736     opacity: [element&#39;s opacity],\r
7737     easing: 'easeOut',\r
7738     duration: .35\r
7739 });\r
7740 </code></pre>\r
7741     * @param {Object} options  Object literal with any of the Fx config options\r
7742     * @return {Ext.Element} The Element\r
7743     */\r
7744     shift : function(o){\r
7745         o = getObject(o);\r
7746         var dom = this.dom,\r
7747             a = {};\r
7748                 \r
7749         this.queueFx(o, function(){\r
7750             for (var prop in o) {\r
7751                 if (o[prop] != UNDEFINED) {                                                 \r
7752                     a[prop] = {to : o[prop]};                   \r
7753                 }\r
7754             } \r
7755             \r
7756             a.width ? a.width.to = fly(dom).adjustWidth(o.width) : a;\r
7757             a.height ? a.height.to = fly(dom).adjustWidth(o.height) : a;   \r
7758             \r
7759             if (a.x || a.y || a.xy) {\r
7760                 a.points = a.xy || \r
7761                            {to : [ a.x ? a.x.to : fly(dom).getX(),\r
7762                                    a.y ? a.y.to : fly(dom).getY()]};                  \r
7763             }\r
7764 \r
7765             arguments.callee.anim = fly(dom).fxanim(a,\r
7766                 o, \r
7767                 MOTION, \r
7768                 .35, \r
7769                 EASEOUT, \r
7770                 function(){\r
7771                     fly(dom).afterFx(o);\r
7772                 });\r
7773         });\r
7774         return this;\r
7775     },\r
7776 \r
7777     /**\r
7778      * Slides the element while fading it out of view.  An anchor point can be optionally passed to set the \r
7779      * ending point of the effect.\r
7780      * Usage:\r
7781      *<pre><code>\r
7782 // default: slide the element downward while fading out\r
7783 el.ghost();\r
7784 \r
7785 // custom: slide the element out to the right with a 2-second duration\r
7786 el.ghost('r', { duration: 2 });\r
7787 \r
7788 // common config options shown with default values\r
7789 el.ghost('b', {\r
7790     easing: 'easeOut',\r
7791     duration: .5,\r
7792     remove: false,\r
7793     useDisplay: false\r
7794 });\r
7795 </code></pre>\r
7796      * @param {String} anchor (optional) One of the valid Fx anchor positions (defaults to bottom: 'b')\r
7797      * @param {Object} options (optional) Object literal with any of the Fx config options\r
7798      * @return {Ext.Element} The Element\r
7799      */\r
7800     ghost : function(anchor, o){\r
7801         o = getObject(o);\r
7802         var me = this,\r
7803             dom = me.dom,\r
7804             st = dom.style,\r
7805             a = {opacity: {to: 0}, points: {}},\r
7806             pt = a.points,\r
7807             r,\r
7808             w,\r
7809             h;\r
7810             \r
7811         anchor = anchor || "b";\r
7812 \r
7813         me.queueFx(o, function(){\r
7814             // restore values after effect\r
7815             r = fly(dom).getFxRestore();\r
7816             w = fly(dom).getWidth();\r
7817             h = fly(dom).getHeight();\r
7818             \r
7819             function after(){\r
7820                 o.useDisplay ? fly(dom).setDisplayed(FALSE) : fly(dom).hide();   \r
7821                 fly(dom).clearOpacity();\r
7822                 fly(dom).setPositioning(r.pos);\r
7823                 st.width = r.width;\r
7824                 st.height = r.height;\r
7825                 fly(dom).afterFx(o);\r
7826             }\r
7827                 \r
7828             pt.by = fly(dom).switchStatements(anchor.toLowerCase(), function(v1,v2){ return [v1, v2];}, {\r
7829                t  : [0, -h],\r
7830                l  : [-w, 0],\r
7831                r  : [w, 0],\r
7832                b  : [0, h],\r
7833                tl : [-w, -h],\r
7834                bl : [-w, h],\r
7835                br : [w, h],\r
7836                tr : [w, -h] \r
7837             });\r
7838                 \r
7839             arguments.callee.anim = fly(dom).fxanim(a,\r
7840                 o,\r
7841                 MOTION,\r
7842                 .5,\r
7843                 EASEOUT, after);\r
7844         });\r
7845         return me;\r
7846     },\r
7847 \r
7848     /**\r
7849      * Ensures that all effects queued after syncFx is called on the element are\r
7850      * run concurrently.  This is the opposite of {@link #sequenceFx}.\r
7851      * @return {Ext.Element} The Element\r
7852      */\r
7853     syncFx : function(){\r
7854         var me = this;\r
7855         me.fxDefaults = Ext.apply(me.fxDefaults || {}, {\r
7856             block : FALSE,\r
7857             concurrent : TRUE,\r
7858             stopFx : FALSE\r
7859         });\r
7860         return me;\r
7861     },\r
7862 \r
7863     /**\r
7864      * Ensures that all effects queued after sequenceFx is called on the element are\r
7865      * run in sequence.  This is the opposite of {@link #syncFx}.\r
7866      * @return {Ext.Element} The Element\r
7867      */\r
7868     sequenceFx : function(){\r
7869         var me = this;\r
7870         me.fxDefaults = Ext.apply(me.fxDefaults || {}, {\r
7871             block : FALSE,\r
7872             concurrent : FALSE,\r
7873             stopFx : FALSE\r
7874         });\r
7875         return me;\r
7876     },\r
7877 \r
7878     /* @private */\r
7879     nextFx : function(){        \r
7880         var ef = getQueue(this.dom.id)[0];\r
7881         if(ef){\r
7882             ef.call(this);\r
7883         }\r
7884     },\r
7885 \r
7886     /**\r
7887      * Returns true if the element has any effects actively running or queued, else returns false.\r
7888      * @return {Boolean} True if element has active effects, else false\r
7889      */\r
7890     hasActiveFx : function(){\r
7891         return getQueue(this.dom.id)[0];\r
7892     },\r
7893 \r
7894     /**\r
7895      * Stops any running effects and clears the element's internal effects queue if it contains\r
7896      * any additional effects that haven't started yet.\r
7897      * @return {Ext.Element} The Element\r
7898      */\r
7899     stopFx : function(finish){\r
7900         var me = this,\r
7901             id = me.dom.id;\r
7902         if(me.hasActiveFx()){\r
7903             var cur = getQueue(id)[0];\r
7904             if(cur && cur.anim){\r
7905                 if(cur.anim.isAnimated){\r
7906                     setQueue(id, [cur]); //clear\r
7907                     cur.anim.stop(finish !== undefined ? finish : TRUE);\r
7908                 }else{\r
7909                     setQueue(id, []);\r
7910                 }\r
7911             }\r
7912         }\r
7913         return me;\r
7914     },\r
7915 \r
7916     /* @private */\r
7917     beforeFx : function(o){\r
7918         if(this.hasActiveFx() && !o.concurrent){\r
7919            if(o.stopFx){\r
7920                this.stopFx();\r
7921                return TRUE;\r
7922            }\r
7923            return FALSE;\r
7924         }\r
7925         return TRUE;\r
7926     },\r
7927 \r
7928     /**\r
7929      * Returns true if the element is currently blocking so that no other effect can be queued\r
7930      * until this effect is finished, else returns false if blocking is not set.  This is commonly\r
7931      * used to ensure that an effect initiated by a user action runs to completion prior to the\r
7932      * same effect being restarted (e.g., firing only one effect even if the user clicks several times).\r
7933      * @return {Boolean} True if blocking, else false\r
7934      */\r
7935     hasFxBlock : function(){\r
7936         var q = getQueue(this.dom.id);\r
7937         return q && q[0] && q[0].block;\r
7938     },\r
7939 \r
7940     /* @private */\r
7941     queueFx : function(o, fn){\r
7942         var me = this;\r
7943         if(!me.hasFxBlock()){\r
7944             Ext.applyIf(o, me.fxDefaults);\r
7945             if(!o.concurrent){\r
7946                 var run = me.beforeFx(o);\r
7947                 fn.block = o.block;\r
7948                 getQueue(me.dom.id).push(fn);\r
7949                 if(run){\r
7950                     me.nextFx();\r
7951                 }\r
7952             }else{\r
7953                 fn.call(me);\r
7954             }\r
7955         }\r
7956         return me;\r
7957     },\r
7958 \r
7959     /* @private */\r
7960     fxWrap : function(pos, o, vis){ \r
7961         var dom = this.dom,\r
7962             wrap,\r
7963             wrapXY;\r
7964         if(!o.wrap || !(wrap = Ext.getDom(o.wrap))){            \r
7965             if(o.fixPosition){\r
7966                 wrapXY = fly(dom).getXY();\r
7967             }\r
7968             var div = document.createElement("div");\r
7969             div.style.visibility = vis;\r
7970             wrap = dom.parentNode.insertBefore(div, dom);\r
7971             fly(wrap).setPositioning(pos);\r
7972             if(fly(wrap).isStyle(POSITION, "static")){\r
7973                 fly(wrap).position("relative");\r
7974             }\r
7975             fly(dom).clearPositioning('auto');\r
7976             fly(wrap).clip();\r
7977             wrap.appendChild(dom);\r
7978             if(wrapXY){\r
7979                 fly(wrap).setXY(wrapXY);\r
7980             }\r
7981         }\r
7982         return wrap;\r
7983     },\r
7984 \r
7985     /* @private */\r
7986     fxUnwrap : function(wrap, pos, o){      \r
7987         var dom = this.dom;\r
7988         fly(dom).clearPositioning();\r
7989         fly(dom).setPositioning(pos);\r
7990         if(!o.wrap){\r
7991             wrap.parentNode.insertBefore(dom, wrap);\r
7992             fly(wrap).remove();\r
7993         }\r
7994     },\r
7995 \r
7996     /* @private */\r
7997     getFxRestore : function(){\r
7998         var st = this.dom.style;\r
7999         return {pos: this.getPositioning(), width: st.width, height : st.height};\r
8000     },\r
8001 \r
8002     /* @private */\r
8003     afterFx : function(o){\r
8004         var dom = this.dom,\r
8005             id = dom.id,\r
8006             notConcurrent = !o.concurrent;\r
8007         if(o.afterStyle){\r
8008             fly(dom).setStyle(o.afterStyle);            \r
8009         }\r
8010         if(o.afterCls){\r
8011             fly(dom).addClass(o.afterCls);\r
8012         }\r
8013         if(o.remove == TRUE){\r
8014             fly(dom).remove();\r
8015         }\r
8016         if(notConcurrent){\r
8017             getQueue(id).shift();\r
8018         }\r
8019         if(o.callback){\r
8020             o.callback.call(o.scope, fly(dom));\r
8021         }\r
8022         if(notConcurrent){\r
8023             fly(dom).nextFx();\r
8024         }\r
8025     },\r
8026 \r
8027     /* @private */\r
8028     fxanim : function(args, opt, animType, defaultDur, defaultEase, cb){\r
8029         animType = animType || 'run';\r
8030         opt = opt || {};\r
8031         var anim = Ext.lib.Anim[animType](\r
8032                 this.dom, \r
8033                 args,\r
8034                 (opt.duration || defaultDur) || .35,\r
8035                 (opt.easing || defaultEase) || EASEOUT,\r
8036                 cb,            \r
8037                 this\r
8038             );\r
8039         opt.anim = anim;\r
8040         return anim;\r
8041     }\r
8042 };\r
8043 \r
8044 // backwards compat\r
8045 Ext.Fx.resize = Ext.Fx.scale;\r
8046 \r
8047 //When included, Ext.Fx is automatically applied to Element so that all basic\r
8048 //effects are available directly via the Element API\r
8049 Ext.Element.addMethods(Ext.Fx);\r
8050 })();/**\r
8051  * @class Ext.CompositeElementLite\r
8052  * Flyweight composite class. Reuses the same Ext.Element for element operations.\r
8053  <pre><code>\r
8054  var els = Ext.select("#some-el div.some-class");\r
8055  // or select directly from an existing element\r
8056  var el = Ext.get('some-el');\r
8057  el.select('div.some-class');\r
8058 \r
8059  els.setWidth(100); // all elements become 100 width\r
8060  els.hide(true); // all elements fade out and hide\r
8061  // or\r
8062  els.setWidth(100).hide(true);\r
8063  </code></pre><br><br>\r
8064  * <b>NOTE: Although they are not listed, this class supports all of the set/update methods of Ext.Element. All Ext.Element\r
8065  * actions will be performed on all the elements in this collection.</b>\r
8066  */\r
8067 Ext.CompositeElementLite = function(els, root){\r
8068     this.elements = [];\r
8069     this.add(els, root);\r
8070     this.el = new Ext.Element.Flyweight();\r
8071 };\r
8072 \r
8073 Ext.CompositeElementLite.prototype = {\r
8074         isComposite: true,      \r
8075         /**\r
8076      * Returns the number of elements in this composite\r
8077      * @return Number\r
8078      */\r
8079     getCount : function(){\r
8080         return this.elements.length;\r
8081     },    \r
8082         add : function(els){\r
8083         if(els){\r
8084             if (Ext.isArray(els)) {\r
8085                 this.elements = this.elements.concat(els);\r
8086             } else {\r
8087                 var yels = this.elements;                                       \r
8088                     Ext.each(els, function(e) {\r
8089                     yels.push(e);\r
8090                 });\r
8091             }\r
8092         }\r
8093         return this;\r
8094     },\r
8095     invoke : function(fn, args){\r
8096         var els = this.elements,\r
8097                 el = this.el;        \r
8098             Ext.each(els, function(e) {    \r
8099             el.dom = e;\r
8100                 Ext.Element.prototype[fn].apply(el, args);\r
8101         });\r
8102         return this;\r
8103     },\r
8104     /**\r
8105      * Returns a flyweight Element of the dom element object at the specified index\r
8106      * @param {Number} index\r
8107      * @return {Ext.Element}\r
8108      */\r
8109     item : function(index){\r
8110             var me = this;\r
8111         if(!me.elements[index]){\r
8112             return null;\r
8113         }\r
8114         me.el.dom = me.elements[index];\r
8115         return me.el;\r
8116     },\r
8117 \r
8118     // fixes scope with flyweight\r
8119     addListener : function(eventName, handler, scope, opt){\r
8120         Ext.each(this.elements, function(e) {\r
8121                 Ext.EventManager.on(e, eventName, handler, scope || e, opt);\r
8122         });\r
8123         return this;\r
8124     },\r
8125     /**\r
8126     * Calls the passed function passing (el, this, index) for each element in this composite. <b>The element\r
8127     * passed is the flyweight (shared) Ext.Element instance, so if you require a\r
8128     * a reference to the dom node, use el.dom.</b>\r
8129     * @param {Function} fn The function to call\r
8130     * @param {Object} scope (optional) The <i>this</i> object (defaults to the element)\r
8131     * @return {CompositeElement} this\r
8132     */\r
8133     each : function(fn, scope){       \r
8134         var me = this,\r
8135                 el = me.el;\r
8136        \r
8137             Ext.each(me.elements, function(e,i) {    \r
8138             el.dom = e;\r
8139                 return fn.call(scope || el, el, me, i);\r
8140         });\r
8141         return me;\r
8142     },\r
8143     \r
8144     /**\r
8145      * Find the index of the passed element within the composite collection.\r
8146      * @param el {Mixed} The id of an element, or an Ext.Element, or an HtmlElement to find within the composite collection.\r
8147      * @return Number The index of the passed Ext.Element in the composite collection, or -1 if not found.\r
8148      */\r
8149     indexOf : function(el){\r
8150         return this.elements.indexOf(Ext.getDom(el));\r
8151     },\r
8152     \r
8153     /**\r
8154     * Replaces the specified element with the passed element.\r
8155     * @param {Mixed} el The id of an element, the Element itself, the index of the element in this composite\r
8156     * to replace.\r
8157     * @param {Mixed} replacement The id of an element or the Element itself.\r
8158     * @param {Boolean} domReplace (Optional) True to remove and replace the element in the document too.\r
8159     * @return {CompositeElement} this\r
8160     */    \r
8161     replaceElement : function(el, replacement, domReplace){\r
8162         var index = !isNaN(el) ? el : this.indexOf(el),\r
8163                 d;\r
8164         if(index > -1){\r
8165             replacement = Ext.getDom(replacement);\r
8166             if(domReplace){\r
8167                 d = this.elements[index];\r
8168                 d.parentNode.insertBefore(replacement, d);\r
8169                 Ext.removeNode(d);\r
8170             }\r
8171             this.elements.splice(index, 1, replacement);\r
8172         }\r
8173         return this;\r
8174     },\r
8175     \r
8176     /**\r
8177      * Removes all elements.\r
8178      */\r
8179     clear : function(){\r
8180         this.elements = [];\r
8181     }\r
8182 };\r
8183 \r
8184 Ext.CompositeElementLite.prototype.on = Ext.CompositeElementLite.prototype.addListener;\r
8185 \r
8186 (function(){\r
8187 var fnName,\r
8188         ElProto = Ext.Element.prototype,\r
8189         CelProto = Ext.CompositeElementLite.prototype;\r
8190         \r
8191 for(fnName in ElProto){\r
8192     if(Ext.isFunction(ElProto[fnName])){\r
8193             (function(fnName){ \r
8194                     CelProto[fnName] = CelProto[fnName] || function(){\r
8195                         return this.invoke(fnName, arguments);\r
8196                 };\r
8197         }).call(CelProto, fnName);\r
8198         \r
8199     }\r
8200 }\r
8201 })();\r
8202 \r
8203 if(Ext.DomQuery){\r
8204     Ext.Element.selectorFunction = Ext.DomQuery.select;\r
8205\r
8206 \r
8207 /**\r
8208  * Selects elements based on the passed CSS selector to enable {@link Ext.Element Element} methods\r
8209  * to be applied to many related elements in one statement through the returned {@link Ext.CompositeElement CompositeElement} or\r
8210  * {@link Ext.CompositeElementLite CompositeElementLite} object.\r
8211  * @param {String/Array} selector The CSS selector or an array of elements\r
8212  * @param {Boolean} unique (optional) true to create a unique Ext.Element for each element (defaults to a shared flyweight object) <b>Not supported in core</b>\r
8213  * @param {HTMLElement/String} root (optional) The root element of the query or id of the root\r
8214  * @return {CompositeElementLite/CompositeElement}\r
8215  * @member Ext.Element\r
8216  * @method select\r
8217  */\r
8218 Ext.Element.select = function(selector, unique, root){\r
8219     var els;\r
8220     if(typeof selector == "string"){\r
8221         els = Ext.Element.selectorFunction(selector, root);\r
8222     }else if(selector.length !== undefined){\r
8223         els = selector;\r
8224     }else{\r
8225         throw "Invalid selector";\r
8226     }\r
8227     return new Ext.CompositeElementLite(els);\r
8228 };\r
8229 /**\r
8230  * Selects elements based on the passed CSS selector to enable {@link Ext.Element Element} methods\r
8231  * to be applied to many related elements in one statement through the returned {@link Ext.CompositeElement CompositeElement} or\r
8232  * {@link Ext.CompositeElementLite CompositeElementLite} object.\r
8233  * @param {String/Array} selector The CSS selector or an array of elements\r
8234  * @param {Boolean} unique (optional) true to create a unique Ext.Element for each element (defaults to a shared flyweight object)\r
8235  * @param {HTMLElement/String} root (optional) The root element of the query or id of the root\r
8236  * @return {CompositeElementLite/CompositeElement}\r
8237  * @member Ext\r
8238  * @method select\r
8239  */\r
8240 Ext.select = Ext.Element.select;/**\r
8241  * @class Ext.CompositeElementLite\r
8242  */\r
8243 Ext.apply(Ext.CompositeElementLite.prototype, { \r
8244         addElements : function(els, root){\r
8245         if(!els){\r
8246             return this;\r
8247         }\r
8248         if(typeof els == "string"){\r
8249             els = Ext.Element.selectorFunction(els, root);\r
8250         }\r
8251         var yels = this.elements;        \r
8252             Ext.each(els, function(e) {\r
8253                 yels.push(Ext.get(e));\r
8254         });\r
8255         return this;\r
8256     },\r
8257     \r
8258     /**\r
8259     * Clears this composite and adds the elements returned by the passed selector.\r
8260     * @param {String/Array} els A string CSS selector, an array of elements or an element\r
8261     * @return {CompositeElement} this\r
8262     */\r
8263     fill : function(els){\r
8264         this.elements = [];\r
8265         this.add(els);\r
8266         return this;\r
8267     },\r
8268     \r
8269     /**\r
8270      * Returns the first Element\r
8271      * @return {Ext.Element}\r
8272      */\r
8273     first : function(){\r
8274         return this.item(0);\r
8275     },   \r
8276     \r
8277     /**\r
8278      * Returns the last Element\r
8279      * @return {Ext.Element}\r
8280      */\r
8281     last : function(){\r
8282         return this.item(this.getCount()-1);\r
8283     },\r
8284     \r
8285     /**\r
8286      * Returns true if this composite contains the passed element\r
8287      * @param el {Mixed} The id of an element, or an Ext.Element, or an HtmlElement to find within the composite collection.\r
8288      * @return Boolean\r
8289      */\r
8290     contains : function(el){\r
8291         return this.indexOf(el) != -1;\r
8292     },\r
8293 \r
8294     /**\r
8295     * Filters this composite to only elements that match the passed selector.\r
8296     * @param {String} selector A string CSS selector\r
8297     * @return {CompositeElement} this\r
8298     */\r
8299     filter : function(selector){\r
8300         var els = [];\r
8301         this.each(function(el){\r
8302             if(el.is(selector)){\r
8303                 els[els.length] = el.dom;\r
8304             }\r
8305         });\r
8306         this.fill(els);\r
8307         return this;\r
8308     },
8309     
8310     /**\r
8311     * Removes the specified element(s).\r
8312     * @param {Mixed} el The id of an element, the Element itself, the index of the element in this composite\r
8313     * or an array of any of those.\r
8314     * @param {Boolean} removeDom (optional) True to also remove the element from the document\r
8315     * @return {CompositeElement} this\r
8316     */\r
8317     removeElement : function(keys, removeDom){\r
8318         var me = this,\r
8319                 els = this.elements,        \r
8320                 el;             \r
8321             Ext.each(keys, function(val){\r
8322                     if ((el = (els[val] || els[val = me.indexOf(val)]))) {\r
8323                         if(removeDom){\r
8324                     if(el.dom){\r
8325                         el.remove();\r
8326                     }else{\r
8327                         Ext.removeNode(el);\r
8328                     }\r
8329                 }\r
8330                         els.splice(val, 1);                     \r
8331                         }\r
8332             });\r
8333         return this;\r
8334     }    \r
8335 });
8336 /**\r
8337  * @class Ext.CompositeElement\r
8338  * @extends Ext.CompositeElementLite\r
8339  * Standard composite class. Creates a Ext.Element for every element in the collection.\r
8340  * <br><br>\r
8341  * <b>NOTE: Although they are not listed, this class supports all of the set/update methods of Ext.Element. All Ext.Element\r
8342  * actions will be performed on all the elements in this collection.</b>\r
8343  * <br><br>\r
8344  * All methods return <i>this</i> and can be chained.\r
8345  <pre><code>\r
8346  var els = Ext.select("#some-el div.some-class", true);\r
8347  // or select directly from an existing element\r
8348  var el = Ext.get('some-el');\r
8349  el.select('div.some-class', true);\r
8350 \r
8351  els.setWidth(100); // all elements become 100 width\r
8352  els.hide(true); // all elements fade out and hide\r
8353  // or\r
8354  els.setWidth(100).hide(true);\r
8355  </code></pre>\r
8356  */\r
8357 Ext.CompositeElement = function(els, root){\r
8358     this.elements = [];\r
8359     this.add(els, root);\r
8360 };\r
8361 \r
8362 Ext.extend(Ext.CompositeElement, Ext.CompositeElementLite, {\r
8363     invoke : function(fn, args){\r
8364             Ext.each(this.elements, function(e) {\r
8365                 Ext.Element.prototype[fn].apply(e, args);\r
8366         });\r
8367         return this;\r
8368     },\r
8369     \r
8370     /**\r
8371     * Adds elements to this composite.\r
8372     * @param {String/Array} els A string CSS selector, an array of elements or an element\r
8373     * @return {CompositeElement} this\r
8374     */\r
8375     add : function(els, root){\r
8376             if(!els){\r
8377             return this;\r
8378         }\r
8379         if(typeof els == "string"){\r
8380             els = Ext.Element.selectorFunction(els, root);\r
8381         }\r
8382         var yels = this.elements;        \r
8383             Ext.each(els, function(e) {\r
8384                 yels.push(Ext.get(e));\r
8385         });\r
8386         return this;\r
8387     },    \r
8388     \r
8389     /**\r
8390      * Returns the Element object at the specified index\r
8391      * @param {Number} index\r
8392      * @return {Ext.Element}\r
8393      */\r
8394     item : function(index){\r
8395         return this.elements[index] || null;\r
8396     },\r
8397 \r
8398 \r
8399     indexOf : function(el){\r
8400         return this.elements.indexOf(Ext.get(el));\r
8401     },\r
8402         \r
8403     filter : function(selector){\r
8404                 var me = this,\r
8405                         out = [];\r
8406                         \r
8407                 Ext.each(me.elements, function(el) {    \r
8408                         if(el.is(selector)){\r
8409                                 out.push(Ext.get(el));\r
8410                         }\r
8411                 });\r
8412                 me.elements = out;\r
8413                 return me;\r
8414         },\r
8415         \r
8416         /**\r
8417     * Calls the passed function passing (el, this, index) for each element in this composite.\r
8418     * @param {Function} fn The function to call\r
8419     * @param {Object} scope (optional) The <i>this</i> object (defaults to the element)\r
8420     * @return {CompositeElement} this\r
8421     */\r
8422     each : function(fn, scope){        \r
8423         Ext.each(this.elements, function(e,i) {\r
8424                 return fn.call(scope || e, e, this, i);\r
8425         }, this);\r
8426         return this;\r
8427     }\r
8428 });\r
8429 \r
8430 /**\r
8431  * Selects elements based on the passed CSS selector to enable {@link Ext.Element Element} methods\r
8432  * to be applied to many related elements in one statement through the returned {@link Ext.CompositeElement CompositeElement} or\r
8433  * {@link Ext.CompositeElementLite CompositeElementLite} object.\r
8434  * @param {String/Array} selector The CSS selector or an array of elements\r
8435  * @param {Boolean} unique (optional) true to create a unique Ext.Element for each element (defaults to a shared flyweight object)\r
8436  * @param {HTMLElement/String} root (optional) The root element of the query or id of the root\r
8437  * @return {CompositeElementLite/CompositeElement}\r
8438  * @member Ext.Element\r
8439  * @method select\r
8440  */\r
8441 Ext.Element.select = function(selector, unique, root){\r
8442     var els;\r
8443     if(typeof selector == "string"){\r
8444         els = Ext.Element.selectorFunction(selector, root);\r
8445     }else if(selector.length !== undefined){\r
8446         els = selector;\r
8447     }else{\r
8448         throw "Invalid selector";\r
8449     }\r
8450 \r
8451     return (unique === true) ? new Ext.CompositeElement(els) : new Ext.CompositeElementLite(els);\r
8452 };
8453 \r
8454 /**\r
8455  * Selects elements based on the passed CSS selector to enable {@link Ext.Element Element} methods\r
8456  * to be applied to many related elements in one statement through the returned {@link Ext.CompositeElement CompositeElement} or\r
8457  * {@link Ext.CompositeElementLite CompositeElementLite} object.\r
8458  * @param {String/Array} selector The CSS selector or an array of elements\r
8459  * @param {Boolean} unique (optional) true to create a unique Ext.Element for each element (defaults to a shared flyweight object)\r
8460  * @param {HTMLElement/String} root (optional) The root element of the query or id of the root\r
8461  * @return {CompositeElementLite/CompositeElement}\r
8462  * @member Ext.Element\r
8463  * @method select\r
8464  */\r
8465 Ext.select = Ext.Element.select;(function(){\r
8466     var BEFOREREQUEST = "beforerequest",\r
8467         REQUESTCOMPLETE = "requestcomplete",\r
8468         REQUESTEXCEPTION = "requestexception",\r
8469         UNDEFINED = undefined,\r
8470         LOAD = 'load',\r
8471         POST = 'POST',\r
8472         GET = 'GET',\r
8473         WINDOW = window;\r
8474     \r
8475     /**\r
8476      * @class Ext.data.Connection\r
8477      * @extends Ext.util.Observable\r
8478      * <p>The class encapsulates a connection to the page's originating domain, allowing requests to be made\r
8479      * either to a configured URL, or to a URL specified at request time.</p>\r
8480      * <p>Requests made by this class are asynchronous, and will return immediately. No data from\r
8481      * the server will be available to the statement immediately following the {@link #request} call.\r
8482      * To process returned data, use a\r
8483      * <a href="#request-option-success" ext:member="request-option-success" ext:cls="Ext.data.Connection">success callback</a>\r
8484      * in the request options object,\r
8485      * or an {@link #requestcomplete event listener}.</p>\r
8486      * <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\r
8487      * is they are <b>not</b> performed using XMLHttpRequests. Instead the form is submitted in the standard\r
8488      * manner with the DOM <tt>&lt;form></tt> element temporarily modified to have its\r
8489      * <a href="http://www.w3.org/TR/REC-html40/present/frames.html#adef-target">target</a> set to refer\r
8490      * to a dynamically generated, hidden <tt>&lt;iframe></tt> which is inserted into the document\r
8491      * but removed after the return data has been gathered.</p>\r
8492      * <p>The server response is parsed by the browser to create the document for the IFRAME. If the\r
8493      * server is using JSON to send the return object, then the\r
8494      * <a href="http://www.w3.org/Protocols/rfc2616/rfc2616-sec14.html#sec14.17">Content-Type</a> header\r
8495      * must be set to "text/html" in order to tell the browser to insert the text unchanged into the document body.</p>\r
8496      * <p>Characters which are significant to an HTML parser must be sent as HTML entities, so encode\r
8497      * "&lt;" as "&amp;lt;", "&amp;" as "&amp;amp;" etc.</p>\r
8498      * <p>The response text is retrieved from the document, and a fake XMLHttpRequest object\r
8499      * is created containing a <tt>responseText</tt> property in order to conform to the\r
8500      * requirements of event handlers and callbacks.</p>\r
8501      * <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>\r
8502      * and some server technologies (notably JEE) may require some custom processing in order to\r
8503      * retrieve parameter names and parameter values from the packet content.</p>\r
8504      * @constructor\r
8505      * @param {Object} config a configuration object.\r
8506      */\r
8507     Ext.data.Connection = function(config){    \r
8508         Ext.apply(this, config);\r
8509         this.addEvents(\r
8510             /**\r
8511              * @event beforerequest\r
8512              * Fires before a network request is made to retrieve a data object.\r
8513              * @param {Connection} conn This Connection object.\r
8514              * @param {Object} options The options config object passed to the {@link #request} method.\r
8515              */\r
8516             BEFOREREQUEST,\r
8517             /**\r
8518              * @event requestcomplete\r
8519              * Fires if the request was successfully completed.\r
8520              * @param {Connection} conn This Connection object.\r
8521              * @param {Object} response The XHR object containing the response data.\r
8522              * See <a href="http://www.w3.org/TR/XMLHttpRequest/">The XMLHttpRequest Object</a>\r
8523              * for details.\r
8524              * @param {Object} options The options config object passed to the {@link #request} method.\r
8525              */\r
8526             REQUESTCOMPLETE,\r
8527             /**\r
8528              * @event requestexception\r
8529              * Fires if an error HTTP status was returned from the server.\r
8530              * See <a href="http://www.w3.org/Protocols/rfc2616/rfc2616-sec10.html">HTTP Status Code Definitions</a>\r
8531              * for details of HTTP status codes.\r
8532              * @param {Connection} conn This Connection object.\r
8533              * @param {Object} response The XHR object containing the response data.\r
8534              * See <a href="http://www.w3.org/TR/XMLHttpRequest/">The XMLHttpRequest Object</a>\r
8535              * for details.\r
8536              * @param {Object} options The options config object passed to the {@link #request} method.\r
8537              */\r
8538             REQUESTEXCEPTION\r
8539         );\r
8540         Ext.data.Connection.superclass.constructor.call(this);\r
8541     };\r
8542 \r
8543     // private\r
8544     function handleResponse(response){\r
8545         this.transId = false;\r
8546         var options = response.argument.options;\r
8547         response.argument = options ? options.argument : null;\r
8548         this.fireEvent(REQUESTCOMPLETE, this, response, options);\r
8549         if(options.success){\r
8550             options.success.call(options.scope, response, options);\r
8551         }\r
8552         if(options.callback){\r
8553             options.callback.call(options.scope, options, true, response);\r
8554         }\r
8555     }\r
8556 \r
8557     // private\r
8558     function handleFailure(response, e){\r
8559         this.transId = false;\r
8560         var options = response.argument.options;\r
8561         response.argument = options ? options.argument : null;\r
8562         this.fireEvent(REQUESTEXCEPTION, this, response, options, e);\r
8563         if(options.failure){\r
8564             options.failure.call(options.scope, response, options);\r
8565         }\r
8566         if(options.callback){\r
8567             options.callback.call(options.scope, options, false, response);\r
8568         }\r
8569     }\r
8570 \r
8571     // private\r
8572     function doFormUpload(o, ps, url){\r
8573         var id = Ext.id(),\r
8574             doc = document,\r
8575             frame = doc.createElement('iframe'),\r
8576             form = Ext.getDom(o.form),\r
8577             hiddens = [],\r
8578             hd,\r
8579             encoding = 'multipart/form-data',\r
8580             buf = {\r
8581                 target: form.target,\r
8582                 method: form.method,\r
8583                 encoding: form.encoding,\r
8584                 enctype: form.enctype,\r
8585                 action: form.action\r
8586             };\r
8587             \r
8588         Ext.apply(frame, {\r
8589             id: id,\r
8590             name: id,\r
8591             className: 'x-hidden',\r
8592             src: Ext.SSL_SECURE_URL // for IE\r
8593         });     \r
8594         doc.body.appendChild(frame);\r
8595         \r
8596         // This is required so that IE doesn't pop the response up in a new window.\r
8597         if(Ext.isIE){\r
8598            document.frames[id].name = id;\r
8599         }\r
8600         \r
8601         Ext.apply(form, {\r
8602             target: id,\r
8603             method: POST,\r
8604             enctype: encoding,\r
8605             encoding: encoding,\r
8606             action: url || buf.action\r
8607         });\r
8608         \r
8609         // add dynamic params            \r
8610         ps = Ext.urlDecode(ps, false);\r
8611         for(var k in ps){\r
8612             if(ps.hasOwnProperty(k)){\r
8613                 hd = doc.createElement('input');\r
8614                 hd.type = 'hidden';                    \r
8615                 hd.value = ps[hd.name = k];\r
8616                 form.appendChild(hd);\r
8617                 hiddens.push(hd);\r
8618             }\r
8619         }        \r
8620 \r
8621         function cb(){\r
8622             var me = this,\r
8623                 // bogus response object\r
8624                 r = {responseText : '',\r
8625                      responseXML : null,\r
8626                      argument : o.argument},\r
8627                 doc,\r
8628                 firstChild;\r
8629 \r
8630             try{ \r
8631                 doc = frame.contentWindow.document || frame.contentDocument || WINDOW.frames[id].document;\r
8632                 if(doc){\r
8633                     if(doc.body){\r
8634                         if(/textarea/i.test((firstChild = doc.body.firstChild || {}).tagName)){ // json response wrapped in textarea                        \r
8635                             r.responseText = firstChild.value;\r
8636                         }else{\r
8637                             r.responseText = doc.body.innerHTML;\r
8638                         }\r
8639                     }\r
8640                     //in IE the document may still have a body even if returns XML.\r
8641                     r.responseXML = doc.XMLDocument || doc;\r
8642                 }\r
8643             }\r
8644             catch(e) {}\r
8645 \r
8646             Ext.EventManager.removeListener(frame, LOAD, cb, me);\r
8647 \r
8648             me.fireEvent(REQUESTCOMPLETE, me, r, o);\r
8649             \r
8650             function runCallback(fn, scope, args){\r
8651                 if(Ext.isFunction(fn)){\r
8652                     fn.apply(scope, args);\r
8653                 }\r
8654             }\r
8655 \r
8656             runCallback(o.success, o.scope, [r, o]);\r
8657             runCallback(o.callback, o.scope, [o, true, r]);\r
8658 \r
8659             if(!me.debugUploads){\r
8660                 setTimeout(function(){Ext.removeNode(frame);}, 100);\r
8661             }\r
8662         }\r
8663 \r
8664         Ext.EventManager.on(frame, LOAD, cb, this);\r
8665         form.submit();\r
8666         \r
8667         Ext.apply(form, buf);\r
8668         Ext.each(hiddens, function(h) {\r
8669             Ext.removeNode(h);\r
8670         });\r
8671     }\r
8672 \r
8673     Ext.extend(Ext.data.Connection, Ext.util.Observable, {\r
8674         /**\r
8675          * @cfg {String} url (Optional) <p>The default URL to be used for requests to the server. Defaults to undefined.</p>\r
8676          * <p>The <code>url</code> config may be a function which <i>returns</i> the URL to use for the Ajax request. The scope\r
8677          * (<code><b>this</b></code> reference) of the function is the <code>scope</code> option passed to the {@link #request} method.</p>\r
8678          */\r
8679         /**\r
8680          * @cfg {Object} extraParams (Optional) An object containing properties which are used as\r
8681          * extra parameters to each request made by this object. (defaults to undefined)\r
8682          */\r
8683         /**\r
8684          * @cfg {Object} defaultHeaders (Optional) An object containing request headers which are added\r
8685          *  to each request made by this object. (defaults to undefined)\r
8686          */\r
8687         /**\r
8688          * @cfg {String} method (Optional) The default HTTP method to be used for requests.\r
8689          * (defaults to undefined; if not set, but {@link #request} params are present, POST will be used;\r
8690          * otherwise, GET will be used.)\r
8691          */\r
8692         /**\r
8693          * @cfg {Number} timeout (Optional) The timeout in milliseconds to be used for requests. (defaults to 30000)\r
8694          */\r
8695         timeout : 30000,\r
8696         /**\r
8697          * @cfg {Boolean} autoAbort (Optional) Whether this request should abort any pending requests. (defaults to false)\r
8698          * @type Boolean\r
8699          */\r
8700         autoAbort:false,\r
8701     \r
8702         /**\r
8703          * @cfg {Boolean} disableCaching (Optional) True to add a unique cache-buster param to GET requests. (defaults to true)\r
8704          * @type Boolean\r
8705          */\r
8706         disableCaching: true,\r
8707         \r
8708         /**\r
8709          * @cfg {String} disableCachingParam (Optional) Change the parameter which is sent went disabling caching\r
8710          * through a cache buster. Defaults to '_dc'\r
8711          * @type String\r
8712          */\r
8713         disableCachingParam: '_dc',\r
8714         \r
8715         /**\r
8716          * <p>Sends an HTTP request to a remote server.</p>\r
8717          * <p><b>Important:</b> Ajax server requests are asynchronous, and this call will\r
8718          * return before the response has been received. Process any returned data\r
8719          * in a callback function.</p>\r
8720          * <pre><code>\r
8721 Ext.Ajax.request({\r
8722    url: 'ajax_demo/sample.json',\r
8723    success: function(response, opts) {\r
8724       var obj = Ext.decode(response.responseText);\r
8725       console.dir(obj);\r
8726    },\r
8727    failure: function(response, opts) {\r
8728       console.log('server-side failure with status code ' + response.status);\r
8729    }\r
8730 });\r
8731          * </code></pre>\r
8732          * <p>To execute a callback function in the correct scope, use the <tt>scope</tt> option.</p>\r
8733          * @param {Object} options An object which may contain the following properties:<ul>\r
8734          * <li><b>url</b> : String/Function (Optional)<div class="sub-desc">The URL to\r
8735          * which to send the request, or a function to call which returns a URL string. The scope of the\r
8736          * function is specified by the <tt>scope</tt> option. Defaults to the configured\r
8737          * <tt>{@link #url}</tt>.</div></li>\r
8738          * <li><b>params</b> : Object/String/Function (Optional)<div class="sub-desc">\r
8739          * An object containing properties which are used as parameters to the\r
8740          * request, a url encoded string or a function to call to get either. The scope of the function\r
8741          * is specified by the <tt>scope</tt> option.</div></li>\r
8742          * <li><b>method</b> : String (Optional)<div class="sub-desc">The HTTP method to use\r
8743          * for the request. Defaults to the configured method, or if no method was configured,\r
8744          * "GET" if no parameters are being sent, and "POST" if parameters are being sent.  Note that\r
8745          * the method name is case-sensitive and should be all caps.</div></li>\r
8746          * <li><b>callback</b> : Function (Optional)<div class="sub-desc">The\r
8747          * function to be called upon receipt of the HTTP response. The callback is\r
8748          * called regardless of success or failure and is passed the following\r
8749          * parameters:<ul>\r
8750          * <li><b>options</b> : Object<div class="sub-desc">The parameter to the request call.</div></li>\r
8751          * <li><b>success</b> : Boolean<div class="sub-desc">True if the request succeeded.</div></li>\r
8752          * <li><b>response</b> : Object<div class="sub-desc">The XMLHttpRequest object containing the response data. \r
8753          * See <a href="http://www.w3.org/TR/XMLHttpRequest/">http://www.w3.org/TR/XMLHttpRequest/</a> for details about \r
8754          * accessing elements of the response.</div></li>\r
8755          * </ul></div></li>\r
8756          * <li><a id="request-option-success"></a><b>success</b> : Function (Optional)<div class="sub-desc">The function\r
8757          * to be called upon success of the request. The callback is passed the following\r
8758          * parameters:<ul>\r
8759          * <li><b>response</b> : Object<div class="sub-desc">The XMLHttpRequest object containing the response data.</div></li>\r
8760          * <li><b>options</b> : Object<div class="sub-desc">The parameter to the request call.</div></li>\r
8761          * </ul></div></li>\r
8762          * <li><b>failure</b> : Function (Optional)<div class="sub-desc">The function\r
8763          * to be called upon failure of the request. The callback is passed the\r
8764          * following parameters:<ul>\r
8765          * <li><b>response</b> : Object<div class="sub-desc">The XMLHttpRequest object containing the response data.</div></li>\r
8766          * <li><b>options</b> : Object<div class="sub-desc">The parameter to the request call.</div></li>\r
8767          * </ul></div></li>\r
8768          * <li><b>scope</b> : Object (Optional)<div class="sub-desc">The scope in\r
8769          * which to execute the callbacks: The "this" object for the callback function. If the <tt>url</tt>, or <tt>params</tt> options were\r
8770          * specified as functions from which to draw values, then this also serves as the scope for those function calls.\r
8771          * Defaults to the browser window.</div></li>\r
8772          * <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>\r
8773          * <li><b>form</b> : Element/HTMLElement/String (Optional)<div class="sub-desc">The <tt>&lt;form&gt;</tt>\r
8774          * Element or the id of the <tt>&lt;form&gt;</tt> to pull parameters from.</div></li>\r
8775          * <li><a id="request-option-isUpload"></a><b>isUpload</b> : Boolean (Optional)<div class="sub-desc"><b>Only meaningful when used \r
8776          * with the <tt>form</tt> option</b>.\r
8777          * <p>True if the form object is a file upload (will be set automatically if the form was\r
8778          * configured with <b><tt>enctype</tt></b> "multipart/form-data").</p>\r
8779          * <p>File uploads are not performed using normal "Ajax" techniques, that is they are <b>not</b>\r
8780          * performed using XMLHttpRequests. Instead the form is submitted in the standard manner with the\r
8781          * DOM <tt>&lt;form></tt> element temporarily modified to have its\r
8782          * <a href="http://www.w3.org/TR/REC-html40/present/frames.html#adef-target">target</a> set to refer\r
8783          * to a dynamically generated, hidden <tt>&lt;iframe></tt> which is inserted into the document\r
8784          * but removed after the return data has been gathered.</p>\r
8785          * <p>The server response is parsed by the browser to create the document for the IFRAME. If the\r
8786          * server is using JSON to send the return object, then the\r
8787          * <a href="http://www.w3.org/Protocols/rfc2616/rfc2616-sec14.html#sec14.17">Content-Type</a> header\r
8788          * must be set to "text/html" in order to tell the browser to insert the text unchanged into the document body.</p>\r
8789          * <p>The response text is retrieved from the document, and a fake XMLHttpRequest object\r
8790          * is created containing a <tt>responseText</tt> property in order to conform to the\r
8791          * requirements of event handlers and callbacks.</p>\r
8792          * <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>\r
8793          * and some server technologies (notably JEE) may require some custom processing in order to\r
8794          * retrieve parameter names and parameter values from the packet content.</p>\r
8795          * </div></li>\r
8796          * <li><b>headers</b> : Object (Optional)<div class="sub-desc">Request\r
8797          * headers to set for the request.</div></li>\r
8798          * <li><b>xmlData</b> : Object (Optional)<div class="sub-desc">XML document\r
8799          * to use for the post. Note: This will be used instead of params for the post\r
8800          * data. Any params will be appended to the URL.</div></li>\r
8801          * <li><b>jsonData</b> : Object/String (Optional)<div class="sub-desc">JSON\r
8802          * data to use as the post. Note: This will be used instead of params for the post\r
8803          * data. Any params will be appended to the URL.</div></li>\r
8804          * <li><b>disableCaching</b> : Boolean (Optional)<div class="sub-desc">True\r
8805          * to add a unique cache-buster param to GET requests.</div></li>\r
8806          * </ul></p>\r
8807          * <p>The options object may also contain any other property which might be needed to perform\r
8808          * postprocessing in a callback because it is passed to callback functions.</p>\r
8809          * @return {Number} transactionId The id of the server transaction. This may be used\r
8810          * to cancel the request.\r
8811          */\r
8812         request : function(o){\r
8813             var me = this;\r
8814             if(me.fireEvent(BEFOREREQUEST, me, o)){\r
8815                 if (o.el) {\r
8816                     if(!Ext.isEmpty(o.indicatorText)){\r
8817                         me.indicatorText = '<div class="loading-indicator">'+o.indicatorText+"</div>";\r
8818                     }\r
8819                     if(me.indicatorText) {\r
8820                         Ext.getDom(o.el).innerHTML = me.indicatorText;                        \r
8821                     }\r
8822                     o.success = (Ext.isFunction(o.success) ? o.success : function(){}).createInterceptor(function(response) {\r
8823                         Ext.getDom(o.el).innerHTML = response.responseText;\r
8824                     });\r
8825                 }\r
8826                 \r
8827                 var p = o.params,\r
8828                     url = o.url || me.url,                \r
8829                     method,\r
8830                     cb = {success: handleResponse,\r
8831                           failure: handleFailure,\r
8832                           scope: me,\r
8833                           argument: {options: o},\r
8834                           timeout : o.timeout || me.timeout\r
8835                     },\r
8836                     form,                    \r
8837                     serForm;                    \r
8838                   \r
8839                      \r
8840                 if (Ext.isFunction(p)) {\r
8841                     p = p.call(o.scope||WINDOW, o);\r
8842                 }\r
8843                                                            \r
8844                 p = Ext.urlEncode(me.extraParams, Ext.isObject(p) ? Ext.urlEncode(p) : p);    \r
8845                 \r
8846                 if (Ext.isFunction(url)) {\r
8847                     url = url.call(o.scope || WINDOW, o);\r
8848                 }\r
8849     \r
8850                 if((form = Ext.getDom(o.form))){\r
8851                     url = url || form.action;\r
8852                      if(o.isUpload || /multipart\/form-data/i.test(form.getAttribute("enctype"))) { \r
8853                          return doFormUpload.call(me, o, p, url);\r
8854                      }\r
8855                     serForm = Ext.lib.Ajax.serializeForm(form);                    \r
8856                     p = p ? (p + '&' + serForm) : serForm;\r
8857                 }\r
8858                 \r
8859                 method = o.method || me.method || ((p || o.xmlData || o.jsonData) ? POST : GET);\r
8860                 \r
8861                 if(method === GET && (me.disableCaching && o.disableCaching !== false) || o.disableCaching === true){\r
8862                     var dcp = o.disableCachingParam || me.disableCachingParam;\r
8863                     url = Ext.urlAppend(url, dcp + '=' + (new Date().getTime()));\r
8864                 }\r
8865                 \r
8866                 o.headers = Ext.apply(o.headers || {}, me.defaultHeaders || {});\r
8867                 \r
8868                 if(o.autoAbort === true || me.autoAbort) {\r
8869                     me.abort();\r
8870                 }\r
8871                  \r
8872                 if((method == GET || o.xmlData || o.jsonData) && p){\r
8873                     url = Ext.urlAppend(url, p);  \r
8874                     p = '';\r
8875                 }\r
8876                 return (me.transId = Ext.lib.Ajax.request(method, url, cb, p, o));\r
8877             }else{                \r
8878                 return o.callback ? o.callback.apply(o.scope, [o,UNDEFINED,UNDEFINED]) : null;\r
8879             }\r
8880         },\r
8881     \r
8882         /**\r
8883          * Determine whether this object has a request outstanding.\r
8884          * @param {Number} transactionId (Optional) defaults to the last transaction\r
8885          * @return {Boolean} True if there is an outstanding request.\r
8886          */\r
8887         isLoading : function(transId){\r
8888             return transId ? Ext.lib.Ajax.isCallInProgress(transId) : !! this.transId;            \r
8889         },\r
8890     \r
8891         /**\r
8892          * Aborts any outstanding request.\r
8893          * @param {Number} transactionId (Optional) defaults to the last transaction\r
8894          */\r
8895         abort : function(transId){\r
8896             if(transId || this.isLoading()){\r
8897                 Ext.lib.Ajax.abort(transId || this.transId);\r
8898             }\r
8899         }\r
8900     });\r
8901 })();\r
8902 \r
8903 /**\r
8904  * @class Ext.Ajax\r
8905  * @extends Ext.data.Connection\r
8906  * <p>The global Ajax request class that provides a simple way to make Ajax requests\r
8907  * with maximum flexibility.</p>\r
8908  * <p>Since Ext.Ajax is a singleton, you can set common properties/events for it once\r
8909  * and override them at the request function level only if necessary.</p>\r
8910  * <p>Common <b>Properties</b> you may want to set are:<div class="mdetail-params"><ul>\r
8911  * <li><b><tt>{@link #method}</tt></b><p class="sub-desc"></p></li>\r
8912  * <li><b><tt>{@link #extraParams}</tt></b><p class="sub-desc"></p></li>\r
8913  * <li><b><tt>{@link #url}</tt></b><p class="sub-desc"></p></li>\r
8914  * </ul></div>\r
8915  * <pre><code>\r
8916 // Default headers to pass in every request\r
8917 Ext.Ajax.defaultHeaders = {\r
8918     'Powered-By': 'Ext'\r
8919 };\r
8920  * </code></pre> \r
8921  * </p>\r
8922  * <p>Common <b>Events</b> you may want to set are:<div class="mdetail-params"><ul>\r
8923  * <li><b><tt>{@link Ext.data.Connection#beforerequest beforerequest}</tt></b><p class="sub-desc"></p></li>\r
8924  * <li><b><tt>{@link Ext.data.Connection#requestcomplete requestcomplete}</tt></b><p class="sub-desc"></p></li>\r
8925  * <li><b><tt>{@link Ext.data.Connection#requestexception requestexception}</tt></b><p class="sub-desc"></p></li>\r
8926  * </ul></div>\r
8927  * <pre><code>\r
8928 // Example: show a spinner during all Ajax requests\r
8929 Ext.Ajax.on('beforerequest', this.showSpinner, this);\r
8930 Ext.Ajax.on('requestcomplete', this.hideSpinner, this);\r
8931 Ext.Ajax.on('requestexception', this.hideSpinner, this);\r
8932  * </code></pre> \r
8933  * </p>\r
8934  * <p>An example request:</p>\r
8935  * <pre><code>\r
8936 // Basic request\r
8937 Ext.Ajax.{@link Ext.data.Connection#request request}({\r
8938    url: 'foo.php',\r
8939    success: someFn,\r
8940    failure: otherFn,\r
8941    headers: {\r
8942        'my-header': 'foo'\r
8943    },\r
8944    params: { foo: 'bar' }\r
8945 });\r
8946 \r
8947 // Simple ajax form submission\r
8948 Ext.Ajax.{@link Ext.data.Connection#request request}({\r
8949     form: 'some-form',\r
8950     params: 'foo=bar'\r
8951 });\r
8952  * </code></pre> \r
8953  * </p>\r
8954  * @singleton\r
8955  */\r
8956 Ext.Ajax = new Ext.data.Connection({\r
8957     /**\r
8958      * @cfg {String} url @hide\r
8959      */\r
8960     /**\r
8961      * @cfg {Object} extraParams @hide\r
8962      */\r
8963     /**\r
8964      * @cfg {Object} defaultHeaders @hide\r
8965      */\r
8966     /**\r
8967      * @cfg {String} method (Optional) @hide\r
8968      */\r
8969     /**\r
8970      * @cfg {Number} timeout (Optional) @hide\r
8971      */\r
8972     /**\r
8973      * @cfg {Boolean} autoAbort (Optional) @hide\r
8974      */\r
8975 \r
8976     /**\r
8977      * @cfg {Boolean} disableCaching (Optional) @hide\r
8978      */\r
8979 \r
8980     /**\r
8981      * @property  disableCaching\r
8982      * True to add a unique cache-buster param to GET requests. (defaults to true)\r
8983      * @type Boolean\r
8984      */\r
8985     /**\r
8986      * @property  url\r
8987      * The default URL to be used for requests to the server. (defaults to undefined)\r
8988      * If the server receives all requests through one URL, setting this once is easier than\r
8989      * entering it on every request.\r
8990      * @type String\r
8991      */\r
8992     /**\r
8993      * @property  extraParams\r
8994      * An object containing properties which are used as extra parameters to each request made\r
8995      * by this object (defaults to undefined). Session information and other data that you need\r
8996      * to pass with each request are commonly put here.\r
8997      * @type Object\r
8998      */\r
8999     /**\r
9000      * @property  defaultHeaders\r
9001      * An object containing request headers which are added to each request made by this object\r
9002      * (defaults to undefined).\r
9003      * @type Object\r
9004      */\r
9005     /**\r
9006      * @property  method\r
9007      * The default HTTP method to be used for requests. Note that this is case-sensitive and\r
9008      * should be all caps (defaults to undefined; if not set but params are present will use\r
9009      * <tt>"POST"</tt>, otherwise will use <tt>"GET"</tt>.)\r
9010      * @type String\r
9011      */\r
9012     /**\r
9013      * @property  timeout\r
9014      * The timeout in milliseconds to be used for requests. (defaults to 30000)\r
9015      * @type Number\r
9016      */\r
9017 \r
9018     /**\r
9019      * @property  autoAbort\r
9020      * Whether a new request should abort any pending requests. (defaults to false)\r
9021      * @type Boolean\r
9022      */\r
9023     autoAbort : false,\r
9024 \r
9025     /**\r
9026      * Serialize the passed form into a url encoded string\r
9027      * @param {String/HTMLElement} form\r
9028      * @return {String}\r
9029      */\r
9030     serializeForm : function(form){\r
9031         return Ext.lib.Ajax.serializeForm(form);\r
9032     }\r
9033 });\r
9034 /**
9035  * @class Ext.Updater
9036  * @extends Ext.util.Observable
9037  * Provides AJAX-style update capabilities for Element objects.  Updater can be used to {@link #update}
9038  * an {@link Ext.Element} once, or you can use {@link #startAutoRefresh} to set up an auto-updating
9039  * {@link Ext.Element Element} on a specific interval.<br><br>
9040  * Usage:<br>
9041  * <pre><code>
9042  * var el = Ext.get("foo"); // Get Ext.Element object
9043  * var mgr = el.getUpdater();
9044  * mgr.update({
9045         url: "http://myserver.com/index.php",
9046         params: {
9047             param1: "foo",
9048             param2: "bar"
9049         }
9050  * });
9051  * ...
9052  * mgr.formUpdate("myFormId", "http://myserver.com/index.php");
9053  * <br>
9054  * // or directly (returns the same Updater instance)
9055  * var mgr = new Ext.Updater("myElementId");
9056  * mgr.startAutoRefresh(60, "http://myserver.com/index.php");
9057  * mgr.on("update", myFcnNeedsToKnow);
9058  * <br>
9059  * // short handed call directly from the element object
9060  * Ext.get("foo").load({
9061         url: "bar.php",
9062         scripts: true,
9063         params: "param1=foo&amp;param2=bar",
9064         text: "Loading Foo..."
9065  * });
9066  * </code></pre>
9067  * @constructor
9068  * Create new Updater directly.
9069  * @param {Mixed} el The element to update
9070  * @param {Boolean} forceNew (optional) By default the constructor checks to see if the passed element already
9071  * has an Updater and if it does it returns the same instance. This will skip that check (useful for extending this class).
9072  */
9073 Ext.UpdateManager = Ext.Updater = Ext.extend(Ext.util.Observable, 
9074 function() {
9075         var BEFOREUPDATE = "beforeupdate",
9076                 UPDATE = "update",
9077                 FAILURE = "failure";
9078                 
9079         // private
9080     function processSuccess(response){      
9081             var me = this;
9082         me.transaction = null;
9083         if (response.argument.form && response.argument.reset) {
9084             try { // put in try/catch since some older FF releases had problems with this
9085                 response.argument.form.reset();
9086             } catch(e){}
9087         }
9088         if (me.loadScripts) {
9089             me.renderer.render(me.el, response, me,
9090                updateComplete.createDelegate(me, [response]));
9091         } else {
9092             me.renderer.render(me.el, response, me);
9093             updateComplete.call(me, response);
9094         }
9095     }
9096     
9097     // private
9098     function updateComplete(response, type, success){
9099         this.fireEvent(type || UPDATE, this.el, response);
9100         if(Ext.isFunction(response.argument.callback)){
9101             response.argument.callback.call(response.argument.scope, this.el, Ext.isEmpty(success) ? true : false, response, response.argument.options);
9102         }
9103     }
9104
9105     // private
9106     function processFailure(response){              
9107         updateComplete.call(this, response, FAILURE, !!(this.transaction = null));
9108     }
9109             
9110         return {
9111             constructor: function(el, forceNew){
9112                     var me = this;
9113                 el = Ext.get(el);
9114                 if(!forceNew && el.updateManager){
9115                     return el.updateManager;
9116                 }
9117                 /**
9118                  * The Element object
9119                  * @type Ext.Element
9120                  */
9121                 me.el = el;
9122                 /**
9123                  * Cached url to use for refreshes. Overwritten every time update() is called unless "discardUrl" param is set to true.
9124                  * @type String
9125                  */
9126                 me.defaultUrl = null;
9127         
9128                 me.addEvents(
9129                     /**
9130                      * @event beforeupdate
9131                      * Fired before an update is made, return false from your handler and the update is cancelled.
9132                      * @param {Ext.Element} el
9133                      * @param {String/Object/Function} url
9134                      * @param {String/Object} params
9135                      */
9136                     BEFOREUPDATE,
9137                     /**
9138                      * @event update
9139                      * Fired after successful update is made.
9140                      * @param {Ext.Element} el
9141                      * @param {Object} oResponseObject The response Object
9142                      */
9143                     UPDATE,
9144                     /**
9145                      * @event failure
9146                      * Fired on update failure.
9147                      * @param {Ext.Element} el
9148                      * @param {Object} oResponseObject The response Object
9149                      */
9150                     FAILURE
9151                 );
9152         
9153                 Ext.apply(me, Ext.Updater.defaults);
9154                 /**
9155                  * Blank page URL to use with SSL file uploads (defaults to {@link Ext.Updater.defaults#sslBlankUrl}).
9156                  * @property sslBlankUrl
9157                  * @type String
9158                  */
9159                 /**
9160                  * Whether to append unique parameter on get request to disable caching (defaults to {@link Ext.Updater.defaults#disableCaching}).
9161                  * @property disableCaching
9162                  * @type Boolean
9163                  */
9164                 /**
9165                  * Text for loading indicator (defaults to {@link Ext.Updater.defaults#indicatorText}).
9166                  * @property indicatorText
9167                  * @type String
9168                  */
9169                 /**
9170                  * Whether to show indicatorText when loading (defaults to {@link Ext.Updater.defaults#showLoadIndicator}).
9171                  * @property showLoadIndicator
9172                  * @type String
9173                  */
9174                 /**
9175                  * Timeout for requests or form posts in seconds (defaults to {@link Ext.Updater.defaults#timeout}).
9176                  * @property timeout
9177                  * @type Number
9178                  */
9179                 /**
9180                  * True to process scripts in the output (defaults to {@link Ext.Updater.defaults#loadScripts}).
9181                  * @property loadScripts
9182                  * @type Boolean
9183                  */
9184         
9185                 /**
9186                  * Transaction object of the current executing transaction, or null if there is no active transaction.
9187                  */
9188                 me.transaction = null;
9189                 /**
9190                  * Delegate for refresh() prebound to "this", use myUpdater.refreshDelegate.createCallback(arg1, arg2) to bind arguments
9191                  * @type Function
9192                  */
9193                 me.refreshDelegate = me.refresh.createDelegate(me);
9194                 /**
9195                  * Delegate for update() prebound to "this", use myUpdater.updateDelegate.createCallback(arg1, arg2) to bind arguments
9196                  * @type Function
9197                  */
9198                 me.updateDelegate = me.update.createDelegate(me);
9199                 /**
9200                  * Delegate for formUpdate() prebound to "this", use myUpdater.formUpdateDelegate.createCallback(arg1, arg2) to bind arguments
9201                  * @type Function
9202                  */
9203                 me.formUpdateDelegate = (me.formUpdate || function(){}).createDelegate(me);     
9204                 
9205                         /**
9206                          * The renderer for this Updater (defaults to {@link Ext.Updater.BasicRenderer}).
9207                          */
9208                 me.renderer = me.renderer || me.getDefaultRenderer();
9209                 
9210                 Ext.Updater.superclass.constructor.call(me);
9211             },
9212         
9213                 /**
9214              * Sets the content renderer for this Updater. See {@link Ext.Updater.BasicRenderer#render} for more details.
9215              * @param {Object} renderer The object implementing the render() method
9216              */
9217             setRenderer : function(renderer){
9218                 this.renderer = renderer;
9219             },  
9220         
9221             /**
9222              * Returns the current content renderer for this Updater. See {@link Ext.Updater.BasicRenderer#render} for more details.
9223              * @return {Object}
9224              */
9225             getRenderer : function(){
9226                return this.renderer;
9227             },
9228
9229             /**
9230              * This is an overrideable method which returns a reference to a default
9231              * renderer class if none is specified when creating the Ext.Updater.
9232              * Defaults to {@link Ext.Updater.BasicRenderer}
9233              */
9234             getDefaultRenderer: function() {
9235                 return new Ext.Updater.BasicRenderer();
9236             },
9237                 
9238             /**
9239              * Sets the default URL used for updates.
9240              * @param {String/Function} defaultUrl The url or a function to call to get the url
9241              */
9242             setDefaultUrl : function(defaultUrl){
9243                 this.defaultUrl = defaultUrl;
9244             },
9245         
9246             /**
9247              * Get the Element this Updater is bound to
9248              * @return {Ext.Element} The element
9249              */
9250             getEl : function(){
9251                 return this.el;
9252             },
9253         
9254                 /**
9255              * Performs an <b>asynchronous</b> request, updating this element with the response.
9256              * If params are specified it uses POST, otherwise it uses GET.<br><br>
9257              * <b>Note:</b> Due to the asynchronous nature of remote server requests, the Element
9258              * will not have been fully updated when the function returns. To post-process the returned
9259              * data, use the callback option, or an <b><tt>update</tt></b> event handler.
9260              * @param {Object} options A config object containing any of the following options:<ul>
9261              * <li>url : <b>String/Function</b><p class="sub-desc">The URL to request or a function which
9262              * <i>returns</i> the URL (defaults to the value of {@link Ext.Ajax#url} if not specified).</p></li>
9263              * <li>method : <b>String</b><p class="sub-desc">The HTTP method to
9264              * use. Defaults to POST if the <tt>params</tt> argument is present, otherwise GET.</p></li>
9265              * <li>params : <b>String/Object/Function</b><p class="sub-desc">The
9266              * parameters to pass to the server (defaults to none). These may be specified as a url-encoded
9267              * string, or as an object containing properties which represent parameters,
9268              * or as a function, which returns such an object.</p></li>
9269              * <li>scripts : <b>Boolean</b><p class="sub-desc">If <tt>true</tt>
9270              * any &lt;script&gt; tags embedded in the response text will be extracted
9271              * and executed (defaults to {@link Ext.Updater.defaults#loadScripts}). If this option is specified,
9272              * the callback will be called <i>after</i> the execution of the scripts.</p></li>
9273              * <li>callback : <b>Function</b><p class="sub-desc">A function to
9274              * be called when the response from the server arrives. The following
9275              * parameters are passed:<ul>
9276              * <li><b>el</b> : Ext.Element<p class="sub-desc">The Element being updated.</p></li>
9277              * <li><b>success</b> : Boolean<p class="sub-desc">True for success, false for failure.</p></li>
9278              * <li><b>response</b> : XMLHttpRequest<p class="sub-desc">The XMLHttpRequest which processed the update.</p></li>
9279              * <li><b>options</b> : Object<p class="sub-desc">The config object passed to the update call.</p></li></ul>
9280              * </p></li>
9281              * <li>scope : <b>Object</b><p class="sub-desc">The scope in which
9282              * to execute the callback (The callback's <tt>this</tt> reference.) If the
9283              * <tt>params</tt> argument is a function, this scope is used for that function also.</p></li>
9284              * <li>discardUrl : <b>Boolean</b><p class="sub-desc">By default, the URL of this request becomes
9285              * the default URL for this Updater object, and will be subsequently used in {@link #refresh}
9286              * calls.  To bypass this behavior, pass <tt>discardUrl:true</tt> (defaults to false).</p></li>
9287              * <li>timeout : <b>Number</b><p class="sub-desc">The number of seconds to wait for a response before
9288              * timing out (defaults to {@link Ext.Updater.defaults#timeout}).</p></li>
9289              * <li>text : <b>String</b><p class="sub-desc">The text to use as the innerHTML of the
9290              * {@link Ext.Updater.defaults#indicatorText} div (defaults to 'Loading...').  To replace the entire div, not
9291              * just the text, override {@link Ext.Updater.defaults#indicatorText} directly.</p></li>
9292              * <li>nocache : <b>Boolean</b><p class="sub-desc">Only needed for GET
9293              * requests, this option causes an extra, auto-generated parameter to be appended to the request
9294              * to defeat caching (defaults to {@link Ext.Updater.defaults#disableCaching}).</p></li></ul>
9295              * <p>
9296              * For example:
9297         <pre><code>
9298         um.update({
9299             url: "your-url.php",
9300             params: {param1: "foo", param2: "bar"}, // or a URL encoded string
9301             callback: yourFunction,
9302             scope: yourObject, //(optional scope)
9303             discardUrl: true,
9304             nocache: true,
9305             text: "Loading...",
9306             timeout: 60,
9307             scripts: false // Save time by avoiding RegExp execution.
9308         });
9309         </code></pre>
9310              */
9311             update : function(url, params, callback, discardUrl){
9312                     var me = this,
9313                         cfg, 
9314                         callerScope;
9315                         
9316                 if(me.fireEvent(BEFOREUPDATE, me.el, url, params) !== false){               
9317                     if(Ext.isObject(url)){ // must be config object
9318                         cfg = url;
9319                         url = cfg.url;
9320                         params = params || cfg.params;
9321                         callback = callback || cfg.callback;
9322                         discardUrl = discardUrl || cfg.discardUrl;
9323                         callerScope = cfg.scope;                        
9324                         if(!Ext.isEmpty(cfg.nocache)){me.disableCaching = cfg.nocache;};
9325                         if(!Ext.isEmpty(cfg.text)){me.indicatorText = '<div class="loading-indicator">'+cfg.text+"</div>";};
9326                         if(!Ext.isEmpty(cfg.scripts)){me.loadScripts = cfg.scripts;};
9327                         if(!Ext.isEmpty(cfg.timeout)){me.timeout = cfg.timeout;};
9328                     }
9329                     me.showLoading();
9330         
9331                     if(!discardUrl){
9332                         me.defaultUrl = url;
9333                     }
9334                     if(Ext.isFunction(url)){
9335                         url = url.call(me);
9336                     }
9337         
9338                     var o = Ext.apply({}, {
9339                         url : url,
9340                         params: (Ext.isFunction(params) && callerScope) ? params.createDelegate(callerScope) : params,
9341                         success: processSuccess,
9342                         failure: processFailure,
9343                         scope: me,
9344                         callback: undefined,
9345                         timeout: (me.timeout*1000),
9346                         disableCaching: me.disableCaching,
9347                         argument: {
9348                             "options": cfg,
9349                             "url": url,
9350                             "form": null,
9351                             "callback": callback,
9352                             "scope": callerScope || window,
9353                             "params": params
9354                         }
9355                     }, cfg);
9356         
9357                     me.transaction = Ext.Ajax.request(o);
9358                 }
9359             },          
9360
9361                 /**
9362              * <p>Performs an async form post, updating this element with the response. If the form has the attribute
9363              * enctype="<a href="http://www.faqs.org/rfcs/rfc2388.html">multipart/form-data</a>", it assumes it's a file upload.
9364              * Uses this.sslBlankUrl for SSL file uploads to prevent IE security warning.</p>
9365              * <p>File uploads are not performed using normal "Ajax" techniques, that is they are <b>not</b>
9366              * performed using XMLHttpRequests. Instead the form is submitted in the standard manner with the
9367              * DOM <tt>&lt;form></tt> element temporarily modified to have its
9368              * <a href="http://www.w3.org/TR/REC-html40/present/frames.html#adef-target">target</a> set to refer
9369              * to a dynamically generated, hidden <tt>&lt;iframe></tt> which is inserted into the document
9370              * but removed after the return data has been gathered.</p>
9371              * <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>
9372              * and some server technologies (notably JEE) may require some custom processing in order to
9373              * retrieve parameter names and parameter values from the packet content.</p>
9374              * @param {String/HTMLElement} form The form Id or form element
9375              * @param {String} url (optional) The url to pass the form to. If omitted the action attribute on the form will be used.
9376              * @param {Boolean} reset (optional) Whether to try to reset the form after the update
9377              * @param {Function} callback (optional) Callback when transaction is complete. The following
9378              * parameters are passed:<ul>
9379              * <li><b>el</b> : Ext.Element<p class="sub-desc">The Element being updated.</p></li>
9380              * <li><b>success</b> : Boolean<p class="sub-desc">True for success, false for failure.</p></li>
9381              * <li><b>response</b> : XMLHttpRequest<p class="sub-desc">The XMLHttpRequest which processed the update.</p></li></ul>
9382              */
9383             formUpdate : function(form, url, reset, callback){
9384                     var me = this;
9385                 if(me.fireEvent(BEFOREUPDATE, me.el, form, url) !== false){
9386                     if(Ext.isFunction(url)){
9387                         url = url.call(me);
9388                     }
9389                     form = Ext.getDom(form)
9390                     me.transaction = Ext.Ajax.request({
9391                         form: form,
9392                         url:url,
9393                         success: processSuccess,
9394                         failure: processFailure,
9395                         scope: me,
9396                         timeout: (me.timeout*1000),
9397                         argument: {
9398                             "url": url,
9399                             "form": form,
9400                             "callback": callback,
9401                             "reset": reset
9402                         }
9403                     });
9404                     me.showLoading.defer(1, me);
9405                 }
9406             },
9407                         
9408             /**
9409              * Set this element to auto refresh.  Can be canceled by calling {@link #stopAutoRefresh}.
9410              * @param {Number} interval How often to update (in seconds).
9411              * @param {String/Object/Function} url (optional) The url for this request, a config object in the same format
9412              * supported by {@link #load}, or a function to call to get the url (defaults to the last used url).  Note that while
9413              * the url used in a load call can be reused by this method, other load config options will not be reused and must be
9414              * sepcified as part of a config object passed as this paramter if needed.
9415              * @param {String/Object} params (optional) The parameters to pass as either a url encoded string
9416              * "&param1=1&param2=2" or as an object {param1: 1, param2: 2}
9417              * @param {Function} callback (optional) Callback when transaction is complete - called with signature (oElement, bSuccess)
9418              * @param {Boolean} refreshNow (optional) Whether to execute the refresh now, or wait the interval
9419              */
9420             startAutoRefresh : function(interval, url, params, callback, refreshNow){
9421                     var me = this;
9422                 if(refreshNow){
9423                     me.update(url || me.defaultUrl, params, callback, true);
9424                 }
9425                 if(me.autoRefreshProcId){
9426                     clearInterval(me.autoRefreshProcId);
9427                 }
9428                 me.autoRefreshProcId = setInterval(me.update.createDelegate(me, [url || me.defaultUrl, params, callback, true]), interval * 1000);
9429             },
9430         
9431             /**
9432              * Stop auto refresh on this element.
9433              */
9434             stopAutoRefresh : function(){
9435                 if(this.autoRefreshProcId){
9436                     clearInterval(this.autoRefreshProcId);
9437                     delete this.autoRefreshProcId;
9438                 }
9439             },
9440         
9441             /**
9442              * Returns true if the Updater is currently set to auto refresh its content (see {@link #startAutoRefresh}), otherwise false.
9443              */
9444             isAutoRefreshing : function(){
9445                return !!this.autoRefreshProcId;
9446             },
9447         
9448             /**
9449              * Display the element's "loading" state. By default, the element is updated with {@link #indicatorText}. This
9450              * method may be overridden to perform a custom action while this Updater is actively updating its contents.
9451              */
9452             showLoading : function(){
9453                 if(this.showLoadIndicator){
9454                 this.el.dom.innerHTML = this.indicatorText;
9455                 }
9456             },
9457         
9458             /**
9459              * Aborts the currently executing transaction, if any.
9460              */
9461             abort : function(){
9462                 if(this.transaction){
9463                     Ext.Ajax.abort(this.transaction);
9464                 }
9465             },
9466         
9467             /**
9468              * Returns true if an update is in progress, otherwise false.
9469              * @return {Boolean}
9470              */
9471             isUpdating : function(){        
9472                 return this.transaction ? Ext.Ajax.isLoading(this.transaction) : false;        
9473             },
9474             
9475             /**
9476              * Refresh the element with the last used url or defaultUrl. If there is no url, it returns immediately
9477              * @param {Function} callback (optional) Callback when transaction is complete - called with signature (oElement, bSuccess)
9478              */
9479             refresh : function(callback){
9480                 if(this.defaultUrl){
9481                         this.update(this.defaultUrl, null, callback, true);
9482                 }
9483             }
9484     }
9485 }());
9486
9487 /**
9488  * @class Ext.Updater.defaults
9489  * The defaults collection enables customizing the default properties of Updater
9490  */
9491 Ext.Updater.defaults = {
9492    /**
9493      * Timeout for requests or form posts in seconds (defaults to 30 seconds).
9494      * @type Number
9495      */
9496     timeout : 30,    
9497     /**
9498      * True to append a unique parameter to GET requests to disable caching (defaults to false).
9499      * @type Boolean
9500      */
9501     disableCaching : false,
9502     /**
9503      * Whether or not to show {@link #indicatorText} during loading (defaults to true).
9504      * @type Boolean
9505      */
9506     showLoadIndicator : true,
9507     /**
9508      * Text for loading indicator (defaults to '&lt;div class="loading-indicator"&gt;Loading...&lt;/div&gt;').
9509      * @type String
9510      */
9511     indicatorText : '<div class="loading-indicator">Loading...</div>',
9512      /**
9513      * True to process scripts by default (defaults to false).
9514      * @type Boolean
9515      */
9516     loadScripts : false,
9517     /**
9518     * Blank page URL to use with SSL file uploads (defaults to {@link Ext#SSL_SECURE_URL} if set, or "javascript:false").
9519     * @type String
9520     */
9521     sslBlankUrl : (Ext.SSL_SECURE_URL || "javascript:false")      
9522 };
9523
9524
9525 /**
9526  * Static convenience method. <b>This method is deprecated in favor of el.load({url:'foo.php', ...})</b>.
9527  * Usage:
9528  * <pre><code>Ext.Updater.updateElement("my-div", "stuff.php");</code></pre>
9529  * @param {Mixed} el The element to update
9530  * @param {String} url The url
9531  * @param {String/Object} params (optional) Url encoded param string or an object of name/value pairs
9532  * @param {Object} options (optional) A config object with any of the Updater properties you want to set - for
9533  * example: {disableCaching:true, indicatorText: "Loading data..."}
9534  * @static
9535  * @deprecated
9536  * @member Ext.Updater
9537  */
9538 Ext.Updater.updateElement = function(el, url, params, options){
9539     var um = Ext.get(el).getUpdater();
9540     Ext.apply(um, options);
9541     um.update(url, params, options ? options.callback : null);
9542 };
9543
9544 /**
9545  * @class Ext.Updater.BasicRenderer
9546  * Default Content renderer. Updates the elements innerHTML with the responseText.
9547  */
9548 Ext.Updater.BasicRenderer = function(){};
9549
9550 Ext.Updater.BasicRenderer.prototype = {
9551     /**
9552      * This is called when the transaction is completed and it's time to update the element - The BasicRenderer
9553      * updates the elements innerHTML with the responseText - To perform a custom render (i.e. XML or JSON processing),
9554      * create an object with a "render(el, response)" method and pass it to setRenderer on the Updater.
9555      * @param {Ext.Element} el The element being rendered
9556      * @param {Object} response The XMLHttpRequest object
9557      * @param {Updater} updateManager The calling update manager
9558      * @param {Function} callback A callback that will need to be called if loadScripts is true on the Updater
9559      */
9560      render : function(el, response, updateManager, callback){       
9561         el.update(response.responseText, updateManager.loadScripts, callback);
9562     }
9563 };/**
9564  * @class Date
9565  *
9566  * The date parsing and formatting syntax contains a subset of
9567  * <a href="http://www.php.net/date">PHP's date() function</a>, and the formats that are
9568  * supported will provide results equivalent to their PHP versions.
9569  *
9570  * The following is a list of all currently supported formats:
9571  * <pre>
9572 Format  Description                                                               Example returned values
9573 ------  -----------------------------------------------------------------------   -----------------------
9574   d     Day of the month, 2 digits with leading zeros                             01 to 31
9575   D     A short textual representation of the day of the week                     Mon to Sun
9576   j     Day of the month without leading zeros                                    1 to 31
9577   l     A full textual representation of the day of the week                      Sunday to Saturday
9578   N     ISO-8601 numeric representation of the day of the week                    1 (for Monday) through 7 (for Sunday)
9579   S     English ordinal suffix for the day of the month, 2 characters             st, nd, rd or th. Works well with j
9580   w     Numeric representation of the day of the week                             0 (for Sunday) to 6 (for Saturday)
9581   z     The day of the year (starting from 0)                                     0 to 364 (365 in leap years)
9582   W     ISO-8601 week number of year, weeks starting on Monday                    01 to 53
9583   F     A full textual representation of a month, such as January or March        January to December
9584   m     Numeric representation of a month, with leading zeros                     01 to 12
9585   M     A short textual representation of a month                                 Jan to Dec
9586   n     Numeric representation of a month, without leading zeros                  1 to 12
9587   t     Number of days in the given month                                         28 to 31
9588   L     Whether it's a leap year                                                  1 if it is a leap year, 0 otherwise.
9589   o     ISO-8601 year number (identical to (Y), but if the ISO week number (W)    Examples: 1998 or 2004
9590         belongs to the previous or next year, that year is used instead)
9591   Y     A full numeric representation of a year, 4 digits                         Examples: 1999 or 2003
9592   y     A two digit representation of a year                                      Examples: 99 or 03
9593   a     Lowercase Ante meridiem and Post meridiem                                 am or pm
9594   A     Uppercase Ante meridiem and Post meridiem                                 AM or PM
9595   g     12-hour format of an hour without leading zeros                           1 to 12
9596   G     24-hour format of an hour without leading zeros                           0 to 23
9597   h     12-hour format of an hour with leading zeros                              01 to 12
9598   H     24-hour format of an hour with leading zeros                              00 to 23
9599   i     Minutes, with leading zeros                                               00 to 59
9600   s     Seconds, with leading zeros                                               00 to 59
9601   u     Decimal fraction of a second                                              Examples:
9602         (minimum 1 digit, arbitrary number of digits allowed)                     001 (i.e. 0.001s) or
9603                                                                                   100 (i.e. 0.100s) or
9604                                                                                   999 (i.e. 0.999s) or
9605                                                                                   999876543210 (i.e. 0.999876543210s)
9606   O     Difference to Greenwich time (GMT) in hours and minutes                   Example: +1030
9607   P     Difference to Greenwich time (GMT) with colon between hours and minutes   Example: -08:00
9608   T     Timezone abbreviation of the machine running the code                     Examples: EST, MDT, PDT ...
9609   Z     Timezone offset in seconds (negative if west of UTC, positive if east)    -43200 to 50400
9610   c     ISO 8601 date
9611         Notes:                                                                    Examples:
9612         1) If unspecified, the month / day defaults to the current month / day,   1991 or
9613            the time defaults to midnight, while the timezone defaults to the      1992-10 or
9614            browser's timezone. If a time is specified, it must include both hours 1993-09-20 or
9615            and minutes. The "T" delimiter, seconds, milliseconds and timezone     1994-08-19T16:20+01:00 or
9616            are optional.                                                          1995-07-18T17:21:28-02:00 or
9617         2) The decimal fraction of a second, if specified, must contain at        1996-06-17T18:22:29.98765+03:00 or
9618            least 1 digit (there is no limit to the maximum number                 1997-05-16T19:23:30,12345-0400 or
9619            of digits allowed), and may be delimited by either a '.' or a ','      1998-04-15T20:24:31.2468Z or
9620         Refer to the examples on the right for the various levels of              1999-03-14T20:24:32Z or
9621         date-time granularity which are supported, or see                         2000-02-13T21:25:33
9622         http://www.w3.org/TR/NOTE-datetime for more info.                         2001-01-12 22:26:34
9623   U     Seconds since the Unix Epoch (January 1 1970 00:00:00 GMT)                1193432466 or -2138434463
9624   M$    Microsoft AJAX serialized dates                                           \/Date(1238606590509)\/ (i.e. UTC milliseconds since epoch) or
9625                                                                                   \/Date(1238606590509+0800)\/
9626 </pre>
9627  *
9628  * Example usage (note that you must escape format specifiers with '\\' to render them as character literals):
9629  * <pre><code>
9630 // Sample date:
9631 // 'Wed Jan 10 2007 15:05:01 GMT-0600 (Central Standard Time)'
9632
9633 var dt = new Date('1/10/2007 03:05:01 PM GMT-0600');
9634 document.write(dt.format('Y-m-d'));                           // 2007-01-10
9635 document.write(dt.format('F j, Y, g:i a'));                   // January 10, 2007, 3:05 pm
9636 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
9637 </code></pre>
9638  *
9639  * Here are some standard date/time patterns that you might find helpful.  They
9640  * are not part of the source of Date.js, but to use them you can simply copy this
9641  * block of code into any script that is included after Date.js and they will also become
9642  * globally available on the Date object.  Feel free to add or remove patterns as needed in your code.
9643  * <pre><code>
9644 Date.patterns = {
9645     ISO8601Long:"Y-m-d H:i:s",
9646     ISO8601Short:"Y-m-d",
9647     ShortDate: "n/j/Y",
9648     LongDate: "l, F d, Y",
9649     FullDateTime: "l, F d, Y g:i:s A",
9650     MonthDay: "F d",
9651     ShortTime: "g:i A",
9652     LongTime: "g:i:s A",
9653     SortableDateTime: "Y-m-d\\TH:i:s",
9654     UniversalSortableDateTime: "Y-m-d H:i:sO",
9655     YearMonth: "F, Y"
9656 };
9657 </code></pre>
9658  *
9659  * Example usage:
9660  * <pre><code>
9661 var dt = new Date();
9662 document.write(dt.format(Date.patterns.ShortDate));
9663 </code></pre>
9664  * <p>Developer-written, custom formats may be used by supplying both a formatting and a parsing function
9665  * which perform to specialized requirements. The functions are stored in {@link #parseFunctions} and {@link #formatFunctions}.</p>
9666  */
9667
9668 /*
9669  * Most of the date-formatting functions below are the excellent work of Baron Schwartz.
9670  * (see http://www.xaprb.com/blog/2005/12/12/javascript-closures-for-runtime-efficiency/)
9671  * They generate precompiled functions from format patterns instead of parsing and
9672  * processing each pattern every time a date is formatted. These functions are available
9673  * on every Date object.
9674  */
9675
9676 (function() {
9677
9678 /**
9679  * Global flag which determines if strict date parsing should be used.
9680  * Strict date parsing will not roll-over invalid dates, which is the
9681  * default behaviour of javascript Date objects.
9682  * (see {@link #parseDate} for more information)
9683  * Defaults to <tt>false</tt>.
9684  * @static
9685  * @type Boolean
9686 */
9687 Date.useStrict = false;
9688
9689
9690 // create private copy of Ext's String.format() method
9691 // - to remove unnecessary dependency
9692 // - to resolve namespace conflict with M$-Ajax's implementation
9693 function xf(format) {
9694     var args = Array.prototype.slice.call(arguments, 1);
9695     return format.replace(/\{(\d+)\}/g, function(m, i) {
9696         return args[i];
9697     });
9698 }
9699
9700
9701 // private
9702 Date.formatCodeToRegex = function(character, currentGroup) {
9703     // Note: currentGroup - position in regex result array (see notes for Date.parseCodes below)
9704     var p = Date.parseCodes[character];
9705
9706     if (p) {
9707       p = typeof p == 'function'? p() : p;
9708       Date.parseCodes[character] = p; // reassign function result to prevent repeated execution
9709     }
9710
9711     return p? Ext.applyIf({
9712       c: p.c? xf(p.c, currentGroup || "{0}") : p.c
9713     }, p) : {
9714         g:0,
9715         c:null,
9716         s:Ext.escapeRe(character) // treat unrecognised characters as literals
9717     }
9718 }
9719
9720 // private shorthand for Date.formatCodeToRegex since we'll be using it fairly often
9721 var $f = Date.formatCodeToRegex;
9722
9723 Ext.apply(Date, {
9724     /**
9725      * <p>An object hash in which each property is a date parsing function. The property name is the
9726      * format string which that function parses.</p>
9727      * <p>This object is automatically populated with date parsing functions as
9728      * date formats are requested for Ext standard formatting strings.</p>
9729      * <p>Custom parsing functions may be inserted into this object, keyed by a name which from then on
9730      * may be used as a format string to {@link #parseDate}.<p>
9731      * <p>Example:</p><pre><code>
9732 Date.parseFunctions['x-date-format'] = myDateParser;
9733 </code></pre>
9734      * <p>A parsing function should return a Date object, and is passed the following parameters:<div class="mdetail-params"><ul>
9735      * <li><code>date</code> : String<div class="sub-desc">The date string to parse.</div></li>
9736      * <li><code>strict</code> : Boolean<div class="sub-desc">True to validate date strings while parsing
9737      * (i.e. prevent javascript Date "rollover") (The default must be false).
9738      * Invalid date strings should return null when parsed.</div></li>
9739      * </ul></div></p>
9740      * <p>To enable Dates to also be <i>formatted</i> according to that format, a corresponding
9741      * formatting function must be placed into the {@link #formatFunctions} property.
9742      * @property parseFunctions
9743      * @static
9744      * @type Object
9745      */
9746     parseFunctions: {
9747         "M$": function(input, strict) {
9748             // note: the timezone offset is ignored since the M$ Ajax server sends
9749             // a UTC milliseconds-since-Unix-epoch value (negative values are allowed)
9750             var re = new RegExp('\\/Date\\(([-+])?(\\d+)(?:[+-]\\d{4})?\\)\\/');
9751             var r = (input || '').match(re);
9752             return r? new Date(((r[1] || '') + r[2]) * 1) : null;
9753         }
9754     },
9755     parseRegexes: [],
9756
9757     /**
9758      * <p>An object hash in which each property is a date formatting function. The property name is the
9759      * format string which corresponds to the produced formatted date string.</p>
9760      * <p>This object is automatically populated with date formatting functions as
9761      * date formats are requested for Ext standard formatting strings.</p>
9762      * <p>Custom formatting functions may be inserted into this object, keyed by a name which from then on
9763      * may be used as a format string to {@link #format}. Example:</p><pre><code>
9764 Date.formatFunctions['x-date-format'] = myDateFormatter;
9765 </code></pre>
9766      * <p>A formatting function should return a string repesentation of the passed Date object:<div class="mdetail-params"><ul>
9767      * <li><code>date</code> : Date<div class="sub-desc">The Date to format.</div></li>
9768      * </ul></div></p>
9769      * <p>To enable date strings to also be <i>parsed</i> according to that format, a corresponding
9770      * parsing function must be placed into the {@link #parseFunctions} property.
9771      * @property formatFunctions
9772      * @static
9773      * @type Object
9774      */
9775     formatFunctions: {
9776         "M$": function() {
9777             // UTC milliseconds since Unix epoch (M$-AJAX serialized date format (MRSF))
9778             return '\\/Date(' + this.getTime() + ')\\/';
9779         }
9780     },
9781
9782     y2kYear : 50,
9783
9784     /**
9785      * Date interval constant
9786      * @static
9787      * @type String
9788      */
9789     MILLI : "ms",
9790
9791     /**
9792      * Date interval constant
9793      * @static
9794      * @type String
9795      */
9796     SECOND : "s",
9797
9798     /**
9799      * Date interval constant
9800      * @static
9801      * @type String
9802      */
9803     MINUTE : "mi",
9804
9805     /** Date interval constant
9806      * @static
9807      * @type String
9808      */
9809     HOUR : "h",
9810
9811     /**
9812      * Date interval constant
9813      * @static
9814      * @type String
9815      */
9816     DAY : "d",
9817
9818     /**
9819      * Date interval constant
9820      * @static
9821      * @type String
9822      */
9823     MONTH : "mo",
9824
9825     /**
9826      * Date interval constant
9827      * @static
9828      * @type String
9829      */
9830     YEAR : "y",
9831
9832     /**
9833      * <p>An object hash containing default date values used during date parsing.</p>
9834      * <p>The following properties are available:<div class="mdetail-params"><ul>
9835      * <li><code>y</code> : Number<div class="sub-desc">The default year value. (defaults to undefined)</div></li>
9836      * <li><code>m</code> : Number<div class="sub-desc">The default 1-based month value. (defaults to undefined)</div></li>
9837      * <li><code>d</code> : Number<div class="sub-desc">The default day value. (defaults to undefined)</div></li>
9838      * <li><code>h</code> : Number<div class="sub-desc">The default hour value. (defaults to undefined)</div></li>
9839      * <li><code>i</code> : Number<div class="sub-desc">The default minute value. (defaults to undefined)</div></li>
9840      * <li><code>s</code> : Number<div class="sub-desc">The default second value. (defaults to undefined)</div></li>
9841      * <li><code>ms</code> : Number<div class="sub-desc">The default millisecond value. (defaults to undefined)</div></li>
9842      * </ul></div></p>
9843      * <p>Override these properties to customize the default date values used by the {@link #parseDate} method.</p>
9844      * <p><b>Note: In countries which experience Daylight Saving Time (i.e. DST), the <tt>h</tt>, <tt>i</tt>, <tt>s</tt>
9845      * and <tt>ms</tt> properties may coincide with the exact time in which DST takes effect.
9846      * It is the responsiblity of the developer to account for this.</b></p>
9847      * Example Usage:
9848      * <pre><code>
9849 // set default day value to the first day of the month
9850 Date.defaults.d = 1;
9851
9852 // parse a February date string containing only year and month values.
9853 // setting the default day value to 1 prevents weird date rollover issues
9854 // when attempting to parse the following date string on, for example, March 31st 2009.
9855 Date.parseDate('2009-02', 'Y-m'); // returns a Date object representing February 1st 2009
9856 </code></pre>
9857      * @property defaults
9858      * @static
9859      * @type Object
9860      */
9861     defaults: {},
9862
9863     /**
9864      * An array of textual day names.
9865      * Override these values for international dates.
9866      * Example:
9867      * <pre><code>
9868 Date.dayNames = [
9869     'SundayInYourLang',
9870     'MondayInYourLang',
9871     ...
9872 ];
9873 </code></pre>
9874      * @type Array
9875      * @static
9876      */
9877     dayNames : [
9878         "Sunday",
9879         "Monday",
9880         "Tuesday",
9881         "Wednesday",
9882         "Thursday",
9883         "Friday",
9884         "Saturday"
9885     ],
9886
9887     /**
9888      * An array of textual month names.
9889      * Override these values for international dates.
9890      * Example:
9891      * <pre><code>
9892 Date.monthNames = [
9893     'JanInYourLang',
9894     'FebInYourLang',
9895     ...
9896 ];
9897 </code></pre>
9898      * @type Array
9899      * @static
9900      */
9901     monthNames : [
9902         "January",
9903         "February",
9904         "March",
9905         "April",
9906         "May",
9907         "June",
9908         "July",
9909         "August",
9910         "September",
9911         "October",
9912         "November",
9913         "December"
9914     ],
9915
9916     /**
9917      * An object hash of zero-based javascript month numbers (with short month names as keys. note: keys are case-sensitive).
9918      * Override these values for international dates.
9919      * Example:
9920      * <pre><code>
9921 Date.monthNumbers = {
9922     'ShortJanNameInYourLang':0,
9923     'ShortFebNameInYourLang':1,
9924     ...
9925 };
9926 </code></pre>
9927      * @type Object
9928      * @static
9929      */
9930     monthNumbers : {
9931         Jan:0,
9932         Feb:1,
9933         Mar:2,
9934         Apr:3,
9935         May:4,
9936         Jun:5,
9937         Jul:6,
9938         Aug:7,
9939         Sep:8,
9940         Oct:9,
9941         Nov:10,
9942         Dec:11
9943     },
9944
9945     /**
9946      * Get the short month name for the given month number.
9947      * Override this function for international dates.
9948      * @param {Number} month A zero-based javascript month number.
9949      * @return {String} The short month name.
9950      * @static
9951      */
9952     getShortMonthName : function(month) {
9953         return Date.monthNames[month].substring(0, 3);
9954     },
9955
9956     /**
9957      * Get the short day name for the given day number.
9958      * Override this function for international dates.
9959      * @param {Number} day A zero-based javascript day number.
9960      * @return {String} The short day name.
9961      * @static
9962      */
9963     getShortDayName : function(day) {
9964         return Date.dayNames[day].substring(0, 3);
9965     },
9966
9967     /**
9968      * Get the zero-based javascript month number for the given short/full month name.
9969      * Override this function for international dates.
9970      * @param {String} name The short/full month name.
9971      * @return {Number} The zero-based javascript month number.
9972      * @static
9973      */
9974     getMonthNumber : function(name) {
9975         // handle camel casing for english month names (since the keys for the Date.monthNumbers hash are case sensitive)
9976         return Date.monthNumbers[name.substring(0, 1).toUpperCase() + name.substring(1, 3).toLowerCase()];
9977     },
9978
9979     /**
9980      * The base format-code to formatting-function hashmap used by the {@link #format} method.
9981      * Formatting functions are strings (or functions which return strings) which
9982      * will return the appropriate value when evaluated in the context of the Date object
9983      * from which the {@link #format} method is called.
9984      * Add to / override these mappings for custom date formatting.
9985      * Note: Date.format() treats characters as literals if an appropriate mapping cannot be found.
9986      * Example:
9987      * <pre><code>
9988 Date.formatCodes.x = "String.leftPad(this.getDate(), 2, '0')";
9989 (new Date()).format("X"); // returns the current day of the month
9990 </code></pre>
9991      * @type Object
9992      * @static
9993      */
9994     formatCodes : {
9995         d: "String.leftPad(this.getDate(), 2, '0')",
9996         D: "Date.getShortDayName(this.getDay())", // get localised short day name
9997         j: "this.getDate()",
9998         l: "Date.dayNames[this.getDay()]",
9999         N: "(this.getDay() ? this.getDay() : 7)",
10000         S: "this.getSuffix()",
10001         w: "this.getDay()",
10002         z: "this.getDayOfYear()",
10003         W: "String.leftPad(this.getWeekOfYear(), 2, '0')",
10004         F: "Date.monthNames[this.getMonth()]",
10005         m: "String.leftPad(this.getMonth() + 1, 2, '0')",
10006         M: "Date.getShortMonthName(this.getMonth())", // get localised short month name
10007         n: "(this.getMonth() + 1)",
10008         t: "this.getDaysInMonth()",
10009         L: "(this.isLeapYear() ? 1 : 0)",
10010         o: "(this.getFullYear() + (this.getWeekOfYear() == 1 && this.getMonth() > 0 ? +1 : (this.getWeekOfYear() >= 52 && this.getMonth() < 11 ? -1 : 0)))",
10011         Y: "this.getFullYear()",
10012         y: "('' + this.getFullYear()).substring(2, 4)",
10013         a: "(this.getHours() < 12 ? 'am' : 'pm')",
10014         A: "(this.getHours() < 12 ? 'AM' : 'PM')",
10015         g: "((this.getHours() % 12) ? this.getHours() % 12 : 12)",
10016         G: "this.getHours()",
10017         h: "String.leftPad((this.getHours() % 12) ? this.getHours() % 12 : 12, 2, '0')",
10018         H: "String.leftPad(this.getHours(), 2, '0')",
10019         i: "String.leftPad(this.getMinutes(), 2, '0')",
10020         s: "String.leftPad(this.getSeconds(), 2, '0')",
10021         u: "String.leftPad(this.getMilliseconds(), 3, '0')",
10022         O: "this.getGMTOffset()",
10023         P: "this.getGMTOffset(true)",
10024         T: "this.getTimezone()",
10025         Z: "(this.getTimezoneOffset() * -60)",
10026
10027         c: function() { // ISO-8601 -- GMT format
10028             for (var c = "Y-m-dTH:i:sP", code = [], i = 0, l = c.length; i < l; ++i) {
10029                 var e = c.charAt(i);
10030                 code.push(e == "T" ? "'T'" : Date.getFormatCode(e)); // treat T as a character literal
10031             }
10032             return code.join(" + ");
10033         },
10034         /*
10035         c: function() { // ISO-8601 -- UTC format
10036             return [
10037               "this.getUTCFullYear()", "'-'",
10038               "String.leftPad(this.getUTCMonth() + 1, 2, '0')", "'-'",
10039               "String.leftPad(this.getUTCDate(), 2, '0')",
10040               "'T'",
10041               "String.leftPad(this.getUTCHours(), 2, '0')", "':'",
10042               "String.leftPad(this.getUTCMinutes(), 2, '0')", "':'",
10043               "String.leftPad(this.getUTCSeconds(), 2, '0')",
10044               "'Z'"
10045             ].join(" + ");
10046         },
10047         */
10048
10049         U: "Math.round(this.getTime() / 1000)"
10050     },
10051
10052     /**
10053      * Checks if the passed Date parameters will cause a javascript Date "rollover".
10054      * @param {Number} year 4-digit year
10055      * @param {Number} month 1-based month-of-year
10056      * @param {Number} day Day of month
10057      * @param {Number} hour (optional) Hour
10058      * @param {Number} minute (optional) Minute
10059      * @param {Number} second (optional) Second
10060      * @param {Number} millisecond (optional) Millisecond
10061      * @return {Boolean} true if the passed parameters do not cause a Date "rollover", false otherwise.
10062      * @static
10063      */
10064     isValid : function(y, m, d, h, i, s, ms) {
10065         // setup defaults
10066         h = h || 0;
10067         i = i || 0;
10068         s = s || 0;
10069         ms = ms || 0;
10070
10071         var dt = new Date(y, m - 1, d, h, i, s, ms);
10072
10073         return y == dt.getFullYear() &&
10074             m == dt.getMonth() + 1 &&
10075             d == dt.getDate() &&
10076             h == dt.getHours() &&
10077             i == dt.getMinutes() &&
10078             s == dt.getSeconds() &&
10079             ms == dt.getMilliseconds();
10080     },
10081
10082     /**
10083      * Parses the passed string using the specified date format.
10084      * Note that this function expects normal calendar dates, meaning that months are 1-based (i.e. 1 = January).
10085      * The {@link #defaults} hash will be used for any date value (i.e. year, month, day, hour, minute, second or millisecond)
10086      * which cannot be found in the passed string. If a corresponding default date value has not been specified in the {@link #defaults} hash,
10087      * the current date's year, month, day or DST-adjusted zero-hour time value will be used instead.
10088      * Keep in mind that the input date string must precisely match the specified format string
10089      * in order for the parse operation to be successful (failed parse operations return a null value).
10090      * <p>Example:</p><pre><code>
10091 //dt = Fri May 25 2007 (current date)
10092 var dt = new Date();
10093
10094 //dt = Thu May 25 2006 (today&#39;s month/day in 2006)
10095 dt = Date.parseDate("2006", "Y");
10096
10097 //dt = Sun Jan 15 2006 (all date parts specified)
10098 dt = Date.parseDate("2006-01-15", "Y-m-d");
10099
10100 //dt = Sun Jan 15 2006 15:20:01
10101 dt = Date.parseDate("2006-01-15 3:20:01 PM", "Y-m-d g:i:s A");
10102
10103 // attempt to parse Sun Feb 29 2006 03:20:01 in strict mode
10104 dt = Date.parseDate("2006-02-29 03:20:01", "Y-m-d H:i:s", true); // returns null
10105 </code></pre>
10106      * @param {String} input The raw date string.
10107      * @param {String} format The expected date string format.
10108      * @param {Boolean} strict (optional) True to validate date strings while parsing (i.e. prevents javascript Date "rollover")
10109                         (defaults to false). Invalid date strings will return null when parsed.
10110      * @return {Date} The parsed Date.
10111      * @static
10112      */
10113     parseDate : function(input, format, strict) {
10114         var p = Date.parseFunctions;
10115         if (p[format] == null) {
10116             Date.createParser(format);
10117         }
10118         return p[format](input, Ext.isDefined(strict) ? strict : Date.useStrict);
10119     },
10120
10121     // private
10122     getFormatCode : function(character) {
10123         var f = Date.formatCodes[character];
10124
10125         if (f) {
10126           f = typeof f == 'function'? f() : f;
10127           Date.formatCodes[character] = f; // reassign function result to prevent repeated execution
10128         }
10129
10130         // note: unknown characters are treated as literals
10131         return f || ("'" + String.escape(character) + "'");
10132     },
10133
10134     // private
10135     createFormat : function(format) {
10136         var code = [],
10137             special = false,
10138             ch = '';
10139
10140         for (var i = 0; i < format.length; ++i) {
10141             ch = format.charAt(i);
10142             if (!special && ch == "\\") {
10143                 special = true;
10144             } else if (special) {
10145                 special = false;
10146                 code.push("'" + String.escape(ch) + "'");
10147             } else {
10148                 code.push(Date.getFormatCode(ch))
10149             }
10150         }
10151         Date.formatFunctions[format] = new Function("return " + code.join('+'));
10152     },
10153
10154     // private
10155     createParser : function() {
10156         var code = [
10157             "var dt, y, m, d, h, i, s, ms, o, z, zz, u, v,",
10158                 "def = Date.defaults,",
10159                 "results = String(input).match(Date.parseRegexes[{0}]);", // either null, or an array of matched strings
10160
10161             "if(results){",
10162                 "{1}",
10163
10164                 "if(u != null){", // i.e. unix time is defined
10165                     "v = new Date(u * 1000);", // give top priority to UNIX time
10166                 "}else{",
10167                     // create Date object representing midnight of the current day;
10168                     // this will provide us with our date defaults
10169                     // (note: clearTime() handles Daylight Saving Time automatically)
10170                     "dt = (new Date()).clearTime();",
10171
10172                     // date calculations (note: these calculations create a dependency on Ext.num())
10173                     "y = y >= 0? y : Ext.num(def.y, dt.getFullYear());",
10174                     "m = m >= 0? m : Ext.num(def.m - 1, dt.getMonth());",
10175                     "d = d >= 0? d : Ext.num(def.d, dt.getDate());",
10176
10177                     // time calculations (note: these calculations create a dependency on Ext.num())
10178                     "h  = h || Ext.num(def.h, dt.getHours());",
10179                     "i  = i || Ext.num(def.i, dt.getMinutes());",
10180                     "s  = s || Ext.num(def.s, dt.getSeconds());",
10181                     "ms = ms || Ext.num(def.ms, dt.getMilliseconds());",
10182
10183                     "if(z >= 0 && y >= 0){",
10184                         // both the year and zero-based day of year are defined and >= 0.
10185                         // these 2 values alone provide sufficient info to create a full date object
10186
10187                         // create Date object representing January 1st for the given year
10188                         "v = new Date(y, 0, 1, h, i, s, ms);",
10189
10190                         // then add day of year, checking for Date "rollover" if necessary
10191                         "v = !strict? v : (strict === true && (z <= 364 || (v.isLeapYear() && z <= 365))? v.add(Date.DAY, z) : null);",
10192                     "}else if(strict === true && !Date.isValid(y, m + 1, d, h, i, s, ms)){", // check for Date "rollover"
10193                         "v = null;", // invalid date, so return null
10194                     "}else{",
10195                         // plain old Date object
10196                         "v = new Date(y, m, d, h, i, s, ms);",
10197                     "}",
10198                 "}",
10199             "}",
10200
10201             "if(v){",
10202                 // favour UTC offset over GMT offset
10203                 "if(zz != null){",
10204                     // reset to UTC, then add offset
10205                     "v = v.add(Date.SECOND, -v.getTimezoneOffset() * 60 - zz);",
10206                 "}else if(o){",
10207                     // reset to GMT, then add offset
10208                     "v = v.add(Date.MINUTE, -v.getTimezoneOffset() + (sn == '+'? -1 : 1) * (hr * 60 + mn));",
10209                 "}",
10210             "}",
10211
10212             "return v;"
10213         ].join('\n');
10214
10215         return function(format) {
10216             var regexNum = Date.parseRegexes.length,
10217                 currentGroup = 1,
10218                 calc = [],
10219                 regex = [],
10220                 special = false,
10221                 ch = "";
10222
10223             for (var i = 0; i < format.length; ++i) {
10224                 ch = format.charAt(i);
10225                 if (!special && ch == "\\") {
10226                     special = true;
10227                 } else if (special) {
10228                     special = false;
10229                     regex.push(String.escape(ch));
10230                 } else {
10231                     var obj = $f(ch, currentGroup);
10232                     currentGroup += obj.g;
10233                     regex.push(obj.s);
10234                     if (obj.g && obj.c) {
10235                         calc.push(obj.c);
10236                     }
10237                 }
10238             }
10239
10240             Date.parseRegexes[regexNum] = new RegExp("^" + regex.join('') + "$", "i");
10241             Date.parseFunctions[format] = new Function("input", "strict", xf(code, regexNum, calc.join('')));
10242         }
10243     }(),
10244
10245     // private
10246     parseCodes : {
10247         /*
10248          * Notes:
10249          * g = {Number} calculation group (0 or 1. only group 1 contributes to date calculations.)
10250          * c = {String} calculation method (required for group 1. null for group 0. {0} = currentGroup - position in regex result array)
10251          * s = {String} regex pattern. all matches are stored in results[], and are accessible by the calculation mapped to 'c'
10252          */
10253         d: {
10254             g:1,
10255             c:"d = parseInt(results[{0}], 10);\n",
10256             s:"(\\d{2})" // day of month with leading zeroes (01 - 31)
10257         },
10258         j: {
10259             g:1,
10260             c:"d = parseInt(results[{0}], 10);\n",
10261             s:"(\\d{1,2})" // day of month without leading zeroes (1 - 31)
10262         },
10263         D: function() {
10264             for (var a = [], i = 0; i < 7; a.push(Date.getShortDayName(i)), ++i); // get localised short day names
10265             return {
10266                 g:0,
10267                 c:null,
10268                 s:"(?:" + a.join("|") +")"
10269             }
10270         },
10271         l: function() {
10272             return {
10273                 g:0,
10274                 c:null,
10275                 s:"(?:" + Date.dayNames.join("|") + ")"
10276             }
10277         },
10278         N: {
10279             g:0,
10280             c:null,
10281             s:"[1-7]" // ISO-8601 day number (1 (monday) - 7 (sunday))
10282         },
10283         S: {
10284             g:0,
10285             c:null,
10286             s:"(?:st|nd|rd|th)"
10287         },
10288         w: {
10289             g:0,
10290             c:null,
10291             s:"[0-6]" // javascript day number (0 (sunday) - 6 (saturday))
10292         },
10293         z: {
10294             g:1,
10295             c:"z = parseInt(results[{0}], 10);\n",
10296             s:"(\\d{1,3})" // day of the year (0 - 364 (365 in leap years))
10297         },
10298         W: {
10299             g:0,
10300             c:null,
10301             s:"(?:\\d{2})" // ISO-8601 week number (with leading zero)
10302         },
10303         F: function() {
10304             return {
10305                 g:1,
10306                 c:"m = parseInt(Date.getMonthNumber(results[{0}]), 10);\n", // get localised month number
10307                 s:"(" + Date.monthNames.join("|") + ")"
10308             }
10309         },
10310         M: function() {
10311             for (var a = [], i = 0; i < 12; a.push(Date.getShortMonthName(i)), ++i); // get localised short month names
10312             return Ext.applyIf({
10313                 s:"(" + a.join("|") + ")"
10314             }, $f("F"));
10315         },
10316         m: {
10317             g:1,
10318             c:"m = parseInt(results[{0}], 10) - 1;\n",
10319             s:"(\\d{2})" // month number with leading zeros (01 - 12)
10320         },
10321         n: {
10322             g:1,
10323             c:"m = parseInt(results[{0}], 10) - 1;\n",
10324             s:"(\\d{1,2})" // month number without leading zeros (1 - 12)
10325         },
10326         t: {
10327             g:0,
10328             c:null,
10329             s:"(?:\\d{2})" // no. of days in the month (28 - 31)
10330         },
10331         L: {
10332             g:0,
10333             c:null,
10334             s:"(?:1|0)"
10335         },
10336         o: function() {
10337             return $f("Y");
10338         },
10339         Y: {
10340             g:1,
10341             c:"y = parseInt(results[{0}], 10);\n",
10342             s:"(\\d{4})" // 4-digit year
10343         },
10344         y: {
10345             g:1,
10346             c:"var ty = parseInt(results[{0}], 10);\n"
10347                 + "y = ty > Date.y2kYear ? 1900 + ty : 2000 + ty;\n", // 2-digit year
10348             s:"(\\d{1,2})"
10349         },
10350         a: {
10351             g:1,
10352             c:"if (results[{0}] == 'am') {\n"
10353                 + "if (h == 12) { h = 0; }\n"
10354                 + "} else { if (h < 12) { h += 12; }}",
10355             s:"(am|pm)"
10356         },
10357         A: {
10358             g:1,
10359             c:"if (results[{0}] == 'AM') {\n"
10360                 + "if (h == 12) { h = 0; }\n"
10361                 + "} else { if (h < 12) { h += 12; }}",
10362             s:"(AM|PM)"
10363         },
10364         g: function() {
10365             return $f("G");
10366         },
10367         G: {
10368             g:1,
10369             c:"h = parseInt(results[{0}], 10);\n",
10370             s:"(\\d{1,2})" // 24-hr format of an hour without leading zeroes (0 - 23)
10371         },
10372         h: function() {
10373             return $f("H");
10374         },
10375         H: {
10376             g:1,
10377             c:"h = parseInt(results[{0}], 10);\n",
10378             s:"(\\d{2})" //  24-hr format of an hour with leading zeroes (00 - 23)
10379         },
10380         i: {
10381             g:1,
10382             c:"i = parseInt(results[{0}], 10);\n",
10383             s:"(\\d{2})" // minutes with leading zeros (00 - 59)
10384         },
10385         s: {
10386             g:1,
10387             c:"s = parseInt(results[{0}], 10);\n",
10388             s:"(\\d{2})" // seconds with leading zeros (00 - 59)
10389         },
10390         u: {
10391             g:1,
10392             c:"ms = results[{0}]; ms = parseInt(ms, 10)/Math.pow(10, ms.length - 3);\n",
10393             s:"(\\d+)" // decimal fraction of a second (minimum = 1 digit, maximum = unlimited)
10394         },
10395         O: {
10396             g:1,
10397             c:[
10398                 "o = results[{0}];",
10399                 "var sn = o.substring(0,1),", // get + / - sign
10400                     "hr = o.substring(1,3)*1 + Math.floor(o.substring(3,5) / 60),", // get hours (performs minutes-to-hour conversion also, just in case)
10401                     "mn = o.substring(3,5) % 60;", // get minutes
10402                 "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
10403             ].join("\n"),
10404             s: "([+\-]\\d{4})" // GMT offset in hrs and mins
10405         },
10406         P: {
10407             g:1,
10408             c:[
10409                 "o = results[{0}];",
10410                 "var sn = o.substring(0,1),", // get + / - sign
10411                     "hr = o.substring(1,3)*1 + Math.floor(o.substring(4,6) / 60),", // get hours (performs minutes-to-hour conversion also, just in case)
10412                     "mn = o.substring(4,6) % 60;", // get minutes
10413                 "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
10414             ].join("\n"),
10415             s: "([+\-]\\d{2}:\\d{2})" // GMT offset in hrs and mins (with colon separator)
10416         },
10417         T: {
10418             g:0,
10419             c:null,
10420             s:"[A-Z]{1,4}" // timezone abbrev. may be between 1 - 4 chars
10421         },
10422         Z: {
10423             g:1,
10424             c:"zz = results[{0}] * 1;\n" // -43200 <= UTC offset <= 50400
10425                   + "zz = (-43200 <= zz && zz <= 50400)? zz : null;\n",
10426             s:"([+\-]?\\d{1,5})" // leading '+' sign is optional for UTC offset
10427         },
10428         c: function() {
10429             var calc = [],
10430                 arr = [
10431                     $f("Y", 1), // year
10432                     $f("m", 2), // month
10433                     $f("d", 3), // day
10434                     $f("h", 4), // hour
10435                     $f("i", 5), // minute
10436                     $f("s", 6), // second
10437                     {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)
10438                     {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
10439                         "if(results[8]) {", // timezone specified
10440                             "if(results[8] == 'Z'){",
10441                                 "zz = 0;", // UTC
10442                             "}else if (results[8].indexOf(':') > -1){",
10443                                 $f("P", 8).c, // timezone offset with colon separator
10444                             "}else{",
10445                                 $f("O", 8).c, // timezone offset without colon separator
10446                             "}",
10447                         "}"
10448                     ].join('\n')}
10449                 ];
10450
10451             for (var i = 0, l = arr.length; i < l; ++i) {
10452                 calc.push(arr[i].c);
10453             }
10454
10455             return {
10456                 g:1,
10457                 c:calc.join(""),
10458                 s:[
10459                     arr[0].s, // year (required)
10460                     "(?:", "-", arr[1].s, // month (optional)
10461                         "(?:", "-", arr[2].s, // day (optional)
10462                             "(?:",
10463                                 "(?:T| )?", // time delimiter -- either a "T" or a single blank space
10464                                 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
10465                                 "(?::", arr[5].s, ")?", // seconds (optional)
10466                                 "(?:(?:\\.|,)(\\d+))?", // decimal fraction of a second (e.g. ",12345" or ".98765") (optional)
10467                                 "(Z|(?:[-+]\\d{2}(?::)?\\d{2}))?", // "Z" (UTC) or "-0530" (UTC offset without colon delimiter) or "+08:00" (UTC offset with colon delimiter) (optional)
10468                             ")?",
10469                         ")?",
10470                     ")?"
10471                 ].join("")
10472             }
10473         },
10474         U: {
10475             g:1,
10476             c:"u = parseInt(results[{0}], 10);\n",
10477             s:"(-?\\d+)" // leading minus sign indicates seconds before UNIX epoch
10478         }
10479     }
10480 });
10481
10482 }());
10483
10484 Ext.apply(Date.prototype, {
10485     // private
10486     dateFormat : function(format) {
10487         if (Date.formatFunctions[format] == null) {
10488             Date.createFormat(format);
10489         }
10490         return Date.formatFunctions[format].call(this);
10491     },
10492
10493     /**
10494      * Get the timezone abbreviation of the current date (equivalent to the format specifier 'T').
10495      *
10496      * Note: The date string returned by the javascript Date object's toString() method varies
10497      * between browsers (e.g. FF vs IE) and system region settings (e.g. IE in Asia vs IE in America).
10498      * For a given date string e.g. "Thu Oct 25 2007 22:55:35 GMT+0800 (Malay Peninsula Standard Time)",
10499      * getTimezone() first tries to get the timezone abbreviation from between a pair of parentheses
10500      * (which may or may not be present), failing which it proceeds to get the timezone abbreviation
10501      * from the GMT offset portion of the date string.
10502      * @return {String} The abbreviated timezone name (e.g. 'CST', 'PDT', 'EDT', 'MPST' ...).
10503      */
10504     getTimezone : function() {
10505         // the following list shows the differences between date strings from different browsers on a WinXP SP2 machine from an Asian locale:
10506         //
10507         // Opera  : "Thu, 25 Oct 2007 22:53:45 GMT+0800" -- shortest (weirdest) date string of the lot
10508         // 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)
10509         // FF     : "Thu Oct 25 2007 22:55:35 GMT+0800 (Malay Peninsula Standard Time)" -- value in parentheses always gives the correct timezone
10510         // IE     : "Thu Oct 25 22:54:35 UTC+0800 2007" -- (Asian system setting) look for 3-4 letter timezone abbrev
10511         // IE     : "Thu Oct 25 17:06:37 PDT 2007" -- (American system setting) look for 3-4 letter timezone abbrev
10512         //
10513         // this crazy regex attempts to guess the correct timezone abbreviation despite these differences.
10514         // step 1: (?:\((.*)\) -- find timezone in parentheses
10515         // 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
10516         // step 3: remove all non uppercase characters found in step 1 and 2
10517         return this.toString().replace(/^.* (?:\((.*)\)|([A-Z]{1,4})(?:[\-+][0-9]{4})?(?: -?\d+)?)$/, "$1$2").replace(/[^A-Z]/g, "");
10518     },
10519
10520     /**
10521      * Get the offset from GMT of the current date (equivalent to the format specifier 'O').
10522      * @param {Boolean} colon (optional) true to separate the hours and minutes with a colon (defaults to false).
10523      * @return {String} The 4-character offset string prefixed with + or - (e.g. '-0600').
10524      */
10525     getGMTOffset : function(colon) {
10526         return (this.getTimezoneOffset() > 0 ? "-" : "+")
10527             + String.leftPad(Math.floor(Math.abs(this.getTimezoneOffset()) / 60), 2, "0")
10528             + (colon ? ":" : "")
10529             + String.leftPad(Math.abs(this.getTimezoneOffset() % 60), 2, "0");
10530     },
10531
10532     /**
10533      * Get the numeric day number of the year, adjusted for leap year.
10534      * @return {Number} 0 to 364 (365 in leap years).
10535      */
10536     getDayOfYear: function() {
10537         var i = 0,
10538             num = 0,
10539             d = this.clone(),
10540             m = this.getMonth();
10541
10542         for (i = 0, d.setMonth(0); i < m; d.setMonth(++i)) {
10543             num += d.getDaysInMonth();
10544         }
10545         return num + this.getDate() - 1;
10546     },
10547
10548     /**
10549      * Get the numeric ISO-8601 week number of the year.
10550      * (equivalent to the format specifier 'W', but without a leading zero).
10551      * @return {Number} 1 to 53
10552      */
10553     getWeekOfYear : function() {
10554         // adapted from http://www.merlyn.demon.co.uk/weekcalc.htm
10555         var ms1d = 864e5, // milliseconds in a day
10556             ms7d = 7 * ms1d; // milliseconds in a week
10557
10558         return function() { // return a closure so constants get calculated only once
10559             var DC3 = Date.UTC(this.getFullYear(), this.getMonth(), this.getDate() + 3) / ms1d, // an Absolute Day Number
10560                 AWN = Math.floor(DC3 / 7), // an Absolute Week Number
10561                 Wyr = new Date(AWN * ms7d).getUTCFullYear();
10562
10563             return AWN - Math.floor(Date.UTC(Wyr, 0, 7) / ms7d) + 1;
10564         }
10565     }(),
10566
10567     /**
10568      * Checks if the current date falls within a leap year.
10569      * @return {Boolean} True if the current date falls within a leap year, false otherwise.
10570      */
10571     isLeapYear : function() {
10572         var year = this.getFullYear();
10573         return !!((year & 3) == 0 && (year % 100 || (year % 400 == 0 && year)));
10574     },
10575
10576     /**
10577      * Get the first day of the current month, adjusted for leap year.  The returned value
10578      * is the numeric day index within the week (0-6) which can be used in conjunction with
10579      * the {@link #monthNames} array to retrieve the textual day name.
10580      * Example:
10581      * <pre><code>
10582 var dt = new Date('1/10/2007');
10583 document.write(Date.dayNames[dt.getFirstDayOfMonth()]); //output: 'Monday'
10584 </code></pre>
10585      * @return {Number} The day number (0-6).
10586      */
10587     getFirstDayOfMonth : function() {
10588         var day = (this.getDay() - (this.getDate() - 1)) % 7;
10589         return (day < 0) ? (day + 7) : day;
10590     },
10591
10592     /**
10593      * Get the last day of the current month, adjusted for leap year.  The returned value
10594      * is the numeric day index within the week (0-6) which can be used in conjunction with
10595      * the {@link #monthNames} array to retrieve the textual day name.
10596      * Example:
10597      * <pre><code>
10598 var dt = new Date('1/10/2007');
10599 document.write(Date.dayNames[dt.getLastDayOfMonth()]); //output: 'Wednesday'
10600 </code></pre>
10601      * @return {Number} The day number (0-6).
10602      */
10603     getLastDayOfMonth : function() {
10604         return this.getLastDateOfMonth().getDay();
10605     },
10606
10607
10608     /**
10609      * Get the date of the first day of the month in which this date resides.
10610      * @return {Date}
10611      */
10612     getFirstDateOfMonth : function() {
10613         return new Date(this.getFullYear(), this.getMonth(), 1);
10614     },
10615
10616     /**
10617      * Get the date of the last day of the month in which this date resides.
10618      * @return {Date}
10619      */
10620     getLastDateOfMonth : function() {
10621         return new Date(this.getFullYear(), this.getMonth(), this.getDaysInMonth());
10622     },
10623
10624     /**
10625      * Get the number of days in the current month, adjusted for leap year.
10626      * @return {Number} The number of days in the month.
10627      */
10628     getDaysInMonth: function() {
10629         var daysInMonth = [31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31];
10630
10631         return function() { // return a closure for efficiency
10632             var m = this.getMonth();
10633
10634             return m == 1 && this.isLeapYear() ? 29 : daysInMonth[m];
10635         }
10636     }(),
10637
10638     /**
10639      * Get the English ordinal suffix of the current day (equivalent to the format specifier 'S').
10640      * @return {String} 'st, 'nd', 'rd' or 'th'.
10641      */
10642     getSuffix : function() {
10643         switch (this.getDate()) {
10644             case 1:
10645             case 21:
10646             case 31:
10647                 return "st";
10648             case 2:
10649             case 22:
10650                 return "nd";
10651             case 3:
10652             case 23:
10653                 return "rd";
10654             default:
10655                 return "th";
10656         }
10657     },
10658
10659     /**
10660      * Creates and returns a new Date instance with the exact same date value as the called instance.
10661      * Dates are copied and passed by reference, so if a copied date variable is modified later, the original
10662      * variable will also be changed.  When the intention is to create a new variable that will not
10663      * modify the original instance, you should create a clone.
10664      *
10665      * Example of correctly cloning a date:
10666      * <pre><code>
10667 //wrong way:
10668 var orig = new Date('10/1/2006');
10669 var copy = orig;
10670 copy.setDate(5);
10671 document.write(orig);  //returns 'Thu Oct 05 2006'!
10672
10673 //correct way:
10674 var orig = new Date('10/1/2006');
10675 var copy = orig.clone();
10676 copy.setDate(5);
10677 document.write(orig);  //returns 'Thu Oct 01 2006'
10678 </code></pre>
10679      * @return {Date} The new Date instance.
10680      */
10681     clone : function() {
10682         return new Date(this.getTime());
10683     },
10684
10685     /**
10686      * Checks if the current date is affected by Daylight Saving Time (DST).
10687      * @return {Boolean} True if the current date is affected by DST.
10688      */
10689     isDST : function() {
10690         // adapted from http://extjs.com/forum/showthread.php?p=247172#post247172
10691         // courtesy of @geoffrey.mcgill
10692         return new Date(this.getFullYear(), 0, 1).getTimezoneOffset() != this.getTimezoneOffset();
10693     },
10694
10695     /**
10696      * Attempts to clear all time information from this Date by setting the time to midnight of the same day,
10697      * automatically adjusting for Daylight Saving Time (DST) where applicable.
10698      * (note: DST timezone information for the browser's host operating system is assumed to be up-to-date)
10699      * @param {Boolean} clone true to create a clone of this date, clear the time and return it (defaults to false).
10700      * @return {Date} this or the clone.
10701      */
10702     clearTime : function(clone) {
10703         if (clone) {
10704             return this.clone().clearTime();
10705         }
10706
10707         // get current date before clearing time
10708         var d = this.getDate();
10709
10710         // clear time
10711         this.setHours(0);
10712         this.setMinutes(0);
10713         this.setSeconds(0);
10714         this.setMilliseconds(0);
10715
10716         if (this.getDate() != d) { // account for DST (i.e. day of month changed when setting hour = 0)
10717             // note: DST adjustments are assumed to occur in multiples of 1 hour (this is almost always the case)
10718             // refer to http://www.timeanddate.com/time/aboutdst.html for the (rare) exceptions to this rule
10719
10720             // increment hour until cloned date == current date
10721             for (var hr = 1, c = this.add(Date.HOUR, hr); c.getDate() != d; hr++, c = this.add(Date.HOUR, hr));
10722
10723             this.setDate(d);
10724             this.setHours(c.getHours());
10725         }
10726
10727         return this;
10728     },
10729
10730     /**
10731      * Provides a convenient method for performing basic date arithmetic. This method
10732      * does not modify the Date instance being called - it creates and returns
10733      * a new Date instance containing the resulting date value.
10734      *
10735      * Examples:
10736      * <pre><code>
10737 // Basic usage:
10738 var dt = new Date('10/29/2006').add(Date.DAY, 5);
10739 document.write(dt); //returns 'Fri Nov 03 2006 00:00:00'
10740
10741 // Negative values will be subtracted:
10742 var dt2 = new Date('10/1/2006').add(Date.DAY, -5);
10743 document.write(dt2); //returns 'Tue Sep 26 2006 00:00:00'
10744
10745 // You can even chain several calls together in one line:
10746 var dt3 = new Date('10/1/2006').add(Date.DAY, 5).add(Date.HOUR, 8).add(Date.MINUTE, -30);
10747 document.write(dt3); //returns 'Fri Oct 06 2006 07:30:00'
10748 </code></pre>
10749      *
10750      * @param {String} interval A valid date interval enum value.
10751      * @param {Number} value The amount to add to the current date.
10752      * @return {Date} The new Date instance.
10753      */
10754     add : function(interval, value) {
10755         var d = this.clone();
10756         if (!interval || value === 0) return d;
10757
10758         switch(interval.toLowerCase()) {
10759             case Date.MILLI:
10760                 d.setMilliseconds(this.getMilliseconds() + value);
10761                 break;
10762             case Date.SECOND:
10763                 d.setSeconds(this.getSeconds() + value);
10764                 break;
10765             case Date.MINUTE:
10766                 d.setMinutes(this.getMinutes() + value);
10767                 break;
10768             case Date.HOUR:
10769                 d.setHours(this.getHours() + value);
10770                 break;
10771             case Date.DAY:
10772                 d.setDate(this.getDate() + value);
10773                 break;
10774             case Date.MONTH:
10775                 var day = this.getDate();
10776                 if (day > 28) {
10777                     day = Math.min(day, this.getFirstDateOfMonth().add('mo', value).getLastDateOfMonth().getDate());
10778                 }
10779                 d.setDate(day);
10780                 d.setMonth(this.getMonth() + value);
10781                 break;
10782             case Date.YEAR:
10783                 d.setFullYear(this.getFullYear() + value);
10784                 break;
10785         }
10786         return d;
10787     },
10788
10789     /**
10790      * Checks if this date falls on or between the given start and end dates.
10791      * @param {Date} start Start date
10792      * @param {Date} end End date
10793      * @return {Boolean} true if this date falls on or between the given start and end dates.
10794      */
10795     between : function(start, end) {
10796         var t = this.getTime();
10797         return start.getTime() <= t && t <= end.getTime();
10798     }
10799 });
10800
10801
10802 /**
10803  * Formats a date given the supplied format string.
10804  * @param {String} format The format string.
10805  * @return {String} The formatted date.
10806  * @method format
10807  */
10808 Date.prototype.format = Date.prototype.dateFormat;
10809
10810
10811 // private
10812 if (Ext.isSafari && (navigator.userAgent.match(/WebKit\/(\d+)/)[1] || NaN) < 420) {
10813     Ext.apply(Date.prototype, {
10814         _xMonth : Date.prototype.setMonth,
10815         _xDate  : Date.prototype.setDate,
10816
10817         // Bug in Safari 1.3, 2.0 (WebKit build < 420)
10818         // Date.setMonth does not work consistently if iMonth is not 0-11
10819         setMonth : function(num) {
10820             if (num <= -1) {
10821                 var n = Math.ceil(-num),
10822                     back_year = Math.ceil(n / 12),
10823                     month = (n % 12) ? 12 - n % 12 : 0;
10824
10825                 this.setFullYear(this.getFullYear() - back_year);
10826
10827                 return this._xMonth(month);
10828             } else {
10829                 return this._xMonth(num);
10830             }
10831         },
10832
10833         // Bug in setDate() method (resolved in WebKit build 419.3, so to be safe we target Webkit builds < 420)
10834         // The parameter for Date.setDate() is converted to a signed byte integer in Safari
10835         // http://brianary.blogspot.com/2006/03/safari-date-bug.html
10836         setDate : function(d) {
10837             // use setTime() to workaround setDate() bug
10838             // subtract current day of month in milliseconds, then add desired day of month in milliseconds
10839             return this.setTime(this.getTime() - (this.getDate() - d) * 864e5);
10840         }
10841     });
10842 }
10843
10844
10845
10846 /* Some basic Date tests... (requires Firebug)
10847
10848 Date.parseDate('', 'c'); // call Date.parseDate() once to force computation of regex string so we can console.log() it
10849 console.log('Insane Regex for "c" format: %o', Date.parseCodes.c.s); // view the insane regex for the "c" format specifier
10850
10851 // standard tests
10852 console.group('Standard Date.parseDate() Tests');
10853     console.log('Date.parseDate("2009-01-05T11:38:56", "c")               = %o', Date.parseDate("2009-01-05T11:38:56", "c")); // assumes browser's timezone setting
10854     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
10855     console.log('Date.parseDate("2009-03-03T13:36:54,101000Z", "c")       = %o', Date.parseDate("2009-03-03T13:36:54,101000Z", "c")); // UTC
10856     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
10857     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
10858 console.groupEnd();
10859
10860 // ISO-8601 format as specified in http://www.w3.org/TR/NOTE-datetime
10861 // -- accepts ALL 6 levels of date-time granularity
10862 console.group('ISO-8601 Granularity Test (see http://www.w3.org/TR/NOTE-datetime)');
10863     console.log('Date.parseDate("1997", "c")                              = %o', Date.parseDate("1997", "c")); // YYYY (e.g. 1997)
10864     console.log('Date.parseDate("1997-07", "c")                           = %o', Date.parseDate("1997-07", "c")); // YYYY-MM (e.g. 1997-07)
10865     console.log('Date.parseDate("1997-07-16", "c")                        = %o', Date.parseDate("1997-07-16", "c")); // YYYY-MM-DD (e.g. 1997-07-16)
10866     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)
10867     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)
10868     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)
10869     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)
10870     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
10871 console.groupEnd();
10872
10873 //*//**
10874  * @class Ext.util.DelayedTask
10875  * <p> The DelayedTask class provides a convenient way to "buffer" the execution of a method,
10876  * performing setTimeout where a new timeout cancels the old timeout. When called, the
10877  * task will wait the specified time period before executing. If durng that time period,
10878  * the task is called again, the original call will be cancelled. This continues so that
10879  * the function is only called a single time for each iteration.</p>
10880  * <p>This method is especially useful for things like detecting whether a user has finished
10881  * typing in a text field. An example would be performing validation on a keypress. You can
10882  * use this class to buffer the keypress events for a certain number of milliseconds, and
10883  * perform only if they stop for that amount of time.  Usage:</p><pre><code>
10884 var task = new Ext.util.DelayedTask(function(){
10885     alert(Ext.getDom('myInputField').value.length);
10886 });
10887 // Wait 500ms before calling our function. If the user presses another key 
10888 // during that 500ms, it will be cancelled and we'll wait another 500ms.
10889 Ext.get('myInputField').on('keypress', function(){
10890     task.{@link #delay}(500); 
10891 });
10892  * </code></pre> 
10893  * <p>Note that we are using a DelayedTask here to illustrate a point. The configuration
10894  * option <tt>buffer</tt> for {@link Ext.util.Observable#addListener addListener/on} will
10895  * also setup a delayed task for you to buffer events.</p> 
10896  * @constructor The parameters to this constructor serve as defaults and are not required.
10897  * @param {Function} fn (optional) The default function to timeout
10898  * @param {Object} scope (optional) The default scope of that timeout
10899  * @param {Array} args (optional) The default Array of arguments
10900  */
10901 Ext.util.DelayedTask = function(fn, scope, args){
10902     var me = this,
10903         id,     
10904         call = function(){
10905                 clearInterval(id);
10906                 id = null;
10907                 fn.apply(scope, args || []);
10908             };
10909             
10910     /**
10911      * Cancels any pending timeout and queues a new one
10912      * @param {Number} delay The milliseconds to delay
10913      * @param {Function} newFn (optional) Overrides function passed to constructor
10914      * @param {Object} newScope (optional) Overrides scope passed to constructor
10915      * @param {Array} newArgs (optional) Overrides args passed to constructor
10916      */
10917     me.delay = function(delay, newFn, newScope, newArgs){
10918         me.cancel();
10919         fn = newFn || fn;
10920         scope = newScope || scope;
10921         args = newArgs || args;
10922         id = setInterval(call, delay);
10923     };
10924
10925     /**
10926      * Cancel the last queued timeout
10927      */
10928     me.cancel = function(){
10929         if(id){
10930             clearInterval(id);
10931             id = null;
10932         }
10933     };
10934 };/**\r
10935  * @class Ext.util.MixedCollection\r
10936  * @extends Ext.util.Observable\r
10937  * A Collection class that maintains both numeric indexes and keys and exposes events.\r
10938  * @constructor\r
10939  * @param {Boolean} allowFunctions True if the addAll function should add function references to the\r
10940  * collection (defaults to false)\r
10941  * @param {Function} keyFn A function that can accept an item of the type(s) stored in this MixedCollection\r
10942  * and return the key value for that item.  This is used when available to look up the key on items that\r
10943  * were passed without an explicit key parameter to a MixedCollection method.  Passing this parameter is\r
10944  * equivalent to providing an implementation for the {@link #getKey} method.\r
10945  */\r
10946 Ext.util.MixedCollection = function(allowFunctions, keyFn){\r
10947     this.items = [];\r
10948     this.map = {};\r
10949     this.keys = [];\r
10950     this.length = 0;\r
10951     this.addEvents(\r
10952         /**\r
10953          * @event clear\r
10954          * Fires when the collection is cleared.\r
10955          */\r
10956         "clear",\r
10957         /**\r
10958          * @event add\r
10959          * Fires when an item is added to the collection.\r
10960          * @param {Number} index The index at which the item was added.\r
10961          * @param {Object} o The item added.\r
10962          * @param {String} key The key associated with the added item.\r
10963          */\r
10964         "add",\r
10965         /**\r
10966          * @event replace\r
10967          * Fires when an item is replaced in the collection.\r
10968          * @param {String} key he key associated with the new added.\r
10969          * @param {Object} old The item being replaced.\r
10970          * @param {Object} new The new item.\r
10971          */\r
10972         "replace",\r
10973         /**\r
10974          * @event remove\r
10975          * Fires when an item is removed from the collection.\r
10976          * @param {Object} o The item being removed.\r
10977          * @param {String} key (optional) The key associated with the removed item.\r
10978          */\r
10979         "remove",\r
10980         "sort"\r
10981     );\r
10982     this.allowFunctions = allowFunctions === true;\r
10983     if(keyFn){\r
10984         this.getKey = keyFn;\r
10985     }\r
10986     Ext.util.MixedCollection.superclass.constructor.call(this);\r
10987 };\r
10988 \r
10989 Ext.extend(Ext.util.MixedCollection, Ext.util.Observable, {\r
10990     allowFunctions : false,\r
10991 \r
10992 /**\r
10993  * Adds an item to the collection. Fires the {@link #add} event when complete.\r
10994  * @param {String} key <p>The key to associate with the item, or the new item.</p>\r
10995  * <p>If you supplied a {@link #getKey} implementation for this MixedCollection, or if the key\r
10996  * of your stored items is in a property called <tt><b>id</b></tt>, then the MixedCollection\r
10997  * will be able to <i>derive</i> the key for the new item. In this case just pass the new item in\r
10998  * this parameter.</p>\r
10999  * @param {Object} o The item to add.\r
11000  * @return {Object} The item added.\r
11001  */\r
11002     add: function(key, o){\r
11003         if(arguments.length == 1){\r
11004             o = arguments[0];\r
11005             key = this.getKey(o);\r
11006         }\r
11007         if(typeof key != 'undefined' && key !== null){\r
11008             var old = this.map[key];\r
11009             if(typeof old != 'undefined'){\r
11010                 return this.replace(key, o);\r
11011             }\r
11012             this.map[key] = o;\r
11013         }\r
11014         this.length++;\r
11015         this.items.push(o);\r
11016         this.keys.push(key);\r
11017         this.fireEvent('add', this.length-1, o, key);\r
11018         return o;\r
11019     },\r
11020 \r
11021 /**\r
11022   * MixedCollection has a generic way to fetch keys if you implement getKey.  The default implementation\r
11023   * simply returns <tt style="font-weight:bold;">item.id</tt> but you can provide your own implementation\r
11024   * to return a different value as in the following examples:\r
11025 <pre><code>\r
11026 // normal way\r
11027 var mc = new Ext.util.MixedCollection();\r
11028 mc.add(someEl.dom.id, someEl);\r
11029 mc.add(otherEl.dom.id, otherEl);\r
11030 //and so on\r
11031 \r
11032 // using getKey\r
11033 var mc = new Ext.util.MixedCollection();\r
11034 mc.getKey = function(el){\r
11035    return el.dom.id;\r
11036 };\r
11037 mc.add(someEl);\r
11038 mc.add(otherEl);\r
11039 \r
11040 // or via the constructor\r
11041 var mc = new Ext.util.MixedCollection(false, function(el){\r
11042    return el.dom.id;\r
11043 });\r
11044 mc.add(someEl);\r
11045 mc.add(otherEl);\r
11046 </code></pre>\r
11047  * @param {Object} item The item for which to find the key.\r
11048  * @return {Object} The key for the passed item.\r
11049  */\r
11050     getKey : function(o){\r
11051          return o.id;\r
11052     },\r
11053 \r
11054 /**\r
11055  * Replaces an item in the collection. Fires the {@link #replace} event when complete.\r
11056  * @param {String} key <p>The key associated with the item to replace, or the replacement item.</p>\r
11057  * <p>If you supplied a {@link #getKey} implementation for this MixedCollection, or if the key\r
11058  * of your stored items is in a property called <tt><b>id</b></tt>, then the MixedCollection\r
11059  * will be able to <i>derive</i> the key of the replacement item. If you want to replace an item\r
11060  * with one having the same key value, then just pass the replacement item in this parameter.</p>\r
11061  * @param o {Object} o (optional) If the first parameter passed was a key, the item to associate\r
11062  * with that key.\r
11063  * @return {Object}  The new item.\r
11064  */\r
11065     replace : function(key, o){\r
11066         if(arguments.length == 1){\r
11067             o = arguments[0];\r
11068             key = this.getKey(o);\r
11069         }\r
11070         var old = this.map[key];\r
11071         if(typeof key == "undefined" || key === null || typeof old == "undefined"){\r
11072              return this.add(key, o);\r
11073         }\r
11074         var index = this.indexOfKey(key);\r
11075         this.items[index] = o;\r
11076         this.map[key] = o;\r
11077         this.fireEvent("replace", key, old, o);\r
11078         return o;\r
11079     },\r
11080 \r
11081 /**\r
11082  * Adds all elements of an Array or an Object to the collection.\r
11083  * @param {Object/Array} objs An Object containing properties which will be added to the collection, or\r
11084  * an Array of values, each of which are added to the collection.\r
11085  */\r
11086     addAll : function(objs){\r
11087         if(arguments.length > 1 || Ext.isArray(objs)){\r
11088             var args = arguments.length > 1 ? arguments : objs;\r
11089             for(var i = 0, len = args.length; i < len; i++){\r
11090                 this.add(args[i]);\r
11091             }\r
11092         }else{\r
11093             for(var key in objs){\r
11094                 if(this.allowFunctions || typeof objs[key] != "function"){\r
11095                     this.add(key, objs[key]);\r
11096                 }\r
11097             }\r
11098         }\r
11099     },\r
11100 \r
11101 /**\r
11102  * Executes the specified function once for every item in the collection, passing the following arguments:\r
11103  * <div class="mdetail-params"><ul>\r
11104  * <li><b>item</b> : Mixed<p class="sub-desc">The collection item</p></li>\r
11105  * <li><b>index</b> : Number<p class="sub-desc">The item's index</p></li>\r
11106  * <li><b>length</b> : Number<p class="sub-desc">The total number of items in the collection</p></li>\r
11107  * </ul></div>\r
11108  * The function should return a boolean value. Returning false from the function will stop the iteration.\r
11109  * @param {Function} fn The function to execute for each item.\r
11110  * @param {Object} scope (optional) The scope in which to execute the function.\r
11111  */\r
11112     each : function(fn, scope){\r
11113         var items = [].concat(this.items); // each safe for removal\r
11114         for(var i = 0, len = items.length; i < len; i++){\r
11115             if(fn.call(scope || items[i], items[i], i, len) === false){\r
11116                 break;\r
11117             }\r
11118         }\r
11119     },\r
11120 \r
11121 /**\r
11122  * Executes the specified function once for every key in the collection, passing each\r
11123  * key, and its associated item as the first two parameters.\r
11124  * @param {Function} fn The function to execute for each item.\r
11125  * @param {Object} scope (optional) The scope in which to execute the function.\r
11126  */\r
11127     eachKey : function(fn, scope){\r
11128         for(var i = 0, len = this.keys.length; i < len; i++){\r
11129             fn.call(scope || window, this.keys[i], this.items[i], i, len);\r
11130         }\r
11131     },\r
11132 \r
11133     /**\r
11134      * Returns the first item in the collection which elicits a true return value from the\r
11135      * passed selection function.\r
11136      * @param {Function} fn The selection function to execute for each item.\r
11137      * @param {Object} scope (optional) The scope in which to execute the function.\r
11138      * @return {Object} The first item in the collection which returned true from the selection function.\r
11139      */\r
11140     find : function(fn, scope){\r
11141         for(var i = 0, len = this.items.length; i < len; i++){\r
11142             if(fn.call(scope || window, this.items[i], this.keys[i])){\r
11143                 return this.items[i];\r
11144             }\r
11145         }\r
11146         return null;\r
11147     },\r
11148 \r
11149 /**\r
11150  * Inserts an item at the specified index in the collection. Fires the {@link #add} event when complete.\r
11151  * @param {Number} index The index to insert the item at.\r
11152  * @param {String} key The key to associate with the new item, or the item itself.\r
11153  * @param {Object} o (optional) If the second parameter was a key, the new item.\r
11154  * @return {Object} The item inserted.\r
11155  */\r
11156     insert : function(index, key, o){\r
11157         if(arguments.length == 2){\r
11158             o = arguments[1];\r
11159             key = this.getKey(o);\r
11160         }\r
11161         if(this.containsKey(key)){\r
11162             this.suspendEvents();\r
11163             this.removeKey(key);\r
11164             this.resumeEvents();\r
11165         }\r
11166         if(index >= this.length){\r
11167             return this.add(key, o);\r
11168         }\r
11169         this.length++;\r
11170         this.items.splice(index, 0, o);\r
11171         if(typeof key != "undefined" && key !== null){\r
11172             this.map[key] = o;\r
11173         }\r
11174         this.keys.splice(index, 0, key);\r
11175         this.fireEvent("add", index, o, key);\r
11176         return o;\r
11177     },\r
11178 \r
11179 /**\r
11180  * Remove an item from the collection.\r
11181  * @param {Object} o The item to remove.\r
11182  * @return {Object} The item removed or false if no item was removed.\r
11183  */\r
11184     remove : function(o){\r
11185         return this.removeAt(this.indexOf(o));\r
11186     },\r
11187 \r
11188 /**\r
11189  * Remove an item from a specified index in the collection. Fires the {@link #remove} event when complete.\r
11190  * @param {Number} index The index within the collection of the item to remove.\r
11191  * @return {Object} The item removed or false if no item was removed.\r
11192  */\r
11193     removeAt : function(index){\r
11194         if(index < this.length && index >= 0){\r
11195             this.length--;\r
11196             var o = this.items[index];\r
11197             this.items.splice(index, 1);\r
11198             var key = this.keys[index];\r
11199             if(typeof key != "undefined"){\r
11200                 delete this.map[key];\r
11201             }\r
11202             this.keys.splice(index, 1);\r
11203             this.fireEvent("remove", o, key);\r
11204             return o;\r
11205         }\r
11206         return false;\r
11207     },\r
11208 \r
11209 /**\r
11210  * Removed an item associated with the passed key fom the collection.\r
11211  * @param {String} key The key of the item to remove.\r
11212  * @return {Object} The item removed or false if no item was removed.\r
11213  */\r
11214     removeKey : function(key){\r
11215         return this.removeAt(this.indexOfKey(key));\r
11216     },\r
11217 \r
11218 /**\r
11219  * Returns the number of items in the collection.\r
11220  * @return {Number} the number of items in the collection.\r
11221  */\r
11222     getCount : function(){\r
11223         return this.length;\r
11224     },\r
11225 \r
11226 /**\r
11227  * Returns index within the collection of the passed Object.\r
11228  * @param {Object} o The item to find the index of.\r
11229  * @return {Number} index of the item. Returns -1 if not found.\r
11230  */\r
11231     indexOf : function(o){\r
11232         return this.items.indexOf(o);\r
11233     },\r
11234 \r
11235 /**\r
11236  * Returns index within the collection of the passed key.\r
11237  * @param {String} key The key to find the index of.\r
11238  * @return {Number} index of the key.\r
11239  */\r
11240     indexOfKey : function(key){\r
11241         return this.keys.indexOf(key);\r
11242     },\r
11243 \r
11244 /**\r
11245  * Returns the item associated with the passed key OR index. Key has priority over index.  This is the equivalent\r
11246  * of calling {@link #key} first, then if nothing matched calling {@link #itemAt}.\r
11247  * @param {String/Number} key The key or index of the item.\r
11248  * @return {Object} If the item is found, returns the item.  If the item was not found, returns <tt>undefined</tt>.\r
11249  * If an item was found, but is a Class, returns <tt>null</tt>.\r
11250  */\r
11251     item : function(key){\r
11252         var mk = this.map[key],\r
11253             item = mk !== undefined ? mk : (typeof key == 'number') ? this.items[key] : undefined;\r
11254         return !Ext.isFunction(item) || this.allowFunctions ? item : null; // for prototype!\r
11255     },\r
11256 \r
11257 /**\r
11258  * Returns the item at the specified index.\r
11259  * @param {Number} index The index of the item.\r
11260  * @return {Object} The item at the specified index.\r
11261  */\r
11262     itemAt : function(index){\r
11263         return this.items[index];\r
11264     },\r
11265 \r
11266 /**\r
11267  * Returns the item associated with the passed key.\r
11268  * @param {String/Number} key The key of the item.\r
11269  * @return {Object} The item associated with the passed key.\r
11270  */\r
11271     key : function(key){\r
11272         return this.map[key];\r
11273     },\r
11274 \r
11275 /**\r
11276  * Returns true if the collection contains the passed Object as an item.\r
11277  * @param {Object} o  The Object to look for in the collection.\r
11278  * @return {Boolean} True if the collection contains the Object as an item.\r
11279  */\r
11280     contains : function(o){\r
11281         return this.indexOf(o) != -1;\r
11282     },\r
11283 \r
11284 /**\r
11285  * Returns true if the collection contains the passed Object as a key.\r
11286  * @param {String} key The key to look for in the collection.\r
11287  * @return {Boolean} True if the collection contains the Object as a key.\r
11288  */\r
11289     containsKey : function(key){\r
11290         return typeof this.map[key] != "undefined";\r
11291     },\r
11292 \r
11293 /**\r
11294  * Removes all items from the collection.  Fires the {@link #clear} event when complete.\r
11295  */\r
11296     clear : function(){\r
11297         this.length = 0;\r
11298         this.items = [];\r
11299         this.keys = [];\r
11300         this.map = {};\r
11301         this.fireEvent("clear");\r
11302     },\r
11303 \r
11304 /**\r
11305  * Returns the first item in the collection.\r
11306  * @return {Object} the first item in the collection..\r
11307  */\r
11308     first : function(){\r
11309         return this.items[0];\r
11310     },\r
11311 \r
11312 /**\r
11313  * Returns the last item in the collection.\r
11314  * @return {Object} the last item in the collection..\r
11315  */\r
11316     last : function(){\r
11317         return this.items[this.length-1];\r
11318     },\r
11319 \r
11320     // private\r
11321     _sort : function(property, dir, fn){\r
11322         var i,\r
11323             len,\r
11324             dsc = String(dir).toUpperCase() == "DESC" ? -1 : 1,\r
11325             c = [], k = this.keys, items = this.items;\r
11326             \r
11327         fn = fn || function(a, b){\r
11328             return a-b;\r
11329         };\r
11330         for(i = 0, len = items.length; i < len; i++){\r
11331             c[c.length] = {key: k[i], value: items[i], index: i};\r
11332         }\r
11333         c.sort(function(a, b){\r
11334             var v = fn(a[property], b[property]) * dsc;\r
11335             if(v === 0){\r
11336                 v = (a.index < b.index ? -1 : 1);\r
11337             }\r
11338             return v;\r
11339         });\r
11340         for(i = 0, len = c.length; i < len; i++){\r
11341             items[i] = c[i].value;\r
11342             k[i] = c[i].key;\r
11343         }\r
11344         this.fireEvent("sort", this);\r
11345     },\r
11346 \r
11347     /**\r
11348      * Sorts this collection with the passed comparison function\r
11349      * @param {String} direction (optional) "ASC" or "DESC"\r
11350      * @param {Function} fn (optional) comparison function\r
11351      */\r
11352     sort : function(dir, fn){\r
11353         this._sort("value", dir, fn);\r
11354     },\r
11355 \r
11356     /**\r
11357      * Sorts this collection by keys\r
11358      * @param {String} direction (optional) "ASC" or "DESC"\r
11359      * @param {Function} fn (optional) a comparison function (defaults to case insensitive string)\r
11360      */\r
11361     keySort : function(dir, fn){\r
11362         this._sort("key", dir, fn || function(a, b){\r
11363             var v1 = String(a).toUpperCase(), v2 = String(b).toUpperCase();\r
11364             return v1 > v2 ? 1 : (v1 < v2 ? -1 : 0);\r
11365         });\r
11366     },\r
11367 \r
11368     /**\r
11369      * Returns a range of items in this collection\r
11370      * @param {Number} startIndex (optional) defaults to 0\r
11371      * @param {Number} endIndex (optional) default to the last item\r
11372      * @return {Array} An array of items\r
11373      */\r
11374     getRange : function(start, end){\r
11375         var items = this.items;\r
11376         if(items.length < 1){\r
11377             return [];\r
11378         }\r
11379         start = start || 0;\r
11380         end = Math.min(typeof end == "undefined" ? this.length-1 : end, this.length-1);\r
11381         var i, r = [];\r
11382         if(start <= end){\r
11383             for(i = start; i <= end; i++) {\r
11384                 r[r.length] = items[i];\r
11385             }\r
11386         }else{\r
11387             for(i = start; i >= end; i--) {\r
11388                 r[r.length] = items[i];\r
11389             }\r
11390         }\r
11391         return r;\r
11392     },\r
11393 \r
11394     /**\r
11395      * Filter the <i>objects</i> in this collection by a specific property.\r
11396      * Returns a new collection that has been filtered.\r
11397      * @param {String} property A property on your objects\r
11398      * @param {String/RegExp} value Either string that the property values\r
11399      * should start with or a RegExp to test against the property\r
11400      * @param {Boolean} anyMatch (optional) True to match any part of the string, not just the beginning\r
11401      * @param {Boolean} caseSensitive (optional) True for case sensitive comparison (defaults to False).\r
11402      * @return {MixedCollection} The new filtered collection\r
11403      */\r
11404     filter : function(property, value, anyMatch, caseSensitive){\r
11405         if(Ext.isEmpty(value, false)){\r
11406             return this.clone();\r
11407         }\r
11408         value = this.createValueMatcher(value, anyMatch, caseSensitive);\r
11409         return this.filterBy(function(o){\r
11410             return o && value.test(o[property]);\r
11411         });\r
11412     },\r
11413 \r
11414     /**\r
11415      * Filter by a function. Returns a <i>new</i> collection that has been filtered.\r
11416      * The passed function will be called with each object in the collection.\r
11417      * If the function returns true, the value is included otherwise it is filtered.\r
11418      * @param {Function} fn The function to be called, it will receive the args o (the object), k (the key)\r
11419      * @param {Object} scope (optional) The scope of the function (defaults to this)\r
11420      * @return {MixedCollection} The new filtered collection\r
11421      */\r
11422     filterBy : function(fn, scope){\r
11423         var r = new Ext.util.MixedCollection();\r
11424         r.getKey = this.getKey;\r
11425         var k = this.keys, it = this.items;\r
11426         for(var i = 0, len = it.length; i < len; i++){\r
11427             if(fn.call(scope||this, it[i], k[i])){\r
11428                 r.add(k[i], it[i]);\r
11429             }\r
11430         }\r
11431         return r;\r
11432     },\r
11433 \r
11434     /**\r
11435      * Finds the index of the first matching object in this collection by a specific property/value.\r
11436      * @param {String} property The name of a property on your objects.\r
11437      * @param {String/RegExp} value A string that the property values\r
11438      * should start with or a RegExp to test against the property.\r
11439      * @param {Number} start (optional) The index to start searching at (defaults to 0).\r
11440      * @param {Boolean} anyMatch (optional) True to match any part of the string, not just the beginning.\r
11441      * @param {Boolean} caseSensitive (optional) True for case sensitive comparison.\r
11442      * @return {Number} The matched index or -1\r
11443      */\r
11444     findIndex : function(property, value, start, anyMatch, caseSensitive){\r
11445         if(Ext.isEmpty(value, false)){\r
11446             return -1;\r
11447         }\r
11448         value = this.createValueMatcher(value, anyMatch, caseSensitive);\r
11449         return this.findIndexBy(function(o){\r
11450             return o && value.test(o[property]);\r
11451         }, null, start);\r
11452     },\r
11453 \r
11454     /**\r
11455      * Find the index of the first matching object in this collection by a function.\r
11456      * If the function returns <i>true</i> it is considered a match.\r
11457      * @param {Function} fn The function to be called, it will receive the args o (the object), k (the key).\r
11458      * @param {Object} scope (optional) The scope of the function (defaults to this).\r
11459      * @param {Number} start (optional) The index to start searching at (defaults to 0).\r
11460      * @return {Number} The matched index or -1\r
11461      */\r
11462     findIndexBy : function(fn, scope, start){\r
11463         var k = this.keys, it = this.items;\r
11464         for(var i = (start||0), len = it.length; i < len; i++){\r
11465             if(fn.call(scope||this, it[i], k[i])){\r
11466                 return i;\r
11467             }\r
11468         }\r
11469         return -1;\r
11470     },\r
11471 \r
11472     // private\r
11473     createValueMatcher : function(value, anyMatch, caseSensitive){\r
11474         if(!value.exec){ // not a regex\r
11475             value = String(value);\r
11476             value = new RegExp((anyMatch === true ? '' : '^') + Ext.escapeRe(value), caseSensitive ? '' : 'i');\r
11477         }\r
11478         return value;\r
11479     },\r
11480 \r
11481     /**\r
11482      * Creates a shallow copy of this collection\r
11483      * @return {MixedCollection}\r
11484      */\r
11485     clone : function(){\r
11486         var r = new Ext.util.MixedCollection();\r
11487         var k = this.keys, it = this.items;\r
11488         for(var i = 0, len = it.length; i < len; i++){\r
11489             r.add(k[i], it[i]);\r
11490         }\r
11491         r.getKey = this.getKey;\r
11492         return r;\r
11493     }\r
11494 });\r
11495 /**\r
11496  * This method calls {@link #item item()}.\r
11497  * Returns the item associated with the passed key OR index. Key has priority over index.  This is the equivalent\r
11498  * of calling {@link #key} first, then if nothing matched calling {@link #itemAt}.\r
11499  * @param {String/Number} key The key or index of the item.\r
11500  * @return {Object} If the item is found, returns the item.  If the item was not found, returns <tt>undefined</tt>.\r
11501  * If an item was found, but is a Class, returns <tt>null</tt>.\r
11502  */\r
11503 Ext.util.MixedCollection.prototype.get = Ext.util.MixedCollection.prototype.item;/**
11504  * @class Ext.util.JSON
11505  * Modified version of Douglas Crockford"s json.js that doesn"t
11506  * mess with the Object prototype
11507  * http://www.json.org/js.html
11508  * @singleton
11509  */
11510 Ext.util.JSON = new (function(){
11511     var useHasOwn = !!{}.hasOwnProperty,
11512         isNative = function() {
11513             var useNative = null;
11514
11515             return function() {
11516                 if (useNative === null) {
11517                     useNative = Ext.USE_NATIVE_JSON && window.JSON && JSON.toString() == '[object JSON]';
11518                 }
11519         
11520                 return useNative;
11521             };
11522         }(),
11523         pad = function(n) {
11524             return n < 10 ? "0" + n : n;
11525         },
11526         doDecode = function(json){
11527             return eval("(" + json + ')');    
11528         },
11529         doEncode = function(o){
11530             if(typeof o == "undefined" || o === null){
11531                 return "null";
11532             }else if(Ext.isArray(o)){
11533                 return encodeArray(o);
11534             }else if(Object.prototype.toString.apply(o) === '[object Date]'){
11535                 return Ext.util.JSON.encodeDate(o);
11536             }else if(typeof o == "string"){
11537                 return encodeString(o);
11538             }else if(typeof o == "number"){
11539                 return isFinite(o) ? String(o) : "null";
11540             }else if(typeof o == "boolean"){
11541                 return String(o);
11542             }else {
11543                 var a = ["{"], b, i, v;
11544                 for (i in o) {
11545                     if(!useHasOwn || o.hasOwnProperty(i)) {
11546                         v = o[i];
11547                         switch (typeof v) {
11548                         case "undefined":
11549                         case "function":
11550                         case "unknown":
11551                             break;
11552                         default:
11553                             if(b){
11554                                 a.push(',');
11555                             }
11556                             a.push(doEncode(i), ":",
11557                                     v === null ? "null" : doEncode(v));
11558                             b = true;
11559                         }
11560                     }
11561                 }
11562                 a.push("}");
11563                 return a.join("");
11564             }    
11565         },
11566         m = {
11567             "\b": '\\b',
11568             "\t": '\\t',
11569             "\n": '\\n',
11570             "\f": '\\f',
11571             "\r": '\\r',
11572             '"' : '\\"',
11573             "\\": '\\\\'
11574         },
11575         encodeString = function(s){
11576             if (/["\\\x00-\x1f]/.test(s)) {
11577                 return '"' + s.replace(/([\x00-\x1f\\"])/g, function(a, b) {
11578                     var c = m[b];
11579                     if(c){
11580                         return c;
11581                     }
11582                     c = b.charCodeAt();
11583                     return "\\u00" +
11584                         Math.floor(c / 16).toString(16) +
11585                         (c % 16).toString(16);
11586                 }) + '"';
11587             }
11588             return '"' + s + '"';
11589         },
11590         encodeArray = function(o){
11591             var a = ["["], b, i, l = o.length, v;
11592                 for (i = 0; i < l; i += 1) {
11593                     v = o[i];
11594                     switch (typeof v) {
11595                         case "undefined":
11596                         case "function":
11597                         case "unknown":
11598                             break;
11599                         default:
11600                             if (b) {
11601                                 a.push(',');
11602                             }
11603                             a.push(v === null ? "null" : Ext.util.JSON.encode(v));
11604                             b = true;
11605                     }
11606                 }
11607                 a.push("]");
11608                 return a.join("");
11609         };
11610
11611     this.encodeDate = function(o){
11612         return '"' + o.getFullYear() + "-" +
11613                 pad(o.getMonth() + 1) + "-" +
11614                 pad(o.getDate()) + "T" +
11615                 pad(o.getHours()) + ":" +
11616                 pad(o.getMinutes()) + ":" +
11617                 pad(o.getSeconds()) + '"';
11618     };
11619
11620     /**
11621      * Encodes an Object, Array or other value
11622      * @param {Mixed} o The variable to encode
11623      * @return {String} The JSON string
11624      */
11625     this.encode = function() {
11626         var ec;
11627         return function(o) {
11628             if (!ec) {
11629                 // setup encoding function on first access
11630                 ec = isNative() ? JSON.stringify : doEncode;
11631             }
11632             return ec(o);
11633         };
11634     }();
11635
11636
11637     /**
11638      * Decodes (parses) a JSON string to an object. If the JSON is invalid, this function throws a SyntaxError unless the safe option is set.
11639      * @param {String} json The JSON string
11640      * @return {Object} The resulting object
11641      */
11642     this.decode = function() {
11643         var dc;
11644         return function(json) {
11645             if (!dc) {
11646                 // setup decoding function on first access
11647                 dc = isNative() ? JSON.parse : doDecode;
11648             }
11649             return dc(json);
11650         };
11651     }();
11652
11653 })();
11654 /**
11655  * Shorthand for {@link Ext.util.JSON#encode}
11656  * @param {Mixed} o The variable to encode
11657  * @return {String} The JSON string
11658  * @member Ext
11659  * @method encode
11660  */
11661 Ext.encode = Ext.util.JSON.encode;
11662 /**
11663  * Shorthand for {@link Ext.util.JSON#decode}
11664  * @param {String} json The JSON string
11665  * @param {Boolean} safe (optional) Whether to return null or throw an exception if the JSON is invalid.
11666  * @return {Object} The resulting object
11667  * @member Ext
11668  * @method decode
11669  */
11670 Ext.decode = Ext.util.JSON.decode;
11671 /**\r
11672  * @class Ext.util.Format\r
11673  * Reusable data formatting functions\r
11674  * @singleton\r
11675  */\r
11676 Ext.util.Format = function(){\r
11677     var trimRe = /^\s+|\s+$/g;\r
11678     return {\r
11679         /**\r
11680          * Truncate a string and add an ellipsis ('...') to the end if it exceeds the specified length\r
11681          * @param {String} value The string to truncate\r
11682          * @param {Number} length The maximum length to allow before truncating\r
11683          * @param {Boolean} word True to try to find a common work break\r
11684          * @return {String} The converted text\r
11685          */\r
11686         ellipsis : function(value, len, word){\r
11687             if(value && value.length > len){\r
11688                 if(word){\r
11689                     var vs = value.substr(0, len - 2);\r
11690                     var index = Math.max(vs.lastIndexOf(' '), vs.lastIndexOf('.'), vs.lastIndexOf('!'), vs.lastIndexOf('?'));\r
11691                     if(index == -1 || index < (len - 15)){\r
11692                         return value.substr(0, len - 3) + "...";\r
11693                     }else{\r
11694                         return vs.substr(0, index) + "...";\r
11695                     }\r
11696                 } else{\r
11697                     return value.substr(0, len - 3) + "...";\r
11698                 }\r
11699             }\r
11700             return value;\r
11701         },\r
11702 \r
11703         /**\r
11704          * Checks a reference and converts it to empty string if it is undefined\r
11705          * @param {Mixed} value Reference to check\r
11706          * @return {Mixed} Empty string if converted, otherwise the original value\r
11707          */\r
11708         undef : function(value){\r
11709             return value !== undefined ? value : "";\r
11710         },\r
11711 \r
11712         /**\r
11713          * Checks a reference and converts it to the default value if it's empty\r
11714          * @param {Mixed} value Reference to check\r
11715          * @param {String} defaultValue The value to insert of it's undefined (defaults to "")\r
11716          * @return {String}\r
11717          */\r
11718         defaultValue : function(value, defaultValue){\r
11719             return value !== undefined && value !== '' ? value : defaultValue;\r
11720         },\r
11721 \r
11722         /**\r
11723          * Convert certain characters (&, <, >, and ') to their HTML character equivalents for literal display in web pages.\r
11724          * @param {String} value The string to encode\r
11725          * @return {String} The encoded text\r
11726          */\r
11727         htmlEncode : function(value){\r
11728             return !value ? value : String(value).replace(/&/g, "&amp;").replace(/>/g, "&gt;").replace(/</g, "&lt;").replace(/"/g, "&quot;");\r
11729         },\r
11730 \r
11731         /**\r
11732          * Convert certain characters (&, <, >, and ') from their HTML character equivalents.\r
11733          * @param {String} value The string to decode\r
11734          * @return {String} The decoded text\r
11735          */\r
11736         htmlDecode : function(value){\r
11737             return !value ? value : String(value).replace(/&gt;/g, ">").replace(/&lt;/g, "<").replace(/&quot;/g, '"').replace(/&amp;/g, "&");\r
11738         },\r
11739 \r
11740         /**\r
11741          * Trims any whitespace from either side of a string\r
11742          * @param {String} value The text to trim\r
11743          * @return {String} The trimmed text\r
11744          */\r
11745         trim : function(value){\r
11746             return String(value).replace(trimRe, "");\r
11747         },\r
11748 \r
11749         /**\r
11750          * Returns a substring from within an original string\r
11751          * @param {String} value The original text\r
11752          * @param {Number} start The start index of the substring\r
11753          * @param {Number} length The length of the substring\r
11754          * @return {String} The substring\r
11755          */\r
11756         substr : function(value, start, length){\r
11757             return String(value).substr(start, length);\r
11758         },\r
11759 \r
11760         /**\r
11761          * Converts a string to all lower case letters\r
11762          * @param {String} value The text to convert\r
11763          * @return {String} The converted text\r
11764          */\r
11765         lowercase : function(value){\r
11766             return String(value).toLowerCase();\r
11767         },\r
11768 \r
11769         /**\r
11770          * Converts a string to all upper case letters\r
11771          * @param {String} value The text to convert\r
11772          * @return {String} The converted text\r
11773          */\r
11774         uppercase : function(value){\r
11775             return String(value).toUpperCase();\r
11776         },\r
11777 \r
11778         /**\r
11779          * Converts the first character only of a string to upper case\r
11780          * @param {String} value The text to convert\r
11781          * @return {String} The converted text\r
11782          */\r
11783         capitalize : function(value){\r
11784             return !value ? value : value.charAt(0).toUpperCase() + value.substr(1).toLowerCase();\r
11785         },\r
11786 \r
11787         // private\r
11788         call : function(value, fn){\r
11789             if(arguments.length > 2){\r
11790                 var args = Array.prototype.slice.call(arguments, 2);\r
11791                 args.unshift(value);\r
11792                 return eval(fn).apply(window, args);\r
11793             }else{\r
11794                 return eval(fn).call(window, value);\r
11795             }\r
11796         },\r
11797 \r
11798         /**\r
11799          * Format a number as US currency\r
11800          * @param {Number/String} value The numeric value to format\r
11801          * @return {String} The formatted currency string\r
11802          */\r
11803         usMoney : function(v){\r
11804             v = (Math.round((v-0)*100))/100;\r
11805             v = (v == Math.floor(v)) ? v + ".00" : ((v*10 == Math.floor(v*10)) ? v + "0" : v);\r
11806             v = String(v);\r
11807             var ps = v.split('.');\r
11808             var whole = ps[0];\r
11809             var sub = ps[1] ? '.'+ ps[1] : '.00';\r
11810             var r = /(\d+)(\d{3})/;\r
11811             while (r.test(whole)) {\r
11812                 whole = whole.replace(r, '$1' + ',' + '$2');\r
11813             }\r
11814             v = whole + sub;\r
11815             if(v.charAt(0) == '-'){\r
11816                 return '-$' + v.substr(1);\r
11817             }\r
11818             return "$" +  v;\r
11819         },\r
11820 \r
11821         /**\r
11822          * Parse a value into a formatted date using the specified format pattern.\r
11823          * @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)\r
11824          * @param {String} format (optional) Any valid date format string (defaults to 'm/d/Y')\r
11825          * @return {String} The formatted date string\r
11826          */\r
11827         date : function(v, format){\r
11828             if(!v){\r
11829                 return "";\r
11830             }\r
11831             if(!Ext.isDate(v)){\r
11832                 v = new Date(Date.parse(v));\r
11833             }\r
11834             return v.dateFormat(format || "m/d/Y");\r
11835         },\r
11836 \r
11837         /**\r
11838          * Returns a date rendering function that can be reused to apply a date format multiple times efficiently\r
11839          * @param {String} format Any valid date format string\r
11840          * @return {Function} The date formatting function\r
11841          */\r
11842         dateRenderer : function(format){\r
11843             return function(v){\r
11844                 return Ext.util.Format.date(v, format);\r
11845             };\r
11846         },\r
11847 \r
11848         // private\r
11849         stripTagsRE : /<\/?[^>]+>/gi,\r
11850         \r
11851         /**\r
11852          * Strips all HTML tags\r
11853          * @param {Mixed} value The text from which to strip tags\r
11854          * @return {String} The stripped text\r
11855          */\r
11856         stripTags : function(v){\r
11857             return !v ? v : String(v).replace(this.stripTagsRE, "");\r
11858         },\r
11859 \r
11860         stripScriptsRe : /(?:<script.*?>)((\n|\r|.)*?)(?:<\/script>)/ig,\r
11861 \r
11862         /**\r
11863          * Strips all script tags\r
11864          * @param {Mixed} value The text from which to strip script tags\r
11865          * @return {String} The stripped text\r
11866          */\r
11867         stripScripts : function(v){\r
11868             return !v ? v : String(v).replace(this.stripScriptsRe, "");\r
11869         },\r
11870 \r
11871         /**\r
11872          * Simple format for a file size (xxx bytes, xxx KB, xxx MB)\r
11873          * @param {Number/String} size The numeric value to format\r
11874          * @return {String} The formatted file size\r
11875          */\r
11876         fileSize : function(size){\r
11877             if(size < 1024) {\r
11878                 return size + " bytes";\r
11879             } else if(size < 1048576) {\r
11880                 return (Math.round(((size*10) / 1024))/10) + " KB";\r
11881             } else {\r
11882                 return (Math.round(((size*10) / 1048576))/10) + " MB";\r
11883             }\r
11884         },\r
11885 \r
11886         /**\r
11887          * It does simple math for use in a template, for example:<pre><code>\r
11888          * var tpl = new Ext.Template('{value} * 10 = {value:math("* 10")}');\r
11889          * </code></pre>\r
11890          * @return {Function} A function that operates on the passed value.\r
11891          */\r
11892         math : function(){\r
11893             var fns = {};\r
11894             return function(v, a){\r
11895                 if(!fns[a]){\r
11896                     fns[a] = new Function('v', 'return v ' + a + ';');\r
11897                 }\r
11898                 return fns[a](v);\r
11899             }\r
11900         }(),\r
11901 \r
11902         /**\r
11903          * Rounds the passed number to the required decimal precision.\r
11904          * @param {Number/String} value The numeric value to round.\r
11905          * @param {Number} precision The number of decimal places to which to round the first parameter's value.\r
11906          * @return {Number} The rounded value.\r
11907          */\r
11908         round : function(value, precision) {\r
11909             var result = Number(value);\r
11910             if (typeof precision == 'number') {\r
11911                 precision = Math.pow(10, precision);\r
11912                 result = Math.round(value * precision) / precision;\r
11913             }\r
11914             return result;\r
11915         },\r
11916 \r
11917         /**\r
11918          * Formats the number according to the format string.\r
11919          * <div style="margin-left:40px">examples (123456.789):\r
11920          * <div style="margin-left:10px">\r
11921          * 0 - (123456) show only digits, no precision<br>\r
11922          * 0.00 - (123456.78) show only digits, 2 precision<br>\r
11923          * 0.0000 - (123456.7890) show only digits, 4 precision<br>\r
11924          * 0,000 - (123,456) show comma and digits, no precision<br>\r
11925          * 0,000.00 - (123,456.78) show comma and digits, 2 precision<br>\r
11926          * 0,0.00 - (123,456.78) shortcut method, show comma and digits, 2 precision<br>\r
11927          * To reverse the grouping (,) and decimal (.) for international numbers, add /i to the end.\r
11928          * For example: 0.000,00/i\r
11929          * </div></div>\r
11930          * @param {Number} v The number to format.\r
11931          * @param {String} format The way you would like to format this text.\r
11932          * @return {String} The formatted number.\r
11933          */\r
11934         number: function(v, format) {\r
11935             if(!format){\r
11936                         return v;\r
11937                     }\r
11938                     v = Ext.num(v, NaN);\r
11939             if (isNaN(v)){\r
11940                 return '';\r
11941             }\r
11942                     var comma = ',',\r
11943                         dec = '.',\r
11944                         i18n = false,\r
11945                         neg = v < 0;\r
11946                 \r
11947                     v = Math.abs(v);\r
11948                     if(format.substr(format.length - 2) == '/i'){\r
11949                         format = format.substr(0, format.length - 2);\r
11950                         i18n = true;\r
11951                         comma = '.';\r
11952                         dec = ',';\r
11953                     }\r
11954                 \r
11955                     var hasComma = format.indexOf(comma) != -1, \r
11956                         psplit = (i18n ? format.replace(/[^\d\,]/g, '') : format.replace(/[^\d\.]/g, '')).split(dec);\r
11957                 \r
11958                     if(1 < psplit.length){\r
11959                         v = v.toFixed(psplit[1].length);\r
11960                     }else if(2 < psplit.length){\r
11961                         throw ('NumberFormatException: invalid format, formats should have no more than 1 period: ' + format);\r
11962                     }else{\r
11963                         v = v.toFixed(0);\r
11964                     }\r
11965                 \r
11966                     var fnum = v.toString();\r
11967                     if(hasComma){\r
11968                         psplit = fnum.split('.');\r
11969                 \r
11970                         var cnum = psplit[0], parr = [], j = cnum.length, m = Math.floor(j / 3), n = cnum.length % 3 || 3;\r
11971                 \r
11972                         for(var i = 0; i < j; i += n){\r
11973                             if(i != 0){\r
11974                                 n = 3;\r
11975                             }\r
11976                             parr[parr.length] = cnum.substr(i, n);\r
11977                             m -= 1;\r
11978                         }\r
11979                         fnum = parr.join(comma);\r
11980                         if(psplit[1]){\r
11981                             fnum += dec + psplit[1];\r
11982                         }\r
11983                     }\r
11984                 \r
11985                     return (neg ? '-' : '') + format.replace(/[\d,?\.?]+/, fnum);\r
11986         },\r
11987 \r
11988         /**\r
11989          * Returns a number rendering function that can be reused to apply a number format multiple times efficiently\r
11990          * @param {String} format Any valid number format string for {@link #number}\r
11991          * @return {Function} The number formatting function\r
11992          */\r
11993         numberRenderer : function(format){\r
11994             return function(v){\r
11995                 return Ext.util.Format.number(v, format);\r
11996             };\r
11997         },\r
11998 \r
11999         /**\r
12000          * Selectively do a plural form of a word based on a numeric value. For example, in a template,\r
12001          * {commentCount:plural("Comment")}  would result in "1 Comment" if commentCount was 1 or would be "x Comments"\r
12002          * if the value is 0 or greater than 1.\r
12003          * @param {Number} value The value to compare against\r
12004          * @param {String} singular The singular form of the word\r
12005          * @param {String} plural (optional) The plural form of the word (defaults to the singular with an "s")\r
12006          */\r
12007         plural : function(v, s, p){\r
12008             return v +' ' + (v == 1 ? s : (p ? p : s+'s'));\r
12009         },\r
12010         \r
12011         /**\r
12012          * Converts newline characters to the HTML tag &lt;br/>\r
12013          * @param {String} The string value to format.\r
12014          * @return {String} The string with embedded &lt;br/> tags in place of newlines.\r
12015          */\r
12016         nl2br : function(v){\r
12017             return v === undefined || v === null ? '' : v.replace(/\n/g, '<br/>');\r
12018         }\r
12019     }\r
12020 }();/**
12021  * @class Ext.XTemplate
12022  * @extends Ext.Template
12023  * <p>A template class that supports advanced functionality like autofilling arrays, conditional processing with
12024  * basic comparison operators, sub-templates, basic math function support, special built-in template variables,
12025  * inline code execution and more.  XTemplate also provides the templating mechanism built into {@link Ext.DataView}.</p>
12026  * <p>XTemplate supports many special tags and built-in operators that aren't defined as part of the API, but are
12027  * supported in the templates that can be created.  The following examples demonstrate all of the supported features.
12028  * This is the data object used for reference in each code example:</p>
12029  * <pre><code>
12030 var data = {
12031     name: 'Jack Slocum',
12032     title: 'Lead Developer',
12033     company: 'Ext JS, LLC',
12034     email: 'jack@extjs.com',
12035     address: '4 Red Bulls Drive',
12036     city: 'Cleveland',
12037     state: 'Ohio',
12038     zip: '44102',
12039     drinks: ['Red Bull', 'Coffee', 'Water'],
12040     kids: [{
12041         name: 'Sara Grace',
12042         age:3
12043     },{
12044         name: 'Zachary',
12045         age:2
12046     },{
12047         name: 'John James',
12048         age:0
12049     }]
12050 };
12051  * </code></pre>
12052  * <p><b>Auto filling of arrays</b><br/>The <tt>tpl</tt> tag and the <tt>for</tt> operator are used
12053  * to process the provided data object. If <tt>for="."</tt> is specified, the data object provided
12054  * is examined. If the variable in <tt>for</tt> is an array, it will auto-fill, repeating the template
12055  * block inside the <tt>tpl</tt> tag for each item in the array:</p>
12056  * <pre><code>
12057 var tpl = new Ext.XTemplate(
12058     '&lt;p>Kids: ',
12059     '&lt;tpl for=".">',
12060         '&lt;p>{name}&lt;/p>',
12061     '&lt;/tpl>&lt;/p>'
12062 );
12063 tpl.overwrite(panel.body, data.kids); // pass the kids property of the data object
12064  * </code></pre>
12065  * <p><b>Scope switching</b><br/>The <tt>for</tt> property can be leveraged to access specified members
12066  * of the provided data object to populate the template:</p>
12067  * <pre><code>
12068 var tpl = new Ext.XTemplate(
12069     '&lt;p>Name: {name}&lt;/p>',
12070     '&lt;p>Title: {title}&lt;/p>',
12071     '&lt;p>Company: {company}&lt;/p>',
12072     '&lt;p>Kids: ',
12073     '&lt;tpl <b>for="kids"</b>>', // interrogate the kids property within the data
12074         '&lt;p>{name}&lt;/p>',
12075     '&lt;/tpl>&lt;/p>'
12076 );
12077 tpl.overwrite(panel.body, data);
12078  * </code></pre>
12079  * <p><b>Access to parent object from within sub-template scope</b><br/>When processing a sub-template, for example while
12080  * looping through a child array, you can access the parent object's members via the <tt>parent</tt> object:</p>
12081  * <pre><code>
12082 var tpl = new Ext.XTemplate(
12083     '&lt;p>Name: {name}&lt;/p>',
12084     '&lt;p>Kids: ',
12085     '&lt;tpl for="kids">',
12086         '&lt;tpl if="age &amp;gt; 1">',  // <-- Note that the &gt; is encoded
12087             '&lt;p>{name}&lt;/p>',
12088             '&lt;p>Dad: {parent.name}&lt;/p>',
12089         '&lt;/tpl>',
12090     '&lt;/tpl>&lt;/p>'
12091 );
12092 tpl.overwrite(panel.body, data);
12093 </code></pre>
12094  * <p><b>Array item index and basic math support</b> <br/>While processing an array, the special variable <tt>{#}</tt>
12095  * will provide the current array index + 1 (starts at 1, not 0). Templates also support the basic math operators
12096  * + - * and / that can be applied directly on numeric data values:</p>
12097  * <pre><code>
12098 var tpl = new Ext.XTemplate(
12099     '&lt;p>Name: {name}&lt;/p>',
12100     '&lt;p>Kids: ',
12101     '&lt;tpl for="kids">',
12102         '&lt;tpl if="age &amp;gt; 1">',  // <-- Note that the &gt; is encoded
12103             '&lt;p>{#}: {name}&lt;/p>',  // <-- Auto-number each item
12104             '&lt;p>In 5 Years: {age+5}&lt;/p>',  // <-- Basic math
12105             '&lt;p>Dad: {parent.name}&lt;/p>',
12106         '&lt;/tpl>',
12107     '&lt;/tpl>&lt;/p>'
12108 );
12109 tpl.overwrite(panel.body, data);
12110 </code></pre>
12111  * <p><b>Auto-rendering of flat arrays</b> <br/>Flat arrays that contain values (and not objects) can be auto-rendered
12112  * using the special <tt>{.}</tt> variable inside a loop.  This variable will represent the value of
12113  * the array at the current index:</p>
12114  * <pre><code>
12115 var tpl = new Ext.XTemplate(
12116     '&lt;p>{name}\'s favorite beverages:&lt;/p>',
12117     '&lt;tpl for="drinks">',
12118        '&lt;div> - {.}&lt;/div>',
12119     '&lt;/tpl>'
12120 );
12121 tpl.overwrite(panel.body, data);
12122 </code></pre>
12123  * <p><b>Basic conditional logic</b> <br/>Using the <tt>tpl</tt> tag and the <tt>if</tt>
12124  * operator you can provide conditional checks for deciding whether or not to render specific parts of the template.
12125  * Note that there is no <tt>else</tt> operator &mdash; if needed, you should use two opposite <tt>if</tt> statements.
12126  * Properly-encoded attributes are required as seen in the following example:</p>
12127  * <pre><code>
12128 var tpl = new Ext.XTemplate(
12129     '&lt;p>Name: {name}&lt;/p>',
12130     '&lt;p>Kids: ',
12131     '&lt;tpl for="kids">',
12132         '&lt;tpl if="age &amp;gt; 1">',  // <-- Note that the &gt; is encoded
12133             '&lt;p>{name}&lt;/p>',
12134         '&lt;/tpl>',
12135     '&lt;/tpl>&lt;/p>'
12136 );
12137 tpl.overwrite(panel.body, data);
12138 </code></pre>
12139  * <p><b>Ability to execute arbitrary inline code</b> <br/>In an XTemplate, anything between {[ ... ]}  is considered
12140  * code to be executed in the scope of the template. There are some special variables available in that code:
12141  * <ul>
12142  * <li><b><tt>values</tt></b>: The values in the current scope. If you are using scope changing sub-templates, you
12143  * can change what <tt>values</tt> is.</li>
12144  * <li><b><tt>parent</tt></b>: The scope (values) of the ancestor template.</li>
12145  * <li><b><tt>xindex</tt></b>: If you are in a looping template, the index of the loop you are in (1-based).</li>
12146  * <li><b><tt>xcount</tt></b>: If you are in a looping template, the total length of the array you are looping.</li>
12147  * <li><b><tt>fm</tt></b>: An alias for <tt>Ext.util.Format</tt>.</li>
12148  * </ul>
12149  * This example demonstrates basic row striping using an inline code block and the <tt>xindex</tt> variable:</p>
12150  * <pre><code>
12151 var tpl = new Ext.XTemplate(
12152     '&lt;p>Name: {name}&lt;/p>',
12153     '&lt;p>Company: {[values.company.toUpperCase() + ", " + values.title]}&lt;/p>',
12154     '&lt;p>Kids: ',
12155     '&lt;tpl for="kids">',
12156        '&lt;div class="{[xindex % 2 === 0 ? "even" : "odd"]}">',
12157         '{name}',
12158         '&lt;/div>',
12159     '&lt;/tpl>&lt;/p>'
12160 );
12161 tpl.overwrite(panel.body, data);
12162 </code></pre>
12163  * <p><b>Template member functions</b> <br/>One or more member functions can be defined directly on the config
12164  * object passed into the XTemplate constructor for more complex processing:</p>
12165  * <pre><code>
12166 var tpl = new Ext.XTemplate(
12167     '&lt;p>Name: {name}&lt;/p>',
12168     '&lt;p>Kids: ',
12169     '&lt;tpl for="kids">',
12170         '&lt;tpl if="this.isGirl(name)">',
12171             '&lt;p>Girl: {name} - {age}&lt;/p>',
12172         '&lt;/tpl>',
12173         '&lt;tpl if="this.isGirl(name) == false">',
12174             '&lt;p>Boy: {name} - {age}&lt;/p>',
12175         '&lt;/tpl>',
12176         '&lt;tpl if="this.isBaby(age)">',
12177             '&lt;p>{name} is a baby!&lt;/p>',
12178         '&lt;/tpl>',
12179     '&lt;/tpl>&lt;/p>', {
12180      isGirl: function(name){
12181          return name == 'Sara Grace';
12182      },
12183      isBaby: function(age){
12184         return age < 1;
12185      }
12186 });
12187 tpl.overwrite(panel.body, data);
12188 </code></pre>
12189  * @constructor
12190  * @param {String/Array/Object} parts The HTML fragment or an array of fragments to join(""), or multiple arguments
12191  * to join("") that can also include a config object
12192  */
12193 Ext.XTemplate = function(){
12194     Ext.XTemplate.superclass.constructor.apply(this, arguments);
12195
12196     var me = this,
12197         s = me.html,
12198         re = /<tpl\b[^>]*>((?:(?=([^<]+))\2|<(?!tpl\b[^>]*>))*?)<\/tpl>/,
12199         nameRe = /^<tpl\b[^>]*?for="(.*?)"/,
12200         ifRe = /^<tpl\b[^>]*?if="(.*?)"/,
12201         execRe = /^<tpl\b[^>]*?exec="(.*?)"/,
12202         m,
12203         id = 0,
12204         tpls = [],
12205         VALUES = 'values',
12206         PARENT = 'parent',
12207         XINDEX = 'xindex',
12208         XCOUNT = 'xcount',
12209         RETURN = 'return ',
12210         WITHVALUES = 'with(values){ ';
12211
12212     s = ['<tpl>', s, '</tpl>'].join('');
12213
12214     while((m = s.match(re))){
12215         var m2 = m[0].match(nameRe),
12216                         m3 = m[0].match(ifRe),
12217                 m4 = m[0].match(execRe),
12218                 exp = null,
12219                 fn = null,
12220                 exec = null,
12221                 name = m2 && m2[1] ? m2[1] : '';
12222
12223        if (m3) {
12224            exp = m3 && m3[1] ? m3[1] : null;
12225            if(exp){
12226                fn = new Function(VALUES, PARENT, XINDEX, XCOUNT, WITHVALUES + RETURN +(Ext.util.Format.htmlDecode(exp))+'; }');
12227            }
12228        }
12229        if (m4) {
12230            exp = m4 && m4[1] ? m4[1] : null;
12231            if(exp){
12232                exec = new Function(VALUES, PARENT, XINDEX, XCOUNT, WITHVALUES +(Ext.util.Format.htmlDecode(exp))+'; }');
12233            }
12234        }
12235        if(name){
12236            switch(name){
12237                case '.': name = new Function(VALUES, PARENT, WITHVALUES + RETURN + VALUES + '; }'); break;
12238                case '..': name = new Function(VALUES, PARENT, WITHVALUES + RETURN + PARENT + '; }'); break;
12239                default: name = new Function(VALUES, PARENT, WITHVALUES + RETURN + name + '; }');
12240            }
12241        }
12242        tpls.push({
12243             id: id,
12244             target: name,
12245             exec: exec,
12246             test: fn,
12247             body: m[1]||''
12248         });
12249        s = s.replace(m[0], '{xtpl'+ id + '}');
12250        ++id;
12251     }
12252         Ext.each(tpls, function(t) {
12253         me.compileTpl(t);
12254     });
12255     me.master = tpls[tpls.length-1];
12256     me.tpls = tpls;
12257 };
12258 Ext.extend(Ext.XTemplate, Ext.Template, {
12259     // private
12260     re : /\{([\w-\.\#]+)(?:\:([\w\.]*)(?:\((.*?)?\))?)?(\s?[\+\-\*\\]\s?[\d\.\+\-\*\\\(\)]+)?\}/g,
12261     // private
12262     codeRe : /\{\[((?:\\\]|.|\n)*?)\]\}/g,
12263
12264     // private
12265     applySubTemplate : function(id, values, parent, xindex, xcount){
12266         var me = this,
12267                 len,
12268                 t = me.tpls[id],
12269                 vs,
12270                 buf = [];
12271         if ((t.test && !t.test.call(me, values, parent, xindex, xcount)) ||
12272             (t.exec && t.exec.call(me, values, parent, xindex, xcount))) {
12273             return '';
12274         }
12275         vs = t.target ? t.target.call(me, values, parent) : values;
12276         len = vs.length;
12277         parent = t.target ? values : parent;
12278         if(t.target && Ext.isArray(vs)){
12279                 Ext.each(vs, function(v, i) {
12280                 buf[buf.length] = t.compiled.call(me, v, parent, i+1, len);
12281             });
12282             return buf.join('');
12283         }
12284         return t.compiled.call(me, vs, parent, xindex, xcount);
12285     },
12286
12287     // private
12288     compileTpl : function(tpl){
12289         var fm = Ext.util.Format,
12290                 useF = this.disableFormats !== true,
12291             sep = Ext.isGecko ? "+" : ",",
12292             body;
12293
12294         function fn(m, name, format, args, math){
12295             if(name.substr(0, 4) == 'xtpl'){
12296                 return "'"+ sep +'this.applySubTemplate('+name.substr(4)+', values, parent, xindex, xcount)'+sep+"'";
12297             }
12298             var v;
12299             if(name === '.'){
12300                 v = 'values';
12301             }else if(name === '#'){
12302                 v = 'xindex';
12303             }else if(name.indexOf('.') != -1){
12304                 v = name;
12305             }else{
12306                 v = "values['" + name + "']";
12307             }
12308             if(math){
12309                 v = '(' + v + math + ')';
12310             }
12311             if (format && useF) {
12312                 args = args ? ',' + args : "";
12313                 if(format.substr(0, 5) != "this."){
12314                     format = "fm." + format + '(';
12315                 }else{
12316                     format = 'this.call("'+ format.substr(5) + '", ';
12317                     args = ", values";
12318                 }
12319             } else {
12320                 args= ''; format = "("+v+" === undefined ? '' : ";
12321             }
12322             return "'"+ sep + format + v + args + ")"+sep+"'";
12323         }
12324
12325         function codeFn(m, code){
12326             return "'"+ sep +'('+code+')'+sep+"'";
12327         }
12328
12329         // branched to use + in gecko and [].join() in others
12330         if(Ext.isGecko){
12331             body = "tpl.compiled = function(values, parent, xindex, xcount){ return '" +
12332                    tpl.body.replace(/(\r\n|\n)/g, '\\n').replace(/'/g, "\\'").replace(this.re, fn).replace(this.codeRe, codeFn) +
12333                     "';};";
12334         }else{
12335             body = ["tpl.compiled = function(values, parent, xindex, xcount){ return ['"];
12336             body.push(tpl.body.replace(/(\r\n|\n)/g, '\\n').replace(/'/g, "\\'").replace(this.re, fn).replace(this.codeRe, codeFn));
12337             body.push("'].join('');};");
12338             body = body.join('');
12339         }
12340         eval(body);
12341         return this;
12342     },
12343
12344     /**
12345      * Returns an HTML fragment of this template with the specified values applied.
12346      * @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'})
12347      * @return {String} The HTML fragment
12348      */
12349     applyTemplate : function(values){
12350         return this.master.compiled.call(this, values, {}, 1, 1);
12351     },
12352
12353     /**
12354      * Compile the template to a function for optimized performance.  Recommended if the template will be used frequently.
12355      * @return {Function} The compiled function
12356      */
12357     compile : function(){return this;}
12358
12359     /**
12360      * @property re
12361      * @hide
12362      */
12363     /**
12364      * @property disableFormats
12365      * @hide
12366      */
12367     /**
12368      * @method set
12369      * @hide
12370      */
12371
12372 });
12373 /**
12374  * Alias for {@link #applyTemplate}
12375  * Returns an HTML fragment of this template with the specified values applied.
12376  * @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'})
12377  * @return {String} The HTML fragment
12378  * @member Ext.XTemplate
12379  * @method apply
12380  */
12381 Ext.XTemplate.prototype.apply = Ext.XTemplate.prototype.applyTemplate;
12382
12383 /**
12384  * Creates a template from the passed element's value (<i>display:none</i> textarea, preferred) or innerHTML.
12385  * @param {String/HTMLElement} el A DOM element or its id
12386  * @return {Ext.Template} The created template
12387  * @static
12388  */
12389 Ext.XTemplate.from = function(el){
12390     el = Ext.getDom(el);
12391     return new Ext.XTemplate(el.value || el.innerHTML);
12392 };/**\r
12393  * @class Ext.util.CSS\r
12394  * Utility class for manipulating CSS rules\r
12395  * @singleton\r
12396  */\r
12397 Ext.util.CSS = function(){\r
12398         var rules = null;\r
12399         var doc = document;\r
12400 \r
12401     var camelRe = /(-[a-z])/gi;\r
12402     var camelFn = function(m, a){ return a.charAt(1).toUpperCase(); };\r
12403 \r
12404    return {\r
12405    /**\r
12406     * Creates a stylesheet from a text blob of rules.\r
12407     * These rules will be wrapped in a STYLE tag and appended to the HEAD of the document.\r
12408     * @param {String} cssText The text containing the css rules\r
12409     * @param {String} id An id to add to the stylesheet for later removal\r
12410     * @return {StyleSheet}\r
12411     */\r
12412    createStyleSheet : function(cssText, id){\r
12413        var ss;\r
12414        var head = doc.getElementsByTagName("head")[0];\r
12415        var rules = doc.createElement("style");\r
12416        rules.setAttribute("type", "text/css");\r
12417        if(id){\r
12418            rules.setAttribute("id", id);\r
12419        }\r
12420        if(Ext.isIE){\r
12421            head.appendChild(rules);\r
12422            ss = rules.styleSheet;\r
12423            ss.cssText = cssText;\r
12424        }else{\r
12425            try{\r
12426                 rules.appendChild(doc.createTextNode(cssText));\r
12427            }catch(e){\r
12428                rules.cssText = cssText;\r
12429            }\r
12430            head.appendChild(rules);\r
12431            ss = rules.styleSheet ? rules.styleSheet : (rules.sheet || doc.styleSheets[doc.styleSheets.length-1]);\r
12432        }\r
12433        this.cacheStyleSheet(ss);\r
12434        return ss;\r
12435    },\r
12436 \r
12437    /**\r
12438     * Removes a style or link tag by id\r
12439     * @param {String} id The id of the tag\r
12440     */\r
12441    removeStyleSheet : function(id){\r
12442        var existing = doc.getElementById(id);\r
12443        if(existing){\r
12444            existing.parentNode.removeChild(existing);\r
12445        }\r
12446    },\r
12447 \r
12448    /**\r
12449     * Dynamically swaps an existing stylesheet reference for a new one\r
12450     * @param {String} id The id of an existing link tag to remove\r
12451     * @param {String} url The href of the new stylesheet to include\r
12452     */\r
12453    swapStyleSheet : function(id, url){\r
12454        this.removeStyleSheet(id);\r
12455        var ss = doc.createElement("link");\r
12456        ss.setAttribute("rel", "stylesheet");\r
12457        ss.setAttribute("type", "text/css");\r
12458        ss.setAttribute("id", id);\r
12459        ss.setAttribute("href", url);\r
12460        doc.getElementsByTagName("head")[0].appendChild(ss);\r
12461    },\r
12462    \r
12463    /**\r
12464     * Refresh the rule cache if you have dynamically added stylesheets\r
12465     * @return {Object} An object (hash) of rules indexed by selector\r
12466     */\r
12467    refreshCache : function(){\r
12468        return this.getRules(true);\r
12469    },\r
12470 \r
12471    // private\r
12472    cacheStyleSheet : function(ss){\r
12473        if(!rules){\r
12474            rules = {};\r
12475        }\r
12476        try{// try catch for cross domain access issue\r
12477            var ssRules = ss.cssRules || ss.rules;\r
12478            for(var j = ssRules.length-1; j >= 0; --j){\r
12479                rules[ssRules[j].selectorText] = ssRules[j];\r
12480            }\r
12481        }catch(e){}\r
12482    },\r
12483    \r
12484    /**\r
12485     * Gets all css rules for the document\r
12486     * @param {Boolean} refreshCache true to refresh the internal cache\r
12487     * @return {Object} An object (hash) of rules indexed by selector\r
12488     */\r
12489    getRules : function(refreshCache){\r
12490                 if(rules === null || refreshCache){\r
12491                         rules = {};\r
12492                         var ds = doc.styleSheets;\r
12493                         for(var i =0, len = ds.length; i < len; i++){\r
12494                             try{\r
12495                         this.cacheStyleSheet(ds[i]);\r
12496                     }catch(e){} \r
12497                 }\r
12498                 }\r
12499                 return rules;\r
12500         },\r
12501         \r
12502         /**\r
12503     * Gets an an individual CSS rule by selector(s)\r
12504     * @param {String/Array} selector The CSS selector or an array of selectors to try. The first selector that is found is returned.\r
12505     * @param {Boolean} refreshCache true to refresh the internal cache if you have recently updated any rules or added styles dynamically\r
12506     * @return {CSSRule} The CSS rule or null if one is not found\r
12507     */\r
12508    getRule : function(selector, refreshCache){\r
12509                 var rs = this.getRules(refreshCache);\r
12510                 if(!Ext.isArray(selector)){\r
12511                     return rs[selector];\r
12512                 }\r
12513                 for(var i = 0; i < selector.length; i++){\r
12514                         if(rs[selector[i]]){\r
12515                                 return rs[selector[i]];\r
12516                         }\r
12517                 }\r
12518                 return null;\r
12519         },\r
12520         \r
12521         \r
12522         /**\r
12523     * Updates a rule property\r
12524     * @param {String/Array} selector If it's an array it tries each selector until it finds one. Stops immediately once one is found.\r
12525     * @param {String} property The css property\r
12526     * @param {String} value The new value for the property\r
12527     * @return {Boolean} true If a rule was found and updated\r
12528     */\r
12529    updateRule : function(selector, property, value){\r
12530                 if(!Ext.isArray(selector)){\r
12531                         var rule = this.getRule(selector);\r
12532                         if(rule){\r
12533                                 rule.style[property.replace(camelRe, camelFn)] = value;\r
12534                                 return true;\r
12535                         }\r
12536                 }else{\r
12537                         for(var i = 0; i < selector.length; i++){\r
12538                                 if(this.updateRule(selector[i], property, value)){\r
12539                                         return true;\r
12540                                 }\r
12541                         }\r
12542                 }\r
12543                 return false;\r
12544         }\r
12545    };   \r
12546 }();/**
12547  @class Ext.util.ClickRepeater
12548  @extends Ext.util.Observable
12549
12550  A wrapper class which can be applied to any element. Fires a "click" event while the
12551  mouse is pressed. The interval between firings may be specified in the config but
12552  defaults to 20 milliseconds.
12553
12554  Optionally, a CSS class may be applied to the element during the time it is pressed.
12555
12556  @cfg {Mixed} el The element to act as a button.
12557  @cfg {Number} delay The initial delay before the repeating event begins firing.
12558  Similar to an autorepeat key delay.
12559  @cfg {Number} interval The interval between firings of the "click" event. Default 20 ms.
12560  @cfg {String} pressClass A CSS class name to be applied to the element while pressed.
12561  @cfg {Boolean} accelerate True if autorepeating should start slowly and accelerate.
12562            "interval" and "delay" are ignored.
12563  @cfg {Boolean} preventDefault True to prevent the default click event
12564  @cfg {Boolean} stopDefault True to stop the default click event
12565
12566  @history
12567     2007-02-02 jvs Original code contributed by Nige "Animal" White
12568     2007-02-02 jvs Renamed to ClickRepeater
12569     2007-02-03 jvs Modifications for FF Mac and Safari
12570
12571  @constructor
12572  @param {Mixed} el The element to listen on
12573  @param {Object} config
12574  */
12575 Ext.util.ClickRepeater = function(el, config)
12576 {
12577     this.el = Ext.get(el);
12578     this.el.unselectable();
12579
12580     Ext.apply(this, config);
12581
12582     this.addEvents(
12583     /**
12584      * @event mousedown
12585      * Fires when the mouse button is depressed.
12586      * @param {Ext.util.ClickRepeater} this
12587      */
12588         "mousedown",
12589     /**
12590      * @event click
12591      * Fires on a specified interval during the time the element is pressed.
12592      * @param {Ext.util.ClickRepeater} this
12593      */
12594         "click",
12595     /**
12596      * @event mouseup
12597      * Fires when the mouse key is released.
12598      * @param {Ext.util.ClickRepeater} this
12599      */
12600         "mouseup"
12601     );
12602
12603     if(!this.disabled){
12604         this.disabled = true;
12605         this.enable();
12606     }
12607
12608     // allow inline handler
12609     if(this.handler){
12610         this.on("click", this.handler,  this.scope || this);
12611     }
12612
12613     Ext.util.ClickRepeater.superclass.constructor.call(this);
12614 };
12615
12616 Ext.extend(Ext.util.ClickRepeater, Ext.util.Observable, {
12617     interval : 20,
12618     delay: 250,
12619     preventDefault : true,
12620     stopDefault : false,
12621     timer : 0,
12622
12623     /**
12624      * Enables the repeater and allows events to fire.
12625      */
12626     enable: function(){
12627         if(this.disabled){
12628             this.el.on('mousedown', this.handleMouseDown, this);
12629             if(this.preventDefault || this.stopDefault){
12630                 this.el.on('click', this.eventOptions, this);
12631             }
12632         }
12633         this.disabled = false;
12634     },
12635     
12636     /**
12637      * Disables the repeater and stops events from firing.
12638      */
12639     disable: function(/* private */ force){
12640         if(force || !this.disabled){
12641             clearTimeout(this.timer);
12642             if(this.pressClass){
12643                 this.el.removeClass(this.pressClass);
12644             }
12645             Ext.getDoc().un('mouseup', this.handleMouseUp, this);
12646             this.el.removeAllListeners();
12647         }
12648         this.disabled = true;
12649     },
12650     
12651     /**
12652      * Convenience function for setting disabled/enabled by boolean.
12653      * @param {Boolean} disabled
12654      */
12655     setDisabled: function(disabled){
12656         this[disabled ? 'disable' : 'enable']();    
12657     },
12658     
12659     eventOptions: function(e){
12660         if(this.preventDefault){
12661             e.preventDefault();
12662         }
12663         if(this.stopDefault){
12664             e.stopEvent();
12665         }       
12666     },
12667     
12668     // private
12669     destroy : function() {
12670         this.disable(true);
12671         Ext.destroy(this.el);
12672         this.purgeListeners();
12673     },
12674     
12675     // private
12676     handleMouseDown : function(){
12677         clearTimeout(this.timer);
12678         this.el.blur();
12679         if(this.pressClass){
12680             this.el.addClass(this.pressClass);
12681         }
12682         this.mousedownTime = new Date();
12683
12684         Ext.getDoc().on("mouseup", this.handleMouseUp, this);
12685         this.el.on("mouseout", this.handleMouseOut, this);
12686
12687         this.fireEvent("mousedown", this);
12688         this.fireEvent("click", this);
12689
12690 //      Do not honor delay or interval if acceleration wanted.
12691         if (this.accelerate) {
12692             this.delay = 400;
12693             }
12694         this.timer = this.click.defer(this.delay || this.interval, this);
12695     },
12696
12697     // private
12698     click : function(){
12699         this.fireEvent("click", this);
12700         this.timer = this.click.defer(this.accelerate ?
12701             this.easeOutExpo(this.mousedownTime.getElapsed(),
12702                 400,
12703                 -390,
12704                 12000) :
12705             this.interval, this);
12706     },
12707
12708     easeOutExpo : function (t, b, c, d) {
12709         return (t==d) ? b+c : c * (-Math.pow(2, -10 * t/d) + 1) + b;
12710     },
12711
12712     // private
12713     handleMouseOut : function(){
12714         clearTimeout(this.timer);
12715         if(this.pressClass){
12716             this.el.removeClass(this.pressClass);
12717         }
12718         this.el.on("mouseover", this.handleMouseReturn, this);
12719     },
12720
12721     // private
12722     handleMouseReturn : function(){
12723         this.el.un("mouseover", this.handleMouseReturn, this);
12724         if(this.pressClass){
12725             this.el.addClass(this.pressClass);
12726         }
12727         this.click();
12728     },
12729
12730     // private
12731     handleMouseUp : function(){
12732         clearTimeout(this.timer);
12733         this.el.un("mouseover", this.handleMouseReturn, this);
12734         this.el.un("mouseout", this.handleMouseOut, this);
12735         Ext.getDoc().un("mouseup", this.handleMouseUp, this);
12736         this.el.removeClass(this.pressClass);
12737         this.fireEvent("mouseup", this);
12738     }
12739 });/**
12740  * @class Ext.KeyNav
12741  * <p>Provides a convenient wrapper for normalized keyboard navigation.  KeyNav allows you to bind
12742  * navigation keys to function calls that will get called when the keys are pressed, providing an easy
12743  * way to implement custom navigation schemes for any UI component.</p>
12744  * <p>The following are all of the possible keys that can be implemented: enter, left, right, up, down, tab, esc,
12745  * pageUp, pageDown, del, home, end.  Usage:</p>
12746  <pre><code>
12747 var nav = new Ext.KeyNav("my-element", {
12748     "left" : function(e){
12749         this.moveLeft(e.ctrlKey);
12750     },
12751     "right" : function(e){
12752         this.moveRight(e.ctrlKey);
12753     },
12754     "enter" : function(e){
12755         this.save();
12756     },
12757     scope : this
12758 });
12759 </code></pre>
12760  * @constructor
12761  * @param {Mixed} el The element to bind to
12762  * @param {Object} config The config
12763  */
12764 Ext.KeyNav = function(el, config){
12765     this.el = Ext.get(el);
12766     Ext.apply(this, config);
12767     if(!this.disabled){
12768         this.disabled = true;
12769         this.enable();
12770     }
12771 };
12772
12773 Ext.KeyNav.prototype = {
12774     /**
12775      * @cfg {Boolean} disabled
12776      * True to disable this KeyNav instance (defaults to false)
12777      */
12778     disabled : false,
12779     /**
12780      * @cfg {String} defaultEventAction
12781      * The method to call on the {@link Ext.EventObject} after this KeyNav intercepts a key.  Valid values are
12782      * {@link Ext.EventObject#stopEvent}, {@link Ext.EventObject#preventDefault} and
12783      * {@link Ext.EventObject#stopPropagation} (defaults to 'stopEvent')
12784      */
12785     defaultEventAction: "stopEvent",
12786     /**
12787      * @cfg {Boolean} forceKeyDown
12788      * Handle the keydown event instead of keypress (defaults to false).  KeyNav automatically does this for IE since
12789      * IE does not propagate special keys on keypress, but setting this to true will force other browsers to also
12790      * handle keydown instead of keypress.
12791      */
12792     forceKeyDown : false,
12793
12794     // private
12795     prepareEvent : function(e){
12796         var k = e.getKey();
12797         var h = this.keyToHandler[k];
12798         if(Ext.isSafari2 && h && k >= 37 && k <= 40){
12799             e.stopEvent();
12800         }
12801     },
12802
12803     // private
12804     relay : function(e){
12805         var k = e.getKey();
12806         var h = this.keyToHandler[k];
12807         if(h && this[h]){
12808             if(this.doRelay(e, this[h], h) !== true){
12809                 e[this.defaultEventAction]();
12810             }
12811         }
12812     },
12813
12814     // private
12815     doRelay : function(e, h, hname){
12816         return h.call(this.scope || this, e);
12817     },
12818
12819     // possible handlers
12820     enter : false,
12821     left : false,
12822     right : false,
12823     up : false,
12824     down : false,
12825     tab : false,
12826     esc : false,
12827     pageUp : false,
12828     pageDown : false,
12829     del : false,
12830     home : false,
12831     end : false,
12832
12833     // quick lookup hash
12834     keyToHandler : {
12835         37 : "left",
12836         39 : "right",
12837         38 : "up",
12838         40 : "down",
12839         33 : "pageUp",
12840         34 : "pageDown",
12841         46 : "del",
12842         36 : "home",
12843         35 : "end",
12844         13 : "enter",
12845         27 : "esc",
12846         9  : "tab"
12847     },
12848
12849         /**
12850          * Enable this KeyNav
12851          */
12852         enable: function(){
12853                 if(this.disabled){
12854             // ie won't do special keys on keypress, no one else will repeat keys with keydown
12855             // the EventObject will normalize Safari automatically
12856             if(this.isKeydown()){
12857                 this.el.on("keydown", this.relay,  this);
12858             }else{
12859                 this.el.on("keydown", this.prepareEvent,  this);
12860                 this.el.on("keypress", this.relay,  this);
12861             }
12862                     this.disabled = false;
12863                 }
12864         },
12865
12866         /**
12867          * Disable this KeyNav
12868          */
12869         disable: function(){
12870                 if(!this.disabled){
12871                     if(this.isKeydown()){
12872                 this.el.un("keydown", this.relay, this);
12873             }else{
12874                 this.el.un("keydown", this.prepareEvent, this);
12875                 this.el.un("keypress", this.relay, this);
12876             }
12877                     this.disabled = true;
12878                 }
12879         },
12880     
12881     /**
12882      * Convenience function for setting disabled/enabled by boolean.
12883      * @param {Boolean} disabled
12884      */
12885     setDisabled : function(disabled){
12886         this[disabled ? "disable" : "enable"]();
12887     },
12888     
12889     // private
12890     isKeydown: function(){
12891         return this.forceKeyDown || Ext.EventManager.useKeydown;
12892     }
12893 };
12894 /**\r
12895  * @class Ext.KeyMap\r
12896  * Handles mapping keys to actions for an element. One key map can be used for multiple actions.\r
12897  * The constructor accepts the same config object as defined by {@link #addBinding}.\r
12898  * If you bind a callback function to a KeyMap, anytime the KeyMap handles an expected key\r
12899  * combination it will call the function with this signature (if the match is a multi-key\r
12900  * combination the callback will still be called only once): (String key, Ext.EventObject e)\r
12901  * A KeyMap can also handle a string representation of keys.<br />\r
12902  * Usage:\r
12903  <pre><code>\r
12904 // map one key by key code\r
12905 var map = new Ext.KeyMap("my-element", {\r
12906     key: 13, // or Ext.EventObject.ENTER\r
12907     fn: myHandler,\r
12908     scope: myObject\r
12909 });\r
12910 \r
12911 // map multiple keys to one action by string\r
12912 var map = new Ext.KeyMap("my-element", {\r
12913     key: "a\r\n\t",\r
12914     fn: myHandler,\r
12915     scope: myObject\r
12916 });\r
12917 \r
12918 // map multiple keys to multiple actions by strings and array of codes\r
12919 var map = new Ext.KeyMap("my-element", [\r
12920     {\r
12921         key: [10,13],\r
12922         fn: function(){ alert("Return was pressed"); }\r
12923     }, {\r
12924         key: "abc",\r
12925         fn: function(){ alert('a, b or c was pressed'); }\r
12926     }, {\r
12927         key: "\t",\r
12928         ctrl:true,\r
12929         shift:true,\r
12930         fn: function(){ alert('Control + shift + tab was pressed.'); }\r
12931     }\r
12932 ]);\r
12933 </code></pre>\r
12934  * <b>Note: A KeyMap starts enabled</b>\r
12935  * @constructor\r
12936  * @param {Mixed} el The element to bind to\r
12937  * @param {Object} config The config (see {@link #addBinding})\r
12938  * @param {String} eventName (optional) The event to bind to (defaults to "keydown")\r
12939  */\r
12940 Ext.KeyMap = function(el, config, eventName){\r
12941     this.el  = Ext.get(el);\r
12942     this.eventName = eventName || "keydown";\r
12943     this.bindings = [];\r
12944     if(config){\r
12945         this.addBinding(config);\r
12946     }\r
12947     this.enable();\r
12948 };\r
12949 \r
12950 Ext.KeyMap.prototype = {\r
12951     /**\r
12952      * True to stop the event from bubbling and prevent the default browser action if the\r
12953      * key was handled by the KeyMap (defaults to false)\r
12954      * @type Boolean\r
12955      */\r
12956     stopEvent : false,\r
12957 \r
12958     /**\r
12959      * Add a new binding to this KeyMap. The following config object properties are supported:\r
12960      * <pre>\r
12961 Property    Type             Description\r
12962 ----------  ---------------  ----------------------------------------------------------------------\r
12963 key         String/Array     A single keycode or an array of keycodes to handle\r
12964 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)\r
12965 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)\r
12966 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)\r
12967 handler     Function         The function to call when KeyMap finds the expected key combination\r
12968 fn          Function         Alias of handler (for backwards-compatibility)\r
12969 scope       Object           The scope of the callback function\r
12970 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)\r
12971 </pre>\r
12972      *\r
12973      * Usage:\r
12974      * <pre><code>\r
12975 // Create a KeyMap\r
12976 var map = new Ext.KeyMap(document, {\r
12977     key: Ext.EventObject.ENTER,\r
12978     fn: handleKey,\r
12979     scope: this\r
12980 });\r
12981 \r
12982 //Add a new binding to the existing KeyMap later\r
12983 map.addBinding({\r
12984     key: 'abc',\r
12985     shift: true,\r
12986     fn: handleKey,\r
12987     scope: this\r
12988 });\r
12989 </code></pre>\r
12990      * @param {Object/Array} config A single KeyMap config or an array of configs\r
12991      */\r
12992         addBinding : function(config){\r
12993         if(Ext.isArray(config)){\r
12994             Ext.each(config, function(c){\r
12995                 this.addBinding(c);\r
12996             }, this);\r
12997             return;\r
12998         }\r
12999         var keyCode = config.key,\r
13000             fn = config.fn || config.handler,\r
13001             scope = config.scope;\r
13002 \r
13003         if (config.stopEvent) {\r
13004             this.stopEvent = config.stopEvent;    \r
13005         }       \r
13006 \r
13007         if(typeof keyCode == "string"){\r
13008             var ks = [];\r
13009             var keyString = keyCode.toUpperCase();\r
13010             for(var j = 0, len = keyString.length; j < len; j++){\r
13011                 ks.push(keyString.charCodeAt(j));\r
13012             }\r
13013             keyCode = ks;\r
13014         }\r
13015         var keyArray = Ext.isArray(keyCode);\r
13016         \r
13017         var handler = function(e){\r
13018             if(this.checkModifiers(config, e)){\r
13019                 var k = e.getKey();\r
13020                 if(keyArray){\r
13021                     for(var i = 0, len = keyCode.length; i < len; i++){\r
13022                         if(keyCode[i] == k){\r
13023                           if(this.stopEvent){\r
13024                               e.stopEvent();\r
13025                           }\r
13026                           fn.call(scope || window, k, e);\r
13027                           return;\r
13028                         }\r
13029                     }\r
13030                 }else{\r
13031                     if(k == keyCode){\r
13032                         if(this.stopEvent){\r
13033                            e.stopEvent();\r
13034                         }\r
13035                         fn.call(scope || window, k, e);\r
13036                     }\r
13037                 }\r
13038             }\r
13039         };\r
13040         this.bindings.push(handler);\r
13041         },\r
13042     \r
13043     // private\r
13044     checkModifiers: function(config, e){\r
13045         var val, key, keys = ['shift', 'ctrl', 'alt'];\r
13046         for (var i = 0, len = keys.length; i < len; ++i){\r
13047             key = keys[i];\r
13048             val = config[key];\r
13049             if(!(val === undefined || (val === e[key + 'Key']))){\r
13050                 return false;\r
13051             }\r
13052         }\r
13053         return true;\r
13054     },\r
13055 \r
13056     /**\r
13057      * Shorthand for adding a single key listener\r
13058      * @param {Number/Array/Object} key Either the numeric key code, array of key codes or an object with the\r
13059      * following options:\r
13060      * {key: (number or array), shift: (true/false), ctrl: (true/false), alt: (true/false)}\r
13061      * @param {Function} fn The function to call\r
13062      * @param {Object} scope (optional) The scope of the function\r
13063      */\r
13064     on : function(key, fn, scope){\r
13065         var keyCode, shift, ctrl, alt;\r
13066         if(typeof key == "object" && !Ext.isArray(key)){\r
13067             keyCode = key.key;\r
13068             shift = key.shift;\r
13069             ctrl = key.ctrl;\r
13070             alt = key.alt;\r
13071         }else{\r
13072             keyCode = key;\r
13073         }\r
13074         this.addBinding({\r
13075             key: keyCode,\r
13076             shift: shift,\r
13077             ctrl: ctrl,\r
13078             alt: alt,\r
13079             fn: fn,\r
13080             scope: scope\r
13081         });\r
13082     },\r
13083 \r
13084     // private\r
13085     handleKeyDown : function(e){\r
13086             if(this.enabled){ //just in case\r
13087             var b = this.bindings;\r
13088             for(var i = 0, len = b.length; i < len; i++){\r
13089                 b[i].call(this, e);\r
13090             }\r
13091             }\r
13092         },\r
13093 \r
13094         /**\r
13095          * Returns true if this KeyMap is enabled\r
13096          * @return {Boolean}\r
13097          */\r
13098         isEnabled : function(){\r
13099             return this.enabled;\r
13100         },\r
13101 \r
13102         /**\r
13103          * Enables this KeyMap\r
13104          */\r
13105         enable: function(){\r
13106                 if(!this.enabled){\r
13107                     this.el.on(this.eventName, this.handleKeyDown, this);\r
13108                     this.enabled = true;\r
13109                 }\r
13110         },\r
13111 \r
13112         /**\r
13113          * Disable this KeyMap\r
13114          */\r
13115         disable: function(){\r
13116                 if(this.enabled){\r
13117                     this.el.removeListener(this.eventName, this.handleKeyDown, this);\r
13118                     this.enabled = false;\r
13119                 }\r
13120         },\r
13121     \r
13122     /**\r
13123      * Convenience function for setting disabled/enabled by boolean.\r
13124      * @param {Boolean} disabled\r
13125      */\r
13126     setDisabled : function(disabled){\r
13127         this[disabled ? "disable" : "enable"]();\r
13128     }\r
13129 };/**
13130  * @class Ext.util.TextMetrics
13131  * Provides precise pixel measurements for blocks of text so that you can determine exactly how high and
13132  * wide, in pixels, a given block of text will be. Note that when measuring text, it should be plain text and
13133  * should not contain any HTML, otherwise it may not be measured correctly.
13134  * @singleton
13135  */
13136 Ext.util.TextMetrics = function(){
13137     var shared;
13138     return {
13139         /**
13140          * Measures the size of the specified text
13141          * @param {String/HTMLElement} el The element, dom node or id from which to copy existing CSS styles
13142          * that can affect the size of the rendered text
13143          * @param {String} text The text to measure
13144          * @param {Number} fixedWidth (optional) If the text will be multiline, you have to set a fixed width
13145          * in order to accurately measure the text height
13146          * @return {Object} An object containing the text's size {width: (width), height: (height)}
13147          */
13148         measure : function(el, text, fixedWidth){
13149             if(!shared){
13150                 shared = Ext.util.TextMetrics.Instance(el, fixedWidth);
13151             }
13152             shared.bind(el);
13153             shared.setFixedWidth(fixedWidth || 'auto');
13154             return shared.getSize(text);
13155         },
13156
13157         /**
13158          * Return a unique TextMetrics instance that can be bound directly to an element and reused.  This reduces
13159          * the overhead of multiple calls to initialize the style properties on each measurement.
13160          * @param {String/HTMLElement} el The element, dom node or id that the instance will be bound to
13161          * @param {Number} fixedWidth (optional) If the text will be multiline, you have to set a fixed width
13162          * in order to accurately measure the text height
13163          * @return {Ext.util.TextMetrics.Instance} instance The new instance
13164          */
13165         createInstance : function(el, fixedWidth){
13166             return Ext.util.TextMetrics.Instance(el, fixedWidth);
13167         }
13168     };
13169 }();
13170
13171 Ext.util.TextMetrics.Instance = function(bindTo, fixedWidth){
13172     var ml = new Ext.Element(document.createElement('div'));
13173     document.body.appendChild(ml.dom);
13174     ml.position('absolute');
13175     ml.setLeftTop(-1000, -1000);
13176     ml.hide();
13177
13178     if(fixedWidth){
13179         ml.setWidth(fixedWidth);
13180     }
13181
13182     var instance = {
13183         /**
13184          * Returns the size of the specified text based on the internal element's style and width properties
13185          * @param {String} text The text to measure
13186          * @return {Object} An object containing the text's size {width: (width), height: (height)}
13187          */
13188         getSize : function(text){
13189             ml.update(text);
13190             var s = ml.getSize();
13191             ml.update('');
13192             return s;
13193         },
13194
13195         /**
13196          * Binds this TextMetrics instance to an element from which to copy existing CSS styles
13197          * that can affect the size of the rendered text
13198          * @param {String/HTMLElement} el The element, dom node or id
13199          */
13200         bind : function(el){
13201             ml.setStyle(
13202                 Ext.fly(el).getStyles('font-size','font-style', 'font-weight', 'font-family','line-height', 'text-transform', 'letter-spacing')
13203             );
13204         },
13205
13206         /**
13207          * Sets a fixed width on the internal measurement element.  If the text will be multiline, you have
13208          * to set a fixed width in order to accurately measure the text height.
13209          * @param {Number} width The width to set on the element
13210          */
13211         setFixedWidth : function(width){
13212             ml.setWidth(width);
13213         },
13214
13215         /**
13216          * Returns the measured width of the specified text
13217          * @param {String} text The text to measure
13218          * @return {Number} width The width in pixels
13219          */
13220         getWidth : function(text){
13221             ml.dom.style.width = 'auto';
13222             return this.getSize(text).width;
13223         },
13224
13225         /**
13226          * Returns the measured height of the specified text.  For multiline text, be sure to call
13227          * {@link #setFixedWidth} if necessary.
13228          * @param {String} text The text to measure
13229          * @return {Number} height The height in pixels
13230          */
13231         getHeight : function(text){
13232             return this.getSize(text).height;
13233         }
13234     };
13235
13236     instance.bind(bindTo);
13237
13238     return instance;
13239 };
13240
13241 Ext.Element.addMethods({
13242     /**
13243      * Returns the width in pixels of the passed text, or the width of the text in this Element.
13244      * @param {String} text The text to measure. Defaults to the innerHTML of the element.
13245      * @param {Number} min (Optional) The minumum value to return.
13246      * @param {Number} max (Optional) The maximum value to return.
13247      * @return {Number} The text width in pixels.
13248      * @member Ext.Element getTextWidth
13249      */
13250     getTextWidth : function(text, min, max){
13251         return (Ext.util.TextMetrics.measure(this.dom, Ext.value(text, this.dom.innerHTML, true)).width).constrain(min || 0, max || 1000000);
13252     }
13253 });
13254 /**\r
13255  * @class Ext.util.Cookies\r
13256  * Utility class for managing and interacting with cookies.\r
13257  * @singleton\r
13258  */\r
13259 Ext.util.Cookies = {\r
13260     /**\r
13261      * Create a cookie with the specified name and value. Additional settings\r
13262      * for the cookie may be optionally specified (for example: expiration,\r
13263      * access restriction, SSL).\r
13264      * @param {Object} name\r
13265      * @param {Object} value\r
13266      * @param {Object} expires (Optional) Specify an expiration date the\r
13267      * cookie is to persist until.  Note that the specified Date object will\r
13268      * be converted to Greenwich Mean Time (GMT). \r
13269      * @param {String} path (Optional) Setting a path on the cookie restricts\r
13270      * access to pages that match that path. Defaults to all pages (<tt>'/'</tt>). \r
13271      * @param {String} domain (Optional) Setting a domain restricts access to\r
13272      * pages on a given domain (typically used to allow cookie access across\r
13273      * subdomains). For example, "extjs.com" will create a cookie that can be\r
13274      * accessed from any subdomain of extjs.com, including www.extjs.com,\r
13275      * support.extjs.com, etc.\r
13276      * @param {Boolean} secure (Optional) Specify true to indicate that the cookie\r
13277      * should only be accessible via SSL on a page using the HTTPS protocol.\r
13278      * Defaults to <tt>false</tt>. Note that this will only work if the page\r
13279      * calling this code uses the HTTPS protocol, otherwise the cookie will be\r
13280      * created with default options.\r
13281      */\r
13282     set : function(name, value){\r
13283         var argv = arguments;\r
13284         var argc = arguments.length;\r
13285         var expires = (argc > 2) ? argv[2] : null;\r
13286         var path = (argc > 3) ? argv[3] : '/';\r
13287         var domain = (argc > 4) ? argv[4] : null;\r
13288         var secure = (argc > 5) ? argv[5] : false;\r
13289         document.cookie = name + "=" + escape(value) + ((expires === null) ? "" : ("; expires=" + expires.toGMTString())) + ((path === null) ? "" : ("; path=" + path)) + ((domain === null) ? "" : ("; domain=" + domain)) + ((secure === true) ? "; secure" : "");\r
13290     },\r
13291 \r
13292     /**\r
13293      * Retrieves cookies that are accessible by the current page. If a cookie\r
13294      * does not exist, <code>get()</code> returns <tt>null</tt>.  The following\r
13295      * example retrieves the cookie called "valid" and stores the String value\r
13296      * in the variable <tt>validStatus</tt>.\r
13297      * <pre><code>\r
13298      * var validStatus = Ext.util.Cookies.get("valid");\r
13299      * </code></pre>\r
13300      * @param {Object} name The name of the cookie to get\r
13301      * @return {Mixed} Returns the cookie value for the specified name;\r
13302      * null if the cookie name does not exist.\r
13303      */\r
13304     get : function(name){\r
13305         var arg = name + "=";\r
13306         var alen = arg.length;\r
13307         var clen = document.cookie.length;\r
13308         var i = 0;\r
13309         var j = 0;\r
13310         while(i < clen){\r
13311             j = i + alen;\r
13312             if(document.cookie.substring(i, j) == arg){\r
13313                 return Ext.util.Cookies.getCookieVal(j);\r
13314             }\r
13315             i = document.cookie.indexOf(" ", i) + 1;\r
13316             if(i === 0){\r
13317                 break;\r
13318             }\r
13319         }\r
13320         return null;\r
13321     },\r
13322 \r
13323     /**\r
13324      * Removes a cookie with the provided name from the browser\r
13325      * if found.\r
13326      * @param {Object} name The name of the cookie to remove\r
13327      */\r
13328     clear : function(name){\r
13329         if(Ext.util.Cookies.get(name)){\r
13330             document.cookie = name + "=" + "; expires=Thu, 01-Jan-70 00:00:01 GMT";\r
13331         }\r
13332     },\r
13333     /**\r
13334      * @private\r
13335      */\r
13336     getCookieVal : function(offset){\r
13337         var endstr = document.cookie.indexOf(";", offset);\r
13338         if(endstr == -1){\r
13339             endstr = document.cookie.length;\r
13340         }\r
13341         return unescape(document.cookie.substring(offset, endstr));\r
13342     }\r
13343 };/**
13344  * Framework-wide error-handler.  Developers can override this method to provide
13345  * custom exception-handling.  Framework errors will often extend from the base
13346  * Ext.Error class.
13347  * @param {Object/Error} e The thrown exception object.
13348  */
13349 Ext.handleError = function(e) {
13350     throw e;
13351 };
13352
13353 /**
13354  * @class Ext.Error
13355  * @extends Error
13356  * <p>A base error class. Future implementations are intended to provide more
13357  * robust error handling throughout the framework (<b>in the debug build only</b>)
13358  * to check for common errors and problems. The messages issued by this class
13359  * will aid error checking. Error checks will be automatically removed in the
13360  * production build so that performance is not negatively impacted.</p>
13361  * <p>Some sample messages currently implemented:</p><pre>
13362 "DataProxy attempted to execute an API-action but found an undefined
13363 url / function. Please review your Proxy url/api-configuration."
13364  * </pre><pre>
13365 "Could not locate your "root" property in your server response.
13366 Please review your JsonReader config to ensure the config-property
13367 "root" matches the property your server-response.  See the JsonReader
13368 docs for additional assistance."
13369  * </pre>
13370  * <p>An example of the code used for generating error messages:</p><pre><code>
13371 try {
13372     generateError({
13373         foo: 'bar'
13374     });
13375 }
13376 catch (e) {
13377     console.error(e);
13378 }
13379 function generateError(data) {
13380     throw new Ext.Error('foo-error', data);
13381 }
13382  * </code></pre>
13383  * @param {String} message
13384  */
13385 Ext.Error = function(message) {
13386     // Try to read the message from Ext.Error.lang
13387     this.message = (this.lang[message]) ? this.lang[message] : message;
13388 }
13389 Ext.Error.prototype = new Error();
13390 Ext.apply(Ext.Error.prototype, {
13391     // protected.  Extensions place their error-strings here.
13392     lang: {},
13393
13394     name: 'Ext.Error',
13395     /**
13396      * getName
13397      * @return {String}
13398      */
13399     getName : function() {
13400         return this.name;
13401     },
13402     /**
13403      * getMessage
13404      * @return {String}
13405      */
13406     getMessage : function() {
13407         return this.message;
13408     },
13409     /**
13410      * toJson
13411      * @return {String}
13412      */
13413     toJson : function() {
13414         return Ext.encode(this);
13415     }
13416 });
13417