Upgrade to ExtJS 3.0.3 - Released 10/11/2009
[extjs.git] / pkgs / ext-foundation-debug.js
1 /*!
2  * Ext JS Library 3.0.3
3  * Copyright(c) 2006-2009 Ext JS, LLC
4  * licensing@extjs.com
5  * http://www.extjs.com/license
6  */
7 /**\r
8  * @class Ext.DomHelper\r
9  * <p>The DomHelper class provides a layer of abstraction from DOM and transparently supports creating\r
10  * elements via DOM or using HTML fragments. It also has the ability to create HTML fragment templates\r
11  * from your DOM building code.</p>\r
12  *\r
13  * <p><b><u>DomHelper element specification object</u></b></p>\r
14  * <p>A specification object is used when creating elements. Attributes of this object\r
15  * are assumed to be element attributes, except for 4 special attributes:\r
16  * <div class="mdetail-params"><ul>\r
17  * <li><b><tt>tag</tt></b> : <div class="sub-desc">The tag name of the element</div></li>\r
18  * <li><b><tt>children</tt></b> : or <tt>cn</tt><div class="sub-desc">An array of the\r
19  * same kind of element definition objects to be created and appended. These can be nested\r
20  * as deep as you want.</div></li>\r
21  * <li><b><tt>cls</tt></b> : <div class="sub-desc">The class attribute of the element.\r
22  * This will end up being either the "class" attribute on a HTML fragment or className\r
23  * for a DOM node, depending on whether DomHelper is using fragments or DOM.</div></li>\r
24  * <li><b><tt>html</tt></b> : <div class="sub-desc">The innerHTML for the element</div></li>\r
25  * </ul></div></p>\r
26  *\r
27  * <p><b><u>Insertion methods</u></b></p>\r
28  * <p>Commonly used insertion methods:\r
29  * <div class="mdetail-params"><ul>\r
30  * <li><b><tt>{@link #append}</tt></b> : <div class="sub-desc"></div></li>\r
31  * <li><b><tt>{@link #insertBefore}</tt></b> : <div class="sub-desc"></div></li>\r
32  * <li><b><tt>{@link #insertAfter}</tt></b> : <div class="sub-desc"></div></li>\r
33  * <li><b><tt>{@link #overwrite}</tt></b> : <div class="sub-desc"></div></li>\r
34  * <li><b><tt>{@link #createTemplate}</tt></b> : <div class="sub-desc"></div></li>\r
35  * <li><b><tt>{@link #insertHtml}</tt></b> : <div class="sub-desc"></div></li>\r
36  * </ul></div></p>\r
37  *\r
38  * <p><b><u>Example</u></b></p>\r
39  * <p>This is an example, where an unordered list with 3 children items is appended to an existing\r
40  * element with id <tt>'my-div'</tt>:<br>\r
41  <pre><code>\r
42 var dh = Ext.DomHelper; // create shorthand alias\r
43 // specification object\r
44 var spec = {\r
45     id: 'my-ul',\r
46     tag: 'ul',\r
47     cls: 'my-list',\r
48     // append children after creating\r
49     children: [     // may also specify 'cn' instead of 'children'\r
50         {tag: 'li', id: 'item0', html: 'List Item 0'},\r
51         {tag: 'li', id: 'item1', html: 'List Item 1'},\r
52         {tag: 'li', id: 'item2', html: 'List Item 2'}\r
53     ]\r
54 };\r
55 var list = dh.append(\r
56     'my-div', // the context element 'my-div' can either be the id or the actual node\r
57     spec      // the specification object\r
58 );\r
59  </code></pre></p>\r
60  * <p>Element creation specification parameters in this class may also be passed as an Array of\r
61  * specification objects. This can be used to insert multiple sibling nodes into an existing\r
62  * container very efficiently. For example, to add more list items to the example above:<pre><code>\r
63 dh.append('my-ul', [\r
64     {tag: 'li', id: 'item3', html: 'List Item 3'},\r
65     {tag: 'li', id: 'item4', html: 'List Item 4'}\r
66 ]);\r
67  * </code></pre></p>\r
68  *\r
69  * <p><b><u>Templating</u></b></p>\r
70  * <p>The real power is in the built-in templating. Instead of creating or appending any elements,\r
71  * <tt>{@link #createTemplate}</tt> returns a Template object which can be used over and over to\r
72  * insert new elements. Revisiting the example above, we could utilize templating this time:\r
73  * <pre><code>\r
74 // create the node\r
75 var list = dh.append('my-div', {tag: 'ul', cls: 'my-list'});\r
76 // get template\r
77 var tpl = dh.createTemplate({tag: 'li', id: 'item{0}', html: 'List Item {0}'});\r
78 \r
79 for(var i = 0; i < 5, i++){\r
80     tpl.append(list, [i]); // use template to append to the actual node\r
81 }\r
82  * </code></pre></p>\r
83  * <p>An example using a template:<pre><code>\r
84 var html = '<a id="{0}" href="{1}" class="nav">{2}</a>';\r
85 \r
86 var tpl = new Ext.DomHelper.createTemplate(html);\r
87 tpl.append('blog-roll', ['link1', 'http://www.jackslocum.com/', "Jack&#39;s Site"]);\r
88 tpl.append('blog-roll', ['link2', 'http://www.dustindiaz.com/', "Dustin&#39;s Site"]);\r
89  * </code></pre></p>\r
90  *\r
91  * <p>The same example using named parameters:<pre><code>\r
92 var html = '<a id="{id}" href="{url}" class="nav">{text}</a>';\r
93 \r
94 var tpl = new Ext.DomHelper.createTemplate(html);\r
95 tpl.append('blog-roll', {\r
96     id: 'link1',\r
97     url: 'http://www.jackslocum.com/',\r
98     text: "Jack&#39;s Site"\r
99 });\r
100 tpl.append('blog-roll', {\r
101     id: 'link2',\r
102     url: 'http://www.dustindiaz.com/',\r
103     text: "Dustin&#39;s Site"\r
104 });\r
105  * </code></pre></p>\r
106  *\r
107  * <p><b><u>Compiling Templates</u></b></p>\r
108  * <p>Templates are applied using regular expressions. The performance is great, but if\r
109  * you are adding a bunch of DOM elements using the same template, you can increase\r
110  * performance even further by {@link Ext.Template#compile "compiling"} the template.\r
111  * The way "{@link Ext.Template#compile compile()}" works is the template is parsed and\r
112  * broken up at the different variable points and a dynamic function is created and eval'ed.\r
113  * The generated function performs string concatenation of these parts and the passed\r
114  * variables instead of using regular expressions.\r
115  * <pre><code>\r
116 var html = '<a id="{id}" href="{url}" class="nav">{text}</a>';\r
117 \r
118 var tpl = new Ext.DomHelper.createTemplate(html);\r
119 tpl.compile();\r
120 \r
121 //... use template like normal\r
122  * </code></pre></p>\r
123  *\r
124  * <p><b><u>Performance Boost</u></b></p>\r
125  * <p>DomHelper will transparently create HTML fragments when it can. Using HTML fragments instead\r
126  * of DOM can significantly boost performance.</p>\r
127  * <p>Element creation specification parameters may also be strings. If {@link #useDom} is <tt>false</tt>,\r
128  * then the string is used as innerHTML. If {@link #useDom} is <tt>true</tt>, a string specification\r
129  * results in the creation of a text node. Usage:</p>\r
130  * <pre><code>\r
131 Ext.DomHelper.useDom = true; // force it to use DOM; reduces performance\r
132  * </code></pre>\r
133  * @singleton\r
134  */\r
135 Ext.DomHelper = function(){\r
136     var tempTableEl = null,\r
137         emptyTags = /^(?:br|frame|hr|img|input|link|meta|range|spacer|wbr|area|param|col)$/i,\r
138         tableRe = /^table|tbody|tr|td$/i,\r
139         pub,\r
140         // kill repeat to save bytes\r
141         afterbegin = 'afterbegin',\r
142         afterend = 'afterend',\r
143         beforebegin = 'beforebegin',\r
144         beforeend = 'beforeend',\r
145         ts = '<table>',\r
146         te = '</table>',\r
147         tbs = ts+'<tbody>',\r
148         tbe = '</tbody>'+te,\r
149         trs = tbs + '<tr>',\r
150         tre = '</tr>'+tbe;\r
151 \r
152     // private\r
153     function doInsert(el, o, returnElement, pos, sibling, append){\r
154         var newNode = pub.insertHtml(pos, Ext.getDom(el), createHtml(o));\r
155         return returnElement ? Ext.get(newNode, true) : newNode;\r
156     }\r
157 \r
158     // build as innerHTML where available\r
159     function createHtml(o){\r
160         var b = '',\r
161             attr,\r
162             val,\r
163             key,\r
164             keyVal,\r
165             cn;\r
166 \r
167         if(Ext.isString(o)){\r
168             b = o;\r
169         } else if (Ext.isArray(o)) {\r
170             Ext.each(o, function(v) {\r
171                 b += createHtml(v);\r
172             });\r
173         } else {\r
174             b += '<' + (o.tag = o.tag || 'div');\r
175             Ext.iterate(o, function(attr, val){\r
176                 if(!/tag|children|cn|html$/i.test(attr)){\r
177                     if (Ext.isObject(val)) {\r
178                         b += ' ' + attr + '="';\r
179                         Ext.iterate(val, function(key, keyVal){\r
180                             b += key + ':' + keyVal + ';';\r
181                         });\r
182                         b += '"';\r
183                     }else{\r
184                         b += ' ' + ({cls : 'class', htmlFor : 'for'}[attr] || attr) + '="' + val + '"';\r
185                     }\r
186                 }\r
187             });\r
188             // Now either just close the tag or try to add children and close the tag.\r
189             if (emptyTags.test(o.tag)) {\r
190                 b += '/>';\r
191             } else {\r
192                 b += '>';\r
193                 if ((cn = o.children || o.cn)) {\r
194                     b += createHtml(cn);\r
195                 } else if(o.html){\r
196                     b += o.html;\r
197                 }\r
198                 b += '</' + o.tag + '>';\r
199             }\r
200         }\r
201         return b;\r
202     }\r
203 \r
204     function ieTable(depth, s, h, e){\r
205         tempTableEl.innerHTML = [s, h, e].join('');\r
206         var i = -1,\r
207             el = tempTableEl,\r
208             ns;\r
209         while(++i < depth){\r
210             el = el.firstChild;\r
211         }\r
212 //      If the result is multiple siblings, then encapsulate them into one fragment.\r
213         if(ns = el.nextSibling){\r
214             var df = document.createDocumentFragment();\r
215             while(el){\r
216                 ns = el.nextSibling;\r
217                 df.appendChild(el);\r
218                 el = ns;\r
219             }\r
220             el = df;\r
221         }\r
222         return el;\r
223     }\r
224 \r
225     /**\r
226      * @ignore\r
227      * Nasty code for IE's broken table implementation\r
228      */\r
229     function insertIntoTable(tag, where, el, html) {\r
230         var node,\r
231             before;\r
232 \r
233         tempTableEl = tempTableEl || document.createElement('div');\r
234 \r
235         if(tag == 'td' && (where == afterbegin || where == beforeend) ||\r
236            !/td|tr|tbody/i.test(tag) && (where == beforebegin || where == afterend)) {\r
237             return;\r
238         }\r
239         before = where == beforebegin ? el :\r
240                  where == afterend ? el.nextSibling :\r
241                  where == afterbegin ? el.firstChild : null;\r
242 \r
243         if (where == beforebegin || where == afterend) {\r
244             el = el.parentNode;\r
245         }\r
246 \r
247         if (tag == 'td' || (tag == 'tr' && (where == beforeend || where == afterbegin))) {\r
248             node = ieTable(4, trs, html, tre);\r
249         } else if ((tag == 'tbody' && (where == beforeend || where == afterbegin)) ||\r
250                    (tag == 'tr' && (where == beforebegin || where == afterend))) {\r
251             node = ieTable(3, tbs, html, tbe);\r
252         } else {\r
253             node = ieTable(2, ts, html, te);\r
254         }\r
255         el.insertBefore(node, before);\r
256         return node;\r
257     }\r
258 \r
259 \r
260     pub = {\r
261         /**\r
262          * Returns the markup for the passed Element(s) config.\r
263          * @param {Object} o The DOM object spec (and children)\r
264          * @return {String}\r
265          */\r
266         markup : function(o){\r
267             return createHtml(o);\r
268         },\r
269         \r
270         /**\r
271          * Applies a style specification to an element.\r
272          * @param {String/HTMLElement} el The element to apply styles to\r
273          * @param {String/Object/Function} styles A style specification string e.g. 'width:100px', or object in the form {width:'100px'}, or\r
274          * a function which returns such a specification.\r
275          */\r
276         applyStyles : function(el, styles){\r
277             if(styles){\r
278                 var i = 0,\r
279                     len,\r
280                     style;\r
281 \r
282                 el = Ext.fly(el);\r
283                 if(Ext.isFunction(styles)){\r
284                     styles = styles.call();\r
285                 }\r
286                 if(Ext.isString(styles)){\r
287                     styles = styles.trim().split(/\s*(?::|;)\s*/);\r
288                     for(len = styles.length; i < len;){\r
289                         el.setStyle(styles[i++], styles[i++]);\r
290                     }\r
291                 }else if (Ext.isObject(styles)){\r
292                     el.setStyle(styles);\r
293                 }\r
294             }\r
295         },\r
296 \r
297         /**\r
298          * Inserts an HTML fragment into the DOM.\r
299          * @param {String} where Where to insert the html in relation to el - beforeBegin, afterBegin, beforeEnd, afterEnd.\r
300          * @param {HTMLElement} el The context element\r
301          * @param {String} html The HTML fragment\r
302          * @return {HTMLElement} The new node\r
303          */\r
304         insertHtml : function(where, el, html){\r
305             var hash = {},\r
306                 hashVal,\r
307                 setStart,\r
308                 range,\r
309                 frag,\r
310                 rangeEl,\r
311                 rs;\r
312 \r
313             where = where.toLowerCase();\r
314             // add these here because they are used in both branches of the condition.\r
315             hash[beforebegin] = ['BeforeBegin', 'previousSibling'];\r
316             hash[afterend] = ['AfterEnd', 'nextSibling'];\r
317 \r
318             if (el.insertAdjacentHTML) {\r
319                 if(tableRe.test(el.tagName) && (rs = insertIntoTable(el.tagName.toLowerCase(), where, el, html))){\r
320                     return rs;\r
321                 }\r
322                 // add these two to the hash.\r
323                 hash[afterbegin] = ['AfterBegin', 'firstChild'];\r
324                 hash[beforeend] = ['BeforeEnd', 'lastChild'];\r
325                 if ((hashVal = hash[where])) {\r
326                     el.insertAdjacentHTML(hashVal[0], html);\r
327                     return el[hashVal[1]];\r
328                 }\r
329             } else {\r
330                 range = el.ownerDocument.createRange();\r
331                 setStart = 'setStart' + (/end/i.test(where) ? 'After' : 'Before');\r
332                 if (hash[where]) {\r
333                     range[setStart](el);\r
334                     frag = range.createContextualFragment(html);\r
335                     el.parentNode.insertBefore(frag, where == beforebegin ? el : el.nextSibling);\r
336                     return el[(where == beforebegin ? 'previous' : 'next') + 'Sibling'];\r
337                 } else {\r
338                     rangeEl = (where == afterbegin ? 'first' : 'last') + 'Child';\r
339                     if (el.firstChild) {\r
340                         range[setStart](el[rangeEl]);\r
341                         frag = range.createContextualFragment(html);\r
342                         if(where == afterbegin){\r
343                             el.insertBefore(frag, el.firstChild);\r
344                         }else{\r
345                             el.appendChild(frag);\r
346                         }\r
347                     } else {\r
348                         el.innerHTML = html;\r
349                     }\r
350                     return el[rangeEl];\r
351                 }\r
352             }\r
353             throw 'Illegal insertion point -> "' + where + '"';\r
354         },\r
355 \r
356         /**\r
357          * Creates new DOM element(s) and inserts them before el.\r
358          * @param {Mixed} el The context element\r
359          * @param {Object/String} o The DOM object spec (and children) or raw HTML blob\r
360          * @param {Boolean} returnElement (optional) true to return a Ext.Element\r
361          * @return {HTMLElement/Ext.Element} The new node\r
362          */\r
363         insertBefore : function(el, o, returnElement){\r
364             return doInsert(el, o, returnElement, beforebegin);\r
365         },\r
366 \r
367         /**\r
368          * Creates new DOM element(s) and inserts them after el.\r
369          * @param {Mixed} el The context element\r
370          * @param {Object} o The DOM object spec (and children)\r
371          * @param {Boolean} returnElement (optional) true to return a Ext.Element\r
372          * @return {HTMLElement/Ext.Element} The new node\r
373          */\r
374         insertAfter : function(el, o, returnElement){\r
375             return doInsert(el, o, returnElement, afterend, 'nextSibling');\r
376         },\r
377 \r
378         /**\r
379          * Creates new DOM element(s) and inserts them as the first child of el.\r
380          * @param {Mixed} el The context element\r
381          * @param {Object/String} o The DOM object spec (and children) or raw HTML blob\r
382          * @param {Boolean} returnElement (optional) true to return a Ext.Element\r
383          * @return {HTMLElement/Ext.Element} The new node\r
384          */\r
385         insertFirst : function(el, o, returnElement){\r
386             return doInsert(el, o, returnElement, afterbegin, 'firstChild');\r
387         },\r
388 \r
389         /**\r
390          * Creates new DOM element(s) and appends them to el.\r
391          * @param {Mixed} el The context element\r
392          * @param {Object/String} o The DOM object spec (and children) or raw HTML blob\r
393          * @param {Boolean} returnElement (optional) true to return a Ext.Element\r
394          * @return {HTMLElement/Ext.Element} The new node\r
395          */\r
396         append : function(el, o, returnElement){\r
397             return doInsert(el, o, returnElement, beforeend, '', true);\r
398         },\r
399 \r
400         /**\r
401          * Creates new DOM element(s) and overwrites the contents of el with them.\r
402          * @param {Mixed} el The context element\r
403          * @param {Object/String} o The DOM object spec (and children) or raw HTML blob\r
404          * @param {Boolean} returnElement (optional) true to return a Ext.Element\r
405          * @return {HTMLElement/Ext.Element} The new node\r
406          */\r
407         overwrite : function(el, o, returnElement){\r
408             el = Ext.getDom(el);\r
409             el.innerHTML = createHtml(o);\r
410             return returnElement ? Ext.get(el.firstChild) : el.firstChild;\r
411         },\r
412 \r
413         createHtml : createHtml\r
414     };\r
415     return pub;\r
416 }();/**\r
417  * @class Ext.DomHelper\r
418  */\r
419 Ext.apply(Ext.DomHelper,\r
420 function(){\r
421         var pub,\r
422                 afterbegin = 'afterbegin',\r
423         afterend = 'afterend',\r
424         beforebegin = 'beforebegin',\r
425         beforeend = 'beforeend';\r
426 \r
427         // private\r
428     function doInsert(el, o, returnElement, pos, sibling, append){\r
429         el = Ext.getDom(el);\r
430         var newNode;\r
431         if (pub.useDom) {\r
432             newNode = createDom(o, null);\r
433             if (append) {\r
434                     el.appendChild(newNode);\r
435             } else {\r
436                         (sibling == 'firstChild' ? el : el.parentNode).insertBefore(newNode, el[sibling] || el);\r
437             }\r
438         } else {\r
439             newNode = Ext.DomHelper.insertHtml(pos, el, Ext.DomHelper.createHtml(o));\r
440         }\r
441         return returnElement ? Ext.get(newNode, true) : newNode;\r
442     }\r
443 \r
444         // build as dom\r
445     /** @ignore */\r
446     function createDom(o, parentNode){\r
447         var el,\r
448                 doc = document,\r
449                 useSet,\r
450                 attr,\r
451                 val,\r
452                 cn;\r
453 \r
454         if (Ext.isArray(o)) {                       // Allow Arrays of siblings to be inserted\r
455             el = doc.createDocumentFragment(); // in one shot using a DocumentFragment\r
456                 Ext.each(o, function(v) {\r
457                 createDom(v, el);\r
458             });\r
459         } else if (Ext.isString(o)) {         // Allow a string as a child spec.\r
460             el = doc.createTextNode(o);\r
461         } else {\r
462             el = doc.createElement( o.tag || 'div' );\r
463             useSet = !!el.setAttribute; // In IE some elements don't have setAttribute\r
464             Ext.iterate(o, function(attr, val){\r
465                 if(!/tag|children|cn|html|style/.test(attr)){\r
466                         if(attr == 'cls'){\r
467                             el.className = val;\r
468                         }else{\r
469                         if(useSet){\r
470                             el.setAttribute(attr, val);\r
471                         }else{\r
472                             el[attr] = val;\r
473                         }\r
474                         }\r
475                 }\r
476             });\r
477             Ext.DomHelper.applyStyles(el, o.style);\r
478 \r
479             if ((cn = o.children || o.cn)) {\r
480                 createDom(cn, el);\r
481             } else if (o.html) {\r
482                 el.innerHTML = o.html;\r
483             }\r
484         }\r
485         if(parentNode){\r
486            parentNode.appendChild(el);\r
487         }\r
488         return el;\r
489     }\r
490 \r
491         pub = {\r
492                 /**\r
493              * Creates a new Ext.Template from the DOM object spec.\r
494              * @param {Object} o The DOM object spec (and children)\r
495              * @return {Ext.Template} The new template\r
496              */\r
497             createTemplate : function(o){\r
498                 var html = Ext.DomHelper.createHtml(o);\r
499                 return new Ext.Template(html);\r
500             },\r
501 \r
502                 /** True to force the use of DOM instead of html fragments @type Boolean */\r
503             useDom : false,\r
504 \r
505             /**\r
506              * Creates new DOM element(s) and inserts them before el.\r
507              * @param {Mixed} el The context element\r
508              * @param {Object/String} o The DOM object spec (and children) or raw HTML blob\r
509              * @param {Boolean} returnElement (optional) true to return a Ext.Element\r
510              * @return {HTMLElement/Ext.Element} The new node\r
511          * @hide (repeat)\r
512              */\r
513             insertBefore : function(el, o, returnElement){\r
514                 return doInsert(el, o, returnElement, beforebegin);\r
515             },\r
516 \r
517             /**\r
518              * Creates new DOM element(s) and inserts them after el.\r
519              * @param {Mixed} el The context element\r
520              * @param {Object} o The DOM object spec (and children)\r
521              * @param {Boolean} returnElement (optional) true to return a Ext.Element\r
522              * @return {HTMLElement/Ext.Element} The new node\r
523          * @hide (repeat)\r
524              */\r
525             insertAfter : function(el, o, returnElement){\r
526                 return doInsert(el, o, returnElement, afterend, 'nextSibling');\r
527             },\r
528 \r
529             /**\r
530              * Creates new DOM element(s) and inserts them as the first child of el.\r
531              * @param {Mixed} el The context element\r
532              * @param {Object/String} o The DOM object spec (and children) or raw HTML blob\r
533              * @param {Boolean} returnElement (optional) true to return a Ext.Element\r
534              * @return {HTMLElement/Ext.Element} The new node\r
535          * @hide (repeat)\r
536              */\r
537             insertFirst : function(el, o, returnElement){\r
538                 return doInsert(el, o, returnElement, afterbegin, 'firstChild');\r
539             },\r
540 \r
541             /**\r
542              * Creates new DOM element(s) and appends them to el.\r
543              * @param {Mixed} el The context element\r
544              * @param {Object/String} o The DOM object spec (and children) or raw HTML blob\r
545              * @param {Boolean} returnElement (optional) true to return a Ext.Element\r
546              * @return {HTMLElement/Ext.Element} The new node\r
547          * @hide (repeat)\r
548              */\r
549             append: function(el, o, returnElement){\r
550             return doInsert(el, o, returnElement, beforeend, '', true);\r
551         },\r
552 \r
553             /**\r
554              * Creates new DOM element(s) without inserting them to the document.\r
555              * @param {Object/String} o The DOM object spec (and children) or raw HTML blob\r
556              * @return {HTMLElement} The new uninserted node\r
557              */\r
558         createDom: createDom\r
559         };\r
560         return pub;\r
561 }());/**
562  * @class Ext.Template
563  * <p>Represents an HTML fragment template. Templates may be {@link #compile precompiled}
564  * for greater performance.</p>
565  * <p>For example usage {@link #Template see the constructor}.</p>
566  * 
567  * @constructor
568  * An instance of this class may be created by passing to the constructor either
569  * a single argument, or multiple arguments:
570  * <div class="mdetail-params"><ul>
571  * <li><b>single argument</b> : String/Array
572  * <div class="sub-desc">
573  * The single argument may be either a String or an Array:<ul>
574  * <li><tt>String</tt> : </li><pre><code>
575 var t = new Ext.Template("&lt;div>Hello {0}.&lt;/div>");
576 t.{@link #append}('some-element', ['foo']);
577  * </code></pre>
578  * <li><tt>Array</tt> : </li>
579  * An Array will be combined with <code>join('')</code>.
580 <pre><code>
581 var t = new Ext.Template([
582     '&lt;div name="{id}"&gt;',
583         '&lt;span class="{cls}"&gt;{name:trim} {value:ellipsis(10)}&lt;/span&gt;',
584     '&lt;/div&gt;',
585 ]);
586 t.{@link #compile}();
587 t.{@link #append}('some-element', {id: 'myid', cls: 'myclass', name: 'foo', value: 'bar'});
588 </code></pre>
589  * </ul></div></li>
590  * <li><b>multiple arguments</b> : String, Object, Array, ...
591  * <div class="sub-desc">
592  * Multiple arguments will be combined with <code>join('')</code>.
593  * <pre><code>
594 var t = new Ext.Template(
595     '&lt;div name="{id}"&gt;',
596         '&lt;span class="{cls}"&gt;{name} {value}&lt;/span&gt;',
597     '&lt;/div&gt;',
598     // a configuration object:
599     {
600         compiled: true,      // {@link #compile} immediately
601         disableFormats: true // See Notes below.
602     } 
603 );
604  * </code></pre>
605  * <p><b>Notes</b>:</p>
606  * <div class="mdetail-params"><ul>
607  * <li>Formatting and <code>disableFormats</code> are not applicable for Ext Core.</li>
608  * <li>For a list of available format functions, see {@link Ext.util.Format}.</li>
609  * <li><code>disableFormats</code> reduces <code>{@link #apply}</code> time
610  * when no formatting is required.</li>
611  * </ul></div>
612  * </div></li>
613  * </ul></div>
614  * @param {Mixed} config
615  */
616 Ext.Template = function(html){
617     var me = this,
618         a = arguments,
619         buf = [];
620
621     if (Ext.isArray(html)) {
622         html = html.join("");
623     } else if (a.length > 1) {
624             Ext.each(a, function(v) {
625             if (Ext.isObject(v)) {
626                 Ext.apply(me, v);
627             } else {
628                 buf.push(v);
629             }
630         });
631         html = buf.join('');
632     }
633
634     /**@private*/
635     me.html = html;
636     /**
637      * @cfg {Boolean} compiled Specify <tt>true</tt> to compile the template
638      * immediately (see <code>{@link #compile}</code>).
639      * Defaults to <tt>false</tt>.
640      */
641     if (me.compiled) {
642         me.compile();
643     }
644 };
645 Ext.Template.prototype = {
646     /**
647      * @cfg {RegExp} re The regular expression used to match template variables.
648      * Defaults to:<pre><code>
649      * re : /\{([\w-]+)\}/g                                     // for Ext Core
650      * re : /\{([\w-]+)(?:\:([\w\.]*)(?:\((.*?)?\))?)?\}/g      // for Ext JS
651      * </code></pre>
652      */
653     re : /\{([\w-]+)\}/g,
654     /**
655      * See <code>{@link #re}</code>.
656      * @type RegExp
657      * @property re
658      */
659
660     /**
661      * Returns an HTML fragment of this template with the specified <code>values</code> applied.
662      * @param {Object/Array} values
663      * The template values. Can be an array if the params are numeric (i.e. <code>{0}</code>)
664      * or an object (i.e. <code>{foo: 'bar'}</code>).
665      * @return {String} The HTML fragment
666      */
667     applyTemplate : function(values){
668                 var me = this;
669
670         return me.compiled ?
671                         me.compiled(values) :
672                                 me.html.replace(me.re, function(m, name){
673                                 return values[name] !== undefined ? values[name] : "";
674                         });
675         },
676
677     /**
678      * Sets the HTML used as the template and optionally compiles it.
679      * @param {String} html
680      * @param {Boolean} compile (optional) True to compile the template (defaults to undefined)
681      * @return {Ext.Template} this
682      */
683     set : function(html, compile){
684             var me = this;
685         me.html = html;
686         me.compiled = null;
687         return compile ? me.compile() : me;
688     },
689
690     /**
691      * Compiles the template into an internal function, eliminating the RegEx overhead.
692      * @return {Ext.Template} this
693      */
694     compile : function(){
695         var me = this,
696                 sep = Ext.isGecko ? "+" : ",";
697
698         function fn(m, name){                        
699                 name = "values['" + name + "']";
700                 return "'"+ sep + '(' + name + " == undefined ? '' : " + name + ')' + sep + "'";
701         }
702                 
703         eval("this.compiled = function(values){ return " + (Ext.isGecko ? "'" : "['") +
704              me.html.replace(/\\/g, '\\\\').replace(/(\r\n|\n)/g, '\\n').replace(/'/g, "\\'").replace(this.re, fn) +
705              (Ext.isGecko ?  "';};" : "'].join('');};"));
706         return me;
707     },
708
709     /**
710      * Applies the supplied values to the template and inserts the new node(s) as the first child of el.
711      * @param {Mixed} el The context element
712      * @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'})
713      * @param {Boolean} returnElement (optional) true to return a Ext.Element (defaults to undefined)
714      * @return {HTMLElement/Ext.Element} The new node or Element
715      */
716     insertFirst: function(el, values, returnElement){
717         return this.doInsert('afterBegin', el, values, returnElement);
718     },
719
720     /**
721      * Applies the supplied values to the template and inserts the new node(s) before el.
722      * @param {Mixed} el The context element
723      * @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'})
724      * @param {Boolean} returnElement (optional) true to return a Ext.Element (defaults to undefined)
725      * @return {HTMLElement/Ext.Element} The new node or Element
726      */
727     insertBefore: function(el, values, returnElement){
728         return this.doInsert('beforeBegin', el, values, returnElement);
729     },
730
731     /**
732      * Applies the supplied values to the template and inserts the new node(s) after el.
733      * @param {Mixed} el The context element
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'})
735      * @param {Boolean} returnElement (optional) true to return a Ext.Element (defaults to undefined)
736      * @return {HTMLElement/Ext.Element} The new node or Element
737      */
738     insertAfter : function(el, values, returnElement){
739         return this.doInsert('afterEnd', el, values, returnElement);
740     },
741
742     /**
743      * Applies the supplied <code>values</code> to the template and appends
744      * the new node(s) to the specified <code>el</code>.
745      * <p>For example usage {@link #Template see the constructor}.</p>
746      * @param {Mixed} el The context element
747      * @param {Object/Array} values
748      * The template values. Can be an array if the params are numeric (i.e. <code>{0}</code>)
749      * or an object (i.e. <code>{foo: 'bar'}</code>).
750      * @param {Boolean} returnElement (optional) true to return an Ext.Element (defaults to undefined)
751      * @return {HTMLElement/Ext.Element} The new node or Element
752      */
753     append : function(el, values, returnElement){
754         return this.doInsert('beforeEnd', el, values, returnElement);
755     },
756
757     doInsert : function(where, el, values, returnEl){
758         el = Ext.getDom(el);
759         var newNode = Ext.DomHelper.insertHtml(where, el, this.applyTemplate(values));
760         return returnEl ? Ext.get(newNode, true) : newNode;
761     },
762
763     /**
764      * Applies the supplied values to the template and overwrites the content of el with the new node(s).
765      * @param {Mixed} el The context element
766      * @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'})
767      * @param {Boolean} returnElement (optional) true to return a Ext.Element (defaults to undefined)
768      * @return {HTMLElement/Ext.Element} The new node or Element
769      */
770     overwrite : function(el, values, returnElement){
771         el = Ext.getDom(el);
772         el.innerHTML = this.applyTemplate(values);
773         return returnElement ? Ext.get(el.firstChild, true) : el.firstChild;
774     }
775 };
776 /**
777  * Alias for {@link #applyTemplate}
778  * Returns an HTML fragment of this template with the specified <code>values</code> applied.
779  * @param {Object/Array} values
780  * The template values. Can be an array if the params are numeric (i.e. <code>{0}</code>)
781  * or an object (i.e. <code>{foo: 'bar'}</code>).
782  * @return {String} The HTML fragment
783  * @member Ext.Template
784  * @method apply
785  */
786 Ext.Template.prototype.apply = Ext.Template.prototype.applyTemplate;
787
788 /**
789  * Creates a template from the passed element's value (<i>display:none</i> textarea, preferred) or innerHTML.
790  * @param {String/HTMLElement} el A DOM element or its id
791  * @param {Object} config A configuration object
792  * @return {Ext.Template} The created template
793  * @static
794  */
795 Ext.Template.from = function(el, config){
796     el = Ext.getDom(el);
797     return new Ext.Template(el.value || el.innerHTML, config || '');
798 };/**\r
799  * @class Ext.Template\r
800  */\r
801 Ext.apply(Ext.Template.prototype, {\r
802     /**\r
803      * @cfg {Boolean} disableFormats Specify <tt>true</tt> to disable format\r
804      * functions in the template. If the template does not contain\r
805      * {@link Ext.util.Format format functions}, setting <code>disableFormats</code>\r
806      * to true will reduce <code>{@link #apply}</code> time. Defaults to <tt>false</tt>.\r
807      * <pre><code>\r
808 var t = new Ext.Template(\r
809     '&lt;div name="{id}"&gt;',\r
810         '&lt;span class="{cls}"&gt;{name} {value}&lt;/span&gt;',\r
811     '&lt;/div&gt;',\r
812     {\r
813         compiled: true,      // {@link #compile} immediately\r
814         disableFormats: true // reduce <code>{@link #apply}</code> time since no formatting\r
815     }    \r
816 );\r
817      * </code></pre>\r
818      * For a list of available format functions, see {@link Ext.util.Format}.\r
819      */\r
820     disableFormats : false,                             \r
821     /**\r
822      * See <code>{@link #disableFormats}</code>.\r
823      * @type Boolean\r
824      * @property disableFormats\r
825      */\r
826 \r
827     /**\r
828      * The regular expression used to match template variables\r
829      * @type RegExp\r
830      * @property\r
831      * @hide repeat doc\r
832      */\r
833     re : /\{([\w-]+)(?:\:([\w\.]*)(?:\((.*?)?\))?)?\}/g,\r
834 \r
835     /**\r
836      * Returns an HTML fragment of this template with the specified values applied.\r
837      * @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
838      * @return {String} The HTML fragment\r
839      * @hide repeat doc\r
840      */\r
841     applyTemplate : function(values){\r
842                 var me = this,\r
843                         useF = me.disableFormats !== true,\r
844                 fm = Ext.util.Format, \r
845                 tpl = me;           \r
846             \r
847         if(me.compiled){\r
848             return me.compiled(values);\r
849         }\r
850         function fn(m, name, format, args){\r
851             if (format && useF) {\r
852                 if (format.substr(0, 5) == "this.") {\r
853                     return tpl.call(format.substr(5), values[name], values);\r
854                 } else {\r
855                     if (args) {\r
856                         // quoted values are required for strings in compiled templates,\r
857                         // but for non compiled we need to strip them\r
858                         // quoted reversed for jsmin\r
859                         var re = /^\s*['"](.*)["']\s*$/;\r
860                         args = args.split(',');\r
861                         for(var i = 0, len = args.length; i < len; i++){\r
862                             args[i] = args[i].replace(re, "$1");\r
863                         }\r
864                         args = [values[name]].concat(args);\r
865                     } else {\r
866                         args = [values[name]];\r
867                     }\r
868                     return fm[format].apply(fm, args);\r
869                 }\r
870             } else {\r
871                 return values[name] !== undefined ? values[name] : "";\r
872             }\r
873         }\r
874         return me.html.replace(me.re, fn);\r
875     },\r
876                 \r
877     /**\r
878      * Compiles the template into an internal function, eliminating the RegEx overhead.\r
879      * @return {Ext.Template} this\r
880      * @hide repeat doc\r
881      */\r
882     compile : function(){\r
883         var me = this,\r
884                 fm = Ext.util.Format,\r
885                 useF = me.disableFormats !== true,\r
886                 sep = Ext.isGecko ? "+" : ",",\r
887                 body;\r
888         \r
889         function fn(m, name, format, args){\r
890             if(format && useF){\r
891                 args = args ? ',' + args : "";\r
892                 if(format.substr(0, 5) != "this."){\r
893                     format = "fm." + format + '(';\r
894                 }else{\r
895                     format = 'this.call("'+ format.substr(5) + '", ';\r
896                     args = ", values";\r
897                 }\r
898             }else{\r
899                 args= ''; format = "(values['" + name + "'] == undefined ? '' : ";\r
900             }\r
901             return "'"+ sep + format + "values['" + name + "']" + args + ")"+sep+"'";\r
902         }\r
903         \r
904         // branched to use + in gecko and [].join() in others\r
905         if(Ext.isGecko){\r
906             body = "this.compiled = function(values){ return '" +\r
907                    me.html.replace(/\\/g, '\\\\').replace(/(\r\n|\n)/g, '\\n').replace(/'/g, "\\'").replace(this.re, fn) +\r
908                     "';};";\r
909         }else{\r
910             body = ["this.compiled = function(values){ return ['"];\r
911             body.push(me.html.replace(/\\/g, '\\\\').replace(/(\r\n|\n)/g, '\\n').replace(/'/g, "\\'").replace(this.re, fn));\r
912             body.push("'].join('');};");\r
913             body = body.join('');\r
914         }\r
915         eval(body);\r
916         return me;\r
917     },\r
918     \r
919     // private function used to call members\r
920     call : function(fnName, value, allValues){\r
921         return this[fnName](value, allValues);\r
922     }\r
923 });\r
924 Ext.Template.prototype.apply = Ext.Template.prototype.applyTemplate; /*\r
925  * This is code is also distributed under MIT license for use\r
926  * with jQuery and prototype JavaScript libraries.\r
927  */\r
928 /**\r
929  * @class Ext.DomQuery\r
930 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
931 <p>\r
932 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
933 \r
934 <p>\r
935 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
936 </p>\r
937 <h4>Element Selectors:</h4>\r
938 <ul class="list">\r
939     <li> <b>*</b> any element</li>\r
940     <li> <b>E</b> an element with the tag E</li>\r
941     <li> <b>E F</b> All descendent elements of E that have the tag F</li>\r
942     <li> <b>E > F</b> or <b>E/F</b> all direct children elements of E that have the tag F</li>\r
943     <li> <b>E + F</b> all elements with the tag F that are immediately preceded by an element with the tag E</li>\r
944     <li> <b>E ~ F</b> all elements with the tag F that are preceded by a sibling element with the tag E</li>\r
945 </ul>\r
946 <h4>Attribute Selectors:</h4>\r
947 <p>The use of &#64; and quotes are optional. For example, div[&#64;foo='bar'] is also a valid attribute selector.</p>\r
948 <ul class="list">\r
949     <li> <b>E[foo]</b> has an attribute "foo"</li>\r
950     <li> <b>E[foo=bar]</b> has an attribute "foo" that equals "bar"</li>\r
951     <li> <b>E[foo^=bar]</b> has an attribute "foo" that starts with "bar"</li>\r
952     <li> <b>E[foo$=bar]</b> has an attribute "foo" that ends with "bar"</li>\r
953     <li> <b>E[foo*=bar]</b> has an attribute "foo" that contains the substring "bar"</li>\r
954     <li> <b>E[foo%=2]</b> has an attribute "foo" that is evenly divisible by 2</li>\r
955     <li> <b>E[foo!=bar]</b> has an attribute "foo" that does not equal "bar"</li>\r
956 </ul>\r
957 <h4>Pseudo Classes:</h4>\r
958 <ul class="list">\r
959     <li> <b>E:first-child</b> E is the first child of its parent</li>\r
960     <li> <b>E:last-child</b> E is the last child of its parent</li>\r
961     <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
962     <li> <b>E:nth-child(odd)</b> E is an odd child of its parent</li>\r
963     <li> <b>E:nth-child(even)</b> E is an even child of its parent</li>\r
964     <li> <b>E:only-child</b> E is the only child of its parent</li>\r
965     <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
966     <li> <b>E:first</b> the first E in the resultset</li>\r
967     <li> <b>E:last</b> the last E in the resultset</li>\r
968     <li> <b>E:nth(<i>n</i>)</b> the <i>n</i>th E in the resultset (1 based)</li>\r
969     <li> <b>E:odd</b> shortcut for :nth-child(odd)</li>\r
970     <li> <b>E:even</b> shortcut for :nth-child(even)</li>\r
971     <li> <b>E:contains(foo)</b> E's innerHTML contains the substring "foo"</li>\r
972     <li> <b>E:nodeValue(foo)</b> E contains a textNode with a nodeValue that equals "foo"</li>\r
973     <li> <b>E:not(S)</b> an E element that does not match simple selector S</li>\r
974     <li> <b>E:has(S)</b> an E element that has a descendent that matches simple selector S</li>\r
975     <li> <b>E:next(S)</b> an E element whose next sibling matches simple selector S</li>\r
976     <li> <b>E:prev(S)</b> an E element whose previous sibling matches simple selector S</li>\r
977 </ul>\r
978 <h4>CSS Value Selectors:</h4>\r
979 <ul class="list">\r
980     <li> <b>E{display=none}</b> css value "display" that equals "none"</li>\r
981     <li> <b>E{display^=none}</b> css value "display" that starts with "none"</li>\r
982     <li> <b>E{display$=none}</b> css value "display" that ends with "none"</li>\r
983     <li> <b>E{display*=none}</b> css value "display" that contains the substring "none"</li>\r
984     <li> <b>E{display%=2}</b> css value "display" that is evenly divisible by 2</li>\r
985     <li> <b>E{display!=none}</b> css value "display" that does not equal "none"</li>\r
986 </ul>\r
987  * @singleton\r
988  */\r
989 Ext.DomQuery = function(){\r
990     var cache = {}, \r
991         simpleCache = {}, \r
992         valueCache = {},\r
993         nonSpace = /\S/,\r
994         trimRe = /^\s+|\s+$/g,\r
995         tplRe = /\{(\d+)\}/g,\r
996         modeRe = /^(\s?[\/>+~]\s?|\s|$)/,\r
997         tagTokenRe = /^(#)?([\w-\*]+)/,\r
998         nthRe = /(\d*)n\+?(\d*)/, \r
999         nthRe2 = /\D/,\r
1000         // This is for IE MSXML which does not support expandos.\r
1001             // IE runs the same speed using setAttribute, however FF slows way down\r
1002             // and Safari completely fails so they need to continue to use expandos.\r
1003             isIE = window.ActiveXObject ? true : false,\r
1004         isOpera = Ext.isOpera,\r
1005             key = 30803;\r
1006             \r
1007     // this eval is stop the compressor from\r
1008         // renaming the variable to something shorter\r
1009         eval("var batch = 30803;");     \r
1010 \r
1011     function child(p, index){\r
1012         var i = 0,\r
1013                 n = p.firstChild;\r
1014         while(n){\r
1015             if(n.nodeType == 1){\r
1016                if(++i == index){\r
1017                    return n;\r
1018                }\r
1019             }\r
1020             n = n.nextSibling;\r
1021         }\r
1022         return null;\r
1023     };\r
1024 \r
1025     function next(n){\r
1026         while((n = n.nextSibling) && n.nodeType != 1);\r
1027         return n;\r
1028     };\r
1029 \r
1030     function prev(n){\r
1031         while((n = n.previousSibling) && n.nodeType != 1);\r
1032         return n;\r
1033     };\r
1034 \r
1035     function children(d){\r
1036         var n = d.firstChild, ni = -1,\r
1037                 nx;\r
1038             while(n){\r
1039                 nx = n.nextSibling;\r
1040                 if(n.nodeType == 3 && !nonSpace.test(n.nodeValue)){\r
1041                     d.removeChild(n);\r
1042                 }else{\r
1043                     n.nodeIndex = ++ni;\r
1044                 }\r
1045                 n = nx;\r
1046             }\r
1047             return this;\r
1048         };\r
1049 \r
1050     function byClassName(c, a, v){\r
1051         if(!v){\r
1052             return c;\r
1053         }\r
1054         var r = [], ri = -1, cn;\r
1055         for(var i = 0, ci; ci = c[i]; i++){\r
1056             if((' '+ci.className+' ').indexOf(v) != -1){\r
1057                 r[++ri] = ci;\r
1058             }\r
1059         }\r
1060         return r;\r
1061     };\r
1062 \r
1063     function attrValue(n, attr){\r
1064         if(!n.tagName && typeof n.length != "undefined"){\r
1065             n = n[0];\r
1066         }\r
1067         if(!n){\r
1068             return null;\r
1069         }\r
1070         if(attr == "for"){\r
1071             return n.htmlFor;\r
1072         }\r
1073         if(attr == "class" || attr == "className"){\r
1074             return n.className;\r
1075         }\r
1076         return n.getAttribute(attr) || n[attr];\r
1077 \r
1078     };\r
1079 \r
1080     function getNodes(ns, mode, tagName){\r
1081         var result = [], ri = -1, cs;\r
1082         if(!ns){\r
1083             return result;\r
1084         }\r
1085         tagName = tagName || "*";\r
1086         if(typeof ns.getElementsByTagName != "undefined"){\r
1087             ns = [ns];\r
1088         }\r
1089         if(!mode){\r
1090             for(var i = 0, ni; ni = ns[i]; i++){\r
1091                 cs = ni.getElementsByTagName(tagName);\r
1092                 for(var j = 0, ci; ci = cs[j]; j++){\r
1093                     result[++ri] = ci;\r
1094                 }\r
1095             }\r
1096         }else if(mode == "/" || mode == ">"){\r
1097             var utag = tagName.toUpperCase();\r
1098             for(var i = 0, ni, cn; ni = ns[i]; i++){\r
1099                 cn = isOpera ? ni.childNodes : (ni.children || ni.childNodes);\r
1100                 for(var j = 0, cj; cj = cn[j]; j++){\r
1101                     if(cj.nodeName == utag || cj.nodeName == tagName  || tagName == '*'){\r
1102                         result[++ri] = cj;\r
1103                     }\r
1104                 }\r
1105             }\r
1106         }else if(mode == "+"){\r
1107             var utag = tagName.toUpperCase();\r
1108             for(var i = 0, n; n = ns[i]; i++){\r
1109                 while((n = n.nextSibling) && n.nodeType != 1);\r
1110                 if(n && (n.nodeName == utag || n.nodeName == tagName || tagName == '*')){\r
1111                     result[++ri] = n;\r
1112                 }\r
1113             }\r
1114         }else if(mode == "~"){\r
1115             var utag = tagName.toUpperCase();\r
1116             for(var i = 0, n; n = ns[i]; i++){\r
1117                 while((n = n.nextSibling)){\r
1118                     if (n.nodeName == utag || n.nodeName == tagName || tagName == '*'){\r
1119                         result[++ri] = n;\r
1120                     }\r
1121                 }\r
1122             }\r
1123         }\r
1124         return result;\r
1125     };\r
1126 \r
1127     function concat(a, b){\r
1128         if(b.slice){\r
1129             return a.concat(b);\r
1130         }\r
1131         for(var i = 0, l = b.length; i < l; i++){\r
1132             a[a.length] = b[i];\r
1133         }\r
1134         return a;\r
1135     }\r
1136 \r
1137     function byTag(cs, tagName){\r
1138         if(cs.tagName || cs == document){\r
1139             cs = [cs];\r
1140         }\r
1141         if(!tagName){\r
1142             return cs;\r
1143         }\r
1144         var r = [], ri = -1;\r
1145         tagName = tagName.toLowerCase();\r
1146         for(var i = 0, ci; ci = cs[i]; i++){\r
1147             if(ci.nodeType == 1 && ci.tagName.toLowerCase()==tagName){\r
1148                 r[++ri] = ci;\r
1149             }\r
1150         }\r
1151         return r;\r
1152     };\r
1153 \r
1154     function byId(cs, attr, id){\r
1155         if(cs.tagName || cs == document){\r
1156             cs = [cs];\r
1157         }\r
1158         if(!id){\r
1159             return cs;\r
1160         }\r
1161         var r = [], ri = -1;\r
1162         for(var i = 0,ci; ci = cs[i]; i++){\r
1163             if(ci && ci.id == id){\r
1164                 r[++ri] = ci;\r
1165                 return r;\r
1166             }\r
1167         }\r
1168         return r;\r
1169     };\r
1170 \r
1171     function byAttribute(cs, attr, value, op, custom){\r
1172         var r = [], \r
1173                 ri = -1, \r
1174                 st = custom=="{",\r
1175                 f = Ext.DomQuery.operators[op];\r
1176         for(var i = 0, ci; ci = cs[i]; i++){\r
1177             if(ci.nodeType != 1){\r
1178                 continue;\r
1179             }\r
1180             var a;\r
1181             if(st){\r
1182                 a = Ext.DomQuery.getStyle(ci, attr);\r
1183             }\r
1184             else if(attr == "class" || attr == "className"){\r
1185                 a = ci.className;\r
1186             }else if(attr == "for"){\r
1187                 a = ci.htmlFor;\r
1188             }else if(attr == "href"){\r
1189                 a = ci.getAttribute("href", 2);\r
1190             }else{\r
1191                 a = ci.getAttribute(attr);\r
1192             }\r
1193             if((f && f(a, value)) || (!f && a)){\r
1194                 r[++ri] = ci;\r
1195             }\r
1196         }\r
1197         return r;\r
1198     };\r
1199 \r
1200     function byPseudo(cs, name, value){\r
1201         return Ext.DomQuery.pseudos[name](cs, value);\r
1202     };\r
1203 \r
1204     function nodupIEXml(cs){\r
1205         var d = ++key, \r
1206                 r;\r
1207         cs[0].setAttribute("_nodup", d);\r
1208         r = [cs[0]];\r
1209         for(var i = 1, len = cs.length; i < len; i++){\r
1210             var c = cs[i];\r
1211             if(!c.getAttribute("_nodup") != d){\r
1212                 c.setAttribute("_nodup", d);\r
1213                 r[r.length] = c;\r
1214             }\r
1215         }\r
1216         for(var i = 0, len = cs.length; i < len; i++){\r
1217             cs[i].removeAttribute("_nodup");\r
1218         }\r
1219         return r;\r
1220     }\r
1221 \r
1222     function nodup(cs){\r
1223         if(!cs){\r
1224             return [];\r
1225         }\r
1226         var len = cs.length, c, i, r = cs, cj, ri = -1;\r
1227         if(!len || typeof cs.nodeType != "undefined" || len == 1){\r
1228             return cs;\r
1229         }\r
1230         if(isIE && typeof cs[0].selectSingleNode != "undefined"){\r
1231             return nodupIEXml(cs);\r
1232         }\r
1233         var d = ++key;\r
1234         cs[0]._nodup = d;\r
1235         for(i = 1; c = cs[i]; i++){\r
1236             if(c._nodup != d){\r
1237                 c._nodup = d;\r
1238             }else{\r
1239                 r = [];\r
1240                 for(var j = 0; j < i; j++){\r
1241                     r[++ri] = cs[j];\r
1242                 }\r
1243                 for(j = i+1; cj = cs[j]; j++){\r
1244                     if(cj._nodup != d){\r
1245                         cj._nodup = d;\r
1246                         r[++ri] = cj;\r
1247                     }\r
1248                 }\r
1249                 return r;\r
1250             }\r
1251         }\r
1252         return r;\r
1253     }\r
1254 \r
1255     function quickDiffIEXml(c1, c2){\r
1256         var d = ++key,\r
1257                 r = [];\r
1258         for(var i = 0, len = c1.length; i < len; i++){\r
1259             c1[i].setAttribute("_qdiff", d);\r
1260         }        \r
1261         for(var i = 0, len = c2.length; i < len; i++){\r
1262             if(c2[i].getAttribute("_qdiff") != d){\r
1263                 r[r.length] = c2[i];\r
1264             }\r
1265         }\r
1266         for(var i = 0, len = c1.length; i < len; i++){\r
1267            c1[i].removeAttribute("_qdiff");\r
1268         }\r
1269         return r;\r
1270     }\r
1271 \r
1272     function quickDiff(c1, c2){\r
1273         var len1 = c1.length,\r
1274                 d = ++key,\r
1275                 r = [];\r
1276         if(!len1){\r
1277             return c2;\r
1278         }\r
1279         if(isIE && c1[0].selectSingleNode){\r
1280             return quickDiffIEXml(c1, c2);\r
1281         }        \r
1282         for(var i = 0; i < len1; i++){\r
1283             c1[i]._qdiff = d;\r
1284         }        \r
1285         for(var i = 0, len = c2.length; i < len; i++){\r
1286             if(c2[i]._qdiff != d){\r
1287                 r[r.length] = c2[i];\r
1288             }\r
1289         }\r
1290         return r;\r
1291     }\r
1292 \r
1293     function quickId(ns, mode, root, id){\r
1294         if(ns == root){\r
1295            var d = root.ownerDocument || root;\r
1296            return d.getElementById(id);\r
1297         }\r
1298         ns = getNodes(ns, mode, "*");\r
1299         return byId(ns, null, id);\r
1300     }\r
1301 \r
1302     return {\r
1303         getStyle : function(el, name){\r
1304             return Ext.fly(el).getStyle(name);\r
1305         },\r
1306         /**\r
1307          * Compiles a selector/xpath query into a reusable function. The returned function\r
1308          * takes one parameter "root" (optional), which is the context node from where the query should start.\r
1309          * @param {String} selector The selector/xpath query\r
1310          * @param {String} type (optional) Either "select" (the default) or "simple" for a simple selector match\r
1311          * @return {Function}\r
1312          */\r
1313         compile : function(path, type){\r
1314             type = type || "select";\r
1315 \r
1316             var fn = ["var f = function(root){\n var mode; ++batch; var n = root || document;\n"],\r
1317                 q = path, mode, lq,\r
1318                 tk = Ext.DomQuery.matchers,\r
1319                 tklen = tk.length,\r
1320                 mm,\r
1321                 // accept leading mode switch\r
1322                 lmode = q.match(modeRe);\r
1323             \r
1324             if(lmode && lmode[1]){\r
1325                 fn[fn.length] = 'mode="'+lmode[1].replace(trimRe, "")+'";';\r
1326                 q = q.replace(lmode[1], "");\r
1327             }\r
1328             // strip leading slashes\r
1329             while(path.substr(0, 1)=="/"){\r
1330                 path = path.substr(1);\r
1331             }\r
1332 \r
1333             while(q && lq != q){\r
1334                 lq = q;\r
1335                 var tm = q.match(tagTokenRe);\r
1336                 if(type == "select"){\r
1337                     if(tm){\r
1338                         if(tm[1] == "#"){\r
1339                             fn[fn.length] = 'n = quickId(n, mode, root, "'+tm[2]+'");';\r
1340                         }else{\r
1341                             fn[fn.length] = 'n = getNodes(n, mode, "'+tm[2]+'");';\r
1342                         }\r
1343                         q = q.replace(tm[0], "");\r
1344                     }else if(q.substr(0, 1) != '@'){\r
1345                         fn[fn.length] = 'n = getNodes(n, mode, "*");';\r
1346                     }\r
1347                 }else{\r
1348                     if(tm){\r
1349                         if(tm[1] == "#"){\r
1350                             fn[fn.length] = 'n = byId(n, null, "'+tm[2]+'");';\r
1351                         }else{\r
1352                             fn[fn.length] = 'n = byTag(n, "'+tm[2]+'");';\r
1353                         }\r
1354                         q = q.replace(tm[0], "");\r
1355                     }\r
1356                 }\r
1357                 while(!(mm = q.match(modeRe))){\r
1358                     var matched = false;\r
1359                     for(var j = 0; j < tklen; j++){\r
1360                         var t = tk[j];\r
1361                         var m = q.match(t.re);\r
1362                         if(m){\r
1363                             fn[fn.length] = t.select.replace(tplRe, function(x, i){\r
1364                                                     return m[i];\r
1365                                                 });\r
1366                             q = q.replace(m[0], "");\r
1367                             matched = true;\r
1368                             break;\r
1369                         }\r
1370                     }\r
1371                     // prevent infinite loop on bad selector\r
1372                     if(!matched){\r
1373                         throw 'Error parsing selector, parsing failed at "' + q + '"';\r
1374                     }\r
1375                 }\r
1376                 if(mm[1]){\r
1377                     fn[fn.length] = 'mode="'+mm[1].replace(trimRe, "")+'";';\r
1378                     q = q.replace(mm[1], "");\r
1379                 }\r
1380             }\r
1381             fn[fn.length] = "return nodup(n);\n}";\r
1382             eval(fn.join(""));\r
1383             return f;\r
1384         },\r
1385 \r
1386         /**\r
1387          * Selects a group of elements.\r
1388          * @param {String} selector The selector/xpath query (can be a comma separated list of selectors)\r
1389          * @param {Node} root (optional) The start of the query (defaults to document).\r
1390          * @return {Array} An Array of DOM elements which match the selector. If there are\r
1391          * no matches, and empty Array is returned.\r
1392          */\r
1393         select : function(path, root, type){\r
1394             if(!root || root == document){\r
1395                 root = document;\r
1396             }\r
1397             if(typeof root == "string"){\r
1398                 root = document.getElementById(root);\r
1399             }\r
1400             var paths = path.split(","),\r
1401                 results = [];\r
1402             for(var i = 0, len = paths.length; i < len; i++){\r
1403                 var p = paths[i].replace(trimRe, "");\r
1404                 if(!cache[p]){\r
1405                     cache[p] = Ext.DomQuery.compile(p);\r
1406                     if(!cache[p]){\r
1407                         throw p + " is not a valid selector";\r
1408                     }\r
1409                 }\r
1410                 var result = cache[p](root);\r
1411                 if(result && result != document){\r
1412                     results = results.concat(result);\r
1413                 }\r
1414             }\r
1415             if(paths.length > 1){\r
1416                 return nodup(results);\r
1417             }\r
1418             return results;\r
1419         },\r
1420 \r
1421         /**\r
1422          * Selects a single element.\r
1423          * @param {String} selector The selector/xpath query\r
1424          * @param {Node} root (optional) The start of the query (defaults to document).\r
1425          * @return {Element} The DOM element which matched the selector.\r
1426          */\r
1427         selectNode : function(path, root){\r
1428             return Ext.DomQuery.select(path, root)[0];\r
1429         },\r
1430 \r
1431         /**\r
1432          * Selects the value of a node, optionally replacing null with the defaultValue.\r
1433          * @param {String} selector The selector/xpath query\r
1434          * @param {Node} root (optional) The start of the query (defaults to document).\r
1435          * @param {String} defaultValue\r
1436          * @return {String}\r
1437          */\r
1438         selectValue : function(path, root, defaultValue){\r
1439             path = path.replace(trimRe, "");\r
1440             if(!valueCache[path]){\r
1441                 valueCache[path] = Ext.DomQuery.compile(path, "select");\r
1442             }\r
1443             var n = valueCache[path](root),\r
1444                 v;\r
1445             n = n[0] ? n[0] : n;\r
1446             v = (n && n.firstChild ? n.firstChild.nodeValue : null);\r
1447             return ((v === null||v === undefined||v==='') ? defaultValue : v);\r
1448         },\r
1449 \r
1450         /**\r
1451          * Selects the value of a node, parsing integers and floats. Returns the defaultValue, or 0 if none is specified.\r
1452          * @param {String} selector The selector/xpath query\r
1453          * @param {Node} root (optional) The start of the query (defaults to document).\r
1454          * @param {Number} defaultValue\r
1455          * @return {Number}\r
1456          */\r
1457         selectNumber : function(path, root, defaultValue){\r
1458             var v = Ext.DomQuery.selectValue(path, root, defaultValue || 0);\r
1459             return parseFloat(v);\r
1460         },\r
1461 \r
1462         /**\r
1463          * Returns true if the passed element(s) match the passed simple selector (e.g. div.some-class or span:first-child)\r
1464          * @param {String/HTMLElement/Array} el An element id, element or array of elements\r
1465          * @param {String} selector The simple selector to test\r
1466          * @return {Boolean}\r
1467          */\r
1468         is : function(el, ss){\r
1469             if(typeof el == "string"){\r
1470                 el = document.getElementById(el);\r
1471             }\r
1472             var isArray = Ext.isArray(el),\r
1473                 result = Ext.DomQuery.filter(isArray ? el : [el], ss);\r
1474             return isArray ? (result.length == el.length) : (result.length > 0);\r
1475         },\r
1476 \r
1477         /**\r
1478          * Filters an array of elements to only include matches of a simple selector (e.g. div.some-class or span:first-child)\r
1479          * @param {Array} el An array of elements to filter\r
1480          * @param {String} selector The simple selector to test\r
1481          * @param {Boolean} nonMatches If true, it returns the elements that DON'T match\r
1482          * the selector instead of the ones that match\r
1483          * @return {Array} An Array of DOM elements which match the selector. If there are\r
1484          * no matches, and empty Array is returned.\r
1485          */\r
1486         filter : function(els, ss, nonMatches){\r
1487             ss = ss.replace(trimRe, "");\r
1488             if(!simpleCache[ss]){\r
1489                 simpleCache[ss] = Ext.DomQuery.compile(ss, "simple");\r
1490             }\r
1491             var result = simpleCache[ss](els);\r
1492             return nonMatches ? quickDiff(result, els) : result;\r
1493         },\r
1494 \r
1495         /**\r
1496          * Collection of matching regular expressions and code snippets.\r
1497          */\r
1498         matchers : [{\r
1499                 re: /^\.([\w-]+)/,\r
1500                 select: 'n = byClassName(n, null, " {1} ");'\r
1501             }, {\r
1502                 re: /^\:([\w-]+)(?:\(((?:[^\s>\/]*|.*?))\))?/,\r
1503                 select: 'n = byPseudo(n, "{1}", "{2}");'\r
1504             },{\r
1505                 re: /^(?:([\[\{])(?:@)?([\w-]+)\s?(?:(=|.=)\s?['"]?(.*?)["']?)?[\]\}])/,\r
1506                 select: 'n = byAttribute(n, "{2}", "{4}", "{3}", "{1}");'\r
1507             }, {\r
1508                 re: /^#([\w-]+)/,\r
1509                 select: 'n = byId(n, null, "{1}");'\r
1510             },{\r
1511                 re: /^@([\w-]+)/,\r
1512                 select: 'return {firstChild:{nodeValue:attrValue(n, "{1}")}};'\r
1513             }\r
1514         ],\r
1515 \r
1516         /**\r
1517          * Collection of operator comparison functions. The default operators are =, !=, ^=, $=, *=, %=, |= and ~=.\r
1518          * 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
1519          */\r
1520         operators : {\r
1521             "=" : function(a, v){\r
1522                 return a == v;\r
1523             },\r
1524             "!=" : function(a, v){\r
1525                 return a != v;\r
1526             },\r
1527             "^=" : function(a, v){\r
1528                 return a && a.substr(0, v.length) == v;\r
1529             },\r
1530             "$=" : function(a, v){\r
1531                 return a && a.substr(a.length-v.length) == v;\r
1532             },\r
1533             "*=" : function(a, v){\r
1534                 return a && a.indexOf(v) !== -1;\r
1535             },\r
1536             "%=" : function(a, v){\r
1537                 return (a % v) == 0;\r
1538             },\r
1539             "|=" : function(a, v){\r
1540                 return a && (a == v || a.substr(0, v.length+1) == v+'-');\r
1541             },\r
1542             "~=" : function(a, v){\r
1543                 return a && (' '+a+' ').indexOf(' '+v+' ') != -1;\r
1544             }\r
1545         },\r
1546 \r
1547         /**\r
1548          * <p>Object hash of "pseudo class" filter functions which are used when filtering selections. Each function is passed\r
1549          * two parameters:</p><div class="mdetail-params"><ul>\r
1550          * <li><b>c</b> : Array<div class="sub-desc">An Array of DOM elements to filter.</div></li>\r
1551          * <li><b>v</b> : String<div class="sub-desc">The argument (if any) supplied in the selector.</div></li>\r
1552          * </ul></div>\r
1553          * <p>A filter function returns an Array of DOM elements which conform to the pseudo class.</p>\r
1554          * <p>In addition to the provided pseudo classes listed above such as <code>first-child</code> and <code>nth-child</code>,\r
1555          * developers may add additional, custom psuedo class filters to select elements according to application-specific requirements.</p>\r
1556          * <p>For example, to filter <code>&lt;a></code> elements to only return links to <i>external</i> resources:</p>\r
1557          * <code><pre>\r
1558 Ext.DomQuery.pseudos.external = function(c, v){\r
1559     var r = [], ri = -1;\r
1560     for(var i = 0, ci; ci = c[i]; i++){\r
1561 //      Include in result set only if it's a link to an external resource\r
1562         if(ci.hostname != location.hostname){\r
1563             r[++ri] = ci;\r
1564         }\r
1565     }\r
1566     return r;\r
1567 };</pre></code>\r
1568          * Then external links could be gathered with the following statement:<code><pre>\r
1569 var externalLinks = Ext.select("a:external");\r
1570 </code></pre>\r
1571          */\r
1572         pseudos : {\r
1573             "first-child" : function(c){\r
1574                 var r = [], ri = -1, n;\r
1575                 for(var i = 0, ci; ci = n = c[i]; i++){\r
1576                     while((n = n.previousSibling) && n.nodeType != 1);\r
1577                     if(!n){\r
1578                         r[++ri] = ci;\r
1579                     }\r
1580                 }\r
1581                 return r;\r
1582             },\r
1583 \r
1584             "last-child" : function(c){\r
1585                 var r = [], ri = -1, n;\r
1586                 for(var i = 0, ci; ci = n = c[i]; i++){\r
1587                     while((n = n.nextSibling) && n.nodeType != 1);\r
1588                     if(!n){\r
1589                         r[++ri] = ci;\r
1590                     }\r
1591                 }\r
1592                 return r;\r
1593             },\r
1594 \r
1595             "nth-child" : function(c, a) {\r
1596                 var r = [], ri = -1,\r
1597                         m = nthRe.exec(a == "even" && "2n" || a == "odd" && "2n+1" || !nthRe2.test(a) && "n+" + a || a),\r
1598                         f = (m[1] || 1) - 0, l = m[2] - 0;\r
1599                 for(var i = 0, n; n = c[i]; i++){\r
1600                     var pn = n.parentNode;\r
1601                     if (batch != pn._batch) {\r
1602                         var j = 0;\r
1603                         for(var cn = pn.firstChild; cn; cn = cn.nextSibling){\r
1604                             if(cn.nodeType == 1){\r
1605                                cn.nodeIndex = ++j;\r
1606                             }\r
1607                         }\r
1608                         pn._batch = batch;\r
1609                     }\r
1610                     if (f == 1) {\r
1611                         if (l == 0 || n.nodeIndex == l){\r
1612                             r[++ri] = n;\r
1613                         }\r
1614                     } else if ((n.nodeIndex + l) % f == 0){\r
1615                         r[++ri] = n;\r
1616                     }\r
1617                 }\r
1618 \r
1619                 return r;\r
1620             },\r
1621 \r
1622             "only-child" : function(c){\r
1623                 var r = [], ri = -1;;\r
1624                 for(var i = 0, ci; ci = c[i]; i++){\r
1625                     if(!prev(ci) && !next(ci)){\r
1626                         r[++ri] = ci;\r
1627                     }\r
1628                 }\r
1629                 return r;\r
1630             },\r
1631 \r
1632             "empty" : function(c){\r
1633                 var r = [], ri = -1;\r
1634                 for(var i = 0, ci; ci = c[i]; i++){\r
1635                     var cns = ci.childNodes, j = 0, cn, empty = true;\r
1636                     while(cn = cns[j]){\r
1637                         ++j;\r
1638                         if(cn.nodeType == 1 || cn.nodeType == 3){\r
1639                             empty = false;\r
1640                             break;\r
1641                         }\r
1642                     }\r
1643                     if(empty){\r
1644                         r[++ri] = ci;\r
1645                     }\r
1646                 }\r
1647                 return r;\r
1648             },\r
1649 \r
1650             "contains" : function(c, v){\r
1651                 var r = [], ri = -1;\r
1652                 for(var i = 0, ci; ci = c[i]; i++){\r
1653                     if((ci.textContent||ci.innerText||'').indexOf(v) != -1){\r
1654                         r[++ri] = ci;\r
1655                     }\r
1656                 }\r
1657                 return r;\r
1658             },\r
1659 \r
1660             "nodeValue" : function(c, v){\r
1661                 var r = [], ri = -1;\r
1662                 for(var i = 0, ci; ci = c[i]; i++){\r
1663                     if(ci.firstChild && ci.firstChild.nodeValue == v){\r
1664                         r[++ri] = ci;\r
1665                     }\r
1666                 }\r
1667                 return r;\r
1668             },\r
1669 \r
1670             "checked" : function(c){\r
1671                 var r = [], ri = -1;\r
1672                 for(var i = 0, ci; ci = c[i]; i++){\r
1673                     if(ci.checked == true){\r
1674                         r[++ri] = ci;\r
1675                     }\r
1676                 }\r
1677                 return r;\r
1678             },\r
1679 \r
1680             "not" : function(c, ss){\r
1681                 return Ext.DomQuery.filter(c, ss, true);\r
1682             },\r
1683 \r
1684             "any" : function(c, selectors){\r
1685                 var ss = selectors.split('|'),\r
1686                         r = [], ri = -1, s;\r
1687                 for(var i = 0, ci; ci = c[i]; i++){\r
1688                     for(var j = 0; s = ss[j]; j++){\r
1689                         if(Ext.DomQuery.is(ci, s)){\r
1690                             r[++ri] = ci;\r
1691                             break;\r
1692                         }\r
1693                     }\r
1694                 }\r
1695                 return r;\r
1696             },\r
1697 \r
1698             "odd" : function(c){\r
1699                 return this["nth-child"](c, "odd");\r
1700             },\r
1701 \r
1702             "even" : function(c){\r
1703                 return this["nth-child"](c, "even");\r
1704             },\r
1705 \r
1706             "nth" : function(c, a){\r
1707                 return c[a-1] || [];\r
1708             },\r
1709 \r
1710             "first" : function(c){\r
1711                 return c[0] || [];\r
1712             },\r
1713 \r
1714             "last" : function(c){\r
1715                 return c[c.length-1] || [];\r
1716             },\r
1717 \r
1718             "has" : function(c, ss){\r
1719                 var s = Ext.DomQuery.select,\r
1720                         r = [], ri = -1;\r
1721                 for(var i = 0, ci; ci = c[i]; i++){\r
1722                     if(s(ss, ci).length > 0){\r
1723                         r[++ri] = ci;\r
1724                     }\r
1725                 }\r
1726                 return r;\r
1727             },\r
1728 \r
1729             "next" : function(c, ss){\r
1730                 var is = Ext.DomQuery.is,\r
1731                         r = [], ri = -1;\r
1732                 for(var i = 0, ci; ci = c[i]; i++){\r
1733                     var n = next(ci);\r
1734                     if(n && is(n, ss)){\r
1735                         r[++ri] = ci;\r
1736                     }\r
1737                 }\r
1738                 return r;\r
1739             },\r
1740 \r
1741             "prev" : function(c, ss){\r
1742                 var is = Ext.DomQuery.is,\r
1743                         r = [], ri = -1;\r
1744                 for(var i = 0, ci; ci = c[i]; i++){\r
1745                     var n = prev(ci);\r
1746                     if(n && is(n, ss)){\r
1747                         r[++ri] = ci;\r
1748                     }\r
1749                 }\r
1750                 return r;\r
1751             }\r
1752         }\r
1753     };\r
1754 }();\r
1755 \r
1756 /**\r
1757  * Selects an array of DOM nodes by CSS/XPath selector. Shorthand of {@link Ext.DomQuery#select}\r
1758  * @param {String} path The selector/xpath query\r
1759  * @param {Node} root (optional) The start of the query (defaults to document).\r
1760  * @return {Array}\r
1761  * @member Ext\r
1762  * @method query\r
1763  */\r
1764 Ext.query = Ext.DomQuery.select;\r
1765 (function(){
1766
1767 var EXTUTIL = Ext.util,
1768     TOARRAY = Ext.toArray,
1769     EACH = Ext.each,
1770     ISOBJECT = Ext.isObject,
1771     TRUE = true,
1772     FALSE = false;
1773 /**
1774  * @class Ext.util.Observable
1775  * Base class that provides a common interface for publishing events. Subclasses are expected to
1776  * to have a property "events" with all the events defined, and, optionally, a property "listeners"
1777  * with configured listeners defined.<br>
1778  * For example:
1779  * <pre><code>
1780 Employee = Ext.extend(Ext.util.Observable, {
1781     constructor: function(config){
1782         this.name = config.name;
1783         this.addEvents({
1784             "fired" : true,
1785             "quit" : true
1786         });
1787
1788         // Copy configured listeners into *this* object so that the base class&#39;s
1789         // constructor will add them.
1790         this.listeners = config.listeners;
1791
1792         // Call our superclass constructor to complete construction process.
1793         Employee.superclass.constructor.call(config)
1794     }
1795 });
1796 </code></pre>
1797  * This could then be used like this:<pre><code>
1798 var newEmployee = new Employee({
1799     name: employeeName,
1800     listeners: {
1801         quit: function() {
1802             // By default, "this" will be the object that fired the event.
1803             alert(this.name + " has quit!");
1804         }
1805     }
1806 });
1807 </code></pre>
1808  */
1809 EXTUTIL.Observable = function(){
1810     /**
1811      * @cfg {Object} listeners (optional) <p>A config object containing one or more event handlers to be added to this
1812      * object during initialization.  This should be a valid listeners config object as specified in the
1813      * {@link #addListener} example for attaching multiple handlers at once.</p>
1814      * <br><p><b><u>DOM events from ExtJs {@link Ext.Component Components}</u></b></p>
1815      * <br><p>While <i>some</i> ExtJs Component classes export selected DOM events (e.g. "click", "mouseover" etc), this
1816      * is usually only done when extra value can be added. For example the {@link Ext.DataView DataView}'s
1817      * <b><code>{@link Ext.DataView#click click}</code></b> event passing the node clicked on. To access DOM
1818      * events directly from a Component's HTMLElement, listeners must be added to the <i>{@link Ext.Component#getEl Element}</i> after the Component
1819      * has been rendered. A plugin can simplify this step:<pre><code>
1820 // Plugin is configured with a listeners config object.
1821 // The Component is appended to the argument list of all handler functions.
1822 Ext.DomObserver = Ext.extend(Object, {
1823     constructor: function(config) {
1824         this.listeners = config.listeners ? config.listeners : config;
1825     },
1826
1827     // Component passes itself into plugin&#39;s init method
1828     init: function(c) {
1829         var p, l = this.listeners;
1830         for (p in l) {
1831             if (Ext.isFunction(l[p])) {
1832                 l[p] = this.createHandler(l[p], c);
1833             } else {
1834                 l[p].fn = this.createHandler(l[p].fn, c);
1835             }
1836         }
1837
1838         // Add the listeners to the Element immediately following the render call
1839         c.render = c.render.{@link Function#createSequence createSequence}(function() {
1840             var e = c.getEl();
1841             if (e) {
1842                 e.on(l);
1843             }
1844         });
1845     },
1846
1847     createHandler: function(fn, c) {
1848         return function(e) {
1849             fn.call(this, e, c);
1850         };
1851     }
1852 });
1853
1854 var combo = new Ext.form.ComboBox({
1855
1856     // Collapse combo when its element is clicked on
1857     plugins: [ new Ext.DomObserver({
1858         click: function(evt, comp) {
1859             comp.collapse();
1860         }
1861     })],
1862     store: myStore,
1863     typeAhead: true,
1864     mode: 'local',
1865     triggerAction: 'all'
1866 });
1867      * </code></pre></p>
1868      */
1869     var me = this, e = me.events;
1870     if(me.listeners){
1871         me.on(me.listeners);
1872         delete me.listeners;
1873     }
1874     me.events = e || {};
1875 };
1876
1877 EXTUTIL.Observable.prototype = {
1878     // private
1879     filterOptRe : /^(?:scope|delay|buffer|single)$/,
1880
1881     /**
1882      * <p>Fires the specified event with the passed parameters (minus the event name).</p>
1883      * <p>An event may be set to bubble up an Observable parent hierarchy (See {@link Ext.Component#getBubbleTarget})
1884      * by calling {@link #enableBubble}.</p>
1885      * @param {String} eventName The name of the event to fire.
1886      * @param {Object...} args Variable number of parameters are passed to handlers.
1887      * @return {Boolean} returns false if any of the handlers return false otherwise it returns true.
1888      */
1889     fireEvent : function(){
1890         var a = TOARRAY(arguments),
1891             ename = a[0].toLowerCase(),
1892             me = this,
1893             ret = TRUE,
1894             ce = me.events[ename],
1895             q,
1896             c;
1897         if (me.eventsSuspended === TRUE) {
1898             if (q = me.eventQueue) {
1899                 q.push(a);
1900             }
1901         }
1902         else if(ISOBJECT(ce) && ce.bubble){
1903             if(ce.fire.apply(ce, a.slice(1)) === FALSE) {
1904                 return FALSE;
1905             }
1906             c = me.getBubbleTarget && me.getBubbleTarget();
1907             if(c && c.enableBubble) {
1908                 if(!c.events[ename] || !Ext.isObject(c.events[ename]) || !c.events[ename].bubble) {
1909                     c.enableBubble(ename);
1910                 }
1911                 return c.fireEvent.apply(c, a);
1912             }
1913         }
1914         else {
1915             if (ISOBJECT(ce)) {
1916                 a.shift();
1917                 ret = ce.fire.apply(ce, a);
1918             }
1919         }
1920         return ret;
1921     },
1922
1923     /**
1924      * Appends an event handler to this object.
1925      * @param {String}   eventName The name of the event to listen for.
1926      * @param {Function} handler The method the event invokes.
1927      * @param {Object}   scope (optional) The scope (<code><b>this</b></code> reference) in which the handler function is executed.
1928      * <b>If omitted, defaults to the object which fired the event.</b>
1929      * @param {Object}   options (optional) An object containing handler configuration.
1930      * properties. This may contain any of the following properties:<ul>
1931      * <li><b>scope</b> : Object<div class="sub-desc">The scope (<code><b>this</b></code> reference) in which the handler function is executed.
1932      * <b>If omitted, defaults to the object which fired the event.</b></div></li>
1933      * <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>
1934      * <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>
1935      * <li><b>buffer</b> : Number<div class="sub-desc">Causes the handler to be scheduled to run in an {@link Ext.util.DelayedTask} delayed
1936      * by the specified number of milliseconds. If the event fires again within that time, the original
1937      * handler is <em>not</em> invoked, but the new handler is scheduled in its place.</div></li>
1938      * <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>
1939      * if the event was bubbled up from a child Observable.</div></li>
1940      * </ul><br>
1941      * <p>
1942      * <b>Combining Options</b><br>
1943      * Using the options argument, it is possible to combine different types of listeners:<br>
1944      * <br>
1945      * A delayed, one-time listener.
1946      * <pre><code>
1947 myDataView.on('click', this.onClick, this, {
1948 single: true,
1949 delay: 100
1950 });</code></pre>
1951      * <p>
1952      * <b>Attaching multiple handlers in 1 call</b><br>
1953      * The method also allows for a single argument to be passed which is a config object containing properties
1954      * which specify multiple handlers.
1955      * <p>
1956      * <pre><code>
1957 myGridPanel.on({
1958 'click' : {
1959     fn: this.onClick,
1960     scope: this,
1961     delay: 100
1962 },
1963 'mouseover' : {
1964     fn: this.onMouseOver,
1965     scope: this
1966 },
1967 'mouseout' : {
1968     fn: this.onMouseOut,
1969     scope: this
1970 }
1971 });</code></pre>
1972  * <p>
1973  * Or a shorthand syntax:<br>
1974  * <pre><code>
1975 myGridPanel.on({
1976 'click' : this.onClick,
1977 'mouseover' : this.onMouseOver,
1978 'mouseout' : this.onMouseOut,
1979  scope: this
1980 });</code></pre>
1981      */
1982     addListener : function(eventName, fn, scope, o){
1983         var me = this,
1984             e,
1985             oe,
1986             isF,
1987         ce;
1988         if (ISOBJECT(eventName)) {
1989             o = eventName;
1990             for (e in o){
1991                 oe = o[e];
1992                 if (!me.filterOptRe.test(e)) {
1993                     me.addListener(e, oe.fn || oe, oe.scope || o.scope, oe.fn ? oe : o);
1994                 }
1995             }
1996         } else {
1997             eventName = eventName.toLowerCase();
1998             ce = me.events[eventName] || TRUE;
1999             if (Ext.isBoolean(ce)) {
2000                 me.events[eventName] = ce = new EXTUTIL.Event(me, eventName);
2001             }
2002             ce.addListener(fn, scope, ISOBJECT(o) ? o : {});
2003         }
2004     },
2005
2006     /**
2007      * Removes an event handler.
2008      * @param {String}   eventName The type of event the handler was associated with.
2009      * @param {Function} handler   The handler to remove. <b>This must be a reference to the function passed into the {@link #addListener} call.</b>
2010      * @param {Object}   scope     (optional) The scope originally specified for the handler.
2011      */
2012     removeListener : function(eventName, fn, scope){
2013         var ce = this.events[eventName.toLowerCase()];
2014         if (ISOBJECT(ce)) {
2015             ce.removeListener(fn, scope);
2016         }
2017     },
2018
2019     /**
2020      * Removes all listeners for this object
2021      */
2022     purgeListeners : function(){
2023         var events = this.events,
2024             evt,
2025             key;
2026         for(key in events){
2027             evt = events[key];
2028             if(ISOBJECT(evt)){
2029                 evt.clearListeners();
2030             }
2031         }
2032     },
2033
2034     /**
2035      * Adds the specified events to the list of events which this Observable may fire.
2036      * @param {Object|String} o Either an object with event names as properties with a value of <code>true</code>
2037      * or the first event name string if multiple event names are being passed as separate parameters.
2038      * @param {string} Optional. Event name if multiple event names are being passed as separate parameters.
2039      * Usage:<pre><code>
2040 this.addEvents('storeloaded', 'storecleared');
2041 </code></pre>
2042      */
2043     addEvents : function(o){
2044         var me = this;
2045         me.events = me.events || {};
2046         if (Ext.isString(o)) {
2047             EACH(arguments, function(a) {
2048                 me.events[a] = me.events[a] || TRUE;
2049             });
2050         } else {
2051             Ext.applyIf(me.events, o);
2052         }
2053     },
2054
2055     /**
2056      * Checks to see if this object has any listeners for a specified event
2057      * @param {String} eventName The name of the event to check for
2058      * @return {Boolean} True if the event is being listened for, else false
2059      */
2060     hasListener : function(eventName){
2061         var e = this.events[eventName];
2062         return ISOBJECT(e) && e.listeners.length > 0;
2063     },
2064
2065     /**
2066      * Suspend the firing of all events. (see {@link #resumeEvents})
2067      * @param {Boolean} queueSuspended Pass as true to queue up suspended events to be fired
2068      * after the {@link #resumeEvents} call instead of discarding all suspended events;
2069      */
2070     suspendEvents : function(queueSuspended){
2071         this.eventsSuspended = TRUE;
2072         if(queueSuspended && !this.eventQueue){
2073             this.eventQueue = [];
2074         }
2075     },
2076
2077     /**
2078      * Resume firing events. (see {@link #suspendEvents})
2079      * If events were suspended using the <tt><b>queueSuspended</b></tt> parameter, then all
2080      * events fired during event suspension will be sent to any listeners now.
2081      */
2082     resumeEvents : function(){
2083         var me = this,
2084             queued = me.eventQueue || [];
2085         me.eventsSuspended = FALSE;
2086         delete me.eventQueue;
2087         EACH(queued, function(e) {
2088             me.fireEvent.apply(me, e);
2089         });
2090     }
2091 };
2092
2093 var OBSERVABLE = EXTUTIL.Observable.prototype;
2094 /**
2095  * Appends an event handler to this object (shorthand for {@link #addListener}.)
2096  * @param {String}   eventName     The type of event to listen for
2097  * @param {Function} handler       The method the event invokes
2098  * @param {Object}   scope         (optional) The scope (<code><b>this</b></code> reference) in which the handler function is executed.
2099  * <b>If omitted, defaults to the object which fired the event.</b>
2100  * @param {Object}   options       (optional) An object containing handler configuration.
2101  * @method
2102  */
2103 OBSERVABLE.on = OBSERVABLE.addListener;
2104 /**
2105  * Removes an event handler (shorthand for {@link #removeListener}.)
2106  * @param {String}   eventName     The type of event the handler was associated with.
2107  * @param {Function} handler       The handler to remove. <b>This must be a reference to the function passed into the {@link #addListener} call.</b>
2108  * @param {Object}   scope         (optional) The scope originally specified for the handler.
2109  * @method
2110  */
2111 OBSERVABLE.un = OBSERVABLE.removeListener;
2112
2113 /**
2114  * Removes <b>all</b> added captures from the Observable.
2115  * @param {Observable} o The Observable to release
2116  * @static
2117  */
2118 EXTUTIL.Observable.releaseCapture = function(o){
2119     o.fireEvent = OBSERVABLE.fireEvent;
2120 };
2121
2122 function createTargeted(h, o, scope){
2123     return function(){
2124         if(o.target == arguments[0]){
2125             h.apply(scope, TOARRAY(arguments));
2126         }
2127     };
2128 };
2129
2130 function createBuffered(h, o, scope){
2131     var task = new EXTUTIL.DelayedTask();
2132     return function(){
2133         task.delay(o.buffer, h, scope, TOARRAY(arguments));
2134     };
2135 }
2136
2137 function createSingle(h, e, fn, scope){
2138     return function(){
2139         e.removeListener(fn, scope);
2140         return h.apply(scope, arguments);
2141     };
2142 }
2143
2144 function createDelayed(h, o, scope){
2145     return function(){
2146         var args = TOARRAY(arguments);
2147         (function(){
2148             h.apply(scope, args);
2149         }).defer(o.delay || 10);
2150     };
2151 };
2152
2153 EXTUTIL.Event = function(obj, name){
2154     this.name = name;
2155     this.obj = obj;
2156     this.listeners = [];
2157 };
2158
2159 EXTUTIL.Event.prototype = {
2160     addListener : function(fn, scope, options){
2161         var me = this,
2162             l;
2163         scope = scope || me.obj;
2164         if(!me.isListening(fn, scope)){
2165             l = me.createListener(fn, scope, options);
2166             if(me.firing){ // if we are currently firing this event, don't disturb the listener loop
2167                 me.listeners = me.listeners.slice(0);
2168             }
2169             me.listeners.push(l);
2170         }
2171     },
2172
2173     createListener: function(fn, scope, o){
2174         o = o || {}, scope = scope || this.obj;
2175         var l = {
2176             fn: fn,
2177             scope: scope,
2178             options: o
2179         }, h = fn;
2180         if(o.target){
2181             h = createTargeted(h, o, scope);
2182         }
2183         if(o.delay){
2184             h = createDelayed(h, o, scope);
2185         }
2186         if(o.single){
2187             h = createSingle(h, this, fn, scope);
2188         }
2189         if(o.buffer){
2190             h = createBuffered(h, o, scope);
2191         }
2192         l.fireFn = h;
2193         return l;
2194     },
2195
2196     findListener : function(fn, scope){
2197         var s, ret = -1;
2198         EACH(this.listeners, function(l, i) {
2199             s = l.scope;
2200             if(l.fn == fn && (s == scope || s == this.obj)){
2201                 ret = i;
2202                 return FALSE;
2203             }
2204         },
2205         this);
2206         return ret;
2207     },
2208
2209     isListening : function(fn, scope){
2210         return this.findListener(fn, scope) != -1;
2211     },
2212
2213     removeListener : function(fn, scope){
2214         var index,
2215             me = this,
2216             ret = FALSE;
2217         if((index = me.findListener(fn, scope)) != -1){
2218             if (me.firing) {
2219                 me.listeners = me.listeners.slice(0);
2220             }
2221             me.listeners.splice(index, 1);
2222             ret = TRUE;
2223         }
2224         return ret;
2225     },
2226
2227     clearListeners : function(){
2228         this.listeners = [];
2229     },
2230
2231     fire : function(){
2232         var me = this,
2233             args = TOARRAY(arguments),
2234             ret = TRUE;
2235
2236         EACH(me.listeners, function(l) {
2237             me.firing = TRUE;
2238             if (l.fireFn.apply(l.scope || me.obj || window, args) === FALSE) {
2239                 return ret = me.firing = FALSE;
2240             }
2241         });
2242         me.firing = FALSE;
2243         return ret;
2244     }
2245 };
2246 })();/**\r
2247  * @class Ext.util.Observable\r
2248  */\r
2249 Ext.apply(Ext.util.Observable.prototype, function(){    \r
2250     // this is considered experimental (along with beforeMethod, afterMethod, removeMethodListener?)\r
2251     // allows for easier interceptor and sequences, including cancelling and overwriting the return value of the call\r
2252     // private\r
2253     function getMethodEvent(method){\r
2254         var e = (this.methodEvents = this.methodEvents ||\r
2255         {})[method], returnValue, v, cancel, obj = this;\r
2256         \r
2257         if (!e) {\r
2258             this.methodEvents[method] = e = {};\r
2259             e.originalFn = this[method];\r
2260             e.methodName = method;\r
2261             e.before = [];\r
2262             e.after = [];\r
2263             \r
2264             var makeCall = function(fn, scope, args){\r
2265                 if (!Ext.isEmpty(v = fn.apply(scope || obj, args))) {\r
2266                     if (Ext.isObject(v)) {\r
2267                         returnValue = !Ext.isEmpty(v.returnValue) ? v.returnValue : v;\r
2268                         cancel = !!v.cancel;\r
2269                     }\r
2270                     else \r
2271                         if (v === false) {\r
2272                             cancel = true;\r
2273                         }\r
2274                         else {\r
2275                             returnValue = v;\r
2276                         }\r
2277                 }\r
2278             };\r
2279             \r
2280             this[method] = function(){\r
2281                 var args = Ext.toArray(arguments);\r
2282                 returnValue = v = undefined;\r
2283                 cancel = false;\r
2284                 \r
2285                 Ext.each(e.before, function(b){\r
2286                     makeCall(b.fn, b.scope, args);\r
2287                     if (cancel) {\r
2288                         return returnValue;\r
2289                     }\r
2290                 });\r
2291                 \r
2292                 if (!Ext.isEmpty(v = e.originalFn.apply(obj, args))) {\r
2293                     returnValue = v;\r
2294                 }\r
2295                 Ext.each(e.after, function(a){\r
2296                     makeCall(a.fn, a.scope, args);\r
2297                     if (cancel) {\r
2298                         return returnValue;\r
2299                     }\r
2300                 });\r
2301                 return returnValue;\r
2302             };\r
2303         }\r
2304         return e;\r
2305     }\r
2306     \r
2307     return {\r
2308         // these are considered experimental\r
2309         // allows for easier interceptor and sequences, including cancelling and overwriting the return value of the call\r
2310         // adds an "interceptor" called before the original method\r
2311         beforeMethod: function(method, fn, scope){\r
2312             getMethodEvent.call(this, method).before.push({\r
2313                 fn: fn,\r
2314                 scope: scope\r
2315             });\r
2316         },\r
2317         \r
2318         // adds a "sequence" called after the original method\r
2319         afterMethod: function(method, fn, scope){\r
2320             getMethodEvent.call(this, method).after.push({\r
2321                 fn: fn,\r
2322                 scope: scope\r
2323             });\r
2324         },\r
2325         \r
2326         removeMethodListener: function(method, fn, scope){\r
2327             var e = getMethodEvent.call(this, method), found = false;\r
2328             Ext.each(e.before, function(b, i, arr){\r
2329                 if (b.fn == fn && b.scope == scope) {\r
2330                     arr.splice(i, 1);\r
2331                     found = true;\r
2332                     return false;\r
2333                 }\r
2334             });\r
2335             if (!found) {\r
2336                 Ext.each(e.after, function(a, i, arr){\r
2337                     if (a.fn == fn && a.scope == scope) {\r
2338                         arr.splice(i, 1);\r
2339                         return false;\r
2340                     }\r
2341                 });\r
2342             }\r
2343         },\r
2344         \r
2345         /**\r
2346          * Relays selected events from the specified Observable as if the events were fired by <tt><b>this</b></tt>.\r
2347          * @param {Object} o The Observable whose events this object is to relay.\r
2348          * @param {Array} events Array of event names to relay.\r
2349          */\r
2350         relayEvents: function(o, events){\r
2351             var me = this;\r
2352             function createHandler(ename){\r
2353                 return function(){\r
2354                     return me.fireEvent.apply(me, [ename].concat(Ext.toArray(arguments)));\r
2355                 };\r
2356             }\r
2357             Ext.each(events, function(ename){\r
2358                 me.events[ename] = me.events[ename] || true;\r
2359                 o.on(ename, createHandler(ename), me);\r
2360             });\r
2361         },\r
2362         \r
2363         /**\r
2364          * <p>Enables events fired by this Observable to bubble up an owner hierarchy by calling\r
2365          * <code>this.getBubbleTarget()</code> if present. There is no implementation in the Observable base class.</p>\r
2366          * <p>This is commonly used by Ext.Components to bubble events to owner Containers. See {@link Ext.Component.getBubbleTarget}. The default\r
2367          * implementation in Ext.Component returns the Component's immediate owner. But if a known target is required, this can be overridden to\r
2368          * access the required target more quickly.</p>\r
2369          * <p>Example:</p><pre><code>\r
2370 Ext.override(Ext.form.Field, {\r
2371 //  Add functionality to Field's initComponent to enable the change event to bubble\r
2372     initComponent: Ext.form.Field.prototype.initComponent.createSequence(function() {\r
2373         this.enableBubble('change');\r
2374     }),\r
2375 \r
2376 //  We know that we want Field's events to bubble directly to the FormPanel.\r
2377     getBubbleTarget: function() {\r
2378         if (!this.formPanel) {\r
2379             this.formPanel = this.findParentByType('form');\r
2380         }\r
2381         return this.formPanel;\r
2382     }\r
2383 });\r
2384 \r
2385 var myForm = new Ext.formPanel({\r
2386     title: 'User Details',\r
2387     items: [{\r
2388         ...\r
2389     }],\r
2390     listeners: {\r
2391         change: function() {\r
2392 //          Title goes red if form has been modified.\r
2393             myForm.header.setStyle("color", "red");\r
2394         }\r
2395     }\r
2396 });\r
2397 </code></pre>\r
2398          * @param {Object} events The event name to bubble, or an Array of event names.\r
2399          */\r
2400         enableBubble: function(events){\r
2401             var me = this;\r
2402             if(!Ext.isEmpty(events)){\r
2403                 events = Ext.isArray(events) ? events : Ext.toArray(arguments);\r
2404                 Ext.each(events, function(ename){\r
2405                     ename = ename.toLowerCase();\r
2406                     var ce = me.events[ename] || true;\r
2407                     if (Ext.isBoolean(ce)) {\r
2408                         ce = new Ext.util.Event(me, ename);\r
2409                         me.events[ename] = ce;\r
2410                     }\r
2411                     ce.bubble = true;\r
2412                 });\r
2413             }\r
2414         }\r
2415     };\r
2416 }());\r
2417 \r
2418 \r
2419 /**\r
2420  * Starts capture on the specified Observable. All events will be passed\r
2421  * to the supplied function with the event name + standard signature of the event\r
2422  * <b>before</b> the event is fired. If the supplied function returns false,\r
2423  * the event will not fire.\r
2424  * @param {Observable} o The Observable to capture\r
2425  * @param {Function} fn The function to call\r
2426  * @param {Object} scope (optional) The scope (this object) for the fn\r
2427  * @static\r
2428  */\r
2429 Ext.util.Observable.capture = function(o, fn, scope){\r
2430     o.fireEvent = o.fireEvent.createInterceptor(fn, scope);\r
2431 };\r
2432 \r
2433 \r
2434 /**\r
2435  * Sets observability on the passed class constructor.<p>\r
2436  * <p>This makes any event fired on any instance of the passed class also fire a single event through\r
2437  * the <i>class</i> allowing for central handling of events on many instances at once.</p>\r
2438  * <p>Usage:</p><pre><code>\r
2439 Ext.util.Observable.observeClass(Ext.data.Connection);\r
2440 Ext.data.Connection.on('beforerequest', function(con, options) {\r
2441     console.log("Ajax request made to " + options.url);\r
2442 });</code></pre>\r
2443  * @param {Function} c The class constructor to make observable.\r
2444  * @static\r
2445  */\r
2446 Ext.util.Observable.observeClass = function(c){\r
2447     Ext.apply(c, new Ext.util.Observable());\r
2448     c.prototype.fireEvent = function(){\r
2449         return (c.fireEvent.apply(c, arguments) !== false) &&\r
2450         (Ext.util.Observable.prototype.fireEvent.apply(this, arguments) !== false);\r
2451     };\r
2452 };/**
2453  * @class Ext.EventManager
2454  * Registers event handlers that want to receive a normalized EventObject instead of the standard browser event and provides
2455  * several useful events directly.
2456  * See {@link Ext.EventObject} for more details on normalized event objects.
2457  * @singleton
2458  */
2459 Ext.EventManager = function(){
2460     var docReadyEvent, 
2461         docReadyProcId, 
2462         docReadyState = false,        
2463         E = Ext.lib.Event,
2464         D = Ext.lib.Dom,
2465         DOC = document,
2466         WINDOW = window,
2467         IEDEFERED = "ie-deferred-loader",
2468         DOMCONTENTLOADED = "DOMContentLoaded",
2469         elHash = {},
2470         propRe = /^(?:scope|delay|buffer|single|stopEvent|preventDefault|stopPropagation|normalized|args|delegate)$/;
2471
2472     /// There is some jquery work around stuff here that isn't needed in Ext Core.
2473     function addListener(el, ename, fn, wrap, scope){        
2474         var id = Ext.id(el),
2475             es = elHash[id] = elHash[id] || {};         
2476        
2477         (es[ename] = es[ename] || []).push([fn, wrap, scope]);
2478         E.on(el, ename, wrap);
2479
2480         // this is a workaround for jQuery and should somehow be removed from Ext Core in the future
2481         // without breaking ExtJS.
2482         if(ename == "mousewheel" && el.addEventListener){ // workaround for jQuery
2483             var args = ["DOMMouseScroll", wrap, false];
2484             el.addEventListener.apply(el, args);
2485             E.on(window, 'unload', function(){
2486                 el.removeEventListener.apply(el, args);                
2487             });
2488         }
2489         if(ename == "mousedown" && el == document){ // fix stopped mousedowns on the document
2490             Ext.EventManager.stoppedMouseDownEvent.addListener(wrap);
2491         }
2492     };
2493     
2494     function fireDocReady(){
2495         if(!docReadyState){            
2496             Ext.isReady = docReadyState = true;
2497             if(docReadyProcId){
2498                 clearInterval(docReadyProcId);
2499             }
2500             if(Ext.isGecko || Ext.isOpera) {
2501                 DOC.removeEventListener(DOMCONTENTLOADED, fireDocReady, false);
2502             }
2503             if(Ext.isIE){
2504                 var defer = DOC.getElementById(IEDEFERED);
2505                 if(defer){
2506                     defer.onreadystatechange = null;
2507                     defer.parentNode.removeChild(defer);
2508                 }
2509             }
2510             if(docReadyEvent){
2511                 docReadyEvent.fire();
2512                 docReadyEvent.clearListeners();
2513             }
2514         }
2515     };
2516
2517     function initDocReady(){
2518         var COMPLETE = "complete";
2519             
2520         docReadyEvent = new Ext.util.Event();
2521         if (Ext.isGecko || Ext.isOpera) {
2522             DOC.addEventListener(DOMCONTENTLOADED, fireDocReady, false);
2523         } else if (Ext.isIE){
2524             DOC.write("<s"+'cript id=' + IEDEFERED + ' defer="defer" src="/'+'/:"></s'+"cript>");            
2525             DOC.getElementById(IEDEFERED).onreadystatechange = function(){
2526                 if(this.readyState == COMPLETE){
2527                     fireDocReady();
2528                 }
2529             };
2530         } else if (Ext.isWebKit){
2531             docReadyProcId = setInterval(function(){                
2532                 if(DOC.readyState == COMPLETE) {
2533                     fireDocReady();
2534                  }
2535             }, 10);
2536         }
2537         // no matter what, make sure it fires on load
2538         E.on(WINDOW, "load", fireDocReady);
2539     };
2540
2541     function createTargeted(h, o){
2542         return function(){
2543             var args = Ext.toArray(arguments);
2544             if(o.target == Ext.EventObject.setEvent(args[0]).target){
2545                 h.apply(this, args);
2546             }
2547         };
2548     };    
2549     
2550     function createBuffered(h, o){
2551         var task = new Ext.util.DelayedTask(h);
2552         return function(e){
2553             // create new event object impl so new events don't wipe out properties            
2554             task.delay(o.buffer, h, null, [new Ext.EventObjectImpl(e)]);
2555         };
2556     };
2557
2558     function createSingle(h, el, ename, fn, scope){
2559         return function(e){
2560             Ext.EventManager.removeListener(el, ename, fn, scope);
2561             h(e);
2562         };
2563     };
2564
2565     function createDelayed(h, o){
2566         return function(e){
2567             // create new event object impl so new events don't wipe out properties   
2568             e = new Ext.EventObjectImpl(e);
2569             setTimeout(function(){
2570                 h(e);
2571             }, o.delay || 10);
2572         };
2573     };
2574
2575     function listen(element, ename, opt, fn, scope){
2576         var o = !Ext.isObject(opt) ? {} : opt,
2577             el = Ext.getDom(element);
2578             
2579         fn = fn || o.fn; 
2580         scope = scope || o.scope;
2581         
2582         if(!el){
2583             throw "Error listening for \"" + ename + '\". Element "' + element + '" doesn\'t exist.';
2584         }
2585         function h(e){
2586             // prevent errors while unload occurring
2587             if(!Ext){// !window[xname]){  ==> can't we do this? 
2588                 return;
2589             }
2590             e = Ext.EventObject.setEvent(e);
2591             var t;
2592             if (o.delegate) {
2593                 if(!(t = e.getTarget(o.delegate, el))){
2594                     return;
2595                 }
2596             } else {
2597                 t = e.target;
2598             }            
2599             if (o.stopEvent) {
2600                 e.stopEvent();
2601             }
2602             if (o.preventDefault) {
2603                e.preventDefault();
2604             }
2605             if (o.stopPropagation) {
2606                 e.stopPropagation();
2607             }
2608             if (o.normalized) {
2609                 e = e.browserEvent;
2610             }
2611             
2612             fn.call(scope || el, e, t, o);
2613         };
2614         if(o.target){
2615             h = createTargeted(h, o);
2616         }
2617         if(o.delay){
2618             h = createDelayed(h, o);
2619         }
2620         if(o.single){
2621             h = createSingle(h, el, ename, fn, scope);
2622         }
2623         if(o.buffer){
2624             h = createBuffered(h, o);
2625         }
2626
2627         addListener(el, ename, fn, h, scope);
2628         return h;
2629     };
2630
2631     var pub = {
2632         /**
2633          * Appends an event handler to an element.  The shorthand version {@link #on} is equivalent.  Typically you will
2634          * use {@link Ext.Element#addListener} directly on an Element in favor of calling this version.
2635          * @param {String/HTMLElement} el The html element or id to assign the event handler to.
2636          * @param {String} eventName The name of the event to listen for.
2637          * @param {Function} handler The handler function the event invokes. This function is passed
2638          * the following parameters:<ul>
2639          * <li>evt : EventObject<div class="sub-desc">The {@link Ext.EventObject EventObject} describing the event.</div></li>
2640          * <li>t : Element<div class="sub-desc">The {@link Ext.Element Element} which was the target of the event.
2641          * Note that this may be filtered by using the <tt>delegate</tt> option.</div></li>
2642          * <li>o : Object<div class="sub-desc">The options object from the addListener call.</div></li>
2643          * </ul>
2644          * @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>.
2645          * @param {Object} options (optional) An object containing handler configuration properties.
2646          * This may contain any of the following properties:<ul>
2647          * <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>
2648          * <li>delegate : String<div class="sub-desc">A simple selector to filter the target or look for a descendant of the target</div></li>
2649          * <li>stopEvent : Boolean<div class="sub-desc">True to stop the event. That is stop propagation, and prevent the default action.</div></li>
2650          * <li>preventDefault : Boolean<div class="sub-desc">True to prevent the default action</div></li>
2651          * <li>stopPropagation : Boolean<div class="sub-desc">True to prevent event propagation</div></li>
2652          * <li>normalized : Boolean<div class="sub-desc">False to pass a browser event to the handler function instead of an Ext.EventObject</div></li>
2653          * <li>delay : Number<div class="sub-desc">The number of milliseconds to delay the invocation of the handler after te event fires.</div></li>
2654          * <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>
2655          * <li>buffer : Number<div class="sub-desc">Causes the handler to be scheduled to run in an {@link Ext.util.DelayedTask} delayed
2656          * by the specified number of milliseconds. If the event fires again within that time, the original
2657          * handler is <em>not</em> invoked, but the new handler is scheduled in its place.</div></li>
2658          * <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>
2659          * </ul><br>
2660          * <p>See {@link Ext.Element#addListener} for examples of how to use these options.</p>
2661          */
2662         addListener : function(element, eventName, fn, scope, options){                                       
2663             if(Ext.isObject(eventName)){                
2664                 var o = eventName, e, val;
2665                 for(e in o){
2666                     val = o[e];
2667                     if(!propRe.test(e)){                                             
2668                         if(Ext.isFunction(val)){
2669                             // shared options
2670                             listen(element, e, o, val, o.scope);
2671                         }else{
2672                             // individual options
2673                             listen(element, e, val);
2674                         }
2675                     }
2676                 }
2677             } else {
2678                 listen(element, eventName, options, fn, scope);
2679             }
2680         },
2681         
2682         /**
2683          * Removes an event handler from an element.  The shorthand version {@link #un} is equivalent.  Typically
2684          * you will use {@link Ext.Element#removeListener} directly on an Element in favor of calling this version.
2685          * @param {String/HTMLElement} el The id or html element from which to remove the listener.
2686          * @param {String} eventName The name of the event.
2687          * @param {Function} fn The handler function to remove. <b>This must be a reference to the function passed into the {@link #addListener} call.</b>
2688          * @param {Object} scope If a scope (<b><code>this</code></b> reference) was specified when the listener was added,
2689          * then this must refer to the same object.
2690          */
2691         removeListener : function(element, eventName, fn, scope){            
2692             var el = Ext.getDom(element),
2693                 id = Ext.id(el),
2694                 wrap;      
2695             
2696             Ext.each((elHash[id] || {})[eventName], function (v,i,a) {
2697                 if (Ext.isArray(v) && v[0] == fn && (!scope || v[2] == scope)) {                                    
2698                     E.un(el, eventName, wrap = v[1]);
2699                     a.splice(i,1);
2700                     return false;                    
2701                 }
2702             });    
2703
2704             // jQuery workaround that should be removed from Ext Core
2705             if(eventName == "mousewheel" && el.addEventListener && wrap){
2706                 el.removeEventListener("DOMMouseScroll", wrap, false);
2707             }
2708                         
2709             if(eventName == "mousedown" && el == DOC && wrap){ // fix stopped mousedowns on the document
2710                 Ext.EventManager.stoppedMouseDownEvent.removeListener(wrap);
2711             }
2712         },
2713         
2714         /**
2715          * Removes all event handers from an element.  Typically you will use {@link Ext.Element#removeAllListeners}
2716          * directly on an Element in favor of calling this version.
2717          * @param {String/HTMLElement} el The id or html element from which to remove all event handlers.
2718          */
2719         removeAll : function(el){
2720             var id = Ext.id(el = Ext.getDom(el)), 
2721                 es = elHash[id],                 
2722                 ename;
2723            
2724             for(ename in es){
2725                 if(es.hasOwnProperty(ename)){                        
2726                     Ext.each(es[ename], function(v) {
2727                         E.un(el, ename, v.wrap);                    
2728                     });
2729                 }            
2730             }
2731             elHash[id] = null;       
2732         },
2733
2734         /**
2735          * Adds a listener to be notified when the document is ready (before onload and before images are loaded). Can be
2736          * accessed shorthanded as Ext.onReady().
2737          * @param {Function} fn The method the event invokes.
2738          * @param {Object} scope (optional) The scope (<code>this</code> reference) in which the handler function executes. Defaults to the browser window.
2739          * @param {boolean} options (optional) Options object as passed to {@link Ext.Element#addListener}. It is recommended that the options
2740          * <code>{single: true}</code> be used so that the handler is removed on first invocation.
2741          */
2742         onDocumentReady : function(fn, scope, options){
2743             if(docReadyState){ // if it already fired
2744                 docReadyEvent.addListener(fn, scope, options);
2745                 docReadyEvent.fire();
2746                 docReadyEvent.clearListeners();               
2747             } else {
2748                 if(!docReadyEvent) initDocReady();
2749                 options = options || {};
2750                 options.delay = options.delay || 1;                
2751                 docReadyEvent.addListener(fn, scope, options);
2752             }
2753         },
2754         
2755         elHash : elHash   
2756     };
2757      /**
2758      * Appends an event handler to an element.  Shorthand for {@link #addListener}.
2759      * @param {String/HTMLElement} el The html element or id to assign the event handler to
2760      * @param {String} eventName The name of the event to listen for.
2761      * @param {Function} handler The handler function the event invokes.
2762      * @param {Object} scope (optional) (<code>this</code> reference) in which the handler function executes. <b>Defaults to the Element</b>.
2763      * @param {Object} options (optional) An object containing standard {@link #addListener} options
2764      * @member Ext.EventManager
2765      * @method on
2766      */
2767     pub.on = pub.addListener;
2768     /**
2769      * Removes an event handler from an element.  Shorthand for {@link #removeListener}.
2770      * @param {String/HTMLElement} el The id or html element from which to remove the listener.
2771      * @param {String} eventName The name of the event.
2772      * @param {Function} fn The handler function to remove. <b>This must be a reference to the function passed into the {@link #on} call.</b>
2773      * @param {Object} scope If a scope (<b><code>this</code></b> reference) was specified when the listener was added,
2774      * then this must refer to the same object.
2775      * @member Ext.EventManager
2776      * @method un
2777      */
2778     pub.un = pub.removeListener;
2779
2780     pub.stoppedMouseDownEvent = new Ext.util.Event();
2781     return pub;
2782 }();
2783 /**
2784   * Adds a listener to be notified when the document is ready (before onload and before images are loaded). Shorthand of {@link Ext.EventManager#onDocumentReady}.
2785   * @param {Function} fn The method the event invokes.
2786   * @param {Object} scope (optional) The scope (<code>this</code> reference) in which the handler function executes. Defaults to the browser window.
2787   * @param {boolean} options (optional) Options object as passed to {@link Ext.Element#addListener}. It is recommended that the options
2788   * <code>{single: true}</code> be used so that the handler is removed on first invocation.
2789   * @member Ext
2790   * @method onReady
2791  */
2792 Ext.onReady = Ext.EventManager.onDocumentReady;
2793
2794
2795 //Initialize doc classes
2796 (function(){
2797     
2798     var initExtCss = function(){
2799         // find the body element
2800         var bd = document.body || document.getElementsByTagName('body')[0];
2801         if(!bd){ return false; }
2802         var cls = [' ',
2803                 Ext.isIE ? "ext-ie " + (Ext.isIE6 ? 'ext-ie6' : (Ext.isIE7 ? 'ext-ie7' : 'ext-ie8'))
2804                 : Ext.isGecko ? "ext-gecko " + (Ext.isGecko2 ? 'ext-gecko2' : 'ext-gecko3')
2805                 : Ext.isOpera ? "ext-opera"
2806                 : Ext.isWebKit ? "ext-webkit" : ""];
2807
2808         if(Ext.isSafari){
2809             cls.push("ext-safari " + (Ext.isSafari2 ? 'ext-safari2' : (Ext.isSafari3 ? 'ext-safari3' : 'ext-safari4')));
2810         }else if(Ext.isChrome){
2811             cls.push("ext-chrome");
2812         }
2813
2814         if(Ext.isMac){
2815             cls.push("ext-mac");
2816         }
2817         if(Ext.isLinux){
2818             cls.push("ext-linux");
2819         }
2820
2821         if(Ext.isStrict || Ext.isBorderBox){ // add to the parent to allow for selectors like ".ext-strict .ext-ie"
2822             var p = bd.parentNode;
2823             if(p){
2824                 p.className += Ext.isStrict ? ' ext-strict' : ' ext-border-box';
2825             }
2826         }
2827         bd.className += cls.join(' ');
2828         return true;
2829     }
2830
2831     if(!initExtCss()){
2832         Ext.onReady(initExtCss);
2833     }
2834 })();
2835
2836
2837 /**
2838  * @class Ext.EventObject
2839  * Just as {@link Ext.Element} wraps around a native DOM node, Ext.EventObject 
2840  * wraps the browser's native event-object normalizing cross-browser differences,
2841  * such as which mouse button is clicked, keys pressed, mechanisms to stop
2842  * event-propagation along with a method to prevent default actions from taking place.
2843  * <p>For example:</p>
2844  * <pre><code>
2845 function handleClick(e, t){ // e is not a standard event object, it is a Ext.EventObject
2846     e.preventDefault();
2847     var target = e.getTarget(); // same as t (the target HTMLElement)
2848     ...
2849 }
2850 var myDiv = {@link Ext#get Ext.get}("myDiv");  // get reference to an {@link Ext.Element}
2851 myDiv.on(         // 'on' is shorthand for addListener
2852     "click",      // perform an action on click of myDiv
2853     handleClick   // reference to the action handler
2854 );  
2855 // other methods to do the same:
2856 Ext.EventManager.on("myDiv", 'click', handleClick);
2857 Ext.EventManager.addListener("myDiv", 'click', handleClick);
2858  </code></pre>
2859  * @singleton
2860  */
2861 Ext.EventObject = function(){
2862     var E = Ext.lib.Event,
2863         // safari keypress events for special keys return bad keycodes
2864         safariKeys = {
2865             3 : 13, // enter
2866             63234 : 37, // left
2867             63235 : 39, // right
2868             63232 : 38, // up
2869             63233 : 40, // down
2870             63276 : 33, // page up
2871             63277 : 34, // page down
2872             63272 : 46, // delete
2873             63273 : 36, // home
2874             63275 : 35  // end
2875         },
2876         // normalize button clicks
2877         btnMap = Ext.isIE ? {1:0,4:1,2:2} :
2878                 (Ext.isWebKit ? {1:0,2:1,3:2} : {0:0,1:1,2:2});
2879
2880     Ext.EventObjectImpl = function(e){
2881         if(e){
2882             this.setEvent(e.browserEvent || e);
2883         }
2884     };
2885
2886     Ext.EventObjectImpl.prototype = {
2887            /** @private */
2888         setEvent : function(e){
2889             var me = this;
2890             if(e == me || (e && e.browserEvent)){ // already wrapped
2891                 return e;
2892             }
2893             me.browserEvent = e;
2894             if(e){
2895                 // normalize buttons
2896                 me.button = e.button ? btnMap[e.button] : (e.which ? e.which - 1 : -1);
2897                 if(e.type == 'click' && me.button == -1){
2898                     me.button = 0;
2899                 }
2900                 me.type = e.type;
2901                 me.shiftKey = e.shiftKey;
2902                 // mac metaKey behaves like ctrlKey
2903                 me.ctrlKey = e.ctrlKey || e.metaKey || false;
2904                 me.altKey = e.altKey;
2905                 // in getKey these will be normalized for the mac
2906                 me.keyCode = e.keyCode;
2907                 me.charCode = e.charCode;
2908                 // cache the target for the delayed and or buffered events
2909                 me.target = E.getTarget(e);
2910                 // same for XY
2911                 me.xy = E.getXY(e);
2912             }else{
2913                 me.button = -1;
2914                 me.shiftKey = false;
2915                 me.ctrlKey = false;
2916                 me.altKey = false;
2917                 me.keyCode = 0;
2918                 me.charCode = 0;
2919                 me.target = null;
2920                 me.xy = [0, 0];
2921             }
2922             return me;
2923         },
2924
2925         /**
2926          * Stop the event (preventDefault and stopPropagation)
2927          */
2928         stopEvent : function(){
2929             var me = this;
2930             if(me.browserEvent){
2931                 if(me.browserEvent.type == 'mousedown'){
2932                     Ext.EventManager.stoppedMouseDownEvent.fire(me);
2933                 }
2934                 E.stopEvent(me.browserEvent);
2935             }
2936         },
2937
2938         /**
2939          * Prevents the browsers default handling of the event.
2940          */
2941         preventDefault : function(){
2942             if(this.browserEvent){
2943                 E.preventDefault(this.browserEvent);
2944             }
2945         },        
2946
2947         /**
2948          * Cancels bubbling of the event.
2949          */
2950         stopPropagation : function(){
2951             var me = this;
2952             if(me.browserEvent){
2953                 if(me.browserEvent.type == 'mousedown'){
2954                     Ext.EventManager.stoppedMouseDownEvent.fire(me);
2955                 }
2956                 E.stopPropagation(me.browserEvent);
2957             }
2958         },
2959
2960         /**
2961          * Gets the character code for the event.
2962          * @return {Number}
2963          */
2964         getCharCode : function(){
2965             return this.charCode || this.keyCode;
2966         },
2967
2968         /**
2969          * Returns a normalized keyCode for the event.
2970          * @return {Number} The key code
2971          */
2972         getKey : function(){
2973             return this.normalizeKey(this.keyCode || this.charCode)
2974         },
2975         
2976         // private
2977         normalizeKey: function(k){
2978             return Ext.isSafari ? (safariKeys[k] || k) : k; 
2979         },
2980
2981         /**
2982          * Gets the x coordinate of the event.
2983          * @return {Number}
2984          */
2985         getPageX : function(){
2986             return this.xy[0];
2987         },
2988
2989         /**
2990          * Gets the y coordinate of the event.
2991          * @return {Number}
2992          */
2993         getPageY : function(){
2994             return this.xy[1];
2995         },
2996
2997         /**
2998          * Gets the page coordinates of the event.
2999          * @return {Array} The xy values like [x, y]
3000          */
3001         getXY : function(){
3002             return this.xy;
3003         },
3004
3005         /**
3006          * Gets the target for the event.
3007          * @param {String} selector (optional) A simple selector to filter the target or look for an ancestor of the target
3008          * @param {Number/Mixed} maxDepth (optional) The max depth to
3009                 search as a number or element (defaults to 10 || document.body)
3010          * @param {Boolean} returnEl (optional) True to return a Ext.Element object instead of DOM node
3011          * @return {HTMLelement}
3012          */
3013         getTarget : function(selector, maxDepth, returnEl){
3014             return selector ? Ext.fly(this.target).findParent(selector, maxDepth, returnEl) : (returnEl ? Ext.get(this.target) : this.target);
3015         },
3016
3017         /**
3018          * Gets the related target.
3019          * @return {HTMLElement}
3020          */
3021         getRelatedTarget : function(){
3022             return this.browserEvent ? E.getRelatedTarget(this.browserEvent) : null;
3023         },
3024
3025         /**
3026          * Normalizes mouse wheel delta across browsers
3027          * @return {Number} The delta
3028          */
3029         getWheelDelta : function(){
3030             var e = this.browserEvent;
3031             var delta = 0;
3032             if(e.wheelDelta){ /* IE/Opera. */
3033                 delta = e.wheelDelta/120;
3034             }else if(e.detail){ /* Mozilla case. */
3035                 delta = -e.detail/3;
3036             }
3037             return delta;
3038         },
3039         
3040         /**
3041         * 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.
3042         * Example usage:<pre><code>
3043         // Handle click on any child of an element
3044         Ext.getBody().on('click', function(e){
3045             if(e.within('some-el')){
3046                 alert('Clicked on a child of some-el!');
3047             }
3048         });
3049         
3050         // Handle click directly on an element, ignoring clicks on child nodes
3051         Ext.getBody().on('click', function(e,t){
3052             if((t.id == 'some-el') && !e.within(t, true)){
3053                 alert('Clicked directly on some-el!');
3054             }
3055         });
3056         </code></pre>
3057          * @param {Mixed} el The id, DOM element or Ext.Element to check
3058          * @param {Boolean} related (optional) true to test if the related target is within el instead of the target
3059          * @param {Boolean} allowEl {optional} true to also check if the passed element is the target or related target
3060          * @return {Boolean}
3061          */
3062         within : function(el, related, allowEl){
3063             if(el){
3064                 var t = this[related ? "getRelatedTarget" : "getTarget"]();
3065                 return t && ((allowEl ? (t == Ext.getDom(el)) : false) || Ext.fly(el).contains(t));
3066             }
3067             return false;
3068         }
3069      };
3070
3071     return new Ext.EventObjectImpl();
3072 }();/**\r
3073  * @class Ext.EventManager\r
3074  */\r
3075 Ext.apply(Ext.EventManager, function(){\r
3076         var resizeEvent, \r
3077         resizeTask, \r
3078         textEvent, \r
3079         textSize,\r
3080         D = Ext.lib.Dom,\r
3081         E = Ext.lib.Event,\r
3082         propRe = /^(?:scope|delay|buffer|single|stopEvent|preventDefault|stopPropagation|normalized|args|delegate)$/,\r
3083         curWidth = 0,\r
3084         curHeight = 0,\r
3085         // note 1: IE fires ONLY the keydown event on specialkey autorepeat\r
3086         // note 2: Safari < 3.1, Gecko (Mac/Linux) & Opera fire only the keypress event on specialkey autorepeat\r
3087         // (research done by @Jan Wolter at http://unixpapa.com/js/key.html)\r
3088         useKeydown = Ext.isWebKit ? \r
3089                     Ext.num(navigator.userAgent.match(/AppleWebKit\/(\d+)/)[1]) >= 525 :\r
3090                     !((Ext.isGecko && !Ext.isWindows) || Ext.isOpera);\r
3091         \r
3092         return { \r
3093                 // private\r
3094             doResizeEvent: function(){\r
3095             var h = D.getViewHeight(),\r
3096                 w = D.getViewWidth();\r
3097             \r
3098             //whacky problem in IE where the resize event will fire even though the w/h are the same.\r
3099             if(curHeight != h || curWidth != w){\r
3100                 resizeEvent.fire(curWidth = w, curHeight = h);\r
3101             }\r
3102             },\r
3103             \r
3104             /**\r
3105              * Fires when the window is resized and provides resize event buffering (50 milliseconds), passes new viewport width and height to handlers.\r
3106              * @param {Function} fn        The method the event invokes\r
3107              * @param {Object}   scope    An object that becomes the scope of the handler\r
3108              * @param {boolean}  options\r
3109              */\r
3110             onWindowResize : function(fn, scope, options){\r
3111                 if(!resizeEvent){\r
3112                     resizeEvent = new Ext.util.Event();\r
3113                     resizeTask = new Ext.util.DelayedTask(this.doResizeEvent);\r
3114                     E.on(window, "resize", this.fireWindowResize, this);\r
3115                 }\r
3116                 resizeEvent.addListener(fn, scope, options);\r
3117             },\r
3118         \r
3119             // exposed only to allow manual firing\r
3120             fireWindowResize : function(){\r
3121                 if(resizeEvent){\r
3122                     if((Ext.isIE||Ext.isAir) && resizeTask){\r
3123                         resizeTask.delay(50);\r
3124                     }else{\r
3125                         resizeEvent.fire(D.getViewWidth(), D.getViewHeight());\r
3126                     }\r
3127                 }\r
3128             },\r
3129         \r
3130             /**\r
3131              * Fires when the user changes the active text size. Handler gets called with 2 params, the old size and the new size.\r
3132              * @param {Function} fn        The method the event invokes\r
3133              * @param {Object}   scope    An object that becomes the scope of the handler\r
3134              * @param {boolean}  options\r
3135              */\r
3136             onTextResize : function(fn, scope, options){\r
3137                 if(!textEvent){\r
3138                     textEvent = new Ext.util.Event();\r
3139                     var textEl = new Ext.Element(document.createElement('div'));\r
3140                     textEl.dom.className = 'x-text-resize';\r
3141                     textEl.dom.innerHTML = 'X';\r
3142                     textEl.appendTo(document.body);\r
3143                     textSize = textEl.dom.offsetHeight;\r
3144                     setInterval(function(){\r
3145                         if(textEl.dom.offsetHeight != textSize){\r
3146                             textEvent.fire(textSize, textSize = textEl.dom.offsetHeight);\r
3147                         }\r
3148                     }, this.textResizeInterval);\r
3149                 }\r
3150                 textEvent.addListener(fn, scope, options);\r
3151             },\r
3152         \r
3153             /**\r
3154              * Removes the passed window resize listener.\r
3155              * @param {Function} fn        The method the event invokes\r
3156              * @param {Object}   scope    The scope of handler\r
3157              */\r
3158             removeResizeListener : function(fn, scope){\r
3159                 if(resizeEvent){\r
3160                     resizeEvent.removeListener(fn, scope);\r
3161                 }\r
3162             },\r
3163         \r
3164             // private\r
3165             fireResize : function(){\r
3166                 if(resizeEvent){\r
3167                     resizeEvent.fire(D.getViewWidth(), D.getViewHeight());\r
3168                 }\r
3169             },\r
3170             \r
3171              /**\r
3172              * The frequency, in milliseconds, to check for text resize events (defaults to 50)\r
3173              */\r
3174             textResizeInterval : 50,\r
3175             \r
3176             /**\r
3177          * Url used for onDocumentReady with using SSL (defaults to Ext.SSL_SECURE_URL)\r
3178          */\r
3179         ieDeferSrc : false,\r
3180         \r
3181         // protected for use inside the framework\r
3182         // detects whether we should use keydown or keypress based on the browser.\r
3183         useKeydown: useKeydown\r
3184     };\r
3185 }());\r
3186 \r
3187 Ext.EventManager.on = Ext.EventManager.addListener;\r
3188 \r
3189 \r
3190 Ext.apply(Ext.EventObjectImpl.prototype, {\r
3191     /** Key constant @type Number */\r
3192     BACKSPACE: 8,\r
3193     /** Key constant @type Number */\r
3194     TAB: 9,\r
3195     /** Key constant @type Number */\r
3196     NUM_CENTER: 12,\r
3197     /** Key constant @type Number */\r
3198     ENTER: 13,\r
3199     /** Key constant @type Number */\r
3200     RETURN: 13,\r
3201     /** Key constant @type Number */\r
3202     SHIFT: 16,\r
3203     /** Key constant @type Number */\r
3204     CTRL: 17,\r
3205     CONTROL : 17, // legacy\r
3206     /** Key constant @type Number */\r
3207     ALT: 18,\r
3208     /** Key constant @type Number */\r
3209     PAUSE: 19,\r
3210     /** Key constant @type Number */\r
3211     CAPS_LOCK: 20,\r
3212     /** Key constant @type Number */\r
3213     ESC: 27,\r
3214     /** Key constant @type Number */\r
3215     SPACE: 32,\r
3216     /** Key constant @type Number */\r
3217     PAGE_UP: 33,\r
3218     PAGEUP : 33, // legacy\r
3219     /** Key constant @type Number */\r
3220     PAGE_DOWN: 34,\r
3221     PAGEDOWN : 34, // legacy\r
3222     /** Key constant @type Number */\r
3223     END: 35,\r
3224     /** Key constant @type Number */\r
3225     HOME: 36,\r
3226     /** Key constant @type Number */\r
3227     LEFT: 37,\r
3228     /** Key constant @type Number */\r
3229     UP: 38,\r
3230     /** Key constant @type Number */\r
3231     RIGHT: 39,\r
3232     /** Key constant @type Number */\r
3233     DOWN: 40,\r
3234     /** Key constant @type Number */\r
3235     PRINT_SCREEN: 44,\r
3236     /** Key constant @type Number */\r
3237     INSERT: 45,\r
3238     /** Key constant @type Number */\r
3239     DELETE: 46,\r
3240     /** Key constant @type Number */\r
3241     ZERO: 48,\r
3242     /** Key constant @type Number */\r
3243     ONE: 49,\r
3244     /** Key constant @type Number */\r
3245     TWO: 50,\r
3246     /** Key constant @type Number */\r
3247     THREE: 51,\r
3248     /** Key constant @type Number */\r
3249     FOUR: 52,\r
3250     /** Key constant @type Number */\r
3251     FIVE: 53,\r
3252     /** Key constant @type Number */\r
3253     SIX: 54,\r
3254     /** Key constant @type Number */\r
3255     SEVEN: 55,\r
3256     /** Key constant @type Number */\r
3257     EIGHT: 56,\r
3258     /** Key constant @type Number */\r
3259     NINE: 57,\r
3260     /** Key constant @type Number */\r
3261     A: 65,\r
3262     /** Key constant @type Number */\r
3263     B: 66,\r
3264     /** Key constant @type Number */\r
3265     C: 67,\r
3266     /** Key constant @type Number */\r
3267     D: 68,\r
3268     /** Key constant @type Number */\r
3269     E: 69,\r
3270     /** Key constant @type Number */\r
3271     F: 70,\r
3272     /** Key constant @type Number */\r
3273     G: 71,\r
3274     /** Key constant @type Number */\r
3275     H: 72,\r
3276     /** Key constant @type Number */\r
3277     I: 73,\r
3278     /** Key constant @type Number */\r
3279     J: 74,\r
3280     /** Key constant @type Number */\r
3281     K: 75,\r
3282     /** Key constant @type Number */\r
3283     L: 76,\r
3284     /** Key constant @type Number */\r
3285     M: 77,\r
3286     /** Key constant @type Number */\r
3287     N: 78,\r
3288     /** Key constant @type Number */\r
3289     O: 79,\r
3290     /** Key constant @type Number */\r
3291     P: 80,\r
3292     /** Key constant @type Number */\r
3293     Q: 81,\r
3294     /** Key constant @type Number */\r
3295     R: 82,\r
3296     /** Key constant @type Number */\r
3297     S: 83,\r
3298     /** Key constant @type Number */\r
3299     T: 84,\r
3300     /** Key constant @type Number */\r
3301     U: 85,\r
3302     /** Key constant @type Number */\r
3303     V: 86,\r
3304     /** Key constant @type Number */\r
3305     W: 87,\r
3306     /** Key constant @type Number */\r
3307     X: 88,\r
3308     /** Key constant @type Number */\r
3309     Y: 89,\r
3310     /** Key constant @type Number */\r
3311     Z: 90,\r
3312     /** Key constant @type Number */\r
3313     CONTEXT_MENU: 93,\r
3314     /** Key constant @type Number */\r
3315     NUM_ZERO: 96,\r
3316     /** Key constant @type Number */\r
3317     NUM_ONE: 97,\r
3318     /** Key constant @type Number */\r
3319     NUM_TWO: 98,\r
3320     /** Key constant @type Number */\r
3321     NUM_THREE: 99,\r
3322     /** Key constant @type Number */\r
3323     NUM_FOUR: 100,\r
3324     /** Key constant @type Number */\r
3325     NUM_FIVE: 101,\r
3326     /** Key constant @type Number */\r
3327     NUM_SIX: 102,\r
3328     /** Key constant @type Number */\r
3329     NUM_SEVEN: 103,\r
3330     /** Key constant @type Number */\r
3331     NUM_EIGHT: 104,\r
3332     /** Key constant @type Number */\r
3333     NUM_NINE: 105,\r
3334     /** Key constant @type Number */\r
3335     NUM_MULTIPLY: 106,\r
3336     /** Key constant @type Number */\r
3337     NUM_PLUS: 107,\r
3338     /** Key constant @type Number */\r
3339     NUM_MINUS: 109,\r
3340     /** Key constant @type Number */\r
3341     NUM_PERIOD: 110,\r
3342     /** Key constant @type Number */\r
3343     NUM_DIVISION: 111,\r
3344     /** Key constant @type Number */\r
3345     F1: 112,\r
3346     /** Key constant @type Number */\r
3347     F2: 113,\r
3348     /** Key constant @type Number */\r
3349     F3: 114,\r
3350     /** Key constant @type Number */\r
3351     F4: 115,\r
3352     /** Key constant @type Number */\r
3353     F5: 116,\r
3354     /** Key constant @type Number */\r
3355     F6: 117,\r
3356     /** Key constant @type Number */\r
3357     F7: 118,\r
3358     /** Key constant @type Number */\r
3359     F8: 119,\r
3360     /** Key constant @type Number */\r
3361     F9: 120,\r
3362     /** Key constant @type Number */\r
3363     F10: 121,\r
3364     /** Key constant @type Number */\r
3365     F11: 122,\r
3366     /** Key constant @type Number */\r
3367     F12: 123,   \r
3368     \r
3369     /** @private */\r
3370     isNavKeyPress : function(){\r
3371         var me = this,\r
3372                 k = this.normalizeKey(me.keyCode);              \r
3373         return (k >= 33 && k <= 40) ||  // Page Up/Down, End, Home, Left, Up, Right, Down\r
3374                 k == me.RETURN ||\r
3375                 k == me.TAB ||\r
3376                 k == me.ESC;\r
3377     },\r
3378 \r
3379     isSpecialKey : function(){\r
3380         var k = this.normalizeKey(this.keyCode);\r
3381         return (this.type == 'keypress' && this.ctrlKey) ||\r
3382                 this.isNavKeyPress() ||\r
3383         (k == this.BACKSPACE) || // Backspace\r
3384                 (k >= 16 && k <= 20) || // Shift, Ctrl, Alt, Pause, Caps Lock\r
3385                 (k >= 44 && k <= 45);   // Print Screen, Insert\r
3386     },\r
3387         \r
3388         getPoint : function(){\r
3389             return new Ext.lib.Point(this.xy[0], this.xy[1]);\r
3390         },\r
3391 \r
3392     /**\r
3393      * Returns true if the control, meta, shift or alt key was pressed during this event.\r
3394      * @return {Boolean}\r
3395      */\r
3396     hasModifier : function(){\r
3397         return ((this.ctrlKey || this.altKey) || this.shiftKey);\r
3398     }\r
3399 });/**\r
3400  * @class Ext.Element\r
3401  * <p>Encapsulates a DOM element, adding simple DOM manipulation facilities, normalizing for browser differences.</p>\r
3402  * <p>All instances of this class inherit the methods of {@link Ext.Fx} making visual effects easily available to all DOM elements.</p>\r
3403  * <p>Note that the events documented in this class are not Ext events, they encapsulate browser events. To\r
3404  * access the underlying browser event, see {@link Ext.EventObject#browserEvent}. Some older\r
3405  * browsers may not support the full range of events. Which events are supported is beyond the control of ExtJs.</p>\r
3406  * Usage:<br>\r
3407 <pre><code>\r
3408 // by id\r
3409 var el = Ext.get("my-div");\r
3410 \r
3411 // by DOM element reference\r
3412 var el = Ext.get(myDivElement);\r
3413 </code></pre>\r
3414  * <b>Animations</b><br />\r
3415  * <p>When an element is manipulated, by default there is no animation.</p>\r
3416  * <pre><code>\r
3417 var el = Ext.get("my-div");\r
3418 \r
3419 // no animation\r
3420 el.setWidth(100);\r
3421  * </code></pre>\r
3422  * <p>Many of the functions for manipulating an element have an optional "animate" parameter.  This\r
3423  * parameter can be specified as boolean (<tt>true</tt>) for default animation effects.</p>\r
3424  * <pre><code>\r
3425 // default animation\r
3426 el.setWidth(100, true);\r
3427  * </code></pre>\r
3428  * \r
3429  * <p>To configure the effects, an object literal with animation options to use as the Element animation\r
3430  * configuration object can also be specified. Note that the supported Element animation configuration\r
3431  * options are a subset of the {@link Ext.Fx} animation options specific to Fx effects.  The supported\r
3432  * Element animation configuration options are:</p>\r
3433 <pre>\r
3434 Option    Default   Description\r
3435 --------- --------  ---------------------------------------------\r
3436 {@link Ext.Fx#duration duration}  .35       The duration of the animation in seconds\r
3437 {@link Ext.Fx#easing easing}    easeOut   The easing method\r
3438 {@link Ext.Fx#callback callback}  none      A function to execute when the anim completes\r
3439 {@link Ext.Fx#scope scope}     this      The scope (this) of the callback function\r
3440 </pre>\r
3441  * \r
3442  * <pre><code>\r
3443 // Element animation options object\r
3444 var opt = {\r
3445     {@link Ext.Fx#duration duration}: 1,\r
3446     {@link Ext.Fx#easing easing}: 'elasticIn',\r
3447     {@link Ext.Fx#callback callback}: this.foo,\r
3448     {@link Ext.Fx#scope scope}: this\r
3449 };\r
3450 // animation with some options set\r
3451 el.setWidth(100, opt);\r
3452  * </code></pre>\r
3453  * <p>The Element animation object being used for the animation will be set on the options\r
3454  * object as "anim", which allows you to stop or manipulate the animation. Here is an example:</p>\r
3455  * <pre><code>\r
3456 // using the "anim" property to get the Anim object\r
3457 if(opt.anim.isAnimated()){\r
3458     opt.anim.stop();\r
3459 }\r
3460  * </code></pre>\r
3461  * <p>Also see the <tt>{@link #animate}</tt> method for another animation technique.</p>\r
3462  * <p><b> Composite (Collections of) Elements</b></p>\r
3463  * <p>For working with collections of Elements, see {@link Ext.CompositeElement}</p>\r
3464  * @constructor Create a new Element directly.\r
3465  * @param {String/HTMLElement} element\r
3466  * @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
3467  */\r
3468 (function(){\r
3469 var DOC = document;\r
3470 \r
3471 Ext.Element = function(element, forceNew){\r
3472     var dom = typeof element == "string" ?\r
3473               DOC.getElementById(element) : element,\r
3474         id;\r
3475 \r
3476     if(!dom) return null;\r
3477 \r
3478     id = dom.id;\r
3479 \r
3480     if(!forceNew && id && Ext.Element.cache[id]){ // element object already exists\r
3481         return Ext.Element.cache[id];\r
3482     }\r
3483 \r
3484     /**\r
3485      * The DOM element\r
3486      * @type HTMLElement\r
3487      */\r
3488     this.dom = dom;\r
3489 \r
3490     /**\r
3491      * The DOM element ID\r
3492      * @type String\r
3493      */\r
3494     this.id = id || Ext.id(dom);\r
3495 };\r
3496 \r
3497 var D = Ext.lib.Dom,\r
3498     DH = Ext.DomHelper,\r
3499     E = Ext.lib.Event,\r
3500     A = Ext.lib.Anim,\r
3501     El = Ext.Element;\r
3502 \r
3503 El.prototype = {\r
3504     /**\r
3505      * Sets the passed attributes as attributes of this element (a style attribute can be a string, object or function)\r
3506      * @param {Object} o The object with the attributes\r
3507      * @param {Boolean} useSet (optional) false to override the default setAttribute to use expandos.\r
3508      * @return {Ext.Element} this\r
3509      */\r
3510     set : function(o, useSet){\r
3511         var el = this.dom,\r
3512             attr,\r
3513             val;        \r
3514        \r
3515         for(attr in o){\r
3516             val = o[attr];\r
3517             if (attr != "style" && !Ext.isFunction(val)) {\r
3518                 if (attr == "cls" ) {\r
3519                     el.className = val;\r
3520                 } else if (o.hasOwnProperty(attr)) {\r
3521                     if (useSet || !!el.setAttribute) el.setAttribute(attr, val);\r
3522                     else el[attr] = val;\r
3523                 }\r
3524             }\r
3525         }\r
3526         if(o.style){\r
3527             DH.applyStyles(el, o.style);\r
3528         }\r
3529         return this;\r
3530     },\r
3531     \r
3532 //  Mouse events\r
3533     /**\r
3534      * @event click\r
3535      * Fires when a mouse click is detected within the element.\r
3536      * @param {Ext.EventObject} e The {@link Ext.EventObject} encapsulating the DOM event.\r
3537      * @param {HtmlElement} t The target of the event.\r
3538      * @param {Object} o The options configuration passed to the {@link #addListener} call.\r
3539      */\r
3540     /**\r
3541      * @event contextmenu\r
3542      * Fires when a right click is detected within the element.\r
3543      * @param {Ext.EventObject} e The {@link Ext.EventObject} encapsulating the DOM event.\r
3544      * @param {HtmlElement} t The target of the event.\r
3545      * @param {Object} o The options configuration passed to the {@link #addListener} call.\r
3546      */\r
3547     /**\r
3548      * @event dblclick\r
3549      * Fires when a mouse double click is detected within the element.\r
3550      * @param {Ext.EventObject} e The {@link Ext.EventObject} encapsulating the DOM event.\r
3551      * @param {HtmlElement} t The target of the event.\r
3552      * @param {Object} o The options configuration passed to the {@link #addListener} call.\r
3553      */\r
3554     /**\r
3555      * @event mousedown\r
3556      * Fires when a mousedown is detected within the element.\r
3557      * @param {Ext.EventObject} e The {@link Ext.EventObject} encapsulating the DOM event.\r
3558      * @param {HtmlElement} t The target of the event.\r
3559      * @param {Object} o The options configuration passed to the {@link #addListener} call.\r
3560      */\r
3561     /**\r
3562      * @event mouseup\r
3563      * Fires when a mouseup is detected within the element.\r
3564      * @param {Ext.EventObject} e The {@link Ext.EventObject} encapsulating the DOM event.\r
3565      * @param {HtmlElement} t The target of the event.\r
3566      * @param {Object} o The options configuration passed to the {@link #addListener} call.\r
3567      */\r
3568     /**\r
3569      * @event mouseover\r
3570      * Fires when a mouseover is detected within the element.\r
3571      * @param {Ext.EventObject} e The {@link Ext.EventObject} encapsulating the DOM event.\r
3572      * @param {HtmlElement} t The target of the event.\r
3573      * @param {Object} o The options configuration passed to the {@link #addListener} call.\r
3574      */\r
3575     /**\r
3576      * @event mousemove\r
3577      * Fires when a mousemove is detected with the element.\r
3578      * @param {Ext.EventObject} e The {@link Ext.EventObject} encapsulating the DOM event.\r
3579      * @param {HtmlElement} t The target of the event.\r
3580      * @param {Object} o The options configuration passed to the {@link #addListener} call.\r
3581      */\r
3582     /**\r
3583      * @event mouseout\r
3584      * Fires when a mouseout is detected with the element.\r
3585      * @param {Ext.EventObject} e The {@link Ext.EventObject} encapsulating the DOM event.\r
3586      * @param {HtmlElement} t The target of the event.\r
3587      * @param {Object} o The options configuration passed to the {@link #addListener} call.\r
3588      */\r
3589     /**\r
3590      * @event mouseenter\r
3591      * Fires when the mouse enters the element.\r
3592      * @param {Ext.EventObject} e The {@link Ext.EventObject} encapsulating the DOM event.\r
3593      * @param {HtmlElement} t The target of the event.\r
3594      * @param {Object} o The options configuration passed to the {@link #addListener} call.\r
3595      */\r
3596     /**\r
3597      * @event mouseleave\r
3598      * Fires when the mouse leaves the element.\r
3599      * @param {Ext.EventObject} e The {@link Ext.EventObject} encapsulating the DOM event.\r
3600      * @param {HtmlElement} t The target of the event.\r
3601      * @param {Object} o The options configuration passed to the {@link #addListener} call.\r
3602      */\r
3603     \r
3604 //  Keyboard events\r
3605     /**\r
3606      * @event keypress\r
3607      * Fires when a keypress is detected within the element.\r
3608      * @param {Ext.EventObject} e The {@link Ext.EventObject} encapsulating the DOM event.\r
3609      * @param {HtmlElement} t The target of the event.\r
3610      * @param {Object} o The options configuration passed to the {@link #addListener} call.\r
3611      */\r
3612     /**\r
3613      * @event keydown\r
3614      * Fires when a keydown is detected within the element.\r
3615      * @param {Ext.EventObject} e The {@link Ext.EventObject} encapsulating the DOM event.\r
3616      * @param {HtmlElement} t The target of the event.\r
3617      * @param {Object} o The options configuration passed to the {@link #addListener} call.\r
3618      */\r
3619     /**\r
3620      * @event keyup\r
3621      * Fires when a keyup is detected within the element.\r
3622      * @param {Ext.EventObject} e The {@link Ext.EventObject} encapsulating the DOM event.\r
3623      * @param {HtmlElement} t The target of the event.\r
3624      * @param {Object} o The options configuration passed to the {@link #addListener} call.\r
3625      */\r
3626 \r
3627 \r
3628 //  HTML frame/object events\r
3629     /**\r
3630      * @event load\r
3631      * Fires when the user agent finishes loading all content within the element. Only supported by window, frames, objects and images.\r
3632      * @param {Ext.EventObject} e The {@link Ext.EventObject} encapsulating the DOM event.\r
3633      * @param {HtmlElement} t The target of the event.\r
3634      * @param {Object} o The options configuration passed to the {@link #addListener} call.\r
3635      */\r
3636     /**\r
3637      * @event unload\r
3638      * 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
3639      * @param {Ext.EventObject} e The {@link Ext.EventObject} encapsulating the DOM event.\r
3640      * @param {HtmlElement} t The target of the event.\r
3641      * @param {Object} o The options configuration passed to the {@link #addListener} call.\r
3642      */\r
3643     /**\r
3644      * @event abort\r
3645      * Fires when an object/image is stopped from loading before completely loaded.\r
3646      * @param {Ext.EventObject} e The {@link Ext.EventObject} encapsulating the DOM event.\r
3647      * @param {HtmlElement} t The target of the event.\r
3648      * @param {Object} o The options configuration passed to the {@link #addListener} call.\r
3649      */\r
3650     /**\r
3651      * @event error\r
3652      * Fires when an object/image/frame cannot be loaded properly.\r
3653      * @param {Ext.EventObject} e The {@link Ext.EventObject} encapsulating the DOM event.\r
3654      * @param {HtmlElement} t The target of the event.\r
3655      * @param {Object} o The options configuration passed to the {@link #addListener} call.\r
3656      */\r
3657     /**\r
3658      * @event resize\r
3659      * Fires when a document view is resized.\r
3660      * @param {Ext.EventObject} e The {@link Ext.EventObject} encapsulating the DOM event.\r
3661      * @param {HtmlElement} t The target of the event.\r
3662      * @param {Object} o The options configuration passed to the {@link #addListener} call.\r
3663      */\r
3664     /**\r
3665      * @event scroll\r
3666      * Fires when a document view is scrolled.\r
3667      * @param {Ext.EventObject} e The {@link Ext.EventObject} encapsulating the DOM event.\r
3668      * @param {HtmlElement} t The target of the event.\r
3669      * @param {Object} o The options configuration passed to the {@link #addListener} call.\r
3670      */\r
3671 \r
3672 //  Form events\r
3673     /**\r
3674      * @event select\r
3675      * Fires when a user selects some text in a text field, including input and textarea.\r
3676      * @param {Ext.EventObject} e The {@link Ext.EventObject} encapsulating the DOM event.\r
3677      * @param {HtmlElement} t The target of the event.\r
3678      * @param {Object} o The options configuration passed to the {@link #addListener} call.\r
3679      */\r
3680     /**\r
3681      * @event change\r
3682      * Fires when a control loses the input focus and its value has been modified since gaining focus.\r
3683      * @param {Ext.EventObject} e The {@link Ext.EventObject} encapsulating the DOM event.\r
3684      * @param {HtmlElement} t The target of the event.\r
3685      * @param {Object} o The options configuration passed to the {@link #addListener} call.\r
3686      */\r
3687     /**\r
3688      * @event submit\r
3689      * Fires when a form is submitted.\r
3690      * @param {Ext.EventObject} e The {@link Ext.EventObject} encapsulating the DOM event.\r
3691      * @param {HtmlElement} t The target of the event.\r
3692      * @param {Object} o The options configuration passed to the {@link #addListener} call.\r
3693      */\r
3694     /**\r
3695      * @event reset\r
3696      * Fires when a form is reset.\r
3697      * @param {Ext.EventObject} e The {@link Ext.EventObject} encapsulating the DOM event.\r
3698      * @param {HtmlElement} t The target of the event.\r
3699      * @param {Object} o The options configuration passed to the {@link #addListener} call.\r
3700      */\r
3701     /**\r
3702      * @event focus\r
3703      * Fires when an element receives focus either via the pointing device or by tab navigation.\r
3704      * @param {Ext.EventObject} e The {@link Ext.EventObject} encapsulating the DOM event.\r
3705      * @param {HtmlElement} t The target of the event.\r
3706      * @param {Object} o The options configuration passed to the {@link #addListener} call.\r
3707      */\r
3708     /**\r
3709      * @event blur\r
3710      * Fires when an element loses focus either via the pointing device or by tabbing navigation.\r
3711      * @param {Ext.EventObject} e The {@link Ext.EventObject} encapsulating the DOM event.\r
3712      * @param {HtmlElement} t The target of the event.\r
3713      * @param {Object} o The options configuration passed to the {@link #addListener} call.\r
3714      */\r
3715 \r
3716 //  User Interface events\r
3717     /**\r
3718      * @event DOMFocusIn\r
3719      * Where supported. Similar to HTML focus event, but can be applied to any focusable element.\r
3720      * @param {Ext.EventObject} e The {@link Ext.EventObject} encapsulating the DOM event.\r
3721      * @param {HtmlElement} t The target of the event.\r
3722      * @param {Object} o The options configuration passed to the {@link #addListener} call.\r
3723      */\r
3724     /**\r
3725      * @event DOMFocusOut\r
3726      * Where supported. Similar to HTML blur event, but can be applied to any focusable element.\r
3727      * @param {Ext.EventObject} e The {@link Ext.EventObject} encapsulating the DOM event.\r
3728      * @param {HtmlElement} t The target of the event.\r
3729      * @param {Object} o The options configuration passed to the {@link #addListener} call.\r
3730      */\r
3731     /**\r
3732      * @event DOMActivate\r
3733      * Where supported. Fires when an element is activated, for instance, through a mouse click or a keypress.\r
3734      * @param {Ext.EventObject} e The {@link Ext.EventObject} encapsulating the DOM event.\r
3735      * @param {HtmlElement} t The target of the event.\r
3736      * @param {Object} o The options configuration passed to the {@link #addListener} call.\r
3737      */\r
3738 \r
3739 //  DOM Mutation events\r
3740     /**\r
3741      * @event DOMSubtreeModified\r
3742      * Where supported. Fires when the subtree is modified.\r
3743      * @param {Ext.EventObject} e The {@link Ext.EventObject} encapsulating the DOM event.\r
3744      * @param {HtmlElement} t The target of the event.\r
3745      * @param {Object} o The options configuration passed to the {@link #addListener} call.\r
3746      */\r
3747     /**\r
3748      * @event DOMNodeInserted\r
3749      * Where supported. Fires when a node has been added as a child of another node.\r
3750      * @param {Ext.EventObject} e The {@link Ext.EventObject} encapsulating the DOM event.\r
3751      * @param {HtmlElement} t The target of the event.\r
3752      * @param {Object} o The options configuration passed to the {@link #addListener} call.\r
3753      */\r
3754     /**\r
3755      * @event DOMNodeRemoved\r
3756      * Where supported. Fires when a descendant node of the element is removed.\r
3757      * @param {Ext.EventObject} e The {@link Ext.EventObject} encapsulating the DOM event.\r
3758      * @param {HtmlElement} t The target of the event.\r
3759      * @param {Object} o The options configuration passed to the {@link #addListener} call.\r
3760      */\r
3761     /**\r
3762      * @event DOMNodeRemovedFromDocument\r
3763      * Where supported. Fires when a node is being removed from a document.\r
3764      * @param {Ext.EventObject} e The {@link Ext.EventObject} encapsulating the DOM event.\r
3765      * @param {HtmlElement} t The target of the event.\r
3766      * @param {Object} o The options configuration passed to the {@link #addListener} call.\r
3767      */\r
3768     /**\r
3769      * @event DOMNodeInsertedIntoDocument\r
3770      * Where supported. Fires when a node is being inserted into a document.\r
3771      * @param {Ext.EventObject} e The {@link Ext.EventObject} encapsulating the DOM event.\r
3772      * @param {HtmlElement} t The target of the event.\r
3773      * @param {Object} o The options configuration passed to the {@link #addListener} call.\r
3774      */\r
3775     /**\r
3776      * @event DOMAttrModified\r
3777      * Where supported. Fires when an attribute has been modified.\r
3778      * @param {Ext.EventObject} e The {@link Ext.EventObject} encapsulating the DOM event.\r
3779      * @param {HtmlElement} t The target of the event.\r
3780      * @param {Object} o The options configuration passed to the {@link #addListener} call.\r
3781      */\r
3782     /**\r
3783      * @event DOMCharacterDataModified\r
3784      * Where supported. Fires when the character data has been modified.\r
3785      * @param {Ext.EventObject} e The {@link Ext.EventObject} encapsulating the DOM event.\r
3786      * @param {HtmlElement} t The target of the event.\r
3787      * @param {Object} o The options configuration passed to the {@link #addListener} call.\r
3788      */\r
3789 \r
3790     /**\r
3791      * The default unit to append to CSS values where a unit isn't provided (defaults to px).\r
3792      * @type String\r
3793      */\r
3794     defaultUnit : "px",\r
3795 \r
3796     /**\r
3797      * Returns true if this element matches the passed simple selector (e.g. div.some-class or span:first-child)\r
3798      * @param {String} selector The simple selector to test\r
3799      * @return {Boolean} True if this element matches the selector, else false\r
3800      */\r
3801     is : function(simpleSelector){\r
3802         return Ext.DomQuery.is(this.dom, simpleSelector);\r
3803     },\r
3804 \r
3805     /**\r
3806      * Tries to focus the element. Any exceptions are caught and ignored.\r
3807      * @param {Number} defer (optional) Milliseconds to defer the focus\r
3808      * @return {Ext.Element} this\r
3809      */\r
3810     focus : function(defer, /* private */ dom) {\r
3811         var me = this,\r
3812             dom = dom || me.dom;\r
3813         try{\r
3814             if(Number(defer)){\r
3815                 me.focus.defer(defer, null, [null, dom]);\r
3816             }else{\r
3817                 dom.focus();\r
3818             }\r
3819         }catch(e){}\r
3820         return me;\r
3821     },\r
3822 \r
3823     /**\r
3824      * Tries to blur the element. Any exceptions are caught and ignored.\r
3825      * @return {Ext.Element} this\r
3826      */\r
3827     blur : function() {\r
3828         try{\r
3829             this.dom.blur();\r
3830         }catch(e){}\r
3831         return this;\r
3832     },\r
3833 \r
3834     /**\r
3835      * Returns the value of the "value" attribute\r
3836      * @param {Boolean} asNumber true to parse the value as a number\r
3837      * @return {String/Number}\r
3838      */\r
3839     getValue : function(asNumber){\r
3840         var val = this.dom.value;\r
3841         return asNumber ? parseInt(val, 10) : val;\r
3842     },\r
3843 \r
3844     /**\r
3845      * Appends an event handler to this element.  The shorthand version {@link #on} is equivalent.\r
3846      * @param {String} eventName The name of event to handle.\r
3847      * @param {Function} fn The handler function the event invokes. This function is passed\r
3848      * the following parameters:<ul>\r
3849      * <li><b>evt</b> : EventObject<div class="sub-desc">The {@link Ext.EventObject EventObject} describing the event.</div></li>\r
3850      * <li><b>el</b> : HtmlElement<div class="sub-desc">The DOM element which was the target of the event.\r
3851      * Note that this may be filtered by using the <tt>delegate</tt> option.</div></li>\r
3852      * <li><b>o</b> : Object<div class="sub-desc">The options object from the addListener call.</div></li>\r
3853      * </ul>\r
3854      * @param {Object} scope (optional) The scope (<code><b>this</b></code> reference) in which the handler function is executed.\r
3855      * <b>If omitted, defaults to this Element.</b>.\r
3856      * @param {Object} options (optional) An object containing handler configuration properties.\r
3857      * This may contain any of the following properties:<ul>\r
3858      * <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
3859      * <b>If omitted, defaults to this Element.</b></div></li>\r
3860      * <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
3861      * <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
3862      * <li><b>preventDefault</b> Boolean: <div class="sub-desc">True to prevent the default action</div></li>\r
3863      * <li><b>stopPropagation</b> Boolean: <div class="sub-desc">True to prevent event propagation</div></li>\r
3864      * <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
3865      * <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
3866      * <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
3867      * <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
3868      * <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
3869      * by the specified number of milliseconds. If the event fires again within that time, the original\r
3870      * handler is <em>not</em> invoked, but the new handler is scheduled in its place.</div></li>\r
3871      * </ul><br>\r
3872      * <p>\r
3873      * <b>Combining Options</b><br>\r
3874      * In the following examples, the shorthand form {@link #on} is used rather than the more verbose\r
3875      * addListener.  The two are equivalent.  Using the options argument, it is possible to combine different\r
3876      * types of listeners:<br>\r
3877      * <br>\r
3878      * A delayed, one-time listener that auto stops the event and adds a custom argument (forumId) to the\r
3879      * options object. The options object is available as the third parameter in the handler function.<div style="margin: 5px 20px 20px;">\r
3880      * Code:<pre><code>\r
3881 el.on('click', this.onClick, this, {\r
3882     single: true,\r
3883     delay: 100,\r
3884     stopEvent : true,\r
3885     forumId: 4\r
3886 });</code></pre></p>\r
3887      * <p>\r
3888      * <b>Attaching multiple handlers in 1 call</b><br>\r
3889      * The method also allows for a single argument to be passed which is a config object containing properties\r
3890      * which specify multiple handlers.</p>\r
3891      * <p>\r
3892      * Code:<pre><code>\r
3893 el.on({\r
3894     'click' : {\r
3895         fn: this.onClick,\r
3896         scope: this,\r
3897         delay: 100\r
3898     },\r
3899     'mouseover' : {\r
3900         fn: this.onMouseOver,\r
3901         scope: this\r
3902     },\r
3903     'mouseout' : {\r
3904         fn: this.onMouseOut,\r
3905         scope: this\r
3906     }\r
3907 });</code></pre>\r
3908      * <p>\r
3909      * Or a shorthand syntax:<br>\r
3910      * Code:<pre><code></p>\r
3911 el.on({\r
3912     'click' : this.onClick,\r
3913     'mouseover' : this.onMouseOver,\r
3914     'mouseout' : this.onMouseOut,\r
3915     scope: this\r
3916 });\r
3917      * </code></pre></p>\r
3918      * <p><b>delegate</b></p>\r
3919      * <p>This is a configuration option that you can pass along when registering a handler for\r
3920      * an event to assist with event delegation. Event delegation is a technique that is used to\r
3921      * reduce memory consumption and prevent exposure to memory-leaks. By registering an event\r
3922      * for a container element as opposed to each element within a container. By setting this\r
3923      * configuration option to a simple selector, the target element will be filtered to look for\r
3924      * a descendant of the target.\r
3925      * For example:<pre><code>\r
3926 // using this markup:\r
3927 &lt;div id='elId'>\r
3928     &lt;p id='p1'>paragraph one&lt;/p>\r
3929     &lt;p id='p2' class='clickable'>paragraph two&lt;/p>\r
3930     &lt;p id='p3'>paragraph three&lt;/p>\r
3931 &lt;/div>\r
3932 // utilize event delegation to registering just one handler on the container element: \r
3933 el = Ext.get('elId');\r
3934 el.on(\r
3935     'click',\r
3936     function(e,t) {\r
3937         // handle click\r
3938         console.info(t.id); // 'p2'\r
3939     },\r
3940     this,\r
3941     {\r
3942         // filter the target element to be a descendant with the class 'clickable'\r
3943         delegate: '.clickable' \r
3944     }\r
3945 );\r
3946      * </code></pre></p>\r
3947      * @return {Ext.Element} this\r
3948      */\r
3949     addListener : function(eventName, fn, scope, options){\r
3950         Ext.EventManager.on(this.dom,  eventName, fn, scope || this, options);\r
3951         return this;\r
3952     },\r
3953 \r
3954     /**\r
3955      * Removes an event handler from this element.  The shorthand version {@link #un} is equivalent.\r
3956      * <b>Note</b>: if a <i>scope</i> was explicitly specified when {@link #addListener adding} the\r
3957      * listener, the same scope must be specified here.\r
3958      * Example:\r
3959      * <pre><code>\r
3960 el.removeListener('click', this.handlerFn);\r
3961 // or\r
3962 el.un('click', this.handlerFn);\r
3963 </code></pre>\r
3964      * @param {String} eventName The name of the event from which to remove the handler.\r
3965      * @param {Function} fn The handler function to remove. <b>This must be a reference to the function passed into the {@link #addListener} call.</b>\r
3966      * @param {Object} scope If a scope (<b><code>this</code></b> reference) was specified when the listener was added,\r
3967      * then this must refer to the same object.\r
3968      * @return {Ext.Element} this\r
3969      */\r
3970     removeListener : function(eventName, fn, scope){\r
3971         Ext.EventManager.removeListener(this.dom,  eventName, fn, scope || this);\r
3972         return this;\r
3973     },\r
3974 \r
3975     /**\r
3976      * Removes all previous added listeners from this element\r
3977      * @return {Ext.Element} this\r
3978      */\r
3979     removeAllListeners : function(){\r
3980         Ext.EventManager.removeAll(this.dom);\r
3981         return this;\r
3982     },\r
3983 \r
3984     /**\r
3985      * @private Test if size has a unit, otherwise appends the default\r
3986      */\r
3987     addUnits : function(size){\r
3988         if(size === "" || size == "auto" || size === undefined){\r
3989             size = size || '';\r
3990         } else if(!isNaN(size) || !unitPattern.test(size)){\r
3991             size = size + (this.defaultUnit || 'px');\r
3992         }\r
3993         return size;\r
3994     },\r
3995 \r
3996     /**\r
3997      * <p>Updates the <a href="http://developer.mozilla.org/en/DOM/element.innerHTML">innerHTML</a> of this Element\r
3998      * 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
3999      * <p>Updating innerHTML of an element will <b>not</b> execute embedded <tt>&lt;script></tt> elements. This is a browser restriction.</p>\r
4000      * @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
4001      * exactly how to request the HTML.\r
4002      * @return {Ext.Element} this\r
4003      */\r
4004     load : function(url, params, cb){\r
4005         Ext.Ajax.request(Ext.apply({\r
4006             params: params,\r
4007             url: url.url || url,\r
4008             callback: cb,\r
4009             el: this.dom,\r
4010             indicatorText: url.indicatorText || ''\r
4011         }, Ext.isObject(url) ? url : {}));\r
4012         return this;\r
4013     },\r
4014 \r
4015     /**\r
4016      * Tests various css rules/browsers to determine if this element uses a border box\r
4017      * @return {Boolean}\r
4018      */\r
4019     isBorderBox : function(){\r
4020         return noBoxAdjust[(this.dom.tagName || "").toLowerCase()] || Ext.isBorderBox;\r
4021     },\r
4022 \r
4023     /**\r
4024      * Removes this element from the DOM and deletes it from the cache\r
4025      */\r
4026     remove : function(){\r
4027         var me = this,\r
4028             dom = me.dom;\r
4029         \r
4030         me.removeAllListeners();\r
4031         if (dom) {\r
4032             delete me.dom;\r
4033             delete El.cache[dom.id];\r
4034             delete El.dataCache[dom.id];\r
4035             Ext.removeNode(dom);\r
4036         }\r
4037     },\r
4038 \r
4039     /**\r
4040      * Sets up event handlers to call the passed functions when the mouse is moved into and out of the Element.\r
4041      * @param {Function} overFn The function to call when the mouse enters the Element.\r
4042      * @param {Function} outFn The function to call when the mouse leaves the Element.\r
4043      * @param {Object} scope (optional) The scope (<code>this</code> reference) in which the functions are executed. Defaults to the Element's DOM element.\r
4044      * @param {Object} options (optional) Options for the listener. See {@link Ext.util.Observable#addListener the <tt>options</tt> parameter}.\r
4045      * @return {Ext.Element} this\r
4046      */\r
4047     hover : function(overFn, outFn, scope, options){\r
4048         var me = this;\r
4049         me.on('mouseenter', overFn, scope || me.dom, options);\r
4050         me.on('mouseleave', outFn, scope || me.dom, options);\r
4051         return me;\r
4052     },\r
4053 \r
4054     /**\r
4055      * Returns true if this element is an ancestor of the passed element\r
4056      * @param {HTMLElement/String} el The element to check\r
4057      * @return {Boolean} True if this element is an ancestor of el, else false\r
4058      */\r
4059     contains : function(el){\r
4060         return !el ? false : Ext.lib.Dom.isAncestor(this.dom, el.dom ? el.dom : el);\r
4061     },\r
4062 \r
4063     /**\r
4064      * Returns the value of a namespaced attribute from the element's underlying DOM node.\r
4065      * @param {String} namespace The namespace in which to look for the attribute\r
4066      * @param {String} name The attribute name\r
4067      * @return {String} The attribute value\r
4068      * @deprecated\r
4069      */\r
4070     getAttributeNS : function(ns, name){\r
4071         return this.getAttribute(name, ns); \r
4072     },\r
4073     \r
4074     /**\r
4075      * Returns the value of an attribute from the element's underlying DOM node.\r
4076      * @param {String} name The attribute name\r
4077      * @param {String} namespace (optional) The namespace in which to look for the attribute\r
4078      * @return {String} The attribute value\r
4079      */\r
4080     getAttribute : Ext.isIE ? function(name, ns){\r
4081         var d = this.dom,\r
4082             type = typeof d[ns + ":" + name];\r
4083 \r
4084         if(['undefined', 'unknown'].indexOf(type) == -1){\r
4085             return d[ns + ":" + name];\r
4086         }\r
4087         return d[name];\r
4088     } : function(name, ns){\r
4089         var d = this.dom;\r
4090         return d.getAttributeNS(ns, name) || d.getAttribute(ns + ":" + name) || d.getAttribute(name) || d[name];\r
4091     },\r
4092     \r
4093     /**\r
4094     * Update the innerHTML of this element\r
4095     * @param {String} html The new HTML\r
4096     * @return {Ext.Element} this\r
4097      */\r
4098     update : function(html) {\r
4099         if (this.dom) {\r
4100             this.dom.innerHTML = html;\r
4101         }\r
4102         return this;\r
4103     }\r
4104 };\r
4105 \r
4106 var ep = El.prototype;\r
4107 \r
4108 El.addMethods = function(o){\r
4109    Ext.apply(ep, o);\r
4110 };\r
4111 \r
4112 /**\r
4113  * Appends an event handler (shorthand for {@link #addListener}).\r
4114  * @param {String} eventName The name of event to handle.\r
4115  * @param {Function} fn The handler function the event invokes.\r
4116  * @param {Object} scope (optional) The scope (<code>this</code> reference) in which the handler function is executed.\r
4117  * @param {Object} options (optional) An object containing standard {@link #addListener} options\r
4118  * @member Ext.Element\r
4119  * @method on\r
4120  */\r
4121 ep.on = ep.addListener;\r
4122 \r
4123 /**\r
4124  * Removes an event handler from this element (see {@link #removeListener} for additional notes).\r
4125  * @param {String} eventName The name of the event from which to remove the handler.\r
4126  * @param {Function} fn The handler function to remove. <b>This must be a reference to the function passed into the {@link #addListener} call.</b>\r
4127  * @param {Object} scope If a scope (<b><code>this</code></b> reference) was specified when the listener was added,\r
4128  * then this must refer to the same object.\r
4129  * @return {Ext.Element} this\r
4130  * @member Ext.Element\r
4131  * @method un\r
4132  */\r
4133 ep.un = ep.removeListener;\r
4134 \r
4135 /**\r
4136  * true to automatically adjust width and height settings for box-model issues (default to true)\r
4137  */\r
4138 ep.autoBoxAdjust = true;\r
4139 \r
4140 // private\r
4141 var unitPattern = /\d+(px|em|%|en|ex|pt|in|cm|mm|pc)$/i,\r
4142     docEl;\r
4143 \r
4144 /**\r
4145  * @private\r
4146  */\r
4147 El.cache = {};\r
4148 El.dataCache = {};\r
4149 \r
4150 /**\r
4151  * Retrieves Ext.Element objects.\r
4152  * <p><b>This method does not retrieve {@link Ext.Component Component}s.</b> This method\r
4153  * retrieves Ext.Element objects which encapsulate DOM elements. To retrieve a Component by\r
4154  * its ID, use {@link Ext.ComponentMgr#get}.</p>\r
4155  * <p>Uses simple caching to consistently return the same object. Automatically fixes if an\r
4156  * object was recreated with the same id via AJAX or DOM.</p>\r
4157  * @param {Mixed} el The id of the node, a DOM Node or an existing Element.\r
4158  * @return {Element} The Element object (or null if no matching element was found)\r
4159  * @static\r
4160  * @member Ext.Element\r
4161  * @method get\r
4162  */\r
4163 El.get = function(el){\r
4164     var ex,\r
4165         elm,\r
4166         id;\r
4167     if(!el){ return null; }\r
4168     if (typeof el == "string") { // element id\r
4169         if (!(elm = DOC.getElementById(el))) {\r
4170             return null;\r
4171         }\r
4172         if (ex = El.cache[el]) {\r
4173             ex.dom = elm;\r
4174         } else {\r
4175             ex = El.cache[el] = new El(elm);\r
4176         }\r
4177         return ex;\r
4178     } else if (el.tagName) { // dom element\r
4179         if(!(id = el.id)){\r
4180             id = Ext.id(el);\r
4181         }\r
4182         if(ex = El.cache[id]){\r
4183             ex.dom = el;\r
4184         }else{\r
4185             ex = El.cache[id] = new El(el);\r
4186         }\r
4187         return ex;\r
4188     } else if (el instanceof El) {\r
4189         if(el != docEl){\r
4190             el.dom = DOC.getElementById(el.id) || el.dom; // refresh dom element in case no longer valid,\r
4191                                                           // catch case where it hasn't been appended\r
4192             El.cache[el.id] = el; // in case it was created directly with Element(), let's cache it\r
4193         }\r
4194         return el;\r
4195     } else if(el.isComposite) {\r
4196         return el;\r
4197     } else if(Ext.isArray(el)) {\r
4198         return El.select(el);\r
4199     } else if(el == DOC) {\r
4200         // create a bogus element object representing the document object\r
4201         if(!docEl){\r
4202             var f = function(){};\r
4203             f.prototype = El.prototype;\r
4204             docEl = new f();\r
4205             docEl.dom = DOC;\r
4206         }\r
4207         return docEl;\r
4208     }\r
4209     return null;\r
4210 };\r
4211 \r
4212 // private method for getting and setting element data\r
4213 El.data = function(el, key, value){\r
4214     var c = El.dataCache[el.id];\r
4215     if(!c){\r
4216         c = El.dataCache[el.id] = {};\r
4217     }\r
4218     if(arguments.length == 2){\r
4219         return c[key];    \r
4220     }else{\r
4221         return (c[key] = value);\r
4222     }\r
4223 };\r
4224 \r
4225 // private\r
4226 // Garbage collection - uncache elements/purge listeners on orphaned elements\r
4227 // so we don't hold a reference and cause the browser to retain them\r
4228 function garbageCollect(){\r
4229     if(!Ext.enableGarbageCollector){\r
4230         clearInterval(El.collectorThread);\r
4231     } else {\r
4232         var eid,\r
4233             el,\r
4234             d;\r
4235 \r
4236         for(eid in El.cache){\r
4237             el = El.cache[eid];\r
4238             d = el.dom;\r
4239             // -------------------------------------------------------\r
4240             // Determining what is garbage:\r
4241             // -------------------------------------------------------\r
4242             // !d\r
4243             // dom node is null, definitely garbage\r
4244             // -------------------------------------------------------\r
4245             // !d.parentNode\r
4246             // no parentNode == direct orphan, definitely garbage\r
4247             // -------------------------------------------------------\r
4248             // !d.offsetParent && !document.getElementById(eid)\r
4249             // display none elements have no offsetParent so we will\r
4250             // also try to look it up by it's id. However, check\r
4251             // offsetParent first so we don't do unneeded lookups.\r
4252             // This enables collection of elements that are not orphans\r
4253             // directly, but somewhere up the line they have an orphan\r
4254             // parent.\r
4255             // -------------------------------------------------------\r
4256             if(!d || !d.parentNode || (!d.offsetParent && !DOC.getElementById(eid))){\r
4257                 delete El.cache[eid];\r
4258                 if(d && Ext.enableListenerCollection){\r
4259                     Ext.EventManager.removeAll(d);\r
4260                 }\r
4261             }\r
4262         }\r
4263     }\r
4264 }\r
4265 El.collectorThreadId = setInterval(garbageCollect, 30000);\r
4266 \r
4267 var flyFn = function(){};\r
4268 flyFn.prototype = El.prototype;\r
4269 \r
4270 // dom is optional\r
4271 El.Flyweight = function(dom){\r
4272     this.dom = dom;\r
4273 };\r
4274 \r
4275 El.Flyweight.prototype = new flyFn();\r
4276 El.Flyweight.prototype.isFlyweight = true;\r
4277 El._flyweights = {};\r
4278 \r
4279 /**\r
4280  * <p>Gets the globally shared flyweight Element, with the passed node as the active element. Do not store a reference to this element -\r
4281  * the dom node can be overwritten by other code. Shorthand of {@link Ext.Element#fly}</p>\r
4282  * <p>Use this to make one-time references to DOM elements which are not going to be accessed again either by\r
4283  * application code, or by Ext's classes. If accessing an element which will be processed regularly, then {@link Ext#get}\r
4284  * will be more appropriate to take advantage of the caching provided by the Ext.Element class.</p>\r
4285  * @param {String/HTMLElement} el The dom node or id\r
4286  * @param {String} named (optional) Allows for creation of named reusable flyweights to prevent conflicts\r
4287  * (e.g. internally Ext uses "_global")\r
4288  * @return {Element} The shared Element object (or null if no matching element was found)\r
4289  * @member Ext.Element\r
4290  * @method fly\r
4291  */\r
4292 El.fly = function(el, named){\r
4293     var ret = null;\r
4294     named = named || '_global';\r
4295 \r
4296     if (el = Ext.getDom(el)) {\r
4297         (El._flyweights[named] = El._flyweights[named] || new El.Flyweight()).dom = el;\r
4298         ret = El._flyweights[named];\r
4299     }\r
4300     return ret;\r
4301 };\r
4302 \r
4303 /**\r
4304  * Retrieves Ext.Element objects.\r
4305  * <p><b>This method does not retrieve {@link Ext.Component Component}s.</b> This method\r
4306  * retrieves Ext.Element objects which encapsulate DOM elements. To retrieve a Component by\r
4307  * its ID, use {@link Ext.ComponentMgr#get}.</p>\r
4308  * <p>Uses simple caching to consistently return the same object. Automatically fixes if an\r
4309  * object was recreated with the same id via AJAX or DOM.</p>\r
4310  * Shorthand of {@link Ext.Element#get}\r
4311  * @param {Mixed} el The id of the node, a DOM Node or an existing Element.\r
4312  * @return {Element} The Element object (or null if no matching element was found)\r
4313  * @member Ext\r
4314  * @method get\r
4315  */\r
4316 Ext.get = El.get;\r
4317 \r
4318 /**\r
4319  * <p>Gets the globally shared flyweight Element, with the passed node as the active element. Do not store a reference to this element -\r
4320  * the dom node can be overwritten by other code. Shorthand of {@link Ext.Element#fly}</p>\r
4321  * <p>Use this to make one-time references to DOM elements which are not going to be accessed again either by\r
4322  * application code, or by Ext's classes. If accessing an element which will be processed regularly, then {@link Ext#get}\r
4323  * will be more appropriate to take advantage of the caching provided by the Ext.Element class.</p>\r
4324  * @param {String/HTMLElement} el The dom node or id\r
4325  * @param {String} named (optional) Allows for creation of named reusable flyweights to prevent conflicts\r
4326  * (e.g. internally Ext uses "_global")\r
4327  * @return {Element} The shared Element object (or null if no matching element was found)\r
4328  * @member Ext\r
4329  * @method fly\r
4330  */\r
4331 Ext.fly = El.fly;\r
4332 \r
4333 // speedy lookup for elements never to box adjust\r
4334 var noBoxAdjust = Ext.isStrict ? {\r
4335     select:1\r
4336 } : {\r
4337     input:1, select:1, textarea:1\r
4338 };\r
4339 if(Ext.isIE || Ext.isGecko){\r
4340     noBoxAdjust['button'] = 1;\r
4341 }\r
4342 \r
4343 \r
4344 Ext.EventManager.on(window, 'unload', function(){\r
4345     delete El.cache;\r
4346     delete El.dataCache;\r
4347     delete El._flyweights;\r
4348 });\r
4349 })();\r
4350 /**\r
4351  * @class Ext.Element\r
4352  */\r
4353 Ext.Element.addMethods({    \r
4354     /**\r
4355      * Stops the specified event(s) from bubbling and optionally prevents the default action\r
4356      * @param {String/Array} eventName an event / array of events to stop from bubbling\r
4357      * @param {Boolean} preventDefault (optional) true to prevent the default action too\r
4358      * @return {Ext.Element} this\r
4359      */\r
4360     swallowEvent : function(eventName, preventDefault){\r
4361             var me = this;\r
4362         function fn(e){\r
4363             e.stopPropagation();\r
4364             if(preventDefault){\r
4365                 e.preventDefault();\r
4366             }\r
4367         }\r
4368         if(Ext.isArray(eventName)){            \r
4369                 Ext.each(eventName, function(e) {\r
4370                  me.on(e, fn);\r
4371             });\r
4372             return me;\r
4373         }\r
4374         me.on(eventName, fn);\r
4375         return me;\r
4376     },\r
4377     \r
4378     /**\r
4379      * Create an event handler on this element such that when the event fires and is handled by this element,\r
4380      * it will be relayed to another object (i.e., fired again as if it originated from that object instead).\r
4381      * @param {String} eventName The type of event to relay\r
4382      * @param {Object} object Any object that extends {@link Ext.util.Observable} that will provide the context\r
4383      * for firing the relayed event\r
4384      */\r
4385     relayEvent : function(eventName, observable){\r
4386         this.on(eventName, function(e){\r
4387             observable.fireEvent(eventName, e);\r
4388         });\r
4389     },\r
4390     \r
4391         /**\r
4392      * Removes worthless text nodes\r
4393      * @param {Boolean} forceReclean (optional) By default the element\r
4394      * keeps track if it has been cleaned already so\r
4395      * you can call this over and over. However, if you update the element and\r
4396      * need to force a reclean, you can pass true.\r
4397      */\r
4398     clean : function(forceReclean){\r
4399         var me = this, \r
4400             dom = me.dom,\r
4401                 n = dom.firstChild, \r
4402                 ni = -1;\r
4403                 \r
4404             if(Ext.Element.data(dom, 'isCleaned') && forceReclean !== true){\r
4405             return me;\r
4406         }      \r
4407                 \r
4408             while(n){\r
4409                 var nx = n.nextSibling;\r
4410             if(n.nodeType == 3 && !/\S/.test(n.nodeValue)){\r
4411                 dom.removeChild(n);\r
4412             }else{\r
4413                 n.nodeIndex = ++ni;\r
4414             }\r
4415                 n = nx;\r
4416             }\r
4417         Ext.Element.data(dom, 'isCleaned', true);\r
4418             return me;\r
4419         },\r
4420     \r
4421     /**\r
4422      * Direct access to the Updater {@link Ext.Updater#update} method. The method takes the same object\r
4423      * parameter as {@link Ext.Updater#update}\r
4424      * @return {Ext.Element} this\r
4425      */\r
4426     load : function(){\r
4427         var um = this.getUpdater();\r
4428         um.update.apply(um, arguments);\r
4429         return this;\r
4430     },\r
4431 \r
4432     /**\r
4433     * Gets this element's {@link Ext.Updater Updater}\r
4434     * @return {Ext.Updater} The Updater\r
4435     */\r
4436     getUpdater : function(){\r
4437         return this.updateManager || (this.updateManager = new Ext.Updater(this));\r
4438     },\r
4439     \r
4440         /**\r
4441     * Update the innerHTML of this element, optionally searching for and processing scripts\r
4442     * @param {String} html The new HTML\r
4443     * @param {Boolean} loadScripts (optional) True to look for and process scripts (defaults to false)\r
4444     * @param {Function} callback (optional) For async script loading you can be notified when the update completes\r
4445     * @return {Ext.Element} this\r
4446      */\r
4447     update : function(html, loadScripts, callback){\r
4448         html = html || "";\r
4449             \r
4450         if(loadScripts !== true){\r
4451             this.dom.innerHTML = html;\r
4452             if(Ext.isFunction(callback)){\r
4453                 callback();\r
4454             }\r
4455             return this;\r
4456         }\r
4457         \r
4458         var id = Ext.id(),\r
4459                 dom = this.dom;\r
4460 \r
4461         html += '<span id="' + id + '"></span>';\r
4462 \r
4463         Ext.lib.Event.onAvailable(id, function(){\r
4464             var DOC = document,\r
4465                 hd = DOC.getElementsByTagName("head")[0],\r
4466                 re = /(?:<script([^>]*)?>)((\n|\r|.)*?)(?:<\/script>)/ig,\r
4467                 srcRe = /\ssrc=([\'\"])(.*?)\1/i,\r
4468                 typeRe = /\stype=([\'\"])(.*?)\1/i,\r
4469                 match,\r
4470                 attrs,\r
4471                 srcMatch,\r
4472                 typeMatch,\r
4473                 el,\r
4474                 s;\r
4475 \r
4476             while((match = re.exec(html))){\r
4477                 attrs = match[1];\r
4478                 srcMatch = attrs ? attrs.match(srcRe) : false;\r
4479                 if(srcMatch && srcMatch[2]){\r
4480                    s = DOC.createElement("script");\r
4481                    s.src = srcMatch[2];\r
4482                    typeMatch = attrs.match(typeRe);\r
4483                    if(typeMatch && typeMatch[2]){\r
4484                        s.type = typeMatch[2];\r
4485                    }\r
4486                    hd.appendChild(s);\r
4487                 }else if(match[2] && match[2].length > 0){\r
4488                     if(window.execScript) {\r
4489                        window.execScript(match[2]);\r
4490                     } else {\r
4491                        window.eval(match[2]);\r
4492                     }\r
4493                 }\r
4494             }\r
4495             el = DOC.getElementById(id);\r
4496             if(el){Ext.removeNode(el);}\r
4497             if(Ext.isFunction(callback)){\r
4498                 callback();\r
4499             }\r
4500         });\r
4501         dom.innerHTML = html.replace(/(?:<script.*?>)((\n|\r|.)*?)(?:<\/script>)/ig, "");\r
4502         return this;\r
4503     },\r
4504     \r
4505     /**\r
4506      * Creates a proxy element of this element\r
4507      * @param {String/Object} config The class name of the proxy element or a DomHelper config object\r
4508      * @param {String/HTMLElement} renderTo (optional) The element or element id to render the proxy to (defaults to document.body)\r
4509      * @param {Boolean} matchBox (optional) True to align and size the proxy to this element now (defaults to false)\r
4510      * @return {Ext.Element} The new proxy element\r
4511      */\r
4512     createProxy : function(config, renderTo, matchBox){\r
4513         config = Ext.isObject(config) ? config : {tag : "div", cls: config};\r
4514 \r
4515         var me = this,\r
4516                 proxy = renderTo ? Ext.DomHelper.append(renderTo, config, true) :\r
4517                                                    Ext.DomHelper.insertBefore(me.dom, config, true);        \r
4518         \r
4519         if(matchBox && me.setBox && me.getBox){ // check to make sure Element.position.js is loaded\r
4520            proxy.setBox(me.getBox());\r
4521         }\r
4522         return proxy;\r
4523     }\r
4524 });\r
4525 \r
4526 Ext.Element.prototype.getUpdateManager = Ext.Element.prototype.getUpdater;\r
4527 \r
4528 // private\r
4529 Ext.Element.uncache = function(el){\r
4530     for(var i = 0, a = arguments, len = a.length; i < len; i++) {\r
4531         if(a[i]){\r
4532             delete Ext.Element.cache[a[i].id || a[i]];\r
4533         }\r
4534     }\r
4535 };/**\r
4536  * @class Ext.Element\r
4537  */\r
4538 Ext.Element.addMethods({\r
4539     /**\r
4540      * Gets the x,y coordinates specified by the anchor position on the element.\r
4541      * @param {String} anchor (optional) The specified anchor position (defaults to "c").  See {@link #alignTo}\r
4542      * for details on supported anchor positions.\r
4543      * @param {Boolean} local (optional) True to get the local (element top/left-relative) anchor position instead\r
4544      * of page coordinates\r
4545      * @param {Object} size (optional) An object containing the size to use for calculating anchor position\r
4546      * {width: (target width), height: (target height)} (defaults to the element's current size)\r
4547      * @return {Array} [x, y] An array containing the element's x and y coordinates\r
4548      */\r
4549     getAnchorXY : function(anchor, local, s){\r
4550         //Passing a different size is useful for pre-calculating anchors,\r
4551         //especially for anchored animations that change the el size.\r
4552                 anchor = (anchor || "tl").toLowerCase();\r
4553         s = s || {};\r
4554         \r
4555         var me = this,        \r
4556                 vp = me.dom == document.body || me.dom == document,\r
4557                 w = s.width || vp ? Ext.lib.Dom.getViewWidth() : me.getWidth(),\r
4558                 h = s.height || vp ? Ext.lib.Dom.getViewHeight() : me.getHeight(),                              \r
4559                 xy,             \r
4560                 r = Math.round,\r
4561                 o = me.getXY(),\r
4562                 scroll = me.getScroll(),\r
4563                 extraX = vp ? scroll.left : !local ? o[0] : 0,\r
4564                 extraY = vp ? scroll.top : !local ? o[1] : 0,\r
4565                 hash = {\r
4566                         c  : [r(w * 0.5), r(h * 0.5)],\r
4567                         t  : [r(w * 0.5), 0],\r
4568                         l  : [0, r(h * 0.5)],\r
4569                         r  : [w, r(h * 0.5)],\r
4570                         b  : [r(w * 0.5), h],\r
4571                         tl : [0, 0],    \r
4572                         bl : [0, h],\r
4573                         br : [w, h],\r
4574                         tr : [w, 0]\r
4575                 };\r
4576         \r
4577         xy = hash[anchor];      \r
4578         return [xy[0] + extraX, xy[1] + extraY]; \r
4579     },\r
4580 \r
4581     /**\r
4582      * Anchors an element to another element and realigns it when the window is resized.\r
4583      * @param {Mixed} element The element to align to.\r
4584      * @param {String} position The position to align to.\r
4585      * @param {Array} offsets (optional) Offset the positioning by [x, y]\r
4586      * @param {Boolean/Object} animate (optional) True for the default animation or a standard Element animation config object\r
4587      * @param {Boolean/Number} monitorScroll (optional) True to monitor body scroll and reposition. If this parameter\r
4588      * is a number, it is used as the buffer delay (defaults to 50ms).\r
4589      * @param {Function} callback The function to call after the animation finishes\r
4590      * @return {Ext.Element} this\r
4591      */\r
4592     anchorTo : function(el, alignment, offsets, animate, monitorScroll, callback){        \r
4593             var me = this,\r
4594             dom = me.dom;\r
4595             \r
4596             function action(){\r
4597             Ext.fly(dom).alignTo(el, alignment, offsets, animate);\r
4598             Ext.callback(callback, Ext.fly(dom));\r
4599         }\r
4600         \r
4601         Ext.EventManager.onWindowResize(action, me);\r
4602         \r
4603         if(!Ext.isEmpty(monitorScroll)){\r
4604             Ext.EventManager.on(window, 'scroll', action, me,\r
4605                 {buffer: !isNaN(monitorScroll) ? monitorScroll : 50});\r
4606         }\r
4607         action.call(me); // align immediately\r
4608         return me;\r
4609     },\r
4610 \r
4611     /**\r
4612      * Gets the x,y coordinates to align this element with another element. See {@link #alignTo} for more info on the\r
4613      * supported position values.\r
4614      * @param {Mixed} element The element to align to.\r
4615      * @param {String} position The position to align to.\r
4616      * @param {Array} offsets (optional) Offset the positioning by [x, y]\r
4617      * @return {Array} [x, y]\r
4618      */\r
4619     getAlignToXY : function(el, p, o){      \r
4620         el = Ext.get(el);\r
4621         \r
4622         if(!el || !el.dom){\r
4623             throw "Element.alignToXY with an element that doesn't exist";\r
4624         }\r
4625         \r
4626         o = o || [0,0];\r
4627         p = (p == "?" ? "tl-bl?" : (!/-/.test(p) && p !== "" ? "tl-" + p : p || "tl-bl")).toLowerCase();       \r
4628                 \r
4629         var me = this,\r
4630                 d = me.dom,\r
4631                 a1,\r
4632                 a2,\r
4633                 x,\r
4634                 y,\r
4635                 //constrain the aligned el to viewport if necessary\r
4636                 w,\r
4637                 h,\r
4638                 r,\r
4639                 dw = Ext.lib.Dom.getViewWidth() -10, // 10px of margin for ie\r
4640                 dh = Ext.lib.Dom.getViewHeight()-10, // 10px of margin for ie\r
4641                 p1y,\r
4642                 p1x,            \r
4643                 p2y,\r
4644                 p2x,\r
4645                 swapY,\r
4646                 swapX,\r
4647                 doc = document,\r
4648                 docElement = doc.documentElement,\r
4649                 docBody = doc.body,\r
4650                 scrollX = (docElement.scrollLeft || docBody.scrollLeft || 0)+5,\r
4651                 scrollY = (docElement.scrollTop || docBody.scrollTop || 0)+5,\r
4652                 c = false, //constrain to viewport\r
4653                 p1 = "", \r
4654                 p2 = "",\r
4655                 m = p.match(/^([a-z]+)-([a-z]+)(\?)?$/);\r
4656         \r
4657         if(!m){\r
4658            throw "Element.alignTo with an invalid alignment " + p;\r
4659         }\r
4660         \r
4661         p1 = m[1]; \r
4662         p2 = m[2]; \r
4663         c = !!m[3];\r
4664 \r
4665         //Subtract the aligned el's internal xy from the target's offset xy\r
4666         //plus custom offset to get the aligned el's new offset xy\r
4667         a1 = me.getAnchorXY(p1, true);\r
4668         a2 = el.getAnchorXY(p2, false);\r
4669 \r
4670         x = a2[0] - a1[0] + o[0];\r
4671         y = a2[1] - a1[1] + o[1];\r
4672 \r
4673         if(c){    \r
4674                w = me.getWidth();\r
4675            h = me.getHeight();\r
4676            r = el.getRegion();       \r
4677            //If we are at a viewport boundary and the aligned el is anchored on a target border that is\r
4678            //perpendicular to the vp border, allow the aligned el to slide on that border,\r
4679            //otherwise swap the aligned el to the opposite border of the target.\r
4680            p1y = p1.charAt(0);\r
4681            p1x = p1.charAt(p1.length-1);\r
4682            p2y = p2.charAt(0);\r
4683            p2x = p2.charAt(p2.length-1);\r
4684            swapY = ((p1y=="t" && p2y=="b") || (p1y=="b" && p2y=="t"));\r
4685            swapX = ((p1x=="r" && p2x=="l") || (p1x=="l" && p2x=="r"));          \r
4686            \r
4687 \r
4688            if (x + w > dw + scrollX) {\r
4689                 x = swapX ? r.left-w : dw+scrollX-w;\r
4690            }\r
4691            if (x < scrollX) {\r
4692                x = swapX ? r.right : scrollX;\r
4693            }\r
4694            if (y + h > dh + scrollY) {\r
4695                 y = swapY ? r.top-h : dh+scrollY-h;\r
4696             }\r
4697            if (y < scrollY){\r
4698                y = swapY ? r.bottom : scrollY;\r
4699            }\r
4700         }\r
4701         return [x,y];\r
4702     },\r
4703 \r
4704     /**\r
4705      * Aligns this element with another element relative to the specified anchor points. If the other element is the\r
4706      * document it aligns it to the viewport.\r
4707      * The position parameter is optional, and can be specified in any one of the following formats:\r
4708      * <ul>\r
4709      *   <li><b>Blank</b>: Defaults to aligning the element's top-left corner to the target's bottom-left corner ("tl-bl").</li>\r
4710      *   <li><b>One anchor (deprecated)</b>: The passed anchor position is used as the target element's anchor point.\r
4711      *       The element being aligned will position its top-left corner (tl) to that point.  <i>This method has been\r
4712      *       deprecated in favor of the newer two anchor syntax below</i>.</li>\r
4713      *   <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
4714      *       element's anchor point, and the second value is used as the target's anchor point.</li>\r
4715      * </ul>\r
4716      * In addition to the anchor points, the position parameter also supports the "?" character.  If "?" is passed at the end of\r
4717      * the position string, the element will attempt to align as specified, but the position will be adjusted to constrain to\r
4718      * the viewport if necessary.  Note that the element being aligned might be swapped to align to a different position than\r
4719      * that specified in order to enforce the viewport constraints.\r
4720      * Following are all of the supported anchor positions:\r
4721 <pre>\r
4722 Value  Description\r
4723 -----  -----------------------------\r
4724 tl     The top left corner (default)\r
4725 t      The center of the top edge\r
4726 tr     The top right corner\r
4727 l      The center of the left edge\r
4728 c      In the center of the element\r
4729 r      The center of the right edge\r
4730 bl     The bottom left corner\r
4731 b      The center of the bottom edge\r
4732 br     The bottom right corner\r
4733 </pre>\r
4734 Example Usage:\r
4735 <pre><code>\r
4736 // align el to other-el using the default positioning ("tl-bl", non-constrained)\r
4737 el.alignTo("other-el");\r
4738 \r
4739 // align the top left corner of el with the top right corner of other-el (constrained to viewport)\r
4740 el.alignTo("other-el", "tr?");\r
4741 \r
4742 // align the bottom right corner of el with the center left edge of other-el\r
4743 el.alignTo("other-el", "br-l?");\r
4744 \r
4745 // align the center of el with the bottom left corner of other-el and\r
4746 // adjust the x position by -6 pixels (and the y position by 0)\r
4747 el.alignTo("other-el", "c-bl", [-6, 0]);\r
4748 </code></pre>\r
4749      * @param {Mixed} element The element to align to.\r
4750      * @param {String} position The position to align to.\r
4751      * @param {Array} offsets (optional) Offset the positioning by [x, y]\r
4752      * @param {Boolean/Object} animate (optional) true for the default animation or a standard Element animation config object\r
4753      * @return {Ext.Element} this\r
4754      */\r
4755     alignTo : function(element, position, offsets, animate){\r
4756             var me = this;\r
4757         return me.setXY(me.getAlignToXY(element, position, offsets),\r
4758                                 me.preanim && !!animate ? me.preanim(arguments, 3) : false);\r
4759     },\r
4760     \r
4761     // private ==>  used outside of core\r
4762     adjustForConstraints : function(xy, parent, offsets){\r
4763         return this.getConstrainToXY(parent || document, false, offsets, xy) ||  xy;\r
4764     },\r
4765 \r
4766     // private ==>  used outside of core\r
4767     getConstrainToXY : function(el, local, offsets, proposedXY){   \r
4768             var os = {top:0, left:0, bottom:0, right: 0};\r
4769 \r
4770         return function(el, local, offsets, proposedXY){\r
4771             el = Ext.get(el);\r
4772             offsets = offsets ? Ext.applyIf(offsets, os) : os;\r
4773 \r
4774             var vw, vh, vx = 0, vy = 0;\r
4775             if(el.dom == document.body || el.dom == document){\r
4776                 vw =Ext.lib.Dom.getViewWidth();\r
4777                 vh = Ext.lib.Dom.getViewHeight();\r
4778             }else{\r
4779                 vw = el.dom.clientWidth;\r
4780                 vh = el.dom.clientHeight;\r
4781                 if(!local){\r
4782                     var vxy = el.getXY();\r
4783                     vx = vxy[0];\r
4784                     vy = vxy[1];\r
4785                 }\r
4786             }\r
4787 \r
4788             var s = el.getScroll();\r
4789 \r
4790             vx += offsets.left + s.left;\r
4791             vy += offsets.top + s.top;\r
4792 \r
4793             vw -= offsets.right;\r
4794             vh -= offsets.bottom;\r
4795 \r
4796             var vr = vx+vw;\r
4797             var vb = vy+vh;\r
4798 \r
4799             var xy = proposedXY || (!local ? this.getXY() : [this.getLeft(true), this.getTop(true)]);\r
4800             var x = xy[0], y = xy[1];\r
4801             var w = this.dom.offsetWidth, h = this.dom.offsetHeight;\r
4802 \r
4803             // only move it if it needs it\r
4804             var moved = false;\r
4805 \r
4806             // first validate right/bottom\r
4807             if((x + w) > vr){\r
4808                 x = vr - w;\r
4809                 moved = true;\r
4810             }\r
4811             if((y + h) > vb){\r
4812                 y = vb - h;\r
4813                 moved = true;\r
4814             }\r
4815             // then make sure top/left isn't negative\r
4816             if(x < vx){\r
4817                 x = vx;\r
4818                 moved = true;\r
4819             }\r
4820             if(y < vy){\r
4821                 y = vy;\r
4822                 moved = true;\r
4823             }\r
4824             return moved ? [x, y] : false;\r
4825         };\r
4826     }(),\r
4827             \r
4828             \r
4829                 \r
4830 //         el = Ext.get(el);\r
4831 //         offsets = Ext.applyIf(offsets || {}, {top : 0, left : 0, bottom : 0, right : 0});\r
4832 \r
4833 //         var  me = this,\r
4834 //              doc = document,\r
4835 //              s = el.getScroll(),\r
4836 //              vxy = el.getXY(),\r
4837 //              vx = offsets.left + s.left, \r
4838 //              vy = offsets.top + s.top,               \r
4839 //              vw = -offsets.right, \r
4840 //              vh = -offsets.bottom, \r
4841 //              vr,\r
4842 //              vb,\r
4843 //              xy = proposedXY || (!local ? me.getXY() : [me.getLeft(true), me.getTop(true)]),\r
4844 //              x = xy[0],\r
4845 //              y = xy[1],\r
4846 //              w = me.dom.offsetWidth, h = me.dom.offsetHeight,\r
4847 //              moved = false; // only move it if it needs it\r
4848 //       \r
4849 //              \r
4850 //         if(el.dom == doc.body || el.dom == doc){\r
4851 //             vw += Ext.lib.Dom.getViewWidth();\r
4852 //             vh += Ext.lib.Dom.getViewHeight();\r
4853 //         }else{\r
4854 //             vw += el.dom.clientWidth;\r
4855 //             vh += el.dom.clientHeight;\r
4856 //             if(!local){                    \r
4857 //                 vx += vxy[0];\r
4858 //                 vy += vxy[1];\r
4859 //             }\r
4860 //         }\r
4861 \r
4862 //         // first validate right/bottom\r
4863 //         if(x + w > vx + vw){\r
4864 //             x = vx + vw - w;\r
4865 //             moved = true;\r
4866 //         }\r
4867 //         if(y + h > vy + vh){\r
4868 //             y = vy + vh - h;\r
4869 //             moved = true;\r
4870 //         }\r
4871 //         // then make sure top/left isn't negative\r
4872 //         if(x < vx){\r
4873 //             x = vx;\r
4874 //             moved = true;\r
4875 //         }\r
4876 //         if(y < vy){\r
4877 //             y = vy;\r
4878 //             moved = true;\r
4879 //         }\r
4880 //         return moved ? [x, y] : false;\r
4881 //    },\r
4882     \r
4883     /**\r
4884     * Calculates the x, y to center this element on the screen\r
4885     * @return {Array} The x, y values [x, y]\r
4886     */\r
4887     getCenterXY : function(){\r
4888         return this.getAlignToXY(document, 'c-c');\r
4889     },\r
4890 \r
4891     /**\r
4892     * Centers the Element in either the viewport, or another Element.\r
4893     * @param {Mixed} centerIn (optional) The element in which to center the element.\r
4894     */\r
4895     center : function(centerIn){\r
4896         return this.alignTo(centerIn || document, 'c-c');        \r
4897     }    \r
4898 });\r
4899 /**\r
4900  * @class Ext.Element\r
4901  */\r
4902 Ext.Element.addMethods(function(){\r
4903         var PARENTNODE = 'parentNode',\r
4904                 NEXTSIBLING = 'nextSibling',\r
4905                 PREVIOUSSIBLING = 'previousSibling',\r
4906                 DQ = Ext.DomQuery,\r
4907                 GET = Ext.get;\r
4908         \r
4909         return {\r
4910                 /**\r
4911              * 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
4912              * @param {String} selector The simple selector to test\r
4913              * @param {Number/Mixed} maxDepth (optional) The max depth to search as a number or element (defaults to 50 || document.body)\r
4914              * @param {Boolean} returnEl (optional) True to return a Ext.Element object instead of DOM node\r
4915              * @return {HTMLElement} The matching DOM node (or null if no match was found)\r
4916              */\r
4917             findParent : function(simpleSelector, maxDepth, returnEl){\r
4918                 var p = this.dom,\r
4919                         b = document.body, \r
4920                         depth = 0,                      \r
4921                         stopEl;         \r
4922             if(Ext.isGecko && Object.prototype.toString.call(p) == '[object XULElement]') {\r
4923                 return null;\r
4924             }\r
4925                 maxDepth = maxDepth || 50;\r
4926                 if (isNaN(maxDepth)) {\r
4927                     stopEl = Ext.getDom(maxDepth);\r
4928                     maxDepth = Number.MAX_VALUE;\r
4929                 }\r
4930                 while(p && p.nodeType == 1 && depth < maxDepth && p != b && p != stopEl){\r
4931                     if(DQ.is(p, simpleSelector)){\r
4932                         return returnEl ? GET(p) : p;\r
4933                     }\r
4934                     depth++;\r
4935                     p = p.parentNode;\r
4936                 }\r
4937                 return null;\r
4938             },\r
4939         \r
4940             /**\r
4941              * Looks at parent nodes for a match of the passed simple selector (e.g. div.some-class or span:first-child)\r
4942              * @param {String} selector The simple selector to test\r
4943              * @param {Number/Mixed} maxDepth (optional) The max depth to\r
4944                     search as a number or element (defaults to 10 || document.body)\r
4945              * @param {Boolean} returnEl (optional) True to return a Ext.Element object instead of DOM node\r
4946              * @return {HTMLElement} The matching DOM node (or null if no match was found)\r
4947              */\r
4948             findParentNode : function(simpleSelector, maxDepth, returnEl){\r
4949                 var p = Ext.fly(this.dom.parentNode, '_internal');\r
4950                 return p ? p.findParent(simpleSelector, maxDepth, returnEl) : null;\r
4951             },\r
4952         \r
4953             /**\r
4954              * 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
4955              * This is a shortcut for findParentNode() that always returns an Ext.Element.\r
4956              * @param {String} selector The simple selector to test\r
4957              * @param {Number/Mixed} maxDepth (optional) The max depth to\r
4958                     search as a number or element (defaults to 10 || document.body)\r
4959              * @return {Ext.Element} The matching DOM node (or null if no match was found)\r
4960              */\r
4961             up : function(simpleSelector, maxDepth){\r
4962                 return this.findParentNode(simpleSelector, maxDepth, true);\r
4963             },\r
4964         \r
4965             /**\r
4966              * Creates a {@link Ext.CompositeElement} for child nodes based on the passed CSS selector (the selector should not contain an id).\r
4967              * @param {String} selector The CSS selector\r
4968              * @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
4969              * @return {CompositeElement/CompositeElementLite} The composite element\r
4970              */\r
4971             select : function(selector, unique){\r
4972                 return Ext.Element.select(selector, unique, this.dom);\r
4973             },\r
4974         \r
4975             /**\r
4976              * Selects child nodes based on the passed CSS selector (the selector should not contain an id).\r
4977              * @param {String} selector The CSS selector\r
4978              * @return {Array} An array of the matched nodes\r
4979              */\r
4980             query : function(selector, unique){\r
4981                 return DQ.select(selector, this.dom);\r
4982             },\r
4983         \r
4984             /**\r
4985              * Selects a single child at any depth below this element based on the passed CSS selector (the selector should not contain an id).\r
4986              * @param {String} selector The CSS selector\r
4987              * @param {Boolean} returnDom (optional) True to return the DOM node instead of Ext.Element (defaults to false)\r
4988              * @return {HTMLElement/Ext.Element} The child Ext.Element (or DOM node if returnDom = true)\r
4989              */\r
4990             child : function(selector, returnDom){\r
4991                 var n = DQ.selectNode(selector, this.dom);\r
4992                 return returnDom ? n : GET(n);\r
4993             },\r
4994         \r
4995             /**\r
4996              * Selects a single *direct* child based on the passed CSS selector (the selector should not contain an id).\r
4997              * @param {String} selector The CSS selector\r
4998              * @param {Boolean} returnDom (optional) True to return the DOM node instead of Ext.Element (defaults to false)\r
4999              * @return {HTMLElement/Ext.Element} The child Ext.Element (or DOM node if returnDom = true)\r
5000              */\r
5001             down : function(selector, returnDom){\r
5002                 var n = DQ.selectNode(" > " + selector, this.dom);\r
5003                 return returnDom ? n : GET(n);\r
5004             },\r
5005         \r
5006                  /**\r
5007              * Gets the parent node for this element, optionally chaining up trying to match a selector\r
5008              * @param {String} selector (optional) Find a parent node that matches the passed simple selector\r
5009              * @param {Boolean} returnDom (optional) True to return a raw dom node instead of an Ext.Element\r
5010              * @return {Ext.Element/HTMLElement} The parent node or null\r
5011                  */\r
5012             parent : function(selector, returnDom){\r
5013                 return this.matchNode(PARENTNODE, PARENTNODE, selector, returnDom);\r
5014             },\r
5015         \r
5016              /**\r
5017              * Gets the next sibling, skipping text nodes\r
5018              * @param {String} selector (optional) Find the next sibling that matches the passed simple selector\r
5019              * @param {Boolean} returnDom (optional) True to return a raw dom node instead of an Ext.Element\r
5020              * @return {Ext.Element/HTMLElement} The next sibling or null\r
5021                  */\r
5022             next : function(selector, returnDom){\r
5023                 return this.matchNode(NEXTSIBLING, NEXTSIBLING, selector, returnDom);\r
5024             },\r
5025         \r
5026             /**\r
5027              * Gets the previous sibling, skipping text nodes\r
5028              * @param {String} selector (optional) Find the previous sibling that matches the passed simple selector\r
5029              * @param {Boolean} returnDom (optional) True to return a raw dom node instead of an Ext.Element\r
5030              * @return {Ext.Element/HTMLElement} The previous sibling or null\r
5031                  */\r
5032             prev : function(selector, returnDom){\r
5033                 return this.matchNode(PREVIOUSSIBLING, PREVIOUSSIBLING, selector, returnDom);\r
5034             },\r
5035         \r
5036         \r
5037             /**\r
5038              * Gets the first child, skipping text nodes\r
5039              * @param {String} selector (optional) Find the next sibling that matches the passed simple selector\r
5040              * @param {Boolean} returnDom (optional) True to return a raw dom node instead of an Ext.Element\r
5041              * @return {Ext.Element/HTMLElement} The first child or null\r
5042                  */\r
5043             first : function(selector, returnDom){\r
5044                 return this.matchNode(NEXTSIBLING, 'firstChild', selector, returnDom);\r
5045             },\r
5046         \r
5047             /**\r
5048              * Gets the last child, skipping text nodes\r
5049              * @param {String} selector (optional) Find the previous sibling that matches the passed simple selector\r
5050              * @param {Boolean} returnDom (optional) True to return a raw dom node instead of an Ext.Element\r
5051              * @return {Ext.Element/HTMLElement} The last child or null\r
5052                  */\r
5053             last : function(selector, returnDom){\r
5054                 return this.matchNode(PREVIOUSSIBLING, 'lastChild', selector, returnDom);\r
5055             },\r
5056             \r
5057             matchNode : function(dir, start, selector, returnDom){\r
5058                 var n = this.dom[start];\r
5059                 while(n){\r
5060                     if(n.nodeType == 1 && (!selector || DQ.is(n, selector))){\r
5061                         return !returnDom ? GET(n) : n;\r
5062                     }\r
5063                     n = n[dir];\r
5064                 }\r
5065                 return null;\r
5066             }   \r
5067     }\r
5068 }());/**\r
5069  * @class Ext.Element\r
5070  */\r
5071 Ext.Element.addMethods(\r
5072 function() {\r
5073         var GETDOM = Ext.getDom,\r
5074                 GET = Ext.get,\r
5075                 DH = Ext.DomHelper;\r
5076         \r
5077         return {\r
5078             /**\r
5079              * Appends the passed element(s) to this element\r
5080              * @param {String/HTMLElement/Array/Element/CompositeElement} el\r
5081              * @return {Ext.Element} this\r
5082              */\r
5083             appendChild: function(el){        \r
5084                 return GET(el).appendTo(this);        \r
5085             },\r
5086         \r
5087             /**\r
5088              * Appends this element to the passed element\r
5089              * @param {Mixed} el The new parent element\r
5090              * @return {Ext.Element} this\r
5091              */\r
5092             appendTo: function(el){        \r
5093                 GETDOM(el).appendChild(this.dom);        \r
5094                 return this;\r
5095             },\r
5096         \r
5097             /**\r
5098              * Inserts this element before the passed element in the DOM\r
5099              * @param {Mixed} el The element before which this element will be inserted\r
5100              * @return {Ext.Element} this\r
5101              */\r
5102             insertBefore: function(el){                   \r
5103                 (el = GETDOM(el)).parentNode.insertBefore(this.dom, el);\r
5104                 return this;\r
5105             },\r
5106         \r
5107             /**\r
5108              * Inserts this element after the passed element in the DOM\r
5109              * @param {Mixed} el The element to insert after\r
5110              * @return {Ext.Element} this\r
5111              */\r
5112             insertAfter: function(el){\r
5113                 (el = GETDOM(el)).parentNode.insertBefore(this.dom, el.nextSibling);\r
5114                 return this;\r
5115             },\r
5116         \r
5117             /**\r
5118              * Inserts (or creates) an element (or DomHelper config) as the first child of this element\r
5119              * @param {Mixed/Object} el The id or element to insert or a DomHelper config to create and insert\r
5120              * @return {Ext.Element} The new child\r
5121              */\r
5122             insertFirst: function(el, returnDom){\r
5123             el = el || {};\r
5124             if(el.nodeType || el.dom || typeof el == 'string'){ // element\r
5125                 el = GETDOM(el);\r
5126                 this.dom.insertBefore(el, this.dom.firstChild);\r
5127                 return !returnDom ? GET(el) : el;\r
5128             }else{ // dh config\r
5129                 return this.createChild(el, this.dom.firstChild, returnDom);\r
5130             }\r
5131         },\r
5132         \r
5133             /**\r
5134              * Replaces the passed element with this element\r
5135              * @param {Mixed} el The element to replace\r
5136              * @return {Ext.Element} this\r
5137              */\r
5138             replace: function(el){\r
5139                 el = GET(el);\r
5140                 this.insertBefore(el);\r
5141                 el.remove();\r
5142                 return this;\r
5143             },\r
5144         \r
5145             /**\r
5146              * Replaces this element with the passed element\r
5147              * @param {Mixed/Object} el The new element or a DomHelper config of an element to create\r
5148              * @return {Ext.Element} this\r
5149              */\r
5150             replaceWith: function(el){\r
5151                     var me = this,\r
5152                         Element = Ext.Element;\r
5153             if(el.nodeType || el.dom || typeof el == 'string'){\r
5154                 el = GETDOM(el);\r
5155                 me.dom.parentNode.insertBefore(el, me.dom);\r
5156             }else{\r
5157                 el = DH.insertBefore(me.dom, el);\r
5158             }\r
5159                 \r
5160                 delete Element.cache[me.id];\r
5161                 Ext.removeNode(me.dom);      \r
5162                 me.id = Ext.id(me.dom = el);\r
5163                 return Element.cache[me.id] = me;        \r
5164             },\r
5165             \r
5166                 /**\r
5167                  * Creates the passed DomHelper config and appends it to this element or optionally inserts it before the passed child element.\r
5168                  * @param {Object} config DomHelper element config object.  If no tag is specified (e.g., {tag:'input'}) then a div will be\r
5169                  * automatically generated with the specified attributes.\r
5170                  * @param {HTMLElement} insertBefore (optional) a child element of this element\r
5171                  * @param {Boolean} returnDom (optional) true to return the dom node instead of creating an Element\r
5172                  * @return {Ext.Element} The new child element\r
5173                  */\r
5174                 createChild: function(config, insertBefore, returnDom){\r
5175                     config = config || {tag:'div'};\r
5176                     return insertBefore ? \r
5177                            DH.insertBefore(insertBefore, config, returnDom !== true) :  \r
5178                            DH[!this.dom.firstChild ? 'overwrite' : 'append'](this.dom, config,  returnDom !== true);\r
5179                 },\r
5180                 \r
5181                 /**\r
5182                  * Creates and wraps this element with another element\r
5183                  * @param {Object} config (optional) DomHelper element config object for the wrapper element or null for an empty div\r
5184                  * @param {Boolean} returnDom (optional) True to return the raw DOM element instead of Ext.Element\r
5185                  * @return {HTMLElement/Element} The newly created wrapper element\r
5186                  */\r
5187                 wrap: function(config, returnDom){        \r
5188                     var newEl = DH.insertBefore(this.dom, config || {tag: "div"}, !returnDom);\r
5189                     newEl.dom ? newEl.dom.appendChild(this.dom) : newEl.appendChild(this.dom);\r
5190                     return newEl;\r
5191                 },\r
5192                 \r
5193                 /**\r
5194                  * Inserts an html fragment into this element\r
5195                  * @param {String} where Where to insert the html in relation to this element - beforeBegin, afterBegin, beforeEnd, afterEnd.\r
5196                  * @param {String} html The HTML fragment\r
5197                  * @param {Boolean} returnEl (optional) True to return an Ext.Element (defaults to false)\r
5198                  * @return {HTMLElement/Ext.Element} The inserted node (or nearest related if more than 1 inserted)\r
5199                  */\r
5200                 insertHtml : function(where, html, returnEl){\r
5201                     var el = DH.insertHtml(where, this.dom, html);\r
5202                     return returnEl ? Ext.get(el) : el;\r
5203                 }\r
5204         }\r
5205 }());/**\r
5206  * @class Ext.Element\r
5207  */\r
5208 Ext.apply(Ext.Element.prototype, function() {\r
5209         var GETDOM = Ext.getDom,\r
5210                 GET = Ext.get,\r
5211                 DH = Ext.DomHelper;\r
5212         \r
5213         return {        \r
5214                 /**\r
5215              * Inserts (or creates) the passed element (or DomHelper config) as a sibling of this element\r
5216              * @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
5217              * @param {String} where (optional) 'before' or 'after' defaults to before\r
5218              * @param {Boolean} returnDom (optional) True to return the raw DOM element instead of Ext.Element\r
5219              * @return {Ext.Element} the inserted Element\r
5220              */\r
5221             insertSibling: function(el, where, returnDom){\r
5222                 var me = this,\r
5223                         rt;\r
5224                         \r
5225                 if(Ext.isArray(el)){            \r
5226                     Ext.each(el, function(e) {\r
5227                             rt = me.insertSibling(e, where, returnDom);\r
5228                     });\r
5229                     return rt;\r
5230                 }\r
5231                         \r
5232                 where = (where || 'before').toLowerCase();\r
5233                 el = el || {};\r
5234                 \r
5235             if(el.nodeType || el.dom){\r
5236                 rt = me.dom.parentNode.insertBefore(GETDOM(el), where == 'before' ? me.dom : me.dom.nextSibling);\r
5237                 if (!returnDom) {\r
5238                     rt = GET(rt);\r
5239                 }\r
5240             }else{\r
5241                 if (where == 'after' && !me.dom.nextSibling) {\r
5242                     rt = DH.append(me.dom.parentNode, el, !returnDom);\r
5243                 } else {                    \r
5244                     rt = DH[where == 'after' ? 'insertAfter' : 'insertBefore'](me.dom, el, !returnDom);\r
5245                 }\r
5246             }\r
5247                 return rt;\r
5248             }\r
5249     };\r
5250 }());/**
5251  * @class Ext.Element
5252  */
5253 Ext.Element.addMethods(function(){  
5254     // local style camelizing for speed
5255     var propCache = {},
5256         camelRe = /(-[a-z])/gi,
5257         classReCache = {},
5258         view = document.defaultView,
5259         propFloat = Ext.isIE ? 'styleFloat' : 'cssFloat',
5260         opacityRe = /alpha\(opacity=(.*)\)/i,
5261         trimRe = /^\s+|\s+$/g,
5262         EL = Ext.Element,   
5263         PADDING = "padding",
5264         MARGIN = "margin",
5265         BORDER = "border",
5266         LEFT = "-left",
5267         RIGHT = "-right",
5268         TOP = "-top",
5269         BOTTOM = "-bottom",
5270         WIDTH = "-width",    
5271         MATH = Math,
5272         HIDDEN = 'hidden',
5273         ISCLIPPED = 'isClipped',
5274         OVERFLOW = 'overflow',
5275         OVERFLOWX = 'overflow-x',
5276         OVERFLOWY = 'overflow-y',
5277         ORIGINALCLIP = 'originalClip',
5278         // special markup used throughout Ext when box wrapping elements    
5279         borders = {l: BORDER + LEFT + WIDTH, r: BORDER + RIGHT + WIDTH, t: BORDER + TOP + WIDTH, b: BORDER + BOTTOM + WIDTH},
5280         paddings = {l: PADDING + LEFT, r: PADDING + RIGHT, t: PADDING + TOP, b: PADDING + BOTTOM},
5281         margins = {l: MARGIN + LEFT, r: MARGIN + RIGHT, t: MARGIN + TOP, b: MARGIN + BOTTOM},
5282         data = Ext.Element.data;
5283         
5284     
5285     // private  
5286     function camelFn(m, a) {
5287         return a.charAt(1).toUpperCase();
5288     }
5289     
5290     function chkCache(prop) {
5291         return propCache[prop] || (propCache[prop] = prop == 'float' ? propFloat : prop.replace(camelRe, camelFn));
5292     }
5293             
5294     return {
5295         // private  ==> used by Fx  
5296         adjustWidth : function(width) {
5297             var me = this;
5298             var isNum = Ext.isNumber(width);
5299             if(isNum && me.autoBoxAdjust && !me.isBorderBox()){
5300                width -= (me.getBorderWidth("lr") + me.getPadding("lr"));
5301             }
5302             return (isNum && width < 0) ? 0 : width;
5303         },
5304         
5305         // private   ==> used by Fx 
5306         adjustHeight : function(height) {
5307             var me = this;
5308             var isNum = Ext.isNumber(height);
5309             if(isNum && me.autoBoxAdjust && !me.isBorderBox()){
5310                height -= (me.getBorderWidth("tb") + me.getPadding("tb"));               
5311             }
5312             return (isNum && height < 0) ? 0 : height;
5313         },
5314     
5315     
5316         /**
5317          * Adds one or more CSS classes to the element. Duplicate classes are automatically filtered out.
5318          * @param {String/Array} className The CSS class to add, or an array of classes
5319          * @return {Ext.Element} this
5320          */
5321         addClass : function(className){
5322             var me = this;
5323             Ext.each(className, function(v) {
5324                 me.dom.className += (!me.hasClass(v) && v ? " " + v : "");  
5325             });
5326             return me;
5327         },
5328     
5329         /**
5330          * Adds one or more CSS classes to this element and removes the same class(es) from all siblings.
5331          * @param {String/Array} className The CSS class to add, or an array of classes
5332          * @return {Ext.Element} this
5333          */
5334         radioClass : function(className){
5335             Ext.each(this.dom.parentNode.childNodes, function(v) {
5336                 if(v.nodeType == 1) {
5337                     Ext.fly(v, '_internal').removeClass(className);          
5338                 }
5339             });
5340             return this.addClass(className);
5341         },
5342     
5343         /**
5344          * Removes one or more CSS classes from the element.
5345          * @param {String/Array} className The CSS class to remove, or an array of classes
5346          * @return {Ext.Element} this
5347          */
5348         removeClass : function(className){
5349             var me = this;
5350             if (me.dom && me.dom.className) {
5351                 Ext.each(className, function(v) {               
5352                     me.dom.className = me.dom.className.replace(
5353                         classReCache[v] = classReCache[v] || new RegExp('(?:^|\\s+)' + v + '(?:\\s+|$)', "g"), 
5354                         " ");               
5355                 });    
5356             }
5357             return me;
5358         },
5359     
5360         /**
5361          * Toggles the specified CSS class on this element (removes it if it already exists, otherwise adds it).
5362          * @param {String} className The CSS class to toggle
5363          * @return {Ext.Element} this
5364          */
5365         toggleClass : function(className){
5366             return this.hasClass(className) ? this.removeClass(className) : this.addClass(className);
5367         },
5368     
5369         /**
5370          * Checks if the specified CSS class exists on this element's DOM node.
5371          * @param {String} className The CSS class to check for
5372          * @return {Boolean} True if the class exists, else false
5373          */
5374         hasClass : function(className){
5375             return className && (' '+this.dom.className+' ').indexOf(' '+className+' ') != -1;
5376         },
5377     
5378         /**
5379          * Replaces a CSS class on the element with another.  If the old name does not exist, the new name will simply be added.
5380          * @param {String} oldClassName The CSS class to replace
5381          * @param {String} newClassName The replacement CSS class
5382          * @return {Ext.Element} this
5383          */
5384         replaceClass : function(oldClassName, newClassName){
5385             return this.removeClass(oldClassName).addClass(newClassName);
5386         },
5387         
5388         isStyle : function(style, val) {
5389             return this.getStyle(style) == val;  
5390         },
5391     
5392         /**
5393          * Normalizes currentStyle and computedStyle.
5394          * @param {String} property The style property whose value is returned.
5395          * @return {String} The current value of the style property for this element.
5396          */
5397         getStyle : function(){         
5398             return view && view.getComputedStyle ?
5399                 function(prop){
5400                     var el = this.dom,
5401                         v,                  
5402                         cs,
5403                         out;
5404                     if(el == document) return null;
5405                     prop = chkCache(prop);
5406                     out = (v = el.style[prop]) ? v : 
5407                            (cs = view.getComputedStyle(el, "")) ? cs[prop] : null;
5408                     
5409                     // Webkit returns rgb values for transparent.
5410                     if(Ext.isWebKit && out == 'rgba(0, 0, 0, 0)'){
5411                         out = 'transparent';
5412                     }
5413                     return out;
5414                 } :
5415                 function(prop){      
5416                     var el = this.dom, 
5417                         m, 
5418                         cs;     
5419                         
5420                     if(el == document) return null;      
5421                     if (prop == 'opacity') {
5422                         if (el.style.filter.match) {                       
5423                             if(m = el.style.filter.match(opacityRe)){
5424                                 var fv = parseFloat(m[1]);
5425                                 if(!isNaN(fv)){
5426                                     return fv ? fv / 100 : 0;
5427                                 }
5428                             }
5429                         }
5430                         return 1;
5431                     }
5432                     prop = chkCache(prop);  
5433                     return el.style[prop] || ((cs = el.currentStyle) ? cs[prop] : null);
5434                 };
5435         }(),
5436
5437         /**
5438          * Return the CSS color for the specified CSS attribute. rgb, 3 digit (like #fff) and valid values
5439          * are convert to standard 6 digit hex color.
5440          * @param {String} attr The css attribute
5441          * @param {String} defaultValue The default value to use when a valid color isn't found
5442          * @param {String} prefix (optional) defaults to #. Use an empty string when working with
5443          * color anims.
5444          */
5445         getColor : function(attr, defaultValue, prefix){
5446             var v = this.getStyle(attr),
5447                 color = Ext.isDefined(prefix) ? prefix : '#',
5448                 h;
5449                 
5450             if(!v || /transparent|inherit/.test(v)){
5451                 return defaultValue;
5452             }
5453             if(/^r/.test(v)){
5454                 Ext.each(v.slice(4, v.length -1).split(','), function(s){
5455                     h = parseInt(s, 10);
5456                     color += (h < 16 ? '0' : '') + h.toString(16); 
5457                 });
5458             }else{
5459                 v = v.replace('#', '');
5460                 color += v.length == 3 ? v.replace(/^(\w)(\w)(\w)$/, '$1$1$2$2$3$3') : v;
5461             }
5462             return(color.length > 5 ? color.toLowerCase() : defaultValue);
5463         },
5464     
5465         /**
5466          * Wrapper for setting style properties, also takes single object parameter of multiple styles.
5467          * @param {String/Object} property The style property to be set, or an object of multiple styles.
5468          * @param {String} value (optional) The value to apply to the given property, or null if an object was passed.
5469          * @return {Ext.Element} this
5470          */
5471         setStyle : function(prop, value){
5472             var tmp, 
5473                 style,
5474                 camel;
5475             if (!Ext.isObject(prop)) {
5476                 tmp = {};
5477                 tmp[prop] = value;          
5478                 prop = tmp;
5479             }
5480             for (style in prop) {
5481                 value = prop[style];            
5482                 style == 'opacity' ? 
5483                     this.setOpacity(value) : 
5484                     this.dom.style[chkCache(style)] = value;
5485             }
5486             return this;
5487         },
5488         
5489         /**
5490          * Set the opacity of the element
5491          * @param {Float} opacity The new opacity. 0 = transparent, .5 = 50% visibile, 1 = fully visible, etc
5492          * @param {Boolean/Object} animate (optional) a standard Element animation config object or <tt>true</tt> for
5493          * the default animation (<tt>{duration: .35, easing: 'easeIn'}</tt>)
5494          * @return {Ext.Element} this
5495          */
5496          setOpacity : function(opacity, animate){
5497             var me = this,
5498                 s = me.dom.style;
5499                 
5500             if(!animate || !me.anim){            
5501                 if(Ext.isIE){
5502                     var opac = opacity < 1 ? 'alpha(opacity=' + opacity * 100 + ')' : '', 
5503                     val = s.filter.replace(opacityRe, '').replace(trimRe, '');
5504
5505                     s.zoom = 1;
5506                     s.filter = val + (val.length > 0 ? ' ' : '') + opac;
5507                 }else{
5508                     s.opacity = opacity;
5509                 }
5510             }else{
5511                 me.anim({opacity: {to: opacity}}, me.preanim(arguments, 1), null, .35, 'easeIn');
5512             }
5513             return me;
5514         },
5515         
5516         /**
5517          * Clears any opacity settings from this element. Required in some cases for IE.
5518          * @return {Ext.Element} this
5519          */
5520         clearOpacity : function(){
5521             var style = this.dom.style;
5522             if(Ext.isIE){
5523                 if(!Ext.isEmpty(style.filter)){
5524                     style.filter = style.filter.replace(opacityRe, '').replace(trimRe, '');
5525                 }
5526             }else{
5527                 style.opacity = style['-moz-opacity'] = style['-khtml-opacity'] = '';
5528             }
5529             return this;
5530         },
5531     
5532         /**
5533          * Returns the offset height of the element
5534          * @param {Boolean} contentHeight (optional) true to get the height minus borders and padding
5535          * @return {Number} The element's height
5536          */
5537         getHeight : function(contentHeight){
5538             var me = this,
5539                 dom = me.dom,
5540                 hidden = Ext.isIE && me.isStyle('display', 'none'),
5541                 h = MATH.max(dom.offsetHeight, hidden ? 0 : dom.clientHeight) || 0;
5542                 
5543             h = !contentHeight ? h : h - me.getBorderWidth("tb") - me.getPadding("tb");
5544             return h < 0 ? 0 : h;
5545         },
5546     
5547         /**
5548          * Returns the offset width of the element
5549          * @param {Boolean} contentWidth (optional) true to get the width minus borders and padding
5550          * @return {Number} The element's width
5551          */
5552         getWidth : function(contentWidth){
5553             var me = this,
5554                 dom = me.dom,
5555                 hidden = Ext.isIE && me.isStyle('display', 'none'),
5556                 w = MATH.max(dom.offsetWidth, hidden ? 0 : dom.clientWidth) || 0;
5557             w = !contentWidth ? w : w - me.getBorderWidth("lr") - me.getPadding("lr");
5558             return w < 0 ? 0 : w;
5559         },
5560     
5561         /**
5562          * Set the width of this Element.
5563          * @param {Mixed} width The new width. This may be one of:<div class="mdetail-params"><ul>
5564          * <li>A Number specifying the new width in this Element's {@link #defaultUnit}s (by default, pixels).</li>
5565          * <li>A String used to set the CSS width style. Animation may <b>not</b> be used.
5566          * </ul></div>
5567          * @param {Boolean/Object} animate (optional) true for the default animation or a standard Element animation config object
5568          * @return {Ext.Element} this
5569          */
5570         setWidth : function(width, animate){
5571             var me = this;
5572             width = me.adjustWidth(width);
5573             !animate || !me.anim ? 
5574                 me.dom.style.width = me.addUnits(width) :
5575                 me.anim({width : {to : width}}, me.preanim(arguments, 1));
5576             return me;
5577         },
5578     
5579         /**
5580          * Set the height of this Element.
5581          * <pre><code>
5582 // change the height to 200px and animate with default configuration
5583 Ext.fly('elementId').setHeight(200, true);
5584
5585 // change the height to 150px and animate with a custom configuration
5586 Ext.fly('elId').setHeight(150, {
5587     duration : .5, // animation will have a duration of .5 seconds
5588     // will change the content to "finished"
5589     callback: function(){ this.{@link #update}("finished"); } 
5590 });
5591          * </code></pre>
5592          * @param {Mixed} height The new height. This may be one of:<div class="mdetail-params"><ul>
5593          * <li>A Number specifying the new height in this Element's {@link #defaultUnit}s (by default, pixels.)</li>
5594          * <li>A String used to set the CSS height style. Animation may <b>not</b> be used.</li>
5595          * </ul></div>
5596          * @param {Boolean/Object} animate (optional) true for the default animation or a standard Element animation config object
5597          * @return {Ext.Element} this
5598          */
5599          setHeight : function(height, animate){
5600             var me = this;
5601             height = me.adjustHeight(height);
5602             !animate || !me.anim ? 
5603                 me.dom.style.height = me.addUnits(height) :
5604                 me.anim({height : {to : height}}, me.preanim(arguments, 1));
5605             return me;
5606         },
5607         
5608         /**
5609          * Gets the width of the border(s) for the specified side(s)
5610          * @param {String} side Can be t, l, r, b or any combination of those to add multiple values. For example,
5611          * passing <tt>'lr'</tt> would get the border <b><u>l</u></b>eft width + the border <b><u>r</u></b>ight width.
5612          * @return {Number} The width of the sides passed added together
5613          */
5614         getBorderWidth : function(side){
5615             return this.addStyles(side, borders);
5616         },
5617     
5618         /**
5619          * Gets the width of the padding(s) for the specified side(s)
5620          * @param {String} side Can be t, l, r, b or any combination of those to add multiple values. For example,
5621          * passing <tt>'lr'</tt> would get the padding <b><u>l</u></b>eft + the padding <b><u>r</u></b>ight.
5622          * @return {Number} The padding of the sides passed added together
5623          */
5624         getPadding : function(side){
5625             return this.addStyles(side, paddings);
5626         },
5627     
5628         /**
5629          *  Store the current overflow setting and clip overflow on the element - use <tt>{@link #unclip}</tt> to remove
5630          * @return {Ext.Element} this
5631          */
5632         clip : function(){
5633             var me = this,
5634                 dom = me.dom;
5635                 
5636             if(!data(dom, ISCLIPPED)){
5637                 data(dom, ISCLIPPED, true);
5638                 data(dom, ORIGINALCLIP, {
5639                     o: me.getStyle(OVERFLOW),
5640                     x: me.getStyle(OVERFLOWX),
5641                     y: me.getStyle(OVERFLOWY)
5642                 });
5643                 me.setStyle(OVERFLOW, HIDDEN);
5644                 me.setStyle(OVERFLOWX, HIDDEN);
5645                 me.setStyle(OVERFLOWY, HIDDEN);
5646             }
5647             return me;
5648         },
5649     
5650         /**
5651          *  Return clipping (overflow) to original clipping before <tt>{@link #clip}</tt> was called
5652          * @return {Ext.Element} this
5653          */
5654         unclip : function(){
5655             var me = this,
5656                 dom = me.dom;
5657                 
5658             if(data(dom, ISCLIPPED)){
5659                 data(dom, ISCLIPPED, false);
5660                 var o = data(dom, ORIGINALCLIP);
5661                 if(o.o){
5662                     me.setStyle(OVERFLOW, o.o);
5663                 }
5664                 if(o.x){
5665                     me.setStyle(OVERFLOWX, o.x);
5666                 }
5667                 if(o.y){
5668                     me.setStyle(OVERFLOWY, o.y);
5669                 }
5670             }
5671             return me;
5672         },
5673
5674         // private
5675         addStyles : function(sides, styles){
5676             var val = 0;
5677
5678             Ext.each(sides.match(/\w/g), function(s) {
5679                 if (s = parseInt(this.getStyle(styles[s]), 10)) {
5680                     val += MATH.abs(s);
5681                 }
5682             },
5683             this);
5684             return val;
5685         },
5686
5687         margins : margins
5688     }
5689 }()         
5690 );
5691 /**\r
5692  * @class Ext.Element\r
5693  */\r
5694 \r
5695 // special markup used throughout Ext when box wrapping elements\r
5696 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
5697 \r
5698 Ext.Element.addMethods(function(){\r
5699         var INTERNAL = "_internal";\r
5700         return {\r
5701             /**\r
5702              * More flexible version of {@link #setStyle} for setting style properties.\r
5703              * @param {String/Object/Function} styles A style specification string, e.g. "width:100px", or object in the form {width:"100px"}, or\r
5704              * a function which returns such a specification.\r
5705              * @return {Ext.Element} this\r
5706              */\r
5707             applyStyles : function(style){\r
5708                 Ext.DomHelper.applyStyles(this.dom, style);\r
5709                 return this;\r
5710             },\r
5711 \r
5712                 /**\r
5713              * Returns an object with properties matching the styles requested.\r
5714              * For example, el.getStyles('color', 'font-size', 'width') might return\r
5715              * {'color': '#FFFFFF', 'font-size': '13px', 'width': '100px'}.\r
5716              * @param {String} style1 A style name\r
5717              * @param {String} style2 A style name\r
5718              * @param {String} etc.\r
5719              * @return {Object} The style object\r
5720              */\r
5721             getStyles : function(){\r
5722                     var ret = {};\r
5723                     Ext.each(arguments, function(v) {\r
5724                            ret[v] = this.getStyle(v);\r
5725                     },\r
5726                     this);\r
5727                     return ret;\r
5728             },\r
5729 \r
5730                 getStyleSize : function(){\r
5731                 var me = this,\r
5732                         w,\r
5733                         h,\r
5734                         d = this.dom,\r
5735                         s = d.style;\r
5736                 if(s.width && s.width != 'auto'){\r
5737                     w = parseInt(s.width, 10);\r
5738                     if(me.isBorderBox()){\r
5739                        w -= me.getFrameWidth('lr');\r
5740                     }\r
5741                 }\r
5742                 if(s.height && s.height != 'auto'){\r
5743                     h = parseInt(s.height, 10);\r
5744                     if(me.isBorderBox()){\r
5745                        h -= me.getFrameWidth('tb');\r
5746                     }\r
5747                 }\r
5748                 return {width: w || me.getWidth(true), height: h || me.getHeight(true)};\r
5749             },\r
5750 \r
5751             // private  ==> used by ext full\r
5752                 setOverflow : function(v){\r
5753                         var dom = this.dom;\r
5754                 if(v=='auto' && Ext.isMac && Ext.isGecko2){ // work around stupid FF 2.0/Mac scroll bar bug\r
5755                         dom.style.overflow = 'hidden';\r
5756                         (function(){dom.style.overflow = 'auto';}).defer(1);\r
5757                 }else{\r
5758                         dom.style.overflow = v;\r
5759                 }\r
5760                 },\r
5761 \r
5762            /**\r
5763                 * <p>Wraps the specified element with a special 9 element markup/CSS block that renders by default as\r
5764                 * a gray container with a gradient background, rounded corners and a 4-way shadow.</p>\r
5765                 * <p>This special markup is used throughout Ext when box wrapping elements ({@link Ext.Button},\r
5766                 * {@link Ext.Panel} when <tt>{@link Ext.Panel#frame frame=true}</tt>, {@link Ext.Window}).  The markup\r
5767                 * is of this form:</p>\r
5768                 * <pre><code>\r
5769 Ext.Element.boxMarkup =\r
5770     &#39;&lt;div class="{0}-tl">&lt;div class="{0}-tr">&lt;div class="{0}-tc">&lt;/div>&lt;/div>&lt;/div>\r
5771      &lt;div class="{0}-ml">&lt;div class="{0}-mr">&lt;div class="{0}-mc">&lt;/div>&lt;/div>&lt;/div>\r
5772      &lt;div class="{0}-bl">&lt;div class="{0}-br">&lt;div class="{0}-bc">&lt;/div>&lt;/div>&lt;/div>&#39;;\r
5773                 * </code></pre>\r
5774                 * <p>Example usage:</p>\r
5775                 * <pre><code>\r
5776 // Basic box wrap\r
5777 Ext.get("foo").boxWrap();\r
5778 \r
5779 // You can also add a custom class and use CSS inheritance rules to customize the box look.\r
5780 // 'x-box-blue' is a built-in alternative -- look at the related CSS definitions as an example\r
5781 // for how to create a custom box wrap style.\r
5782 Ext.get("foo").boxWrap().addClass("x-box-blue");\r
5783                 * </code></pre>\r
5784                 * @param {String} class (optional) A base CSS class to apply to the containing wrapper element\r
5785                 * (defaults to <tt>'x-box'</tt>). Note that there are a number of CSS rules that are dependent on\r
5786                 * this name to make the overall effect work, so if you supply an alternate base class, make sure you\r
5787                 * also supply all of the necessary rules.\r
5788                 * @return {Ext.Element} this\r
5789                 */\r
5790             boxWrap : function(cls){\r
5791                 cls = cls || 'x-box';\r
5792                 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
5793                 Ext.DomQuery.selectNode('.' + cls + '-mc', el.dom).appendChild(this.dom);\r
5794                 return el;\r
5795             },\r
5796 \r
5797         /**\r
5798          * Set the size of this Element. If animation is true, both width and height will be animated concurrently.\r
5799          * @param {Mixed} width The new width. This may be one of:<div class="mdetail-params"><ul>\r
5800          * <li>A Number specifying the new width in this Element's {@link #defaultUnit}s (by default, pixels).</li>\r
5801          * <li>A String used to set the CSS width style. Animation may <b>not</b> be used.\r
5802          * <li>A size object in the format <code>{width: widthValue, height: heightValue}</code>.</li>\r
5803          * </ul></div>\r
5804          * @param {Mixed} height The new height. This may be one of:<div class="mdetail-params"><ul>\r
5805          * <li>A Number specifying the new height in this Element's {@link #defaultUnit}s (by default, pixels).</li>\r
5806          * <li>A String used to set the CSS height style. Animation may <b>not</b> be used.</li>\r
5807          * </ul></div>\r
5808          * @param {Boolean/Object} animate (optional) true for the default animation or a standard Element animation config object\r
5809          * @return {Ext.Element} this\r
5810          */\r
5811             setSize : function(width, height, animate){\r
5812                         var me = this;\r
5813                         if(Ext.isObject(width)){ // in case of object from getSize()\r
5814                             height = width.height;\r
5815                             width = width.width;\r
5816                         }\r
5817                         width = me.adjustWidth(width);\r
5818                         height = me.adjustHeight(height);\r
5819                         if(!animate || !me.anim){\r
5820                             me.dom.style.width = me.addUnits(width);\r
5821                             me.dom.style.height = me.addUnits(height);\r
5822                         }else{\r
5823                             me.anim({width: {to: width}, height: {to: height}}, me.preanim(arguments, 2));\r
5824                         }\r
5825                         return me;\r
5826             },\r
5827 \r
5828             /**\r
5829              * Returns either the offsetHeight or the height of this element based on CSS height adjusted by padding or borders\r
5830              * when needed to simulate offsetHeight when offsets aren't available. This may not work on display:none elements\r
5831              * if a height has not been set using CSS.\r
5832              * @return {Number}\r
5833              */\r
5834             getComputedHeight : function(){\r
5835                     var me = this,\r
5836                         h = Math.max(me.dom.offsetHeight, me.dom.clientHeight);\r
5837                 if(!h){\r
5838                     h = parseInt(me.getStyle('height'), 10) || 0;\r
5839                     if(!me.isBorderBox()){\r
5840                         h += me.getFrameWidth('tb');\r
5841                     }\r
5842                 }\r
5843                 return h;\r
5844             },\r
5845 \r
5846             /**\r
5847              * Returns either the offsetWidth or the width of this element based on CSS width adjusted by padding or borders\r
5848              * when needed to simulate offsetWidth when offsets aren't available. This may not work on display:none elements\r
5849              * if a width has not been set using CSS.\r
5850              * @return {Number}\r
5851              */\r
5852             getComputedWidth : function(){\r
5853                 var w = Math.max(this.dom.offsetWidth, this.dom.clientWidth);\r
5854                 if(!w){\r
5855                     w = parseInt(this.getStyle('width'), 10) || 0;\r
5856                     if(!this.isBorderBox()){\r
5857                         w += this.getFrameWidth('lr');\r
5858                     }\r
5859                 }\r
5860                 return w;\r
5861             },\r
5862 \r
5863             /**\r
5864              * Returns the sum width of the padding and borders for the passed "sides". See getBorderWidth()\r
5865              for more information about the sides.\r
5866              * @param {String} sides\r
5867              * @return {Number}\r
5868              */\r
5869             getFrameWidth : function(sides, onlyContentBox){\r
5870                 return onlyContentBox && this.isBorderBox() ? 0 : (this.getPadding(sides) + this.getBorderWidth(sides));\r
5871             },\r
5872 \r
5873             /**\r
5874              * Sets up event handlers to add and remove a css class when the mouse is over this element\r
5875              * @param {String} className\r
5876              * @return {Ext.Element} this\r
5877              */\r
5878             addClassOnOver : function(className){\r
5879                 this.hover(\r
5880                     function(){\r
5881                         Ext.fly(this, INTERNAL).addClass(className);\r
5882                     },\r
5883                     function(){\r
5884                         Ext.fly(this, INTERNAL).removeClass(className);\r
5885                     }\r
5886                 );\r
5887                 return this;\r
5888             },\r
5889 \r
5890             /**\r
5891              * Sets up event handlers to add and remove a css class when this element has the focus\r
5892              * @param {String} className\r
5893              * @return {Ext.Element} this\r
5894              */\r
5895             addClassOnFocus : function(className){\r
5896                     this.on("focus", function(){\r
5897                         Ext.fly(this, INTERNAL).addClass(className);\r
5898                     }, this.dom);\r
5899                     this.on("blur", function(){\r
5900                         Ext.fly(this, INTERNAL).removeClass(className);\r
5901                     }, this.dom);\r
5902                     return this;\r
5903             },\r
5904 \r
5905             /**\r
5906              * 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
5907              * @param {String} className\r
5908              * @return {Ext.Element} this\r
5909              */\r
5910             addClassOnClick : function(className){\r
5911                 var dom = this.dom;\r
5912                 this.on("mousedown", function(){\r
5913                     Ext.fly(dom, INTERNAL).addClass(className);\r
5914                     var d = Ext.getDoc(),\r
5915                         fn = function(){\r
5916                                 Ext.fly(dom, INTERNAL).removeClass(className);\r
5917                                 d.removeListener("mouseup", fn);\r
5918                             };\r
5919                     d.on("mouseup", fn);\r
5920                 });\r
5921                 return this;\r
5922             },\r
5923 \r
5924             /**\r
5925              * Returns the width and height of the viewport.\r
5926         * <pre><code>\r
5927         var vpSize = Ext.getBody().getViewSize();\r
5928 \r
5929         // all Windows created afterwards will have a default value of 90% height and 95% width\r
5930         Ext.Window.override({\r
5931             width: vpSize.width * 0.9,\r
5932             height: vpSize.height * 0.95\r
5933         });\r
5934         // To handle window resizing you would have to hook onto onWindowResize.\r
5935         </code></pre>\r
5936              * @return {Object} An object containing the viewport's size {width: (viewport width), height: (viewport height)}\r
5937              */\r
5938             getViewSize : function(){\r
5939                 var doc = document,\r
5940                         d = this.dom,\r
5941                         extdom = Ext.lib.Dom,\r
5942                         isDoc = (d == doc || d == doc.body);\r
5943                 return { width : (isDoc ? extdom.getViewWidth() : d.clientWidth),\r
5944                                  height : (isDoc ? extdom.getViewHeight() : d.clientHeight) };\r
5945             },\r
5946 \r
5947             /**\r
5948              * Returns the size of the element.\r
5949              * @param {Boolean} contentSize (optional) true to get the width/size minus borders and padding\r
5950              * @return {Object} An object containing the element's size {width: (element width), height: (element height)}\r
5951              */\r
5952             getSize : function(contentSize){\r
5953                 return {width: this.getWidth(contentSize), height: this.getHeight(contentSize)};\r
5954             },\r
5955 \r
5956             /**\r
5957              * Forces the browser to repaint this element\r
5958              * @return {Ext.Element} this\r
5959              */\r
5960             repaint : function(){\r
5961                 var dom = this.dom;\r
5962                 this.addClass("x-repaint");\r
5963                 setTimeout(function(){\r
5964                     Ext.fly(dom).removeClass("x-repaint");\r
5965                 }, 1);\r
5966                 return this;\r
5967             },\r
5968 \r
5969             /**\r
5970              * Disables text selection for this element (normalized across browsers)\r
5971              * @return {Ext.Element} this\r
5972              */\r
5973             unselectable : function(){\r
5974                 this.dom.unselectable = "on";\r
5975                 return this.swallowEvent("selectstart", true).\r
5976                                     applyStyles("-moz-user-select:none;-khtml-user-select:none;").\r
5977                                     addClass("x-unselectable");\r
5978             },\r
5979 \r
5980             /**\r
5981              * Returns an object with properties top, left, right and bottom representing the margins of this element unless sides is passed,\r
5982              * then it returns the calculated width of the sides (see getPadding)\r
5983              * @param {String} sides (optional) Any combination of l, r, t, b to get the sum of those sides\r
5984              * @return {Object/Number}\r
5985              */\r
5986             getMargins : function(side){\r
5987                     var me = this,\r
5988                         key,\r
5989                         hash = {t:"top", l:"left", r:"right", b: "bottom"},\r
5990                         o = {};\r
5991 \r
5992                     if (!side) {\r
5993                         for (key in me.margins){\r
5994                                 o[hash[key]] = parseInt(me.getStyle(me.margins[key]), 10) || 0;\r
5995                 }\r
5996                         return o;\r
5997                 } else {\r
5998                     return me.addStyles.call(me, side, me.margins);\r
5999                 }\r
6000             }\r
6001     };\r
6002 }());/**\r
6003  * @class Ext.Element\r
6004  */\r
6005 (function(){\r
6006 var D = Ext.lib.Dom,\r
6007         LEFT = "left",\r
6008         RIGHT = "right",\r
6009         TOP = "top",\r
6010         BOTTOM = "bottom",\r
6011         POSITION = "position",\r
6012         STATIC = "static",\r
6013         RELATIVE = "relative",\r
6014         AUTO = "auto",\r
6015         ZINDEX = "z-index";\r
6016 \r
6017 Ext.Element.addMethods({\r
6018         /**\r
6019       * 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
6020       * @return {Number} The X position of the element\r
6021       */\r
6022     getX : function(){\r
6023         return D.getX(this.dom);\r
6024     },\r
6025 \r
6026     /**\r
6027       * 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
6028       * @return {Number} The Y position of the element\r
6029       */\r
6030     getY : function(){\r
6031         return D.getY(this.dom);\r
6032     },\r
6033 \r
6034     /**\r
6035       * 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
6036       * @return {Array} The XY position of the element\r
6037       */\r
6038     getXY : function(){\r
6039         return D.getXY(this.dom);\r
6040     },\r
6041 \r
6042     /**\r
6043       * 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
6044       * @param {Mixed} element The element to get the offsets from.\r
6045       * @return {Array} The XY page offsets (e.g. [100, -200])\r
6046       */\r
6047     getOffsetsTo : function(el){\r
6048         var o = this.getXY(),\r
6049                 e = Ext.fly(el, '_internal').getXY();\r
6050         return [o[0]-e[0],o[1]-e[1]];\r
6051     },\r
6052 \r
6053     /**\r
6054      * 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
6055      * @param {Number} The X position of the element\r
6056      * @param {Boolean/Object} animate (optional) True for the default animation, or a standard Element animation config object\r
6057      * @return {Ext.Element} this\r
6058      */\r
6059     setX : function(x, animate){            \r
6060             return this.setXY([x, this.getY()], this.animTest(arguments, animate, 1));\r
6061     },\r
6062 \r
6063     /**\r
6064      * 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
6065      * @param {Number} The Y position of the element\r
6066      * @param {Boolean/Object} animate (optional) True for the default animation, or a standard Element animation config object\r
6067      * @return {Ext.Element} this\r
6068      */\r
6069     setY : function(y, animate){            \r
6070             return this.setXY([this.getX(), y], this.animTest(arguments, animate, 1));\r
6071     },\r
6072 \r
6073     /**\r
6074      * Sets the element's left position directly using CSS style (instead of {@link #setX}).\r
6075      * @param {String} left The left CSS property value\r
6076      * @return {Ext.Element} this\r
6077      */\r
6078     setLeft : function(left){\r
6079         this.setStyle(LEFT, this.addUnits(left));\r
6080         return this;\r
6081     },\r
6082 \r
6083     /**\r
6084      * Sets the element's top position directly using CSS style (instead of {@link #setY}).\r
6085      * @param {String} top The top CSS property value\r
6086      * @return {Ext.Element} this\r
6087      */\r
6088     setTop : function(top){\r
6089         this.setStyle(TOP, this.addUnits(top));\r
6090         return this;\r
6091     },\r
6092 \r
6093     /**\r
6094      * Sets the element's CSS right style.\r
6095      * @param {String} right The right CSS property value\r
6096      * @return {Ext.Element} this\r
6097      */\r
6098     setRight : function(right){\r
6099         this.setStyle(RIGHT, this.addUnits(right));\r
6100         return this;\r
6101     },\r
6102 \r
6103     /**\r
6104      * Sets the element's CSS bottom style.\r
6105      * @param {String} bottom The bottom CSS property value\r
6106      * @return {Ext.Element} this\r
6107      */\r
6108     setBottom : function(bottom){\r
6109         this.setStyle(BOTTOM, this.addUnits(bottom));\r
6110         return this;\r
6111     },\r
6112 \r
6113     /**\r
6114      * Sets the position of the element in page coordinates, regardless of how the element is positioned.\r
6115      * The element must be part of the DOM tree to have page coordinates (display:none or elements not appended return false).\r
6116      * @param {Array} pos Contains X & Y [x, y] values for new position (coordinates are page-based)\r
6117      * @param {Boolean/Object} animate (optional) True for the default animation, or a standard Element animation config object\r
6118      * @return {Ext.Element} this\r
6119      */\r
6120     setXY : function(pos, animate){\r
6121             var me = this;\r
6122         if(!animate || !me.anim){\r
6123             D.setXY(me.dom, pos);\r
6124         }else{\r
6125             me.anim({points: {to: pos}}, me.preanim(arguments, 1), 'motion');\r
6126         }\r
6127         return me;\r
6128     },\r
6129 \r
6130     /**\r
6131      * Sets the position of the element in page coordinates, regardless of how the element is positioned.\r
6132      * The element must be part of the DOM tree to have page coordinates (display:none or elements not appended return false).\r
6133      * @param {Number} x X value for new position (coordinates are page-based)\r
6134      * @param {Number} y Y value for new position (coordinates are page-based)\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     setLocation : function(x, y, animate){\r
6139         return this.setXY([x, y], this.animTest(arguments, animate, 2));\r
6140     },\r
6141 \r
6142     /**\r
6143      * Sets the position of the element in page coordinates, regardless of how the element is positioned.\r
6144      * The element must be part of the DOM tree to have page coordinates (display:none or elements not appended return false).\r
6145      * @param {Number} x X value for new position (coordinates are page-based)\r
6146      * @param {Number} y Y value for new position (coordinates are page-based)\r
6147      * @param {Boolean/Object} animate (optional) True for the default animation, or a standard Element animation config object\r
6148      * @return {Ext.Element} this\r
6149      */\r
6150     moveTo : function(x, y, animate){\r
6151         return this.setXY([x, y], this.animTest(arguments, animate, 2));        \r
6152     },    \r
6153     \r
6154     /**\r
6155      * Gets the left X coordinate\r
6156      * @param {Boolean} local True to get the local css position instead of page coordinate\r
6157      * @return {Number}\r
6158      */\r
6159     getLeft : function(local){\r
6160             return !local ? this.getX() : parseInt(this.getStyle(LEFT), 10) || 0;\r
6161     },\r
6162 \r
6163     /**\r
6164      * Gets the right X coordinate of the element (element X position + element width)\r
6165      * @param {Boolean} local True to get the local css position instead of page coordinate\r
6166      * @return {Number}\r
6167      */\r
6168     getRight : function(local){\r
6169             var me = this;\r
6170             return !local ? me.getX() + me.getWidth() : (me.getLeft(true) + me.getWidth()) || 0;\r
6171     },\r
6172 \r
6173     /**\r
6174      * Gets the top Y coordinate\r
6175      * @param {Boolean} local True to get the local css position instead of page coordinate\r
6176      * @return {Number}\r
6177      */\r
6178     getTop : function(local) {\r
6179             return !local ? this.getY() : parseInt(this.getStyle(TOP), 10) || 0;\r
6180     },\r
6181 \r
6182     /**\r
6183      * Gets the bottom Y coordinate of the element (element Y position + element height)\r
6184      * @param {Boolean} local True to get the local css position instead of page coordinate\r
6185      * @return {Number}\r
6186      */\r
6187     getBottom : function(local){\r
6188             var me = this;\r
6189             return !local ? me.getY() + me.getHeight() : (me.getTop(true) + me.getHeight()) || 0;\r
6190     },\r
6191 \r
6192     /**\r
6193     * Initializes positioning on this element. If a desired position is not passed, it will make the\r
6194     * the element positioned relative IF it is not already positioned.\r
6195     * @param {String} pos (optional) Positioning to use "relative", "absolute" or "fixed"\r
6196     * @param {Number} zIndex (optional) The zIndex to apply\r
6197     * @param {Number} x (optional) Set the page X position\r
6198     * @param {Number} y (optional) Set the page Y position\r
6199     */\r
6200     position : function(pos, zIndex, x, y){\r
6201             var me = this;\r
6202             \r
6203         if(!pos && me.isStyle(POSITION, STATIC)){           \r
6204             me.setStyle(POSITION, RELATIVE);           \r
6205         } else if(pos) {\r
6206             me.setStyle(POSITION, pos);\r
6207         }\r
6208         if(zIndex){\r
6209             me.setStyle(ZINDEX, zIndex);\r
6210         }\r
6211         if(x || y) me.setXY([x || false, y || false]);\r
6212     },\r
6213 \r
6214     /**\r
6215     * Clear positioning back to the default when the document was loaded\r
6216     * @param {String} value (optional) The value to use for the left,right,top,bottom, defaults to '' (empty string). You could use 'auto'.\r
6217     * @return {Ext.Element} this\r
6218      */\r
6219     clearPositioning : function(value){\r
6220         value = value || '';\r
6221         this.setStyle({\r
6222             left : value,\r
6223             right : value,\r
6224             top : value,\r
6225             bottom : value,\r
6226             "z-index" : "",\r
6227             position : STATIC\r
6228         });\r
6229         return this;\r
6230     },\r
6231 \r
6232     /**\r
6233     * Gets an object with all CSS positioning properties. Useful along with setPostioning to get\r
6234     * snapshot before performing an update and then restoring the element.\r
6235     * @return {Object}\r
6236     */\r
6237     getPositioning : function(){\r
6238         var l = this.getStyle(LEFT);\r
6239         var t = this.getStyle(TOP);\r
6240         return {\r
6241             "position" : this.getStyle(POSITION),\r
6242             "left" : l,\r
6243             "right" : l ? "" : this.getStyle(RIGHT),\r
6244             "top" : t,\r
6245             "bottom" : t ? "" : this.getStyle(BOTTOM),\r
6246             "z-index" : this.getStyle(ZINDEX)\r
6247         };\r
6248     },\r
6249     \r
6250     /**\r
6251     * Set positioning with an object returned by getPositioning().\r
6252     * @param {Object} posCfg\r
6253     * @return {Ext.Element} this\r
6254      */\r
6255     setPositioning : function(pc){\r
6256             var me = this,\r
6257                 style = me.dom.style;\r
6258                 \r
6259         me.setStyle(pc);\r
6260         \r
6261         if(pc.right == AUTO){\r
6262             style.right = "";\r
6263         }\r
6264         if(pc.bottom == AUTO){\r
6265             style.bottom = "";\r
6266         }\r
6267         \r
6268         return me;\r
6269     },    \r
6270         \r
6271     /**\r
6272      * Translates the passed page coordinates into left/top css values for this element\r
6273      * @param {Number/Array} x The page x or an array containing [x, y]\r
6274      * @param {Number} y (optional) The page y, required if x is not an array\r
6275      * @return {Object} An object with left and top properties. e.g. {left: (value), top: (value)}\r
6276      */\r
6277     translatePoints : function(x, y){                \r
6278             y = isNaN(x[1]) ? y : x[1];\r
6279         x = isNaN(x[0]) ? x : x[0];\r
6280         var me = this,\r
6281                 relative = me.isStyle(POSITION, RELATIVE),\r
6282                 o = me.getXY(),\r
6283                 l = parseInt(me.getStyle(LEFT), 10),\r
6284                 t = parseInt(me.getStyle(TOP), 10);\r
6285         \r
6286         l = !isNaN(l) ? l : (relative ? 0 : me.dom.offsetLeft);\r
6287         t = !isNaN(t) ? t : (relative ? 0 : me.dom.offsetTop);        \r
6288 \r
6289         return {left: (x - o[0] + l), top: (y - o[1] + t)}; \r
6290     },\r
6291     \r
6292     animTest : function(args, animate, i) {\r
6293         return !!animate && this.preanim ? this.preanim(args, i) : false;\r
6294     }\r
6295 });\r
6296 })();/**\r
6297  * @class Ext.Element\r
6298  */\r
6299 Ext.Element.addMethods({\r
6300     /**\r
6301      * 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
6302      * @param {Object} box The box to fill {x, y, width, height}\r
6303      * @param {Boolean} adjust (optional) Whether to adjust for box-model issues automatically\r
6304      * @param {Boolean/Object} animate (optional) true for the default animation or a standard Element animation config object\r
6305      * @return {Ext.Element} this\r
6306      */\r
6307     setBox : function(box, adjust, animate){\r
6308         var me = this,\r
6309                 w = box.width, \r
6310                 h = box.height;\r
6311         if((adjust && !me.autoBoxAdjust) && !me.isBorderBox()){\r
6312            w -= (me.getBorderWidth("lr") + me.getPadding("lr"));\r
6313            h -= (me.getBorderWidth("tb") + me.getPadding("tb"));\r
6314         }\r
6315         me.setBounds(box.x, box.y, w, h, me.animTest.call(me, arguments, animate, 2));\r
6316         return me;\r
6317     },\r
6318     \r
6319     /**\r
6320      * Return a box {x, y, width, height} that can be used to set another elements\r
6321      * size/location to match this element.\r
6322      * @param {Boolean} contentBox (optional) If true a box for the content of the element is returned.\r
6323      * @param {Boolean} local (optional) If true the element's left and top are returned instead of page x/y.\r
6324      * @return {Object} box An object in the format {x, y, width, height}\r
6325      */\r
6326         getBox : function(contentBox, local) {      \r
6327             var me = this,\r
6328                 xy,\r
6329                 left,\r
6330                 top,\r
6331                 getBorderWidth = me.getBorderWidth,\r
6332                 getPadding = me.getPadding, \r
6333                 l,\r
6334                 r,\r
6335                 t,\r
6336                 b;\r
6337         if(!local){\r
6338             xy = me.getXY();\r
6339         }else{\r
6340             left = parseInt(me.getStyle("left"), 10) || 0;\r
6341             top = parseInt(me.getStyle("top"), 10) || 0;\r
6342             xy = [left, top];\r
6343         }\r
6344         var el = me.dom, w = el.offsetWidth, h = el.offsetHeight, bx;\r
6345         if(!contentBox){\r
6346             bx = {x: xy[0], y: xy[1], 0: xy[0], 1: xy[1], width: w, height: h};\r
6347         }else{\r
6348             l = getBorderWidth.call(me, "l") + getPadding.call(me, "l");\r
6349             r = getBorderWidth.call(me, "r") + getPadding.call(me, "r");\r
6350             t = getBorderWidth.call(me, "t") + getPadding.call(me, "t");\r
6351             b = getBorderWidth.call(me, "b") + getPadding.call(me, "b");\r
6352             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
6353         }\r
6354         bx.right = bx.x + bx.width;\r
6355         bx.bottom = bx.y + bx.height;\r
6356         return bx;\r
6357         },\r
6358         \r
6359     /**\r
6360      * Move this element relative to its current position.\r
6361      * @param {String} direction Possible values are: "l" (or "left"), "r" (or "right"), "t" (or "top", or "up"), "b" (or "bottom", or "down").\r
6362      * @param {Number} distance How far to move the element in pixels\r
6363      * @param {Boolean/Object} animate (optional) true for the default animation or a standard Element animation config object\r
6364      * @return {Ext.Element} this\r
6365      */\r
6366      move : function(direction, distance, animate){\r
6367         var me = this,          \r
6368                 xy = me.getXY(),\r
6369                 x = xy[0],\r
6370                 y = xy[1],              \r
6371                 left = [x - distance, y],\r
6372                 right = [x + distance, y],\r
6373                 top = [x, y - distance],\r
6374                 bottom = [x, y + distance],\r
6375                 hash = {\r
6376                         l :     left,\r
6377                         left : left,\r
6378                         r : right,\r
6379                         right : right,\r
6380                         t : top,\r
6381                         top : top,\r
6382                         up : top,\r
6383                         b : bottom, \r
6384                         bottom : bottom,\r
6385                         down : bottom                           \r
6386                 };\r
6387         \r
6388             direction = direction.toLowerCase();    \r
6389             me.moveTo(hash[direction][0], hash[direction][1], me.animTest.call(me, arguments, animate, 2));\r
6390     },\r
6391     \r
6392     /**\r
6393      * Quick set left and top adding default units\r
6394      * @param {String} left The left CSS property value\r
6395      * @param {String} top The top CSS property value\r
6396      * @return {Ext.Element} this\r
6397      */\r
6398      setLeftTop : function(left, top){\r
6399             var me = this,\r
6400                 style = me.dom.style;\r
6401         style.left = me.addUnits(left);\r
6402         style.top = me.addUnits(top);\r
6403         return me;\r
6404     },\r
6405     \r
6406     /**\r
6407      * Returns the region of the given element.\r
6408      * The element must be part of the DOM tree to have a region (display:none or elements not appended return false).\r
6409      * @return {Region} A Ext.lib.Region containing "top, left, bottom, right" member data.\r
6410      */\r
6411     getRegion : function(){\r
6412         return Ext.lib.Dom.getRegion(this.dom);\r
6413     },\r
6414     \r
6415     /**\r
6416      * 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
6417      * @param {Number} x X value for new position (coordinates are page-based)\r
6418      * @param {Number} y Y value for new position (coordinates are page-based)\r
6419      * @param {Mixed} width The new width. This may be one of:<div class="mdetail-params"><ul>\r
6420      * <li>A Number specifying the new width in this Element's {@link #defaultUnit}s (by default, pixels)</li>\r
6421      * <li>A String used to set the CSS width style. Animation may <b>not</b> be used.\r
6422      * </ul></div>\r
6423      * @param {Mixed} height The new height. This may be one of:<div class="mdetail-params"><ul>\r
6424      * <li>A Number specifying the new height in this Element's {@link #defaultUnit}s (by default, pixels)</li>\r
6425      * <li>A String used to set the CSS height style. Animation may <b>not</b> be used.</li>\r
6426      * </ul></div>\r
6427      * @param {Boolean/Object} animate (optional) true for the default animation or a standard Element animation config object\r
6428      * @return {Ext.Element} this\r
6429      */\r
6430     setBounds : function(x, y, width, height, animate){\r
6431             var me = this;\r
6432         if (!animate || !me.anim) {\r
6433             me.setSize(width, height);\r
6434             me.setLocation(x, y);\r
6435         } else {\r
6436             me.anim({points: {to: [x, y]}, \r
6437                          width: {to: me.adjustWidth(width)}, \r
6438                          height: {to: me.adjustHeight(height)}},\r
6439                      me.preanim(arguments, 4), \r
6440                      'motion');\r
6441         }\r
6442         return me;\r
6443     },\r
6444 \r
6445     /**\r
6446      * 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
6447      * @param {Ext.lib.Region} region The region to fill\r
6448      * @param {Boolean/Object} animate (optional) true for the default animation or a standard Element animation config object\r
6449      * @return {Ext.Element} this\r
6450      */\r
6451     setRegion : function(region, animate) {\r
6452         return this.setBounds(region.left, region.top, region.right-region.left, region.bottom-region.top, this.animTest.call(this, arguments, animate, 1));\r
6453     }\r
6454 });/**\r
6455  * @class Ext.Element\r
6456  */\r
6457 Ext.Element.addMethods({\r
6458     /**\r
6459      * Returns true if this element is scrollable.\r
6460      * @return {Boolean}\r
6461      */\r
6462     isScrollable : function(){\r
6463         var dom = this.dom;\r
6464         return dom.scrollHeight > dom.clientHeight || dom.scrollWidth > dom.clientWidth;\r
6465     },\r
6466 \r
6467     /**\r
6468      * 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
6469      * @param {String} side Either "left" for scrollLeft values or "top" for scrollTop values.\r
6470      * @param {Number} value The new scroll value.\r
6471      * @return {Element} this\r
6472      */\r
6473     scrollTo : function(side, value){\r
6474         this.dom["scroll" + (/top/i.test(side) ? "Top" : "Left")] = value;\r
6475         return this;\r
6476     },\r
6477 \r
6478     /**\r
6479      * Returns the current scroll position of the element.\r
6480      * @return {Object} An object containing the scroll position in the format {left: (scrollLeft), top: (scrollTop)}\r
6481      */\r
6482     getScroll : function(){\r
6483         var d = this.dom, \r
6484             doc = document,\r
6485             body = doc.body,\r
6486             docElement = doc.documentElement,\r
6487             l,\r
6488             t,\r
6489             ret;\r
6490 \r
6491         if(d == doc || d == body){\r
6492             if(Ext.isIE && Ext.isStrict){\r
6493                 l = docElement.scrollLeft; \r
6494                 t = docElement.scrollTop;\r
6495             }else{\r
6496                 l = window.pageXOffset;\r
6497                 t = window.pageYOffset;\r
6498             }\r
6499             ret = {left: l || (body ? body.scrollLeft : 0), top: t || (body ? body.scrollTop : 0)};\r
6500         }else{\r
6501             ret = {left: d.scrollLeft, top: d.scrollTop};\r
6502         }\r
6503         return ret;\r
6504     }\r
6505 });/**\r
6506  * @class Ext.Element\r
6507  */\r
6508 Ext.Element.addMethods({\r
6509     /**\r
6510      * 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
6511      * @param {String} side Either "left" for scrollLeft values or "top" for scrollTop values.\r
6512      * @param {Number} value The new scroll value\r
6513      * @param {Boolean/Object} animate (optional) true for the default animation or a standard Element animation config object\r
6514      * @return {Element} this\r
6515      */\r
6516     scrollTo : function(side, value, animate){\r
6517         var top = /top/i.test(side), //check if we're scrolling top or left\r
6518             prop = 'scroll' + (top ? 'Left' : 'Top'), // if scrolling top, we need to grab scrollLeft, if left, scrollTop\r
6519             me = this,\r
6520             dom = me.dom;\r
6521         if (!animate || !me.anim) {\r
6522             dom[prop] = value;\r
6523         } else {\r
6524             me.anim({scroll: {to: top ? [dom[prop], value] : [value, dom[prop]]}},\r
6525                      me.preanim(arguments, 2), 'scroll');\r
6526         }\r
6527         return me;\r
6528     },\r
6529     \r
6530     /**\r
6531      * Scrolls this element into view within the passed container.\r
6532      * @param {Mixed} container (optional) The container element to scroll (defaults to document.body).  Should be a\r
6533      * string (id), dom node, or Ext.Element.\r
6534      * @param {Boolean} hscroll (optional) False to disable horizontal scroll (defaults to true)\r
6535      * @return {Ext.Element} this\r
6536      */\r
6537     scrollIntoView : function(container, hscroll){\r
6538         var c = Ext.getDom(container) || Ext.getBody().dom,\r
6539                 el = this.dom,\r
6540                 o = this.getOffsetsTo(c),\r
6541             l = o[0] + c.scrollLeft,\r
6542             t = o[1] + c.scrollTop,\r
6543             b = t + el.offsetHeight,\r
6544             r = l + el.offsetWidth,\r
6545                 ch = c.clientHeight,\r
6546                 ct = parseInt(c.scrollTop, 10),\r
6547                 cl = parseInt(c.scrollLeft, 10),\r
6548                 cb = ct + ch,\r
6549                 cr = cl + c.clientWidth;\r
6550 \r
6551         if (el.offsetHeight > ch || t < ct) {\r
6552                 c.scrollTop = t;\r
6553         } else if (b > cb){\r
6554             c.scrollTop = b-ch;\r
6555         }\r
6556         c.scrollTop = c.scrollTop; // corrects IE, other browsers will ignore\r
6557 \r
6558         if(hscroll !== false){\r
6559                         if(el.offsetWidth > c.clientWidth || l < cl){\r
6560                 c.scrollLeft = l;\r
6561             }else if(r > cr){\r
6562                 c.scrollLeft = r - c.clientWidth;\r
6563             }\r
6564             c.scrollLeft = c.scrollLeft;\r
6565         }\r
6566         return this;\r
6567     },\r
6568 \r
6569     // private\r
6570     scrollChildIntoView : function(child, hscroll){\r
6571         Ext.fly(child, '_scrollChildIntoView').scrollIntoView(this, hscroll);\r
6572     },\r
6573     \r
6574     /**\r
6575      * Scrolls this element the specified direction. Does bounds checking to make sure the scroll is\r
6576      * within this element's scrollable range.\r
6577      * @param {String} direction Possible values are: "l" (or "left"), "r" (or "right"), "t" (or "top", or "up"), "b" (or "bottom", or "down").\r
6578      * @param {Number} distance How far to scroll the element in pixels\r
6579      * @param {Boolean/Object} animate (optional) true for the default animation or a standard Element animation config object\r
6580      * @return {Boolean} Returns true if a scroll was triggered or false if the element\r
6581      * was scrolled as far as it could go.\r
6582      */\r
6583      scroll : function(direction, distance, animate){\r
6584          if(!this.isScrollable()){\r
6585              return;\r
6586          }\r
6587          var el = this.dom,\r
6588             l = el.scrollLeft, t = el.scrollTop,\r
6589             w = el.scrollWidth, h = el.scrollHeight,\r
6590             cw = el.clientWidth, ch = el.clientHeight,\r
6591             scrolled = false, v,\r
6592             hash = {\r
6593                 l: Math.min(l + distance, w-cw),\r
6594                 r: v = Math.max(l - distance, 0),\r
6595                 t: Math.max(t - distance, 0),\r
6596                 b: Math.min(t + distance, h-ch)\r
6597             };\r
6598             hash.d = hash.b;\r
6599             hash.u = hash.t;\r
6600             \r
6601          direction = direction.substr(0, 1);\r
6602          if((v = hash[direction]) > -1){\r
6603             scrolled = true;\r
6604             this.scrollTo(direction == 'l' || direction == 'r' ? 'left' : 'top', v, this.preanim(arguments, 2));\r
6605          }\r
6606          return scrolled;\r
6607     }\r
6608 });/**\r
6609  * @class Ext.Element\r
6610  */\r
6611 /**\r
6612  * Visibility mode constant for use with {@link #setVisibilityMode}. Use visibility to hide element\r
6613  * @static\r
6614  * @type Number\r
6615  */\r
6616 Ext.Element.VISIBILITY = 1;\r
6617 /**\r
6618  * Visibility mode constant for use with {@link #setVisibilityMode}. Use display to hide element\r
6619  * @static\r
6620  * @type Number\r
6621  */\r
6622 Ext.Element.DISPLAY = 2;\r
6623 \r
6624 Ext.Element.addMethods(function(){\r
6625     var VISIBILITY = "visibility",\r
6626         DISPLAY = "display",\r
6627         HIDDEN = "hidden",\r
6628         NONE = "none",      \r
6629         ORIGINALDISPLAY = 'originalDisplay',\r
6630         VISMODE = 'visibilityMode',\r
6631         ELDISPLAY = Ext.Element.DISPLAY,\r
6632         data = Ext.Element.data,\r
6633         getDisplay = function(dom){\r
6634             var d = data(dom, ORIGINALDISPLAY);\r
6635             if(d === undefined){\r
6636                 data(dom, ORIGINALDISPLAY, d = '');\r
6637             }\r
6638             return d;\r
6639         },\r
6640         getVisMode = function(dom){\r
6641             var m = data(dom, VISMODE);\r
6642             if(m === undefined){\r
6643                 data(dom, VISMODE, m = 1)\r
6644             }\r
6645             return m;\r
6646         };\r
6647     \r
6648     return {\r
6649         /**\r
6650          * The element's default display mode  (defaults to "")\r
6651          * @type String\r
6652          */\r
6653         originalDisplay : "",\r
6654         visibilityMode : 1,\r
6655         \r
6656         /**\r
6657          * Sets the element's visibility mode. When setVisible() is called it\r
6658          * will use this to determine whether to set the visibility or the display property.\r
6659          * @param {Number} visMode Ext.Element.VISIBILITY or Ext.Element.DISPLAY\r
6660          * @return {Ext.Element} this\r
6661          */\r
6662         setVisibilityMode : function(visMode){  \r
6663             data(this.dom, VISMODE, visMode);\r
6664             return this;\r
6665         },\r
6666         \r
6667         /**\r
6668          * Perform custom animation on this element.\r
6669          * <div><ul class="mdetail-params">\r
6670          * <li><u>Animation Properties</u></li>\r
6671          * \r
6672          * <p>The Animation Control Object enables gradual transitions for any member of an\r
6673          * element's style object that takes a numeric value including but not limited to\r
6674          * these properties:</p><div><ul class="mdetail-params">\r
6675          * <li><tt>bottom, top, left, right</tt></li>\r
6676          * <li><tt>height, width</tt></li>\r
6677          * <li><tt>margin, padding</tt></li>\r
6678          * <li><tt>borderWidth</tt></li>\r
6679          * <li><tt>opacity</tt></li>\r
6680          * <li><tt>fontSize</tt></li>\r
6681          * <li><tt>lineHeight</tt></li>\r
6682          * </ul></div>\r
6683          * \r
6684          * \r
6685          * <li><u>Animation Property Attributes</u></li>\r
6686          * \r
6687          * <p>Each Animation Property is a config object with optional properties:</p>\r
6688          * <div><ul class="mdetail-params">\r
6689          * <li><tt>by</tt>*  : relative change - start at current value, change by this value</li>\r
6690          * <li><tt>from</tt> : ignore current value, start from this value</li>\r
6691          * <li><tt>to</tt>*  : start at current value, go to this value</li>\r
6692          * <li><tt>unit</tt> : any allowable unit specification</li>\r
6693          * <p>* do not specify both <tt>to</tt> and <tt>by</tt> for an animation property</p>\r
6694          * </ul></div>\r
6695          * \r
6696          * <li><u>Animation Types</u></li>\r
6697          * \r
6698          * <p>The supported animation types:</p><div><ul class="mdetail-params">\r
6699          * <li><tt>'run'</tt> : Default\r
6700          * <pre><code>\r
6701 var el = Ext.get('complexEl');\r
6702 el.animate(\r
6703     // animation control object\r
6704     {\r
6705         borderWidth: {to: 3, from: 0},\r
6706         opacity: {to: .3, from: 1},\r
6707         height: {to: 50, from: el.getHeight()},\r
6708         width: {to: 300, from: el.getWidth()},\r
6709         top  : {by: - 100, unit: 'px'},\r
6710     },\r
6711     0.35,      // animation duration\r
6712     null,      // callback\r
6713     'easeOut', // easing method\r
6714     'run'      // animation type ('run','color','motion','scroll')    \r
6715 );\r
6716          * </code></pre>\r
6717          * </li>\r
6718          * <li><tt>'color'</tt>\r
6719          * <p>Animates transition of background, text, or border colors.</p>\r
6720          * <pre><code>\r
6721 el.animate(\r
6722     // animation control object\r
6723     {\r
6724         color: { to: '#06e' },\r
6725         backgroundColor: { to: '#e06' }\r
6726     },\r
6727     0.35,      // animation duration\r
6728     null,      // callback\r
6729     'easeOut', // easing method\r
6730     'color'    // animation type ('run','color','motion','scroll')    \r
6731 );\r
6732          * </code></pre> \r
6733          * </li>\r
6734          * \r
6735          * <li><tt>'motion'</tt>\r
6736          * <p>Animates the motion of an element to/from specific points using optional bezier\r
6737          * way points during transit.</p>\r
6738          * <pre><code>\r
6739 el.animate(\r
6740     // animation control object\r
6741     {\r
6742         borderWidth: {to: 3, from: 0},\r
6743         opacity: {to: .3, from: 1},\r
6744         height: {to: 50, from: el.getHeight()},\r
6745         width: {to: 300, from: el.getWidth()},\r
6746         top  : {by: - 100, unit: 'px'},\r
6747         points: {\r
6748             to: [50, 100],  // go to this point\r
6749             control: [      // optional bezier way points\r
6750                 [ 600, 800],\r
6751                 [-100, 200]\r
6752             ]\r
6753         }\r
6754     },\r
6755     3000,      // animation duration (milliseconds!)\r
6756     null,      // callback\r
6757     'easeOut', // easing method\r
6758     'motion'   // animation type ('run','color','motion','scroll')    \r
6759 );\r
6760          * </code></pre> \r
6761          * </li>\r
6762          * <li><tt>'scroll'</tt>\r
6763          * <p>Animate horizontal or vertical scrolling of an overflowing page element.</p>\r
6764          * <pre><code>\r
6765 el.animate(\r
6766     // animation control object\r
6767     {\r
6768         scroll: {to: [400, 300]}\r
6769     },\r
6770     0.35,      // animation duration\r
6771     null,      // callback\r
6772     'easeOut', // easing method\r
6773     'scroll'   // animation type ('run','color','motion','scroll')    \r
6774 );\r
6775          * </code></pre> \r
6776          * </li>\r
6777          * </ul></div>\r
6778          * \r
6779          * </ul></div>\r
6780          * \r
6781          * @param {Object} args The animation control args\r
6782          * @param {Float} duration (optional) How long the animation lasts in seconds (defaults to <tt>.35</tt>)\r
6783          * @param {Function} onComplete (optional) Function to call when animation completes\r
6784          * @param {String} easing (optional) {@link Ext.Fx#easing} method to use (defaults to <tt>'easeOut'</tt>)\r
6785          * @param {String} animType (optional) <tt>'run'</tt> is the default. Can also be <tt>'color'</tt>,\r
6786          * <tt>'motion'</tt>, or <tt>'scroll'</tt>\r
6787          * @return {Ext.Element} this\r
6788          */\r
6789         animate : function(args, duration, onComplete, easing, animType){       \r
6790             this.anim(args, {duration: duration, callback: onComplete, easing: easing}, animType);\r
6791             return this;\r
6792         },\r
6793     \r
6794         /*\r
6795          * @private Internal animation call\r
6796          */\r
6797         anim : function(args, opt, animType, defaultDur, defaultEase, cb){\r
6798             animType = animType || 'run';\r
6799             opt = opt || {};\r
6800             var me = this,              \r
6801                 anim = Ext.lib.Anim[animType](\r
6802                     me.dom, \r
6803                     args,\r
6804                     (opt.duration || defaultDur) || .35,\r
6805                     (opt.easing || defaultEase) || 'easeOut',\r
6806                     function(){\r
6807                         if(cb) cb.call(me);\r
6808                         if(opt.callback) opt.callback.call(opt.scope || me, me, opt);\r
6809                     },\r
6810                     me\r
6811                 );\r
6812             opt.anim = anim;\r
6813             return anim;\r
6814         },\r
6815     \r
6816         // private legacy anim prep\r
6817         preanim : function(a, i){\r
6818             return !a[i] ? false : (Ext.isObject(a[i]) ? a[i]: {duration: a[i+1], callback: a[i+2], easing: a[i+3]});\r
6819         },\r
6820         \r
6821         /**\r
6822          * Checks whether the element is currently visible using both visibility and display properties.         \r
6823          * @return {Boolean} True if the element is currently visible, else false\r
6824          */\r
6825         isVisible : function() {\r
6826             return !this.isStyle(VISIBILITY, HIDDEN) && !this.isStyle(DISPLAY, NONE);\r
6827         },\r
6828         \r
6829         /**\r
6830          * Sets the visibility of the element (see details). If the visibilityMode is set to Element.DISPLAY, it will use\r
6831          * the display property to hide the element, otherwise it uses visibility. The default is to hide and show using the visibility property.\r
6832          * @param {Boolean} visible Whether the element is visible\r
6833          * @param {Boolean/Object} animate (optional) True for the default animation, or a standard Element animation config object\r
6834          * @return {Ext.Element} this\r
6835          */\r
6836          setVisible : function(visible, animate){\r
6837             var me = this,\r
6838                 dom = me.dom,\r
6839                 isDisplay = getVisMode(this.dom) == ELDISPLAY;\r
6840                 \r
6841             if (!animate || !me.anim) {\r
6842                 if(isDisplay){\r
6843                     me.setDisplayed(visible);\r
6844                 }else{\r
6845                     me.fixDisplay();\r
6846                     dom.style.visibility = visible ? "visible" : HIDDEN;\r
6847                 }\r
6848             }else{\r
6849                 // closure for composites            \r
6850                 if(visible){\r
6851                     me.setOpacity(.01);\r
6852                     me.setVisible(true);\r
6853                 }\r
6854                 me.anim({opacity: { to: (visible?1:0) }},\r
6855                         me.preanim(arguments, 1),\r
6856                         null,\r
6857                         .35,\r
6858                         'easeIn',\r
6859                         function(){\r
6860                              if(!visible){\r
6861                                  dom.style[isDisplay ? DISPLAY : VISIBILITY] = (isDisplay) ? NONE : HIDDEN;                     \r
6862                                  Ext.fly(dom).setOpacity(1);\r
6863                              }\r
6864                         });\r
6865             }\r
6866             return me;\r
6867         },\r
6868     \r
6869         /**\r
6870          * Toggles the element's visibility or display, depending on visibility mode.\r
6871          * @param {Boolean/Object} animate (optional) True for the default animation, or a standard Element animation config object\r
6872          * @return {Ext.Element} this\r
6873          */\r
6874         toggle : function(animate){\r
6875             var me = this;\r
6876             me.setVisible(!me.isVisible(), me.preanim(arguments, 0));\r
6877             return me;\r
6878         },\r
6879     \r
6880         /**\r
6881          * Sets the CSS display property. Uses originalDisplay if the specified value is a boolean true.\r
6882          * @param {Mixed} value Boolean value to display the element using its default display, or a string to set the display directly.\r
6883          * @return {Ext.Element} this\r
6884          */\r
6885         setDisplayed : function(value) {            \r
6886             if(typeof value == "boolean"){\r
6887                value = value ? getDisplay(this.dom) : NONE;\r
6888             }\r
6889             this.setStyle(DISPLAY, value);\r
6890             return this;\r
6891         },\r
6892         \r
6893         // private\r
6894         fixDisplay : function(){\r
6895             var me = this;\r
6896             if(me.isStyle(DISPLAY, NONE)){\r
6897                 me.setStyle(VISIBILITY, HIDDEN);\r
6898                 me.setStyle(DISPLAY, getDisplay(this.dom)); // first try reverting to default\r
6899                 if(me.isStyle(DISPLAY, NONE)){ // if that fails, default to block\r
6900                     me.setStyle(DISPLAY, "block");\r
6901                 }\r
6902             }\r
6903         },\r
6904     \r
6905         /**\r
6906          * Hide this element - Uses display mode to determine whether to use "display" or "visibility". See {@link #setVisible}.\r
6907          * @param {Boolean/Object} animate (optional) true for the default animation or a standard Element animation config object\r
6908          * @return {Ext.Element} this\r
6909          */\r
6910         hide : function(animate){\r
6911             this.setVisible(false, this.preanim(arguments, 0));\r
6912             return this;\r
6913         },\r
6914     \r
6915         /**\r
6916         * Show this element - Uses display mode to determine whether to use "display" or "visibility". See {@link #setVisible}.\r
6917         * @param {Boolean/Object} animate (optional) true for the default animation or a standard Element animation config object\r
6918          * @return {Ext.Element} this\r
6919          */\r
6920         show : function(animate){\r
6921             this.setVisible(true, this.preanim(arguments, 0));\r
6922             return this;\r
6923         }\r
6924     }\r
6925 }());/**\r
6926  * @class Ext.Element\r
6927  */\r
6928 Ext.Element.addMethods(\r
6929 function(){\r
6930     var VISIBILITY = "visibility",\r
6931         DISPLAY = "display",\r
6932         HIDDEN = "hidden",\r
6933         NONE = "none",\r
6934             XMASKED = "x-masked",\r
6935                 XMASKEDRELATIVE = "x-masked-relative",\r
6936         data = Ext.Element.data;\r
6937                 \r
6938         return {\r
6939                 /**\r
6940              * Checks whether the element is currently visible using both visibility and display properties.\r
6941              * @param {Boolean} deep (optional) True to walk the dom and see if parent elements are hidden (defaults to false)\r
6942              * @return {Boolean} True if the element is currently visible, else false\r
6943              */\r
6944             isVisible : function(deep) {\r
6945                 var vis = !this.isStyle(VISIBILITY,HIDDEN) && !this.isStyle(DISPLAY,NONE),\r
6946                         p = this.dom.parentNode;\r
6947                 if(deep !== true || !vis){\r
6948                     return vis;\r
6949                 }               \r
6950                 while(p && !/body/i.test(p.tagName)){\r
6951                     if(!Ext.fly(p, '_isVisible').isVisible()){\r
6952                         return false;\r
6953                     }\r
6954                     p = p.parentNode;\r
6955                 }\r
6956                 return true;\r
6957             },\r
6958             \r
6959             /**\r
6960              * Returns true if display is not "none"\r
6961              * @return {Boolean}\r
6962              */\r
6963             isDisplayed : function() {\r
6964                 return !this.isStyle(DISPLAY, NONE);\r
6965             },\r
6966             \r
6967                 /**\r
6968              * Convenience method for setVisibilityMode(Element.DISPLAY)\r
6969              * @param {String} display (optional) What to set display to when visible\r
6970              * @return {Ext.Element} this\r
6971              */\r
6972             enableDisplayMode : function(display){          \r
6973                 this.setVisibilityMode(Ext.Element.DISPLAY);\r
6974                 if(!Ext.isEmpty(display)){\r
6975                 data(this.dom, 'originalDisplay', display);\r
6976             }\r
6977                 return this;\r
6978             },\r
6979             \r
6980                 /**\r
6981              * Puts a mask over this element to disable user interaction. Requires core.css.\r
6982              * This method can only be applied to elements which accept child nodes.\r
6983              * @param {String} msg (optional) A message to display in the mask\r
6984              * @param {String} msgCls (optional) A css class to apply to the msg element\r
6985              * @return {Element} The mask element\r
6986              */\r
6987             mask : function(msg, msgCls){\r
6988                     var me = this,\r
6989                         dom = me.dom,\r
6990                         dh = Ext.DomHelper,\r
6991                         EXTELMASKMSG = "ext-el-mask-msg",\r
6992                 el, \r
6993                 mask;\r
6994                         \r
6995                 if(me.getStyle("position") == "static"){\r
6996                     me.addClass(XMASKEDRELATIVE);\r
6997                 }\r
6998                 if((el = data(dom, 'maskMsg'))){\r
6999                     el.remove();\r
7000                 }\r
7001                 if((el = data(dom, 'mask'))){\r
7002                     el.remove();\r
7003                 }\r
7004         \r
7005             mask = dh.append(dom, {cls : "ext-el-mask"}, true);\r
7006                 data(dom, 'mask', mask);\r
7007         \r
7008                 me.addClass(XMASKED);\r
7009                 mask.setDisplayed(true);\r
7010                 if(typeof msg == 'string'){\r
7011                 var mm = dh.append(dom, {cls : EXTELMASKMSG, cn:{tag:'div'}}, true);\r
7012                 data(dom, 'maskMsg', mm);\r
7013                     mm.dom.className = msgCls ? EXTELMASKMSG + " " + msgCls : EXTELMASKMSG;\r
7014                     mm.dom.firstChild.innerHTML = msg;\r
7015                     mm.setDisplayed(true);\r
7016                     mm.center(me);\r
7017                 }\r
7018                 if(Ext.isIE && !(Ext.isIE7 && Ext.isStrict) && me.getStyle('height') == 'auto'){ // ie will not expand full height automatically\r
7019                     mask.setSize(undefined, me.getHeight());\r
7020                 }\r
7021                 return mask;\r
7022             },\r
7023         \r
7024             /**\r
7025              * Removes a previously applied mask.\r
7026              */\r
7027             unmask : function(){\r
7028                     var me = this,\r
7029                 dom = me.dom,\r
7030                         mask = data(dom, 'mask'),\r
7031                         maskMsg = data(dom, 'maskMsg');\r
7032                 if(mask){\r
7033                     if(maskMsg){\r
7034                         maskMsg.remove();\r
7035                     data(dom, 'maskMsg', undefined);\r
7036                     }\r
7037                     mask.remove();\r
7038                 data(dom, 'mask', undefined);\r
7039                 }\r
7040                 me.removeClass([XMASKED, XMASKEDRELATIVE]);\r
7041             },\r
7042         \r
7043             /**\r
7044              * Returns true if this element is masked\r
7045              * @return {Boolean}\r
7046              */\r
7047             isMasked : function(){\r
7048             var m = data(this.dom, 'mask');\r
7049                 return m && m.isVisible();\r
7050             },\r
7051             \r
7052             /**\r
7053              * Creates an iframe shim for this element to keep selects and other windowed objects from\r
7054              * showing through.\r
7055              * @return {Ext.Element} The new shim element\r
7056              */\r
7057             createShim : function(){\r
7058                 var el = document.createElement('iframe'),              \r
7059                         shim;\r
7060                 el.frameBorder = '0';\r
7061                 el.className = 'ext-shim';\r
7062                 el.src = Ext.SSL_SECURE_URL;\r
7063                 shim = Ext.get(this.dom.parentNode.insertBefore(el, this.dom));\r
7064                 shim.autoBoxAdjust = false;\r
7065                 return shim;\r
7066             }\r
7067     };\r
7068 }());/**\r
7069  * @class Ext.Element\r
7070  */\r
7071 Ext.Element.addMethods({\r
7072     /**\r
7073      * Convenience method for constructing a KeyMap\r
7074      * @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
7075      *                                  {key: (number or array), shift: (true/false), ctrl: (true/false), alt: (true/false)}\r
7076      * @param {Function} fn The function to call\r
7077      * @param {Object} scope (optional) The scope of the function\r
7078      * @return {Ext.KeyMap} The KeyMap created\r
7079      */\r
7080     addKeyListener : function(key, fn, scope){\r
7081         var config;\r
7082         if(!Ext.isObject(key) || Ext.isArray(key)){\r
7083             config = {\r
7084                 key: key,\r
7085                 fn: fn,\r
7086                 scope: scope\r
7087             };\r
7088         }else{\r
7089             config = {\r
7090                 key : key.key,\r
7091                 shift : key.shift,\r
7092                 ctrl : key.ctrl,\r
7093                 alt : key.alt,\r
7094                 fn: fn,\r
7095                 scope: scope\r
7096             };\r
7097         }\r
7098         return new Ext.KeyMap(this, config);\r
7099     },\r
7100 \r
7101     /**\r
7102      * Creates a KeyMap for this element\r
7103      * @param {Object} config The KeyMap config. See {@link Ext.KeyMap} for more details\r
7104      * @return {Ext.KeyMap} The KeyMap created\r
7105      */\r
7106     addKeyMap : function(config){\r
7107         return new Ext.KeyMap(this, config);\r
7108     }\r
7109 });(function(){\r
7110     // contants\r
7111     var NULL = null,\r
7112         UNDEFINED = undefined,\r
7113         TRUE = true,\r
7114         FALSE = false,\r
7115         SETX = "setX",\r
7116         SETY = "setY",\r
7117         SETXY = "setXY",\r
7118         LEFT = "left",\r
7119         BOTTOM = "bottom",\r
7120         TOP = "top",\r
7121         RIGHT = "right",\r
7122         HEIGHT = "height",\r
7123         WIDTH = "width",\r
7124         POINTS = "points",\r
7125         HIDDEN = "hidden",\r
7126         ABSOLUTE = "absolute",\r
7127         VISIBLE = "visible",\r
7128         MOTION = "motion",\r
7129         POSITION = "position",\r
7130         EASEOUT = "easeOut",\r
7131         /*\r
7132          * Use a light flyweight here since we are using so many callbacks and are always assured a DOM element\r
7133          */\r
7134         flyEl = new Ext.Element.Flyweight(),\r
7135         queues = {},\r
7136         getObject = function(o){\r
7137             return o || {};\r
7138         },\r
7139         fly = function(dom){\r
7140             flyEl.dom = dom;\r
7141             flyEl.id = Ext.id(dom);\r
7142             return flyEl;\r
7143         },\r
7144         /*\r
7145          * Queueing now stored outside of the element due to closure issues\r
7146          */\r
7147         getQueue = function(id){\r
7148             if(!queues[id]){\r
7149                 queues[id] = [];\r
7150             }\r
7151             return queues[id];\r
7152         },\r
7153         setQueue = function(id, value){\r
7154             queues[id] = value;\r
7155         };\r
7156         \r
7157 //Notifies Element that fx methods are available\r
7158 Ext.enableFx = TRUE;\r
7159 \r
7160 /**\r
7161  * @class Ext.Fx\r
7162  * <p>A class to provide basic animation and visual effects support.  <b>Note:</b> This class is automatically applied\r
7163  * to the {@link Ext.Element} interface when included, so all effects calls should be performed via {@link Ext.Element}.\r
7164  * Conversely, since the effects are not actually defined in {@link Ext.Element}, Ext.Fx <b>must</b> be\r
7165  * {@link Ext#enableFx included} in order for the Element effects to work.</p><br/>\r
7166  * \r
7167  * <p><b><u>Method Chaining</u></b></p>\r
7168  * <p>It is important to note that although the Fx methods and many non-Fx Element methods support "method chaining" in that\r
7169  * they return the Element object itself as the method return value, it is not always possible to mix the two in a single\r
7170  * method chain.  The Fx methods use an internal effects queue so that each effect can be properly timed and sequenced.\r
7171  * Non-Fx methods, on the other hand, have no such internal queueing and will always execute immediately.  For this reason,\r
7172  * 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
7173  * expected results and should be done with care.  Also see <tt>{@link #callback}</tt>.</p><br/>\r
7174  *\r
7175  * <p><b><u>Anchor Options for Motion Effects</u></b></p>\r
7176  * <p>Motion effects support 8-way anchoring, meaning that you can choose one of 8 different anchor points on the Element\r
7177  * that will serve as either the start or end point of the animation.  Following are all of the supported anchor positions:</p>\r
7178 <pre>\r
7179 Value  Description\r
7180 -----  -----------------------------\r
7181 tl     The top left corner\r
7182 t      The center of the top edge\r
7183 tr     The top right corner\r
7184 l      The center of the left edge\r
7185 r      The center of the right edge\r
7186 bl     The bottom left corner\r
7187 b      The center of the bottom edge\r
7188 br     The bottom right corner\r
7189 </pre>\r
7190  * <b>Note</b>: some Fx methods accept specific custom config parameters.  The options shown in the Config Options\r
7191  * section below are common options that can be passed to any Fx method unless otherwise noted.</b>\r
7192  * \r
7193  * @cfg {Function} callback A function called when the effect is finished.  Note that effects are queued internally by the\r
7194  * Fx class, so a callback is not required to specify another effect -- effects can simply be chained together\r
7195  * and called in sequence (see note for <b><u>Method Chaining</u></b> above), for example:<pre><code>\r
7196  * el.slideIn().highlight();\r
7197  * </code></pre>\r
7198  * The callback is intended for any additional code that should run once a particular effect has completed. The Element\r
7199  * being operated upon is passed as the first parameter.\r
7200  * \r
7201  * @cfg {Object} scope The scope (<code>this</code> reference) in which the <tt>{@link #callback}</tt> function is executed. Defaults to the browser window.\r
7202  * \r
7203  * @cfg {String} easing A valid Ext.lib.Easing value for the effect:</p><div class="mdetail-params"><ul>\r
7204  * <li><b><tt>backBoth</tt></b></li>\r
7205  * <li><b><tt>backIn</tt></b></li>\r
7206  * <li><b><tt>backOut</tt></b></li>\r
7207  * <li><b><tt>bounceBoth</tt></b></li>\r
7208  * <li><b><tt>bounceIn</tt></b></li>\r
7209  * <li><b><tt>bounceOut</tt></b></li>\r
7210  * <li><b><tt>easeBoth</tt></b></li>\r
7211  * <li><b><tt>easeBothStrong</tt></b></li>\r
7212  * <li><b><tt>easeIn</tt></b></li>\r
7213  * <li><b><tt>easeInStrong</tt></b></li>\r
7214  * <li><b><tt>easeNone</tt></b></li>\r
7215  * <li><b><tt>easeOut</tt></b></li>\r
7216  * <li><b><tt>easeOutStrong</tt></b></li>\r
7217  * <li><b><tt>elasticBoth</tt></b></li>\r
7218  * <li><b><tt>elasticIn</tt></b></li>\r
7219  * <li><b><tt>elasticOut</tt></b></li>\r
7220  * </ul></div>\r
7221  *\r
7222  * @cfg {String} afterCls A css class to apply after the effect\r
7223  * @cfg {Number} duration The length of time (in seconds) that the effect should last\r
7224  * \r
7225  * @cfg {Number} endOpacity Only applicable for {@link #fadeIn} or {@link #fadeOut}, a number between\r
7226  * <tt>0</tt> and <tt>1</tt> inclusive to configure the ending opacity value.\r
7227  *  \r
7228  * @cfg {Boolean} remove Whether the Element should be removed from the DOM and destroyed after the effect finishes\r
7229  * @cfg {Boolean} useDisplay Whether to use the <i>display</i> CSS property instead of <i>visibility</i> when hiding Elements (only applies to \r
7230  * effects that end with the element being visually hidden, ignored otherwise)\r
7231  * @cfg {String/Object/Function} afterStyle A style specification string, e.g. <tt>"width:100px"</tt>, or an object\r
7232  * in the form <tt>{width:"100px"}</tt>, or a function which returns such a specification that will be applied to the\r
7233  * Element after the effect finishes.\r
7234  * @cfg {Boolean} block Whether the effect should block other effects from queueing while it runs\r
7235  * @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
7236  * @cfg {Boolean} stopFx Whether preceding effects should be stopped and removed before running current effect (only applies to non blocking effects)\r
7237  */\r
7238 Ext.Fx = {\r
7239     \r
7240     // private - calls the function taking arguments from the argHash based on the key.  Returns the return value of the function.\r
7241     //           this is useful for replacing switch statements (for example).\r
7242     switchStatements : function(key, fn, argHash){\r
7243         return fn.apply(this, argHash[key]);\r
7244     },\r
7245     \r
7246     /**\r
7247      * Slides the element into view.  An anchor point can be optionally passed to set the point of\r
7248      * origin for the slide effect.  This function automatically handles wrapping the element with\r
7249      * a fixed-size container if needed.  See the Fx class overview for valid anchor point options.\r
7250      * Usage:\r
7251      *<pre><code>\r
7252 // default: slide the element in from the top\r
7253 el.slideIn();\r
7254 \r
7255 // custom: slide the element in from the right with a 2-second duration\r
7256 el.slideIn('r', { duration: 2 });\r
7257 \r
7258 // common config options shown with default values\r
7259 el.slideIn('t', {\r
7260     easing: 'easeOut',\r
7261     duration: .5\r
7262 });\r
7263 </code></pre>\r
7264      * @param {String} anchor (optional) One of the valid Fx anchor positions (defaults to top: 't')\r
7265      * @param {Object} options (optional) Object literal with any of the Fx config options\r
7266      * @return {Ext.Element} The Element\r
7267      */\r
7268     slideIn : function(anchor, o){ \r
7269         o = getObject(o);\r
7270         var me = this,\r
7271             dom = me.dom,\r
7272             st = dom.style,\r
7273             xy,\r
7274             r,\r
7275             b,              \r
7276             wrap,               \r
7277             after,\r
7278             st,\r
7279             args, \r
7280             pt,\r
7281             bw,\r
7282             bh;\r
7283             \r
7284         anchor = anchor || "t";\r
7285 \r
7286         me.queueFx(o, function(){            \r
7287             xy = fly(dom).getXY();\r
7288             // fix display to visibility\r
7289             fly(dom).fixDisplay();            \r
7290             \r
7291             // restore values after effect\r
7292             r = fly(dom).getFxRestore();      \r
7293             b = {x: xy[0], y: xy[1], 0: xy[0], 1: xy[1], width: dom.offsetWidth, height: dom.offsetHeight};\r
7294             b.right = b.x + b.width;\r
7295             b.bottom = b.y + b.height;\r
7296             \r
7297             // fixed size for slide\r
7298             fly(dom).setWidth(b.width).setHeight(b.height);            \r
7299             \r
7300             // wrap if needed\r
7301             wrap = fly(dom).fxWrap(r.pos, o, HIDDEN);\r
7302             \r
7303             st.visibility = VISIBLE;\r
7304             st.position = ABSOLUTE;\r
7305             \r
7306             // clear out temp styles after slide and unwrap\r
7307             function after(){\r
7308                  fly(dom).fxUnwrap(wrap, r.pos, o);\r
7309                  st.width = r.width;\r
7310                  st.height = r.height;\r
7311                  fly(dom).afterFx(o);\r
7312             }\r
7313             \r
7314             // time to calculate the positions        \r
7315             pt = {to: [b.x, b.y]}; \r
7316             bw = {to: b.width};\r
7317             bh = {to: b.height};\r
7318                 \r
7319             function argCalc(wrap, style, ww, wh, sXY, sXYval, s1, s2, w, h, p){                    \r
7320                 var ret = {};\r
7321                 fly(wrap).setWidth(ww).setHeight(wh);\r
7322                 if(fly(wrap)[sXY]){\r
7323                     fly(wrap)[sXY](sXYval);                  \r
7324                 }\r
7325                 style[s1] = style[s2] = "0";                    \r
7326                 if(w){\r
7327                     ret.width = w\r
7328                 };\r
7329                 if(h){\r
7330                     ret.height = h;\r
7331                 }\r
7332                 if(p){\r
7333                     ret.points = p;\r
7334                 }\r
7335                 return ret;\r
7336             };\r
7337 \r
7338             args = fly(dom).switchStatements(anchor.toLowerCase(), argCalc, {\r
7339                     t  : [wrap, st, b.width, 0, NULL, NULL, LEFT, BOTTOM, NULL, bh, NULL],\r
7340                     l  : [wrap, st, 0, b.height, NULL, NULL, RIGHT, TOP, bw, NULL, NULL],\r
7341                     r  : [wrap, st, b.width, b.height, SETX, b.right, LEFT, TOP, NULL, NULL, pt],\r
7342                     b  : [wrap, st, b.width, b.height, SETY, b.bottom, LEFT, TOP, NULL, bh, pt],\r
7343                     tl : [wrap, st, 0, 0, NULL, NULL, RIGHT, BOTTOM, bw, bh, pt],\r
7344                     bl : [wrap, st, 0, 0, SETY, b.y + b.height, RIGHT, TOP, bw, bh, pt],\r
7345                     br : [wrap, st, 0, 0, SETXY, [b.right, b.bottom], LEFT, TOP, bw, bh, pt],\r
7346                     tr : [wrap, st, 0, 0, SETX, b.x + b.width, LEFT, BOTTOM, bw, bh, pt]\r
7347                 });\r
7348             \r
7349             st.visibility = VISIBLE;\r
7350             fly(wrap).show();\r
7351 \r
7352             arguments.callee.anim = fly(wrap).fxanim(args,\r
7353                 o,\r
7354                 MOTION,\r
7355                 .5,\r
7356                 EASEOUT, \r
7357                 after);\r
7358         });\r
7359         return me;\r
7360     },\r
7361     \r
7362     /**\r
7363      * Slides the element out of view.  An anchor point can be optionally passed to set the end point\r
7364      * for the slide effect.  When the effect is completed, the element will be hidden (visibility = \r
7365      * 'hidden') but block elements will still take up space in the document.  The element must be removed\r
7366      * from the DOM using the 'remove' config option if desired.  This function automatically handles \r
7367      * wrapping the element with a fixed-size container if needed.  See the Fx class overview for valid anchor point options.\r
7368      * Usage:\r
7369      *<pre><code>\r
7370 // default: slide the element out to the top\r
7371 el.slideOut();\r
7372 \r
7373 // custom: slide the element out to the right with a 2-second duration\r
7374 el.slideOut('r', { duration: 2 });\r
7375 \r
7376 // common config options shown with default values\r
7377 el.slideOut('t', {\r
7378     easing: 'easeOut',\r
7379     duration: .5,\r
7380     remove: false,\r
7381     useDisplay: false\r
7382 });\r
7383 </code></pre>\r
7384      * @param {String} anchor (optional) One of the valid Fx anchor positions (defaults to top: 't')\r
7385      * @param {Object} options (optional) Object literal with any of the Fx config options\r
7386      * @return {Ext.Element} The Element\r
7387      */\r
7388     slideOut : function(anchor, o){\r
7389         o = getObject(o);\r
7390         var me = this,\r
7391             dom = me.dom,\r
7392             st = dom.style,\r
7393             xy = me.getXY(),\r
7394             wrap,\r
7395             r,\r
7396             b,\r
7397             a,\r
7398             zero = {to: 0}; \r
7399                     \r
7400         anchor = anchor || "t";\r
7401 \r
7402         me.queueFx(o, function(){\r
7403             \r
7404             // restore values after effect\r
7405             r = fly(dom).getFxRestore(); \r
7406             b = {x: xy[0], y: xy[1], 0: xy[0], 1: xy[1], width: dom.offsetWidth, height: dom.offsetHeight};\r
7407             b.right = b.x + b.width;\r
7408             b.bottom = b.y + b.height;\r
7409                 \r
7410             // fixed size for slide   \r
7411             fly(dom).setWidth(b.width).setHeight(b.height);\r
7412 \r
7413             // wrap if needed\r
7414             wrap = fly(dom).fxWrap(r.pos, o, VISIBLE);\r
7415                 \r
7416             st.visibility = VISIBLE;\r
7417             st.position = ABSOLUTE;\r
7418             fly(wrap).setWidth(b.width).setHeight(b.height);            \r
7419 \r
7420             function after(){\r
7421                 o.useDisplay ? fly(dom).setDisplayed(FALSE) : fly(dom).hide();                \r
7422                 fly(dom).fxUnwrap(wrap, r.pos, o);\r
7423                 st.width = r.width;\r
7424                 st.height = r.height;\r
7425                 fly(dom).afterFx(o);\r
7426             }            \r
7427             \r
7428             function argCalc(style, s1, s2, p1, v1, p2, v2, p3, v3){                    \r
7429                 var ret = {};\r
7430                 \r
7431                 style[s1] = style[s2] = "0";\r
7432                 ret[p1] = v1;               \r
7433                 if(p2){\r
7434                     ret[p2] = v2;               \r
7435                 }\r
7436                 if(p3){\r
7437                     ret[p3] = v3;\r
7438                 }\r
7439                 \r
7440                 return ret;\r
7441             };\r
7442             \r
7443             a = fly(dom).switchStatements(anchor.toLowerCase(), argCalc, {\r
7444                 t  : [st, LEFT, BOTTOM, HEIGHT, zero],\r
7445                 l  : [st, RIGHT, TOP, WIDTH, zero],\r
7446                 r  : [st, LEFT, TOP, WIDTH, zero, POINTS, {to : [b.right, b.y]}],\r
7447                 b  : [st, LEFT, TOP, HEIGHT, zero, POINTS, {to : [b.x, b.bottom]}],\r
7448                 tl : [st, RIGHT, BOTTOM, WIDTH, zero, HEIGHT, zero],\r
7449                 bl : [st, RIGHT, TOP, WIDTH, zero, HEIGHT, zero, POINTS, {to : [b.x, b.bottom]}],\r
7450                 br : [st, LEFT, TOP, WIDTH, zero, HEIGHT, zero, POINTS, {to : [b.x + b.width, b.bottom]}],\r
7451                 tr : [st, LEFT, BOTTOM, WIDTH, zero, HEIGHT, zero, POINTS, {to : [b.right, b.y]}]\r
7452             });\r
7453             \r
7454             arguments.callee.anim = fly(wrap).fxanim(a,\r
7455                 o,\r
7456                 MOTION,\r
7457                 .5,\r
7458                 EASEOUT, \r
7459                 after);\r
7460         });\r
7461         return me;\r
7462     },\r
7463 \r
7464     /**\r
7465      * Fades the element out while slowly expanding it in all directions.  When the effect is completed, the \r
7466      * element will be hidden (visibility = 'hidden') but block elements will still take up space in the document. \r
7467      * The element must be removed from the DOM using the 'remove' config option if desired.\r
7468      * Usage:\r
7469      *<pre><code>\r
7470 // default\r
7471 el.puff();\r
7472 \r
7473 // common config options shown with default values\r
7474 el.puff({\r
7475     easing: 'easeOut',\r
7476     duration: .5,\r
7477     remove: false,\r
7478     useDisplay: false\r
7479 });\r
7480 </code></pre>\r
7481      * @param {Object} options (optional) Object literal with any of the Fx config options\r
7482      * @return {Ext.Element} The Element\r
7483      */\r
7484     puff : function(o){\r
7485         o = getObject(o);\r
7486         var me = this,\r
7487             dom = me.dom,\r
7488             st = dom.style,\r
7489             width,\r
7490             height,\r
7491             r;\r
7492 \r
7493         me.queueFx(o, function(){\r
7494             width = fly(dom).getWidth();\r
7495             height = fly(dom).getHeight();\r
7496             fly(dom).clearOpacity();\r
7497             fly(dom).show();\r
7498 \r
7499             // restore values after effect\r
7500             r = fly(dom).getFxRestore();                   \r
7501             \r
7502             function after(){\r
7503                 o.useDisplay ? fly(dom).setDisplayed(FALSE) : fly(dom).hide();                  \r
7504                 fly(dom).clearOpacity();  \r
7505                 fly(dom).setPositioning(r.pos);\r
7506                 st.width = r.width;\r
7507                 st.height = r.height;\r
7508                 st.fontSize = '';\r
7509                 fly(dom).afterFx(o);\r
7510             }   \r
7511 \r
7512             arguments.callee.anim = fly(dom).fxanim({\r
7513                     width : {to : fly(dom).adjustWidth(width * 2)},\r
7514                     height : {to : fly(dom).adjustHeight(height * 2)},\r
7515                     points : {by : [-width * .5, -height * .5]},\r
7516                     opacity : {to : 0},\r
7517                     fontSize: {to : 200, unit: "%"}\r
7518                 },\r
7519                 o,\r
7520                 MOTION,\r
7521                 .5,\r
7522                 EASEOUT,\r
7523                  after);\r
7524         });\r
7525         return me;\r
7526     },\r
7527 \r
7528     /**\r
7529      * Blinks the element as if it was clicked and then collapses on its center (similar to switching off a television).\r
7530      * When the effect is completed, the element will be hidden (visibility = 'hidden') but block elements will still \r
7531      * take up space in the document. The element must be removed from the DOM using the 'remove' config option if desired.\r
7532      * Usage:\r
7533      *<pre><code>\r
7534 // default\r
7535 el.switchOff();\r
7536 \r
7537 // all config options shown with default values\r
7538 el.switchOff({\r
7539     easing: 'easeIn',\r
7540     duration: .3,\r
7541     remove: false,\r
7542     useDisplay: false\r
7543 });\r
7544 </code></pre>\r
7545      * @param {Object} options (optional) Object literal with any of the Fx config options\r
7546      * @return {Ext.Element} The Element\r
7547      */\r
7548     switchOff : function(o){\r
7549         o = getObject(o);\r
7550         var me = this,\r
7551             dom = me.dom,\r
7552             st = dom.style,\r
7553             r;\r
7554 \r
7555         me.queueFx(o, function(){\r
7556             fly(dom).clearOpacity();\r
7557             fly(dom).clip();\r
7558 \r
7559             // restore values after effect\r
7560             r = fly(dom).getFxRestore();\r
7561                 \r
7562             function after(){\r
7563                 o.useDisplay ? fly(dom).setDisplayed(FALSE) : fly(dom).hide();  \r
7564                 fly(dom).clearOpacity();\r
7565                 fly(dom).setPositioning(r.pos);\r
7566                 st.width = r.width;\r
7567                 st.height = r.height;   \r
7568                 fly(dom).afterFx(o);\r
7569             };\r
7570 \r
7571             fly(dom).fxanim({opacity : {to : 0.3}}, \r
7572                 NULL, \r
7573                 NULL, \r
7574                 .1, \r
7575                 NULL, \r
7576                 function(){                                 \r
7577                     fly(dom).clearOpacity();\r
7578                         (function(){                            \r
7579                             fly(dom).fxanim({\r
7580                                 height : {to : 1},\r
7581                                 points : {by : [0, fly(dom).getHeight() * .5]}\r
7582                             }, \r
7583                             o, \r
7584                             MOTION, \r
7585                             0.3, \r
7586                             'easeIn', \r
7587                             after);\r
7588                         }).defer(100);\r
7589                 });\r
7590         });\r
7591         return me;\r
7592     },\r
7593 \r
7594     /**\r
7595      * Highlights the Element by setting a color (applies to the background-color by default, but can be\r
7596      * changed using the "attr" config option) and then fading back to the original color. If no original\r
7597      * color is available, you should provide the "endColor" config option which will be cleared after the animation.\r
7598      * Usage:\r
7599 <pre><code>\r
7600 // default: highlight background to yellow\r
7601 el.highlight();\r
7602 \r
7603 // custom: highlight foreground text to blue for 2 seconds\r
7604 el.highlight("0000ff", { attr: 'color', duration: 2 });\r
7605 \r
7606 // common config options shown with default values\r
7607 el.highlight("ffff9c", {\r
7608     attr: "background-color", //can be any valid CSS property (attribute) that supports a color value\r
7609     endColor: (current color) or "ffffff",\r
7610     easing: 'easeIn',\r
7611     duration: 1\r
7612 });\r
7613 </code></pre>\r
7614      * @param {String} color (optional) The highlight color. Should be a 6 char hex color without the leading # (defaults to yellow: 'ffff9c')\r
7615      * @param {Object} options (optional) Object literal with any of the Fx config options\r
7616      * @return {Ext.Element} The Element\r
7617      */ \r
7618     highlight : function(color, o){\r
7619         o = getObject(o);\r
7620         var me = this,\r
7621             dom = me.dom,\r
7622             attr = o.attr || "backgroundColor",\r
7623             a = {},\r
7624             restore;\r
7625 \r
7626         me.queueFx(o, function(){\r
7627             fly(dom).clearOpacity();\r
7628             fly(dom).show();\r
7629 \r
7630             function after(){\r
7631                 dom.style[attr] = restore;\r
7632                 fly(dom).afterFx(o);\r
7633             }            \r
7634             restore = dom.style[attr];\r
7635             a[attr] = {from: color || "ffff9c", to: o.endColor || fly(dom).getColor(attr) || "ffffff"};\r
7636             arguments.callee.anim = fly(dom).fxanim(a,\r
7637                 o,\r
7638                 'color',\r
7639                 1,\r
7640                 'easeIn', \r
7641                 after);\r
7642         });\r
7643         return me;\r
7644     },\r
7645 \r
7646    /**\r
7647     * Shows a ripple of exploding, attenuating borders to draw attention to an Element.\r
7648     * Usage:\r
7649 <pre><code>\r
7650 // default: a single light blue ripple\r
7651 el.frame();\r
7652 \r
7653 // custom: 3 red ripples lasting 3 seconds total\r
7654 el.frame("ff0000", 3, { duration: 3 });\r
7655 \r
7656 // common config options shown with default values\r
7657 el.frame("C3DAF9", 1, {\r
7658     duration: 1 //duration of each individual ripple.\r
7659     // Note: Easing is not configurable and will be ignored if included\r
7660 });\r
7661 </code></pre>\r
7662     * @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
7663     * @param {Number} count (optional) The number of ripples to display (defaults to 1)\r
7664     * @param {Object} options (optional) Object literal with any of the Fx config options\r
7665     * @return {Ext.Element} The Element\r
7666     */\r
7667     frame : function(color, count, o){\r
7668         o = getObject(o);\r
7669         var me = this,\r
7670             dom = me.dom,\r
7671             proxy,\r
7672             active;\r
7673 \r
7674         me.queueFx(o, function(){\r
7675             color = color || '#C3DAF9'\r
7676             if(color.length == 6){\r
7677                 color = '#' + color;\r
7678             }            \r
7679             count = count || 1;\r
7680             fly(dom).show();\r
7681 \r
7682             var xy = fly(dom).getXY(),\r
7683                 b = {x: xy[0], y: xy[1], 0: xy[0], 1: xy[1], width: dom.offsetWidth, height: dom.offsetHeight},\r
7684                 queue = function(){\r
7685                     proxy = fly(document.body || document.documentElement).createChild({\r
7686                         style:{\r
7687                             position : ABSOLUTE,\r
7688                             'z-index': 35000, // yee haw\r
7689                             border : '0px solid ' + color\r
7690                         }\r
7691                     });\r
7692                     return proxy.queueFx({}, animFn);\r
7693                 };\r
7694             \r
7695             \r
7696             arguments.callee.anim = {\r
7697                 isAnimated: true,\r
7698                 stop: function() {\r
7699                     count = 0;\r
7700                     proxy.stopFx();\r
7701                 }\r
7702             };\r
7703             \r
7704             function animFn(){\r
7705                 var scale = Ext.isBorderBox ? 2 : 1;\r
7706                 active = proxy.anim({\r
7707                     top : {from : b.y, to : b.y - 20},\r
7708                     left : {from : b.x, to : b.x - 20},\r
7709                     borderWidth : {from : 0, to : 10},\r
7710                     opacity : {from : 1, to : 0},\r
7711                     height : {from : b.height, to : b.height + 20 * scale},\r
7712                     width : {from : b.width, to : b.width + 20 * scale}\r
7713                 },{\r
7714                     duration: o.duration || 1,\r
7715                     callback: function() {\r
7716                         proxy.remove();\r
7717                         --count > 0 ? queue() : fly(dom).afterFx(o);\r
7718                     }\r
7719                 });\r
7720                 arguments.callee.anim = {\r
7721                     isAnimated: true,\r
7722                     stop: function(){\r
7723                         active.stop();\r
7724                     }\r
7725                 };\r
7726             };\r
7727             queue();\r
7728         });\r
7729         return me;\r
7730     },\r
7731 \r
7732    /**\r
7733     * Creates a pause before any subsequent queued effects begin.  If there are\r
7734     * no effects queued after the pause it will have no effect.\r
7735     * Usage:\r
7736 <pre><code>\r
7737 el.pause(1);\r
7738 </code></pre>\r
7739     * @param {Number} seconds The length of time to pause (in seconds)\r
7740     * @return {Ext.Element} The Element\r
7741     */\r
7742     pause : function(seconds){        \r
7743         var dom = this.dom,\r
7744             t;\r
7745 \r
7746         this.queueFx({}, function(){\r
7747             t = setTimeout(function(){\r
7748                 fly(dom).afterFx({});\r
7749             }, seconds * 1000);\r
7750             arguments.callee.anim = {\r
7751                 isAnimated: true,\r
7752                 stop: function(){\r
7753                     clearTimeout(t);\r
7754                     fly(dom).afterFx({});\r
7755                 }\r
7756             };\r
7757         });\r
7758         return this;\r
7759     },\r
7760 \r
7761    /**\r
7762     * Fade an element in (from transparent to opaque).  The ending opacity can be specified\r
7763     * using the <tt>{@link #endOpacity}</tt> config option.\r
7764     * Usage:\r
7765 <pre><code>\r
7766 // default: fade in from opacity 0 to 100%\r
7767 el.fadeIn();\r
7768 \r
7769 // custom: fade in from opacity 0 to 75% over 2 seconds\r
7770 el.fadeIn({ endOpacity: .75, duration: 2});\r
7771 \r
7772 // common config options shown with default values\r
7773 el.fadeIn({\r
7774     endOpacity: 1, //can be any value between 0 and 1 (e.g. .5)\r
7775     easing: 'easeOut',\r
7776     duration: .5\r
7777 });\r
7778 </code></pre>\r
7779     * @param {Object} options (optional) Object literal with any of the Fx config options\r
7780     * @return {Ext.Element} The Element\r
7781     */\r
7782     fadeIn : function(o){\r
7783         o = getObject(o);\r
7784         var me = this,\r
7785             dom = me.dom,\r
7786             to = o.endOpacity || 1;\r
7787         \r
7788         me.queueFx(o, function(){\r
7789             fly(dom).setOpacity(0);\r
7790             fly(dom).fixDisplay();\r
7791             dom.style.visibility = VISIBLE;\r
7792             arguments.callee.anim = fly(dom).fxanim({opacity:{to:to}},\r
7793                 o, NULL, .5, EASEOUT, function(){\r
7794                 if(to == 1){\r
7795                     fly(dom).clearOpacity();\r
7796                 }\r
7797                 fly(dom).afterFx(o);\r
7798             });\r
7799         });\r
7800         return me;\r
7801     },\r
7802 \r
7803    /**\r
7804     * Fade an element out (from opaque to transparent).  The ending opacity can be specified\r
7805     * using the <tt>{@link #endOpacity}</tt> config option.  Note that IE may require\r
7806     * <tt>{@link #useDisplay}:true</tt> in order to redisplay correctly.\r
7807     * Usage:\r
7808 <pre><code>\r
7809 // default: fade out from the element's current opacity to 0\r
7810 el.fadeOut();\r
7811 \r
7812 // custom: fade out from the element's current opacity to 25% over 2 seconds\r
7813 el.fadeOut({ endOpacity: .25, duration: 2});\r
7814 \r
7815 // common config options shown with default values\r
7816 el.fadeOut({\r
7817     endOpacity: 0, //can be any value between 0 and 1 (e.g. .5)\r
7818     easing: 'easeOut',\r
7819     duration: .5,\r
7820     remove: false,\r
7821     useDisplay: false\r
7822 });\r
7823 </code></pre>\r
7824     * @param {Object} options (optional) Object literal with any of the Fx config options\r
7825     * @return {Ext.Element} The Element\r
7826     */\r
7827     fadeOut : function(o){\r
7828         o = getObject(o);\r
7829         var me = this,\r
7830             dom = me.dom,\r
7831             style = dom.style,\r
7832             to = o.endOpacity || 0;         \r
7833         \r
7834         me.queueFx(o, function(){  \r
7835             arguments.callee.anim = fly(dom).fxanim({ \r
7836                 opacity : {to : to}},\r
7837                 o, \r
7838                 NULL, \r
7839                 .5, \r
7840                 EASEOUT, \r
7841                 function(){\r
7842                     if(to == 0){\r
7843                         Ext.Element.data(dom, 'visibilityMode') == Ext.Element.DISPLAY || o.useDisplay ? \r
7844                             style.display = "none" :\r
7845                             style.visibility = HIDDEN;\r
7846                             \r
7847                         fly(dom).clearOpacity();\r
7848                     }\r
7849                     fly(dom).afterFx(o);\r
7850             });\r
7851         });\r
7852         return me;\r
7853     },\r
7854 \r
7855    /**\r
7856     * Animates the transition of an element's dimensions from a starting height/width\r
7857     * to an ending height/width.  This method is a convenience implementation of {@link shift}.\r
7858     * Usage:\r
7859 <pre><code>\r
7860 // change height and width to 100x100 pixels\r
7861 el.scale(100, 100);\r
7862 \r
7863 // common config options shown with default values.  The height and width will default to\r
7864 // the element&#39;s existing values if passed as null.\r
7865 el.scale(\r
7866     [element&#39;s width],\r
7867     [element&#39;s height], {\r
7868         easing: 'easeOut',\r
7869         duration: .35\r
7870     }\r
7871 );\r
7872 </code></pre>\r
7873     * @param {Number} width  The new width (pass undefined to keep the original width)\r
7874     * @param {Number} height  The new height (pass undefined to keep the original height)\r
7875     * @param {Object} options (optional) Object literal with any of the Fx config options\r
7876     * @return {Ext.Element} The Element\r
7877     */\r
7878     scale : function(w, h, o){\r
7879         this.shift(Ext.apply({}, o, {\r
7880             width: w,\r
7881             height: h\r
7882         }));\r
7883         return this;\r
7884     },\r
7885 \r
7886    /**\r
7887     * Animates the transition of any combination of an element's dimensions, xy position and/or opacity.\r
7888     * Any of these properties not specified in the config object will not be changed.  This effect \r
7889     * requires that at least one new dimension, position or opacity setting must be passed in on\r
7890     * the config object in order for the function to have any effect.\r
7891     * Usage:\r
7892 <pre><code>\r
7893 // slide the element horizontally to x position 200 while changing the height and opacity\r
7894 el.shift({ x: 200, height: 50, opacity: .8 });\r
7895 \r
7896 // common config options shown with default values.\r
7897 el.shift({\r
7898     width: [element&#39;s width],\r
7899     height: [element&#39;s height],\r
7900     x: [element&#39;s x position],\r
7901     y: [element&#39;s y position],\r
7902     opacity: [element&#39;s opacity],\r
7903     easing: 'easeOut',\r
7904     duration: .35\r
7905 });\r
7906 </code></pre>\r
7907     * @param {Object} options  Object literal with any of the Fx config options\r
7908     * @return {Ext.Element} The Element\r
7909     */\r
7910     shift : function(o){\r
7911         o = getObject(o);\r
7912         var dom = this.dom,\r
7913             a = {};\r
7914                 \r
7915         this.queueFx(o, function(){\r
7916             for (var prop in o) {\r
7917                 if (o[prop] != UNDEFINED) {                                                 \r
7918                     a[prop] = {to : o[prop]};                   \r
7919                 }\r
7920             } \r
7921             \r
7922             a.width ? a.width.to = fly(dom).adjustWidth(o.width) : a;\r
7923             a.height ? a.height.to = fly(dom).adjustWidth(o.height) : a;   \r
7924             \r
7925             if (a.x || a.y || a.xy) {\r
7926                 a.points = a.xy || \r
7927                            {to : [ a.x ? a.x.to : fly(dom).getX(),\r
7928                                    a.y ? a.y.to : fly(dom).getY()]};                  \r
7929             }\r
7930 \r
7931             arguments.callee.anim = fly(dom).fxanim(a,\r
7932                 o, \r
7933                 MOTION, \r
7934                 .35, \r
7935                 EASEOUT, \r
7936                 function(){\r
7937                     fly(dom).afterFx(o);\r
7938                 });\r
7939         });\r
7940         return this;\r
7941     },\r
7942 \r
7943     /**\r
7944      * Slides the element while fading it out of view.  An anchor point can be optionally passed to set the \r
7945      * ending point of the effect.\r
7946      * Usage:\r
7947      *<pre><code>\r
7948 // default: slide the element downward while fading out\r
7949 el.ghost();\r
7950 \r
7951 // custom: slide the element out to the right with a 2-second duration\r
7952 el.ghost('r', { duration: 2 });\r
7953 \r
7954 // common config options shown with default values\r
7955 el.ghost('b', {\r
7956     easing: 'easeOut',\r
7957     duration: .5,\r
7958     remove: false,\r
7959     useDisplay: false\r
7960 });\r
7961 </code></pre>\r
7962      * @param {String} anchor (optional) One of the valid Fx anchor positions (defaults to bottom: 'b')\r
7963      * @param {Object} options (optional) Object literal with any of the Fx config options\r
7964      * @return {Ext.Element} The Element\r
7965      */\r
7966     ghost : function(anchor, o){\r
7967         o = getObject(o);\r
7968         var me = this,\r
7969             dom = me.dom,\r
7970             st = dom.style,\r
7971             a = {opacity: {to: 0}, points: {}},\r
7972             pt = a.points,\r
7973             r,\r
7974             w,\r
7975             h;\r
7976             \r
7977         anchor = anchor || "b";\r
7978 \r
7979         me.queueFx(o, function(){\r
7980             // restore values after effect\r
7981             r = fly(dom).getFxRestore();\r
7982             w = fly(dom).getWidth();\r
7983             h = fly(dom).getHeight();\r
7984             \r
7985             function after(){\r
7986                 o.useDisplay ? fly(dom).setDisplayed(FALSE) : fly(dom).hide();   \r
7987                 fly(dom).clearOpacity();\r
7988                 fly(dom).setPositioning(r.pos);\r
7989                 st.width = r.width;\r
7990                 st.height = r.height;\r
7991                 fly(dom).afterFx(o);\r
7992             }\r
7993                 \r
7994             pt.by = fly(dom).switchStatements(anchor.toLowerCase(), function(v1,v2){ return [v1, v2];}, {\r
7995                t  : [0, -h],\r
7996                l  : [-w, 0],\r
7997                r  : [w, 0],\r
7998                b  : [0, h],\r
7999                tl : [-w, -h],\r
8000                bl : [-w, h],\r
8001                br : [w, h],\r
8002                tr : [w, -h] \r
8003             });\r
8004                 \r
8005             arguments.callee.anim = fly(dom).fxanim(a,\r
8006                 o,\r
8007                 MOTION,\r
8008                 .5,\r
8009                 EASEOUT, after);\r
8010         });\r
8011         return me;\r
8012     },\r
8013 \r
8014     /**\r
8015      * Ensures that all effects queued after syncFx is called on the element are\r
8016      * run concurrently.  This is the opposite of {@link #sequenceFx}.\r
8017      * @return {Ext.Element} The Element\r
8018      */\r
8019     syncFx : function(){\r
8020         var me = this;\r
8021         me.fxDefaults = Ext.apply(me.fxDefaults || {}, {\r
8022             block : FALSE,\r
8023             concurrent : TRUE,\r
8024             stopFx : FALSE\r
8025         });\r
8026         return me;\r
8027     },\r
8028 \r
8029     /**\r
8030      * Ensures that all effects queued after sequenceFx is called on the element are\r
8031      * run in sequence.  This is the opposite of {@link #syncFx}.\r
8032      * @return {Ext.Element} The Element\r
8033      */\r
8034     sequenceFx : function(){\r
8035         var me = this;\r
8036         me.fxDefaults = Ext.apply(me.fxDefaults || {}, {\r
8037             block : FALSE,\r
8038             concurrent : FALSE,\r
8039             stopFx : FALSE\r
8040         });\r
8041         return me;\r
8042     },\r
8043 \r
8044     /* @private */\r
8045     nextFx : function(){        \r
8046         var ef = getQueue(this.dom.id)[0];\r
8047         if(ef){\r
8048             ef.call(this);\r
8049         }\r
8050     },\r
8051 \r
8052     /**\r
8053      * Returns true if the element has any effects actively running or queued, else returns false.\r
8054      * @return {Boolean} True if element has active effects, else false\r
8055      */\r
8056     hasActiveFx : function(){\r
8057         return getQueue(this.dom.id)[0];\r
8058     },\r
8059 \r
8060     /**\r
8061      * Stops any running effects and clears the element's internal effects queue if it contains\r
8062      * any additional effects that haven't started yet.\r
8063      * @return {Ext.Element} The Element\r
8064      */\r
8065     stopFx : function(finish){\r
8066         var me = this,\r
8067             id = me.dom.id;\r
8068         if(me.hasActiveFx()){\r
8069             var cur = getQueue(id)[0];\r
8070             if(cur && cur.anim){\r
8071                 if(cur.anim.isAnimated){\r
8072                     setQueue(id, [cur]); //clear\r
8073                     cur.anim.stop(finish !== undefined ? finish : TRUE);\r
8074                 }else{\r
8075                     setQueue(id, []);\r
8076                 }\r
8077             }\r
8078         }\r
8079         return me;\r
8080     },\r
8081 \r
8082     /* @private */\r
8083     beforeFx : function(o){\r
8084         if(this.hasActiveFx() && !o.concurrent){\r
8085            if(o.stopFx){\r
8086                this.stopFx();\r
8087                return TRUE;\r
8088            }\r
8089            return FALSE;\r
8090         }\r
8091         return TRUE;\r
8092     },\r
8093 \r
8094     /**\r
8095      * Returns true if the element is currently blocking so that no other effect can be queued\r
8096      * until this effect is finished, else returns false if blocking is not set.  This is commonly\r
8097      * used to ensure that an effect initiated by a user action runs to completion prior to the\r
8098      * same effect being restarted (e.g., firing only one effect even if the user clicks several times).\r
8099      * @return {Boolean} True if blocking, else false\r
8100      */\r
8101     hasFxBlock : function(){\r
8102         var q = getQueue(this.dom.id);\r
8103         return q && q[0] && q[0].block;\r
8104     },\r
8105 \r
8106     /* @private */\r
8107     queueFx : function(o, fn){\r
8108         var me = fly(this.dom);\r
8109         if(!me.hasFxBlock()){\r
8110             Ext.applyIf(o, me.fxDefaults);\r
8111             if(!o.concurrent){\r
8112                 var run = me.beforeFx(o);\r
8113                 fn.block = o.block;\r
8114                 getQueue(me.dom.id).push(fn);\r
8115                 if(run){\r
8116                     me.nextFx();\r
8117                 }\r
8118             }else{\r
8119                 fn.call(me);\r
8120             }\r
8121         }\r
8122         return me;\r
8123     },\r
8124 \r
8125     /* @private */\r
8126     fxWrap : function(pos, o, vis){ \r
8127         var dom = this.dom,\r
8128             wrap,\r
8129             wrapXY;\r
8130         if(!o.wrap || !(wrap = Ext.getDom(o.wrap))){            \r
8131             if(o.fixPosition){\r
8132                 wrapXY = fly(dom).getXY();\r
8133             }\r
8134             var div = document.createElement("div");\r
8135             div.style.visibility = vis;\r
8136             wrap = dom.parentNode.insertBefore(div, dom);\r
8137             fly(wrap).setPositioning(pos);\r
8138             if(fly(wrap).isStyle(POSITION, "static")){\r
8139                 fly(wrap).position("relative");\r
8140             }\r
8141             fly(dom).clearPositioning('auto');\r
8142             fly(wrap).clip();\r
8143             wrap.appendChild(dom);\r
8144             if(wrapXY){\r
8145                 fly(wrap).setXY(wrapXY);\r
8146             }\r
8147         }\r
8148         return wrap;\r
8149     },\r
8150 \r
8151     /* @private */\r
8152     fxUnwrap : function(wrap, pos, o){      \r
8153         var dom = this.dom;\r
8154         fly(dom).clearPositioning();\r
8155         fly(dom).setPositioning(pos);\r
8156         if(!o.wrap){\r
8157             var pn = fly(wrap).dom.parentNode;
8158             pn.insertBefore(dom, wrap); \r
8159             fly(wrap).remove();\r
8160         }\r
8161     },\r
8162 \r
8163     /* @private */\r
8164     getFxRestore : function(){\r
8165         var st = this.dom.style;\r
8166         return {pos: this.getPositioning(), width: st.width, height : st.height};\r
8167     },\r
8168 \r
8169     /* @private */\r
8170     afterFx : function(o){\r
8171         var dom = this.dom,\r
8172             id = dom.id;\r
8173         if(o.afterStyle){\r
8174             fly(dom).setStyle(o.afterStyle);            \r
8175         }\r
8176         if(o.afterCls){\r
8177             fly(dom).addClass(o.afterCls);\r
8178         }\r
8179         if(o.remove == TRUE){\r
8180             fly(dom).remove();\r
8181         }\r
8182         if(o.callback){\r
8183             o.callback.call(o.scope, fly(dom));\r
8184         }\r
8185         if(!o.concurrent){\r
8186             getQueue(id).shift();\r
8187             fly(dom).nextFx();\r
8188         }\r
8189     },\r
8190 \r
8191     /* @private */\r
8192     fxanim : function(args, opt, animType, defaultDur, defaultEase, cb){\r
8193         animType = animType || 'run';\r
8194         opt = opt || {};\r
8195         var anim = Ext.lib.Anim[animType](\r
8196                 this.dom, \r
8197                 args,\r
8198                 (opt.duration || defaultDur) || .35,\r
8199                 (opt.easing || defaultEase) || EASEOUT,\r
8200                 cb,            \r
8201                 this\r
8202             );\r
8203         opt.anim = anim;\r
8204         return anim;\r
8205     }\r
8206 };\r
8207 \r
8208 // backwards compat\r
8209 Ext.Fx.resize = Ext.Fx.scale;\r
8210 \r
8211 //When included, Ext.Fx is automatically applied to Element so that all basic\r
8212 //effects are available directly via the Element API\r
8213 Ext.Element.addMethods(Ext.Fx);\r
8214 })();
8215 /**\r
8216  * @class Ext.CompositeElementLite\r
8217  * <p>This class encapsulates a <i>collection</i> of DOM elements, providing methods to filter\r
8218  * members, or to perform collective actions upon the whole set.</p>\r
8219  * <p>Although they are not listed, this class supports all of the methods of {@link Ext.Element} and\r
8220  * {@link Ext.Fx}. The methods from these classes will be performed on all the elements in this collection.</p>\r
8221  * Example:<pre><code>\r
8222 var els = Ext.select("#some-el div.some-class");\r
8223 // or select directly from an existing element\r
8224 var el = Ext.get('some-el');\r
8225 el.select('div.some-class');\r
8226 \r
8227 els.setWidth(100); // all elements become 100 width\r
8228 els.hide(true); // all elements fade out and hide\r
8229 // or\r
8230 els.setWidth(100).hide(true);\r
8231 </code>\r
8232  */\r
8233 Ext.CompositeElementLite = function(els, root){\r
8234     /**\r
8235      * <p>The Array of DOM elements which this CompositeElement encapsulates. Read-only.</p>\r
8236      * <p>This will not <i>usually</i> be accessed in developers' code, but developers wishing\r
8237      * to augment the capabilities of the CompositeElementLite class may use it when adding\r
8238      * methods to the class.</p>\r
8239      * <p>For example to add the <code>nextAll</code> method to the class to <b>add</b> all\r
8240      * following siblings of selected elements, the code would be</p><code><pre>\r
8241 Ext.override(Ext.CompositeElementLite, {\r
8242     nextAll: function() {\r
8243         var els = this.elements, i, l = els.length, n, r = [], ri = -1;\r
8244 \r
8245 //      Loop through all elements in this Composite, accumulating\r
8246 //      an Array of all siblings.\r
8247         for (i = 0; i < l; i++) {\r
8248             for (n = els[i].nextSibling; n; n = n.nextSibling) {\r
8249                 r[++ri] = n;\r
8250             }\r
8251         }\r
8252 \r
8253 //      Add all found siblings to this Composite\r
8254         return this.add(r);\r
8255     }\r
8256 });</pre></code>\r
8257      * @type Array\r
8258      * @property elements\r
8259      */\r
8260     this.elements = [];\r
8261     this.add(els, root);\r
8262     this.el = new Ext.Element.Flyweight();\r
8263 };\r
8264 \r
8265 Ext.CompositeElementLite.prototype = {\r
8266     isComposite: true,    \r
8267     /**\r
8268      * Returns the number of elements in this Composite.\r
8269      * @return Number\r
8270      */\r
8271     getCount : function(){\r
8272         return this.elements.length;\r
8273     },    \r
8274     /**\r
8275      * Adds elements to this Composite object.\r
8276      * @param {Mixed} els Either an Array of DOM elements to add, or another Composite object who's elements should be added.\r
8277      * @return {CompositeElement} This Composite object.\r
8278      */\r
8279     add : function(els){\r
8280         if(els){\r
8281             if (Ext.isArray(els)) {\r
8282                 this.elements = this.elements.concat(els);\r
8283             } else {\r
8284                 var yels = this.elements;                                    \r
8285                 Ext.each(els, function(e) {\r
8286                     yels.push(e);\r
8287                 });\r
8288             }\r
8289         }\r
8290         return this;\r
8291     },\r
8292     invoke : function(fn, args){\r
8293         var els = this.elements,\r
8294             el = this.el;        \r
8295         Ext.each(els, function(e) {    \r
8296             el.dom = e;\r
8297             Ext.Element.prototype[fn].apply(el, args);\r
8298         });\r
8299         return this;\r
8300     },\r
8301     /**\r
8302      * Returns a flyweight Element of the dom element object at the specified index\r
8303      * @param {Number} index\r
8304      * @return {Ext.Element}\r
8305      */\r
8306     item : function(index){\r
8307         var me = this;\r
8308         if(!me.elements[index]){\r
8309             return null;\r
8310         }\r
8311         me.el.dom = me.elements[index];\r
8312         return me.el;\r
8313     },\r
8314 \r
8315     // fixes scope with flyweight\r
8316     addListener : function(eventName, handler, scope, opt){\r
8317         Ext.each(this.elements, function(e) {\r
8318             Ext.EventManager.on(e, eventName, handler, scope || e, opt);\r
8319         });\r
8320         return this;\r
8321     },\r
8322     /**\r
8323      * <p>Calls the passed function for each element in this composite.</p>\r
8324      * @param {Function} fn The function to call. The function is passed the following parameters:<ul>\r
8325      * <li><b>el</b> : Element<div class="sub-desc">The current Element in the iteration.\r
8326      * <b>This is the flyweight (shared) Ext.Element instance, so if you require a\r
8327      * a reference to the dom node, use el.dom.</b></div></li>\r
8328      * <li><b>c</b> : Composite<div class="sub-desc">This Composite object.</div></li>\r
8329      * <li><b>idx</b> : Number<div class="sub-desc">The zero-based index in the iteration.</div></li>\r
8330      * </ul>\r
8331      * @param {Object} scope (optional) The scope (<i>this</i> reference) in which the function is executed. (defaults to the Element)\r
8332      * @return {CompositeElement} this\r
8333      */\r
8334     each : function(fn, scope){       \r
8335         var me = this,\r
8336             el = me.el;\r
8337        \r
8338         Ext.each(me.elements, function(e,i) {    \r
8339             el.dom = e;\r
8340             return fn.call(scope || el, el, me, i);\r
8341         });\r
8342         return me;\r
8343     },\r
8344     \r
8345     /**\r
8346     * Clears this Composite and adds the elements passed.\r
8347     * @param {Mixed} els Either an array of DOM elements, or another Composite from which to fill this Composite.\r
8348     * @return {CompositeElement} this\r
8349     */\r
8350     fill : function(els){\r
8351         var me = this;\r
8352         me.elements = [];\r
8353         me.add(els);\r
8354         return me;\r
8355     },\r
8356     \r
8357     /**\r
8358      * Filters this composite to only elements that match the passed selector.\r
8359      * @param {String/Function} selector A string CSS selector or a comparison function.\r
8360      * The comparison function will be called with the following arguments:<ul>\r
8361      * <li><code>el</code> : Ext.Element<div class="sub-desc">The current DOM element.</div></li>\r
8362      * <li><code>index</code> : Number<div class="sub-desc">The current index within the collection.</div></li>\r
8363      * </ul>\r
8364      * @return {CompositeElement} this\r
8365      */\r
8366     filter : function(selector){\r
8367         var els = [],\r
8368             me = this,\r
8369             fn = Ext.isFunction(selector) ? selector\r
8370                 : function(el){\r
8371                     return el.is(selector);\r
8372                 }\r
8373         me.each(function(el, self, i){\r
8374             if(fn(el, i) !== false){\r
8375                 els[els.length] = el.dom;\r
8376             }\r
8377         });\r
8378         me.fill(els);\r
8379         return me;\r
8380     },\r
8381     \r
8382     /**\r
8383      * Find the index of the passed element within the composite collection.\r
8384      * @param el {Mixed} The id of an element, or an Ext.Element, or an HtmlElement to find within the composite collection.\r
8385      * @return Number The index of the passed Ext.Element in the composite collection, or -1 if not found.\r
8386      */\r
8387     indexOf : function(el){\r
8388         return this.elements.indexOf(Ext.getDom(el));\r
8389     },\r
8390     \r
8391     /**\r
8392     * Replaces the specified element with the passed element.\r
8393     * @param {Mixed} el The id of an element, the Element itself, the index of the element in this composite\r
8394     * to replace.\r
8395     * @param {Mixed} replacement The id of an element or the Element itself.\r
8396     * @param {Boolean} domReplace (Optional) True to remove and replace the element in the document too.\r
8397     * @return {CompositeElement} this\r
8398     */    \r
8399     replaceElement : function(el, replacement, domReplace){\r
8400         var index = !isNaN(el) ? el : this.indexOf(el),\r
8401             d;\r
8402         if(index > -1){\r
8403             replacement = Ext.getDom(replacement);\r
8404             if(domReplace){\r
8405                 d = this.elements[index];\r
8406                 d.parentNode.insertBefore(replacement, d);\r
8407                 Ext.removeNode(d);\r
8408             }\r
8409             this.elements.splice(index, 1, replacement);\r
8410         }\r
8411         return this;\r
8412     },\r
8413     \r
8414     /**\r
8415      * Removes all elements.\r
8416      */\r
8417     clear : function(){\r
8418         this.elements = [];\r
8419     }\r
8420 };\r
8421 \r
8422 Ext.CompositeElementLite.prototype.on = Ext.CompositeElementLite.prototype.addListener;\r
8423 \r
8424 (function(){\r
8425 var fnName,\r
8426     ElProto = Ext.Element.prototype,\r
8427     CelProto = Ext.CompositeElementLite.prototype;\r
8428     \r
8429 for(fnName in ElProto){\r
8430     if(Ext.isFunction(ElProto[fnName])){\r
8431         (function(fnName){ \r
8432             CelProto[fnName] = CelProto[fnName] || function(){\r
8433                 return this.invoke(fnName, arguments);\r
8434             };\r
8435         }).call(CelProto, fnName);\r
8436         \r
8437     }\r
8438 }\r
8439 })();\r
8440 \r
8441 if(Ext.DomQuery){\r
8442     Ext.Element.selectorFunction = Ext.DomQuery.select;\r
8443\r
8444 \r
8445 /**\r
8446  * Selects elements based on the passed CSS selector to enable {@link Ext.Element Element} methods\r
8447  * to be applied to many related elements in one statement through the returned {@link Ext.CompositeElement CompositeElement} or\r
8448  * {@link Ext.CompositeElementLite CompositeElementLite} object.\r
8449  * @param {String/Array} selector The CSS selector or an array of elements\r
8450  * @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
8451  * @param {HTMLElement/String} root (optional) The root element of the query or id of the root\r
8452  * @return {CompositeElementLite/CompositeElement}\r
8453  * @member Ext.Element\r
8454  * @method select\r
8455  */\r
8456 Ext.Element.select = function(selector, unique, root){\r
8457     var els;\r
8458     if(typeof selector == "string"){\r
8459         els = Ext.Element.selectorFunction(selector, root);\r
8460     }else if(selector.length !== undefined){\r
8461         els = selector;\r
8462     }else{\r
8463         throw "Invalid selector";\r
8464     }\r
8465     return new Ext.CompositeElementLite(els);\r
8466 };\r
8467 /**\r
8468  * Selects elements based on the passed CSS selector to enable {@link Ext.Element Element} methods\r
8469  * to be applied to many related elements in one statement through the returned {@link Ext.CompositeElement CompositeElement} or\r
8470  * {@link Ext.CompositeElementLite CompositeElementLite} object.\r
8471  * @param {String/Array} selector The CSS selector or an array of elements\r
8472  * @param {Boolean} unique (optional) true to create a unique Ext.Element for each element (defaults to a shared flyweight object)\r
8473  * @param {HTMLElement/String} root (optional) The root element of the query or id of the root\r
8474  * @return {CompositeElementLite/CompositeElement}\r
8475  * @member Ext\r
8476  * @method select\r
8477  */\r
8478 Ext.select = Ext.Element.select;/**\r
8479  * @class Ext.CompositeElementLite\r
8480  */\r
8481 Ext.apply(Ext.CompositeElementLite.prototype, { \r
8482         addElements : function(els, root){\r
8483         if(!els){\r
8484             return this;\r
8485         }\r
8486         if(typeof els == "string"){\r
8487             els = Ext.Element.selectorFunction(els, root);\r
8488         }\r
8489         var yels = this.elements;        \r
8490             Ext.each(els, function(e) {\r
8491                 yels.push(Ext.get(e));\r
8492         });\r
8493         return this;\r
8494     },\r
8495     \r
8496     /**\r
8497      * Returns the first Element\r
8498      * @return {Ext.Element}\r
8499      */\r
8500     first : function(){\r
8501         return this.item(0);\r
8502     },   \r
8503     \r
8504     /**\r
8505      * Returns the last Element\r
8506      * @return {Ext.Element}\r
8507      */\r
8508     last : function(){\r
8509         return this.item(this.getCount()-1);\r
8510     },\r
8511     \r
8512     /**\r
8513      * Returns true if this composite contains the passed element\r
8514      * @param el {Mixed} The id of an element, or an Ext.Element, or an HtmlElement to find within the composite collection.\r
8515      * @return Boolean\r
8516      */\r
8517     contains : function(el){\r
8518         return this.indexOf(el) != -1;\r
8519     },
8520     
8521     /**\r
8522     * Removes the specified element(s).\r
8523     * @param {Mixed} el The id of an element, the Element itself, the index of the element in this composite\r
8524     * or an array of any of those.\r
8525     * @param {Boolean} removeDom (optional) True to also remove the element from the document\r
8526     * @return {CompositeElement} this\r
8527     */\r
8528     removeElement : function(keys, removeDom){\r
8529         var me = this,\r
8530                 els = this.elements,        \r
8531                 el;             \r
8532             Ext.each(keys, function(val){\r
8533                     if ((el = (els[val] || els[val = me.indexOf(val)]))) {\r
8534                         if(removeDom){\r
8535                     if(el.dom){\r
8536                         el.remove();\r
8537                     }else{\r
8538                         Ext.removeNode(el);\r
8539                     }\r
8540                 }\r
8541                         els.splice(val, 1);                     \r
8542                         }\r
8543             });\r
8544         return this;\r
8545     }    \r
8546 });
8547 /**\r
8548  * @class Ext.CompositeElement\r
8549  * @extends Ext.CompositeElementLite\r
8550  * Standard composite class. Creates a Ext.Element for every element in the collection.\r
8551  * <br><br>\r
8552  * <b>NOTE: Although they are not listed, this class supports all of the set/update methods of Ext.Element. All Ext.Element\r
8553  * actions will be performed on all the elements in this collection.</b>\r
8554  * <br><br>\r
8555  * All methods return <i>this</i> and can be chained.\r
8556  <pre><code>\r
8557  var els = Ext.select("#some-el div.some-class", true);\r
8558  // or select directly from an existing element\r
8559  var el = Ext.get('some-el');\r
8560  el.select('div.some-class', true);\r
8561 \r
8562  els.setWidth(100); // all elements become 100 width\r
8563  els.hide(true); // all elements fade out and hide\r
8564  // or\r
8565  els.setWidth(100).hide(true);\r
8566  </code></pre>\r
8567  */\r
8568 Ext.CompositeElement = function(els, root){\r
8569     this.elements = [];\r
8570     this.add(els, root);\r
8571 };\r
8572 \r
8573 Ext.extend(Ext.CompositeElement, Ext.CompositeElementLite, {\r
8574     invoke : function(fn, args){\r
8575             Ext.each(this.elements, function(e) {\r
8576                 Ext.Element.prototype[fn].apply(e, args);\r
8577         });\r
8578         return this;\r
8579     },\r
8580 \r
8581     /**\r
8582     * Adds elements to this composite.\r
8583     * @param {String/Array} els A string CSS selector, an array of elements or an element\r
8584     * @return {CompositeElement} this\r
8585     */\r
8586     add : function(els, root){\r
8587             if(!els){\r
8588             return this;\r
8589         }\r
8590         if(typeof els == "string"){\r
8591             els = Ext.Element.selectorFunction(els, root);\r
8592         }\r
8593         var yels = this.elements;\r
8594             Ext.each(els, function(e) {\r
8595                 yels.push(Ext.get(e));\r
8596         });\r
8597         return this;\r
8598     },\r
8599 \r
8600     /**\r
8601      * Returns the Element object at the specified index\r
8602      * @param {Number} index\r
8603      * @return {Ext.Element}\r
8604      */\r
8605     item : function(index){\r
8606         return this.elements[index] || null;\r
8607     },\r
8608 \r
8609 \r
8610     indexOf : function(el){\r
8611         return this.elements.indexOf(Ext.get(el));\r
8612     },\r
8613 \r
8614     filter : function(selector){\r
8615                 var me = this,\r
8616                         out = [];\r
8617 \r
8618                 Ext.each(me.elements, function(el) {\r
8619                         if(el.is(selector)){\r
8620                                 out.push(Ext.get(el));\r
8621                         }\r
8622                 });\r
8623                 me.elements = out;\r
8624                 return me;\r
8625         },\r
8626 \r
8627     /**\r
8628      * Iterates each <code>element</code> in this <code>composite</code>\r
8629      * calling the supplied function using {@link Ext#each}.\r
8630      * @param {Function} fn The function to be called with each\r
8631      * <code>element</code>. If the supplied function returns <tt>false</tt>,\r
8632      * iteration stops. This function is called with the following arguments:\r
8633      * <div class="mdetail-params"><ul>\r
8634      * <li><code>element</code> : <i>Object</i>\r
8635      * <div class="sub-desc">The element at the current <code>index</code>\r
8636      * in the <code>composite</code></div></li>\r
8637      * <li><code>composite</code> : <i>Object</i>\r
8638      * <div class="sub-desc">This composite.</div></li>\r
8639      * <li><code>index</code> : <i>Number</i>\r
8640      * <div class="sub-desc">The current index within the <code>composite</code>\r
8641      * </div></li>\r
8642      * </ul></div>\r
8643      * @param {Object} scope (optional) The scope to call the specified function.\r
8644      * Defaults to the <code>element</code> at the current <code>index</code>\r
8645      * within the composite.\r
8646      * @return {CompositeElement} this\r
8647      */\r
8648     each : function(fn, scope){\r
8649         Ext.each(this.elements, function(e, i){\r
8650             return fn.call(scope || e, e, this, i);\r
8651         }, this);\r
8652         return this;\r
8653     }\r
8654 });\r
8655 \r
8656 /**\r
8657  * Selects elements based on the passed CSS selector to enable {@link Ext.Element Element} methods\r
8658  * to be applied to many related elements in one statement through the returned {@link Ext.CompositeElement CompositeElement} or\r
8659  * {@link Ext.CompositeElementLite CompositeElementLite} object.\r
8660  * @param {String/Array} selector The CSS selector or an array of elements\r
8661  * @param {Boolean} unique (optional) true to create a unique Ext.Element for each element (defaults to a shared flyweight object)\r
8662  * @param {HTMLElement/String} root (optional) The root element of the query or id of the root\r
8663  * @return {CompositeElementLite/CompositeElement}\r
8664  * @member Ext.Element\r
8665  * @method select\r
8666  */\r
8667 Ext.Element.select = function(selector, unique, root){\r
8668     var els;\r
8669     if(typeof selector == "string"){\r
8670         els = Ext.Element.selectorFunction(selector, root);\r
8671     }else if(selector.length !== undefined){\r
8672         els = selector;\r
8673     }else{\r
8674         throw "Invalid selector";\r
8675     }\r
8676 \r
8677     return (unique === true) ? new Ext.CompositeElement(els) : new Ext.CompositeElementLite(els);\r
8678 };\r
8679 \r
8680 /**\r
8681  * Selects elements based on the passed CSS selector to enable {@link Ext.Element Element} methods\r
8682  * to be applied to many related elements in one statement through the returned {@link Ext.CompositeElement CompositeElement} or\r
8683  * {@link Ext.CompositeElementLite CompositeElementLite} object.\r
8684  * @param {String/Array} selector The CSS selector or an array of elements\r
8685  * @param {Boolean} unique (optional) true to create a unique Ext.Element for each element (defaults to a shared flyweight object)\r
8686  * @param {HTMLElement/String} root (optional) The root element of the query or id of the root\r
8687  * @return {CompositeElementLite/CompositeElement}\r
8688  * @member Ext.Element\r
8689  * @method select\r
8690  */\r
8691 Ext.select = Ext.Element.select;(function(){\r
8692     var BEFOREREQUEST = "beforerequest",\r
8693         REQUESTCOMPLETE = "requestcomplete",\r
8694         REQUESTEXCEPTION = "requestexception",\r
8695         UNDEFINED = undefined,\r
8696         LOAD = 'load',\r
8697         POST = 'POST',\r
8698         GET = 'GET',\r
8699         WINDOW = window;\r
8700     \r
8701     /**\r
8702      * @class Ext.data.Connection\r
8703      * @extends Ext.util.Observable\r
8704      * <p>The class encapsulates a connection to the page's originating domain, allowing requests to be made\r
8705      * either to a configured URL, or to a URL specified at request time.</p>\r
8706      * <p>Requests made by this class are asynchronous, and will return immediately. No data from\r
8707      * the server will be available to the statement immediately following the {@link #request} call.\r
8708      * To process returned data, use a\r
8709      * <a href="#request-option-success" ext:member="request-option-success" ext:cls="Ext.data.Connection">success callback</a>\r
8710      * in the request options object,\r
8711      * or an {@link #requestcomplete event listener}.</p>\r
8712      * <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
8713      * is they are <b>not</b> performed using XMLHttpRequests. Instead the form is submitted in the standard\r
8714      * manner with the DOM <tt>&lt;form></tt> element temporarily modified to have its\r
8715      * <a href="http://www.w3.org/TR/REC-html40/present/frames.html#adef-target">target</a> set to refer\r
8716      * to a dynamically generated, hidden <tt>&lt;iframe></tt> which is inserted into the document\r
8717      * but removed after the return data has been gathered.</p>\r
8718      * <p>The server response is parsed by the browser to create the document for the IFRAME. If the\r
8719      * server is using JSON to send the return object, then the\r
8720      * <a href="http://www.w3.org/Protocols/rfc2616/rfc2616-sec14.html#sec14.17">Content-Type</a> header\r
8721      * must be set to "text/html" in order to tell the browser to insert the text unchanged into the document body.</p>\r
8722      * <p>Characters which are significant to an HTML parser must be sent as HTML entities, so encode\r
8723      * "&lt;" as "&amp;lt;", "&amp;" as "&amp;amp;" etc.</p>\r
8724      * <p>The response text is retrieved from the document, and a fake XMLHttpRequest object\r
8725      * is created containing a <tt>responseText</tt> property in order to conform to the\r
8726      * requirements of event handlers and callbacks.</p>\r
8727      * <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
8728      * and some server technologies (notably JEE) may require some custom processing in order to\r
8729      * retrieve parameter names and parameter values from the packet content.</p>\r
8730      * @constructor\r
8731      * @param {Object} config a configuration object.\r
8732      */\r
8733     Ext.data.Connection = function(config){    \r
8734         Ext.apply(this, config);\r
8735         this.addEvents(\r
8736             /**\r
8737              * @event beforerequest\r
8738              * Fires before a network request is made to retrieve a data object.\r
8739              * @param {Connection} conn This Connection object.\r
8740              * @param {Object} options The options config object passed to the {@link #request} method.\r
8741              */\r
8742             BEFOREREQUEST,\r
8743             /**\r
8744              * @event requestcomplete\r
8745              * Fires if the request was successfully completed.\r
8746              * @param {Connection} conn This Connection object.\r
8747              * @param {Object} response The XHR object containing the response data.\r
8748              * See <a href="http://www.w3.org/TR/XMLHttpRequest/">The XMLHttpRequest Object</a>\r
8749              * for details.\r
8750              * @param {Object} options The options config object passed to the {@link #request} method.\r
8751              */\r
8752             REQUESTCOMPLETE,\r
8753             /**\r
8754              * @event requestexception\r
8755              * Fires if an error HTTP status was returned from the server.\r
8756              * See <a href="http://www.w3.org/Protocols/rfc2616/rfc2616-sec10.html">HTTP Status Code Definitions</a>\r
8757              * for details of HTTP status codes.\r
8758              * @param {Connection} conn This Connection object.\r
8759              * @param {Object} response The XHR object containing the response data.\r
8760              * See <a href="http://www.w3.org/TR/XMLHttpRequest/">The XMLHttpRequest Object</a>\r
8761              * for details.\r
8762              * @param {Object} options The options config object passed to the {@link #request} method.\r
8763              */\r
8764             REQUESTEXCEPTION\r
8765         );\r
8766         Ext.data.Connection.superclass.constructor.call(this);\r
8767     };\r
8768 \r
8769     Ext.extend(Ext.data.Connection, Ext.util.Observable, {\r
8770         /**\r
8771          * @cfg {String} url (Optional) <p>The default URL to be used for requests to the server. Defaults to undefined.</p>\r
8772          * <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
8773          * (<code><b>this</b></code> reference) of the function is the <code>scope</code> option passed to the {@link #request} method.</p>\r
8774          */\r
8775         /**\r
8776          * @cfg {Object} extraParams (Optional) An object containing properties which are used as\r
8777          * extra parameters to each request made by this object. (defaults to undefined)\r
8778          */\r
8779         /**\r
8780          * @cfg {Object} defaultHeaders (Optional) An object containing request headers which are added\r
8781          *  to each request made by this object. (defaults to undefined)\r
8782          */\r
8783         /**\r
8784          * @cfg {String} method (Optional) The default HTTP method to be used for requests.\r
8785          * (defaults to undefined; if not set, but {@link #request} params are present, POST will be used;\r
8786          * otherwise, GET will be used.)\r
8787          */\r
8788         /**\r
8789          * @cfg {Number} timeout (Optional) The timeout in milliseconds to be used for requests. (defaults to 30000)\r
8790          */\r
8791         timeout : 30000,\r
8792         /**\r
8793          * @cfg {Boolean} autoAbort (Optional) Whether this request should abort any pending requests. (defaults to false)\r
8794          * @type Boolean\r
8795          */\r
8796         autoAbort:false,\r
8797     \r
8798         /**\r
8799          * @cfg {Boolean} disableCaching (Optional) True to add a unique cache-buster param to GET requests. (defaults to true)\r
8800          * @type Boolean\r
8801          */\r
8802         disableCaching: true,\r
8803         \r
8804         /**\r
8805          * @cfg {String} disableCachingParam (Optional) Change the parameter which is sent went disabling caching\r
8806          * through a cache buster. Defaults to '_dc'\r
8807          * @type String\r
8808          */\r
8809         disableCachingParam: '_dc',\r
8810         \r
8811         /**\r
8812          * <p>Sends an HTTP request to a remote server.</p>\r
8813          * <p><b>Important:</b> Ajax server requests are asynchronous, and this call will\r
8814          * return before the response has been received. Process any returned data\r
8815          * in a callback function.</p>\r
8816          * <pre><code>\r
8817 Ext.Ajax.request({\r
8818    url: 'ajax_demo/sample.json',\r
8819    success: function(response, opts) {\r
8820       var obj = Ext.decode(response.responseText);\r
8821       console.dir(obj);\r
8822    },\r
8823    failure: function(response, opts) {\r
8824       console.log('server-side failure with status code ' + response.status);\r
8825    }\r
8826 });\r
8827          * </code></pre>\r
8828          * <p>To execute a callback function in the correct scope, use the <tt>scope</tt> option.</p>\r
8829          * @param {Object} options An object which may contain the following properties:<ul>\r
8830          * <li><b>url</b> : String/Function (Optional)<div class="sub-desc">The URL to\r
8831          * which to send the request, or a function to call which returns a URL string. The scope of the\r
8832          * function is specified by the <tt>scope</tt> option. Defaults to the configured\r
8833          * <tt>{@link #url}</tt>.</div></li>\r
8834          * <li><b>params</b> : Object/String/Function (Optional)<div class="sub-desc">\r
8835          * An object containing properties which are used as parameters to the\r
8836          * request, a url encoded string or a function to call to get either. The scope of the function\r
8837          * is specified by the <tt>scope</tt> option.</div></li>\r
8838          * <li><b>method</b> : String (Optional)<div class="sub-desc">The HTTP method to use\r
8839          * for the request. Defaults to the configured method, or if no method was configured,\r
8840          * "GET" if no parameters are being sent, and "POST" if parameters are being sent.  Note that\r
8841          * the method name is case-sensitive and should be all caps.</div></li>\r
8842          * <li><b>callback</b> : Function (Optional)<div class="sub-desc">The\r
8843          * function to be called upon receipt of the HTTP response. The callback is\r
8844          * called regardless of success or failure and is passed the following\r
8845          * parameters:<ul>\r
8846          * <li><b>options</b> : Object<div class="sub-desc">The parameter to the request call.</div></li>\r
8847          * <li><b>success</b> : Boolean<div class="sub-desc">True if the request succeeded.</div></li>\r
8848          * <li><b>response</b> : Object<div class="sub-desc">The XMLHttpRequest object containing the response data. \r
8849          * See <a href="http://www.w3.org/TR/XMLHttpRequest/">http://www.w3.org/TR/XMLHttpRequest/</a> for details about \r
8850          * accessing elements of the response.</div></li>\r
8851          * </ul></div></li>\r
8852          * <li><a id="request-option-success"></a><b>success</b> : Function (Optional)<div class="sub-desc">The function\r
8853          * to be called upon success of the request. The callback is passed the following\r
8854          * parameters:<ul>\r
8855          * <li><b>response</b> : Object<div class="sub-desc">The XMLHttpRequest object containing the response data.</div></li>\r
8856          * <li><b>options</b> : Object<div class="sub-desc">The parameter to the request call.</div></li>\r
8857          * </ul></div></li>\r
8858          * <li><b>failure</b> : Function (Optional)<div class="sub-desc">The function\r
8859          * to be called upon failure of the request. The callback is passed the\r
8860          * following parameters:<ul>\r
8861          * <li><b>response</b> : Object<div class="sub-desc">The XMLHttpRequest object containing the response data.</div></li>\r
8862          * <li><b>options</b> : Object<div class="sub-desc">The parameter to the request call.</div></li>\r
8863          * </ul></div></li>\r
8864          * <li><b>scope</b> : Object (Optional)<div class="sub-desc">The scope in\r
8865          * which to execute the callbacks: The "this" object for the callback function. If the <tt>url</tt>, or <tt>params</tt> options were\r
8866          * specified as functions from which to draw values, then this also serves as the scope for those function calls.\r
8867          * Defaults to the browser window.</div></li>\r
8868          * <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
8869          * <li><b>form</b> : Element/HTMLElement/String (Optional)<div class="sub-desc">The <tt>&lt;form&gt;</tt>\r
8870          * Element or the id of the <tt>&lt;form&gt;</tt> to pull parameters from.</div></li>\r
8871          * <li><a id="request-option-isUpload"></a><b>isUpload</b> : Boolean (Optional)<div class="sub-desc"><b>Only meaningful when used \r
8872          * with the <tt>form</tt> option</b>.\r
8873          * <p>True if the form object is a file upload (will be set automatically if the form was\r
8874          * configured with <b><tt>enctype</tt></b> "multipart/form-data").</p>\r
8875          * <p>File uploads are not performed using normal "Ajax" techniques, that is they are <b>not</b>\r
8876          * performed using XMLHttpRequests. Instead the form is submitted in the standard manner with the\r
8877          * DOM <tt>&lt;form></tt> element temporarily modified to have its\r
8878          * <a href="http://www.w3.org/TR/REC-html40/present/frames.html#adef-target">target</a> set to refer\r
8879          * to a dynamically generated, hidden <tt>&lt;iframe></tt> which is inserted into the document\r
8880          * but removed after the return data has been gathered.</p>\r
8881          * <p>The server response is parsed by the browser to create the document for the IFRAME. If the\r
8882          * server is using JSON to send the return object, then the\r
8883          * <a href="http://www.w3.org/Protocols/rfc2616/rfc2616-sec14.html#sec14.17">Content-Type</a> header\r
8884          * must be set to "text/html" in order to tell the browser to insert the text unchanged into the document body.</p>\r
8885          * <p>The response text is retrieved from the document, and a fake XMLHttpRequest object\r
8886          * is created containing a <tt>responseText</tt> property in order to conform to the\r
8887          * requirements of event handlers and callbacks.</p>\r
8888          * <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
8889          * and some server technologies (notably JEE) may require some custom processing in order to\r
8890          * retrieve parameter names and parameter values from the packet content.</p>\r
8891          * </div></li>\r
8892          * <li><b>headers</b> : Object (Optional)<div class="sub-desc">Request\r
8893          * headers to set for the request.</div></li>\r
8894          * <li><b>xmlData</b> : Object (Optional)<div class="sub-desc">XML document\r
8895          * to use for the post. Note: This will be used instead of params for the post\r
8896          * data. Any params will be appended to the URL.</div></li>\r
8897          * <li><b>jsonData</b> : Object/String (Optional)<div class="sub-desc">JSON\r
8898          * data to use as the post. Note: This will be used instead of params for the post\r
8899          * data. Any params will be appended to the URL.</div></li>\r
8900          * <li><b>disableCaching</b> : Boolean (Optional)<div class="sub-desc">True\r
8901          * to add a unique cache-buster param to GET requests.</div></li>\r
8902          * </ul></p>\r
8903          * <p>The options object may also contain any other property which might be needed to perform\r
8904          * postprocessing in a callback because it is passed to callback functions.</p>\r
8905          * @return {Number} transactionId The id of the server transaction. This may be used\r
8906          * to cancel the request.\r
8907          */\r
8908         request : function(o){\r
8909             var me = this;\r
8910             if(me.fireEvent(BEFOREREQUEST, me, o)){\r
8911                 if (o.el) {\r
8912                     if(!Ext.isEmpty(o.indicatorText)){\r
8913                         me.indicatorText = '<div class="loading-indicator">'+o.indicatorText+"</div>";\r
8914                     }\r
8915                     if(me.indicatorText) {\r
8916                         Ext.getDom(o.el).innerHTML = me.indicatorText;                        \r
8917                     }\r
8918                     o.success = (Ext.isFunction(o.success) ? o.success : function(){}).createInterceptor(function(response) {\r
8919                         Ext.getDom(o.el).innerHTML = response.responseText;\r
8920                     });\r
8921                 }\r
8922                 \r
8923                 var p = o.params,\r
8924                     url = o.url || me.url,                \r
8925                     method,\r
8926                     cb = {success: me.handleResponse,\r
8927                           failure: me.handleFailure,\r
8928                           scope: me,\r
8929                           argument: {options: o},\r
8930                           timeout : o.timeout || me.timeout\r
8931                     },\r
8932                     form,                    \r
8933                     serForm;                    \r
8934                   \r
8935                      \r
8936                 if (Ext.isFunction(p)) {\r
8937                     p = p.call(o.scope||WINDOW, o);\r
8938                 }\r
8939                                                            \r
8940                 p = Ext.urlEncode(me.extraParams, Ext.isObject(p) ? Ext.urlEncode(p) : p);    \r
8941                 \r
8942                 if (Ext.isFunction(url)) {\r
8943                     url = url.call(o.scope || WINDOW, o);\r
8944                 }\r
8945     \r
8946                 if((form = Ext.getDom(o.form))){\r
8947                     url = url || form.action;\r
8948                      if(o.isUpload || /multipart\/form-data/i.test(form.getAttribute("enctype"))) { \r
8949                          return me.doFormUpload.call(me, o, p, url);\r
8950                      }\r
8951                     serForm = Ext.lib.Ajax.serializeForm(form);                    \r
8952                     p = p ? (p + '&' + serForm) : serForm;\r
8953                 }\r
8954                 \r
8955                 method = o.method || me.method || ((p || o.xmlData || o.jsonData) ? POST : GET);\r
8956                 \r
8957                 if(method === GET && (me.disableCaching && o.disableCaching !== false) || o.disableCaching === true){\r
8958                     var dcp = o.disableCachingParam || me.disableCachingParam;\r
8959                     url = Ext.urlAppend(url, dcp + '=' + (new Date().getTime()));\r
8960                 }\r
8961                 \r
8962                 o.headers = Ext.apply(o.headers || {}, me.defaultHeaders || {});\r
8963                 \r
8964                 if(o.autoAbort === true || me.autoAbort) {\r
8965                     me.abort();\r
8966                 }\r
8967                  \r
8968                 if((method == GET || o.xmlData || o.jsonData) && p){\r
8969                     url = Ext.urlAppend(url, p);  \r
8970                     p = '';\r
8971                 }\r
8972                 return (me.transId = Ext.lib.Ajax.request(method, url, cb, p, o));\r
8973             }else{                \r
8974                 return o.callback ? o.callback.apply(o.scope, [o,UNDEFINED,UNDEFINED]) : null;\r
8975             }\r
8976         },\r
8977     \r
8978         /**\r
8979          * Determine whether this object has a request outstanding.\r
8980          * @param {Number} transactionId (Optional) defaults to the last transaction\r
8981          * @return {Boolean} True if there is an outstanding request.\r
8982          */\r
8983         isLoading : function(transId){\r
8984             return transId ? Ext.lib.Ajax.isCallInProgress(transId) : !! this.transId;            \r
8985         },\r
8986     \r
8987         /**\r
8988          * Aborts any outstanding request.\r
8989          * @param {Number} transactionId (Optional) defaults to the last transaction\r
8990          */\r
8991         abort : function(transId){\r
8992             if(transId || this.isLoading()){\r
8993                 Ext.lib.Ajax.abort(transId || this.transId);\r
8994             }\r
8995         },\r
8996 \r
8997         // private\r
8998         handleResponse : function(response){\r
8999             this.transId = false;\r
9000             var options = response.argument.options;\r
9001             response.argument = options ? options.argument : null;\r
9002             this.fireEvent(REQUESTCOMPLETE, this, response, options);\r
9003             if(options.success){\r
9004                 options.success.call(options.scope, response, options);\r
9005             }\r
9006             if(options.callback){\r
9007                 options.callback.call(options.scope, options, true, response);\r
9008             }\r
9009         },\r
9010 \r
9011         // private\r
9012         handleFailure : function(response, e){\r
9013             this.transId = false;\r
9014             var options = response.argument.options;\r
9015             response.argument = options ? options.argument : null;\r
9016             this.fireEvent(REQUESTEXCEPTION, this, response, options, e);\r
9017             if(options.failure){\r
9018                 options.failure.call(options.scope, response, options);\r
9019             }\r
9020             if(options.callback){\r
9021                 options.callback.call(options.scope, options, false, response);\r
9022             }\r
9023         },\r
9024 \r
9025         // private\r
9026         doFormUpload : function(o, ps, url){\r
9027             var id = Ext.id(),\r
9028                 doc = document,\r
9029                 frame = doc.createElement('iframe'),\r
9030                 form = Ext.getDom(o.form),\r
9031                 hiddens = [],\r
9032                 hd,\r
9033                 encoding = 'multipart/form-data',\r
9034                 buf = {\r
9035                     target: form.target,\r
9036                     method: form.method,\r
9037                     encoding: form.encoding,\r
9038                     enctype: form.enctype,\r
9039                     action: form.action\r
9040                 };\r
9041 \r
9042             Ext.fly(frame).set({\r
9043                 id: id,\r
9044                 name: id,\r
9045                 cls: 'x-hidden',\r
9046                 src: Ext.SSL_SECURE_URL // for IE\r
9047             });\r
9048             doc.body.appendChild(frame);\r
9049 \r
9050             // This is required so that IE doesn't pop the response up in a new window.\r
9051             if(Ext.isIE){\r
9052                document.frames[id].name = id;\r
9053             }\r
9054 \r
9055             Ext.fly(form).set({\r
9056                 target: id,\r
9057                 method: POST,\r
9058                 enctype: encoding,\r
9059                 encoding: encoding,\r
9060                 action: url || buf.action\r
9061             });\r
9062 \r
9063             // add dynamic params\r
9064             Ext.iterate(Ext.urlDecode(ps, false), function(k, v){\r
9065                 hd = doc.createElement('input');\r
9066                 Ext.fly(hd).set({\r
9067                     type: 'hidden',\r
9068                     value: v,\r
9069                     name: k\r
9070                 });\r
9071                 form.appendChild(hd);\r
9072                 hiddens.push(hd);\r
9073             });\r
9074 \r
9075             function cb(){\r
9076                 var me = this,\r
9077                     // bogus response object\r
9078                     r = {responseText : '',\r
9079                          responseXML : null,\r
9080                          argument : o.argument},\r
9081                     doc,\r
9082                     firstChild;\r
9083 \r
9084                 try{\r
9085                     doc = frame.contentWindow.document || frame.contentDocument || WINDOW.frames[id].document;\r
9086                     if(doc){\r
9087                         if(doc.body){\r
9088                             if(/textarea/i.test((firstChild = doc.body.firstChild || {}).tagName)){ // json response wrapped in textarea\r
9089                                 r.responseText = firstChild.value;\r
9090                             }else{\r
9091                                 r.responseText = doc.body.innerHTML;\r
9092                             }\r
9093                         }\r
9094                         //in IE the document may still have a body even if returns XML.\r
9095                         r.responseXML = doc.XMLDocument || doc;\r
9096                     }\r
9097                 }\r
9098                 catch(e) {}\r
9099 \r
9100                 Ext.EventManager.removeListener(frame, LOAD, cb, me);\r
9101 \r
9102                 me.fireEvent(REQUESTCOMPLETE, me, r, o);\r
9103 \r
9104                 function runCallback(fn, scope, args){\r
9105                     if(Ext.isFunction(fn)){\r
9106                         fn.apply(scope, args);\r
9107                     }\r
9108                 }\r
9109 \r
9110                 runCallback(o.success, o.scope, [r, o]);\r
9111                 runCallback(o.callback, o.scope, [o, true, r]);\r
9112 \r
9113                 if(!me.debugUploads){\r
9114                     setTimeout(function(){Ext.removeNode(frame);}, 100);\r
9115                 }\r
9116             }\r
9117 \r
9118             Ext.EventManager.on(frame, LOAD, cb, this);\r
9119             form.submit();\r
9120 \r
9121             Ext.fly(form).set(buf);\r
9122             Ext.each(hiddens, function(h) {\r
9123                 Ext.removeNode(h);\r
9124             });\r
9125         }\r
9126     });\r
9127 })();\r
9128 \r
9129 /**\r
9130  * @class Ext.Ajax\r
9131  * @extends Ext.data.Connection\r
9132  * <p>The global Ajax request class that provides a simple way to make Ajax requests\r
9133  * with maximum flexibility.</p>\r
9134  * <p>Since Ext.Ajax is a singleton, you can set common properties/events for it once\r
9135  * and override them at the request function level only if necessary.</p>\r
9136  * <p>Common <b>Properties</b> you may want to set are:<div class="mdetail-params"><ul>\r
9137  * <li><b><tt>{@link #method}</tt></b><p class="sub-desc"></p></li>\r
9138  * <li><b><tt>{@link #extraParams}</tt></b><p class="sub-desc"></p></li>\r
9139  * <li><b><tt>{@link #url}</tt></b><p class="sub-desc"></p></li>\r
9140  * </ul></div>\r
9141  * <pre><code>\r
9142 // Default headers to pass in every request\r
9143 Ext.Ajax.defaultHeaders = {\r
9144     'Powered-By': 'Ext'\r
9145 };\r
9146  * </code></pre> \r
9147  * </p>\r
9148  * <p>Common <b>Events</b> you may want to set are:<div class="mdetail-params"><ul>\r
9149  * <li><b><tt>{@link Ext.data.Connection#beforerequest beforerequest}</tt></b><p class="sub-desc"></p></li>\r
9150  * <li><b><tt>{@link Ext.data.Connection#requestcomplete requestcomplete}</tt></b><p class="sub-desc"></p></li>\r
9151  * <li><b><tt>{@link Ext.data.Connection#requestexception requestexception}</tt></b><p class="sub-desc"></p></li>\r
9152  * </ul></div>\r
9153  * <pre><code>\r
9154 // Example: show a spinner during all Ajax requests\r
9155 Ext.Ajax.on('beforerequest', this.showSpinner, this);\r
9156 Ext.Ajax.on('requestcomplete', this.hideSpinner, this);\r
9157 Ext.Ajax.on('requestexception', this.hideSpinner, this);\r
9158  * </code></pre> \r
9159  * </p>\r
9160  * <p>An example request:</p>\r
9161  * <pre><code>\r
9162 // Basic request\r
9163 Ext.Ajax.{@link Ext.data.Connection#request request}({\r
9164    url: 'foo.php',\r
9165    success: someFn,\r
9166    failure: otherFn,\r
9167    headers: {\r
9168        'my-header': 'foo'\r
9169    },\r
9170    params: { foo: 'bar' }\r
9171 });\r
9172 \r
9173 // Simple ajax form submission\r
9174 Ext.Ajax.{@link Ext.data.Connection#request request}({\r
9175     form: 'some-form',\r
9176     params: 'foo=bar'\r
9177 });\r
9178  * </code></pre> \r
9179  * </p>\r
9180  * @singleton\r
9181  */\r
9182 Ext.Ajax = new Ext.data.Connection({\r
9183     /**\r
9184      * @cfg {String} url @hide\r
9185      */\r
9186     /**\r
9187      * @cfg {Object} extraParams @hide\r
9188      */\r
9189     /**\r
9190      * @cfg {Object} defaultHeaders @hide\r
9191      */\r
9192     /**\r
9193      * @cfg {String} method (Optional) @hide\r
9194      */\r
9195     /**\r
9196      * @cfg {Number} timeout (Optional) @hide\r
9197      */\r
9198     /**\r
9199      * @cfg {Boolean} autoAbort (Optional) @hide\r
9200      */\r
9201 \r
9202     /**\r
9203      * @cfg {Boolean} disableCaching (Optional) @hide\r
9204      */\r
9205 \r
9206     /**\r
9207      * @property  disableCaching\r
9208      * True to add a unique cache-buster param to GET requests. (defaults to true)\r
9209      * @type Boolean\r
9210      */\r
9211     /**\r
9212      * @property  url\r
9213      * The default URL to be used for requests to the server. (defaults to undefined)\r
9214      * If the server receives all requests through one URL, setting this once is easier than\r
9215      * entering it on every request.\r
9216      * @type String\r
9217      */\r
9218     /**\r
9219      * @property  extraParams\r
9220      * An object containing properties which are used as extra parameters to each request made\r
9221      * by this object (defaults to undefined). Session information and other data that you need\r
9222      * to pass with each request are commonly put here.\r
9223      * @type Object\r
9224      */\r
9225     /**\r
9226      * @property  defaultHeaders\r
9227      * An object containing request headers which are added to each request made by this object\r
9228      * (defaults to undefined).\r
9229      * @type Object\r
9230      */\r
9231     /**\r
9232      * @property  method\r
9233      * The default HTTP method to be used for requests. Note that this is case-sensitive and\r
9234      * should be all caps (defaults to undefined; if not set but params are present will use\r
9235      * <tt>"POST"</tt>, otherwise will use <tt>"GET"</tt>.)\r
9236      * @type String\r
9237      */\r
9238     /**\r
9239      * @property  timeout\r
9240      * The timeout in milliseconds to be used for requests. (defaults to 30000)\r
9241      * @type Number\r
9242      */\r
9243 \r
9244     /**\r
9245      * @property  autoAbort\r
9246      * Whether a new request should abort any pending requests. (defaults to false)\r
9247      * @type Boolean\r
9248      */\r
9249     autoAbort : false,\r
9250 \r
9251     /**\r
9252      * Serialize the passed form into a url encoded string\r
9253      * @param {String/HTMLElement} form\r
9254      * @return {String}\r
9255      */\r
9256     serializeForm : function(form){\r
9257         return Ext.lib.Ajax.serializeForm(form);\r
9258     }\r
9259 });\r
9260 /**
9261  * @class Ext.Updater
9262  * @extends Ext.util.Observable
9263  * Provides AJAX-style update capabilities for Element objects.  Updater can be used to {@link #update}
9264  * an {@link Ext.Element} once, or you can use {@link #startAutoRefresh} to set up an auto-updating
9265  * {@link Ext.Element Element} on a specific interval.<br><br>
9266  * Usage:<br>
9267  * <pre><code>
9268  * var el = Ext.get("foo"); // Get Ext.Element object
9269  * var mgr = el.getUpdater();
9270  * mgr.update({
9271         url: "http://myserver.com/index.php",
9272         params: {
9273             param1: "foo",
9274             param2: "bar"
9275         }
9276  * });
9277  * ...
9278  * mgr.formUpdate("myFormId", "http://myserver.com/index.php");
9279  * <br>
9280  * // or directly (returns the same Updater instance)
9281  * var mgr = new Ext.Updater("myElementId");
9282  * mgr.startAutoRefresh(60, "http://myserver.com/index.php");
9283  * mgr.on("update", myFcnNeedsToKnow);
9284  * <br>
9285  * // short handed call directly from the element object
9286  * Ext.get("foo").load({
9287         url: "bar.php",
9288         scripts: true,
9289         params: "param1=foo&amp;param2=bar",
9290         text: "Loading Foo..."
9291  * });
9292  * </code></pre>
9293  * @constructor
9294  * Create new Updater directly.
9295  * @param {Mixed} el The element to update
9296  * @param {Boolean} forceNew (optional) By default the constructor checks to see if the passed element already
9297  * has an Updater and if it does it returns the same instance. This will skip that check (useful for extending this class).
9298  */
9299 Ext.UpdateManager = Ext.Updater = Ext.extend(Ext.util.Observable, 
9300 function() {
9301         var BEFOREUPDATE = "beforeupdate",
9302                 UPDATE = "update",
9303                 FAILURE = "failure";
9304                 
9305         // private
9306     function processSuccess(response){      
9307             var me = this;
9308         me.transaction = null;
9309         if (response.argument.form && response.argument.reset) {
9310             try { // put in try/catch since some older FF releases had problems with this
9311                 response.argument.form.reset();
9312             } catch(e){}
9313         }
9314         if (me.loadScripts) {
9315             me.renderer.render(me.el, response, me,
9316                updateComplete.createDelegate(me, [response]));
9317         } else {
9318             me.renderer.render(me.el, response, me);
9319             updateComplete.call(me, response);
9320         }
9321     }
9322     
9323     // private
9324     function updateComplete(response, type, success){
9325         this.fireEvent(type || UPDATE, this.el, response);
9326         if(Ext.isFunction(response.argument.callback)){
9327             response.argument.callback.call(response.argument.scope, this.el, Ext.isEmpty(success) ? true : false, response, response.argument.options);
9328         }
9329     }
9330
9331     // private
9332     function processFailure(response){              
9333         updateComplete.call(this, response, FAILURE, !!(this.transaction = null));
9334     }
9335             
9336         return {
9337             constructor: function(el, forceNew){
9338                     var me = this;
9339                 el = Ext.get(el);
9340                 if(!forceNew && el.updateManager){
9341                     return el.updateManager;
9342                 }
9343                 /**
9344                  * The Element object
9345                  * @type Ext.Element
9346                  */
9347                 me.el = el;
9348                 /**
9349                  * Cached url to use for refreshes. Overwritten every time update() is called unless "discardUrl" param is set to true.
9350                  * @type String
9351                  */
9352                 me.defaultUrl = null;
9353         
9354                 me.addEvents(
9355                     /**
9356                      * @event beforeupdate
9357                      * Fired before an update is made, return false from your handler and the update is cancelled.
9358                      * @param {Ext.Element} el
9359                      * @param {String/Object/Function} url
9360                      * @param {String/Object} params
9361                      */
9362                     BEFOREUPDATE,
9363                     /**
9364                      * @event update
9365                      * Fired after successful update is made.
9366                      * @param {Ext.Element} el
9367                      * @param {Object} oResponseObject The response Object
9368                      */
9369                     UPDATE,
9370                     /**
9371                      * @event failure
9372                      * Fired on update failure.
9373                      * @param {Ext.Element} el
9374                      * @param {Object} oResponseObject The response Object
9375                      */
9376                     FAILURE
9377                 );
9378         
9379                 Ext.apply(me, Ext.Updater.defaults);
9380                 /**
9381                  * Blank page URL to use with SSL file uploads (defaults to {@link Ext.Updater.defaults#sslBlankUrl}).
9382                  * @property sslBlankUrl
9383                  * @type String
9384                  */
9385                 /**
9386                  * Whether to append unique parameter on get request to disable caching (defaults to {@link Ext.Updater.defaults#disableCaching}).
9387                  * @property disableCaching
9388                  * @type Boolean
9389                  */
9390                 /**
9391                  * Text for loading indicator (defaults to {@link Ext.Updater.defaults#indicatorText}).
9392                  * @property indicatorText
9393                  * @type String
9394                  */
9395                 /**
9396                  * Whether to show indicatorText when loading (defaults to {@link Ext.Updater.defaults#showLoadIndicator}).
9397                  * @property showLoadIndicator
9398                  * @type String
9399                  */
9400                 /**
9401                  * Timeout for requests or form posts in seconds (defaults to {@link Ext.Updater.defaults#timeout}).
9402                  * @property timeout
9403                  * @type Number
9404                  */
9405                 /**
9406                  * True to process scripts in the output (defaults to {@link Ext.Updater.defaults#loadScripts}).
9407                  * @property loadScripts
9408                  * @type Boolean
9409                  */
9410         
9411                 /**
9412                  * Transaction object of the current executing transaction, or null if there is no active transaction.
9413                  */
9414                 me.transaction = null;
9415                 /**
9416                  * Delegate for refresh() prebound to "this", use myUpdater.refreshDelegate.createCallback(arg1, arg2) to bind arguments
9417                  * @type Function
9418                  */
9419                 me.refreshDelegate = me.refresh.createDelegate(me);
9420                 /**
9421                  * Delegate for update() prebound to "this", use myUpdater.updateDelegate.createCallback(arg1, arg2) to bind arguments
9422                  * @type Function
9423                  */
9424                 me.updateDelegate = me.update.createDelegate(me);
9425                 /**
9426                  * Delegate for formUpdate() prebound to "this", use myUpdater.formUpdateDelegate.createCallback(arg1, arg2) to bind arguments
9427                  * @type Function
9428                  */
9429                 me.formUpdateDelegate = (me.formUpdate || function(){}).createDelegate(me);     
9430                 
9431                         /**
9432                          * The renderer for this Updater (defaults to {@link Ext.Updater.BasicRenderer}).
9433                          */
9434                 me.renderer = me.renderer || me.getDefaultRenderer();
9435                 
9436                 Ext.Updater.superclass.constructor.call(me);
9437             },
9438         
9439                 /**
9440              * Sets the content renderer for this Updater. See {@link Ext.Updater.BasicRenderer#render} for more details.
9441              * @param {Object} renderer The object implementing the render() method
9442              */
9443             setRenderer : function(renderer){
9444                 this.renderer = renderer;
9445             },  
9446         
9447             /**
9448              * Returns the current content renderer for this Updater. See {@link Ext.Updater.BasicRenderer#render} for more details.
9449              * @return {Object}
9450              */
9451             getRenderer : function(){
9452                return this.renderer;
9453             },
9454
9455             /**
9456              * This is an overrideable method which returns a reference to a default
9457              * renderer class if none is specified when creating the Ext.Updater.
9458              * Defaults to {@link Ext.Updater.BasicRenderer}
9459              */
9460             getDefaultRenderer: function() {
9461                 return new Ext.Updater.BasicRenderer();
9462             },
9463                 
9464             /**
9465              * Sets the default URL used for updates.
9466              * @param {String/Function} defaultUrl The url or a function to call to get the url
9467              */
9468             setDefaultUrl : function(defaultUrl){
9469                 this.defaultUrl = defaultUrl;
9470             },
9471         
9472             /**
9473              * Get the Element this Updater is bound to
9474              * @return {Ext.Element} The element
9475              */
9476             getEl : function(){
9477                 return this.el;
9478             },
9479         
9480                 /**
9481              * Performs an <b>asynchronous</b> request, updating this element with the response.
9482              * If params are specified it uses POST, otherwise it uses GET.<br><br>
9483              * <b>Note:</b> Due to the asynchronous nature of remote server requests, the Element
9484              * will not have been fully updated when the function returns. To post-process the returned
9485              * data, use the callback option, or an <b><tt>update</tt></b> event handler.
9486              * @param {Object} options A config object containing any of the following options:<ul>
9487              * <li>url : <b>String/Function</b><p class="sub-desc">The URL to request or a function which
9488              * <i>returns</i> the URL (defaults to the value of {@link Ext.Ajax#url} if not specified).</p></li>
9489              * <li>method : <b>String</b><p class="sub-desc">The HTTP method to
9490              * use. Defaults to POST if the <tt>params</tt> argument is present, otherwise GET.</p></li>
9491              * <li>params : <b>String/Object/Function</b><p class="sub-desc">The
9492              * parameters to pass to the server (defaults to none). These may be specified as a url-encoded
9493              * string, or as an object containing properties which represent parameters,
9494              * or as a function, which returns such an object.</p></li>
9495              * <li>scripts : <b>Boolean</b><p class="sub-desc">If <tt>true</tt>
9496              * any &lt;script&gt; tags embedded in the response text will be extracted
9497              * and executed (defaults to {@link Ext.Updater.defaults#loadScripts}). If this option is specified,
9498              * the callback will be called <i>after</i> the execution of the scripts.</p></li>
9499              * <li>callback : <b>Function</b><p class="sub-desc">A function to
9500              * be called when the response from the server arrives. The following
9501              * parameters are passed:<ul>
9502              * <li><b>el</b> : Ext.Element<p class="sub-desc">The Element being updated.</p></li>
9503              * <li><b>success</b> : Boolean<p class="sub-desc">True for success, false for failure.</p></li>
9504              * <li><b>response</b> : XMLHttpRequest<p class="sub-desc">The XMLHttpRequest which processed the update.</p></li>
9505              * <li><b>options</b> : Object<p class="sub-desc">The config object passed to the update call.</p></li></ul>
9506              * </p></li>
9507              * <li>scope : <b>Object</b><p class="sub-desc">The scope in which
9508              * to execute the callback (The callback's <tt>this</tt> reference.) If the
9509              * <tt>params</tt> argument is a function, this scope is used for that function also.</p></li>
9510              * <li>discardUrl : <b>Boolean</b><p class="sub-desc">By default, the URL of this request becomes
9511              * the default URL for this Updater object, and will be subsequently used in {@link #refresh}
9512              * calls.  To bypass this behavior, pass <tt>discardUrl:true</tt> (defaults to false).</p></li>
9513              * <li>timeout : <b>Number</b><p class="sub-desc">The number of seconds to wait for a response before
9514              * timing out (defaults to {@link Ext.Updater.defaults#timeout}).</p></li>
9515              * <li>text : <b>String</b><p class="sub-desc">The text to use as the innerHTML of the
9516              * {@link Ext.Updater.defaults#indicatorText} div (defaults to 'Loading...').  To replace the entire div, not
9517              * just the text, override {@link Ext.Updater.defaults#indicatorText} directly.</p></li>
9518              * <li>nocache : <b>Boolean</b><p class="sub-desc">Only needed for GET
9519              * requests, this option causes an extra, auto-generated parameter to be appended to the request
9520              * to defeat caching (defaults to {@link Ext.Updater.defaults#disableCaching}).</p></li></ul>
9521              * <p>
9522              * For example:
9523         <pre><code>
9524         um.update({
9525             url: "your-url.php",
9526             params: {param1: "foo", param2: "bar"}, // or a URL encoded string
9527             callback: yourFunction,
9528             scope: yourObject, //(optional scope)
9529             discardUrl: true,
9530             nocache: true,
9531             text: "Loading...",
9532             timeout: 60,
9533             scripts: false // Save time by avoiding RegExp execution.
9534         });
9535         </code></pre>
9536              */
9537             update : function(url, params, callback, discardUrl){
9538                     var me = this,
9539                         cfg, 
9540                         callerScope;
9541                         
9542                 if(me.fireEvent(BEFOREUPDATE, me.el, url, params) !== false){               
9543                     if(Ext.isObject(url)){ // must be config object
9544                         cfg = url;
9545                         url = cfg.url;
9546                         params = params || cfg.params;
9547                         callback = callback || cfg.callback;
9548                         discardUrl = discardUrl || cfg.discardUrl;
9549                         callerScope = cfg.scope;                        
9550                         if(!Ext.isEmpty(cfg.nocache)){me.disableCaching = cfg.nocache;};
9551                         if(!Ext.isEmpty(cfg.text)){me.indicatorText = '<div class="loading-indicator">'+cfg.text+"</div>";};
9552                         if(!Ext.isEmpty(cfg.scripts)){me.loadScripts = cfg.scripts;};
9553                         if(!Ext.isEmpty(cfg.timeout)){me.timeout = cfg.timeout;};
9554                     }
9555                     me.showLoading();
9556         
9557                     if(!discardUrl){
9558                         me.defaultUrl = url;
9559                     }
9560                     if(Ext.isFunction(url)){
9561                         url = url.call(me);
9562                     }
9563         
9564                     var o = Ext.apply({}, {
9565                         url : url,
9566                         params: (Ext.isFunction(params) && callerScope) ? params.createDelegate(callerScope) : params,
9567                         success: processSuccess,
9568                         failure: processFailure,
9569                         scope: me,
9570                         callback: undefined,
9571                         timeout: (me.timeout*1000),
9572                         disableCaching: me.disableCaching,
9573                         argument: {
9574                             "options": cfg,
9575                             "url": url,
9576                             "form": null,
9577                             "callback": callback,
9578                             "scope": callerScope || window,
9579                             "params": params
9580                         }
9581                     }, cfg);
9582         
9583                     me.transaction = Ext.Ajax.request(o);
9584                 }
9585             },          
9586
9587                 /**
9588              * <p>Performs an async form post, updating this element with the response. If the form has the attribute
9589              * enctype="<a href="http://www.faqs.org/rfcs/rfc2388.html">multipart/form-data</a>", it assumes it's a file upload.
9590              * Uses this.sslBlankUrl for SSL file uploads to prevent IE security warning.</p>
9591              * <p>File uploads are not performed using normal "Ajax" techniques, that is they are <b>not</b>
9592              * performed using XMLHttpRequests. Instead the form is submitted in the standard manner with the
9593              * DOM <tt>&lt;form></tt> element temporarily modified to have its
9594              * <a href="http://www.w3.org/TR/REC-html40/present/frames.html#adef-target">target</a> set to refer
9595              * to a dynamically generated, hidden <tt>&lt;iframe></tt> which is inserted into the document
9596              * but removed after the return data has been gathered.</p>
9597              * <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>
9598              * and some server technologies (notably JEE) may require some custom processing in order to
9599              * retrieve parameter names and parameter values from the packet content.</p>
9600              * @param {String/HTMLElement} form The form Id or form element
9601              * @param {String} url (optional) The url to pass the form to. If omitted the action attribute on the form will be used.
9602              * @param {Boolean} reset (optional) Whether to try to reset the form after the update
9603              * @param {Function} callback (optional) Callback when transaction is complete. The following
9604              * parameters are passed:<ul>
9605              * <li><b>el</b> : Ext.Element<p class="sub-desc">The Element being updated.</p></li>
9606              * <li><b>success</b> : Boolean<p class="sub-desc">True for success, false for failure.</p></li>
9607              * <li><b>response</b> : XMLHttpRequest<p class="sub-desc">The XMLHttpRequest which processed the update.</p></li></ul>
9608              */
9609             formUpdate : function(form, url, reset, callback){
9610                     var me = this;
9611                 if(me.fireEvent(BEFOREUPDATE, me.el, form, url) !== false){
9612                     if(Ext.isFunction(url)){
9613                         url = url.call(me);
9614                     }
9615                     form = Ext.getDom(form)
9616                     me.transaction = Ext.Ajax.request({
9617                         form: form,
9618                         url:url,
9619                         success: processSuccess,
9620                         failure: processFailure,
9621                         scope: me,
9622                         timeout: (me.timeout*1000),
9623                         argument: {
9624                             "url": url,
9625                             "form": form,
9626                             "callback": callback,
9627                             "reset": reset
9628                         }
9629                     });
9630                     me.showLoading.defer(1, me);
9631                 }
9632             },
9633                         
9634             /**
9635              * Set this element to auto refresh.  Can be canceled by calling {@link #stopAutoRefresh}.
9636              * @param {Number} interval How often to update (in seconds).
9637              * @param {String/Object/Function} url (optional) The url for this request, a config object in the same format
9638              * supported by {@link #load}, or a function to call to get the url (defaults to the last used url).  Note that while
9639              * the url used in a load call can be reused by this method, other load config options will not be reused and must be
9640              * sepcified as part of a config object passed as this paramter if needed.
9641              * @param {String/Object} params (optional) The parameters to pass as either a url encoded string
9642              * "&param1=1&param2=2" or as an object {param1: 1, param2: 2}
9643              * @param {Function} callback (optional) Callback when transaction is complete - called with signature (oElement, bSuccess)
9644              * @param {Boolean} refreshNow (optional) Whether to execute the refresh now, or wait the interval
9645              */
9646             startAutoRefresh : function(interval, url, params, callback, refreshNow){
9647                     var me = this;
9648                 if(refreshNow){
9649                     me.update(url || me.defaultUrl, params, callback, true);
9650                 }
9651                 if(me.autoRefreshProcId){
9652                     clearInterval(me.autoRefreshProcId);
9653                 }
9654                 me.autoRefreshProcId = setInterval(me.update.createDelegate(me, [url || me.defaultUrl, params, callback, true]), interval * 1000);
9655             },
9656         
9657             /**
9658              * Stop auto refresh on this element.
9659              */
9660             stopAutoRefresh : function(){
9661                 if(this.autoRefreshProcId){
9662                     clearInterval(this.autoRefreshProcId);
9663                     delete this.autoRefreshProcId;
9664                 }
9665             },
9666         
9667             /**
9668              * Returns true if the Updater is currently set to auto refresh its content (see {@link #startAutoRefresh}), otherwise false.
9669              */
9670             isAutoRefreshing : function(){
9671                return !!this.autoRefreshProcId;
9672             },
9673         
9674             /**
9675              * Display the element's "loading" state. By default, the element is updated with {@link #indicatorText}. This
9676              * method may be overridden to perform a custom action while this Updater is actively updating its contents.
9677              */
9678             showLoading : function(){
9679                 if(this.showLoadIndicator){
9680                 this.el.dom.innerHTML = this.indicatorText;
9681                 }
9682             },
9683         
9684             /**
9685              * Aborts the currently executing transaction, if any.
9686              */
9687             abort : function(){
9688                 if(this.transaction){
9689                     Ext.Ajax.abort(this.transaction);
9690                 }
9691             },
9692         
9693             /**
9694              * Returns true if an update is in progress, otherwise false.
9695              * @return {Boolean}
9696              */
9697             isUpdating : function(){        
9698                 return this.transaction ? Ext.Ajax.isLoading(this.transaction) : false;        
9699             },
9700             
9701             /**
9702              * Refresh the element with the last used url or defaultUrl. If there is no url, it returns immediately
9703              * @param {Function} callback (optional) Callback when transaction is complete - called with signature (oElement, bSuccess)
9704              */
9705             refresh : function(callback){
9706                 if(this.defaultUrl){
9707                         this.update(this.defaultUrl, null, callback, true);
9708                 }
9709             }
9710     }
9711 }());
9712
9713 /**
9714  * @class Ext.Updater.defaults
9715  * The defaults collection enables customizing the default properties of Updater
9716  */
9717 Ext.Updater.defaults = {
9718    /**
9719      * Timeout for requests or form posts in seconds (defaults to 30 seconds).
9720      * @type Number
9721      */
9722     timeout : 30,    
9723     /**
9724      * True to append a unique parameter to GET requests to disable caching (defaults to false).
9725      * @type Boolean
9726      */
9727     disableCaching : false,
9728     /**
9729      * Whether or not to show {@link #indicatorText} during loading (defaults to true).
9730      * @type Boolean
9731      */
9732     showLoadIndicator : true,
9733     /**
9734      * Text for loading indicator (defaults to '&lt;div class="loading-indicator"&gt;Loading...&lt;/div&gt;').
9735      * @type String
9736      */
9737     indicatorText : '<div class="loading-indicator">Loading...</div>',
9738      /**
9739      * True to process scripts by default (defaults to false).
9740      * @type Boolean
9741      */
9742     loadScripts : false,
9743     /**
9744     * Blank page URL to use with SSL file uploads (defaults to {@link Ext#SSL_SECURE_URL} if set, or "javascript:false").
9745     * @type String
9746     */
9747     sslBlankUrl : Ext.SSL_SECURE_URL      
9748 };
9749
9750
9751 /**
9752  * Static convenience method. <b>This method is deprecated in favor of el.load({url:'foo.php', ...})</b>.
9753  * Usage:
9754  * <pre><code>Ext.Updater.updateElement("my-div", "stuff.php");</code></pre>
9755  * @param {Mixed} el The element to update
9756  * @param {String} url The url
9757  * @param {String/Object} params (optional) Url encoded param string or an object of name/value pairs
9758  * @param {Object} options (optional) A config object with any of the Updater properties you want to set - for
9759  * example: {disableCaching:true, indicatorText: "Loading data..."}
9760  * @static
9761  * @deprecated
9762  * @member Ext.Updater
9763  */
9764 Ext.Updater.updateElement = function(el, url, params, options){
9765     var um = Ext.get(el).getUpdater();
9766     Ext.apply(um, options);
9767     um.update(url, params, options ? options.callback : null);
9768 };
9769
9770 /**
9771  * @class Ext.Updater.BasicRenderer
9772  * Default Content renderer. Updates the elements innerHTML with the responseText.
9773  */
9774 Ext.Updater.BasicRenderer = function(){};
9775
9776 Ext.Updater.BasicRenderer.prototype = {
9777     /**
9778      * This is called when the transaction is completed and it's time to update the element - The BasicRenderer
9779      * updates the elements innerHTML with the responseText - To perform a custom render (i.e. XML or JSON processing),
9780      * create an object with a "render(el, response)" method and pass it to setRenderer on the Updater.
9781      * @param {Ext.Element} el The element being rendered
9782      * @param {Object} response The XMLHttpRequest object
9783      * @param {Updater} updateManager The calling update manager
9784      * @param {Function} callback A callback that will need to be called if loadScripts is true on the Updater
9785      */
9786      render : function(el, response, updateManager, callback){       
9787         el.update(response.responseText, updateManager.loadScripts, callback);
9788     }
9789 };/**
9790  * @class Date
9791  *
9792  * The date parsing and formatting syntax contains a subset of
9793  * <a href="http://www.php.net/date">PHP's date() function</a>, and the formats that are
9794  * supported will provide results equivalent to their PHP versions.
9795  *
9796  * The following is a list of all currently supported formats:
9797  * <pre>
9798 Format  Description                                                               Example returned values
9799 ------  -----------------------------------------------------------------------   -----------------------
9800   d     Day of the month, 2 digits with leading zeros                             01 to 31
9801   D     A short textual representation of the day of the week                     Mon to Sun
9802   j     Day of the month without leading zeros                                    1 to 31
9803   l     A full textual representation of the day of the week                      Sunday to Saturday
9804   N     ISO-8601 numeric representation of the day of the week                    1 (for Monday) through 7 (for Sunday)
9805   S     English ordinal suffix for the day of the month, 2 characters             st, nd, rd or th. Works well with j
9806   w     Numeric representation of the day of the week                             0 (for Sunday) to 6 (for Saturday)
9807   z     The day of the year (starting from 0)                                     0 to 364 (365 in leap years)
9808   W     ISO-8601 week number of year, weeks starting on Monday                    01 to 53
9809   F     A full textual representation of a month, such as January or March        January to December
9810   m     Numeric representation of a month, with leading zeros                     01 to 12
9811   M     A short textual representation of a month                                 Jan to Dec
9812   n     Numeric representation of a month, without leading zeros                  1 to 12
9813   t     Number of days in the given month                                         28 to 31
9814   L     Whether it's a leap year                                                  1 if it is a leap year, 0 otherwise.
9815   o     ISO-8601 year number (identical to (Y), but if the ISO week number (W)    Examples: 1998 or 2004
9816         belongs to the previous or next year, that year is used instead)
9817   Y     A full numeric representation of a year, 4 digits                         Examples: 1999 or 2003
9818   y     A two digit representation of a year                                      Examples: 99 or 03
9819   a     Lowercase Ante meridiem and Post meridiem                                 am or pm
9820   A     Uppercase Ante meridiem and Post meridiem                                 AM or PM
9821   g     12-hour format of an hour without leading zeros                           1 to 12
9822   G     24-hour format of an hour without leading zeros                           0 to 23
9823   h     12-hour format of an hour with leading zeros                              01 to 12
9824   H     24-hour format of an hour with leading zeros                              00 to 23
9825   i     Minutes, with leading zeros                                               00 to 59
9826   s     Seconds, with leading zeros                                               00 to 59
9827   u     Decimal fraction of a second                                              Examples:
9828         (minimum 1 digit, arbitrary number of digits allowed)                     001 (i.e. 0.001s) or
9829                                                                                   100 (i.e. 0.100s) or
9830                                                                                   999 (i.e. 0.999s) or
9831                                                                                   999876543210 (i.e. 0.999876543210s)
9832   O     Difference to Greenwich time (GMT) in hours and minutes                   Example: +1030
9833   P     Difference to Greenwich time (GMT) with colon between hours and minutes   Example: -08:00
9834   T     Timezone abbreviation of the machine running the code                     Examples: EST, MDT, PDT ...
9835   Z     Timezone offset in seconds (negative if west of UTC, positive if east)    -43200 to 50400
9836   c     ISO 8601 date
9837         Notes:                                                                    Examples:
9838         1) If unspecified, the month / day defaults to the current month / day,   1991 or
9839            the time defaults to midnight, while the timezone defaults to the      1992-10 or
9840            browser's timezone. If a time is specified, it must include both hours 1993-09-20 or
9841            and minutes. The "T" delimiter, seconds, milliseconds and timezone     1994-08-19T16:20+01:00 or
9842            are optional.                                                          1995-07-18T17:21:28-02:00 or
9843         2) The decimal fraction of a second, if specified, must contain at        1996-06-17T18:22:29.98765+03:00 or
9844            least 1 digit (there is no limit to the maximum number                 1997-05-16T19:23:30,12345-0400 or
9845            of digits allowed), and may be delimited by either a '.' or a ','      1998-04-15T20:24:31.2468Z or
9846         Refer to the examples on the right for the various levels of              1999-03-14T20:24:32Z or
9847         date-time granularity which are supported, or see                         2000-02-13T21:25:33
9848         http://www.w3.org/TR/NOTE-datetime for more info.                         2001-01-12 22:26:34
9849   U     Seconds since the Unix Epoch (January 1 1970 00:00:00 GMT)                1193432466 or -2138434463
9850   M$    Microsoft AJAX serialized dates                                           \/Date(1238606590509)\/ (i.e. UTC milliseconds since epoch) or
9851                                                                                   \/Date(1238606590509+0800)\/
9852 </pre>
9853  *
9854  * Example usage (note that you must escape format specifiers with '\\' to render them as character literals):
9855  * <pre><code>
9856 // Sample date:
9857 // 'Wed Jan 10 2007 15:05:01 GMT-0600 (Central Standard Time)'
9858
9859 var dt = new Date('1/10/2007 03:05:01 PM GMT-0600');
9860 document.write(dt.format('Y-m-d'));                           // 2007-01-10
9861 document.write(dt.format('F j, Y, g:i a'));                   // January 10, 2007, 3:05 pm
9862 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
9863 </code></pre>
9864  *
9865  * Here are some standard date/time patterns that you might find helpful.  They
9866  * are not part of the source of Date.js, but to use them you can simply copy this
9867  * block of code into any script that is included after Date.js and they will also become
9868  * globally available on the Date object.  Feel free to add or remove patterns as needed in your code.
9869  * <pre><code>
9870 Date.patterns = {
9871     ISO8601Long:"Y-m-d H:i:s",
9872     ISO8601Short:"Y-m-d",
9873     ShortDate: "n/j/Y",
9874     LongDate: "l, F d, Y",
9875     FullDateTime: "l, F d, Y g:i:s A",
9876     MonthDay: "F d",
9877     ShortTime: "g:i A",
9878     LongTime: "g:i:s A",
9879     SortableDateTime: "Y-m-d\\TH:i:s",
9880     UniversalSortableDateTime: "Y-m-d H:i:sO",
9881     YearMonth: "F, Y"
9882 };
9883 </code></pre>
9884  *
9885  * Example usage:
9886  * <pre><code>
9887 var dt = new Date();
9888 document.write(dt.format(Date.patterns.ShortDate));
9889 </code></pre>
9890  * <p>Developer-written, custom formats may be used by supplying both a formatting and a parsing function
9891  * which perform to specialized requirements. The functions are stored in {@link #parseFunctions} and {@link #formatFunctions}.</p>
9892  */
9893
9894 /*
9895  * Most of the date-formatting functions below are the excellent work of Baron Schwartz.
9896  * (see http://www.xaprb.com/blog/2005/12/12/javascript-closures-for-runtime-efficiency/)
9897  * They generate precompiled functions from format patterns instead of parsing and
9898  * processing each pattern every time a date is formatted. These functions are available
9899  * on every Date object.
9900  */
9901
9902 (function() {
9903
9904 /**
9905  * Global flag which determines if strict date parsing should be used.
9906  * Strict date parsing will not roll-over invalid dates, which is the
9907  * default behaviour of javascript Date objects.
9908  * (see {@link #parseDate} for more information)
9909  * Defaults to <tt>false</tt>.
9910  * @static
9911  * @type Boolean
9912 */
9913 Date.useStrict = false;
9914
9915
9916 // create private copy of Ext's String.format() method
9917 // - to remove unnecessary dependency
9918 // - to resolve namespace conflict with M$-Ajax's implementation
9919 function xf(format) {
9920     var args = Array.prototype.slice.call(arguments, 1);
9921     return format.replace(/\{(\d+)\}/g, function(m, i) {
9922         return args[i];
9923     });
9924 }
9925
9926
9927 // private
9928 Date.formatCodeToRegex = function(character, currentGroup) {
9929     // Note: currentGroup - position in regex result array (see notes for Date.parseCodes below)
9930     var p = Date.parseCodes[character];
9931
9932     if (p) {
9933       p = typeof p == 'function'? p() : p;
9934       Date.parseCodes[character] = p; // reassign function result to prevent repeated execution
9935     }
9936
9937     return p? Ext.applyIf({
9938       c: p.c? xf(p.c, currentGroup || "{0}") : p.c
9939     }, p) : {
9940         g:0,
9941         c:null,
9942         s:Ext.escapeRe(character) // treat unrecognised characters as literals
9943     }
9944 }
9945
9946 // private shorthand for Date.formatCodeToRegex since we'll be using it fairly often
9947 var $f = Date.formatCodeToRegex;
9948
9949 Ext.apply(Date, {
9950     /**
9951      * <p>An object hash in which each property is a date parsing function. The property name is the
9952      * format string which that function parses.</p>
9953      * <p>This object is automatically populated with date parsing functions as
9954      * date formats are requested for Ext standard formatting strings.</p>
9955      * <p>Custom parsing functions may be inserted into this object, keyed by a name which from then on
9956      * may be used as a format string to {@link #parseDate}.<p>
9957      * <p>Example:</p><pre><code>
9958 Date.parseFunctions['x-date-format'] = myDateParser;
9959 </code></pre>
9960      * <p>A parsing function should return a Date object, and is passed the following parameters:<div class="mdetail-params"><ul>
9961      * <li><code>date</code> : String<div class="sub-desc">The date string to parse.</div></li>
9962      * <li><code>strict</code> : Boolean<div class="sub-desc">True to validate date strings while parsing
9963      * (i.e. prevent javascript Date "rollover") (The default must be false).
9964      * Invalid date strings should return null when parsed.</div></li>
9965      * </ul></div></p>
9966      * <p>To enable Dates to also be <i>formatted</i> according to that format, a corresponding
9967      * formatting function must be placed into the {@link #formatFunctions} property.
9968      * @property parseFunctions
9969      * @static
9970      * @type Object
9971      */
9972     parseFunctions: {
9973         "M$": function(input, strict) {
9974             // note: the timezone offset is ignored since the M$ Ajax server sends
9975             // a UTC milliseconds-since-Unix-epoch value (negative values are allowed)
9976             var re = new RegExp('\\/Date\\(([-+])?(\\d+)(?:[+-]\\d{4})?\\)\\/');
9977             var r = (input || '').match(re);
9978             return r? new Date(((r[1] || '') + r[2]) * 1) : null;
9979         }
9980     },
9981     parseRegexes: [],
9982
9983     /**
9984      * <p>An object hash in which each property is a date formatting function. The property name is the
9985      * format string which corresponds to the produced formatted date string.</p>
9986      * <p>This object is automatically populated with date formatting functions as
9987      * date formats are requested for Ext standard formatting strings.</p>
9988      * <p>Custom formatting functions may be inserted into this object, keyed by a name which from then on
9989      * may be used as a format string to {@link #format}. Example:</p><pre><code>
9990 Date.formatFunctions['x-date-format'] = myDateFormatter;
9991 </code></pre>
9992      * <p>A formatting function should return a string repesentation of the passed Date object:<div class="mdetail-params"><ul>
9993      * <li><code>date</code> : Date<div class="sub-desc">The Date to format.</div></li>
9994      * </ul></div></p>
9995      * <p>To enable date strings to also be <i>parsed</i> according to that format, a corresponding
9996      * parsing function must be placed into the {@link #parseFunctions} property.
9997      * @property formatFunctions
9998      * @static
9999      * @type Object
10000      */
10001     formatFunctions: {
10002         "M$": function() {
10003             // UTC milliseconds since Unix epoch (M$-AJAX serialized date format (MRSF))
10004             return '\\/Date(' + this.getTime() + ')\\/';
10005         }
10006     },
10007
10008     y2kYear : 50,
10009
10010     /**
10011      * Date interval constant
10012      * @static
10013      * @type String
10014      */
10015     MILLI : "ms",
10016
10017     /**
10018      * Date interval constant
10019      * @static
10020      * @type String
10021      */
10022     SECOND : "s",
10023
10024     /**
10025      * Date interval constant
10026      * @static
10027      * @type String
10028      */
10029     MINUTE : "mi",
10030
10031     /** Date interval constant
10032      * @static
10033      * @type String
10034      */
10035     HOUR : "h",
10036
10037     /**
10038      * Date interval constant
10039      * @static
10040      * @type String
10041      */
10042     DAY : "d",
10043
10044     /**
10045      * Date interval constant
10046      * @static
10047      * @type String
10048      */
10049     MONTH : "mo",
10050
10051     /**
10052      * Date interval constant
10053      * @static
10054      * @type String
10055      */
10056     YEAR : "y",
10057
10058     /**
10059      * <p>An object hash containing default date values used during date parsing.</p>
10060      * <p>The following properties are available:<div class="mdetail-params"><ul>
10061      * <li><code>y</code> : Number<div class="sub-desc">The default year value. (defaults to undefined)</div></li>
10062      * <li><code>m</code> : Number<div class="sub-desc">The default 1-based month value. (defaults to undefined)</div></li>
10063      * <li><code>d</code> : Number<div class="sub-desc">The default day value. (defaults to undefined)</div></li>
10064      * <li><code>h</code> : Number<div class="sub-desc">The default hour value. (defaults to undefined)</div></li>
10065      * <li><code>i</code> : Number<div class="sub-desc">The default minute value. (defaults to undefined)</div></li>
10066      * <li><code>s</code> : Number<div class="sub-desc">The default second value. (defaults to undefined)</div></li>
10067      * <li><code>ms</code> : Number<div class="sub-desc">The default millisecond value. (defaults to undefined)</div></li>
10068      * </ul></div></p>
10069      * <p>Override these properties to customize the default date values used by the {@link #parseDate} method.</p>
10070      * <p><b>Note: In countries which experience Daylight Saving Time (i.e. DST), the <tt>h</tt>, <tt>i</tt>, <tt>s</tt>
10071      * and <tt>ms</tt> properties may coincide with the exact time in which DST takes effect.
10072      * It is the responsiblity of the developer to account for this.</b></p>
10073      * Example Usage:
10074      * <pre><code>
10075 // set default day value to the first day of the month
10076 Date.defaults.d = 1;
10077
10078 // parse a February date string containing only year and month values.
10079 // setting the default day value to 1 prevents weird date rollover issues
10080 // when attempting to parse the following date string on, for example, March 31st 2009.
10081 Date.parseDate('2009-02', 'Y-m'); // returns a Date object representing February 1st 2009
10082 </code></pre>
10083      * @property defaults
10084      * @static
10085      * @type Object
10086      */
10087     defaults: {},
10088
10089     /**
10090      * An array of textual day names.
10091      * Override these values for international dates.
10092      * Example:
10093      * <pre><code>
10094 Date.dayNames = [
10095     'SundayInYourLang',
10096     'MondayInYourLang',
10097     ...
10098 ];
10099 </code></pre>
10100      * @type Array
10101      * @static
10102      */
10103     dayNames : [
10104         "Sunday",
10105         "Monday",
10106         "Tuesday",
10107         "Wednesday",
10108         "Thursday",
10109         "Friday",
10110         "Saturday"
10111     ],
10112
10113     /**
10114      * An array of textual month names.
10115      * Override these values for international dates.
10116      * Example:
10117      * <pre><code>
10118 Date.monthNames = [
10119     'JanInYourLang',
10120     'FebInYourLang',
10121     ...
10122 ];
10123 </code></pre>
10124      * @type Array
10125      * @static
10126      */
10127     monthNames : [
10128         "January",
10129         "February",
10130         "March",
10131         "April",
10132         "May",
10133         "June",
10134         "July",
10135         "August",
10136         "September",
10137         "October",
10138         "November",
10139         "December"
10140     ],
10141
10142     /**
10143      * An object hash of zero-based javascript month numbers (with short month names as keys. note: keys are case-sensitive).
10144      * Override these values for international dates.
10145      * Example:
10146      * <pre><code>
10147 Date.monthNumbers = {
10148     'ShortJanNameInYourLang':0,
10149     'ShortFebNameInYourLang':1,
10150     ...
10151 };
10152 </code></pre>
10153      * @type Object
10154      * @static
10155      */
10156     monthNumbers : {
10157         Jan:0,
10158         Feb:1,
10159         Mar:2,
10160         Apr:3,
10161         May:4,
10162         Jun:5,
10163         Jul:6,
10164         Aug:7,
10165         Sep:8,
10166         Oct:9,
10167         Nov:10,
10168         Dec:11
10169     },
10170
10171     /**
10172      * Get the short month name for the given month number.
10173      * Override this function for international dates.
10174      * @param {Number} month A zero-based javascript month number.
10175      * @return {String} The short month name.
10176      * @static
10177      */
10178     getShortMonthName : function(month) {
10179         return Date.monthNames[month].substring(0, 3);
10180     },
10181
10182     /**
10183      * Get the short day name for the given day number.
10184      * Override this function for international dates.
10185      * @param {Number} day A zero-based javascript day number.
10186      * @return {String} The short day name.
10187      * @static
10188      */
10189     getShortDayName : function(day) {
10190         return Date.dayNames[day].substring(0, 3);
10191     },
10192
10193     /**
10194      * Get the zero-based javascript month number for the given short/full month name.
10195      * Override this function for international dates.
10196      * @param {String} name The short/full month name.
10197      * @return {Number} The zero-based javascript month number.
10198      * @static
10199      */
10200     getMonthNumber : function(name) {
10201         // handle camel casing for english month names (since the keys for the Date.monthNumbers hash are case sensitive)
10202         return Date.monthNumbers[name.substring(0, 1).toUpperCase() + name.substring(1, 3).toLowerCase()];
10203     },
10204
10205     /**
10206      * The base format-code to formatting-function hashmap used by the {@link #format} method.
10207      * Formatting functions are strings (or functions which return strings) which
10208      * will return the appropriate value when evaluated in the context of the Date object
10209      * from which the {@link #format} method is called.
10210      * Add to / override these mappings for custom date formatting.
10211      * Note: Date.format() treats characters as literals if an appropriate mapping cannot be found.
10212      * Example:
10213      * <pre><code>
10214 Date.formatCodes.x = "String.leftPad(this.getDate(), 2, '0')";
10215 (new Date()).format("X"); // returns the current day of the month
10216 </code></pre>
10217      * @type Object
10218      * @static
10219      */
10220     formatCodes : {
10221         d: "String.leftPad(this.getDate(), 2, '0')",
10222         D: "Date.getShortDayName(this.getDay())", // get localised short day name
10223         j: "this.getDate()",
10224         l: "Date.dayNames[this.getDay()]",
10225         N: "(this.getDay() ? this.getDay() : 7)",
10226         S: "this.getSuffix()",
10227         w: "this.getDay()",
10228         z: "this.getDayOfYear()",
10229         W: "String.leftPad(this.getWeekOfYear(), 2, '0')",
10230         F: "Date.monthNames[this.getMonth()]",
10231         m: "String.leftPad(this.getMonth() + 1, 2, '0')",
10232         M: "Date.getShortMonthName(this.getMonth())", // get localised short month name
10233         n: "(this.getMonth() + 1)",
10234         t: "this.getDaysInMonth()",
10235         L: "(this.isLeapYear() ? 1 : 0)",
10236         o: "(this.getFullYear() + (this.getWeekOfYear() == 1 && this.getMonth() > 0 ? +1 : (this.getWeekOfYear() >= 52 && this.getMonth() < 11 ? -1 : 0)))",
10237         Y: "this.getFullYear()",
10238         y: "('' + this.getFullYear()).substring(2, 4)",
10239         a: "(this.getHours() < 12 ? 'am' : 'pm')",
10240         A: "(this.getHours() < 12 ? 'AM' : 'PM')",
10241         g: "((this.getHours() % 12) ? this.getHours() % 12 : 12)",
10242         G: "this.getHours()",
10243         h: "String.leftPad((this.getHours() % 12) ? this.getHours() % 12 : 12, 2, '0')",
10244         H: "String.leftPad(this.getHours(), 2, '0')",
10245         i: "String.leftPad(this.getMinutes(), 2, '0')",
10246         s: "String.leftPad(this.getSeconds(), 2, '0')",
10247         u: "String.leftPad(this.getMilliseconds(), 3, '0')",
10248         O: "this.getGMTOffset()",
10249         P: "this.getGMTOffset(true)",
10250         T: "this.getTimezone()",
10251         Z: "(this.getTimezoneOffset() * -60)",
10252
10253         c: function() { // ISO-8601 -- GMT format
10254             for (var c = "Y-m-dTH:i:sP", code = [], i = 0, l = c.length; i < l; ++i) {
10255                 var e = c.charAt(i);
10256                 code.push(e == "T" ? "'T'" : Date.getFormatCode(e)); // treat T as a character literal
10257             }
10258             return code.join(" + ");
10259         },
10260         /*
10261         c: function() { // ISO-8601 -- UTC format
10262             return [
10263               "this.getUTCFullYear()", "'-'",
10264               "String.leftPad(this.getUTCMonth() + 1, 2, '0')", "'-'",
10265               "String.leftPad(this.getUTCDate(), 2, '0')",
10266               "'T'",
10267               "String.leftPad(this.getUTCHours(), 2, '0')", "':'",
10268               "String.leftPad(this.getUTCMinutes(), 2, '0')", "':'",
10269               "String.leftPad(this.getUTCSeconds(), 2, '0')",
10270               "'Z'"
10271             ].join(" + ");
10272         },
10273         */
10274
10275         U: "Math.round(this.getTime() / 1000)"
10276     },
10277
10278     /**
10279      * Checks if the passed Date parameters will cause a javascript Date "rollover".
10280      * @param {Number} year 4-digit year
10281      * @param {Number} month 1-based month-of-year
10282      * @param {Number} day Day of month
10283      * @param {Number} hour (optional) Hour
10284      * @param {Number} minute (optional) Minute
10285      * @param {Number} second (optional) Second
10286      * @param {Number} millisecond (optional) Millisecond
10287      * @return {Boolean} true if the passed parameters do not cause a Date "rollover", false otherwise.
10288      * @static
10289      */
10290     isValid : function(y, m, d, h, i, s, ms) {
10291         // setup defaults
10292         h = h || 0;
10293         i = i || 0;
10294         s = s || 0;
10295         ms = ms || 0;
10296
10297         var dt = new Date(y, m - 1, d, h, i, s, ms);
10298
10299         return y == dt.getFullYear() &&
10300             m == dt.getMonth() + 1 &&
10301             d == dt.getDate() &&
10302             h == dt.getHours() &&
10303             i == dt.getMinutes() &&
10304             s == dt.getSeconds() &&
10305             ms == dt.getMilliseconds();
10306     },
10307
10308     /**
10309      * Parses the passed string using the specified date format.
10310      * Note that this function expects normal calendar dates, meaning that months are 1-based (i.e. 1 = January).
10311      * The {@link #defaults} hash will be used for any date value (i.e. year, month, day, hour, minute, second or millisecond)
10312      * which cannot be found in the passed string. If a corresponding default date value has not been specified in the {@link #defaults} hash,
10313      * the current date's year, month, day or DST-adjusted zero-hour time value will be used instead.
10314      * Keep in mind that the input date string must precisely match the specified format string
10315      * in order for the parse operation to be successful (failed parse operations return a null value).
10316      * <p>Example:</p><pre><code>
10317 //dt = Fri May 25 2007 (current date)
10318 var dt = new Date();
10319
10320 //dt = Thu May 25 2006 (today&#39;s month/day in 2006)
10321 dt = Date.parseDate("2006", "Y");
10322
10323 //dt = Sun Jan 15 2006 (all date parts specified)
10324 dt = Date.parseDate("2006-01-15", "Y-m-d");
10325
10326 //dt = Sun Jan 15 2006 15:20:01
10327 dt = Date.parseDate("2006-01-15 3:20:01 PM", "Y-m-d g:i:s A");
10328
10329 // attempt to parse Sun Feb 29 2006 03:20:01 in strict mode
10330 dt = Date.parseDate("2006-02-29 03:20:01", "Y-m-d H:i:s", true); // returns null
10331 </code></pre>
10332      * @param {String} input The raw date string.
10333      * @param {String} format The expected date string format.
10334      * @param {Boolean} strict (optional) True to validate date strings while parsing (i.e. prevents javascript Date "rollover")
10335                         (defaults to false). Invalid date strings will return null when parsed.
10336      * @return {Date} The parsed Date.
10337      * @static
10338      */
10339     parseDate : function(input, format, strict) {
10340         var p = Date.parseFunctions;
10341         if (p[format] == null) {
10342             Date.createParser(format);
10343         }
10344         return p[format](input, Ext.isDefined(strict) ? strict : Date.useStrict);
10345     },
10346
10347     // private
10348     getFormatCode : function(character) {
10349         var f = Date.formatCodes[character];
10350
10351         if (f) {
10352           f = typeof f == 'function'? f() : f;
10353           Date.formatCodes[character] = f; // reassign function result to prevent repeated execution
10354         }
10355
10356         // note: unknown characters are treated as literals
10357         return f || ("'" + String.escape(character) + "'");
10358     },
10359
10360     // private
10361     createFormat : function(format) {
10362         var code = [],
10363             special = false,
10364             ch = '';
10365
10366         for (var i = 0; i < format.length; ++i) {
10367             ch = format.charAt(i);
10368             if (!special && ch == "\\") {
10369                 special = true;
10370             } else if (special) {
10371                 special = false;
10372                 code.push("'" + String.escape(ch) + "'");
10373             } else {
10374                 code.push(Date.getFormatCode(ch))
10375             }
10376         }
10377         Date.formatFunctions[format] = new Function("return " + code.join('+'));
10378     },
10379
10380     // private
10381     createParser : function() {
10382         var code = [
10383             "var dt, y, m, d, h, i, s, ms, o, z, zz, u, v,",
10384                 "def = Date.defaults,",
10385                 "results = String(input).match(Date.parseRegexes[{0}]);", // either null, or an array of matched strings
10386
10387             "if(results){",
10388                 "{1}",
10389
10390                 "if(u != null){", // i.e. unix time is defined
10391                     "v = new Date(u * 1000);", // give top priority to UNIX time
10392                 "}else{",
10393                     // create Date object representing midnight of the current day;
10394                     // this will provide us with our date defaults
10395                     // (note: clearTime() handles Daylight Saving Time automatically)
10396                     "dt = (new Date()).clearTime();",
10397
10398                     // date calculations (note: these calculations create a dependency on Ext.num())
10399                     "y = y >= 0? y : Ext.num(def.y, dt.getFullYear());",
10400                     "m = m >= 0? m : Ext.num(def.m - 1, dt.getMonth());",
10401                     "d = d >= 0? d : Ext.num(def.d, dt.getDate());",
10402
10403                     // time calculations (note: these calculations create a dependency on Ext.num())
10404                     "h  = h || Ext.num(def.h, dt.getHours());",
10405                     "i  = i || Ext.num(def.i, dt.getMinutes());",
10406                     "s  = s || Ext.num(def.s, dt.getSeconds());",
10407                     "ms = ms || Ext.num(def.ms, dt.getMilliseconds());",
10408
10409                     "if(z >= 0 && y >= 0){",
10410                         // both the year and zero-based day of year are defined and >= 0.
10411                         // these 2 values alone provide sufficient info to create a full date object
10412
10413                         // create Date object representing January 1st for the given year
10414                         "v = new Date(y, 0, 1, h, i, s, ms);",
10415
10416                         // then add day of year, checking for Date "rollover" if necessary
10417                         "v = !strict? v : (strict === true && (z <= 364 || (v.isLeapYear() && z <= 365))? v.add(Date.DAY, z) : null);",
10418                     "}else if(strict === true && !Date.isValid(y, m + 1, d, h, i, s, ms)){", // check for Date "rollover"
10419                         "v = null;", // invalid date, so return null
10420                     "}else{",
10421                         // plain old Date object
10422                         "v = new Date(y, m, d, h, i, s, ms);",
10423                     "}",
10424                 "}",
10425             "}",
10426
10427             "if(v){",
10428                 // favour UTC offset over GMT offset
10429                 "if(zz != null){",
10430                     // reset to UTC, then add offset
10431                     "v = v.add(Date.SECOND, -v.getTimezoneOffset() * 60 - zz);",
10432                 "}else if(o){",
10433                     // reset to GMT, then add offset
10434                     "v = v.add(Date.MINUTE, -v.getTimezoneOffset() + (sn == '+'? -1 : 1) * (hr * 60 + mn));",
10435                 "}",
10436             "}",
10437
10438             "return v;"
10439         ].join('\n');
10440
10441         return function(format) {
10442             var regexNum = Date.parseRegexes.length,
10443                 currentGroup = 1,
10444                 calc = [],
10445                 regex = [],
10446                 special = false,
10447                 ch = "";
10448
10449             for (var i = 0; i < format.length; ++i) {
10450                 ch = format.charAt(i);
10451                 if (!special && ch == "\\") {
10452                     special = true;
10453                 } else if (special) {
10454                     special = false;
10455                     regex.push(String.escape(ch));
10456                 } else {
10457                     var obj = $f(ch, currentGroup);
10458                     currentGroup += obj.g;
10459                     regex.push(obj.s);
10460                     if (obj.g && obj.c) {
10461                         calc.push(obj.c);
10462                     }
10463                 }
10464             }
10465
10466             Date.parseRegexes[regexNum] = new RegExp("^" + regex.join('') + "$", "i");
10467             Date.parseFunctions[format] = new Function("input", "strict", xf(code, regexNum, calc.join('')));
10468         }
10469     }(),
10470
10471     // private
10472     parseCodes : {
10473         /*
10474          * Notes:
10475          * g = {Number} calculation group (0 or 1. only group 1 contributes to date calculations.)
10476          * c = {String} calculation method (required for group 1. null for group 0. {0} = currentGroup - position in regex result array)
10477          * s = {String} regex pattern. all matches are stored in results[], and are accessible by the calculation mapped to 'c'
10478          */
10479         d: {
10480             g:1,
10481             c:"d = parseInt(results[{0}], 10);\n",
10482             s:"(\\d{2})" // day of month with leading zeroes (01 - 31)
10483         },
10484         j: {
10485             g:1,
10486             c:"d = parseInt(results[{0}], 10);\n",
10487             s:"(\\d{1,2})" // day of month without leading zeroes (1 - 31)
10488         },
10489         D: function() {
10490             for (var a = [], i = 0; i < 7; a.push(Date.getShortDayName(i)), ++i); // get localised short day names
10491             return {
10492                 g:0,
10493                 c:null,
10494                 s:"(?:" + a.join("|") +")"
10495             }
10496         },
10497         l: function() {
10498             return {
10499                 g:0,
10500                 c:null,
10501                 s:"(?:" + Date.dayNames.join("|") + ")"
10502             }
10503         },
10504         N: {
10505             g:0,
10506             c:null,
10507             s:"[1-7]" // ISO-8601 day number (1 (monday) - 7 (sunday))
10508         },
10509         S: {
10510             g:0,
10511             c:null,
10512             s:"(?:st|nd|rd|th)"
10513         },
10514         w: {
10515             g:0,
10516             c:null,
10517             s:"[0-6]" // javascript day number (0 (sunday) - 6 (saturday))
10518         },
10519         z: {
10520             g:1,
10521             c:"z = parseInt(results[{0}], 10);\n",
10522             s:"(\\d{1,3})" // day of the year (0 - 364 (365 in leap years))
10523         },
10524         W: {
10525             g:0,
10526             c:null,
10527             s:"(?:\\d{2})" // ISO-8601 week number (with leading zero)
10528         },
10529         F: function() {
10530             return {
10531                 g:1,
10532                 c:"m = parseInt(Date.getMonthNumber(results[{0}]), 10);\n", // get localised month number
10533                 s:"(" + Date.monthNames.join("|") + ")"
10534             }
10535         },
10536         M: function() {
10537             for (var a = [], i = 0; i < 12; a.push(Date.getShortMonthName(i)), ++i); // get localised short month names
10538             return Ext.applyIf({
10539                 s:"(" + a.join("|") + ")"
10540             }, $f("F"));
10541         },
10542         m: {
10543             g:1,
10544             c:"m = parseInt(results[{0}], 10) - 1;\n",
10545             s:"(\\d{2})" // month number with leading zeros (01 - 12)
10546         },
10547         n: {
10548             g:1,
10549             c:"m = parseInt(results[{0}], 10) - 1;\n",
10550             s:"(\\d{1,2})" // month number without leading zeros (1 - 12)
10551         },
10552         t: {
10553             g:0,
10554             c:null,
10555             s:"(?:\\d{2})" // no. of days in the month (28 - 31)
10556         },
10557         L: {
10558             g:0,
10559             c:null,
10560             s:"(?:1|0)"
10561         },
10562         o: function() {
10563             return $f("Y");
10564         },
10565         Y: {
10566             g:1,
10567             c:"y = parseInt(results[{0}], 10);\n",
10568             s:"(\\d{4})" // 4-digit year
10569         },
10570         y: {
10571             g:1,
10572             c:"var ty = parseInt(results[{0}], 10);\n"
10573                 + "y = ty > Date.y2kYear ? 1900 + ty : 2000 + ty;\n", // 2-digit year
10574             s:"(\\d{1,2})"
10575         },
10576         a: {
10577             g:1,
10578             c:"if (results[{0}] == 'am') {\n"
10579                 + "if (!h || h == 12) { h = 0; }\n"
10580                 + "} else { if (!h || h < 12) { h = (h || 0) + 12; }}",
10581             s:"(am|pm)"
10582         },
10583         A: {
10584             g:1,
10585             c:"if (results[{0}] == 'AM') {\n"
10586                 + "if (!h || h == 12) { h = 0; }\n"
10587                 + "} else { if (!h || h < 12) { h = (h || 0) + 12; }}",
10588             s:"(AM|PM)"
10589         },
10590         g: function() {
10591             return $f("G");
10592         },
10593         G: {
10594             g:1,
10595             c:"h = parseInt(results[{0}], 10);\n",
10596             s:"(\\d{1,2})" // 24-hr format of an hour without leading zeroes (0 - 23)
10597         },
10598         h: function() {
10599             return $f("H");
10600         },
10601         H: {
10602             g:1,
10603             c:"h = parseInt(results[{0}], 10);\n",
10604             s:"(\\d{2})" //  24-hr format of an hour with leading zeroes (00 - 23)
10605         },
10606         i: {
10607             g:1,
10608             c:"i = parseInt(results[{0}], 10);\n",
10609             s:"(\\d{2})" // minutes with leading zeros (00 - 59)
10610         },
10611         s: {
10612             g:1,
10613             c:"s = parseInt(results[{0}], 10);\n",
10614             s:"(\\d{2})" // seconds with leading zeros (00 - 59)
10615         },
10616         u: {
10617             g:1,
10618             c:"ms = results[{0}]; ms = parseInt(ms, 10)/Math.pow(10, ms.length - 3);\n",
10619             s:"(\\d+)" // decimal fraction of a second (minimum = 1 digit, maximum = unlimited)
10620         },
10621         O: {
10622             g:1,
10623             c:[
10624                 "o = results[{0}];",
10625                 "var sn = o.substring(0,1),", // get + / - sign
10626                     "hr = o.substring(1,3)*1 + Math.floor(o.substring(3,5) / 60),", // get hours (performs minutes-to-hour conversion also, just in case)
10627                     "mn = o.substring(3,5) % 60;", // get minutes
10628                 "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
10629             ].join("\n"),
10630             s: "([+\-]\\d{4})" // GMT offset in hrs and mins
10631         },
10632         P: {
10633             g:1,
10634             c:[
10635                 "o = results[{0}];",
10636                 "var sn = o.substring(0,1),", // get + / - sign
10637                     "hr = o.substring(1,3)*1 + Math.floor(o.substring(4,6) / 60),", // get hours (performs minutes-to-hour conversion also, just in case)
10638                     "mn = o.substring(4,6) % 60;", // get minutes
10639                 "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
10640             ].join("\n"),
10641             s: "([+\-]\\d{2}:\\d{2})" // GMT offset in hrs and mins (with colon separator)
10642         },
10643         T: {
10644             g:0,
10645             c:null,
10646             s:"[A-Z]{1,4}" // timezone abbrev. may be between 1 - 4 chars
10647         },
10648         Z: {
10649             g:1,
10650             c:"zz = results[{0}] * 1;\n" // -43200 <= UTC offset <= 50400
10651                   + "zz = (-43200 <= zz && zz <= 50400)? zz : null;\n",
10652             s:"([+\-]?\\d{1,5})" // leading '+' sign is optional for UTC offset
10653         },
10654         c: function() {
10655             var calc = [],
10656                 arr = [
10657                     $f("Y", 1), // year
10658                     $f("m", 2), // month
10659                     $f("d", 3), // day
10660                     $f("h", 4), // hour
10661                     $f("i", 5), // minute
10662                     $f("s", 6), // second
10663                     {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)
10664                     {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
10665                         "if(results[8]) {", // timezone specified
10666                             "if(results[8] == 'Z'){",
10667                                 "zz = 0;", // UTC
10668                             "}else if (results[8].indexOf(':') > -1){",
10669                                 $f("P", 8).c, // timezone offset with colon separator
10670                             "}else{",
10671                                 $f("O", 8).c, // timezone offset without colon separator
10672                             "}",
10673                         "}"
10674                     ].join('\n')}
10675                 ];
10676
10677             for (var i = 0, l = arr.length; i < l; ++i) {
10678                 calc.push(arr[i].c);
10679             }
10680
10681             return {
10682                 g:1,
10683                 c:calc.join(""),
10684                 s:[
10685                     arr[0].s, // year (required)
10686                     "(?:", "-", arr[1].s, // month (optional)
10687                         "(?:", "-", arr[2].s, // day (optional)
10688                             "(?:",
10689                                 "(?:T| )?", // time delimiter -- either a "T" or a single blank space
10690                                 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
10691                                 "(?::", arr[5].s, ")?", // seconds (optional)
10692                                 "(?:(?:\\.|,)(\\d+))?", // decimal fraction of a second (e.g. ",12345" or ".98765") (optional)
10693                                 "(Z|(?:[-+]\\d{2}(?::)?\\d{2}))?", // "Z" (UTC) or "-0530" (UTC offset without colon delimiter) or "+08:00" (UTC offset with colon delimiter) (optional)
10694                             ")?",
10695                         ")?",
10696                     ")?"
10697                 ].join("")
10698             }
10699         },
10700         U: {
10701             g:1,
10702             c:"u = parseInt(results[{0}], 10);\n",
10703             s:"(-?\\d+)" // leading minus sign indicates seconds before UNIX epoch
10704         }
10705     }
10706 });
10707
10708 }());
10709
10710 Ext.apply(Date.prototype, {
10711     // private
10712     dateFormat : function(format) {
10713         if (Date.formatFunctions[format] == null) {
10714             Date.createFormat(format);
10715         }
10716         return Date.formatFunctions[format].call(this);
10717     },
10718
10719     /**
10720      * Get the timezone abbreviation of the current date (equivalent to the format specifier 'T').
10721      *
10722      * Note: The date string returned by the javascript Date object's toString() method varies
10723      * between browsers (e.g. FF vs IE) and system region settings (e.g. IE in Asia vs IE in America).
10724      * For a given date string e.g. "Thu Oct 25 2007 22:55:35 GMT+0800 (Malay Peninsula Standard Time)",
10725      * getTimezone() first tries to get the timezone abbreviation from between a pair of parentheses
10726      * (which may or may not be present), failing which it proceeds to get the timezone abbreviation
10727      * from the GMT offset portion of the date string.
10728      * @return {String} The abbreviated timezone name (e.g. 'CST', 'PDT', 'EDT', 'MPST' ...).
10729      */
10730     getTimezone : function() {
10731         // the following list shows the differences between date strings from different browsers on a WinXP SP2 machine from an Asian locale:
10732         //
10733         // Opera  : "Thu, 25 Oct 2007 22:53:45 GMT+0800" -- shortest (weirdest) date string of the lot
10734         // 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)
10735         // FF     : "Thu Oct 25 2007 22:55:35 GMT+0800 (Malay Peninsula Standard Time)" -- value in parentheses always gives the correct timezone
10736         // IE     : "Thu Oct 25 22:54:35 UTC+0800 2007" -- (Asian system setting) look for 3-4 letter timezone abbrev
10737         // IE     : "Thu Oct 25 17:06:37 PDT 2007" -- (American system setting) look for 3-4 letter timezone abbrev
10738         //
10739         // this crazy regex attempts to guess the correct timezone abbreviation despite these differences.
10740         // step 1: (?:\((.*)\) -- find timezone in parentheses
10741         // 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
10742         // step 3: remove all non uppercase characters found in step 1 and 2
10743         return this.toString().replace(/^.* (?:\((.*)\)|([A-Z]{1,4})(?:[\-+][0-9]{4})?(?: -?\d+)?)$/, "$1$2").replace(/[^A-Z]/g, "");
10744     },
10745
10746     /**
10747      * Get the offset from GMT of the current date (equivalent to the format specifier 'O').
10748      * @param {Boolean} colon (optional) true to separate the hours and minutes with a colon (defaults to false).
10749      * @return {String} The 4-character offset string prefixed with + or - (e.g. '-0600').
10750      */
10751     getGMTOffset : function(colon) {
10752         return (this.getTimezoneOffset() > 0 ? "-" : "+")
10753             + String.leftPad(Math.floor(Math.abs(this.getTimezoneOffset()) / 60), 2, "0")
10754             + (colon ? ":" : "")
10755             + String.leftPad(Math.abs(this.getTimezoneOffset() % 60), 2, "0");
10756     },
10757
10758     /**
10759      * Get the numeric day number of the year, adjusted for leap year.
10760      * @return {Number} 0 to 364 (365 in leap years).
10761      */
10762     getDayOfYear: function() {
10763         var num = 0,
10764             d = this.clone(),
10765             m = this.getMonth(),
10766             i;
10767
10768         for (i = 0, d.setDate(1), d.setMonth(0); i < m; d.setMonth(++i)) {
10769             num += d.getDaysInMonth();
10770         }
10771         return num + this.getDate() - 1;
10772     },
10773
10774     /**
10775      * Get the numeric ISO-8601 week number of the year.
10776      * (equivalent to the format specifier 'W', but without a leading zero).
10777      * @return {Number} 1 to 53
10778      */
10779     getWeekOfYear : function() {
10780         // adapted from http://www.merlyn.demon.co.uk/weekcalc.htm
10781         var ms1d = 864e5, // milliseconds in a day
10782             ms7d = 7 * ms1d; // milliseconds in a week
10783
10784         return function() { // return a closure so constants get calculated only once
10785             var DC3 = Date.UTC(this.getFullYear(), this.getMonth(), this.getDate() + 3) / ms1d, // an Absolute Day Number
10786                 AWN = Math.floor(DC3 / 7), // an Absolute Week Number
10787                 Wyr = new Date(AWN * ms7d).getUTCFullYear();
10788
10789             return AWN - Math.floor(Date.UTC(Wyr, 0, 7) / ms7d) + 1;
10790         }
10791     }(),
10792
10793     /**
10794      * Checks if the current date falls within a leap year.
10795      * @return {Boolean} True if the current date falls within a leap year, false otherwise.
10796      */
10797     isLeapYear : function() {
10798         var year = this.getFullYear();
10799         return !!((year & 3) == 0 && (year % 100 || (year % 400 == 0 && year)));
10800     },
10801
10802     /**
10803      * Get the first day of the current month, adjusted for leap year.  The returned value
10804      * is the numeric day index within the week (0-6) which can be used in conjunction with
10805      * the {@link #monthNames} array to retrieve the textual day name.
10806      * Example:
10807      * <pre><code>
10808 var dt = new Date('1/10/2007');
10809 document.write(Date.dayNames[dt.getFirstDayOfMonth()]); //output: 'Monday'
10810 </code></pre>
10811      * @return {Number} The day number (0-6).
10812      */
10813     getFirstDayOfMonth : function() {
10814         var day = (this.getDay() - (this.getDate() - 1)) % 7;
10815         return (day < 0) ? (day + 7) : day;
10816     },
10817
10818     /**
10819      * Get the last day of the current month, adjusted for leap year.  The returned value
10820      * is the numeric day index within the week (0-6) which can be used in conjunction with
10821      * the {@link #monthNames} array to retrieve the textual day name.
10822      * Example:
10823      * <pre><code>
10824 var dt = new Date('1/10/2007');
10825 document.write(Date.dayNames[dt.getLastDayOfMonth()]); //output: 'Wednesday'
10826 </code></pre>
10827      * @return {Number} The day number (0-6).
10828      */
10829     getLastDayOfMonth : function() {
10830         return this.getLastDateOfMonth().getDay();
10831     },
10832
10833
10834     /**
10835      * Get the date of the first day of the month in which this date resides.
10836      * @return {Date}
10837      */
10838     getFirstDateOfMonth : function() {
10839         return new Date(this.getFullYear(), this.getMonth(), 1);
10840     },
10841
10842     /**
10843      * Get the date of the last day of the month in which this date resides.
10844      * @return {Date}
10845      */
10846     getLastDateOfMonth : function() {
10847         return new Date(this.getFullYear(), this.getMonth(), this.getDaysInMonth());
10848     },
10849
10850     /**
10851      * Get the number of days in the current month, adjusted for leap year.
10852      * @return {Number} The number of days in the month.
10853      */
10854     getDaysInMonth: function() {
10855         var daysInMonth = [31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31];
10856
10857         return function() { // return a closure for efficiency
10858             var m = this.getMonth();
10859
10860             return m == 1 && this.isLeapYear() ? 29 : daysInMonth[m];
10861         }
10862     }(),
10863
10864     /**
10865      * Get the English ordinal suffix of the current day (equivalent to the format specifier 'S').
10866      * @return {String} 'st, 'nd', 'rd' or 'th'.
10867      */
10868     getSuffix : function() {
10869         switch (this.getDate()) {
10870             case 1:
10871             case 21:
10872             case 31:
10873                 return "st";
10874             case 2:
10875             case 22:
10876                 return "nd";
10877             case 3:
10878             case 23:
10879                 return "rd";
10880             default:
10881                 return "th";
10882         }
10883     },
10884
10885     /**
10886      * Creates and returns a new Date instance with the exact same date value as the called instance.
10887      * Dates are copied and passed by reference, so if a copied date variable is modified later, the original
10888      * variable will also be changed.  When the intention is to create a new variable that will not
10889      * modify the original instance, you should create a clone.
10890      *
10891      * Example of correctly cloning a date:
10892      * <pre><code>
10893 //wrong way:
10894 var orig = new Date('10/1/2006');
10895 var copy = orig;
10896 copy.setDate(5);
10897 document.write(orig);  //returns 'Thu Oct 05 2006'!
10898
10899 //correct way:
10900 var orig = new Date('10/1/2006');
10901 var copy = orig.clone();
10902 copy.setDate(5);
10903 document.write(orig);  //returns 'Thu Oct 01 2006'
10904 </code></pre>
10905      * @return {Date} The new Date instance.
10906      */
10907     clone : function() {
10908         return new Date(this.getTime());
10909     },
10910
10911     /**
10912      * Checks if the current date is affected by Daylight Saving Time (DST).
10913      * @return {Boolean} True if the current date is affected by DST.
10914      */
10915     isDST : function() {
10916         // adapted from http://extjs.com/forum/showthread.php?p=247172#post247172
10917         // courtesy of @geoffrey.mcgill
10918         return new Date(this.getFullYear(), 0, 1).getTimezoneOffset() != this.getTimezoneOffset();
10919     },
10920
10921     /**
10922      * Attempts to clear all time information from this Date by setting the time to midnight of the same day,
10923      * automatically adjusting for Daylight Saving Time (DST) where applicable.
10924      * (note: DST timezone information for the browser's host operating system is assumed to be up-to-date)
10925      * @param {Boolean} clone true to create a clone of this date, clear the time and return it (defaults to false).
10926      * @return {Date} this or the clone.
10927      */
10928     clearTime : function(clone) {
10929         if (clone) {
10930             return this.clone().clearTime();
10931         }
10932
10933         // get current date before clearing time
10934         var d = this.getDate();
10935
10936         // clear time
10937         this.setHours(0);
10938         this.setMinutes(0);
10939         this.setSeconds(0);
10940         this.setMilliseconds(0);
10941
10942         if (this.getDate() != d) { // account for DST (i.e. day of month changed when setting hour = 0)
10943             // note: DST adjustments are assumed to occur in multiples of 1 hour (this is almost always the case)
10944             // refer to http://www.timeanddate.com/time/aboutdst.html for the (rare) exceptions to this rule
10945
10946             // increment hour until cloned date == current date
10947             for (var hr = 1, c = this.add(Date.HOUR, hr); c.getDate() != d; hr++, c = this.add(Date.HOUR, hr));
10948
10949             this.setDate(d);
10950             this.setHours(c.getHours());
10951         }
10952
10953         return this;
10954     },
10955
10956     /**
10957      * Provides a convenient method for performing basic date arithmetic. This method
10958      * does not modify the Date instance being called - it creates and returns
10959      * a new Date instance containing the resulting date value.
10960      *
10961      * Examples:
10962      * <pre><code>
10963 // Basic usage:
10964 var dt = new Date('10/29/2006').add(Date.DAY, 5);
10965 document.write(dt); //returns 'Fri Nov 03 2006 00:00:00'
10966
10967 // Negative values will be subtracted:
10968 var dt2 = new Date('10/1/2006').add(Date.DAY, -5);
10969 document.write(dt2); //returns 'Tue Sep 26 2006 00:00:00'
10970
10971 // You can even chain several calls together in one line:
10972 var dt3 = new Date('10/1/2006').add(Date.DAY, 5).add(Date.HOUR, 8).add(Date.MINUTE, -30);
10973 document.write(dt3); //returns 'Fri Oct 06 2006 07:30:00'
10974 </code></pre>
10975      *
10976      * @param {String} interval A valid date interval enum value.
10977      * @param {Number} value The amount to add to the current date.
10978      * @return {Date} The new Date instance.
10979      */
10980     add : function(interval, value) {
10981         var d = this.clone();
10982         if (!interval || value === 0) return d;
10983
10984         switch(interval.toLowerCase()) {
10985             case Date.MILLI:
10986                 d.setMilliseconds(this.getMilliseconds() + value);
10987                 break;
10988             case Date.SECOND:
10989                 d.setSeconds(this.getSeconds() + value);
10990                 break;
10991             case Date.MINUTE:
10992                 d.setMinutes(this.getMinutes() + value);
10993                 break;
10994             case Date.HOUR:
10995                 d.setHours(this.getHours() + value);
10996                 break;
10997             case Date.DAY:
10998                 d.setDate(this.getDate() + value);
10999                 break;
11000             case Date.MONTH:
11001                 var day = this.getDate();
11002                 if (day > 28) {
11003                     day = Math.min(day, this.getFirstDateOfMonth().add('mo', value).getLastDateOfMonth().getDate());
11004                 }
11005                 d.setDate(day);
11006                 d.setMonth(this.getMonth() + value);
11007                 break;
11008             case Date.YEAR:
11009                 d.setFullYear(this.getFullYear() + value);
11010                 break;
11011         }
11012         return d;
11013     },
11014
11015     /**
11016      * Checks if this date falls on or between the given start and end dates.
11017      * @param {Date} start Start date
11018      * @param {Date} end End date
11019      * @return {Boolean} true if this date falls on or between the given start and end dates.
11020      */
11021     between : function(start, end) {
11022         var t = this.getTime();
11023         return start.getTime() <= t && t <= end.getTime();
11024     }
11025 });
11026
11027
11028 /**
11029  * Formats a date given the supplied format string.
11030  * @param {String} format The format string.
11031  * @return {String} The formatted date.
11032  * @method format
11033  */
11034 Date.prototype.format = Date.prototype.dateFormat;
11035
11036
11037 // private
11038 if (Ext.isSafari && (navigator.userAgent.match(/WebKit\/(\d+)/)[1] || NaN) < 420) {
11039     Ext.apply(Date.prototype, {
11040         _xMonth : Date.prototype.setMonth,
11041         _xDate  : Date.prototype.setDate,
11042
11043         // Bug in Safari 1.3, 2.0 (WebKit build < 420)
11044         // Date.setMonth does not work consistently if iMonth is not 0-11
11045         setMonth : function(num) {
11046             if (num <= -1) {
11047                 var n = Math.ceil(-num),
11048                     back_year = Math.ceil(n / 12),
11049                     month = (n % 12) ? 12 - n % 12 : 0;
11050
11051                 this.setFullYear(this.getFullYear() - back_year);
11052
11053                 return this._xMonth(month);
11054             } else {
11055                 return this._xMonth(num);
11056             }
11057         },
11058
11059         // Bug in setDate() method (resolved in WebKit build 419.3, so to be safe we target Webkit builds < 420)
11060         // The parameter for Date.setDate() is converted to a signed byte integer in Safari
11061         // http://brianary.blogspot.com/2006/03/safari-date-bug.html
11062         setDate : function(d) {
11063             // use setTime() to workaround setDate() bug
11064             // subtract current day of month in milliseconds, then add desired day of month in milliseconds
11065             return this.setTime(this.getTime() - (this.getDate() - d) * 864e5);
11066         }
11067     });
11068 }
11069
11070
11071
11072 /* Some basic Date tests... (requires Firebug)
11073
11074 Date.parseDate('', 'c'); // call Date.parseDate() once to force computation of regex string so we can console.log() it
11075 console.log('Insane Regex for "c" format: %o', Date.parseCodes.c.s); // view the insane regex for the "c" format specifier
11076
11077 // standard tests
11078 console.group('Standard Date.parseDate() Tests');
11079     console.log('Date.parseDate("2009-01-05T11:38:56", "c")               = %o', Date.parseDate("2009-01-05T11:38:56", "c")); // assumes browser's timezone setting
11080     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
11081     console.log('Date.parseDate("2009-03-03T13:36:54,101000Z", "c")       = %o', Date.parseDate("2009-03-03T13:36:54,101000Z", "c")); // UTC
11082     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
11083     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
11084 console.groupEnd();
11085
11086 // ISO-8601 format as specified in http://www.w3.org/TR/NOTE-datetime
11087 // -- accepts ALL 6 levels of date-time granularity
11088 console.group('ISO-8601 Granularity Test (see http://www.w3.org/TR/NOTE-datetime)');
11089     console.log('Date.parseDate("1997", "c")                              = %o', Date.parseDate("1997", "c")); // YYYY (e.g. 1997)
11090     console.log('Date.parseDate("1997-07", "c")                           = %o', Date.parseDate("1997-07", "c")); // YYYY-MM (e.g. 1997-07)
11091     console.log('Date.parseDate("1997-07-16", "c")                        = %o', Date.parseDate("1997-07-16", "c")); // YYYY-MM-DD (e.g. 1997-07-16)
11092     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)
11093     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)
11094     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)
11095     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)
11096     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
11097 console.groupEnd();
11098
11099 //*//**
11100  * @class Ext.util.DelayedTask
11101  * <p> The DelayedTask class provides a convenient way to "buffer" the execution of a method,
11102  * performing setTimeout where a new timeout cancels the old timeout. When called, the
11103  * task will wait the specified time period before executing. If durng that time period,
11104  * the task is called again, the original call will be cancelled. This continues so that
11105  * the function is only called a single time for each iteration.</p>
11106  * <p>This method is especially useful for things like detecting whether a user has finished
11107  * typing in a text field. An example would be performing validation on a keypress. You can
11108  * use this class to buffer the keypress events for a certain number of milliseconds, and
11109  * perform only if they stop for that amount of time.  Usage:</p><pre><code>
11110 var task = new Ext.util.DelayedTask(function(){
11111     alert(Ext.getDom('myInputField').value.length);
11112 });
11113 // Wait 500ms before calling our function. If the user presses another key 
11114 // during that 500ms, it will be cancelled and we'll wait another 500ms.
11115 Ext.get('myInputField').on('keypress', function(){
11116     task.{@link #delay}(500); 
11117 });
11118  * </code></pre> 
11119  * <p>Note that we are using a DelayedTask here to illustrate a point. The configuration
11120  * option <tt>buffer</tt> for {@link Ext.util.Observable#addListener addListener/on} will
11121  * also setup a delayed task for you to buffer events.</p> 
11122  * @constructor The parameters to this constructor serve as defaults and are not required.
11123  * @param {Function} fn (optional) The default function to call.
11124  * @param {Object} scope The default scope (The <code><b>this</b></code> reference) in which the
11125  * function is called. If not specified, <code>this</code> will refer to the browser window.
11126  * @param {Array} args (optional) The default Array of arguments.
11127  */
11128 Ext.util.DelayedTask = function(fn, scope, args){
11129     var me = this,
11130         id,     
11131         call = function(){
11132                 clearInterval(id);
11133                 id = null;
11134                 fn.apply(scope, args || []);
11135             };
11136             
11137     /**
11138      * Cancels any pending timeout and queues a new one
11139      * @param {Number} delay The milliseconds to delay
11140      * @param {Function} newFn (optional) Overrides function passed to constructor
11141      * @param {Object} newScope (optional) Overrides scope passed to constructor. Remember that if no scope
11142      * is specified, <code>this</code> will refer to the browser window.
11143      * @param {Array} newArgs (optional) Overrides args passed to constructor
11144      */
11145     me.delay = function(delay, newFn, newScope, newArgs){
11146         me.cancel();
11147         fn = newFn || fn;
11148         scope = newScope || scope;
11149         args = newArgs || args;
11150         id = setInterval(call, delay);
11151     };
11152
11153     /**
11154      * Cancel the last queued timeout
11155      */
11156     me.cancel = function(){
11157         if(id){
11158             clearInterval(id);
11159             id = null;
11160         }
11161     };
11162 };/**\r
11163  * @class Ext.util.MixedCollection\r
11164  * @extends Ext.util.Observable\r
11165  * A Collection class that maintains both numeric indexes and keys and exposes events.\r
11166  * @constructor\r
11167  * @param {Boolean} allowFunctions Specify <tt>true</tt> if the {@link #addAll}\r
11168  * function should add function references to the collection. Defaults to\r
11169  * <tt>false</tt>.\r
11170  * @param {Function} keyFn A function that can accept an item of the type(s) stored in this MixedCollection\r
11171  * and return the key value for that item.  This is used when available to look up the key on items that\r
11172  * were passed without an explicit key parameter to a MixedCollection method.  Passing this parameter is\r
11173  * equivalent to providing an implementation for the {@link #getKey} method.\r
11174  */\r
11175 Ext.util.MixedCollection = function(allowFunctions, keyFn){\r
11176     this.items = [];\r
11177     this.map = {};\r
11178     this.keys = [];\r
11179     this.length = 0;\r
11180     this.addEvents(\r
11181         /**\r
11182          * @event clear\r
11183          * Fires when the collection is cleared.\r
11184          */\r
11185         'clear',\r
11186         /**\r
11187          * @event add\r
11188          * Fires when an item is added to the collection.\r
11189          * @param {Number} index The index at which the item was added.\r
11190          * @param {Object} o The item added.\r
11191          * @param {String} key The key associated with the added item.\r
11192          */\r
11193         'add',\r
11194         /**\r
11195          * @event replace\r
11196          * Fires when an item is replaced in the collection.\r
11197          * @param {String} key he key associated with the new added.\r
11198          * @param {Object} old The item being replaced.\r
11199          * @param {Object} new The new item.\r
11200          */\r
11201         'replace',\r
11202         /**\r
11203          * @event remove\r
11204          * Fires when an item is removed from the collection.\r
11205          * @param {Object} o The item being removed.\r
11206          * @param {String} key (optional) The key associated with the removed item.\r
11207          */\r
11208         'remove',\r
11209         'sort'\r
11210     );\r
11211     this.allowFunctions = allowFunctions === true;\r
11212     if(keyFn){\r
11213         this.getKey = keyFn;\r
11214     }\r
11215     Ext.util.MixedCollection.superclass.constructor.call(this);\r
11216 };\r
11217 \r
11218 Ext.extend(Ext.util.MixedCollection, Ext.util.Observable, {\r
11219 \r
11220     /**\r
11221      * @cfg {Boolean} allowFunctions Specify <tt>true</tt> if the {@link #addAll}\r
11222      * function should add function references to the collection. Defaults to\r
11223      * <tt>false</tt>.\r
11224      */\r
11225     allowFunctions : false,\r
11226 \r
11227     /**\r
11228      * Adds an item to the collection. Fires the {@link #add} event when complete.\r
11229      * @param {String} key <p>The key to associate with the item, or the new item.</p>\r
11230      * <p>If a {@link #getKey} implementation was specified for this MixedCollection,\r
11231      * or if the key of the stored items is in a property called <tt><b>id</b></tt>,\r
11232      * the MixedCollection will be able to <i>derive</i> the key for the new item.\r
11233      * In this case just pass the new item in this parameter.</p>\r
11234      * @param {Object} o The item to add.\r
11235      * @return {Object} The item added.\r
11236      */\r
11237     add : function(key, o){\r
11238         if(arguments.length == 1){\r
11239             o = arguments[0];\r
11240             key = this.getKey(o);\r
11241         }\r
11242         if(typeof key != 'undefined' && key !== null){\r
11243             var old = this.map[key];\r
11244             if(typeof old != 'undefined'){\r
11245                 return this.replace(key, o);\r
11246             }\r
11247             this.map[key] = o;\r
11248         }\r
11249         this.length++;\r
11250         this.items.push(o);\r
11251         this.keys.push(key);\r
11252         this.fireEvent('add', this.length-1, o, key);\r
11253         return o;\r
11254     },\r
11255 \r
11256     /**\r
11257       * MixedCollection has a generic way to fetch keys if you implement getKey.  The default implementation\r
11258       * simply returns <b><code>item.id</code></b> but you can provide your own implementation\r
11259       * to return a different value as in the following examples:<pre><code>\r
11260 // normal way\r
11261 var mc = new Ext.util.MixedCollection();\r
11262 mc.add(someEl.dom.id, someEl);\r
11263 mc.add(otherEl.dom.id, otherEl);\r
11264 //and so on\r
11265 \r
11266 // using getKey\r
11267 var mc = new Ext.util.MixedCollection();\r
11268 mc.getKey = function(el){\r
11269    return el.dom.id;\r
11270 };\r
11271 mc.add(someEl);\r
11272 mc.add(otherEl);\r
11273 \r
11274 // or via the constructor\r
11275 var mc = new Ext.util.MixedCollection(false, function(el){\r
11276    return el.dom.id;\r
11277 });\r
11278 mc.add(someEl);\r
11279 mc.add(otherEl);\r
11280      * </code></pre>\r
11281      * @param {Object} item The item for which to find the key.\r
11282      * @return {Object} The key for the passed item.\r
11283      */\r
11284     getKey : function(o){\r
11285          return o.id;\r
11286     },\r
11287 \r
11288     /**\r
11289      * Replaces an item in the collection. Fires the {@link #replace} event when complete.\r
11290      * @param {String} key <p>The key associated with the item to replace, or the replacement item.</p>\r
11291      * <p>If you supplied a {@link #getKey} implementation for this MixedCollection, or if the key\r
11292      * of your stored items is in a property called <tt><b>id</b></tt>, then the MixedCollection\r
11293      * will be able to <i>derive</i> the key of the replacement item. If you want to replace an item\r
11294      * with one having the same key value, then just pass the replacement item in this parameter.</p>\r
11295      * @param o {Object} o (optional) If the first parameter passed was a key, the item to associate\r
11296      * with that key.\r
11297      * @return {Object}  The new item.\r
11298      */\r
11299     replace : function(key, o){\r
11300         if(arguments.length == 1){\r
11301             o = arguments[0];\r
11302             key = this.getKey(o);\r
11303         }\r
11304         var old = this.map[key];\r
11305         if(typeof key == 'undefined' || key === null || typeof old == 'undefined'){\r
11306              return this.add(key, o);\r
11307         }\r
11308         var index = this.indexOfKey(key);\r
11309         this.items[index] = o;\r
11310         this.map[key] = o;\r
11311         this.fireEvent('replace', key, old, o);\r
11312         return o;\r
11313     },\r
11314 \r
11315     /**\r
11316      * Adds all elements of an Array or an Object to the collection.\r
11317      * @param {Object/Array} objs An Object containing properties which will be added\r
11318      * to the collection, or an Array of values, each of which are added to the collection.\r
11319      * Functions references will be added to the collection if <code>{@link #allowFunctions}</code>\r
11320      * has been set to <tt>true</tt>.\r
11321      */\r
11322     addAll : function(objs){\r
11323         if(arguments.length > 1 || Ext.isArray(objs)){\r
11324             var args = arguments.length > 1 ? arguments : objs;\r
11325             for(var i = 0, len = args.length; i < len; i++){\r
11326                 this.add(args[i]);\r
11327             }\r
11328         }else{\r
11329             for(var key in objs){\r
11330                 if(this.allowFunctions || typeof objs[key] != 'function'){\r
11331                     this.add(key, objs[key]);\r
11332                 }\r
11333             }\r
11334         }\r
11335     },\r
11336 \r
11337     /**\r
11338      * Executes the specified function once for every item in the collection, passing the following arguments:\r
11339      * <div class="mdetail-params"><ul>\r
11340      * <li><b>item</b> : Mixed<p class="sub-desc">The collection item</p></li>\r
11341      * <li><b>index</b> : Number<p class="sub-desc">The item's index</p></li>\r
11342      * <li><b>length</b> : Number<p class="sub-desc">The total number of items in the collection</p></li>\r
11343      * </ul></div>\r
11344      * The function should return a boolean value. Returning false from the function will stop the iteration.\r
11345      * @param {Function} fn The function to execute for each item.\r
11346      * @param {Object} scope (optional) The scope in which to execute the function.\r
11347      */\r
11348     each : function(fn, scope){\r
11349         var items = [].concat(this.items); // each safe for removal\r
11350         for(var i = 0, len = items.length; i < len; i++){\r
11351             if(fn.call(scope || items[i], items[i], i, len) === false){\r
11352                 break;\r
11353             }\r
11354         }\r
11355     },\r
11356 \r
11357     /**\r
11358      * Executes the specified function once for every key in the collection, passing each\r
11359      * key, and its associated item as the first two parameters.\r
11360      * @param {Function} fn The function to execute for each item.\r
11361      * @param {Object} scope (optional) The scope in which to execute the function.\r
11362      */\r
11363     eachKey : function(fn, scope){\r
11364         for(var i = 0, len = this.keys.length; i < len; i++){\r
11365             fn.call(scope || window, this.keys[i], this.items[i], i, len);\r
11366         }\r
11367     },\r
11368 \r
11369     /**\r
11370      * Returns the first item in the collection which elicits a true return value from the\r
11371      * passed selection function.\r
11372      * @param {Function} fn The selection function to execute for each item.\r
11373      * @param {Object} scope (optional) The scope in which to execute the function.\r
11374      * @return {Object} The first item in the collection which returned true from the selection function.\r
11375      */\r
11376     find : function(fn, scope){\r
11377         for(var i = 0, len = this.items.length; i < len; i++){\r
11378             if(fn.call(scope || window, this.items[i], this.keys[i])){\r
11379                 return this.items[i];\r
11380             }\r
11381         }\r
11382         return null;\r
11383     },\r
11384 \r
11385     /**\r
11386      * Inserts an item at the specified index in the collection. Fires the {@link #add} event when complete.\r
11387      * @param {Number} index The index to insert the item at.\r
11388      * @param {String} key The key to associate with the new item, or the item itself.\r
11389      * @param {Object} o (optional) If the second parameter was a key, the new item.\r
11390      * @return {Object} The item inserted.\r
11391      */\r
11392     insert : function(index, key, o){\r
11393         if(arguments.length == 2){\r
11394             o = arguments[1];\r
11395             key = this.getKey(o);\r
11396         }\r
11397         if(this.containsKey(key)){\r
11398             this.suspendEvents();\r
11399             this.removeKey(key);\r
11400             this.resumeEvents();\r
11401         }\r
11402         if(index >= this.length){\r
11403             return this.add(key, o);\r
11404         }\r
11405         this.length++;\r
11406         this.items.splice(index, 0, o);\r
11407         if(typeof key != 'undefined' && key !== null){\r
11408             this.map[key] = o;\r
11409         }\r
11410         this.keys.splice(index, 0, key);\r
11411         this.fireEvent('add', index, o, key);\r
11412         return o;\r
11413     },\r
11414 \r
11415     /**\r
11416      * Remove an item from the collection.\r
11417      * @param {Object} o The item to remove.\r
11418      * @return {Object} The item removed or false if no item was removed.\r
11419      */\r
11420     remove : function(o){\r
11421         return this.removeAt(this.indexOf(o));\r
11422     },\r
11423 \r
11424     /**\r
11425      * Remove an item from a specified index in the collection. Fires the {@link #remove} event when complete.\r
11426      * @param {Number} index The index within the collection of the item to remove.\r
11427      * @return {Object} The item removed or false if no item was removed.\r
11428      */\r
11429     removeAt : function(index){\r
11430         if(index < this.length && index >= 0){\r
11431             this.length--;\r
11432             var o = this.items[index];\r
11433             this.items.splice(index, 1);\r
11434             var key = this.keys[index];\r
11435             if(typeof key != 'undefined'){\r
11436                 delete this.map[key];\r
11437             }\r
11438             this.keys.splice(index, 1);\r
11439             this.fireEvent('remove', o, key);\r
11440             return o;\r
11441         }\r
11442         return false;\r
11443     },\r
11444 \r
11445     /**\r
11446      * Removed an item associated with the passed key fom the collection.\r
11447      * @param {String} key The key of the item to remove.\r
11448      * @return {Object} The item removed or false if no item was removed.\r
11449      */\r
11450     removeKey : function(key){\r
11451         return this.removeAt(this.indexOfKey(key));\r
11452     },\r
11453 \r
11454     /**\r
11455      * Returns the number of items in the collection.\r
11456      * @return {Number} the number of items in the collection.\r
11457      */\r
11458     getCount : function(){\r
11459         return this.length;\r
11460     },\r
11461     \r
11462     /**\r
11463      * Returns index within the collection of the passed Object.\r
11464      * @param {Object} o The item to find the index of.\r
11465      * @return {Number} index of the item. Returns -1 if not found.\r
11466      */\r
11467     indexOf : function(o){\r
11468         return this.items.indexOf(o);\r
11469     },\r
11470 \r
11471     /**\r
11472      * Returns index within the collection of the passed key.\r
11473      * @param {String} key The key to find the index of.\r
11474      * @return {Number} index of the key.\r
11475      */\r
11476     indexOfKey : function(key){\r
11477         return this.keys.indexOf(key);\r
11478     },\r
11479 \r
11480     /**\r
11481      * Returns the item associated with the passed key OR index.\r
11482      * Key has priority over index.  This is the equivalent\r
11483      * of calling {@link #key} first, then if nothing matched calling {@link #itemAt}.\r
11484      * @param {String/Number} key The key or index of the item.\r
11485      * @return {Object} If the item is found, returns the item.  If the item was not found, returns <tt>undefined</tt>.\r
11486      * If an item was found, but is a Class, returns <tt>null</tt>.\r
11487      */\r
11488     item : function(key){\r
11489         var mk = this.map[key],\r
11490             item = mk !== undefined ? mk : (typeof key == 'number') ? this.items[key] : undefined;\r
11491         return !Ext.isFunction(item) || this.allowFunctions ? item : null; // for prototype!\r
11492     },\r
11493 \r
11494     /**\r
11495      * Returns the item at the specified index.\r
11496      * @param {Number} index The index of the item.\r
11497      * @return {Object} The item at the specified index.\r
11498      */\r
11499     itemAt : function(index){\r
11500         return this.items[index];\r
11501     },\r
11502 \r
11503     /**\r
11504      * Returns the item associated with the passed key.\r
11505      * @param {String/Number} key The key of the item.\r
11506      * @return {Object} The item associated with the passed key.\r
11507      */\r
11508     key : function(key){\r
11509         return this.map[key];\r
11510     },\r
11511 \r
11512     /**\r
11513      * Returns true if the collection contains the passed Object as an item.\r
11514      * @param {Object} o  The Object to look for in the collection.\r
11515      * @return {Boolean} True if the collection contains the Object as an item.\r
11516      */\r
11517     contains : function(o){\r
11518         return this.indexOf(o) != -1;\r
11519     },\r
11520 \r
11521     /**\r
11522      * Returns true if the collection contains the passed Object as a key.\r
11523      * @param {String} key The key to look for in the collection.\r
11524      * @return {Boolean} True if the collection contains the Object as a key.\r
11525      */\r
11526     containsKey : function(key){\r
11527         return typeof this.map[key] != 'undefined';\r
11528     },\r
11529 \r
11530     /**\r
11531      * Removes all items from the collection.  Fires the {@link #clear} event when complete.\r
11532      */\r
11533     clear : function(){\r
11534         this.length = 0;\r
11535         this.items = [];\r
11536         this.keys = [];\r
11537         this.map = {};\r
11538         this.fireEvent('clear');\r
11539     },\r
11540 \r
11541     /**\r
11542      * Returns the first item in the collection.\r
11543      * @return {Object} the first item in the collection..\r
11544      */\r
11545     first : function(){\r
11546         return this.items[0];\r
11547     },\r
11548 \r
11549     /**\r
11550      * Returns the last item in the collection.\r
11551      * @return {Object} the last item in the collection..\r
11552      */\r
11553     last : function(){\r
11554         return this.items[this.length-1];\r
11555     },\r
11556 \r
11557     /**\r
11558      * @private\r
11559      * @param {String} property Property to sort by ('key', 'value', or 'index')\r
11560      * @param {String} dir (optional) Direction to sort 'ASC' or 'DESC'. Defaults to 'ASC'.\r
11561      * @param {Function} fn (optional) Comparison function that defines the sort order.\r
11562      * Defaults to sorting by numeric value.  \r
11563      */\r
11564     _sort : function(property, dir, fn){\r
11565         var i,\r
11566             len,\r
11567             dsc = String(dir).toUpperCase() == 'DESC' ? -1 : 1,\r
11568             c = [], k = this.keys, items = this.items;\r
11569             \r
11570         fn = fn || function(a, b){\r
11571             return a-b;\r
11572         };\r
11573         for(i = 0, len = items.length; i < len; i++){\r
11574             c[c.length] = {key: k[i], value: items[i], index: i};\r
11575         }\r
11576         c.sort(function(a, b){\r
11577             var v = fn(a[property], b[property]) * dsc;\r
11578             if(v === 0){\r
11579                 v = (a.index < b.index ? -1 : 1);\r
11580             }\r
11581             return v;\r
11582         });\r
11583         for(i = 0, len = c.length; i < len; i++){\r
11584             items[i] = c[i].value;\r
11585             k[i] = c[i].key;\r
11586         }\r
11587         this.fireEvent('sort', this);\r
11588     },\r
11589 \r
11590     /**\r
11591      * Sorts this collection by <b>item</b> value with the passed comparison function.\r
11592      * @param {String} direction (optional) 'ASC' or 'DESC'. Defaults to 'ASC'.\r
11593      * @param {Function} fn (optional) Comparison function that defines the sort order.\r
11594      * Defaults to sorting by numeric value.  \r
11595      */\r
11596     sort : function(dir, fn){\r
11597         this._sort('value', dir, fn);\r
11598     },\r
11599 \r
11600     /**\r
11601      * Sorts this collection by <b>key</b>s.\r
11602      * @param {String} direction (optional) 'ASC' or 'DESC'. Defaults to 'ASC'.\r
11603      * @param {Function} fn (optional) Comparison function that defines the sort order.\r
11604      * Defaults to sorting by case insensitive string.  \r
11605      */\r
11606     keySort : function(dir, fn){\r
11607         this._sort('key', dir, fn || function(a, b){\r
11608             var v1 = String(a).toUpperCase(), v2 = String(b).toUpperCase();\r
11609             return v1 > v2 ? 1 : (v1 < v2 ? -1 : 0);\r
11610         });\r
11611     },\r
11612 \r
11613     /**\r
11614      * Returns a range of items in this collection\r
11615      * @param {Number} startIndex (optional) The starting index. Defaults to 0.\r
11616      * @param {Number} endIndex (optional) The ending index. Defaults to the last item.\r
11617      * @return {Array} An array of items\r
11618      */\r
11619     getRange : function(start, end){\r
11620         var items = this.items;\r
11621         if(items.length < 1){\r
11622             return [];\r
11623         }\r
11624         start = start || 0;\r
11625         end = Math.min(typeof end == 'undefined' ? this.length-1 : end, this.length-1);\r
11626         var i, r = [];\r
11627         if(start <= end){\r
11628             for(i = start; i <= end; i++) {\r
11629                 r[r.length] = items[i];\r
11630             }\r
11631         }else{\r
11632             for(i = start; i >= end; i--) {\r
11633                 r[r.length] = items[i];\r
11634             }\r
11635         }\r
11636         return r;\r
11637     },\r
11638 \r
11639     /**\r
11640      * Filter the <i>objects</i> in this collection by a specific property.\r
11641      * Returns a new collection that has been filtered.\r
11642      * @param {String} property A property on your objects\r
11643      * @param {String/RegExp} value Either string that the property values\r
11644      * should start with or a RegExp to test against the property\r
11645      * @param {Boolean} anyMatch (optional) True to match any part of the string, not just the beginning\r
11646      * @param {Boolean} caseSensitive (optional) True for case sensitive comparison (defaults to False).\r
11647      * @return {MixedCollection} The new filtered collection\r
11648      */\r
11649     filter : function(property, value, anyMatch, caseSensitive){\r
11650         if(Ext.isEmpty(value, false)){\r
11651             return this.clone();\r
11652         }\r
11653         value = this.createValueMatcher(value, anyMatch, caseSensitive);\r
11654         return this.filterBy(function(o){\r
11655             return o && value.test(o[property]);\r
11656         });\r
11657     },\r
11658 \r
11659     /**\r
11660      * Filter by a function. Returns a <i>new</i> collection that has been filtered.\r
11661      * The passed function will be called with each object in the collection.\r
11662      * If the function returns true, the value is included otherwise it is filtered.\r
11663      * @param {Function} fn The function to be called, it will receive the args o (the object), k (the key)\r
11664      * @param {Object} scope (optional) The scope of the function (defaults to this)\r
11665      * @return {MixedCollection} The new filtered collection\r
11666      */\r
11667     filterBy : function(fn, scope){\r
11668         var r = new Ext.util.MixedCollection();\r
11669         r.getKey = this.getKey;\r
11670         var k = this.keys, it = this.items;\r
11671         for(var i = 0, len = it.length; i < len; i++){\r
11672             if(fn.call(scope||this, it[i], k[i])){\r
11673                 r.add(k[i], it[i]);\r
11674             }\r
11675         }\r
11676         return r;\r
11677     },\r
11678 \r
11679     /**\r
11680      * Finds the index of the first matching object in this collection by a specific property/value.\r
11681      * @param {String} property The name of a property on your objects.\r
11682      * @param {String/RegExp} value A string that the property values\r
11683      * should start with or a RegExp to test against the property.\r
11684      * @param {Number} start (optional) The index to start searching at (defaults to 0).\r
11685      * @param {Boolean} anyMatch (optional) True to match any part of the string, not just the beginning.\r
11686      * @param {Boolean} caseSensitive (optional) True for case sensitive comparison.\r
11687      * @return {Number} The matched index or -1\r
11688      */\r
11689     findIndex : function(property, value, start, anyMatch, caseSensitive){\r
11690         if(Ext.isEmpty(value, false)){\r
11691             return -1;\r
11692         }\r
11693         value = this.createValueMatcher(value, anyMatch, caseSensitive);\r
11694         return this.findIndexBy(function(o){\r
11695             return o && value.test(o[property]);\r
11696         }, null, start);\r
11697     },\r
11698 \r
11699     /**\r
11700      * Find the index of the first matching object in this collection by a function.\r
11701      * If the function returns <i>true</i> it is considered a match.\r
11702      * @param {Function} fn The function to be called, it will receive the args o (the object), k (the key).\r
11703      * @param {Object} scope (optional) The scope of the function (defaults to this).\r
11704      * @param {Number} start (optional) The index to start searching at (defaults to 0).\r
11705      * @return {Number} The matched index or -1\r
11706      */\r
11707     findIndexBy : function(fn, scope, start){\r
11708         var k = this.keys, it = this.items;\r
11709         for(var i = (start||0), len = it.length; i < len; i++){\r
11710             if(fn.call(scope||this, it[i], k[i])){\r
11711                 return i;\r
11712             }\r
11713         }\r
11714         return -1;\r
11715     },\r
11716 \r
11717     // private\r
11718     createValueMatcher : function(value, anyMatch, caseSensitive){\r
11719         if(!value.exec){ // not a regex\r
11720             value = String(value);\r
11721             value = new RegExp((anyMatch === true ? '' : '^') + Ext.escapeRe(value), caseSensitive ? '' : 'i');\r
11722         }\r
11723         return value;\r
11724     },\r
11725 \r
11726     /**\r
11727      * Creates a shallow copy of this collection\r
11728      * @return {MixedCollection}\r
11729      */\r
11730     clone : function(){\r
11731         var r = new Ext.util.MixedCollection();\r
11732         var k = this.keys, it = this.items;\r
11733         for(var i = 0, len = it.length; i < len; i++){\r
11734             r.add(k[i], it[i]);\r
11735         }\r
11736         r.getKey = this.getKey;\r
11737         return r;\r
11738     }\r
11739 });\r
11740 /**\r
11741  * This method calls {@link #item item()}.\r
11742  * Returns the item associated with the passed key OR index. Key has priority\r
11743  * over index.  This is the equivalent of calling {@link #key} first, then if\r
11744  * nothing matched calling {@link #itemAt}.\r
11745  * @param {String/Number} key The key or index of the item.\r
11746  * @return {Object} If the item is found, returns the item.  If the item was\r
11747  * not found, returns <tt>undefined</tt>. If an item was found, but is a Class,\r
11748  * returns <tt>null</tt>.\r
11749  */\r
11750 Ext.util.MixedCollection.prototype.get = Ext.util.MixedCollection.prototype.item;/**
11751  * @class Ext.util.JSON
11752  * Modified version of Douglas Crockford"s json.js that doesn"t
11753  * mess with the Object prototype
11754  * http://www.json.org/js.html
11755  * @singleton
11756  */
11757 Ext.util.JSON = new (function(){
11758     var useHasOwn = !!{}.hasOwnProperty,
11759         isNative = function() {
11760             var useNative = null;
11761
11762             return function() {
11763                 if (useNative === null) {
11764                     useNative = Ext.USE_NATIVE_JSON && window.JSON && JSON.toString() == '[object JSON]';
11765                 }
11766         
11767                 return useNative;
11768             };
11769         }(),
11770         pad = function(n) {
11771             return n < 10 ? "0" + n : n;
11772         },
11773         doDecode = function(json){
11774             return eval("(" + json + ')');    
11775         },
11776         doEncode = function(o){
11777             if(!Ext.isDefined(o) || o === null){
11778                 return "null";
11779             }else if(Ext.isArray(o)){
11780                 return encodeArray(o);
11781             }else if(Ext.isDate(o)){
11782                 return Ext.util.JSON.encodeDate(o);
11783             }else if(Ext.isString(o)){
11784                 return encodeString(o);
11785             }else if(typeof o == "number"){
11786                 //don't use isNumber here, since finite checks happen inside isNumber
11787                 return isFinite(o) ? String(o) : "null";
11788             }else if(Ext.isBoolean(o)){
11789                 return String(o);
11790             }else {
11791                 var a = ["{"], b, i, v;
11792                 for (i in o) {
11793                     // don't encode DOM objects
11794                     if(!o.getElementsByTagName){
11795                         if(!useHasOwn || o.hasOwnProperty(i)) {
11796                             v = o[i];
11797                             switch (typeof v) {
11798                             case "undefined":
11799                             case "function":
11800                             case "unknown":
11801                                 break;
11802                             default:
11803                                 if(b){
11804                                     a.push(',');
11805                                 }
11806                                 a.push(doEncode(i), ":",
11807                                         v === null ? "null" : doEncode(v));
11808                                 b = true;
11809                             }
11810                         }
11811                     }
11812                 }
11813                 a.push("}");
11814                 return a.join("");
11815             }    
11816         },
11817         m = {
11818             "\b": '\\b',
11819             "\t": '\\t',
11820             "\n": '\\n',
11821             "\f": '\\f',
11822             "\r": '\\r',
11823             '"' : '\\"',
11824             "\\": '\\\\'
11825         },
11826         encodeString = function(s){
11827             if (/["\\\x00-\x1f]/.test(s)) {
11828                 return '"' + s.replace(/([\x00-\x1f\\"])/g, function(a, b) {
11829                     var c = m[b];
11830                     if(c){
11831                         return c;
11832                     }
11833                     c = b.charCodeAt();
11834                     return "\\u00" +
11835                         Math.floor(c / 16).toString(16) +
11836                         (c % 16).toString(16);
11837                 }) + '"';
11838             }
11839             return '"' + s + '"';
11840         },
11841         encodeArray = function(o){
11842             var a = ["["], b, i, l = o.length, v;
11843                 for (i = 0; i < l; i += 1) {
11844                     v = o[i];
11845                     switch (typeof v) {
11846                         case "undefined":
11847                         case "function":
11848                         case "unknown":
11849                             break;
11850                         default:
11851                             if (b) {
11852                                 a.push(',');
11853                             }
11854                             a.push(v === null ? "null" : Ext.util.JSON.encode(v));
11855                             b = true;
11856                     }
11857                 }
11858                 a.push("]");
11859                 return a.join("");
11860         };
11861
11862     this.encodeDate = function(o){
11863         return '"' + o.getFullYear() + "-" +
11864                 pad(o.getMonth() + 1) + "-" +
11865                 pad(o.getDate()) + "T" +
11866                 pad(o.getHours()) + ":" +
11867                 pad(o.getMinutes()) + ":" +
11868                 pad(o.getSeconds()) + '"';
11869     };
11870
11871     /**
11872      * Encodes an Object, Array or other value
11873      * @param {Mixed} o The variable to encode
11874      * @return {String} The JSON string
11875      */
11876     this.encode = function() {
11877         var ec;
11878         return function(o) {
11879             if (!ec) {
11880                 // setup encoding function on first access
11881                 ec = isNative() ? JSON.stringify : doEncode;
11882             }
11883             return ec(o);
11884         };
11885     }();
11886
11887
11888     /**
11889      * Decodes (parses) a JSON string to an object. If the JSON is invalid, this function throws a SyntaxError unless the safe option is set.
11890      * @param {String} json The JSON string
11891      * @return {Object} The resulting object
11892      */
11893     this.decode = function() {
11894         var dc;
11895         return function(json) {
11896             if (!dc) {
11897                 // setup decoding function on first access
11898                 dc = isNative() ? JSON.parse : doDecode;
11899             }
11900             return dc(json);
11901         };
11902     }();
11903
11904 })();
11905 /**
11906  * Shorthand for {@link Ext.util.JSON#encode}
11907  * @param {Mixed} o The variable to encode
11908  * @return {String} The JSON string
11909  * @member Ext
11910  * @method encode
11911  */
11912 Ext.encode = Ext.util.JSON.encode;
11913 /**
11914  * Shorthand for {@link Ext.util.JSON#decode}
11915  * @param {String} json The JSON string
11916  * @param {Boolean} safe (optional) Whether to return null or throw an exception if the JSON is invalid.
11917  * @return {Object} The resulting object
11918  * @member Ext
11919  * @method decode
11920  */
11921 Ext.decode = Ext.util.JSON.decode;
11922 /**\r
11923  * @class Ext.util.Format\r
11924  * Reusable data formatting functions\r
11925  * @singleton\r
11926  */\r
11927 Ext.util.Format = function(){\r
11928     var trimRe = /^\s+|\s+$/g;\r
11929     return {\r
11930         /**\r
11931          * Truncate a string and add an ellipsis ('...') to the end if it exceeds the specified length\r
11932          * @param {String} value The string to truncate\r
11933          * @param {Number} length The maximum length to allow before truncating\r
11934          * @param {Boolean} word True to try to find a common work break\r
11935          * @return {String} The converted text\r
11936          */\r
11937         ellipsis : function(value, len, word){\r
11938             if(value && value.length > len){\r
11939                 if(word){\r
11940                     var vs = value.substr(0, len - 2);\r
11941                     var index = Math.max(vs.lastIndexOf(' '), vs.lastIndexOf('.'), vs.lastIndexOf('!'), vs.lastIndexOf('?'));\r
11942                     if(index == -1 || index < (len - 15)){\r
11943                         return value.substr(0, len - 3) + "...";\r
11944                     }else{\r
11945                         return vs.substr(0, index) + "...";\r
11946                     }\r
11947                 } else{\r
11948                     return value.substr(0, len - 3) + "...";\r
11949                 }\r
11950             }\r
11951             return value;\r
11952         },\r
11953 \r
11954         /**\r
11955          * Checks a reference and converts it to empty string if it is undefined\r
11956          * @param {Mixed} value Reference to check\r
11957          * @return {Mixed} Empty string if converted, otherwise the original value\r
11958          */\r
11959         undef : function(value){\r
11960             return value !== undefined ? value : "";\r
11961         },\r
11962 \r
11963         /**\r
11964          * Checks a reference and converts it to the default value if it's empty\r
11965          * @param {Mixed} value Reference to check\r
11966          * @param {String} defaultValue The value to insert of it's undefined (defaults to "")\r
11967          * @return {String}\r
11968          */\r
11969         defaultValue : function(value, defaultValue){\r
11970             return value !== undefined && value !== '' ? value : defaultValue;\r
11971         },\r
11972 \r
11973         /**\r
11974          * Convert certain characters (&, <, >, and ') to their HTML character equivalents for literal display in web pages.\r
11975          * @param {String} value The string to encode\r
11976          * @return {String} The encoded text\r
11977          */\r
11978         htmlEncode : function(value){\r
11979             return !value ? value : String(value).replace(/&/g, "&amp;").replace(/>/g, "&gt;").replace(/</g, "&lt;").replace(/"/g, "&quot;");\r
11980         },\r
11981 \r
11982         /**\r
11983          * Convert certain characters (&, <, >, and ') from their HTML character equivalents.\r
11984          * @param {String} value The string to decode\r
11985          * @return {String} The decoded text\r
11986          */\r
11987         htmlDecode : function(value){\r
11988             return !value ? value : String(value).replace(/&gt;/g, ">").replace(/&lt;/g, "<").replace(/&quot;/g, '"').replace(/&amp;/g, "&");\r
11989         },\r
11990 \r
11991         /**\r
11992          * Trims any whitespace from either side of a string\r
11993          * @param {String} value The text to trim\r
11994          * @return {String} The trimmed text\r
11995          */\r
11996         trim : function(value){\r
11997             return String(value).replace(trimRe, "");\r
11998         },\r
11999 \r
12000         /**\r
12001          * Returns a substring from within an original string\r
12002          * @param {String} value The original text\r
12003          * @param {Number} start The start index of the substring\r
12004          * @param {Number} length The length of the substring\r
12005          * @return {String} The substring\r
12006          */\r
12007         substr : function(value, start, length){\r
12008             return String(value).substr(start, length);\r
12009         },\r
12010 \r
12011         /**\r
12012          * Converts a string to all lower case letters\r
12013          * @param {String} value The text to convert\r
12014          * @return {String} The converted text\r
12015          */\r
12016         lowercase : function(value){\r
12017             return String(value).toLowerCase();\r
12018         },\r
12019 \r
12020         /**\r
12021          * Converts a string to all upper case letters\r
12022          * @param {String} value The text to convert\r
12023          * @return {String} The converted text\r
12024          */\r
12025         uppercase : function(value){\r
12026             return String(value).toUpperCase();\r
12027         },\r
12028 \r
12029         /**\r
12030          * Converts the first character only of a string to upper case\r
12031          * @param {String} value The text to convert\r
12032          * @return {String} The converted text\r
12033          */\r
12034         capitalize : function(value){\r
12035             return !value ? value : value.charAt(0).toUpperCase() + value.substr(1).toLowerCase();\r
12036         },\r
12037 \r
12038         // private\r
12039         call : function(value, fn){\r
12040             if(arguments.length > 2){\r
12041                 var args = Array.prototype.slice.call(arguments, 2);\r
12042                 args.unshift(value);\r
12043                 return eval(fn).apply(window, args);\r
12044             }else{\r
12045                 return eval(fn).call(window, value);\r
12046             }\r
12047         },\r
12048 \r
12049         /**\r
12050          * Format a number as US currency\r
12051          * @param {Number/String} value The numeric value to format\r
12052          * @return {String} The formatted currency string\r
12053          */\r
12054         usMoney : function(v){\r
12055             v = (Math.round((v-0)*100))/100;\r
12056             v = (v == Math.floor(v)) ? v + ".00" : ((v*10 == Math.floor(v*10)) ? v + "0" : v);\r
12057             v = String(v);\r
12058             var ps = v.split('.');\r
12059             var whole = ps[0];\r
12060             var sub = ps[1] ? '.'+ ps[1] : '.00';\r
12061             var r = /(\d+)(\d{3})/;\r
12062             while (r.test(whole)) {\r
12063                 whole = whole.replace(r, '$1' + ',' + '$2');\r
12064             }\r
12065             v = whole + sub;\r
12066             if(v.charAt(0) == '-'){\r
12067                 return '-$' + v.substr(1);\r
12068             }\r
12069             return "$" +  v;\r
12070         },\r
12071 \r
12072         /**\r
12073          * Parse a value into a formatted date using the specified format pattern.\r
12074          * @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
12075          * @param {String} format (optional) Any valid date format string (defaults to 'm/d/Y')\r
12076          * @return {String} The formatted date string\r
12077          */\r
12078         date : function(v, format){\r
12079             if(!v){\r
12080                 return "";\r
12081             }\r
12082             if(!Ext.isDate(v)){\r
12083                 v = new Date(Date.parse(v));\r
12084             }\r
12085             return v.dateFormat(format || "m/d/Y");\r
12086         },\r
12087 \r
12088         /**\r
12089          * Returns a date rendering function that can be reused to apply a date format multiple times efficiently\r
12090          * @param {String} format Any valid date format string\r
12091          * @return {Function} The date formatting function\r
12092          */\r
12093         dateRenderer : function(format){\r
12094             return function(v){\r
12095                 return Ext.util.Format.date(v, format);\r
12096             };\r
12097         },\r
12098 \r
12099         // private\r
12100         stripTagsRE : /<\/?[^>]+>/gi,\r
12101         \r
12102         /**\r
12103          * Strips all HTML tags\r
12104          * @param {Mixed} value The text from which to strip tags\r
12105          * @return {String} The stripped text\r
12106          */\r
12107         stripTags : function(v){\r
12108             return !v ? v : String(v).replace(this.stripTagsRE, "");\r
12109         },\r
12110 \r
12111         stripScriptsRe : /(?:<script.*?>)((\n|\r|.)*?)(?:<\/script>)/ig,\r
12112 \r
12113         /**\r
12114          * Strips all script tags\r
12115          * @param {Mixed} value The text from which to strip script tags\r
12116          * @return {String} The stripped text\r
12117          */\r
12118         stripScripts : function(v){\r
12119             return !v ? v : String(v).replace(this.stripScriptsRe, "");\r
12120         },\r
12121 \r
12122         /**\r
12123          * Simple format for a file size (xxx bytes, xxx KB, xxx MB)\r
12124          * @param {Number/String} size The numeric value to format\r
12125          * @return {String} The formatted file size\r
12126          */\r
12127         fileSize : function(size){\r
12128             if(size < 1024) {\r
12129                 return size + " bytes";\r
12130             } else if(size < 1048576) {\r
12131                 return (Math.round(((size*10) / 1024))/10) + " KB";\r
12132             } else {\r
12133                 return (Math.round(((size*10) / 1048576))/10) + " MB";\r
12134             }\r
12135         },\r
12136 \r
12137         /**\r
12138          * It does simple math for use in a template, for example:<pre><code>\r
12139          * var tpl = new Ext.Template('{value} * 10 = {value:math("* 10")}');\r
12140          * </code></pre>\r
12141          * @return {Function} A function that operates on the passed value.\r
12142          */\r
12143         math : function(){\r
12144             var fns = {};\r
12145             return function(v, a){\r
12146                 if(!fns[a]){\r
12147                     fns[a] = new Function('v', 'return v ' + a + ';');\r
12148                 }\r
12149                 return fns[a](v);\r
12150             }\r
12151         }(),\r
12152 \r
12153         /**\r
12154          * Rounds the passed number to the required decimal precision.\r
12155          * @param {Number/String} value The numeric value to round.\r
12156          * @param {Number} precision The number of decimal places to which to round the first parameter's value.\r
12157          * @return {Number} The rounded value.\r
12158          */\r
12159         round : function(value, precision) {\r
12160             var result = Number(value);\r
12161             if (typeof precision == 'number') {\r
12162                 precision = Math.pow(10, precision);\r
12163                 result = Math.round(value * precision) / precision;\r
12164             }\r
12165             return result;\r
12166         },\r
12167 \r
12168         /**\r
12169          * Formats the number according to the format string.\r
12170          * <div style="margin-left:40px">examples (123456.789):\r
12171          * <div style="margin-left:10px">\r
12172          * 0 - (123456) show only digits, no precision<br>\r
12173          * 0.00 - (123456.78) show only digits, 2 precision<br>\r
12174          * 0.0000 - (123456.7890) show only digits, 4 precision<br>\r
12175          * 0,000 - (123,456) show comma and digits, no precision<br>\r
12176          * 0,000.00 - (123,456.78) show comma and digits, 2 precision<br>\r
12177          * 0,0.00 - (123,456.78) shortcut method, show comma and digits, 2 precision<br>\r
12178          * To reverse the grouping (,) and decimal (.) for international numbers, add /i to the end.\r
12179          * For example: 0.000,00/i\r
12180          * </div></div>\r
12181          * @param {Number} v The number to format.\r
12182          * @param {String} format The way you would like to format this text.\r
12183          * @return {String} The formatted number.\r
12184          */\r
12185         number: function(v, format) {\r
12186             if(!format){\r
12187                         return v;\r
12188                     }\r
12189                     v = Ext.num(v, NaN);\r
12190             if (isNaN(v)){\r
12191                 return '';\r
12192             }\r
12193                     var comma = ',',\r
12194                         dec = '.',\r
12195                         i18n = false,\r
12196                         neg = v < 0;\r
12197                 \r
12198                     v = Math.abs(v);\r
12199                     if(format.substr(format.length - 2) == '/i'){\r
12200                         format = format.substr(0, format.length - 2);\r
12201                         i18n = true;\r
12202                         comma = '.';\r
12203                         dec = ',';\r
12204                     }\r
12205                 \r
12206                     var hasComma = format.indexOf(comma) != -1, \r
12207                         psplit = (i18n ? format.replace(/[^\d\,]/g, '') : format.replace(/[^\d\.]/g, '')).split(dec);\r
12208                 \r
12209                     if(1 < psplit.length){\r
12210                         v = v.toFixed(psplit[1].length);\r
12211                     }else if(2 < psplit.length){\r
12212                         throw ('NumberFormatException: invalid format, formats should have no more than 1 period: ' + format);\r
12213                     }else{\r
12214                         v = v.toFixed(0);\r
12215                     }\r
12216                 \r
12217                     var fnum = v.toString();\r
12218                     if(hasComma){\r
12219                         psplit = fnum.split('.');\r
12220                 \r
12221                         var cnum = psplit[0], parr = [], j = cnum.length, m = Math.floor(j / 3), n = cnum.length % 3 || 3;\r
12222                 \r
12223                         for(var i = 0; i < j; i += n){\r
12224                             if(i != 0){\r
12225                                 n = 3;\r
12226                             }\r
12227                             parr[parr.length] = cnum.substr(i, n);\r
12228                             m -= 1;\r
12229                         }\r
12230                         fnum = parr.join(comma);\r
12231                         if(psplit[1]){\r
12232                             fnum += dec + psplit[1];\r
12233                         }\r
12234                     }\r
12235                 \r
12236                     return (neg ? '-' : '') + format.replace(/[\d,?\.?]+/, fnum);\r
12237         },\r
12238 \r
12239         /**\r
12240          * Returns a number rendering function that can be reused to apply a number format multiple times efficiently\r
12241          * @param {String} format Any valid number format string for {@link #number}\r
12242          * @return {Function} The number formatting function\r
12243          */\r
12244         numberRenderer : function(format){\r
12245             return function(v){\r
12246                 return Ext.util.Format.number(v, format);\r
12247             };\r
12248         },\r
12249 \r
12250         /**\r
12251          * Selectively do a plural form of a word based on a numeric value. For example, in a template,\r
12252          * {commentCount:plural("Comment")}  would result in "1 Comment" if commentCount was 1 or would be "x Comments"\r
12253          * if the value is 0 or greater than 1.\r
12254          * @param {Number} value The value to compare against\r
12255          * @param {String} singular The singular form of the word\r
12256          * @param {String} plural (optional) The plural form of the word (defaults to the singular with an "s")\r
12257          */\r
12258         plural : function(v, s, p){\r
12259             return v +' ' + (v == 1 ? s : (p ? p : s+'s'));\r
12260         },\r
12261         \r
12262         /**\r
12263          * Converts newline characters to the HTML tag &lt;br/>\r
12264          * @param {String} The string value to format.\r
12265          * @return {String} The string with embedded &lt;br/> tags in place of newlines.\r
12266          */\r
12267         nl2br : function(v){\r
12268             return v === undefined || v === null ? '' : v.replace(/\n/g, '<br/>');\r
12269         }\r
12270     }\r
12271 }();/**
12272  * @class Ext.XTemplate
12273  * @extends Ext.Template
12274  * <p>A template class that supports advanced functionality like:<div class="mdetail-params"><ul>
12275  * <li>Autofilling arrays using templates and sub-templates</li>
12276  * <li>Conditional processing with basic comparison operators</li>
12277  * <li>Basic math function support</li>
12278  * <li>Execute arbitrary inline code with special built-in template variables</li>
12279  * <li>Custom member functions</li>
12280  * <li>Many special tags and built-in operators that aren't defined as part of
12281  * the API, but are supported in the templates that can be created</li>
12282  * </ul></div></p>
12283  * <p>XTemplate provides the templating mechanism built into:<div class="mdetail-params"><ul>
12284  * <li>{@link Ext.DataView}</li>
12285  * <li>{@link Ext.ListView}</li>
12286  * <li>{@link Ext.form.ComboBox}</li>
12287  * <li>{@link Ext.grid.TemplateColumn}</li>
12288  * <li>{@link Ext.grid.GroupingView}</li>
12289  * <li>{@link Ext.menu.Item}</li>
12290  * <li>{@link Ext.layout.MenuLayout}</li>
12291  * <li>{@link Ext.ColorPalette}</li>
12292  * </ul></div></p>
12293  * 
12294  * <p>For example usage {@link #XTemplate see the constructor}.</p>  
12295  *   
12296  * @constructor
12297  * The {@link Ext.Template#Template Ext.Template constructor} describes
12298  * the acceptable parameters to pass to the constructor. The following
12299  * examples demonstrate all of the supported features.</p>
12300  * 
12301  * <div class="mdetail-params"><ul>
12302  * 
12303  * <li><b><u>Sample Data</u></b> 
12304  * <div class="sub-desc">
12305  * <p>This is the data object used for reference in each code example:</p>
12306  * <pre><code>
12307 var data = {
12308     name: 'Jack Slocum',
12309     title: 'Lead Developer',
12310     company: 'Ext JS, LLC',
12311     email: 'jack@extjs.com',
12312     address: '4 Red Bulls Drive',
12313     city: 'Cleveland',
12314     state: 'Ohio',
12315     zip: '44102',
12316     drinks: ['Red Bull', 'Coffee', 'Water'],
12317     kids: [{
12318         name: 'Sara Grace',
12319         age:3
12320     },{
12321         name: 'Zachary',
12322         age:2
12323     },{
12324         name: 'John James',
12325         age:0
12326     }]
12327 };
12328  * </code></pre>
12329  * </div>
12330  * </li>
12331  * 
12332  * 
12333  * <li><b><u>Auto filling of arrays</u></b> 
12334  * <div class="sub-desc">
12335  * <p>The <b><tt>tpl</tt></b> tag and the <b><tt>for</tt></b> operator are used
12336  * to process the provided data object:
12337  * <ul>
12338  * <li>If the value specified in <tt>for</tt> is an array, it will auto-fill,
12339  * repeating the template block inside the <tt>tpl</tt> tag for each item in the
12340  * array.</li>
12341  * <li>If <tt>for="."</tt> is specified, the data object provided is examined.</li>
12342  * <li>While processing an array, the special variable <tt>{#}</tt>
12343  * will provide the current array index + 1 (starts at 1, not 0).</li>
12344  * </ul>
12345  * </p>
12346  * <pre><code>
12347 &lt;tpl <b>for</b>=".">...&lt;/tpl>       // loop through array at root node
12348 &lt;tpl <b>for</b>="foo">...&lt;/tpl>     // loop through array at foo node
12349 &lt;tpl <b>for</b>="foo.bar">...&lt;/tpl> // loop through array at foo.bar node
12350  * </code></pre>
12351  * Using the sample data above:
12352  * <pre><code>
12353 var tpl = new Ext.XTemplate(
12354     '&lt;p>Kids: ',
12355     '&lt;tpl <b>for</b>=".">',       // process the data.kids node
12356         '&lt;p>{#}. {name}&lt;/p>',  // use current array index to autonumber
12357     '&lt;/tpl>&lt;/p>'
12358 );
12359 tpl.overwrite(panel.body, data.kids); // pass the kids property of the data object
12360  * </code></pre>
12361  * <p>An example illustrating how the <b><tt>for</tt></b> property can be leveraged
12362  * to access specified members of the provided data object to populate the template:</p>
12363  * <pre><code>
12364 var tpl = new Ext.XTemplate(
12365     '&lt;p>Name: {name}&lt;/p>',
12366     '&lt;p>Title: {title}&lt;/p>',
12367     '&lt;p>Company: {company}&lt;/p>',
12368     '&lt;p>Kids: ',
12369     '&lt;tpl <b>for="kids"</b>>',     // interrogate the kids property within the data
12370         '&lt;p>{name}&lt;/p>',
12371     '&lt;/tpl>&lt;/p>'
12372 );
12373 tpl.overwrite(panel.body, data);  // pass the root node of the data object
12374  * </code></pre>
12375  * <p>Flat arrays that contain values (and not objects) can be auto-rendered
12376  * using the special <b><tt>{.}</tt></b> variable inside a loop.  This variable
12377  * will represent the value of the array at the current index:</p>
12378  * <pre><code>
12379 var tpl = new Ext.XTemplate(
12380     '&lt;p>{name}\&#39;s favorite beverages:&lt;/p>',
12381     '&lt;tpl for="drinks">',
12382        '&lt;div> - {.}&lt;/div>',
12383     '&lt;/tpl>'
12384 );
12385 tpl.overwrite(panel.body, data);
12386  * </code></pre>
12387  * <p>When processing a sub-template, for example while looping through a child array,
12388  * you can access the parent object's members via the <b><tt>parent</tt></b> object:</p>
12389  * <pre><code>
12390 var tpl = new Ext.XTemplate(
12391     '&lt;p>Name: {name}&lt;/p>',
12392     '&lt;p>Kids: ',
12393     '&lt;tpl for="kids">',
12394         '&lt;tpl if="age > 1">',
12395             '&lt;p>{name}&lt;/p>',
12396             '&lt;p>Dad: {<b>parent</b>.name}&lt;/p>',
12397         '&lt;/tpl>',
12398     '&lt;/tpl>&lt;/p>'
12399 );
12400 tpl.overwrite(panel.body, data);
12401  * </code></pre>
12402  * </div>
12403  * </li>
12404  * 
12405  * 
12406  * <li><b><u>Conditional processing with basic comparison operators</u></b> 
12407  * <div class="sub-desc">
12408  * <p>The <b><tt>tpl</tt></b> tag and the <b><tt>if</tt></b> operator are used
12409  * to provide conditional checks for deciding whether or not to render specific
12410  * parts of the template. Notes:<div class="sub-desc"><ul>
12411  * <li>Double quotes must be encoded if used within the conditional</li>
12412  * <li>There is no <tt>else</tt> operator &mdash; if needed, two opposite
12413  * <tt>if</tt> statements should be used.</li>
12414  * </ul></div>
12415  * <pre><code>
12416 &lt;tpl if="age &gt; 1 &amp;&amp; age &lt; 10">Child&lt;/tpl>
12417 &lt;tpl if="age >= 10 && age < 18">Teenager&lt;/tpl>
12418 &lt;tpl <b>if</b>="this.isGirl(name)">...&lt;/tpl>
12419 &lt;tpl <b>if</b>="id==\'download\'">...&lt;/tpl>
12420 &lt;tpl <b>if</b>="needsIcon">&lt;img src="{icon}" class="{iconCls}"/>&lt;/tpl>
12421 // no good:
12422 &lt;tpl if="name == "Jack"">Hello&lt;/tpl>
12423 // encode &#34; if it is part of the condition, e.g.
12424 &lt;tpl if="name == &#38;quot;Jack&#38;quot;">Hello&lt;/tpl>
12425  * </code></pre>
12426  * Using the sample data above:
12427  * <pre><code>
12428 var tpl = new Ext.XTemplate(
12429     '&lt;p>Name: {name}&lt;/p>',
12430     '&lt;p>Kids: ',
12431     '&lt;tpl for="kids">',
12432         '&lt;tpl if="age > 1">',
12433             '&lt;p>{name}&lt;/p>',
12434         '&lt;/tpl>',
12435     '&lt;/tpl>&lt;/p>'
12436 );
12437 tpl.overwrite(panel.body, data);
12438  * </code></pre>
12439  * </div>
12440  * </li>
12441  * 
12442  * 
12443  * <li><b><u>Basic math support</u></b> 
12444  * <div class="sub-desc">
12445  * <p>The following basic math operators may be applied directly on numeric
12446  * data values:</p><pre>
12447  * + - * /
12448  * </pre>
12449  * For example:
12450  * <pre><code>
12451 var tpl = new Ext.XTemplate(
12452     '&lt;p>Name: {name}&lt;/p>',
12453     '&lt;p>Kids: ',
12454     '&lt;tpl for="kids">',
12455         '&lt;tpl if="age &amp;gt; 1">',  // <-- Note that the &gt; is encoded
12456             '&lt;p>{#}: {name}&lt;/p>',  // <-- Auto-number each item
12457             '&lt;p>In 5 Years: {age+5}&lt;/p>',  // <-- Basic math
12458             '&lt;p>Dad: {parent.name}&lt;/p>',
12459         '&lt;/tpl>',
12460     '&lt;/tpl>&lt;/p>'
12461 );
12462 tpl.overwrite(panel.body, data);
12463 </code></pre>
12464  * </div>
12465  * </li>
12466  *
12467  * 
12468  * <li><b><u>Execute arbitrary inline code with special built-in template variables</u></b> 
12469  * <div class="sub-desc">
12470  * <p>Anything between <code>{[ ... ]}</code> is considered code to be executed
12471  * in the scope of the template. There are some special variables available in that code:
12472  * <ul>
12473  * <li><b><tt>values</tt></b>: The values in the current scope. If you are using
12474  * scope changing sub-templates, you can change what <tt>values</tt> is.</li>
12475  * <li><b><tt>parent</tt></b>: The scope (values) of the ancestor template.</li>
12476  * <li><b><tt>xindex</tt></b>: If you are in a looping template, the index of the
12477  * loop you are in (1-based).</li>
12478  * <li><b><tt>xcount</tt></b>: If you are in a looping template, the total length
12479  * of the array you are looping.</li>
12480  * <li><b><tt>fm</tt></b>: An alias for <tt>Ext.util.Format</tt>.</li>
12481  * </ul>
12482  * This example demonstrates basic row striping using an inline code block and the
12483  * <tt>xindex</tt> variable:</p>
12484  * <pre><code>
12485 var tpl = new Ext.XTemplate(
12486     '&lt;p>Name: {name}&lt;/p>',
12487     '&lt;p>Company: {[values.company.toUpperCase() + ", " + values.title]}&lt;/p>',
12488     '&lt;p>Kids: ',
12489     '&lt;tpl for="kids">',
12490        '&lt;div class="{[xindex % 2 === 0 ? "even" : "odd"]}">',
12491         '{name}',
12492         '&lt;/div>',
12493     '&lt;/tpl>&lt;/p>'
12494 );
12495 tpl.overwrite(panel.body, data);
12496  * </code></pre>
12497  * </div>
12498  * </li>
12499  * 
12500  * <li><b><u>Template member functions</u></b> 
12501  * <div class="sub-desc">
12502  * <p>One or more member functions can be specified in a configuration
12503  * object passed into the XTemplate constructor for more complex processing:</p>
12504  * <pre><code>
12505 var tpl = new Ext.XTemplate(
12506     '&lt;p>Name: {name}&lt;/p>',
12507     '&lt;p>Kids: ',
12508     '&lt;tpl for="kids">',
12509         '&lt;tpl if="this.isGirl(name)">',
12510             '&lt;p>Girl: {name} - {age}&lt;/p>',
12511         '&lt;/tpl>',
12512         // use opposite if statement to simulate 'else' processing:
12513         '&lt;tpl if="this.isGirl(name) == false">',
12514             '&lt;p>Boy: {name} - {age}&lt;/p>',
12515         '&lt;/tpl>',
12516         '&lt;tpl if="this.isBaby(age)">',
12517             '&lt;p>{name} is a baby!&lt;/p>',
12518         '&lt;/tpl>',
12519     '&lt;/tpl>&lt;/p>',
12520     {
12521         // XTemplate configuration:
12522         compiled: true,
12523         disableFormats: true,
12524         // member functions:
12525         isGirl: function(name){
12526             return name == 'Sara Grace';
12527         },
12528         isBaby: function(age){
12529             return age < 1;
12530         }
12531     }
12532 );
12533 tpl.overwrite(panel.body, data);
12534  * </code></pre>
12535  * </div>
12536  * </li>
12537  * 
12538  * </ul></div>
12539  * 
12540  * @param {Mixed} config
12541  */
12542 Ext.XTemplate = function(){
12543     Ext.XTemplate.superclass.constructor.apply(this, arguments);
12544
12545     var me = this,
12546         s = me.html,
12547         re = /<tpl\b[^>]*>((?:(?=([^<]+))\2|<(?!tpl\b[^>]*>))*?)<\/tpl>/,
12548         nameRe = /^<tpl\b[^>]*?for="(.*?)"/,
12549         ifRe = /^<tpl\b[^>]*?if="(.*?)"/,
12550         execRe = /^<tpl\b[^>]*?exec="(.*?)"/,
12551         m,
12552         id = 0,
12553         tpls = [],
12554         VALUES = 'values',
12555         PARENT = 'parent',
12556         XINDEX = 'xindex',
12557         XCOUNT = 'xcount',
12558         RETURN = 'return ',
12559         WITHVALUES = 'with(values){ ';
12560
12561     s = ['<tpl>', s, '</tpl>'].join('');
12562
12563     while((m = s.match(re))){
12564         var m2 = m[0].match(nameRe),
12565                         m3 = m[0].match(ifRe),
12566                 m4 = m[0].match(execRe),
12567                 exp = null,
12568                 fn = null,
12569                 exec = null,
12570                 name = m2 && m2[1] ? m2[1] : '';
12571
12572        if (m3) {
12573            exp = m3 && m3[1] ? m3[1] : null;
12574            if(exp){
12575                fn = new Function(VALUES, PARENT, XINDEX, XCOUNT, WITHVALUES + RETURN +(Ext.util.Format.htmlDecode(exp))+'; }');
12576            }
12577        }
12578        if (m4) {
12579            exp = m4 && m4[1] ? m4[1] : null;
12580            if(exp){
12581                exec = new Function(VALUES, PARENT, XINDEX, XCOUNT, WITHVALUES +(Ext.util.Format.htmlDecode(exp))+'; }');
12582            }
12583        }
12584        if(name){
12585            switch(name){
12586                case '.': name = new Function(VALUES, PARENT, WITHVALUES + RETURN + VALUES + '; }'); break;
12587                case '..': name = new Function(VALUES, PARENT, WITHVALUES + RETURN + PARENT + '; }'); break;
12588                default: name = new Function(VALUES, PARENT, WITHVALUES + RETURN + name + '; }');
12589            }
12590        }
12591        tpls.push({
12592             id: id,
12593             target: name,
12594             exec: exec,
12595             test: fn,
12596             body: m[1]||''
12597         });
12598        s = s.replace(m[0], '{xtpl'+ id + '}');
12599        ++id;
12600     }
12601         Ext.each(tpls, function(t) {
12602         me.compileTpl(t);
12603     });
12604     me.master = tpls[tpls.length-1];
12605     me.tpls = tpls;
12606 };
12607 Ext.extend(Ext.XTemplate, Ext.Template, {
12608     // private
12609     re : /\{([\w-\.\#]+)(?:\:([\w\.]*)(?:\((.*?)?\))?)?(\s?[\+\-\*\\]\s?[\d\.\+\-\*\\\(\)]+)?\}/g,
12610     // private
12611     codeRe : /\{\[((?:\\\]|.|\n)*?)\]\}/g,
12612
12613     // private
12614     applySubTemplate : function(id, values, parent, xindex, xcount){
12615         var me = this,
12616                 len,
12617                 t = me.tpls[id],
12618                 vs,
12619                 buf = [];
12620         if ((t.test && !t.test.call(me, values, parent, xindex, xcount)) ||
12621             (t.exec && t.exec.call(me, values, parent, xindex, xcount))) {
12622             return '';
12623         }
12624         vs = t.target ? t.target.call(me, values, parent) : values;
12625         len = vs.length;
12626         parent = t.target ? values : parent;
12627         if(t.target && Ext.isArray(vs)){
12628                 Ext.each(vs, function(v, i) {
12629                 buf[buf.length] = t.compiled.call(me, v, parent, i+1, len);
12630             });
12631             return buf.join('');
12632         }
12633         return t.compiled.call(me, vs, parent, xindex, xcount);
12634     },
12635
12636     // private
12637     compileTpl : function(tpl){
12638         var fm = Ext.util.Format,
12639                 useF = this.disableFormats !== true,
12640             sep = Ext.isGecko ? "+" : ",",
12641             body;
12642
12643         function fn(m, name, format, args, math){
12644             if(name.substr(0, 4) == 'xtpl'){
12645                 return "'"+ sep +'this.applySubTemplate('+name.substr(4)+', values, parent, xindex, xcount)'+sep+"'";
12646             }
12647             var v;
12648             if(name === '.'){
12649                 v = 'values';
12650             }else if(name === '#'){
12651                 v = 'xindex';
12652             }else if(name.indexOf('.') != -1){
12653                 v = name;
12654             }else{
12655                 v = "values['" + name + "']";
12656             }
12657             if(math){
12658                 v = '(' + v + math + ')';
12659             }
12660             if (format && useF) {
12661                 args = args ? ',' + args : "";
12662                 if(format.substr(0, 5) != "this."){
12663                     format = "fm." + format + '(';
12664                 }else{
12665                     format = 'this.call("'+ format.substr(5) + '", ';
12666                     args = ", values";
12667                 }
12668             } else {
12669                 args= ''; format = "("+v+" === undefined ? '' : ";
12670             }
12671             return "'"+ sep + format + v + args + ")"+sep+"'";
12672         }
12673
12674         function codeFn(m, code){
12675             // Single quotes get escaped when the template is compiled, however we want to undo this when running code.
12676             return "'" + sep + '(' + code.replace(/\\'/g, "'") + ')' + sep + "'";
12677         }
12678
12679         // branched to use + in gecko and [].join() in others
12680         if(Ext.isGecko){
12681             body = "tpl.compiled = function(values, parent, xindex, xcount){ return '" +
12682                    tpl.body.replace(/(\r\n|\n)/g, '\\n').replace(/'/g, "\\'").replace(this.re, fn).replace(this.codeRe, codeFn) +
12683                     "';};";
12684         }else{
12685             body = ["tpl.compiled = function(values, parent, xindex, xcount){ return ['"];
12686             body.push(tpl.body.replace(/(\r\n|\n)/g, '\\n').replace(/'/g, "\\'").replace(this.re, fn).replace(this.codeRe, codeFn));
12687             body.push("'].join('');};");
12688             body = body.join('');
12689         }
12690         eval(body);
12691         return this;
12692     },
12693
12694     /**
12695      * Returns an HTML fragment of this template with the specified values applied.
12696      * @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'})
12697      * @return {String} The HTML fragment
12698      */
12699     applyTemplate : function(values){
12700         return this.master.compiled.call(this, values, {}, 1, 1);
12701     },
12702
12703     /**
12704      * Compile the template to a function for optimized performance.  Recommended if the template will be used frequently.
12705      * @return {Function} The compiled function
12706      */
12707     compile : function(){return this;}
12708
12709     /**
12710      * @property re
12711      * @hide
12712      */
12713     /**
12714      * @property disableFormats
12715      * @hide
12716      */
12717     /**
12718      * @method set
12719      * @hide
12720      */
12721
12722 });
12723 /**
12724  * Alias for {@link #applyTemplate}
12725  * Returns an HTML fragment of this template with the specified values applied.
12726  * @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'})
12727  * @return {String} The HTML fragment
12728  * @member Ext.XTemplate
12729  * @method apply
12730  */
12731 Ext.XTemplate.prototype.apply = Ext.XTemplate.prototype.applyTemplate;
12732
12733 /**
12734  * Creates a template from the passed element's value (<i>display:none</i> textarea, preferred) or innerHTML.
12735  * @param {String/HTMLElement} el A DOM element or its id
12736  * @return {Ext.Template} The created template
12737  * @static
12738  */
12739 Ext.XTemplate.from = function(el){
12740     el = Ext.getDom(el);
12741     return new Ext.XTemplate(el.value || el.innerHTML);
12742 };/**\r
12743  * @class Ext.util.CSS\r
12744  * Utility class for manipulating CSS rules\r
12745  * @singleton\r
12746  */\r
12747 Ext.util.CSS = function(){\r
12748         var rules = null;\r
12749         var doc = document;\r
12750 \r
12751     var camelRe = /(-[a-z])/gi;\r
12752     var camelFn = function(m, a){ return a.charAt(1).toUpperCase(); };\r
12753 \r
12754    return {\r
12755    /**\r
12756     * Creates a stylesheet from a text blob of rules.\r
12757     * These rules will be wrapped in a STYLE tag and appended to the HEAD of the document.\r
12758     * @param {String} cssText The text containing the css rules\r
12759     * @param {String} id An id to add to the stylesheet for later removal\r
12760     * @return {StyleSheet}\r
12761     */\r
12762    createStyleSheet : function(cssText, id){\r
12763        var ss;\r
12764        var head = doc.getElementsByTagName("head")[0];\r
12765        var rules = doc.createElement("style");\r
12766        rules.setAttribute("type", "text/css");\r
12767        if(id){\r
12768            rules.setAttribute("id", id);\r
12769        }\r
12770        if(Ext.isIE){\r
12771            head.appendChild(rules);\r
12772            ss = rules.styleSheet;\r
12773            ss.cssText = cssText;\r
12774        }else{\r
12775            try{\r
12776                 rules.appendChild(doc.createTextNode(cssText));\r
12777            }catch(e){\r
12778                rules.cssText = cssText;\r
12779            }\r
12780            head.appendChild(rules);\r
12781            ss = rules.styleSheet ? rules.styleSheet : (rules.sheet || doc.styleSheets[doc.styleSheets.length-1]);\r
12782        }\r
12783        this.cacheStyleSheet(ss);\r
12784        return ss;\r
12785    },\r
12786 \r
12787    /**\r
12788     * Removes a style or link tag by id\r
12789     * @param {String} id The id of the tag\r
12790     */\r
12791    removeStyleSheet : function(id){\r
12792        var existing = doc.getElementById(id);\r
12793        if(existing){\r
12794            existing.parentNode.removeChild(existing);\r
12795        }\r
12796    },\r
12797 \r
12798    /**\r
12799     * Dynamically swaps an existing stylesheet reference for a new one\r
12800     * @param {String} id The id of an existing link tag to remove\r
12801     * @param {String} url The href of the new stylesheet to include\r
12802     */\r
12803    swapStyleSheet : function(id, url){\r
12804        this.removeStyleSheet(id);\r
12805        var ss = doc.createElement("link");\r
12806        ss.setAttribute("rel", "stylesheet");\r
12807        ss.setAttribute("type", "text/css");\r
12808        ss.setAttribute("id", id);\r
12809        ss.setAttribute("href", url);\r
12810        doc.getElementsByTagName("head")[0].appendChild(ss);\r
12811    },\r
12812    \r
12813    /**\r
12814     * Refresh the rule cache if you have dynamically added stylesheets\r
12815     * @return {Object} An object (hash) of rules indexed by selector\r
12816     */\r
12817    refreshCache : function(){\r
12818        return this.getRules(true);\r
12819    },\r
12820 \r
12821    // private\r
12822    cacheStyleSheet : function(ss){\r
12823        if(!rules){\r
12824            rules = {};\r
12825        }\r
12826        try{// try catch for cross domain access issue\r
12827            var ssRules = ss.cssRules || ss.rules;\r
12828            for(var j = ssRules.length-1; j >= 0; --j){\r
12829                rules[ssRules[j].selectorText.toLowerCase()] = ssRules[j];\r
12830            }\r
12831        }catch(e){}\r
12832    },\r
12833    \r
12834    /**\r
12835     * Gets all css rules for the document\r
12836     * @param {Boolean} refreshCache true to refresh the internal cache\r
12837     * @return {Object} An object (hash) of rules indexed by selector\r
12838     */\r
12839    getRules : function(refreshCache){\r
12840                 if(rules === null || refreshCache){\r
12841                         rules = {};\r
12842                         var ds = doc.styleSheets;\r
12843                         for(var i =0, len = ds.length; i < len; i++){\r
12844                             try{\r
12845                         this.cacheStyleSheet(ds[i]);\r
12846                     }catch(e){} \r
12847                 }\r
12848                 }\r
12849                 return rules;\r
12850         },\r
12851         \r
12852         /**\r
12853     * Gets an an individual CSS rule by selector(s)\r
12854     * @param {String/Array} selector The CSS selector or an array of selectors to try. The first selector that is found is returned.\r
12855     * @param {Boolean} refreshCache true to refresh the internal cache if you have recently updated any rules or added styles dynamically\r
12856     * @return {CSSRule} The CSS rule or null if one is not found\r
12857     */\r
12858    getRule : function(selector, refreshCache){\r
12859                 var rs = this.getRules(refreshCache);\r
12860                 if(!Ext.isArray(selector)){\r
12861                     return rs[selector.toLowerCase()];\r
12862                 }\r
12863                 for(var i = 0; i < selector.length; i++){\r
12864                         if(rs[selector[i]]){\r
12865                                 return rs[selector[i].toLowerCase()];\r
12866                         }\r
12867                 }\r
12868                 return null;\r
12869         },\r
12870         \r
12871         \r
12872         /**\r
12873     * Updates a rule property\r
12874     * @param {String/Array} selector If it's an array it tries each selector until it finds one. Stops immediately once one is found.\r
12875     * @param {String} property The css property\r
12876     * @param {String} value The new value for the property\r
12877     * @return {Boolean} true If a rule was found and updated\r
12878     */\r
12879    updateRule : function(selector, property, value){\r
12880                 if(!Ext.isArray(selector)){\r
12881                         var rule = this.getRule(selector);\r
12882                         if(rule){\r
12883                                 rule.style[property.replace(camelRe, camelFn)] = value;\r
12884                                 return true;\r
12885                         }\r
12886                 }else{\r
12887                         for(var i = 0; i < selector.length; i++){\r
12888                                 if(this.updateRule(selector[i], property, value)){\r
12889                                         return true;\r
12890                                 }\r
12891                         }\r
12892                 }\r
12893                 return false;\r
12894         }\r
12895    };   \r
12896 }();/**
12897  @class Ext.util.ClickRepeater
12898  @extends Ext.util.Observable
12899
12900  A wrapper class which can be applied to any element. Fires a "click" event while the
12901  mouse is pressed. The interval between firings may be specified in the config but
12902  defaults to 20 milliseconds.
12903
12904  Optionally, a CSS class may be applied to the element during the time it is pressed.
12905
12906  @cfg {Mixed} el The element to act as a button.
12907  @cfg {Number} delay The initial delay before the repeating event begins firing.
12908  Similar to an autorepeat key delay.
12909  @cfg {Number} interval The interval between firings of the "click" event. Default 20 ms.
12910  @cfg {String} pressClass A CSS class name to be applied to the element while pressed.
12911  @cfg {Boolean} accelerate True if autorepeating should start slowly and accelerate.
12912            "interval" and "delay" are ignored.
12913  @cfg {Boolean} preventDefault True to prevent the default click event
12914  @cfg {Boolean} stopDefault True to stop the default click event
12915
12916  @history
12917     2007-02-02 jvs Original code contributed by Nige "Animal" White
12918     2007-02-02 jvs Renamed to ClickRepeater
12919     2007-02-03 jvs Modifications for FF Mac and Safari
12920
12921  @constructor
12922  @param {Mixed} el The element to listen on
12923  @param {Object} config
12924  */
12925 Ext.util.ClickRepeater = function(el, config)
12926 {
12927     this.el = Ext.get(el);
12928     this.el.unselectable();
12929
12930     Ext.apply(this, config);
12931
12932     this.addEvents(
12933     /**
12934      * @event mousedown
12935      * Fires when the mouse button is depressed.
12936      * @param {Ext.util.ClickRepeater} this
12937      */
12938         "mousedown",
12939     /**
12940      * @event click
12941      * Fires on a specified interval during the time the element is pressed.
12942      * @param {Ext.util.ClickRepeater} this
12943      */
12944         "click",
12945     /**
12946      * @event mouseup
12947      * Fires when the mouse key is released.
12948      * @param {Ext.util.ClickRepeater} this
12949      */
12950         "mouseup"
12951     );
12952
12953     if(!this.disabled){
12954         this.disabled = true;
12955         this.enable();
12956     }
12957
12958     // allow inline handler
12959     if(this.handler){
12960         this.on("click", this.handler,  this.scope || this);
12961     }
12962
12963     Ext.util.ClickRepeater.superclass.constructor.call(this);
12964 };
12965
12966 Ext.extend(Ext.util.ClickRepeater, Ext.util.Observable, {
12967     interval : 20,
12968     delay: 250,
12969     preventDefault : true,
12970     stopDefault : false,
12971     timer : 0,
12972
12973     /**
12974      * Enables the repeater and allows events to fire.
12975      */
12976     enable: function(){
12977         if(this.disabled){
12978             this.el.on('mousedown', this.handleMouseDown, this);
12979             if(this.preventDefault || this.stopDefault){
12980                 this.el.on('click', this.eventOptions, this);
12981             }
12982         }
12983         this.disabled = false;
12984     },
12985     
12986     /**
12987      * Disables the repeater and stops events from firing.
12988      */
12989     disable: function(/* private */ force){
12990         if(force || !this.disabled){
12991             clearTimeout(this.timer);
12992             if(this.pressClass){
12993                 this.el.removeClass(this.pressClass);
12994             }
12995             Ext.getDoc().un('mouseup', this.handleMouseUp, this);
12996             this.el.removeAllListeners();
12997         }
12998         this.disabled = true;
12999     },
13000     
13001     /**
13002      * Convenience function for setting disabled/enabled by boolean.
13003      * @param {Boolean} disabled
13004      */
13005     setDisabled: function(disabled){
13006         this[disabled ? 'disable' : 'enable']();    
13007     },
13008     
13009     eventOptions: function(e){
13010         if(this.preventDefault){
13011             e.preventDefault();
13012         }
13013         if(this.stopDefault){
13014             e.stopEvent();
13015         }       
13016     },
13017     
13018     // private
13019     destroy : function() {
13020         this.disable(true);
13021         Ext.destroy(this.el);
13022         this.purgeListeners();
13023     },
13024     
13025     // private
13026     handleMouseDown : function(){
13027         clearTimeout(this.timer);
13028         this.el.blur();
13029         if(this.pressClass){
13030             this.el.addClass(this.pressClass);
13031         }
13032         this.mousedownTime = new Date();
13033
13034         Ext.getDoc().on("mouseup", this.handleMouseUp, this);
13035         this.el.on("mouseout", this.handleMouseOut, this);
13036
13037         this.fireEvent("mousedown", this);
13038         this.fireEvent("click", this);
13039
13040 //      Do not honor delay or interval if acceleration wanted.
13041         if (this.accelerate) {
13042             this.delay = 400;
13043             }
13044         this.timer = this.click.defer(this.delay || this.interval, this);
13045     },
13046
13047     // private
13048     click : function(){
13049         this.fireEvent("click", this);
13050         this.timer = this.click.defer(this.accelerate ?
13051             this.easeOutExpo(this.mousedownTime.getElapsed(),
13052                 400,
13053                 -390,
13054                 12000) :
13055             this.interval, this);
13056     },
13057
13058     easeOutExpo : function (t, b, c, d) {
13059         return (t==d) ? b+c : c * (-Math.pow(2, -10 * t/d) + 1) + b;
13060     },
13061
13062     // private
13063     handleMouseOut : function(){
13064         clearTimeout(this.timer);
13065         if(this.pressClass){
13066             this.el.removeClass(this.pressClass);
13067         }
13068         this.el.on("mouseover", this.handleMouseReturn, this);
13069     },
13070
13071     // private
13072     handleMouseReturn : function(){
13073         this.el.un("mouseover", this.handleMouseReturn, this);
13074         if(this.pressClass){
13075             this.el.addClass(this.pressClass);
13076         }
13077         this.click();
13078     },
13079
13080     // private
13081     handleMouseUp : function(){
13082         clearTimeout(this.timer);
13083         this.el.un("mouseover", this.handleMouseReturn, this);
13084         this.el.un("mouseout", this.handleMouseOut, this);
13085         Ext.getDoc().un("mouseup", this.handleMouseUp, this);
13086         this.el.removeClass(this.pressClass);
13087         this.fireEvent("mouseup", this);
13088     }
13089 });/**
13090  * @class Ext.KeyNav
13091  * <p>Provides a convenient wrapper for normalized keyboard navigation.  KeyNav allows you to bind
13092  * navigation keys to function calls that will get called when the keys are pressed, providing an easy
13093  * way to implement custom navigation schemes for any UI component.</p>
13094  * <p>The following are all of the possible keys that can be implemented: enter, left, right, up, down, tab, esc,
13095  * pageUp, pageDown, del, home, end.  Usage:</p>
13096  <pre><code>
13097 var nav = new Ext.KeyNav("my-element", {
13098     "left" : function(e){
13099         this.moveLeft(e.ctrlKey);
13100     },
13101     "right" : function(e){
13102         this.moveRight(e.ctrlKey);
13103     },
13104     "enter" : function(e){
13105         this.save();
13106     },
13107     scope : this
13108 });
13109 </code></pre>
13110  * @constructor
13111  * @param {Mixed} el The element to bind to
13112  * @param {Object} config The config
13113  */
13114 Ext.KeyNav = function(el, config){
13115     this.el = Ext.get(el);
13116     Ext.apply(this, config);
13117     if(!this.disabled){
13118         this.disabled = true;
13119         this.enable();
13120     }
13121 };
13122
13123 Ext.KeyNav.prototype = {
13124     /**
13125      * @cfg {Boolean} disabled
13126      * True to disable this KeyNav instance (defaults to false)
13127      */
13128     disabled : false,
13129     /**
13130      * @cfg {String} defaultEventAction
13131      * The method to call on the {@link Ext.EventObject} after this KeyNav intercepts a key.  Valid values are
13132      * {@link Ext.EventObject#stopEvent}, {@link Ext.EventObject#preventDefault} and
13133      * {@link Ext.EventObject#stopPropagation} (defaults to 'stopEvent')
13134      */
13135     defaultEventAction: "stopEvent",
13136     /**
13137      * @cfg {Boolean} forceKeyDown
13138      * Handle the keydown event instead of keypress (defaults to false).  KeyNav automatically does this for IE since
13139      * IE does not propagate special keys on keypress, but setting this to true will force other browsers to also
13140      * handle keydown instead of keypress.
13141      */
13142     forceKeyDown : false,
13143
13144     // private
13145     relay : function(e){
13146         var k = e.getKey();
13147         var h = this.keyToHandler[k];
13148         if(h && this[h]){
13149             if(this.doRelay(e, this[h], h) !== true){
13150                 e[this.defaultEventAction]();
13151             }
13152         }
13153     },
13154
13155     // private
13156     doRelay : function(e, h, hname){
13157         return h.call(this.scope || this, e);
13158     },
13159
13160     // possible handlers
13161     enter : false,
13162     left : false,
13163     right : false,
13164     up : false,
13165     down : false,
13166     tab : false,
13167     esc : false,
13168     pageUp : false,
13169     pageDown : false,
13170     del : false,
13171     home : false,
13172     end : false,
13173
13174     // quick lookup hash
13175     keyToHandler : {
13176         37 : "left",
13177         39 : "right",
13178         38 : "up",
13179         40 : "down",
13180         33 : "pageUp",
13181         34 : "pageDown",
13182         46 : "del",
13183         36 : "home",
13184         35 : "end",
13185         13 : "enter",
13186         27 : "esc",
13187         9  : "tab"
13188     },
13189     
13190     stopKeyUp: function(e) {
13191         var k = e.getKey();
13192
13193         if (k >= 37 && k <= 40) {
13194             // *** bugfix - safari 2.x fires 2 keyup events on cursor keys
13195             // *** (note: this bugfix sacrifices the "keyup" event originating from keyNav elements in Safari 2)
13196             e.stopEvent();
13197         }
13198     },
13199
13200         /**
13201          * Enable this KeyNav
13202          */
13203         enable: function() {
13204         if (this.disabled) {
13205             if (Ext.isSafari2) {
13206                 // call stopKeyUp() on "keyup" event
13207                 this.el.on('keyup', this.stopKeyUp, this);
13208             }
13209
13210             this.el.on(this.isKeydown()? 'keydown' : 'keypress', this.relay, this);
13211             this.disabled = false;
13212         }
13213     },
13214
13215         /**
13216          * Disable this KeyNav
13217          */
13218         disable: function() {
13219         if (!this.disabled) {
13220             if (Ext.isSafari2) {
13221                 // remove "keyup" event handler
13222                 this.el.un('keyup', this.stopKeyUp, this);
13223             }
13224
13225             this.el.un(this.isKeydown()? 'keydown' : 'keypress', this.relay, this);
13226             this.disabled = true;
13227         }
13228     },
13229     
13230     /**
13231      * Convenience function for setting disabled/enabled by boolean.
13232      * @param {Boolean} disabled
13233      */
13234     setDisabled : function(disabled){
13235         this[disabled ? "disable" : "enable"]();
13236     },
13237     
13238     // private
13239     isKeydown: function(){
13240         return this.forceKeyDown || Ext.EventManager.useKeydown;
13241     }
13242 };
13243 /**\r
13244  * @class Ext.KeyMap\r
13245  * Handles mapping keys to actions for an element. One key map can be used for multiple actions.\r
13246  * The constructor accepts the same config object as defined by {@link #addBinding}.\r
13247  * If you bind a callback function to a KeyMap, anytime the KeyMap handles an expected key\r
13248  * combination it will call the function with this signature (if the match is a multi-key\r
13249  * combination the callback will still be called only once): (String key, Ext.EventObject e)\r
13250  * A KeyMap can also handle a string representation of keys.<br />\r
13251  * Usage:\r
13252  <pre><code>\r
13253 // map one key by key code\r
13254 var map = new Ext.KeyMap("my-element", {\r
13255     key: 13, // or Ext.EventObject.ENTER\r
13256     fn: myHandler,\r
13257     scope: myObject\r
13258 });\r
13259 \r
13260 // map multiple keys to one action by string\r
13261 var map = new Ext.KeyMap("my-element", {\r
13262     key: "a\r\n\t",\r
13263     fn: myHandler,\r
13264     scope: myObject\r
13265 });\r
13266 \r
13267 // map multiple keys to multiple actions by strings and array of codes\r
13268 var map = new Ext.KeyMap("my-element", [\r
13269     {\r
13270         key: [10,13],\r
13271         fn: function(){ alert("Return was pressed"); }\r
13272     }, {\r
13273         key: "abc",\r
13274         fn: function(){ alert('a, b or c was pressed'); }\r
13275     }, {\r
13276         key: "\t",\r
13277         ctrl:true,\r
13278         shift:true,\r
13279         fn: function(){ alert('Control + shift + tab was pressed.'); }\r
13280     }\r
13281 ]);\r
13282 </code></pre>\r
13283  * <b>Note: A KeyMap starts enabled</b>\r
13284  * @constructor\r
13285  * @param {Mixed} el The element to bind to\r
13286  * @param {Object} config The config (see {@link #addBinding})\r
13287  * @param {String} eventName (optional) The event to bind to (defaults to "keydown")\r
13288  */\r
13289 Ext.KeyMap = function(el, config, eventName){\r
13290     this.el  = Ext.get(el);\r
13291     this.eventName = eventName || "keydown";\r
13292     this.bindings = [];\r
13293     if(config){\r
13294         this.addBinding(config);\r
13295     }\r
13296     this.enable();\r
13297 };\r
13298 \r
13299 Ext.KeyMap.prototype = {\r
13300     /**\r
13301      * True to stop the event from bubbling and prevent the default browser action if the\r
13302      * key was handled by the KeyMap (defaults to false)\r
13303      * @type Boolean\r
13304      */\r
13305     stopEvent : false,\r
13306 \r
13307     /**\r
13308      * Add a new binding to this KeyMap. The following config object properties are supported:\r
13309      * <pre>\r
13310 Property    Type             Description\r
13311 ----------  ---------------  ----------------------------------------------------------------------\r
13312 key         String/Array     A single keycode or an array of keycodes to handle\r
13313 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
13314 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
13315 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
13316 handler     Function         The function to call when KeyMap finds the expected key combination\r
13317 fn          Function         Alias of handler (for backwards-compatibility)\r
13318 scope       Object           The scope of the callback function\r
13319 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
13320 </pre>\r
13321      *\r
13322      * Usage:\r
13323      * <pre><code>\r
13324 // Create a KeyMap\r
13325 var map = new Ext.KeyMap(document, {\r
13326     key: Ext.EventObject.ENTER,\r
13327     fn: handleKey,\r
13328     scope: this\r
13329 });\r
13330 \r
13331 //Add a new binding to the existing KeyMap later\r
13332 map.addBinding({\r
13333     key: 'abc',\r
13334     shift: true,\r
13335     fn: handleKey,\r
13336     scope: this\r
13337 });\r
13338 </code></pre>\r
13339      * @param {Object/Array} config A single KeyMap config or an array of configs\r
13340      */\r
13341         addBinding : function(config){\r
13342         if(Ext.isArray(config)){\r
13343             Ext.each(config, function(c){\r
13344                 this.addBinding(c);\r
13345             }, this);\r
13346             return;\r
13347         }\r
13348         var keyCode = config.key,\r
13349             fn = config.fn || config.handler,\r
13350             scope = config.scope;\r
13351 \r
13352         if (config.stopEvent) {\r
13353             this.stopEvent = config.stopEvent;    \r
13354         }       \r
13355 \r
13356         if(typeof keyCode == "string"){\r
13357             var ks = [];\r
13358             var keyString = keyCode.toUpperCase();\r
13359             for(var j = 0, len = keyString.length; j < len; j++){\r
13360                 ks.push(keyString.charCodeAt(j));\r
13361             }\r
13362             keyCode = ks;\r
13363         }\r
13364         var keyArray = Ext.isArray(keyCode);\r
13365         \r
13366         var handler = function(e){\r
13367             if(this.checkModifiers(config, e)){\r
13368                 var k = e.getKey();\r
13369                 if(keyArray){\r
13370                     for(var i = 0, len = keyCode.length; i < len; i++){\r
13371                         if(keyCode[i] == k){\r
13372                           if(this.stopEvent){\r
13373                               e.stopEvent();\r
13374                           }\r
13375                           fn.call(scope || window, k, e);\r
13376                           return;\r
13377                         }\r
13378                     }\r
13379                 }else{\r
13380                     if(k == keyCode){\r
13381                         if(this.stopEvent){\r
13382                            e.stopEvent();\r
13383                         }\r
13384                         fn.call(scope || window, k, e);\r
13385                     }\r
13386                 }\r
13387             }\r
13388         };\r
13389         this.bindings.push(handler);\r
13390         },\r
13391     \r
13392     // private\r
13393     checkModifiers: function(config, e){\r
13394         var val, key, keys = ['shift', 'ctrl', 'alt'];\r
13395         for (var i = 0, len = keys.length; i < len; ++i){\r
13396             key = keys[i];\r
13397             val = config[key];\r
13398             if(!(val === undefined || (val === e[key + 'Key']))){\r
13399                 return false;\r
13400             }\r
13401         }\r
13402         return true;\r
13403     },\r
13404 \r
13405     /**\r
13406      * Shorthand for adding a single key listener\r
13407      * @param {Number/Array/Object} key Either the numeric key code, array of key codes or an object with the\r
13408      * following options:\r
13409      * {key: (number or array), shift: (true/false), ctrl: (true/false), alt: (true/false)}\r
13410      * @param {Function} fn The function to call\r
13411      * @param {Object} scope (optional) The scope of the function\r
13412      */\r
13413     on : function(key, fn, scope){\r
13414         var keyCode, shift, ctrl, alt;\r
13415         if(typeof key == "object" && !Ext.isArray(key)){\r
13416             keyCode = key.key;\r
13417             shift = key.shift;\r
13418             ctrl = key.ctrl;\r
13419             alt = key.alt;\r
13420         }else{\r
13421             keyCode = key;\r
13422         }\r
13423         this.addBinding({\r
13424             key: keyCode,\r
13425             shift: shift,\r
13426             ctrl: ctrl,\r
13427             alt: alt,\r
13428             fn: fn,\r
13429             scope: scope\r
13430         });\r
13431     },\r
13432 \r
13433     // private\r
13434     handleKeyDown : function(e){\r
13435             if(this.enabled){ //just in case\r
13436             var b = this.bindings;\r
13437             for(var i = 0, len = b.length; i < len; i++){\r
13438                 b[i].call(this, e);\r
13439             }\r
13440             }\r
13441         },\r
13442 \r
13443         /**\r
13444          * Returns true if this KeyMap is enabled\r
13445          * @return {Boolean}\r
13446          */\r
13447         isEnabled : function(){\r
13448             return this.enabled;\r
13449         },\r
13450 \r
13451         /**\r
13452          * Enables this KeyMap\r
13453          */\r
13454         enable: function(){\r
13455                 if(!this.enabled){\r
13456                     this.el.on(this.eventName, this.handleKeyDown, this);\r
13457                     this.enabled = true;\r
13458                 }\r
13459         },\r
13460 \r
13461         /**\r
13462          * Disable this KeyMap\r
13463          */\r
13464         disable: function(){\r
13465                 if(this.enabled){\r
13466                     this.el.removeListener(this.eventName, this.handleKeyDown, this);\r
13467                     this.enabled = false;\r
13468                 }\r
13469         },\r
13470     \r
13471     /**\r
13472      * Convenience function for setting disabled/enabled by boolean.\r
13473      * @param {Boolean} disabled\r
13474      */\r
13475     setDisabled : function(disabled){\r
13476         this[disabled ? "disable" : "enable"]();\r
13477     }\r
13478 };/**
13479  * @class Ext.util.TextMetrics
13480  * Provides precise pixel measurements for blocks of text so that you can determine exactly how high and
13481  * wide, in pixels, a given block of text will be. Note that when measuring text, it should be plain text and
13482  * should not contain any HTML, otherwise it may not be measured correctly.
13483  * @singleton
13484  */
13485 Ext.util.TextMetrics = function(){
13486     var shared;
13487     return {
13488         /**
13489          * Measures the size of the specified text
13490          * @param {String/HTMLElement} el The element, dom node or id from which to copy existing CSS styles
13491          * that can affect the size of the rendered text
13492          * @param {String} text The text to measure
13493          * @param {Number} fixedWidth (optional) If the text will be multiline, you have to set a fixed width
13494          * in order to accurately measure the text height
13495          * @return {Object} An object containing the text's size {width: (width), height: (height)}
13496          */
13497         measure : function(el, text, fixedWidth){
13498             if(!shared){
13499                 shared = Ext.util.TextMetrics.Instance(el, fixedWidth);
13500             }
13501             shared.bind(el);
13502             shared.setFixedWidth(fixedWidth || 'auto');
13503             return shared.getSize(text);
13504         },
13505
13506         /**
13507          * Return a unique TextMetrics instance that can be bound directly to an element and reused.  This reduces
13508          * the overhead of multiple calls to initialize the style properties on each measurement.
13509          * @param {String/HTMLElement} el The element, dom node or id that the instance will be bound to
13510          * @param {Number} fixedWidth (optional) If the text will be multiline, you have to set a fixed width
13511          * in order to accurately measure the text height
13512          * @return {Ext.util.TextMetrics.Instance} instance The new instance
13513          */
13514         createInstance : function(el, fixedWidth){
13515             return Ext.util.TextMetrics.Instance(el, fixedWidth);
13516         }
13517     };
13518 }();
13519
13520 Ext.util.TextMetrics.Instance = function(bindTo, fixedWidth){
13521     var ml = new Ext.Element(document.createElement('div'));
13522     document.body.appendChild(ml.dom);
13523     ml.position('absolute');
13524     ml.setLeftTop(-1000, -1000);
13525     ml.hide();
13526
13527     if(fixedWidth){
13528         ml.setWidth(fixedWidth);
13529     }
13530
13531     var instance = {
13532         /**
13533          * Returns the size of the specified text based on the internal element's style and width properties
13534          * @param {String} text The text to measure
13535          * @return {Object} An object containing the text's size {width: (width), height: (height)}
13536          */
13537         getSize : function(text){
13538             ml.update(text);
13539             var s = ml.getSize();
13540             ml.update('');
13541             return s;
13542         },
13543
13544         /**
13545          * Binds this TextMetrics instance to an element from which to copy existing CSS styles
13546          * that can affect the size of the rendered text
13547          * @param {String/HTMLElement} el The element, dom node or id
13548          */
13549         bind : function(el){
13550             ml.setStyle(
13551                 Ext.fly(el).getStyles('font-size','font-style', 'font-weight', 'font-family','line-height', 'text-transform', 'letter-spacing')
13552             );
13553         },
13554
13555         /**
13556          * Sets a fixed width on the internal measurement element.  If the text will be multiline, you have
13557          * to set a fixed width in order to accurately measure the text height.
13558          * @param {Number} width The width to set on the element
13559          */
13560         setFixedWidth : function(width){
13561             ml.setWidth(width);
13562         },
13563
13564         /**
13565          * Returns the measured width of the specified text
13566          * @param {String} text The text to measure
13567          * @return {Number} width The width in pixels
13568          */
13569         getWidth : function(text){
13570             ml.dom.style.width = 'auto';
13571             return this.getSize(text).width;
13572         },
13573
13574         /**
13575          * Returns the measured height of the specified text.  For multiline text, be sure to call
13576          * {@link #setFixedWidth} if necessary.
13577          * @param {String} text The text to measure
13578          * @return {Number} height The height in pixels
13579          */
13580         getHeight : function(text){
13581             return this.getSize(text).height;
13582         }
13583     };
13584
13585     instance.bind(bindTo);
13586
13587     return instance;
13588 };
13589
13590 Ext.Element.addMethods({
13591     /**
13592      * Returns the width in pixels of the passed text, or the width of the text in this Element.
13593      * @param {String} text The text to measure. Defaults to the innerHTML of the element.
13594      * @param {Number} min (Optional) The minumum value to return.
13595      * @param {Number} max (Optional) The maximum value to return.
13596      * @return {Number} The text width in pixels.
13597      * @member Ext.Element getTextWidth
13598      */
13599     getTextWidth : function(text, min, max){
13600         return (Ext.util.TextMetrics.measure(this.dom, Ext.value(text, this.dom.innerHTML, true)).width).constrain(min || 0, max || 1000000);
13601     }
13602 });
13603 /**\r
13604  * @class Ext.util.Cookies\r
13605  * Utility class for managing and interacting with cookies.\r
13606  * @singleton\r
13607  */\r
13608 Ext.util.Cookies = {\r
13609     /**\r
13610      * Create a cookie with the specified name and value. Additional settings\r
13611      * for the cookie may be optionally specified (for example: expiration,\r
13612      * access restriction, SSL).\r
13613      * @param {String} name The name of the cookie to set. \r
13614      * @param {Mixed} value The value to set for the cookie.\r
13615      * @param {Object} expires (Optional) Specify an expiration date the\r
13616      * cookie is to persist until.  Note that the specified Date object will\r
13617      * be converted to Greenwich Mean Time (GMT). \r
13618      * @param {String} path (Optional) Setting a path on the cookie restricts\r
13619      * access to pages that match that path. Defaults to all pages (<tt>'/'</tt>). \r
13620      * @param {String} domain (Optional) Setting a domain restricts access to\r
13621      * pages on a given domain (typically used to allow cookie access across\r
13622      * subdomains). For example, "extjs.com" will create a cookie that can be\r
13623      * accessed from any subdomain of extjs.com, including www.extjs.com,\r
13624      * support.extjs.com, etc.\r
13625      * @param {Boolean} secure (Optional) Specify true to indicate that the cookie\r
13626      * should only be accessible via SSL on a page using the HTTPS protocol.\r
13627      * Defaults to <tt>false</tt>. Note that this will only work if the page\r
13628      * calling this code uses the HTTPS protocol, otherwise the cookie will be\r
13629      * created with default options.\r
13630      */\r
13631     set : function(name, value){\r
13632         var argv = arguments;\r
13633         var argc = arguments.length;\r
13634         var expires = (argc > 2) ? argv[2] : null;\r
13635         var path = (argc > 3) ? argv[3] : '/';\r
13636         var domain = (argc > 4) ? argv[4] : null;\r
13637         var secure = (argc > 5) ? argv[5] : false;\r
13638         document.cookie = name + "=" + escape(value) + ((expires === null) ? "" : ("; expires=" + expires.toGMTString())) + ((path === null) ? "" : ("; path=" + path)) + ((domain === null) ? "" : ("; domain=" + domain)) + ((secure === true) ? "; secure" : "");\r
13639     },\r
13640 \r
13641     /**\r
13642      * Retrieves cookies that are accessible by the current page. If a cookie\r
13643      * does not exist, <code>get()</code> returns <tt>null</tt>.  The following\r
13644      * example retrieves the cookie called "valid" and stores the String value\r
13645      * in the variable <tt>validStatus</tt>.\r
13646      * <pre><code>\r
13647      * var validStatus = Ext.util.Cookies.get("valid");\r
13648      * </code></pre>\r
13649      * @param {String} name The name of the cookie to get\r
13650      * @return {Mixed} Returns the cookie value for the specified name;\r
13651      * null if the cookie name does not exist.\r
13652      */\r
13653     get : function(name){\r
13654         var arg = name + "=";\r
13655         var alen = arg.length;\r
13656         var clen = document.cookie.length;\r
13657         var i = 0;\r
13658         var j = 0;\r
13659         while(i < clen){\r
13660             j = i + alen;\r
13661             if(document.cookie.substring(i, j) == arg){\r
13662                 return Ext.util.Cookies.getCookieVal(j);\r
13663             }\r
13664             i = document.cookie.indexOf(" ", i) + 1;\r
13665             if(i === 0){\r
13666                 break;\r
13667             }\r
13668         }\r
13669         return null;\r
13670     },\r
13671 \r
13672     /**\r
13673      * Removes a cookie with the provided name from the browser\r
13674      * if found by setting its expiration date to sometime in the past. \r
13675      * @param {String} name The name of the cookie to remove\r
13676      */\r
13677     clear : function(name){\r
13678         if(Ext.util.Cookies.get(name)){\r
13679             document.cookie = name + "=" + "; expires=Thu, 01-Jan-70 00:00:01 GMT";\r
13680         }\r
13681     },\r
13682     /**\r
13683      * @private\r
13684      */\r
13685     getCookieVal : function(offset){\r
13686         var endstr = document.cookie.indexOf(";", offset);\r
13687         if(endstr == -1){\r
13688             endstr = document.cookie.length;\r
13689         }\r
13690         return unescape(document.cookie.substring(offset, endstr));\r
13691     }\r
13692 };/**
13693  * Framework-wide error-handler.  Developers can override this method to provide
13694  * custom exception-handling.  Framework errors will often extend from the base
13695  * Ext.Error class.
13696  * @param {Object/Error} e The thrown exception object.
13697  */
13698 Ext.handleError = function(e) {
13699     throw e;
13700 };
13701
13702 /**
13703  * @class Ext.Error
13704  * @extends Error
13705  * <p>A base error class. Future implementations are intended to provide more
13706  * robust error handling throughout the framework (<b>in the debug build only</b>)
13707  * to check for common errors and problems. The messages issued by this class
13708  * will aid error checking. Error checks will be automatically removed in the
13709  * production build so that performance is not negatively impacted.</p>
13710  * <p>Some sample messages currently implemented:</p><pre>
13711 "DataProxy attempted to execute an API-action but found an undefined
13712 url / function. Please review your Proxy url/api-configuration."
13713  * </pre><pre>
13714 "Could not locate your "root" property in your server response.
13715 Please review your JsonReader config to ensure the config-property
13716 "root" matches the property your server-response.  See the JsonReader
13717 docs for additional assistance."
13718  * </pre>
13719  * <p>An example of the code used for generating error messages:</p><pre><code>
13720 try {
13721     generateError({
13722         foo: 'bar'
13723     });
13724 }
13725 catch (e) {
13726     console.error(e);
13727 }
13728 function generateError(data) {
13729     throw new Ext.Error('foo-error', data);
13730 }
13731  * </code></pre>
13732  * @param {String} message
13733  */
13734 Ext.Error = function(message) {
13735     // Try to read the message from Ext.Error.lang
13736     this.message = (this.lang[message]) ? this.lang[message] : message;
13737 }
13738 Ext.Error.prototype = new Error();
13739 Ext.apply(Ext.Error.prototype, {
13740     // protected.  Extensions place their error-strings here.
13741     lang: {},
13742
13743     name: 'Ext.Error',
13744     /**
13745      * getName
13746      * @return {String}
13747      */
13748     getName : function() {
13749         return this.name;
13750     },
13751     /**
13752      * getMessage
13753      * @return {String}
13754      */
13755     getMessage : function() {
13756         return this.message;
13757     },
13758     /**
13759      * toJson
13760      * @return {String}
13761      */
13762     toJson : function() {
13763         return Ext.encode(this);
13764     }
13765 });
13766