Upgrade to ExtJS 3.3.1 - Released 11/30/2010
[extjs.git] / pkgs / ext-core-debug.js
1 /*!
2  * Ext JS Library 3.3.1
3  * Copyright(c) 2006-2010 Sencha Inc.
4  * licensing@sencha.com
5  * http://www.sencha.com/license
6  */
7 (function(){
8
9 var EXTUTIL = Ext.util,
10     EACH = Ext.each,
11     TRUE = true,
12     FALSE = false;
13 /**
14  * @class Ext.util.Observable
15  * Base class that provides a common interface for publishing events. Subclasses are expected to
16  * to have a property "events" with all the events defined, and, optionally, a property "listeners"
17  * with configured listeners defined.<br>
18  * For example:
19  * <pre><code>
20 Employee = Ext.extend(Ext.util.Observable, {
21     constructor: function(config){
22         this.name = config.name;
23         this.addEvents({
24             "fired" : true,
25             "quit" : true
26         });
27
28         // Copy configured listeners into *this* object so that the base class&#39;s
29         // constructor will add them.
30         this.listeners = config.listeners;
31
32         // Call our superclass constructor to complete construction process.
33         Employee.superclass.constructor.call(this, config)
34     }
35 });
36 </code></pre>
37  * This could then be used like this:<pre><code>
38 var newEmployee = new Employee({
39     name: employeeName,
40     listeners: {
41         quit: function() {
42             // By default, "this" will be the object that fired the event.
43             alert(this.name + " has quit!");
44         }
45     }
46 });
47 </code></pre>
48  */
49 EXTUTIL.Observable = function(){
50     /**
51      * @cfg {Object} listeners (optional) <p>A config object containing one or more event handlers to be added to this
52      * object during initialization.  This should be a valid listeners config object as specified in the
53      * {@link #addListener} example for attaching multiple handlers at once.</p>
54      * <br><p><b><u>DOM events from ExtJs {@link Ext.Component Components}</u></b></p>
55      * <br><p>While <i>some</i> ExtJs Component classes export selected DOM events (e.g. "click", "mouseover" etc), this
56      * is usually only done when extra value can be added. For example the {@link Ext.DataView DataView}'s
57      * <b><code>{@link Ext.DataView#click click}</code></b> event passing the node clicked on. To access DOM
58      * events directly from a Component's HTMLElement, listeners must be added to the <i>{@link Ext.Component#getEl Element}</i> after the Component
59      * has been rendered. A plugin can simplify this step:<pre><code>
60 // Plugin is configured with a listeners config object.
61 // The Component is appended to the argument list of all handler functions.
62 Ext.DomObserver = Ext.extend(Object, {
63     constructor: function(config) {
64         this.listeners = config.listeners ? config.listeners : config;
65     },
66
67     // Component passes itself into plugin&#39;s init method
68     init: function(c) {
69         var p, l = this.listeners;
70         for (p in l) {
71             if (Ext.isFunction(l[p])) {
72                 l[p] = this.createHandler(l[p], c);
73             } else {
74                 l[p].fn = this.createHandler(l[p].fn, c);
75             }
76         }
77
78         // Add the listeners to the Element immediately following the render call
79         c.render = c.render.{@link Function#createSequence createSequence}(function() {
80             var e = c.getEl();
81             if (e) {
82                 e.on(l);
83             }
84         });
85     },
86
87     createHandler: function(fn, c) {
88         return function(e) {
89             fn.call(this, e, c);
90         };
91     }
92 });
93
94 var combo = new Ext.form.ComboBox({
95
96     // Collapse combo when its element is clicked on
97     plugins: [ new Ext.DomObserver({
98         click: function(evt, comp) {
99             comp.collapse();
100         }
101     })],
102     store: myStore,
103     typeAhead: true,
104     mode: 'local',
105     triggerAction: 'all'
106 });
107      * </code></pre></p>
108      */
109     var me = this, e = me.events;
110     if(me.listeners){
111         me.on(me.listeners);
112         delete me.listeners;
113     }
114     me.events = e || {};
115 };
116
117 EXTUTIL.Observable.prototype = {
118     // private
119     filterOptRe : /^(?:scope|delay|buffer|single)$/,
120
121     /**
122      * <p>Fires the specified event with the passed parameters (minus the event name).</p>
123      * <p>An event may be set to bubble up an Observable parent hierarchy (See {@link Ext.Component#getBubbleTarget})
124      * by calling {@link #enableBubble}.</p>
125      * @param {String} eventName The name of the event to fire.
126      * @param {Object...} args Variable number of parameters are passed to handlers.
127      * @return {Boolean} returns false if any of the handlers return false otherwise it returns true.
128      */
129     fireEvent : function(){
130         var a = Array.prototype.slice.call(arguments, 0),
131             ename = a[0].toLowerCase(),
132             me = this,
133             ret = TRUE,
134             ce = me.events[ename],
135             cc,
136             q,
137             c;
138         if (me.eventsSuspended === TRUE) {
139             if (q = me.eventQueue) {
140                 q.push(a);
141             }
142         }
143         else if(typeof ce == 'object') {
144             if (ce.bubble){
145                 if(ce.fire.apply(ce, a.slice(1)) === FALSE) {
146                     return FALSE;
147                 }
148                 c = me.getBubbleTarget && me.getBubbleTarget();
149                 if(c && c.enableBubble) {
150                     cc = c.events[ename];
151                     if(!cc || typeof cc != 'object' || !cc.bubble) {
152                         c.enableBubble(ename);
153                     }
154                     return c.fireEvent.apply(c, a);
155                 }
156             }
157             else {
158                 a.shift();
159                 ret = ce.fire.apply(ce, a);
160             }
161         }
162         return ret;
163     },
164
165     /**
166      * Appends an event handler to this object.
167      * @param {String}   eventName The name of the event to listen for.
168      * @param {Function} handler The method the event invokes.
169      * @param {Object}   scope (optional) The scope (<code><b>this</b></code> reference) in which the handler function is executed.
170      * <b>If omitted, defaults to the object which fired the event.</b>
171      * @param {Object}   options (optional) An object containing handler configuration.
172      * properties. This may contain any of the following properties:<ul>
173      * <li><b>scope</b> : Object<div class="sub-desc">The scope (<code><b>this</b></code> reference) in which the handler function is executed.
174      * <b>If omitted, defaults to the object which fired the event.</b></div></li>
175      * <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>
176      * <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>
177      * <li><b>buffer</b> : Number<div class="sub-desc">Causes the handler to be scheduled to run in an {@link Ext.util.DelayedTask} delayed
178      * by the specified number of milliseconds. If the event fires again within that time, the original
179      * handler is <em>not</em> invoked, but the new handler is scheduled in its place.</div></li>
180      * <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>
181      * if the event was bubbled up from a child Observable.</div></li>
182      * </ul><br>
183      * <p>
184      * <b>Combining Options</b><br>
185      * Using the options argument, it is possible to combine different types of listeners:<br>
186      * <br>
187      * A delayed, one-time listener.
188      * <pre><code>
189 myDataView.on('click', this.onClick, this, {
190 single: true,
191 delay: 100
192 });</code></pre>
193      * <p>
194      * <b>Attaching multiple handlers in 1 call</b><br>
195      * The method also allows for a single argument to be passed which is a config object containing properties
196      * which specify multiple handlers.
197      * <p>
198      * <pre><code>
199 myGridPanel.on({
200 'click' : {
201     fn: this.onClick,
202     scope: this,
203     delay: 100
204 },
205 'mouseover' : {
206     fn: this.onMouseOver,
207     scope: this
208 },
209 'mouseout' : {
210     fn: this.onMouseOut,
211     scope: this
212 }
213 });</code></pre>
214  * <p>
215  * Or a shorthand syntax:<br>
216  * <pre><code>
217 myGridPanel.on({
218 'click' : this.onClick,
219 'mouseover' : this.onMouseOver,
220 'mouseout' : this.onMouseOut,
221  scope: this
222 });</code></pre>
223      */
224     addListener : function(eventName, fn, scope, o){
225         var me = this,
226             e,
227             oe,
228             ce;
229             
230         if (typeof eventName == 'object') {
231             o = eventName;
232             for (e in o) {
233                 oe = o[e];
234                 if (!me.filterOptRe.test(e)) {
235                     me.addListener(e, oe.fn || oe, oe.scope || o.scope, oe.fn ? oe : o);
236                 }
237             }
238         } else {
239             eventName = eventName.toLowerCase();
240             ce = me.events[eventName] || TRUE;
241             if (typeof ce == 'boolean') {
242                 me.events[eventName] = ce = new EXTUTIL.Event(me, eventName);
243             }
244             ce.addListener(fn, scope, typeof o == 'object' ? o : {});
245         }
246     },
247
248     /**
249      * Removes an event handler.
250      * @param {String}   eventName The type of event the handler was associated with.
251      * @param {Function} handler   The handler to remove. <b>This must be a reference to the function passed into the {@link #addListener} call.</b>
252      * @param {Object}   scope     (optional) The scope originally specified for the handler.
253      */
254     removeListener : function(eventName, fn, scope){
255         var ce = this.events[eventName.toLowerCase()];
256         if (typeof ce == 'object') {
257             ce.removeListener(fn, scope);
258         }
259     },
260
261     /**
262      * Removes all listeners for this object
263      */
264     purgeListeners : function(){
265         var events = this.events,
266             evt,
267             key;
268         for(key in events){
269             evt = events[key];
270             if(typeof evt == 'object'){
271                 evt.clearListeners();
272             }
273         }
274     },
275
276     /**
277      * Adds the specified events to the list of events which this Observable may fire.
278      * @param {Object|String} o Either an object with event names as properties with a value of <code>true</code>
279      * or the first event name string if multiple event names are being passed as separate parameters.
280      * @param {string} Optional. Event name if multiple event names are being passed as separate parameters.
281      * Usage:<pre><code>
282 this.addEvents('storeloaded', 'storecleared');
283 </code></pre>
284      */
285     addEvents : function(o){
286         var me = this;
287         me.events = me.events || {};
288         if (typeof o == 'string') {
289             var a = arguments,
290                 i = a.length;
291             while(i--) {
292                 me.events[a[i]] = me.events[a[i]] || TRUE;
293             }
294         } else {
295             Ext.applyIf(me.events, o);
296         }
297     },
298
299     /**
300      * Checks to see if this object has any listeners for a specified event
301      * @param {String} eventName The name of the event to check for
302      * @return {Boolean} True if the event is being listened for, else false
303      */
304     hasListener : function(eventName){
305         var e = this.events[eventName.toLowerCase()];
306         return typeof e == 'object' && e.listeners.length > 0;
307     },
308
309     /**
310      * Suspend the firing of all events. (see {@link #resumeEvents})
311      * @param {Boolean} queueSuspended Pass as true to queue up suspended events to be fired
312      * after the {@link #resumeEvents} call instead of discarding all suspended events;
313      */
314     suspendEvents : function(queueSuspended){
315         this.eventsSuspended = TRUE;
316         if(queueSuspended && !this.eventQueue){
317             this.eventQueue = [];
318         }
319     },
320
321     /**
322      * Resume firing events. (see {@link #suspendEvents})
323      * If events were suspended using the <tt><b>queueSuspended</b></tt> parameter, then all
324      * events fired during event suspension will be sent to any listeners now.
325      */
326     resumeEvents : function(){
327         var me = this,
328             queued = me.eventQueue || [];
329         me.eventsSuspended = FALSE;
330         delete me.eventQueue;
331         EACH(queued, function(e) {
332             me.fireEvent.apply(me, e);
333         });
334     }
335 };
336
337 var OBSERVABLE = EXTUTIL.Observable.prototype;
338 /**
339  * Appends an event handler to this object (shorthand for {@link #addListener}.)
340  * @param {String}   eventName     The type of event to listen for
341  * @param {Function} handler       The method the event invokes
342  * @param {Object}   scope         (optional) The scope (<code><b>this</b></code> reference) in which the handler function is executed.
343  * <b>If omitted, defaults to the object which fired the event.</b>
344  * @param {Object}   options       (optional) An object containing handler configuration.
345  * @method
346  */
347 OBSERVABLE.on = OBSERVABLE.addListener;
348 /**
349  * Removes an event handler (shorthand for {@link #removeListener}.)
350  * @param {String}   eventName     The type of event the handler was associated with.
351  * @param {Function} handler       The handler to remove. <b>This must be a reference to the function passed into the {@link #addListener} call.</b>
352  * @param {Object}   scope         (optional) The scope originally specified for the handler.
353  * @method
354  */
355 OBSERVABLE.un = OBSERVABLE.removeListener;
356
357 /**
358  * Removes <b>all</b> added captures from the Observable.
359  * @param {Observable} o The Observable to release
360  * @static
361  */
362 EXTUTIL.Observable.releaseCapture = function(o){
363     o.fireEvent = OBSERVABLE.fireEvent;
364 };
365
366 function createTargeted(h, o, scope){
367     return function(){
368         if(o.target == arguments[0]){
369             h.apply(scope, Array.prototype.slice.call(arguments, 0));
370         }
371     };
372 };
373
374 function createBuffered(h, o, l, scope){
375     l.task = new EXTUTIL.DelayedTask();
376     return function(){
377         l.task.delay(o.buffer, h, scope, Array.prototype.slice.call(arguments, 0));
378     };
379 };
380
381 function createSingle(h, e, fn, scope){
382     return function(){
383         e.removeListener(fn, scope);
384         return h.apply(scope, arguments);
385     };
386 };
387
388 function createDelayed(h, o, l, scope){
389     return function(){
390         var task = new EXTUTIL.DelayedTask(),
391             args = Array.prototype.slice.call(arguments, 0);
392         if(!l.tasks) {
393             l.tasks = [];
394         }
395         l.tasks.push(task);
396         task.delay(o.delay || 10, function(){
397             l.tasks.remove(task);
398             h.apply(scope, args);
399         }, scope);
400     };
401 };
402
403 EXTUTIL.Event = function(obj, name){
404     this.name = name;
405     this.obj = obj;
406     this.listeners = [];
407 };
408
409 EXTUTIL.Event.prototype = {
410     addListener : function(fn, scope, options){
411         var me = this,
412             l;
413         scope = scope || me.obj;
414         if(!me.isListening(fn, scope)){
415             l = me.createListener(fn, scope, options);
416             if(me.firing){ // if we are currently firing this event, don't disturb the listener loop
417                 me.listeners = me.listeners.slice(0);
418             }
419             me.listeners.push(l);
420         }
421     },
422
423     createListener: function(fn, scope, o){
424         o = o || {};
425         scope = scope || this.obj;
426         var l = {
427             fn: fn,
428             scope: scope,
429             options: o
430         }, h = fn;
431         if(o.target){
432             h = createTargeted(h, o, scope);
433         }
434         if(o.delay){
435             h = createDelayed(h, o, l, scope);
436         }
437         if(o.single){
438             h = createSingle(h, this, fn, scope);
439         }
440         if(o.buffer){
441             h = createBuffered(h, o, l, scope);
442         }
443         l.fireFn = h;
444         return l;
445     },
446
447     findListener : function(fn, scope){
448         var list = this.listeners,
449             i = list.length,
450             l;
451
452         scope = scope || this.obj;
453         while(i--){
454             l = list[i];
455             if(l){
456                 if(l.fn == fn && l.scope == scope){
457                     return i;
458                 }
459             }
460         }
461         return -1;
462     },
463
464     isListening : function(fn, scope){
465         return this.findListener(fn, scope) != -1;
466     },
467
468     removeListener : function(fn, scope){
469         var index,
470             l,
471             k,
472             me = this,
473             ret = FALSE;
474         if((index = me.findListener(fn, scope)) != -1){
475             if (me.firing) {
476                 me.listeners = me.listeners.slice(0);
477             }
478             l = me.listeners[index];
479             if(l.task) {
480                 l.task.cancel();
481                 delete l.task;
482             }
483             k = l.tasks && l.tasks.length;
484             if(k) {
485                 while(k--) {
486                     l.tasks[k].cancel();
487                 }
488                 delete l.tasks;
489             }
490             me.listeners.splice(index, 1);
491             ret = TRUE;
492         }
493         return ret;
494     },
495
496     // Iterate to stop any buffered/delayed events
497     clearListeners : function(){
498         var me = this,
499             l = me.listeners,
500             i = l.length;
501         while(i--) {
502             me.removeListener(l[i].fn, l[i].scope);
503         }
504     },
505
506     fire : function(){
507         var me = this,
508             listeners = me.listeners,
509             len = listeners.length,
510             i = 0,
511             l;
512
513         if(len > 0){
514             me.firing = TRUE;
515             var args = Array.prototype.slice.call(arguments, 0);
516             for (; i < len; i++) {
517                 l = listeners[i];
518                 if(l && l.fireFn.apply(l.scope || me.obj || window, args) === FALSE) {
519                     return (me.firing = FALSE);
520                 }
521             }
522         }
523         me.firing = FALSE;
524         return TRUE;
525     }
526
527 };
528 })();
529 /**
530  * @class Ext.DomHelper
531  * <p>The DomHelper class provides a layer of abstraction from DOM and transparently supports creating
532  * elements via DOM or using HTML fragments. It also has the ability to create HTML fragment templates
533  * from your DOM building code.</p>
534  *
535  * <p><b><u>DomHelper element specification object</u></b></p>
536  * <p>A specification object is used when creating elements. Attributes of this object
537  * are assumed to be element attributes, except for 4 special attributes:
538  * <div class="mdetail-params"><ul>
539  * <li><b><tt>tag</tt></b> : <div class="sub-desc">The tag name of the element</div></li>
540  * <li><b><tt>children</tt></b> : or <tt>cn</tt><div class="sub-desc">An array of the
541  * same kind of element definition objects to be created and appended. These can be nested
542  * as deep as you want.</div></li>
543  * <li><b><tt>cls</tt></b> : <div class="sub-desc">The class attribute of the element.
544  * This will end up being either the "class" attribute on a HTML fragment or className
545  * for a DOM node, depending on whether DomHelper is using fragments or DOM.</div></li>
546  * <li><b><tt>html</tt></b> : <div class="sub-desc">The innerHTML for the element</div></li>
547  * </ul></div></p>
548  *
549  * <p><b><u>Insertion methods</u></b></p>
550  * <p>Commonly used insertion methods:
551  * <div class="mdetail-params"><ul>
552  * <li><b><tt>{@link #append}</tt></b> : <div class="sub-desc"></div></li>
553  * <li><b><tt>{@link #insertBefore}</tt></b> : <div class="sub-desc"></div></li>
554  * <li><b><tt>{@link #insertAfter}</tt></b> : <div class="sub-desc"></div></li>
555  * <li><b><tt>{@link #overwrite}</tt></b> : <div class="sub-desc"></div></li>
556  * <li><b><tt>{@link #createTemplate}</tt></b> : <div class="sub-desc"></div></li>
557  * <li><b><tt>{@link #insertHtml}</tt></b> : <div class="sub-desc"></div></li>
558  * </ul></div></p>
559  *
560  * <p><b><u>Example</u></b></p>
561  * <p>This is an example, where an unordered list with 3 children items is appended to an existing
562  * element with id <tt>'my-div'</tt>:<br>
563  <pre><code>
564 var dh = Ext.DomHelper; // create shorthand alias
565 // specification object
566 var spec = {
567     id: 'my-ul',
568     tag: 'ul',
569     cls: 'my-list',
570     // append children after creating
571     children: [     // may also specify 'cn' instead of 'children'
572         {tag: 'li', id: 'item0', html: 'List Item 0'},
573         {tag: 'li', id: 'item1', html: 'List Item 1'},
574         {tag: 'li', id: 'item2', html: 'List Item 2'}
575     ]
576 };
577 var list = dh.append(
578     'my-div', // the context element 'my-div' can either be the id or the actual node
579     spec      // the specification object
580 );
581  </code></pre></p>
582  * <p>Element creation specification parameters in this class may also be passed as an Array of
583  * specification objects. This can be used to insert multiple sibling nodes into an existing
584  * container very efficiently. For example, to add more list items to the example above:<pre><code>
585 dh.append('my-ul', [
586     {tag: 'li', id: 'item3', html: 'List Item 3'},
587     {tag: 'li', id: 'item4', html: 'List Item 4'}
588 ]);
589  * </code></pre></p>
590  *
591  * <p><b><u>Templating</u></b></p>
592  * <p>The real power is in the built-in templating. Instead of creating or appending any elements,
593  * <tt>{@link #createTemplate}</tt> returns a Template object which can be used over and over to
594  * insert new elements. Revisiting the example above, we could utilize templating this time:
595  * <pre><code>
596 // create the node
597 var list = dh.append('my-div', {tag: 'ul', cls: 'my-list'});
598 // get template
599 var tpl = dh.createTemplate({tag: 'li', id: 'item{0}', html: 'List Item {0}'});
600
601 for(var i = 0; i < 5, i++){
602     tpl.append(list, [i]); // use template to append to the actual node
603 }
604  * </code></pre></p>
605  * <p>An example using a template:<pre><code>
606 var html = '<a id="{0}" href="{1}" class="nav">{2}</a>';
607
608 var tpl = new Ext.DomHelper.createTemplate(html);
609 tpl.append('blog-roll', ['link1', 'http://www.jackslocum.com/', "Jack&#39;s Site"]);
610 tpl.append('blog-roll', ['link2', 'http://www.dustindiaz.com/', "Dustin&#39;s Site"]);
611  * </code></pre></p>
612  *
613  * <p>The same example using named parameters:<pre><code>
614 var html = '<a id="{id}" href="{url}" class="nav">{text}</a>';
615
616 var tpl = new Ext.DomHelper.createTemplate(html);
617 tpl.append('blog-roll', {
618     id: 'link1',
619     url: 'http://www.jackslocum.com/',
620     text: "Jack&#39;s Site"
621 });
622 tpl.append('blog-roll', {
623     id: 'link2',
624     url: 'http://www.dustindiaz.com/',
625     text: "Dustin&#39;s Site"
626 });
627  * </code></pre></p>
628  *
629  * <p><b><u>Compiling Templates</u></b></p>
630  * <p>Templates are applied using regular expressions. The performance is great, but if
631  * you are adding a bunch of DOM elements using the same template, you can increase
632  * performance even further by {@link Ext.Template#compile "compiling"} the template.
633  * The way "{@link Ext.Template#compile compile()}" works is the template is parsed and
634  * broken up at the different variable points and a dynamic function is created and eval'ed.
635  * The generated function performs string concatenation of these parts and the passed
636  * variables instead of using regular expressions.
637  * <pre><code>
638 var html = '<a id="{id}" href="{url}" class="nav">{text}</a>';
639
640 var tpl = new Ext.DomHelper.createTemplate(html);
641 tpl.compile();
642
643 //... use template like normal
644  * </code></pre></p>
645  *
646  * <p><b><u>Performance Boost</u></b></p>
647  * <p>DomHelper will transparently create HTML fragments when it can. Using HTML fragments instead
648  * of DOM can significantly boost performance.</p>
649  * <p>Element creation specification parameters may also be strings. If {@link #useDom} is <tt>false</tt>,
650  * then the string is used as innerHTML. If {@link #useDom} is <tt>true</tt>, a string specification
651  * results in the creation of a text node. Usage:</p>
652  * <pre><code>
653 Ext.DomHelper.useDom = true; // force it to use DOM; reduces performance
654  * </code></pre>
655  * @singleton
656  */
657 Ext.DomHelper = function(){
658     var tempTableEl = null,
659         emptyTags = /^(?:br|frame|hr|img|input|link|meta|range|spacer|wbr|area|param|col)$/i,
660         tableRe = /^table|tbody|tr|td$/i,
661         confRe = /tag|children|cn|html$/i,
662         tableElRe = /td|tr|tbody/i,
663         cssRe = /([a-z0-9-]+)\s*:\s*([^;\s]+(?:\s*[^;\s]+)*);?/gi,
664         endRe = /end/i,
665         pub,
666         // kill repeat to save bytes
667         afterbegin = 'afterbegin',
668         afterend = 'afterend',
669         beforebegin = 'beforebegin',
670         beforeend = 'beforeend',
671         ts = '<table>',
672         te = '</table>',
673         tbs = ts+'<tbody>',
674         tbe = '</tbody>'+te,
675         trs = tbs + '<tr>',
676         tre = '</tr>'+tbe;
677
678     // private
679     function doInsert(el, o, returnElement, pos, sibling, append){
680         var newNode = pub.insertHtml(pos, Ext.getDom(el), createHtml(o));
681         return returnElement ? Ext.get(newNode, true) : newNode;
682     }
683
684     // build as innerHTML where available
685     function createHtml(o){
686         var b = '',
687             attr,
688             val,
689             key,
690             cn;
691
692         if(typeof o == "string"){
693             b = o;
694         } else if (Ext.isArray(o)) {
695             for (var i=0; i < o.length; i++) {
696                 if(o[i]) {
697                     b += createHtml(o[i]);
698                 }
699             };
700         } else {
701             b += '<' + (o.tag = o.tag || 'div');
702             for (attr in o) {
703                 val = o[attr];
704                 if(!confRe.test(attr)){
705                     if (typeof val == "object") {
706                         b += ' ' + attr + '="';
707                         for (key in val) {
708                             b += key + ':' + val[key] + ';';
709                         };
710                         b += '"';
711                     }else{
712                         b += ' ' + ({cls : 'class', htmlFor : 'for'}[attr] || attr) + '="' + val + '"';
713                     }
714                 }
715             };
716             // Now either just close the tag or try to add children and close the tag.
717             if (emptyTags.test(o.tag)) {
718                 b += '/>';
719             } else {
720                 b += '>';
721                 if ((cn = o.children || o.cn)) {
722                     b += createHtml(cn);
723                 } else if(o.html){
724                     b += o.html;
725                 }
726                 b += '</' + o.tag + '>';
727             }
728         }
729         return b;
730     }
731
732     function ieTable(depth, s, h, e){
733         tempTableEl.innerHTML = [s, h, e].join('');
734         var i = -1,
735             el = tempTableEl,
736             ns;
737         while(++i < depth){
738             el = el.firstChild;
739         }
740 //      If the result is multiple siblings, then encapsulate them into one fragment.
741         if(ns = el.nextSibling){
742             var df = document.createDocumentFragment();
743             while(el){
744                 ns = el.nextSibling;
745                 df.appendChild(el);
746                 el = ns;
747             }
748             el = df;
749         }
750         return el;
751     }
752
753     /**
754      * @ignore
755      * Nasty code for IE's broken table implementation
756      */
757     function insertIntoTable(tag, where, el, html) {
758         var node,
759             before;
760
761         tempTableEl = tempTableEl || document.createElement('div');
762
763         if(tag == 'td' && (where == afterbegin || where == beforeend) ||
764            !tableElRe.test(tag) && (where == beforebegin || where == afterend)) {
765             return;
766         }
767         before = where == beforebegin ? el :
768                  where == afterend ? el.nextSibling :
769                  where == afterbegin ? el.firstChild : null;
770
771         if (where == beforebegin || where == afterend) {
772             el = el.parentNode;
773         }
774
775         if (tag == 'td' || (tag == 'tr' && (where == beforeend || where == afterbegin))) {
776             node = ieTable(4, trs, html, tre);
777         } else if ((tag == 'tbody' && (where == beforeend || where == afterbegin)) ||
778                    (tag == 'tr' && (where == beforebegin || where == afterend))) {
779             node = ieTable(3, tbs, html, tbe);
780         } else {
781             node = ieTable(2, ts, html, te);
782         }
783         el.insertBefore(node, before);
784         return node;
785     }
786
787
788     pub = {
789         /**
790          * Returns the markup for the passed Element(s) config.
791          * @param {Object} o The DOM object spec (and children)
792          * @return {String}
793          */
794         markup : function(o){
795             return createHtml(o);
796         },
797
798         /**
799          * Applies a style specification to an element.
800          * @param {String/HTMLElement} el The element to apply styles to
801          * @param {String/Object/Function} styles A style specification string e.g. 'width:100px', or object in the form {width:'100px'}, or
802          * a function which returns such a specification.
803          */
804         applyStyles : function(el, styles){
805             if (styles) {
806                 var matches;
807
808                 el = Ext.fly(el);
809                 if (typeof styles == "function") {
810                     styles = styles.call();
811                 }
812                 if (typeof styles == "string") {
813                     /**
814                      * Since we're using the g flag on the regex, we need to set the lastIndex.
815                      * This automatically happens on some implementations, but not others, see:
816                      * http://stackoverflow.com/questions/2645273/javascript-regular-expression-literal-persists-between-function-calls
817                      * http://blog.stevenlevithan.com/archives/fixing-javascript-regexp
818                      */
819                     cssRe.lastIndex = 0;
820                     while ((matches = cssRe.exec(styles))) {
821                         el.setStyle(matches[1], matches[2]);
822                     }
823                 } else if (typeof styles == "object") {
824                     el.setStyle(styles);
825                 }
826             }
827         },
828
829         /**
830          * Inserts an HTML fragment into the DOM.
831          * @param {String} where Where to insert the html in relation to el - beforeBegin, afterBegin, beforeEnd, afterEnd.
832          * @param {HTMLElement} el The context element
833          * @param {String} html The HTML fragment
834          * @return {HTMLElement} The new node
835          */
836         insertHtml : function(where, el, html){
837             var hash = {},
838                 hashVal,
839                 setStart,
840                 range,
841                 frag,
842                 rangeEl,
843                 rs;
844
845             where = where.toLowerCase();
846             // add these here because they are used in both branches of the condition.
847             hash[beforebegin] = ['BeforeBegin', 'previousSibling'];
848             hash[afterend] = ['AfterEnd', 'nextSibling'];
849
850             if (el.insertAdjacentHTML) {
851                 if(tableRe.test(el.tagName) && (rs = insertIntoTable(el.tagName.toLowerCase(), where, el, html))){
852                     return rs;
853                 }
854                 // add these two to the hash.
855                 hash[afterbegin] = ['AfterBegin', 'firstChild'];
856                 hash[beforeend] = ['BeforeEnd', 'lastChild'];
857                 if ((hashVal = hash[where])) {
858                     el.insertAdjacentHTML(hashVal[0], html);
859                     return el[hashVal[1]];
860                 }
861             } else {
862                 range = el.ownerDocument.createRange();
863                 setStart = 'setStart' + (endRe.test(where) ? 'After' : 'Before');
864                 if (hash[where]) {
865                     range[setStart](el);
866                     frag = range.createContextualFragment(html);
867                     el.parentNode.insertBefore(frag, where == beforebegin ? el : el.nextSibling);
868                     return el[(where == beforebegin ? 'previous' : 'next') + 'Sibling'];
869                 } else {
870                     rangeEl = (where == afterbegin ? 'first' : 'last') + 'Child';
871                     if (el.firstChild) {
872                         range[setStart](el[rangeEl]);
873                         frag = range.createContextualFragment(html);
874                         if(where == afterbegin){
875                             el.insertBefore(frag, el.firstChild);
876                         }else{
877                             el.appendChild(frag);
878                         }
879                     } else {
880                         el.innerHTML = html;
881                     }
882                     return el[rangeEl];
883                 }
884             }
885             throw 'Illegal insertion point -> "' + where + '"';
886         },
887
888         /**
889          * Creates new DOM element(s) and inserts them before el.
890          * @param {Mixed} el The context element
891          * @param {Object/String} o The DOM object spec (and children) or raw HTML blob
892          * @param {Boolean} returnElement (optional) true to return a Ext.Element
893          * @return {HTMLElement/Ext.Element} The new node
894          */
895         insertBefore : function(el, o, returnElement){
896             return doInsert(el, o, returnElement, beforebegin);
897         },
898
899         /**
900          * Creates new DOM element(s) and inserts them after el.
901          * @param {Mixed} el The context element
902          * @param {Object} o The DOM object spec (and children)
903          * @param {Boolean} returnElement (optional) true to return a Ext.Element
904          * @return {HTMLElement/Ext.Element} The new node
905          */
906         insertAfter : function(el, o, returnElement){
907             return doInsert(el, o, returnElement, afterend, 'nextSibling');
908         },
909
910         /**
911          * Creates new DOM element(s) and inserts them as the first child of el.
912          * @param {Mixed} el The context element
913          * @param {Object/String} o The DOM object spec (and children) or raw HTML blob
914          * @param {Boolean} returnElement (optional) true to return a Ext.Element
915          * @return {HTMLElement/Ext.Element} The new node
916          */
917         insertFirst : function(el, o, returnElement){
918             return doInsert(el, o, returnElement, afterbegin, 'firstChild');
919         },
920
921         /**
922          * Creates new DOM element(s) and appends them to el.
923          * @param {Mixed} el The context element
924          * @param {Object/String} o The DOM object spec (and children) or raw HTML blob
925          * @param {Boolean} returnElement (optional) true to return a Ext.Element
926          * @return {HTMLElement/Ext.Element} The new node
927          */
928         append : function(el, o, returnElement){
929             return doInsert(el, o, returnElement, beforeend, '', true);
930         },
931
932         /**
933          * Creates new DOM element(s) and overwrites the contents of el with them.
934          * @param {Mixed} el The context element
935          * @param {Object/String} o The DOM object spec (and children) or raw HTML blob
936          * @param {Boolean} returnElement (optional) true to return a Ext.Element
937          * @return {HTMLElement/Ext.Element} The new node
938          */
939         overwrite : function(el, o, returnElement){
940             el = Ext.getDom(el);
941             el.innerHTML = createHtml(o);
942             return returnElement ? Ext.get(el.firstChild) : el.firstChild;
943         },
944
945         createHtml : createHtml
946     };
947     return pub;
948 }();
949 /**
950  * @class Ext.Template
951  * <p>Represents an HTML fragment template. Templates may be {@link #compile precompiled}
952  * for greater performance.</p>
953  * <p>For example usage {@link #Template see the constructor}.</p>
954  *
955  * @constructor
956  * An instance of this class may be created by passing to the constructor either
957  * a single argument, or multiple arguments:
958  * <div class="mdetail-params"><ul>
959  * <li><b>single argument</b> : String/Array
960  * <div class="sub-desc">
961  * The single argument may be either a String or an Array:<ul>
962  * <li><tt>String</tt> : </li><pre><code>
963 var t = new Ext.Template("&lt;div>Hello {0}.&lt;/div>");
964 t.{@link #append}('some-element', ['foo']);
965  * </code></pre>
966  * <li><tt>Array</tt> : </li>
967  * An Array will be combined with <code>join('')</code>.
968 <pre><code>
969 var t = new Ext.Template([
970     '&lt;div name="{id}"&gt;',
971         '&lt;span class="{cls}"&gt;{name:trim} {value:ellipsis(10)}&lt;/span&gt;',
972     '&lt;/div&gt;',
973 ]);
974 t.{@link #compile}();
975 t.{@link #append}('some-element', {id: 'myid', cls: 'myclass', name: 'foo', value: 'bar'});
976 </code></pre>
977  * </ul></div></li>
978  * <li><b>multiple arguments</b> : String, Object, Array, ...
979  * <div class="sub-desc">
980  * Multiple arguments will be combined with <code>join('')</code>.
981  * <pre><code>
982 var t = new Ext.Template(
983     '&lt;div name="{id}"&gt;',
984         '&lt;span class="{cls}"&gt;{name} {value}&lt;/span&gt;',
985     '&lt;/div&gt;',
986     // a configuration object:
987     {
988         compiled: true,      // {@link #compile} immediately
989         disableFormats: true // See Notes below.
990     }
991 );
992  * </code></pre>
993  * <p><b>Notes</b>:</p>
994  * <div class="mdetail-params"><ul>
995  * <li>Formatting and <code>disableFormats</code> are not applicable for Ext Core.</li>
996  * <li>For a list of available format functions, see {@link Ext.util.Format}.</li>
997  * <li><code>disableFormats</code> reduces <code>{@link #apply}</code> time
998  * when no formatting is required.</li>
999  * </ul></div>
1000  * </div></li>
1001  * </ul></div>
1002  * @param {Mixed} config
1003  */
1004 Ext.Template = function(html){
1005     var me = this,
1006         a = arguments,
1007         buf = [],
1008         v;
1009
1010     if (Ext.isArray(html)) {
1011         html = html.join("");
1012     } else if (a.length > 1) {
1013         for(var i = 0, len = a.length; i < len; i++){
1014             v = a[i];
1015             if(typeof v == 'object'){
1016                 Ext.apply(me, v);
1017             } else {
1018                 buf.push(v);
1019             }
1020         };
1021         html = buf.join('');
1022     }
1023
1024     /**@private*/
1025     me.html = html;
1026     /**
1027      * @cfg {Boolean} compiled Specify <tt>true</tt> to compile the template
1028      * immediately (see <code>{@link #compile}</code>).
1029      * Defaults to <tt>false</tt>.
1030      */
1031     if (me.compiled) {
1032         me.compile();
1033     }
1034 };
1035 Ext.Template.prototype = {
1036     /**
1037      * @cfg {RegExp} re The regular expression used to match template variables.
1038      * Defaults to:<pre><code>
1039      * re : /\{([\w-]+)\}/g                                     // for Ext Core
1040      * re : /\{([\w-]+)(?:\:([\w\.]*)(?:\((.*?)?\))?)?\}/g      // for Ext JS
1041      * </code></pre>
1042      */
1043     re : /\{([\w-]+)\}/g,
1044     /**
1045      * See <code>{@link #re}</code>.
1046      * @type RegExp
1047      * @property re
1048      */
1049
1050     /**
1051      * Returns an HTML fragment of this template with the specified <code>values</code> applied.
1052      * @param {Object/Array} values
1053      * The template values. Can be an array if the params are numeric (i.e. <code>{0}</code>)
1054      * or an object (i.e. <code>{foo: 'bar'}</code>).
1055      * @return {String} The HTML fragment
1056      */
1057     applyTemplate : function(values){
1058         var me = this;
1059
1060         return me.compiled ?
1061                 me.compiled(values) :
1062                 me.html.replace(me.re, function(m, name){
1063                     return values[name] !== undefined ? values[name] : "";
1064                 });
1065     },
1066
1067     /**
1068      * Sets the HTML used as the template and optionally compiles it.
1069      * @param {String} html
1070      * @param {Boolean} compile (optional) True to compile the template (defaults to undefined)
1071      * @return {Ext.Template} this
1072      */
1073     set : function(html, compile){
1074         var me = this;
1075         me.html = html;
1076         me.compiled = null;
1077         return compile ? me.compile() : me;
1078     },
1079
1080     /**
1081      * Compiles the template into an internal function, eliminating the RegEx overhead.
1082      * @return {Ext.Template} this
1083      */
1084     compile : function(){
1085         var me = this,
1086             sep = Ext.isGecko ? "+" : ",";
1087
1088         function fn(m, name){
1089             name = "values['" + name + "']";
1090             return "'"+ sep + '(' + name + " == undefined ? '' : " + name + ')' + sep + "'";
1091         }
1092
1093         eval("this.compiled = function(values){ return " + (Ext.isGecko ? "'" : "['") +
1094              me.html.replace(/\\/g, '\\\\').replace(/(\r\n|\n)/g, '\\n').replace(/'/g, "\\'").replace(this.re, fn) +
1095              (Ext.isGecko ?  "';};" : "'].join('');};"));
1096         return me;
1097     },
1098
1099     /**
1100      * Applies the supplied values to the template and inserts the new node(s) as the first child of el.
1101      * @param {Mixed} el The context element
1102      * @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'})
1103      * @param {Boolean} returnElement (optional) true to return a Ext.Element (defaults to undefined)
1104      * @return {HTMLElement/Ext.Element} The new node or Element
1105      */
1106     insertFirst: function(el, values, returnElement){
1107         return this.doInsert('afterBegin', el, values, returnElement);
1108     },
1109
1110     /**
1111      * Applies the supplied values to the template and inserts the new node(s) before el.
1112      * @param {Mixed} el The context element
1113      * @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'})
1114      * @param {Boolean} returnElement (optional) true to return a Ext.Element (defaults to undefined)
1115      * @return {HTMLElement/Ext.Element} The new node or Element
1116      */
1117     insertBefore: function(el, values, returnElement){
1118         return this.doInsert('beforeBegin', el, values, returnElement);
1119     },
1120
1121     /**
1122      * Applies the supplied values to the template and inserts the new node(s) after el.
1123      * @param {Mixed} el The context element
1124      * @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'})
1125      * @param {Boolean} returnElement (optional) true to return a Ext.Element (defaults to undefined)
1126      * @return {HTMLElement/Ext.Element} The new node or Element
1127      */
1128     insertAfter : function(el, values, returnElement){
1129         return this.doInsert('afterEnd', el, values, returnElement);
1130     },
1131
1132     /**
1133      * Applies the supplied <code>values</code> to the template and appends
1134      * the new node(s) to the specified <code>el</code>.
1135      * <p>For example usage {@link #Template see the constructor}.</p>
1136      * @param {Mixed} el The context element
1137      * @param {Object/Array} values
1138      * The template values. Can be an array if the params are numeric (i.e. <code>{0}</code>)
1139      * or an object (i.e. <code>{foo: 'bar'}</code>).
1140      * @param {Boolean} returnElement (optional) true to return an Ext.Element (defaults to undefined)
1141      * @return {HTMLElement/Ext.Element} The new node or Element
1142      */
1143     append : function(el, values, returnElement){
1144         return this.doInsert('beforeEnd', el, values, returnElement);
1145     },
1146
1147     doInsert : function(where, el, values, returnEl){
1148         el = Ext.getDom(el);
1149         var newNode = Ext.DomHelper.insertHtml(where, el, this.applyTemplate(values));
1150         return returnEl ? Ext.get(newNode, true) : newNode;
1151     },
1152
1153     /**
1154      * Applies the supplied values to the template and overwrites the content of el with the new node(s).
1155      * @param {Mixed} el The context element
1156      * @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'})
1157      * @param {Boolean} returnElement (optional) true to return a Ext.Element (defaults to undefined)
1158      * @return {HTMLElement/Ext.Element} The new node or Element
1159      */
1160     overwrite : function(el, values, returnElement){
1161         el = Ext.getDom(el);
1162         el.innerHTML = this.applyTemplate(values);
1163         return returnElement ? Ext.get(el.firstChild, true) : el.firstChild;
1164     }
1165 };
1166 /**
1167  * Alias for {@link #applyTemplate}
1168  * Returns an HTML fragment of this template with the specified <code>values</code> applied.
1169  * @param {Object/Array} values
1170  * The template values. Can be an array if the params are numeric (i.e. <code>{0}</code>)
1171  * or an object (i.e. <code>{foo: 'bar'}</code>).
1172  * @return {String} The HTML fragment
1173  * @member Ext.Template
1174  * @method apply
1175  */
1176 Ext.Template.prototype.apply = Ext.Template.prototype.applyTemplate;
1177
1178 /**
1179  * Creates a template from the passed element's value (<i>display:none</i> textarea, preferred) or innerHTML.
1180  * @param {String/HTMLElement} el A DOM element or its id
1181  * @param {Object} config A configuration object
1182  * @return {Ext.Template} The created template
1183  * @static
1184  */
1185 Ext.Template.from = function(el, config){
1186     el = Ext.getDom(el);
1187     return new Ext.Template(el.value || el.innerHTML, config || '');
1188 };
1189 /*
1190  * This is code is also distributed under MIT license for use
1191  * with jQuery and prototype JavaScript libraries.
1192  */
1193 /**
1194  * @class Ext.DomQuery
1195 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).
1196 <p>
1197 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>
1198
1199 <p>
1200 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.
1201 </p>
1202 <h4>Element Selectors:</h4>
1203 <ul class="list">
1204     <li> <b>*</b> any element</li>
1205     <li> <b>E</b> an element with the tag E</li>
1206     <li> <b>E F</b> All descendent elements of E that have the tag F</li>
1207     <li> <b>E > F</b> or <b>E/F</b> all direct children elements of E that have the tag F</li>
1208     <li> <b>E + F</b> all elements with the tag F that are immediately preceded by an element with the tag E</li>
1209     <li> <b>E ~ F</b> all elements with the tag F that are preceded by a sibling element with the tag E</li>
1210 </ul>
1211 <h4>Attribute Selectors:</h4>
1212 <p>The use of &#64; and quotes are optional. For example, div[&#64;foo='bar'] is also a valid attribute selector.</p>
1213 <ul class="list">
1214     <li> <b>E[foo]</b> has an attribute "foo"</li>
1215     <li> <b>E[foo=bar]</b> has an attribute "foo" that equals "bar"</li>
1216     <li> <b>E[foo^=bar]</b> has an attribute "foo" that starts with "bar"</li>
1217     <li> <b>E[foo$=bar]</b> has an attribute "foo" that ends with "bar"</li>
1218     <li> <b>E[foo*=bar]</b> has an attribute "foo" that contains the substring "bar"</li>
1219     <li> <b>E[foo%=2]</b> has an attribute "foo" that is evenly divisible by 2</li>
1220     <li> <b>E[foo!=bar]</b> attribute "foo" does not equal "bar"</li>
1221 </ul>
1222 <h4>Pseudo Classes:</h4>
1223 <ul class="list">
1224     <li> <b>E:first-child</b> E is the first child of its parent</li>
1225     <li> <b>E:last-child</b> E is the last child of its parent</li>
1226     <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>
1227     <li> <b>E:nth-child(odd)</b> E is an odd child of its parent</li>
1228     <li> <b>E:nth-child(even)</b> E is an even child of its parent</li>
1229     <li> <b>E:only-child</b> E is the only child of its parent</li>
1230     <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>
1231     <li> <b>E:first</b> the first E in the resultset</li>
1232     <li> <b>E:last</b> the last E in the resultset</li>
1233     <li> <b>E:nth(<i>n</i>)</b> the <i>n</i>th E in the resultset (1 based)</li>
1234     <li> <b>E:odd</b> shortcut for :nth-child(odd)</li>
1235     <li> <b>E:even</b> shortcut for :nth-child(even)</li>
1236     <li> <b>E:contains(foo)</b> E's innerHTML contains the substring "foo"</li>
1237     <li> <b>E:nodeValue(foo)</b> E contains a textNode with a nodeValue that equals "foo"</li>
1238     <li> <b>E:not(S)</b> an E element that does not match simple selector S</li>
1239     <li> <b>E:has(S)</b> an E element that has a descendent that matches simple selector S</li>
1240     <li> <b>E:next(S)</b> an E element whose next sibling matches simple selector S</li>
1241     <li> <b>E:prev(S)</b> an E element whose previous sibling matches simple selector S</li>
1242     <li> <b>E:any(S1|S2|S2)</b> an E element which matches any of the simple selectors S1, S2 or S3//\\</li>
1243 </ul>
1244 <h4>CSS Value Selectors:</h4>
1245 <ul class="list">
1246     <li> <b>E{display=none}</b> css value "display" that equals "none"</li>
1247     <li> <b>E{display^=none}</b> css value "display" that starts with "none"</li>
1248     <li> <b>E{display$=none}</b> css value "display" that ends with "none"</li>
1249     <li> <b>E{display*=none}</b> css value "display" that contains the substring "none"</li>
1250     <li> <b>E{display%=2}</b> css value "display" that is evenly divisible by 2</li>
1251     <li> <b>E{display!=none}</b> css value "display" that does not equal "none"</li>
1252 </ul>
1253  * @singleton
1254  */
1255 Ext.DomQuery = function(){
1256     var cache = {}, 
1257         simpleCache = {}, 
1258         valueCache = {},
1259         nonSpace = /\S/,
1260         trimRe = /^\s+|\s+$/g,
1261         tplRe = /\{(\d+)\}/g,
1262         modeRe = /^(\s?[\/>+~]\s?|\s|$)/,
1263         tagTokenRe = /^(#)?([\w-\*]+)/,
1264         nthRe = /(\d*)n\+?(\d*)/, 
1265         nthRe2 = /\D/,
1266         // This is for IE MSXML which does not support expandos.
1267         // IE runs the same speed using setAttribute, however FF slows way down
1268         // and Safari completely fails so they need to continue to use expandos.
1269         isIE = window.ActiveXObject ? true : false,
1270         key = 30803;
1271     
1272     // this eval is stop the compressor from
1273     // renaming the variable to something shorter
1274     eval("var batch = 30803;");         
1275
1276     // Retrieve the child node from a particular
1277     // parent at the specified index.
1278     function child(parent, index){
1279         var i = 0,
1280             n = parent.firstChild;
1281         while(n){
1282             if(n.nodeType == 1){
1283                if(++i == index){
1284                    return n;
1285                }
1286             }
1287             n = n.nextSibling;
1288         }
1289         return null;
1290     }
1291
1292     // retrieve the next element node
1293     function next(n){   
1294         while((n = n.nextSibling) && n.nodeType != 1);
1295         return n;
1296     }
1297
1298     // retrieve the previous element node 
1299     function prev(n){
1300         while((n = n.previousSibling) && n.nodeType != 1);
1301         return n;
1302     }
1303
1304     // Mark each child node with a nodeIndex skipping and
1305     // removing empty text nodes.
1306     function children(parent){
1307         var n = parent.firstChild,
1308             nodeIndex = -1,
1309             nextNode;
1310         while(n){
1311             nextNode = n.nextSibling;
1312             // clean worthless empty nodes.
1313             if(n.nodeType == 3 && !nonSpace.test(n.nodeValue)){
1314                 parent.removeChild(n);
1315             }else{
1316                 // add an expando nodeIndex
1317                 n.nodeIndex = ++nodeIndex;
1318             }
1319             n = nextNode;
1320         }
1321         return this;
1322     }
1323
1324
1325     // nodeSet - array of nodes
1326     // cls - CSS Class
1327     function byClassName(nodeSet, cls){
1328         if(!cls){
1329             return nodeSet;
1330         }
1331         var result = [], ri = -1;
1332         for(var i = 0, ci; ci = nodeSet[i]; i++){
1333             if((' '+ci.className+' ').indexOf(cls) != -1){
1334                 result[++ri] = ci;
1335             }
1336         }
1337         return result;
1338     };
1339
1340     function attrValue(n, attr){
1341         // if its an array, use the first node.
1342         if(!n.tagName && typeof n.length != "undefined"){
1343             n = n[0];
1344         }
1345         if(!n){
1346             return null;
1347         }
1348
1349         if(attr == "for"){
1350             return n.htmlFor;
1351         }
1352         if(attr == "class" || attr == "className"){
1353             return n.className;
1354         }
1355         return n.getAttribute(attr) || n[attr];
1356
1357     };
1358
1359
1360     // ns - nodes
1361     // mode - false, /, >, +, ~
1362     // tagName - defaults to "*"
1363     function getNodes(ns, mode, tagName){
1364         var result = [], ri = -1, cs;
1365         if(!ns){
1366             return result;
1367         }
1368         tagName = tagName || "*";
1369         // convert to array
1370         if(typeof ns.getElementsByTagName != "undefined"){
1371             ns = [ns];
1372         }
1373         
1374         // no mode specified, grab all elements by tagName
1375         // at any depth
1376         if(!mode){
1377             for(var i = 0, ni; ni = ns[i]; i++){
1378                 cs = ni.getElementsByTagName(tagName);
1379                 for(var j = 0, ci; ci = cs[j]; j++){
1380                     result[++ri] = ci;
1381                 }
1382             }
1383         // Direct Child mode (/ or >)
1384         // E > F or E/F all direct children elements of E that have the tag     
1385         } else if(mode == "/" || mode == ">"){
1386             var utag = tagName.toUpperCase();
1387             for(var i = 0, ni, cn; ni = ns[i]; i++){
1388                 cn = ni.childNodes;
1389                 for(var j = 0, cj; cj = cn[j]; j++){
1390                     if(cj.nodeName == utag || cj.nodeName == tagName  || tagName == '*'){
1391                         result[++ri] = cj;
1392                     }
1393                 }
1394             }
1395         // Immediately Preceding mode (+)
1396         // E + F all elements with the tag F that are immediately preceded by an element with the tag E
1397         }else if(mode == "+"){
1398             var utag = tagName.toUpperCase();
1399             for(var i = 0, n; n = ns[i]; i++){
1400                 while((n = n.nextSibling) && n.nodeType != 1);
1401                 if(n && (n.nodeName == utag || n.nodeName == tagName || tagName == '*')){
1402                     result[++ri] = n;
1403                 }
1404             }
1405         // Sibling mode (~)
1406         // E ~ F all elements with the tag F that are preceded by a sibling element with the tag E
1407         }else if(mode == "~"){
1408             var utag = tagName.toUpperCase();
1409             for(var i = 0, n; n = ns[i]; i++){
1410                 while((n = n.nextSibling)){
1411                     if (n.nodeName == utag || n.nodeName == tagName || tagName == '*'){
1412                         result[++ri] = n;
1413                     }
1414                 }
1415             }
1416         }
1417         return result;
1418     }
1419
1420     function concat(a, b){
1421         if(b.slice){
1422             return a.concat(b);
1423         }
1424         for(var i = 0, l = b.length; i < l; i++){
1425             a[a.length] = b[i];
1426         }
1427         return a;
1428     }
1429
1430     function byTag(cs, tagName){
1431         if(cs.tagName || cs == document){
1432             cs = [cs];
1433         }
1434         if(!tagName){
1435             return cs;
1436         }
1437         var result = [], ri = -1;
1438         tagName = tagName.toLowerCase();
1439         for(var i = 0, ci; ci = cs[i]; i++){
1440             if(ci.nodeType == 1 && ci.tagName.toLowerCase() == tagName){
1441                 result[++ri] = ci;
1442             }
1443         }
1444         return result;
1445     }
1446
1447     function byId(cs, id){
1448         if(cs.tagName || cs == document){
1449             cs = [cs];
1450         }
1451         if(!id){
1452             return cs;
1453         }
1454         var result = [], ri = -1;
1455         for(var i = 0, ci; ci = cs[i]; i++){
1456             if(ci && ci.id == id){
1457                 result[++ri] = ci;
1458                 return result;
1459             }
1460         }
1461         return result;
1462     }
1463
1464     // operators are =, !=, ^=, $=, *=, %=, |= and ~=
1465     // custom can be "{"
1466     function byAttribute(cs, attr, value, op, custom){
1467         var result = [], 
1468             ri = -1, 
1469             useGetStyle = custom == "{",            
1470             fn = Ext.DomQuery.operators[op],        
1471             a,
1472             xml,
1473             hasXml;
1474             
1475         for(var i = 0, ci; ci = cs[i]; i++){
1476             // skip non-element nodes.
1477             if(ci.nodeType != 1){
1478                 continue;
1479             }
1480             // only need to do this for the first node
1481             if(!hasXml){
1482                 xml = Ext.DomQuery.isXml(ci);
1483                 hasXml = true;
1484             }
1485             
1486             // we only need to change the property names if we're dealing with html nodes, not XML
1487             if(!xml){
1488                 if(useGetStyle){
1489                     a = Ext.DomQuery.getStyle(ci, attr);
1490                 } else if (attr == "class" || attr == "className"){
1491                     a = ci.className;
1492                 } else if (attr == "for"){
1493                     a = ci.htmlFor;
1494                 } else if (attr == "href"){
1495                     // getAttribute href bug
1496                     // http://www.glennjones.net/Post/809/getAttributehrefbug.htm
1497                     a = ci.getAttribute("href", 2);
1498                 } else{
1499                     a = ci.getAttribute(attr);
1500                 }
1501             }else{
1502                 a = ci.getAttribute(attr);
1503             }
1504             if((fn && fn(a, value)) || (!fn && a)){
1505                 result[++ri] = ci;
1506             }
1507         }
1508         return result;
1509     }
1510
1511     function byPseudo(cs, name, value){
1512         return Ext.DomQuery.pseudos[name](cs, value);
1513     }
1514
1515     function nodupIEXml(cs){
1516         var d = ++key, 
1517             r;
1518         cs[0].setAttribute("_nodup", d);
1519         r = [cs[0]];
1520         for(var i = 1, len = cs.length; i < len; i++){
1521             var c = cs[i];
1522             if(!c.getAttribute("_nodup") != d){
1523                 c.setAttribute("_nodup", d);
1524                 r[r.length] = c;
1525             }
1526         }
1527         for(var i = 0, len = cs.length; i < len; i++){
1528             cs[i].removeAttribute("_nodup");
1529         }
1530         return r;
1531     }
1532
1533     function nodup(cs){
1534         if(!cs){
1535             return [];
1536         }
1537         var len = cs.length, c, i, r = cs, cj, ri = -1;
1538         if(!len || typeof cs.nodeType != "undefined" || len == 1){
1539             return cs;
1540         }
1541         if(isIE && typeof cs[0].selectSingleNode != "undefined"){
1542             return nodupIEXml(cs);
1543         }
1544         var d = ++key;
1545         cs[0]._nodup = d;
1546         for(i = 1; c = cs[i]; i++){
1547             if(c._nodup != d){
1548                 c._nodup = d;
1549             }else{
1550                 r = [];
1551                 for(var j = 0; j < i; j++){
1552                     r[++ri] = cs[j];
1553                 }
1554                 for(j = i+1; cj = cs[j]; j++){
1555                     if(cj._nodup != d){
1556                         cj._nodup = d;
1557                         r[++ri] = cj;
1558                     }
1559                 }
1560                 return r;
1561             }
1562         }
1563         return r;
1564     }
1565
1566     function quickDiffIEXml(c1, c2){
1567         var d = ++key,
1568             r = [];
1569         for(var i = 0, len = c1.length; i < len; i++){
1570             c1[i].setAttribute("_qdiff", d);
1571         }        
1572         for(var i = 0, len = c2.length; i < len; i++){
1573             if(c2[i].getAttribute("_qdiff") != d){
1574                 r[r.length] = c2[i];
1575             }
1576         }
1577         for(var i = 0, len = c1.length; i < len; i++){
1578            c1[i].removeAttribute("_qdiff");
1579         }
1580         return r;
1581     }
1582
1583     function quickDiff(c1, c2){
1584         var len1 = c1.length,
1585                 d = ++key,
1586                 r = [];
1587         if(!len1){
1588             return c2;
1589         }
1590         if(isIE && typeof c1[0].selectSingleNode != "undefined"){
1591             return quickDiffIEXml(c1, c2);
1592         }        
1593         for(var i = 0; i < len1; i++){
1594             c1[i]._qdiff = d;
1595         }        
1596         for(var i = 0, len = c2.length; i < len; i++){
1597             if(c2[i]._qdiff != d){
1598                 r[r.length] = c2[i];
1599             }
1600         }
1601         return r;
1602     }
1603
1604     function quickId(ns, mode, root, id){
1605         if(ns == root){
1606            var d = root.ownerDocument || root;
1607            return d.getElementById(id);
1608         }
1609         ns = getNodes(ns, mode, "*");
1610         return byId(ns, id);
1611     }
1612
1613     return {
1614         getStyle : function(el, name){
1615             return Ext.fly(el).getStyle(name);
1616         },
1617         /**
1618          * Compiles a selector/xpath query into a reusable function. The returned function
1619          * takes one parameter "root" (optional), which is the context node from where the query should start.
1620          * @param {String} selector The selector/xpath query
1621          * @param {String} type (optional) Either "select" (the default) or "simple" for a simple selector match
1622          * @return {Function}
1623          */
1624         compile : function(path, type){
1625             type = type || "select";
1626
1627             // setup fn preamble
1628             var fn = ["var f = function(root){\n var mode; ++batch; var n = root || document;\n"],
1629                         mode,           
1630                         lastPath,
1631                 matchers = Ext.DomQuery.matchers,
1632                 matchersLn = matchers.length,
1633                 modeMatch,
1634                 // accept leading mode switch
1635                 lmode = path.match(modeRe);
1636             
1637             if(lmode && lmode[1]){
1638                 fn[fn.length] = 'mode="'+lmode[1].replace(trimRe, "")+'";';
1639                 path = path.replace(lmode[1], "");
1640             }
1641             
1642             // strip leading slashes
1643             while(path.substr(0, 1)=="/"){
1644                 path = path.substr(1);
1645             }
1646
1647             while(path && lastPath != path){
1648                 lastPath = path;
1649                 var tokenMatch = path.match(tagTokenRe);
1650                 if(type == "select"){
1651                     if(tokenMatch){
1652                         // ID Selector
1653                         if(tokenMatch[1] == "#"){
1654                             fn[fn.length] = 'n = quickId(n, mode, root, "'+tokenMatch[2]+'");';                 
1655                         }else{
1656                             fn[fn.length] = 'n = getNodes(n, mode, "'+tokenMatch[2]+'");';
1657                         }
1658                         path = path.replace(tokenMatch[0], "");
1659                     }else if(path.substr(0, 1) != '@'){
1660                         fn[fn.length] = 'n = getNodes(n, mode, "*");';
1661                     }
1662                 // type of "simple"
1663                 }else{
1664                     if(tokenMatch){
1665                         if(tokenMatch[1] == "#"){
1666                             fn[fn.length] = 'n = byId(n, "'+tokenMatch[2]+'");';
1667                         }else{
1668                             fn[fn.length] = 'n = byTag(n, "'+tokenMatch[2]+'");';
1669                         }
1670                         path = path.replace(tokenMatch[0], "");
1671                     }
1672                 }
1673                 while(!(modeMatch = path.match(modeRe))){
1674                     var matched = false;
1675                     for(var j = 0; j < matchersLn; j++){
1676                         var t = matchers[j];
1677                         var m = path.match(t.re);
1678                         if(m){
1679                             fn[fn.length] = t.select.replace(tplRe, function(x, i){
1680                                 return m[i];
1681                             });
1682                             path = path.replace(m[0], "");
1683                             matched = true;
1684                             break;
1685                         }
1686                     }
1687                     // prevent infinite loop on bad selector
1688                     if(!matched){
1689                         throw 'Error parsing selector, parsing failed at "' + path + '"';
1690                     }
1691                 }
1692                 if(modeMatch[1]){
1693                     fn[fn.length] = 'mode="'+modeMatch[1].replace(trimRe, "")+'";';
1694                     path = path.replace(modeMatch[1], "");
1695                 }
1696             }
1697             // close fn out
1698             fn[fn.length] = "return nodup(n);\n}";
1699             
1700             // eval fn and return it
1701             eval(fn.join(""));
1702             return f;
1703         },
1704
1705         /**
1706          * Selects a group of elements.
1707          * @param {String} selector The selector/xpath query (can be a comma separated list of selectors)
1708          * @param {Node/String} root (optional) The start of the query (defaults to document).
1709          * @return {Array} An Array of DOM elements which match the selector. If there are
1710          * no matches, and empty Array is returned.
1711          */
1712         jsSelect: function(path, root, type){
1713             // set root to doc if not specified.
1714             root = root || document;
1715             
1716             if(typeof root == "string"){
1717                 root = document.getElementById(root);
1718             }
1719             var paths = path.split(","),
1720                 results = [];
1721                 
1722             // loop over each selector
1723             for(var i = 0, len = paths.length; i < len; i++){           
1724                 var subPath = paths[i].replace(trimRe, "");
1725                 // compile and place in cache
1726                 if(!cache[subPath]){
1727                     cache[subPath] = Ext.DomQuery.compile(subPath);
1728                     if(!cache[subPath]){
1729                         throw subPath + " is not a valid selector";
1730                     }
1731                 }
1732                 var result = cache[subPath](root);
1733                 if(result && result != document){
1734                     results = results.concat(result);
1735                 }
1736             }
1737             
1738             // if there were multiple selectors, make sure dups
1739             // are eliminated
1740             if(paths.length > 1){
1741                 return nodup(results);
1742             }
1743             return results;
1744         },
1745         isXml: function(el) {
1746             var docEl = (el ? el.ownerDocument || el : 0).documentElement;
1747             return docEl ? docEl.nodeName !== "HTML" : false;
1748         },
1749         select : document.querySelectorAll ? function(path, root, type) {
1750             root = root || document;
1751             if (!Ext.DomQuery.isXml(root)) {
1752                 try {
1753                     var cs = root.querySelectorAll(path);
1754                     return Ext.toArray(cs);
1755                 }
1756                 catch (ex) {}           
1757             }       
1758             return Ext.DomQuery.jsSelect.call(this, path, root, type);
1759         } : function(path, root, type) {
1760             return Ext.DomQuery.jsSelect.call(this, path, root, type);
1761         },
1762
1763         /**
1764          * Selects a single element.
1765          * @param {String} selector The selector/xpath query
1766          * @param {Node} root (optional) The start of the query (defaults to document).
1767          * @return {Element} The DOM element which matched the selector.
1768          */
1769         selectNode : function(path, root){
1770             return Ext.DomQuery.select(path, root)[0];
1771         },
1772
1773         /**
1774          * Selects the value of a node, optionally replacing null with the defaultValue.
1775          * @param {String} selector The selector/xpath query
1776          * @param {Node} root (optional) The start of the query (defaults to document).
1777          * @param {String} defaultValue
1778          * @return {String}
1779          */
1780         selectValue : function(path, root, defaultValue){
1781             path = path.replace(trimRe, "");
1782             if(!valueCache[path]){
1783                 valueCache[path] = Ext.DomQuery.compile(path, "select");
1784             }
1785             var n = valueCache[path](root), v;
1786             n = n[0] ? n[0] : n;
1787                     
1788             // overcome a limitation of maximum textnode size
1789             // Rumored to potentially crash IE6 but has not been confirmed.
1790             // http://reference.sitepoint.com/javascript/Node/normalize
1791             // https://developer.mozilla.org/En/DOM/Node.normalize          
1792             if (typeof n.normalize == 'function') n.normalize();
1793             
1794             v = (n && n.firstChild ? n.firstChild.nodeValue : null);
1795             return ((v === null||v === undefined||v==='') ? defaultValue : v);
1796         },
1797
1798         /**
1799          * Selects the value of a node, parsing integers and floats. Returns the defaultValue, or 0 if none is specified.
1800          * @param {String} selector The selector/xpath query
1801          * @param {Node} root (optional) The start of the query (defaults to document).
1802          * @param {Number} defaultValue
1803          * @return {Number}
1804          */
1805         selectNumber : function(path, root, defaultValue){
1806             var v = Ext.DomQuery.selectValue(path, root, defaultValue || 0);
1807             return parseFloat(v);
1808         },
1809
1810         /**
1811          * Returns true if the passed element(s) match the passed simple selector (e.g. div.some-class or span:first-child)
1812          * @param {String/HTMLElement/Array} el An element id, element or array of elements
1813          * @param {String} selector The simple selector to test
1814          * @return {Boolean}
1815          */
1816         is : function(el, ss){
1817             if(typeof el == "string"){
1818                 el = document.getElementById(el);
1819             }
1820             var isArray = Ext.isArray(el),
1821                 result = Ext.DomQuery.filter(isArray ? el : [el], ss);
1822             return isArray ? (result.length == el.length) : (result.length > 0);
1823         },
1824
1825         /**
1826          * Filters an array of elements to only include matches of a simple selector (e.g. div.some-class or span:first-child)
1827          * @param {Array} el An array of elements to filter
1828          * @param {String} selector The simple selector to test
1829          * @param {Boolean} nonMatches If true, it returns the elements that DON'T match
1830          * the selector instead of the ones that match
1831          * @return {Array} An Array of DOM elements which match the selector. If there are
1832          * no matches, and empty Array is returned.
1833          */
1834         filter : function(els, ss, nonMatches){
1835             ss = ss.replace(trimRe, "");
1836             if(!simpleCache[ss]){
1837                 simpleCache[ss] = Ext.DomQuery.compile(ss, "simple");
1838             }
1839             var result = simpleCache[ss](els);
1840             return nonMatches ? quickDiff(result, els) : result;
1841         },
1842
1843         /**
1844          * Collection of matching regular expressions and code snippets.
1845          * Each capture group within () will be replace the {} in the select
1846          * statement as specified by their index.
1847          */
1848         matchers : [{
1849                 re: /^\.([\w-]+)/,
1850                 select: 'n = byClassName(n, " {1} ");'
1851             }, {
1852                 re: /^\:([\w-]+)(?:\(((?:[^\s>\/]*|.*?))\))?/,
1853                 select: 'n = byPseudo(n, "{1}", "{2}");'
1854             },{
1855                 re: /^(?:([\[\{])(?:@)?([\w-]+)\s?(?:(=|.=)\s?['"]?(.*?)["']?)?[\]\}])/,
1856                 select: 'n = byAttribute(n, "{2}", "{4}", "{3}", "{1}");'
1857             }, {
1858                 re: /^#([\w-]+)/,
1859                 select: 'n = byId(n, "{1}");'
1860             },{
1861                 re: /^@([\w-]+)/,
1862                 select: 'return {firstChild:{nodeValue:attrValue(n, "{1}")}};'
1863             }
1864         ],
1865
1866         /**
1867          * Collection of operator comparison functions. The default operators are =, !=, ^=, $=, *=, %=, |= and ~=.
1868          * 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;.
1869          */
1870         operators : {
1871             "=" : function(a, v){
1872                 return a == v;
1873             },
1874             "!=" : function(a, v){
1875                 return a != v;
1876             },
1877             "^=" : function(a, v){
1878                 return a && a.substr(0, v.length) == v;
1879             },
1880             "$=" : function(a, v){
1881                 return a && a.substr(a.length-v.length) == v;
1882             },
1883             "*=" : function(a, v){
1884                 return a && a.indexOf(v) !== -1;
1885             },
1886             "%=" : function(a, v){
1887                 return (a % v) == 0;
1888             },
1889             "|=" : function(a, v){
1890                 return a && (a == v || a.substr(0, v.length+1) == v+'-');
1891             },
1892             "~=" : function(a, v){
1893                 return a && (' '+a+' ').indexOf(' '+v+' ') != -1;
1894             }
1895         },
1896
1897         /**
1898          * <p>Object hash of "pseudo class" filter functions which are used when filtering selections. Each function is passed
1899          * two parameters:</p><div class="mdetail-params"><ul>
1900          * <li><b>c</b> : Array<div class="sub-desc">An Array of DOM elements to filter.</div></li>
1901          * <li><b>v</b> : String<div class="sub-desc">The argument (if any) supplied in the selector.</div></li>
1902          * </ul></div>
1903          * <p>A filter function returns an Array of DOM elements which conform to the pseudo class.</p>
1904          * <p>In addition to the provided pseudo classes listed above such as <code>first-child</code> and <code>nth-child</code>,
1905          * developers may add additional, custom psuedo class filters to select elements according to application-specific requirements.</p>
1906          * <p>For example, to filter <code>&lt;a></code> elements to only return links to <i>external</i> resources:</p>
1907          * <code><pre>
1908 Ext.DomQuery.pseudos.external = function(c, v){
1909     var r = [], ri = -1;
1910     for(var i = 0, ci; ci = c[i]; i++){
1911 //      Include in result set only if it's a link to an external resource
1912         if(ci.hostname != location.hostname){
1913             r[++ri] = ci;
1914         }
1915     }
1916     return r;
1917 };</pre></code>
1918          * Then external links could be gathered with the following statement:<code><pre>
1919 var externalLinks = Ext.select("a:external");
1920 </code></pre>
1921          */
1922         pseudos : {
1923             "first-child" : function(c){
1924                 var r = [], ri = -1, n;
1925                 for(var i = 0, ci; ci = n = c[i]; i++){
1926                     while((n = n.previousSibling) && n.nodeType != 1);
1927                     if(!n){
1928                         r[++ri] = ci;
1929                     }
1930                 }
1931                 return r;
1932             },
1933
1934             "last-child" : function(c){
1935                 var r = [], ri = -1, n;
1936                 for(var i = 0, ci; ci = n = c[i]; i++){
1937                     while((n = n.nextSibling) && n.nodeType != 1);
1938                     if(!n){
1939                         r[++ri] = ci;
1940                     }
1941                 }
1942                 return r;
1943             },
1944
1945             "nth-child" : function(c, a) {
1946                 var r = [], ri = -1,
1947                         m = nthRe.exec(a == "even" && "2n" || a == "odd" && "2n+1" || !nthRe2.test(a) && "n+" + a || a),
1948                         f = (m[1] || 1) - 0, l = m[2] - 0;
1949                 for(var i = 0, n; n = c[i]; i++){
1950                     var pn = n.parentNode;
1951                     if (batch != pn._batch) {
1952                         var j = 0;
1953                         for(var cn = pn.firstChild; cn; cn = cn.nextSibling){
1954                             if(cn.nodeType == 1){
1955                                cn.nodeIndex = ++j;
1956                             }
1957                         }
1958                         pn._batch = batch;
1959                     }
1960                     if (f == 1) {
1961                         if (l == 0 || n.nodeIndex == l){
1962                             r[++ri] = n;
1963                         }
1964                     } else if ((n.nodeIndex + l) % f == 0){
1965                         r[++ri] = n;
1966                     }
1967                 }
1968
1969                 return r;
1970             },
1971
1972             "only-child" : function(c){
1973                 var r = [], ri = -1;;
1974                 for(var i = 0, ci; ci = c[i]; i++){
1975                     if(!prev(ci) && !next(ci)){
1976                         r[++ri] = ci;
1977                     }
1978                 }
1979                 return r;
1980             },
1981
1982             "empty" : function(c){
1983                 var r = [], ri = -1;
1984                 for(var i = 0, ci; ci = c[i]; i++){
1985                     var cns = ci.childNodes, j = 0, cn, empty = true;
1986                     while(cn = cns[j]){
1987                         ++j;
1988                         if(cn.nodeType == 1 || cn.nodeType == 3){
1989                             empty = false;
1990                             break;
1991                         }
1992                     }
1993                     if(empty){
1994                         r[++ri] = ci;
1995                     }
1996                 }
1997                 return r;
1998             },
1999
2000             "contains" : function(c, v){
2001                 var r = [], ri = -1;
2002                 for(var i = 0, ci; ci = c[i]; i++){
2003                     if((ci.textContent||ci.innerText||'').indexOf(v) != -1){
2004                         r[++ri] = ci;
2005                     }
2006                 }
2007                 return r;
2008             },
2009
2010             "nodeValue" : function(c, v){
2011                 var r = [], ri = -1;
2012                 for(var i = 0, ci; ci = c[i]; i++){
2013                     if(ci.firstChild && ci.firstChild.nodeValue == v){
2014                         r[++ri] = ci;
2015                     }
2016                 }
2017                 return r;
2018             },
2019
2020             "checked" : function(c){
2021                 var r = [], ri = -1;
2022                 for(var i = 0, ci; ci = c[i]; i++){
2023                     if(ci.checked == true){
2024                         r[++ri] = ci;
2025                     }
2026                 }
2027                 return r;
2028             },
2029
2030             "not" : function(c, ss){
2031                 return Ext.DomQuery.filter(c, ss, true);
2032             },
2033
2034             "any" : function(c, selectors){
2035                 var ss = selectors.split('|'),
2036                         r = [], ri = -1, s;
2037                 for(var i = 0, ci; ci = c[i]; i++){
2038                     for(var j = 0; s = ss[j]; j++){
2039                         if(Ext.DomQuery.is(ci, s)){
2040                             r[++ri] = ci;
2041                             break;
2042                         }
2043                     }
2044                 }
2045                 return r;
2046             },
2047
2048             "odd" : function(c){
2049                 return this["nth-child"](c, "odd");
2050             },
2051
2052             "even" : function(c){
2053                 return this["nth-child"](c, "even");
2054             },
2055
2056             "nth" : function(c, a){
2057                 return c[a-1] || [];
2058             },
2059
2060             "first" : function(c){
2061                 return c[0] || [];
2062             },
2063
2064             "last" : function(c){
2065                 return c[c.length-1] || [];
2066             },
2067
2068             "has" : function(c, ss){
2069                 var s = Ext.DomQuery.select,
2070                         r = [], ri = -1;
2071                 for(var i = 0, ci; ci = c[i]; i++){
2072                     if(s(ss, ci).length > 0){
2073                         r[++ri] = ci;
2074                     }
2075                 }
2076                 return r;
2077             },
2078
2079             "next" : function(c, ss){
2080                 var is = Ext.DomQuery.is,
2081                         r = [], ri = -1;
2082                 for(var i = 0, ci; ci = c[i]; i++){
2083                     var n = next(ci);
2084                     if(n && is(n, ss)){
2085                         r[++ri] = ci;
2086                     }
2087                 }
2088                 return r;
2089             },
2090
2091             "prev" : function(c, ss){
2092                 var is = Ext.DomQuery.is,
2093                         r = [], ri = -1;
2094                 for(var i = 0, ci; ci = c[i]; i++){
2095                     var n = prev(ci);
2096                     if(n && is(n, ss)){
2097                         r[++ri] = ci;
2098                     }
2099                 }
2100                 return r;
2101             }
2102         }
2103     };
2104 }();
2105
2106 /**
2107  * Selects an array of DOM nodes by CSS/XPath selector. Shorthand of {@link Ext.DomQuery#select}
2108  * @param {String} path The selector/xpath query
2109  * @param {Node} root (optional) The start of the query (defaults to document).
2110  * @return {Array}
2111  * @member Ext
2112  * @method query
2113  */
2114 Ext.query = Ext.DomQuery.select;
2115 /**
2116  * @class Ext.util.DelayedTask
2117  * <p> The DelayedTask class provides a convenient way to "buffer" the execution of a method,
2118  * performing setTimeout where a new timeout cancels the old timeout. When called, the
2119  * task will wait the specified time period before executing. If durng that time period,
2120  * the task is called again, the original call will be cancelled. This continues so that
2121  * the function is only called a single time for each iteration.</p>
2122  * <p>This method is especially useful for things like detecting whether a user has finished
2123  * typing in a text field. An example would be performing validation on a keypress. You can
2124  * use this class to buffer the keypress events for a certain number of milliseconds, and
2125  * perform only if they stop for that amount of time.  Usage:</p><pre><code>
2126 var task = new Ext.util.DelayedTask(function(){
2127     alert(Ext.getDom('myInputField').value.length);
2128 });
2129 // Wait 500ms before calling our function. If the user presses another key 
2130 // during that 500ms, it will be cancelled and we'll wait another 500ms.
2131 Ext.get('myInputField').on('keypress', function(){
2132     task.{@link #delay}(500); 
2133 });
2134  * </code></pre> 
2135  * <p>Note that we are using a DelayedTask here to illustrate a point. The configuration
2136  * option <tt>buffer</tt> for {@link Ext.util.Observable#addListener addListener/on} will
2137  * also setup a delayed task for you to buffer events.</p> 
2138  * @constructor The parameters to this constructor serve as defaults and are not required.
2139  * @param {Function} fn (optional) The default function to call.
2140  * @param {Object} scope The default scope (The <code><b>this</b></code> reference) in which the
2141  * function is called. If not specified, <code>this</code> will refer to the browser window.
2142  * @param {Array} args (optional) The default Array of arguments.
2143  */
2144 Ext.util.DelayedTask = function(fn, scope, args){
2145     var me = this,
2146         id,     
2147         call = function(){
2148                 clearInterval(id);
2149                 id = null;
2150                 fn.apply(scope, args || []);
2151             };
2152             
2153     /**
2154      * Cancels any pending timeout and queues a new one
2155      * @param {Number} delay The milliseconds to delay
2156      * @param {Function} newFn (optional) Overrides function passed to constructor
2157      * @param {Object} newScope (optional) Overrides scope passed to constructor. Remember that if no scope
2158      * is specified, <code>this</code> will refer to the browser window.
2159      * @param {Array} newArgs (optional) Overrides args passed to constructor
2160      */
2161     me.delay = function(delay, newFn, newScope, newArgs){
2162         me.cancel();
2163         fn = newFn || fn;
2164         scope = newScope || scope;
2165         args = newArgs || args;
2166         id = setInterval(call, delay);
2167     };
2168
2169     /**
2170      * Cancel the last queued timeout
2171      */
2172     me.cancel = function(){
2173         if(id){
2174             clearInterval(id);
2175             id = null;
2176         }
2177     };
2178 };/**
2179  * @class Ext.Element
2180  * <p>Encapsulates a DOM element, adding simple DOM manipulation facilities, normalizing for browser differences.</p>
2181  * <p>All instances of this class inherit the methods of {@link Ext.Fx} making visual effects easily available to all DOM elements.</p>
2182  * <p>Note that the events documented in this class are not Ext events, they encapsulate browser events. To
2183  * access the underlying browser event, see {@link Ext.EventObject#browserEvent}. Some older
2184  * browsers may not support the full range of events. Which events are supported is beyond the control of ExtJs.</p>
2185  * Usage:<br>
2186 <pre><code>
2187 // by id
2188 var el = Ext.get("my-div");
2189
2190 // by DOM element reference
2191 var el = Ext.get(myDivElement);
2192 </code></pre>
2193  * <b>Animations</b><br />
2194  * <p>When an element is manipulated, by default there is no animation.</p>
2195  * <pre><code>
2196 var el = Ext.get("my-div");
2197
2198 // no animation
2199 el.setWidth(100);
2200  * </code></pre>
2201  * <p>Many of the functions for manipulating an element have an optional "animate" parameter.  This
2202  * parameter can be specified as boolean (<tt>true</tt>) for default animation effects.</p>
2203  * <pre><code>
2204 // default animation
2205 el.setWidth(100, true);
2206  * </code></pre>
2207  *
2208  * <p>To configure the effects, an object literal with animation options to use as the Element animation
2209  * configuration object can also be specified. Note that the supported Element animation configuration
2210  * options are a subset of the {@link Ext.Fx} animation options specific to Fx effects.  The supported
2211  * Element animation configuration options are:</p>
2212 <pre>
2213 Option    Default   Description
2214 --------- --------  ---------------------------------------------
2215 {@link Ext.Fx#duration duration}  .35       The duration of the animation in seconds
2216 {@link Ext.Fx#easing easing}    easeOut   The easing method
2217 {@link Ext.Fx#callback callback}  none      A function to execute when the anim completes
2218 {@link Ext.Fx#scope scope}     this      The scope (this) of the callback function
2219 </pre>
2220  *
2221  * <pre><code>
2222 // Element animation options object
2223 var opt = {
2224     {@link Ext.Fx#duration duration}: 1,
2225     {@link Ext.Fx#easing easing}: 'elasticIn',
2226     {@link Ext.Fx#callback callback}: this.foo,
2227     {@link Ext.Fx#scope scope}: this
2228 };
2229 // animation with some options set
2230 el.setWidth(100, opt);
2231  * </code></pre>
2232  * <p>The Element animation object being used for the animation will be set on the options
2233  * object as "anim", which allows you to stop or manipulate the animation. Here is an example:</p>
2234  * <pre><code>
2235 // using the "anim" property to get the Anim object
2236 if(opt.anim.isAnimated()){
2237     opt.anim.stop();
2238 }
2239  * </code></pre>
2240  * <p>Also see the <tt>{@link #animate}</tt> method for another animation technique.</p>
2241  * <p><b> Composite (Collections of) Elements</b></p>
2242  * <p>For working with collections of Elements, see {@link Ext.CompositeElement}</p>
2243  * @constructor Create a new Element directly.
2244  * @param {String/HTMLElement} element
2245  * @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).
2246  */
2247 (function(){
2248 var DOC = document;
2249
2250 Ext.Element = function(element, forceNew){
2251     var dom = typeof element == "string" ?
2252               DOC.getElementById(element) : element,
2253         id;
2254
2255     if(!dom) return null;
2256
2257     id = dom.id;
2258
2259     if(!forceNew && id && Ext.elCache[id]){ // element object already exists
2260         return Ext.elCache[id].el;
2261     }
2262
2263     /**
2264      * The DOM element
2265      * @type HTMLElement
2266      */
2267     this.dom = dom;
2268
2269     /**
2270      * The DOM element ID
2271      * @type String
2272      */
2273     this.id = id || Ext.id(dom);
2274 };
2275
2276 var DH = Ext.DomHelper,
2277     El = Ext.Element,
2278     EC = Ext.elCache;
2279
2280 El.prototype = {
2281     /**
2282      * Sets the passed attributes as attributes of this element (a style attribute can be a string, object or function)
2283      * @param {Object} o The object with the attributes
2284      * @param {Boolean} useSet (optional) false to override the default setAttribute to use expandos.
2285      * @return {Ext.Element} this
2286      */
2287     set : function(o, useSet){
2288         var el = this.dom,
2289             attr,
2290             val,
2291             useSet = (useSet !== false) && !!el.setAttribute;
2292
2293         for (attr in o) {
2294             if (o.hasOwnProperty(attr)) {
2295                 val = o[attr];
2296                 if (attr == 'style') {
2297                     DH.applyStyles(el, val);
2298                 } else if (attr == 'cls') {
2299                     el.className = val;
2300                 } else if (useSet) {
2301                     el.setAttribute(attr, val);
2302                 } else {
2303                     el[attr] = val;
2304                 }
2305             }
2306         }
2307         return this;
2308     },
2309
2310 //  Mouse events
2311     /**
2312      * @event click
2313      * Fires when a mouse click is detected within the element.
2314      * @param {Ext.EventObject} e The {@link Ext.EventObject} encapsulating the DOM event.
2315      * @param {HtmlElement} t The target of the event.
2316      * @param {Object} o The options configuration passed to the {@link #addListener} call.
2317      */
2318     /**
2319      * @event contextmenu
2320      * Fires when a right click is detected within the element.
2321      * @param {Ext.EventObject} e The {@link Ext.EventObject} encapsulating the DOM event.
2322      * @param {HtmlElement} t The target of the event.
2323      * @param {Object} o The options configuration passed to the {@link #addListener} call.
2324      */
2325     /**
2326      * @event dblclick
2327      * Fires when a mouse double click is detected within the element.
2328      * @param {Ext.EventObject} e The {@link Ext.EventObject} encapsulating the DOM event.
2329      * @param {HtmlElement} t The target of the event.
2330      * @param {Object} o The options configuration passed to the {@link #addListener} call.
2331      */
2332     /**
2333      * @event mousedown
2334      * Fires when a mousedown is detected within the element.
2335      * @param {Ext.EventObject} e The {@link Ext.EventObject} encapsulating the DOM event.
2336      * @param {HtmlElement} t The target of the event.
2337      * @param {Object} o The options configuration passed to the {@link #addListener} call.
2338      */
2339     /**
2340      * @event mouseup
2341      * Fires when a mouseup is detected within the element.
2342      * @param {Ext.EventObject} e The {@link Ext.EventObject} encapsulating the DOM event.
2343      * @param {HtmlElement} t The target of the event.
2344      * @param {Object} o The options configuration passed to the {@link #addListener} call.
2345      */
2346     /**
2347      * @event mouseover
2348      * Fires when a mouseover is detected within the element.
2349      * @param {Ext.EventObject} e The {@link Ext.EventObject} encapsulating the DOM event.
2350      * @param {HtmlElement} t The target of the event.
2351      * @param {Object} o The options configuration passed to the {@link #addListener} call.
2352      */
2353     /**
2354      * @event mousemove
2355      * Fires when a mousemove is detected with the element.
2356      * @param {Ext.EventObject} e The {@link Ext.EventObject} encapsulating the DOM event.
2357      * @param {HtmlElement} t The target of the event.
2358      * @param {Object} o The options configuration passed to the {@link #addListener} call.
2359      */
2360     /**
2361      * @event mouseout
2362      * Fires when a mouseout is detected with the element.
2363      * @param {Ext.EventObject} e The {@link Ext.EventObject} encapsulating the DOM event.
2364      * @param {HtmlElement} t The target of the event.
2365      * @param {Object} o The options configuration passed to the {@link #addListener} call.
2366      */
2367     /**
2368      * @event mouseenter
2369      * Fires when the mouse enters the element.
2370      * @param {Ext.EventObject} e The {@link Ext.EventObject} encapsulating the DOM event.
2371      * @param {HtmlElement} t The target of the event.
2372      * @param {Object} o The options configuration passed to the {@link #addListener} call.
2373      */
2374     /**
2375      * @event mouseleave
2376      * Fires when the mouse leaves the element.
2377      * @param {Ext.EventObject} e The {@link Ext.EventObject} encapsulating the DOM event.
2378      * @param {HtmlElement} t The target of the event.
2379      * @param {Object} o The options configuration passed to the {@link #addListener} call.
2380      */
2381
2382 //  Keyboard events
2383     /**
2384      * @event keypress
2385      * Fires when a keypress is detected within the element.
2386      * @param {Ext.EventObject} e The {@link Ext.EventObject} encapsulating the DOM event.
2387      * @param {HtmlElement} t The target of the event.
2388      * @param {Object} o The options configuration passed to the {@link #addListener} call.
2389      */
2390     /**
2391      * @event keydown
2392      * Fires when a keydown is detected within the element.
2393      * @param {Ext.EventObject} e The {@link Ext.EventObject} encapsulating the DOM event.
2394      * @param {HtmlElement} t The target of the event.
2395      * @param {Object} o The options configuration passed to the {@link #addListener} call.
2396      */
2397     /**
2398      * @event keyup
2399      * Fires when a keyup is detected within the element.
2400      * @param {Ext.EventObject} e The {@link Ext.EventObject} encapsulating the DOM event.
2401      * @param {HtmlElement} t The target of the event.
2402      * @param {Object} o The options configuration passed to the {@link #addListener} call.
2403      */
2404
2405
2406 //  HTML frame/object events
2407     /**
2408      * @event load
2409      * Fires when the user agent finishes loading all content within the element. Only supported by window, frames, objects and images.
2410      * @param {Ext.EventObject} e The {@link Ext.EventObject} encapsulating the DOM event.
2411      * @param {HtmlElement} t The target of the event.
2412      * @param {Object} o The options configuration passed to the {@link #addListener} call.
2413      */
2414     /**
2415      * @event unload
2416      * 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.
2417      * @param {Ext.EventObject} e The {@link Ext.EventObject} encapsulating the DOM event.
2418      * @param {HtmlElement} t The target of the event.
2419      * @param {Object} o The options configuration passed to the {@link #addListener} call.
2420      */
2421     /**
2422      * @event abort
2423      * Fires when an object/image is stopped from loading before completely loaded.
2424      * @param {Ext.EventObject} e The {@link Ext.EventObject} encapsulating the DOM event.
2425      * @param {HtmlElement} t The target of the event.
2426      * @param {Object} o The options configuration passed to the {@link #addListener} call.
2427      */
2428     /**
2429      * @event error
2430      * Fires when an object/image/frame cannot be loaded properly.
2431      * @param {Ext.EventObject} e The {@link Ext.EventObject} encapsulating the DOM event.
2432      * @param {HtmlElement} t The target of the event.
2433      * @param {Object} o The options configuration passed to the {@link #addListener} call.
2434      */
2435     /**
2436      * @event resize
2437      * Fires when a document view is resized.
2438      * @param {Ext.EventObject} e The {@link Ext.EventObject} encapsulating the DOM event.
2439      * @param {HtmlElement} t The target of the event.
2440      * @param {Object} o The options configuration passed to the {@link #addListener} call.
2441      */
2442     /**
2443      * @event scroll
2444      * Fires when a document view is scrolled.
2445      * @param {Ext.EventObject} e The {@link Ext.EventObject} encapsulating the DOM event.
2446      * @param {HtmlElement} t The target of the event.
2447      * @param {Object} o The options configuration passed to the {@link #addListener} call.
2448      */
2449
2450 //  Form events
2451     /**
2452      * @event select
2453      * Fires when a user selects some text in a text field, including input and textarea.
2454      * @param {Ext.EventObject} e The {@link Ext.EventObject} encapsulating the DOM event.
2455      * @param {HtmlElement} t The target of the event.
2456      * @param {Object} o The options configuration passed to the {@link #addListener} call.
2457      */
2458     /**
2459      * @event change
2460      * Fires when a control loses the input focus and its value has been modified since gaining focus.
2461      * @param {Ext.EventObject} e The {@link Ext.EventObject} encapsulating the DOM event.
2462      * @param {HtmlElement} t The target of the event.
2463      * @param {Object} o The options configuration passed to the {@link #addListener} call.
2464      */
2465     /**
2466      * @event submit
2467      * Fires when a form is submitted.
2468      * @param {Ext.EventObject} e The {@link Ext.EventObject} encapsulating the DOM event.
2469      * @param {HtmlElement} t The target of the event.
2470      * @param {Object} o The options configuration passed to the {@link #addListener} call.
2471      */
2472     /**
2473      * @event reset
2474      * Fires when a form is reset.
2475      * @param {Ext.EventObject} e The {@link Ext.EventObject} encapsulating the DOM event.
2476      * @param {HtmlElement} t The target of the event.
2477      * @param {Object} o The options configuration passed to the {@link #addListener} call.
2478      */
2479     /**
2480      * @event focus
2481      * Fires when an element receives focus either via the pointing device or by tab navigation.
2482      * @param {Ext.EventObject} e The {@link Ext.EventObject} encapsulating the DOM event.
2483      * @param {HtmlElement} t The target of the event.
2484      * @param {Object} o The options configuration passed to the {@link #addListener} call.
2485      */
2486     /**
2487      * @event blur
2488      * Fires when an element loses focus either via the pointing device or by tabbing navigation.
2489      * @param {Ext.EventObject} e The {@link Ext.EventObject} encapsulating the DOM event.
2490      * @param {HtmlElement} t The target of the event.
2491      * @param {Object} o The options configuration passed to the {@link #addListener} call.
2492      */
2493
2494 //  User Interface events
2495     /**
2496      * @event DOMFocusIn
2497      * Where supported. Similar to HTML focus event, but can be applied to any focusable element.
2498      * @param {Ext.EventObject} e The {@link Ext.EventObject} encapsulating the DOM event.
2499      * @param {HtmlElement} t The target of the event.
2500      * @param {Object} o The options configuration passed to the {@link #addListener} call.
2501      */
2502     /**
2503      * @event DOMFocusOut
2504      * Where supported. Similar to HTML blur event, but can be applied to any focusable element.
2505      * @param {Ext.EventObject} e The {@link Ext.EventObject} encapsulating the DOM event.
2506      * @param {HtmlElement} t The target of the event.
2507      * @param {Object} o The options configuration passed to the {@link #addListener} call.
2508      */
2509     /**
2510      * @event DOMActivate
2511      * Where supported. Fires when an element is activated, for instance, through a mouse click or a keypress.
2512      * @param {Ext.EventObject} e The {@link Ext.EventObject} encapsulating the DOM event.
2513      * @param {HtmlElement} t The target of the event.
2514      * @param {Object} o The options configuration passed to the {@link #addListener} call.
2515      */
2516
2517 //  DOM Mutation events
2518     /**
2519      * @event DOMSubtreeModified
2520      * Where supported. Fires when the subtree is modified.
2521      * @param {Ext.EventObject} e The {@link Ext.EventObject} encapsulating the DOM event.
2522      * @param {HtmlElement} t The target of the event.
2523      * @param {Object} o The options configuration passed to the {@link #addListener} call.
2524      */
2525     /**
2526      * @event DOMNodeInserted
2527      * Where supported. Fires when a node has been added as a child of another node.
2528      * @param {Ext.EventObject} e The {@link Ext.EventObject} encapsulating the DOM event.
2529      * @param {HtmlElement} t The target of the event.
2530      * @param {Object} o The options configuration passed to the {@link #addListener} call.
2531      */
2532     /**
2533      * @event DOMNodeRemoved
2534      * Where supported. Fires when a descendant node of the element is removed.
2535      * @param {Ext.EventObject} e The {@link Ext.EventObject} encapsulating the DOM event.
2536      * @param {HtmlElement} t The target of the event.
2537      * @param {Object} o The options configuration passed to the {@link #addListener} call.
2538      */
2539     /**
2540      * @event DOMNodeRemovedFromDocument
2541      * Where supported. Fires when a node is being removed from a document.
2542      * @param {Ext.EventObject} e The {@link Ext.EventObject} encapsulating the DOM event.
2543      * @param {HtmlElement} t The target of the event.
2544      * @param {Object} o The options configuration passed to the {@link #addListener} call.
2545      */
2546     /**
2547      * @event DOMNodeInsertedIntoDocument
2548      * Where supported. Fires when a node is being inserted into a document.
2549      * @param {Ext.EventObject} e The {@link Ext.EventObject} encapsulating the DOM event.
2550      * @param {HtmlElement} t The target of the event.
2551      * @param {Object} o The options configuration passed to the {@link #addListener} call.
2552      */
2553     /**
2554      * @event DOMAttrModified
2555      * Where supported. Fires when an attribute has been modified.
2556      * @param {Ext.EventObject} e The {@link Ext.EventObject} encapsulating the DOM event.
2557      * @param {HtmlElement} t The target of the event.
2558      * @param {Object} o The options configuration passed to the {@link #addListener} call.
2559      */
2560     /**
2561      * @event DOMCharacterDataModified
2562      * Where supported. Fires when the character data has been modified.
2563      * @param {Ext.EventObject} e The {@link Ext.EventObject} encapsulating the DOM event.
2564      * @param {HtmlElement} t The target of the event.
2565      * @param {Object} o The options configuration passed to the {@link #addListener} call.
2566      */
2567
2568     /**
2569      * The default unit to append to CSS values where a unit isn't provided (defaults to px).
2570      * @type String
2571      */
2572     defaultUnit : "px",
2573
2574     /**
2575      * Returns true if this element matches the passed simple selector (e.g. div.some-class or span:first-child)
2576      * @param {String} selector The simple selector to test
2577      * @return {Boolean} True if this element matches the selector, else false
2578      */
2579     is : function(simpleSelector){
2580         return Ext.DomQuery.is(this.dom, simpleSelector);
2581     },
2582
2583     /**
2584      * Tries to focus the element. Any exceptions are caught and ignored.
2585      * @param {Number} defer (optional) Milliseconds to defer the focus
2586      * @return {Ext.Element} this
2587      */
2588     focus : function(defer, /* private */ dom) {
2589         var me = this,
2590             dom = dom || me.dom;
2591         try{
2592             if(Number(defer)){
2593                 me.focus.defer(defer, null, [null, dom]);
2594             }else{
2595                 dom.focus();
2596             }
2597         }catch(e){}
2598         return me;
2599     },
2600
2601     /**
2602      * Tries to blur the element. Any exceptions are caught and ignored.
2603      * @return {Ext.Element} this
2604      */
2605     blur : function() {
2606         try{
2607             this.dom.blur();
2608         }catch(e){}
2609         return this;
2610     },
2611
2612     /**
2613      * Returns the value of the "value" attribute
2614      * @param {Boolean} asNumber true to parse the value as a number
2615      * @return {String/Number}
2616      */
2617     getValue : function(asNumber){
2618         var val = this.dom.value;
2619         return asNumber ? parseInt(val, 10) : val;
2620     },
2621
2622     /**
2623      * Appends an event handler to this element.  The shorthand version {@link #on} is equivalent.
2624      * @param {String} eventName The name of event to handle.
2625      * @param {Function} fn The handler function the event invokes. This function is passed
2626      * the following parameters:<ul>
2627      * <li><b>evt</b> : EventObject<div class="sub-desc">The {@link Ext.EventObject EventObject} describing the event.</div></li>
2628      * <li><b>el</b> : HtmlElement<div class="sub-desc">The DOM element which was the target of the event.
2629      * Note that this may be filtered by using the <tt>delegate</tt> option.</div></li>
2630      * <li><b>o</b> : Object<div class="sub-desc">The options object from the addListener call.</div></li>
2631      * </ul>
2632      * @param {Object} scope (optional) The scope (<code><b>this</b></code> reference) in which the handler function is executed.
2633      * <b>If omitted, defaults to this Element.</b>.
2634      * @param {Object} options (optional) An object containing handler configuration properties.
2635      * This may contain any of the following properties:<ul>
2636      * <li><b>scope</b> Object : <div class="sub-desc">The scope (<code><b>this</b></code> reference) in which the handler function is executed.
2637      * <b>If omitted, defaults to this Element.</b></div></li>
2638      * <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>
2639      * <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>
2640      * <li><b>preventDefault</b> Boolean: <div class="sub-desc">True to prevent the default action</div></li>
2641      * <li><b>stopPropagation</b> Boolean: <div class="sub-desc">True to prevent event propagation</div></li>
2642      * <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>
2643      * <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>
2644      * <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>
2645      * <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>
2646      * <li><b>buffer</b> Number: <div class="sub-desc">Causes the handler to be scheduled to run in an {@link Ext.util.DelayedTask} delayed
2647      * by the specified number of milliseconds. If the event fires again within that time, the original
2648      * handler is <em>not</em> invoked, but the new handler is scheduled in its place.</div></li>
2649      * </ul><br>
2650      * <p>
2651      * <b>Combining Options</b><br>
2652      * In the following examples, the shorthand form {@link #on} is used rather than the more verbose
2653      * addListener.  The two are equivalent.  Using the options argument, it is possible to combine different
2654      * types of listeners:<br>
2655      * <br>
2656      * A delayed, one-time listener that auto stops the event and adds a custom argument (forumId) to the
2657      * options object. The options object is available as the third parameter in the handler function.<div style="margin: 5px 20px 20px;">
2658      * Code:<pre><code>
2659 el.on('click', this.onClick, this, {
2660     single: true,
2661     delay: 100,
2662     stopEvent : true,
2663     forumId: 4
2664 });</code></pre></p>
2665      * <p>
2666      * <b>Attaching multiple handlers in 1 call</b><br>
2667      * The method also allows for a single argument to be passed which is a config object containing properties
2668      * which specify multiple handlers.</p>
2669      * <p>
2670      * Code:<pre><code>
2671 el.on({
2672     'click' : {
2673         fn: this.onClick,
2674         scope: this,
2675         delay: 100
2676     },
2677     'mouseover' : {
2678         fn: this.onMouseOver,
2679         scope: this
2680     },
2681     'mouseout' : {
2682         fn: this.onMouseOut,
2683         scope: this
2684     }
2685 });</code></pre>
2686      * <p>
2687      * Or a shorthand syntax:<br>
2688      * Code:<pre><code></p>
2689 el.on({
2690     'click' : this.onClick,
2691     'mouseover' : this.onMouseOver,
2692     'mouseout' : this.onMouseOut,
2693     scope: this
2694 });
2695      * </code></pre></p>
2696      * <p><b>delegate</b></p>
2697      * <p>This is a configuration option that you can pass along when registering a handler for
2698      * an event to assist with event delegation. Event delegation is a technique that is used to
2699      * reduce memory consumption and prevent exposure to memory-leaks. By registering an event
2700      * for a container element as opposed to each element within a container. By setting this
2701      * configuration option to a simple selector, the target element will be filtered to look for
2702      * a descendant of the target.
2703      * For example:<pre><code>
2704 // using this markup:
2705 &lt;div id='elId'>
2706     &lt;p id='p1'>paragraph one&lt;/p>
2707     &lt;p id='p2' class='clickable'>paragraph two&lt;/p>
2708     &lt;p id='p3'>paragraph three&lt;/p>
2709 &lt;/div>
2710 // utilize event delegation to registering just one handler on the container element:
2711 el = Ext.get('elId');
2712 el.on(
2713     'click',
2714     function(e,t) {
2715         // handle click
2716         console.info(t.id); // 'p2'
2717     },
2718     this,
2719     {
2720         // filter the target element to be a descendant with the class 'clickable'
2721         delegate: '.clickable'
2722     }
2723 );
2724      * </code></pre></p>
2725      * @return {Ext.Element} this
2726      */
2727     addListener : function(eventName, fn, scope, options){
2728         Ext.EventManager.on(this.dom,  eventName, fn, scope || this, options);
2729         return this;
2730     },
2731
2732     /**
2733      * Removes an event handler from this element.  The shorthand version {@link #un} is equivalent.
2734      * <b>Note</b>: if a <i>scope</i> was explicitly specified when {@link #addListener adding} the
2735      * listener, the same scope must be specified here.
2736      * Example:
2737      * <pre><code>
2738 el.removeListener('click', this.handlerFn);
2739 // or
2740 el.un('click', this.handlerFn);
2741 </code></pre>
2742      * @param {String} eventName The name of the event from which to remove the handler.
2743      * @param {Function} fn The handler function to remove. <b>This must be a reference to the function passed into the {@link #addListener} call.</b>
2744      * @param {Object} scope If a scope (<b><code>this</code></b> reference) was specified when the listener was added,
2745      * then this must refer to the same object.
2746      * @return {Ext.Element} this
2747      */
2748     removeListener : function(eventName, fn, scope){
2749         Ext.EventManager.removeListener(this.dom,  eventName, fn, scope || this);
2750         return this;
2751     },
2752
2753     /**
2754      * Removes all previous added listeners from this element
2755      * @return {Ext.Element} this
2756      */
2757     removeAllListeners : function(){
2758         Ext.EventManager.removeAll(this.dom);
2759         return this;
2760     },
2761
2762     /**
2763      * Recursively removes all previous added listeners from this element and its children
2764      * @return {Ext.Element} this
2765      */
2766     purgeAllListeners : function() {
2767         Ext.EventManager.purgeElement(this, true);
2768         return this;
2769     },
2770     /**
2771      * @private Test if size has a unit, otherwise appends the default
2772      */
2773     addUnits : function(size){
2774         if(size === "" || size == "auto" || size === undefined){
2775             size = size || '';
2776         } else if(!isNaN(size) || !unitPattern.test(size)){
2777             size = size + (this.defaultUnit || 'px');
2778         }
2779         return size;
2780     },
2781
2782     /**
2783      * <p>Updates the <a href="http://developer.mozilla.org/en/DOM/element.innerHTML">innerHTML</a> of this Element
2784      * 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>
2785      * <p>Updating innerHTML of an element will <b>not</b> execute embedded <tt>&lt;script></tt> elements. This is a browser restriction.</p>
2786      * @param {Mixed} options. Either a sring containing the URL from which to load the HTML, or an {@link Ext.Ajax#request} options object specifying
2787      * exactly how to request the HTML.
2788      * @return {Ext.Element} this
2789      */
2790     load : function(url, params, cb){
2791         Ext.Ajax.request(Ext.apply({
2792             params: params,
2793             url: url.url || url,
2794             callback: cb,
2795             el: this.dom,
2796             indicatorText: url.indicatorText || ''
2797         }, Ext.isObject(url) ? url : {}));
2798         return this;
2799     },
2800
2801     /**
2802      * Tests various css rules/browsers to determine if this element uses a border box
2803      * @return {Boolean}
2804      */
2805     isBorderBox : function(){
2806         return Ext.isBorderBox || Ext.isForcedBorderBox || noBoxAdjust[(this.dom.tagName || "").toLowerCase()];
2807     },
2808
2809     /**
2810      * <p>Removes this element's dom reference.  Note that event and cache removal is handled at {@link Ext#removeNode}</p>
2811      */
2812     remove : function(){
2813         var me = this,
2814             dom = me.dom;
2815
2816         if (dom) {
2817             delete me.dom;
2818             Ext.removeNode(dom);
2819         }
2820     },
2821
2822     /**
2823      * Sets up event handlers to call the passed functions when the mouse is moved into and out of the Element.
2824      * @param {Function} overFn The function to call when the mouse enters the Element.
2825      * @param {Function} outFn The function to call when the mouse leaves the Element.
2826      * @param {Object} scope (optional) The scope (<code>this</code> reference) in which the functions are executed. Defaults to the Element's DOM element.
2827      * @param {Object} options (optional) Options for the listener. See {@link Ext.util.Observable#addListener the <tt>options</tt> parameter}.
2828      * @return {Ext.Element} this
2829      */
2830     hover : function(overFn, outFn, scope, options){
2831         var me = this;
2832         me.on('mouseenter', overFn, scope || me.dom, options);
2833         me.on('mouseleave', outFn, scope || me.dom, options);
2834         return me;
2835     },
2836
2837     /**
2838      * Returns true if this element is an ancestor of the passed element
2839      * @param {HTMLElement/String} el The element to check
2840      * @return {Boolean} True if this element is an ancestor of el, else false
2841      */
2842     contains : function(el){
2843         return !el ? false : Ext.lib.Dom.isAncestor(this.dom, el.dom ? el.dom : el);
2844     },
2845
2846     /**
2847      * Returns the value of a namespaced attribute from the element's underlying DOM node.
2848      * @param {String} namespace The namespace in which to look for the attribute
2849      * @param {String} name The attribute name
2850      * @return {String} The attribute value
2851      * @deprecated
2852      */
2853     getAttributeNS : function(ns, name){
2854         return this.getAttribute(name, ns);
2855     },
2856
2857     /**
2858      * Returns the value of an attribute from the element's underlying DOM node.
2859      * @param {String} name The attribute name
2860      * @param {String} namespace (optional) The namespace in which to look for the attribute
2861      * @return {String} The attribute value
2862      */
2863     getAttribute : Ext.isIE ? function(name, ns){
2864         var d = this.dom,
2865             type = typeof d[ns + ":" + name];
2866
2867         if(['undefined', 'unknown'].indexOf(type) == -1){
2868             return d[ns + ":" + name];
2869         }
2870         return d[name];
2871     } : function(name, ns){
2872         var d = this.dom;
2873         return d.getAttributeNS(ns, name) || d.getAttribute(ns + ":" + name) || d.getAttribute(name) || d[name];
2874     },
2875
2876     /**
2877     * Update the innerHTML of this element
2878     * @param {String} html The new HTML
2879     * @return {Ext.Element} this
2880      */
2881     update : function(html) {
2882         if (this.dom) {
2883             this.dom.innerHTML = html;
2884         }
2885         return this;
2886     }
2887 };
2888
2889 var ep = El.prototype;
2890
2891 El.addMethods = function(o){
2892    Ext.apply(ep, o);
2893 };
2894
2895 /**
2896  * Appends an event handler (shorthand for {@link #addListener}).
2897  * @param {String} eventName The name of event to handle.
2898  * @param {Function} fn The handler function the event invokes.
2899  * @param {Object} scope (optional) The scope (<code>this</code> reference) in which the handler function is executed.
2900  * @param {Object} options (optional) An object containing standard {@link #addListener} options
2901  * @member Ext.Element
2902  * @method on
2903  */
2904 ep.on = ep.addListener;
2905
2906 /**
2907  * Removes an event handler from this element (see {@link #removeListener} for additional notes).
2908  * @param {String} eventName The name of the event from which to remove the handler.
2909  * @param {Function} fn The handler function to remove. <b>This must be a reference to the function passed into the {@link #addListener} call.</b>
2910  * @param {Object} scope If a scope (<b><code>this</code></b> reference) was specified when the listener was added,
2911  * then this must refer to the same object.
2912  * @return {Ext.Element} this
2913  * @member Ext.Element
2914  * @method un
2915  */
2916 ep.un = ep.removeListener;
2917
2918 /**
2919  * true to automatically adjust width and height settings for box-model issues (default to true)
2920  */
2921 ep.autoBoxAdjust = true;
2922
2923 // private
2924 var unitPattern = /\d+(px|em|%|en|ex|pt|in|cm|mm|pc)$/i,
2925     docEl;
2926
2927 /**
2928  * @private
2929  */
2930
2931 /**
2932  * Retrieves Ext.Element objects.
2933  * <p><b>This method does not retrieve {@link Ext.Component Component}s.</b> This method
2934  * retrieves Ext.Element objects which encapsulate DOM elements. To retrieve a Component by
2935  * its ID, use {@link Ext.ComponentMgr#get}.</p>
2936  * <p>Uses simple caching to consistently return the same object. Automatically fixes if an
2937  * object was recreated with the same id via AJAX or DOM.</p>
2938  * @param {Mixed} el The id of the node, a DOM Node or an existing Element.
2939  * @return {Element} The Element object (or null if no matching element was found)
2940  * @static
2941  * @member Ext.Element
2942  * @method get
2943  */
2944 El.get = function(el){
2945     var ex,
2946         elm,
2947         id;
2948     if(!el){ return null; }
2949     if (typeof el == "string") { // element id
2950         if (!(elm = DOC.getElementById(el))) {
2951             return null;
2952         }
2953         if (EC[el] && EC[el].el) {
2954             ex = EC[el].el;
2955             ex.dom = elm;
2956         } else {
2957             ex = El.addToCache(new El(elm));
2958         }
2959         return ex;
2960     } else if (el.tagName) { // dom element
2961         if(!(id = el.id)){
2962             id = Ext.id(el);
2963         }
2964         if (EC[id] && EC[id].el) {
2965             ex = EC[id].el;
2966             ex.dom = el;
2967         } else {
2968             ex = El.addToCache(new El(el));
2969         }
2970         return ex;
2971     } else if (el instanceof El) {
2972         if(el != docEl){
2973             // refresh dom element in case no longer valid,
2974             // catch case where it hasn't been appended
2975
2976             // If an el instance is passed, don't pass to getElementById without some kind of id
2977             if (Ext.isIE && (el.id == undefined || el.id == '')) {
2978                 el.dom = el.dom;
2979             } else {
2980                 el.dom = DOC.getElementById(el.id) || el.dom;
2981             }
2982         }
2983         return el;
2984     } else if(el.isComposite) {
2985         return el;
2986     } else if(Ext.isArray(el)) {
2987         return El.select(el);
2988     } else if(el == DOC) {
2989         // create a bogus element object representing the document object
2990         if(!docEl){
2991             var f = function(){};
2992             f.prototype = El.prototype;
2993             docEl = new f();
2994             docEl.dom = DOC;
2995         }
2996         return docEl;
2997     }
2998     return null;
2999 };
3000
3001 El.addToCache = function(el, id){
3002     id = id || el.id;
3003     EC[id] = {
3004         el:  el,
3005         data: {},
3006         events: {}
3007     };
3008     return el;
3009 };
3010
3011 // private method for getting and setting element data
3012 El.data = function(el, key, value){
3013     el = El.get(el);
3014     if (!el) {
3015         return null;
3016     }
3017     var c = EC[el.id].data;
3018     if(arguments.length == 2){
3019         return c[key];
3020     }else{
3021         return (c[key] = value);
3022     }
3023 };
3024
3025 // private
3026 // Garbage collection - uncache elements/purge listeners on orphaned elements
3027 // so we don't hold a reference and cause the browser to retain them
3028 function garbageCollect(){
3029     if(!Ext.enableGarbageCollector){
3030         clearInterval(El.collectorThreadId);
3031     } else {
3032         var eid,
3033             el,
3034             d,
3035             o;
3036
3037         for(eid in EC){
3038             o = EC[eid];
3039             if(o.skipGC){
3040                 continue;
3041             }
3042             el = o.el;
3043             d = el.dom;
3044             // -------------------------------------------------------
3045             // Determining what is garbage:
3046             // -------------------------------------------------------
3047             // !d
3048             // dom node is null, definitely garbage
3049             // -------------------------------------------------------
3050             // !d.parentNode
3051             // no parentNode == direct orphan, definitely garbage
3052             // -------------------------------------------------------
3053             // !d.offsetParent && !document.getElementById(eid)
3054             // display none elements have no offsetParent so we will
3055             // also try to look it up by it's id. However, check
3056             // offsetParent first so we don't do unneeded lookups.
3057             // This enables collection of elements that are not orphans
3058             // directly, but somewhere up the line they have an orphan
3059             // parent.
3060             // -------------------------------------------------------
3061             if(!d || !d.parentNode || (!d.offsetParent && !DOC.getElementById(eid))){
3062                 if(Ext.enableListenerCollection){
3063                     Ext.EventManager.removeAll(d);
3064                 }
3065                 delete EC[eid];
3066             }
3067         }
3068         // Cleanup IE Object leaks
3069         if (Ext.isIE) {
3070             var t = {};
3071             for (eid in EC) {
3072                 t[eid] = EC[eid];
3073             }
3074             EC = Ext.elCache = t;
3075         }
3076     }
3077 }
3078 El.collectorThreadId = setInterval(garbageCollect, 30000);
3079
3080 var flyFn = function(){};
3081 flyFn.prototype = El.prototype;
3082
3083 // dom is optional
3084 El.Flyweight = function(dom){
3085     this.dom = dom;
3086 };
3087
3088 El.Flyweight.prototype = new flyFn();
3089 El.Flyweight.prototype.isFlyweight = true;
3090 El._flyweights = {};
3091
3092 /**
3093  * <p>Gets the globally shared flyweight Element, with the passed node as the active element. Do not store a reference to this element -
3094  * the dom node can be overwritten by other code. Shorthand of {@link Ext.Element#fly}</p>
3095  * <p>Use this to make one-time references to DOM elements which are not going to be accessed again either by
3096  * application code, or by Ext's classes. If accessing an element which will be processed regularly, then {@link Ext#get}
3097  * will be more appropriate to take advantage of the caching provided by the Ext.Element class.</p>
3098  * @param {String/HTMLElement} el The dom node or id
3099  * @param {String} named (optional) Allows for creation of named reusable flyweights to prevent conflicts
3100  * (e.g. internally Ext uses "_global")
3101  * @return {Element} The shared Element object (or null if no matching element was found)
3102  * @member Ext.Element
3103  * @method fly
3104  */
3105 El.fly = function(el, named){
3106     var ret = null;
3107     named = named || '_global';
3108
3109     if (el = Ext.getDom(el)) {
3110         (El._flyweights[named] = El._flyweights[named] || new El.Flyweight()).dom = el;
3111         ret = El._flyweights[named];
3112     }
3113     return ret;
3114 };
3115
3116 /**
3117  * Retrieves Ext.Element objects.
3118  * <p><b>This method does not retrieve {@link Ext.Component Component}s.</b> This method
3119  * retrieves Ext.Element objects which encapsulate DOM elements. To retrieve a Component by
3120  * its ID, use {@link Ext.ComponentMgr#get}.</p>
3121  * <p>Uses simple caching to consistently return the same object. Automatically fixes if an
3122  * object was recreated with the same id via AJAX or DOM.</p>
3123  * Shorthand of {@link Ext.Element#get}
3124  * @param {Mixed} el The id of the node, a DOM Node or an existing Element.
3125  * @return {Element} The Element object (or null if no matching element was found)
3126  * @member Ext
3127  * @method get
3128  */
3129 Ext.get = El.get;
3130
3131 /**
3132  * <p>Gets the globally shared flyweight Element, with the passed node as the active element. Do not store a reference to this element -
3133  * the dom node can be overwritten by other code. Shorthand of {@link Ext.Element#fly}</p>
3134  * <p>Use this to make one-time references to DOM elements which are not going to be accessed again either by
3135  * application code, or by Ext's classes. If accessing an element which will be processed regularly, then {@link Ext#get}
3136  * will be more appropriate to take advantage of the caching provided by the Ext.Element class.</p>
3137  * @param {String/HTMLElement} el The dom node or id
3138  * @param {String} named (optional) Allows for creation of named reusable flyweights to prevent conflicts
3139  * (e.g. internally Ext uses "_global")
3140  * @return {Element} The shared Element object (or null if no matching element was found)
3141  * @member Ext
3142  * @method fly
3143  */
3144 Ext.fly = El.fly;
3145
3146 // speedy lookup for elements never to box adjust
3147 var noBoxAdjust = Ext.isStrict ? {
3148     select:1
3149 } : {
3150     input:1, select:1, textarea:1
3151 };
3152 if(Ext.isIE || Ext.isGecko){
3153     noBoxAdjust['button'] = 1;
3154 }
3155
3156 })();
3157 /**
3158  * @class Ext.Element
3159  */
3160 Ext.Element.addMethods(function(){
3161         var PARENTNODE = 'parentNode',
3162                 NEXTSIBLING = 'nextSibling',
3163                 PREVIOUSSIBLING = 'previousSibling',
3164                 DQ = Ext.DomQuery,
3165                 GET = Ext.get;
3166         
3167         return {
3168                 /**
3169              * 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)
3170              * @param {String} selector The simple selector to test
3171              * @param {Number/Mixed} maxDepth (optional) The max depth to search as a number or element (defaults to 50 || document.body)
3172              * @param {Boolean} returnEl (optional) True to return a Ext.Element object instead of DOM node
3173              * @return {HTMLElement} The matching DOM node (or null if no match was found)
3174              */
3175             findParent : function(simpleSelector, maxDepth, returnEl){
3176                 var p = this.dom,
3177                         b = document.body, 
3178                         depth = 0,                      
3179                         stopEl;         
3180             if(Ext.isGecko && Object.prototype.toString.call(p) == '[object XULElement]') {
3181                 return null;
3182             }
3183                 maxDepth = maxDepth || 50;
3184                 if (isNaN(maxDepth)) {
3185                     stopEl = Ext.getDom(maxDepth);
3186                     maxDepth = Number.MAX_VALUE;
3187                 }
3188                 while(p && p.nodeType == 1 && depth < maxDepth && p != b && p != stopEl){
3189                     if(DQ.is(p, simpleSelector)){
3190                         return returnEl ? GET(p) : p;
3191                     }
3192                     depth++;
3193                     p = p.parentNode;
3194                 }
3195                 return null;
3196             },
3197         
3198             /**
3199              * Looks at parent nodes for a match of the passed simple selector (e.g. div.some-class or span:first-child)
3200              * @param {String} selector The simple selector to test
3201              * @param {Number/Mixed} maxDepth (optional) The max depth to
3202                     search as a number or element (defaults to 10 || document.body)
3203              * @param {Boolean} returnEl (optional) True to return a Ext.Element object instead of DOM node
3204              * @return {HTMLElement} The matching DOM node (or null if no match was found)
3205              */
3206             findParentNode : function(simpleSelector, maxDepth, returnEl){
3207                 var p = Ext.fly(this.dom.parentNode, '_internal');
3208                 return p ? p.findParent(simpleSelector, maxDepth, returnEl) : null;
3209             },
3210         
3211             /**
3212              * Walks up the dom looking for a parent node that matches the passed simple selector (e.g. div.some-class or span:first-child).
3213              * This is a shortcut for findParentNode() that always returns an Ext.Element.
3214              * @param {String} selector The simple selector to test
3215              * @param {Number/Mixed} maxDepth (optional) The max depth to
3216                     search as a number or element (defaults to 10 || document.body)
3217              * @return {Ext.Element} The matching DOM node (or null if no match was found)
3218              */
3219             up : function(simpleSelector, maxDepth){
3220                 return this.findParentNode(simpleSelector, maxDepth, true);
3221             },
3222         
3223             /**
3224              * Creates a {@link Ext.CompositeElement} for child nodes based on the passed CSS selector (the selector should not contain an id).
3225              * @param {String} selector The CSS selector
3226              * @return {CompositeElement/CompositeElementLite} The composite element
3227              */
3228             select : function(selector){
3229                 return Ext.Element.select(selector, this.dom);
3230             },
3231         
3232             /**
3233              * Selects child nodes based on the passed CSS selector (the selector should not contain an id).
3234              * @param {String} selector The CSS selector
3235              * @return {Array} An array of the matched nodes
3236              */
3237             query : function(selector){
3238                 return DQ.select(selector, this.dom);
3239             },
3240         
3241             /**
3242              * Selects a single child at any depth below this element based on the passed CSS selector (the selector should not contain an id).
3243              * @param {String} selector The CSS selector
3244              * @param {Boolean} returnDom (optional) True to return the DOM node instead of Ext.Element (defaults to false)
3245              * @return {HTMLElement/Ext.Element} The child Ext.Element (or DOM node if returnDom = true)
3246              */
3247             child : function(selector, returnDom){
3248                 var n = DQ.selectNode(selector, this.dom);
3249                 return returnDom ? n : GET(n);
3250             },
3251         
3252             /**
3253              * Selects a single *direct* child based on the passed CSS selector (the selector should not contain an id).
3254              * @param {String} selector The CSS selector
3255              * @param {Boolean} returnDom (optional) True to return the DOM node instead of Ext.Element (defaults to false)
3256              * @return {HTMLElement/Ext.Element} The child Ext.Element (or DOM node if returnDom = true)
3257              */
3258             down : function(selector, returnDom){
3259                 var n = DQ.selectNode(" > " + selector, this.dom);
3260                 return returnDom ? n : GET(n);
3261             },
3262         
3263                  /**
3264              * Gets the parent node for this element, optionally chaining up trying to match a selector
3265              * @param {String} selector (optional) Find a parent node that matches the passed simple selector
3266              * @param {Boolean} returnDom (optional) True to return a raw dom node instead of an Ext.Element
3267              * @return {Ext.Element/HTMLElement} The parent node or null
3268                  */
3269             parent : function(selector, returnDom){
3270                 return this.matchNode(PARENTNODE, PARENTNODE, selector, returnDom);
3271             },
3272         
3273              /**
3274              * Gets the next sibling, skipping text nodes
3275              * @param {String} selector (optional) Find the next sibling that matches the passed simple selector
3276              * @param {Boolean} returnDom (optional) True to return a raw dom node instead of an Ext.Element
3277              * @return {Ext.Element/HTMLElement} The next sibling or null
3278                  */
3279             next : function(selector, returnDom){
3280                 return this.matchNode(NEXTSIBLING, NEXTSIBLING, selector, returnDom);
3281             },
3282         
3283             /**
3284              * Gets the previous sibling, skipping text nodes
3285              * @param {String} selector (optional) Find the previous sibling that matches the passed simple selector
3286              * @param {Boolean} returnDom (optional) True to return a raw dom node instead of an Ext.Element
3287              * @return {Ext.Element/HTMLElement} The previous sibling or null
3288                  */
3289             prev : function(selector, returnDom){
3290                 return this.matchNode(PREVIOUSSIBLING, PREVIOUSSIBLING, selector, returnDom);
3291             },
3292         
3293         
3294             /**
3295              * Gets the first child, skipping text nodes
3296              * @param {String} selector (optional) Find the next sibling that matches the passed simple selector
3297              * @param {Boolean} returnDom (optional) True to return a raw dom node instead of an Ext.Element
3298              * @return {Ext.Element/HTMLElement} The first child or null
3299                  */
3300             first : function(selector, returnDom){
3301                 return this.matchNode(NEXTSIBLING, 'firstChild', selector, returnDom);
3302             },
3303         
3304             /**
3305              * Gets the last child, skipping text nodes
3306              * @param {String} selector (optional) Find the previous sibling that matches the passed simple selector
3307              * @param {Boolean} returnDom (optional) True to return a raw dom node instead of an Ext.Element
3308              * @return {Ext.Element/HTMLElement} The last child or null
3309                  */
3310             last : function(selector, returnDom){
3311                 return this.matchNode(PREVIOUSSIBLING, 'lastChild', selector, returnDom);
3312             },
3313             
3314             matchNode : function(dir, start, selector, returnDom){
3315                 var n = this.dom[start];
3316                 while(n){
3317                     if(n.nodeType == 1 && (!selector || DQ.is(n, selector))){
3318                         return !returnDom ? GET(n) : n;
3319                     }
3320                     n = n[dir];
3321                 }
3322                 return null;
3323             }   
3324     };
3325 }());/**
3326  * @class Ext.Element
3327  */
3328 Ext.Element.addMethods(
3329 function() {
3330         var GETDOM = Ext.getDom,
3331                 GET = Ext.get,
3332                 DH = Ext.DomHelper;
3333         
3334         return {
3335             /**
3336              * Appends the passed element(s) to this element
3337              * @param {String/HTMLElement/Array/Element/CompositeElement} el
3338              * @return {Ext.Element} this
3339              */
3340             appendChild: function(el){        
3341                 return GET(el).appendTo(this);        
3342             },
3343         
3344             /**
3345              * Appends this element to the passed element
3346              * @param {Mixed} el The new parent element
3347              * @return {Ext.Element} this
3348              */
3349             appendTo: function(el){        
3350                 GETDOM(el).appendChild(this.dom);        
3351                 return this;
3352             },
3353         
3354             /**
3355              * Inserts this element before the passed element in the DOM
3356              * @param {Mixed} el The element before which this element will be inserted
3357              * @return {Ext.Element} this
3358              */
3359             insertBefore: function(el){                   
3360                 (el = GETDOM(el)).parentNode.insertBefore(this.dom, el);
3361                 return this;
3362             },
3363         
3364             /**
3365              * Inserts this element after the passed element in the DOM
3366              * @param {Mixed} el The element to insert after
3367              * @return {Ext.Element} this
3368              */
3369             insertAfter: function(el){
3370                 (el = GETDOM(el)).parentNode.insertBefore(this.dom, el.nextSibling);
3371                 return this;
3372             },
3373         
3374             /**
3375              * Inserts (or creates) an element (or DomHelper config) as the first child of this element
3376              * @param {Mixed/Object} el The id or element to insert or a DomHelper config to create and insert
3377              * @return {Ext.Element} The new child
3378              */
3379             insertFirst: function(el, returnDom){
3380             el = el || {};
3381             if(el.nodeType || el.dom || typeof el == 'string'){ // element
3382                 el = GETDOM(el);
3383                 this.dom.insertBefore(el, this.dom.firstChild);
3384                 return !returnDom ? GET(el) : el;
3385             }else{ // dh config
3386                 return this.createChild(el, this.dom.firstChild, returnDom);
3387             }
3388         },
3389         
3390             /**
3391              * Replaces the passed element with this element
3392              * @param {Mixed} el The element to replace
3393              * @return {Ext.Element} this
3394              */
3395             replace: function(el){
3396                 el = GET(el);
3397                 this.insertBefore(el);
3398                 el.remove();
3399                 return this;
3400             },
3401         
3402             /**
3403              * Replaces this element with the passed element
3404              * @param {Mixed/Object} el The new element or a DomHelper config of an element to create
3405              * @return {Ext.Element} this
3406              */
3407             replaceWith: function(el){
3408                     var me = this;
3409                 
3410             if(el.nodeType || el.dom || typeof el == 'string'){
3411                 el = GETDOM(el);
3412                 me.dom.parentNode.insertBefore(el, me.dom);
3413             }else{
3414                 el = DH.insertBefore(me.dom, el);
3415             }
3416                 
3417                 delete Ext.elCache[me.id];
3418                 Ext.removeNode(me.dom);      
3419                 me.id = Ext.id(me.dom = el);
3420                 Ext.Element.addToCache(me.isFlyweight ? new Ext.Element(me.dom) : me);     
3421             return me;
3422             },
3423             
3424                 /**
3425                  * Creates the passed DomHelper config and appends it to this element or optionally inserts it before the passed child element.
3426                  * @param {Object} config DomHelper element config object.  If no tag is specified (e.g., {tag:'input'}) then a div will be
3427                  * automatically generated with the specified attributes.
3428                  * @param {HTMLElement} insertBefore (optional) a child element of this element
3429                  * @param {Boolean} returnDom (optional) true to return the dom node instead of creating an Element
3430                  * @return {Ext.Element} The new child element
3431                  */
3432                 createChild: function(config, insertBefore, returnDom){
3433                     config = config || {tag:'div'};
3434                     return insertBefore ? 
3435                            DH.insertBefore(insertBefore, config, returnDom !== true) :  
3436                            DH[!this.dom.firstChild ? 'overwrite' : 'append'](this.dom, config,  returnDom !== true);
3437                 },
3438                 
3439                 /**
3440                  * Creates and wraps this element with another element
3441                  * @param {Object} config (optional) DomHelper element config object for the wrapper element or null for an empty div
3442                  * @param {Boolean} returnDom (optional) True to return the raw DOM element instead of Ext.Element
3443                  * @return {HTMLElement/Element} The newly created wrapper element
3444                  */
3445                 wrap: function(config, returnDom){        
3446                     var newEl = DH.insertBefore(this.dom, config || {tag: "div"}, !returnDom);
3447                     newEl.dom ? newEl.dom.appendChild(this.dom) : newEl.appendChild(this.dom);
3448                     return newEl;
3449                 },
3450                 
3451                 /**
3452                  * Inserts an html fragment into this element
3453                  * @param {String} where Where to insert the html in relation to this element - beforeBegin, afterBegin, beforeEnd, afterEnd.
3454                  * @param {String} html The HTML fragment
3455                  * @param {Boolean} returnEl (optional) True to return an Ext.Element (defaults to false)
3456                  * @return {HTMLElement/Ext.Element} The inserted node (or nearest related if more than 1 inserted)
3457                  */
3458                 insertHtml : function(where, html, returnEl){
3459                     var el = DH.insertHtml(where, this.dom, html);
3460                     return returnEl ? Ext.get(el) : el;
3461                 }
3462         };
3463 }());/**
3464  * @class Ext.Element
3465  */
3466 Ext.Element.addMethods(function(){
3467     // local style camelizing for speed
3468     var supports = Ext.supports,
3469         propCache = {},
3470         camelRe = /(-[a-z])/gi,
3471         view = document.defaultView,
3472         opacityRe = /alpha\(opacity=(.*)\)/i,
3473         trimRe = /^\s+|\s+$/g,
3474         EL = Ext.Element,
3475         spacesRe = /\s+/,
3476         wordsRe = /\w/g,
3477         PADDING = "padding",
3478         MARGIN = "margin",
3479         BORDER = "border",
3480         LEFT = "-left",
3481         RIGHT = "-right",
3482         TOP = "-top",
3483         BOTTOM = "-bottom",
3484         WIDTH = "-width",
3485         MATH = Math,
3486         HIDDEN = 'hidden',
3487         ISCLIPPED = 'isClipped',
3488         OVERFLOW = 'overflow',
3489         OVERFLOWX = 'overflow-x',
3490         OVERFLOWY = 'overflow-y',
3491         ORIGINALCLIP = 'originalClip',
3492         // special markup used throughout Ext when box wrapping elements
3493         borders = {l: BORDER + LEFT + WIDTH, r: BORDER + RIGHT + WIDTH, t: BORDER + TOP + WIDTH, b: BORDER + BOTTOM + WIDTH},
3494         paddings = {l: PADDING + LEFT, r: PADDING + RIGHT, t: PADDING + TOP, b: PADDING + BOTTOM},
3495         margins = {l: MARGIN + LEFT, r: MARGIN + RIGHT, t: MARGIN + TOP, b: MARGIN + BOTTOM},
3496         data = Ext.Element.data;
3497
3498
3499     // private
3500     function camelFn(m, a) {
3501         return a.charAt(1).toUpperCase();
3502     }
3503
3504     function chkCache(prop) {
3505         return propCache[prop] || (propCache[prop] = prop == 'float' ? (supports.cssFloat ? 'cssFloat' : 'styleFloat') : prop.replace(camelRe, camelFn));
3506     }
3507
3508     return {
3509         // private  ==> used by Fx
3510         adjustWidth : function(width) {
3511             var me = this;
3512             var isNum = (typeof width == "number");
3513             if(isNum && me.autoBoxAdjust && !me.isBorderBox()){
3514                width -= (me.getBorderWidth("lr") + me.getPadding("lr"));
3515             }
3516             return (isNum && width < 0) ? 0 : width;
3517         },
3518
3519         // private   ==> used by Fx
3520         adjustHeight : function(height) {
3521             var me = this;
3522             var isNum = (typeof height == "number");
3523             if(isNum && me.autoBoxAdjust && !me.isBorderBox()){
3524                height -= (me.getBorderWidth("tb") + me.getPadding("tb"));
3525             }
3526             return (isNum && height < 0) ? 0 : height;
3527         },
3528
3529
3530         /**
3531          * Adds one or more CSS classes to the element. Duplicate classes are automatically filtered out.
3532          * @param {String/Array} className The CSS class to add, or an array of classes
3533          * @return {Ext.Element} this
3534          */
3535         addClass : function(className){
3536             var me = this,
3537                 i,
3538                 len,
3539                 v,
3540                 cls = [];
3541             // Separate case is for speed
3542             if (!Ext.isArray(className)) {
3543                 if (typeof className == 'string' && !this.hasClass(className)) {
3544                     me.dom.className += " " + className;
3545                 }
3546             }
3547             else {
3548                 for (i = 0, len = className.length; i < len; i++) {
3549                     v = className[i];
3550                     if (typeof v == 'string' && (' ' + me.dom.className + ' ').indexOf(' ' + v + ' ') == -1) {
3551                         cls.push(v);
3552                     }
3553                 }
3554                 if (cls.length) {
3555                     me.dom.className += " " + cls.join(" ");
3556                 }
3557             }
3558             return me;
3559         },
3560
3561         /**
3562          * Removes one or more CSS classes from the element.
3563          * @param {String/Array} className The CSS class to remove, or an array of classes
3564          * @return {Ext.Element} this
3565          */
3566         removeClass : function(className){
3567             var me = this,
3568                 i,
3569                 idx,
3570                 len,
3571                 cls,
3572                 elClasses;
3573             if (!Ext.isArray(className)){
3574                 className = [className];
3575             }
3576             if (me.dom && me.dom.className) {
3577                 elClasses = me.dom.className.replace(trimRe, '').split(spacesRe);
3578                 for (i = 0, len = className.length; i < len; i++) {
3579                     cls = className[i];
3580                     if (typeof cls == 'string') {
3581                         cls = cls.replace(trimRe, '');
3582                         idx = elClasses.indexOf(cls);
3583                         if (idx != -1) {
3584                             elClasses.splice(idx, 1);
3585                         }
3586                     }
3587                 }
3588                 me.dom.className = elClasses.join(" ");
3589             }
3590             return me;
3591         },
3592
3593         /**
3594          * Adds one or more CSS classes to this element and removes the same class(es) from all siblings.
3595          * @param {String/Array} className The CSS class to add, or an array of classes
3596          * @return {Ext.Element} this
3597          */
3598         radioClass : function(className){
3599             var cn = this.dom.parentNode.childNodes,
3600                 v,
3601                 i,
3602                 len;
3603             className = Ext.isArray(className) ? className : [className];
3604             for (i = 0, len = cn.length; i < len; i++) {
3605                 v = cn[i];
3606                 if (v && v.nodeType == 1) {
3607                     Ext.fly(v, '_internal').removeClass(className);
3608                 }
3609             };
3610             return this.addClass(className);
3611         },
3612
3613         /**
3614          * Toggles the specified CSS class on this element (removes it if it already exists, otherwise adds it).
3615          * @param {String} className The CSS class to toggle
3616          * @return {Ext.Element} this
3617          */
3618         toggleClass : function(className){
3619             return this.hasClass(className) ? this.removeClass(className) : this.addClass(className);
3620         },
3621
3622         /**
3623          * Checks if the specified CSS class exists on this element's DOM node.
3624          * @param {String} className The CSS class to check for
3625          * @return {Boolean} True if the class exists, else false
3626          */
3627         hasClass : function(className){
3628             return className && (' '+this.dom.className+' ').indexOf(' '+className+' ') != -1;
3629         },
3630
3631         /**
3632          * Replaces a CSS class on the element with another.  If the old name does not exist, the new name will simply be added.
3633          * @param {String} oldClassName The CSS class to replace
3634          * @param {String} newClassName The replacement CSS class
3635          * @return {Ext.Element} this
3636          */
3637         replaceClass : function(oldClassName, newClassName){
3638             return this.removeClass(oldClassName).addClass(newClassName);
3639         },
3640
3641         isStyle : function(style, val) {
3642             return this.getStyle(style) == val;
3643         },
3644
3645         /**
3646          * Normalizes currentStyle and computedStyle.
3647          * @param {String} property The style property whose value is returned.
3648          * @return {String} The current value of the style property for this element.
3649          */
3650         getStyle : function(){
3651             return view && view.getComputedStyle ?
3652                 function(prop){
3653                     var el = this.dom,
3654                         v,
3655                         cs,
3656                         out,
3657                         display;
3658
3659                     if(el == document){
3660                         return null;
3661                     }
3662                     prop = chkCache(prop);
3663                     out = (v = el.style[prop]) ? v :
3664                            (cs = view.getComputedStyle(el, "")) ? cs[prop] : null;
3665                            
3666                     // Ignore cases when the margin is correctly reported as 0, the bug only shows
3667                     // numbers larger.
3668                     if(prop == 'marginRight' && out != '0px' && !supports.correctRightMargin){
3669                         display = el.style.display;
3670                         el.style.display = 'inline-block';
3671                         out = view.getComputedStyle(el, '').marginRight;
3672                         el.style.display = display;
3673                     }
3674                     
3675                     if(prop == 'backgroundColor' && out == 'rgba(0, 0, 0, 0)' && !supports.correctTransparentColor){
3676                         out = 'transparent';
3677                     }
3678                     return out;
3679                 } :
3680                 function(prop){
3681                     var el = this.dom,
3682                         m,
3683                         cs;
3684
3685                     if(el == document) return null;
3686                     if (prop == 'opacity') {
3687                         if (el.style.filter.match) {
3688                             if(m = el.style.filter.match(opacityRe)){
3689                                 var fv = parseFloat(m[1]);
3690                                 if(!isNaN(fv)){
3691                                     return fv ? fv / 100 : 0;
3692                                 }
3693                             }
3694                         }
3695                         return 1;
3696                     }
3697                     prop = chkCache(prop);
3698                     return el.style[prop] || ((cs = el.currentStyle) ? cs[prop] : null);
3699                 };
3700         }(),
3701
3702         /**
3703          * Return the CSS color for the specified CSS attribute. rgb, 3 digit (like #fff) and valid values
3704          * are convert to standard 6 digit hex color.
3705          * @param {String} attr The css attribute
3706          * @param {String} defaultValue The default value to use when a valid color isn't found
3707          * @param {String} prefix (optional) defaults to #. Use an empty string when working with
3708          * color anims.
3709          */
3710         getColor : function(attr, defaultValue, prefix){
3711             var v = this.getStyle(attr),
3712                 color = (typeof prefix != 'undefined') ? prefix : '#',
3713                 h;
3714
3715             if(!v || (/transparent|inherit/.test(v))) {
3716                 return defaultValue;
3717             }
3718             if(/^r/.test(v)){
3719                 Ext.each(v.slice(4, v.length -1).split(','), function(s){
3720                     h = parseInt(s, 10);
3721                     color += (h < 16 ? '0' : '') + h.toString(16);
3722                 });
3723             }else{
3724                 v = v.replace('#', '');
3725                 color += v.length == 3 ? v.replace(/^(\w)(\w)(\w)$/, '$1$1$2$2$3$3') : v;
3726             }
3727             return(color.length > 5 ? color.toLowerCase() : defaultValue);
3728         },
3729
3730         /**
3731          * Wrapper for setting style properties, also takes single object parameter of multiple styles.
3732          * @param {String/Object} property The style property to be set, or an object of multiple styles.
3733          * @param {String} value (optional) The value to apply to the given property, or null if an object was passed.
3734          * @return {Ext.Element} this
3735          */
3736         setStyle : function(prop, value){
3737             var tmp, style;
3738             
3739             if (typeof prop != 'object') {
3740                 tmp = {};
3741                 tmp[prop] = value;
3742                 prop = tmp;
3743             }
3744             for (style in prop) {
3745                 value = prop[style];
3746                 style == 'opacity' ?
3747                     this.setOpacity(value) :
3748                     this.dom.style[chkCache(style)] = value;
3749             }
3750             return this;
3751         },
3752
3753         /**
3754          * Set the opacity of the element
3755          * @param {Float} opacity The new opacity. 0 = transparent, .5 = 50% visibile, 1 = fully visible, etc
3756          * @param {Boolean/Object} animate (optional) a standard Element animation config object or <tt>true</tt> for
3757          * the default animation (<tt>{duration: .35, easing: 'easeIn'}</tt>)
3758          * @return {Ext.Element} this
3759          */
3760          setOpacity : function(opacity, animate){
3761             var me = this,
3762                 s = me.dom.style;
3763
3764             if(!animate || !me.anim){
3765                 if(Ext.isIE){
3766                     var opac = opacity < 1 ? 'alpha(opacity=' + opacity * 100 + ')' : '',
3767                     val = s.filter.replace(opacityRe, '').replace(trimRe, '');
3768
3769                     s.zoom = 1;
3770                     s.filter = val + (val.length > 0 ? ' ' : '') + opac;
3771                 }else{
3772                     s.opacity = opacity;
3773                 }
3774             }else{
3775                 me.anim({opacity: {to: opacity}}, me.preanim(arguments, 1), null, .35, 'easeIn');
3776             }
3777             return me;
3778         },
3779
3780         /**
3781          * Clears any opacity settings from this element. Required in some cases for IE.
3782          * @return {Ext.Element} this
3783          */
3784         clearOpacity : function(){
3785             var style = this.dom.style;
3786             if(Ext.isIE){
3787                 if(!Ext.isEmpty(style.filter)){
3788                     style.filter = style.filter.replace(opacityRe, '').replace(trimRe, '');
3789                 }
3790             }else{
3791                 style.opacity = style['-moz-opacity'] = style['-khtml-opacity'] = '';
3792             }
3793             return this;
3794         },
3795
3796         /**
3797          * Returns the offset height of the element
3798          * @param {Boolean} contentHeight (optional) true to get the height minus borders and padding
3799          * @return {Number} The element's height
3800          */
3801         getHeight : function(contentHeight){
3802             var me = this,
3803                 dom = me.dom,
3804                 hidden = Ext.isIE && me.isStyle('display', 'none'),
3805                 h = MATH.max(dom.offsetHeight, hidden ? 0 : dom.clientHeight) || 0;
3806
3807             h = !contentHeight ? h : h - me.getBorderWidth("tb") - me.getPadding("tb");
3808             return h < 0 ? 0 : h;
3809         },
3810
3811         /**
3812          * Returns the offset width of the element
3813          * @param {Boolean} contentWidth (optional) true to get the width minus borders and padding
3814          * @return {Number} The element's width
3815          */
3816         getWidth : function(contentWidth){
3817             var me = this,
3818                 dom = me.dom,
3819                 hidden = Ext.isIE && me.isStyle('display', 'none'),
3820                 w = MATH.max(dom.offsetWidth, hidden ? 0 : dom.clientWidth) || 0;
3821             w = !contentWidth ? w : w - me.getBorderWidth("lr") - me.getPadding("lr");
3822             return w < 0 ? 0 : w;
3823         },
3824
3825         /**
3826          * Set the width of this Element.
3827          * @param {Mixed} width The new width. This may be one of:<div class="mdetail-params"><ul>
3828          * <li>A Number specifying the new width in this Element's {@link #defaultUnit}s (by default, pixels).</li>
3829          * <li>A String used to set the CSS width style. Animation may <b>not</b> be used.
3830          * </ul></div>
3831          * @param {Boolean/Object} animate (optional) true for the default animation or a standard Element animation config object
3832          * @return {Ext.Element} this
3833          */
3834         setWidth : function(width, animate){
3835             var me = this;
3836             width = me.adjustWidth(width);
3837             !animate || !me.anim ?
3838                 me.dom.style.width = me.addUnits(width) :
3839                 me.anim({width : {to : width}}, me.preanim(arguments, 1));
3840             return me;
3841         },
3842
3843         /**
3844          * Set the height of this Element.
3845          * <pre><code>
3846 // change the height to 200px and animate with default configuration
3847 Ext.fly('elementId').setHeight(200, true);
3848
3849 // change the height to 150px and animate with a custom configuration
3850 Ext.fly('elId').setHeight(150, {
3851     duration : .5, // animation will have a duration of .5 seconds
3852     // will change the content to "finished"
3853     callback: function(){ this.{@link #update}("finished"); }
3854 });
3855          * </code></pre>
3856          * @param {Mixed} height The new height. This may be one of:<div class="mdetail-params"><ul>
3857          * <li>A Number specifying the new height in this Element's {@link #defaultUnit}s (by default, pixels.)</li>
3858          * <li>A String used to set the CSS height style. Animation may <b>not</b> be used.</li>
3859          * </ul></div>
3860          * @param {Boolean/Object} animate (optional) true for the default animation or a standard Element animation config object
3861          * @return {Ext.Element} this
3862          */
3863          setHeight : function(height, animate){
3864             var me = this;
3865             height = me.adjustHeight(height);
3866             !animate || !me.anim ?
3867                 me.dom.style.height = me.addUnits(height) :
3868                 me.anim({height : {to : height}}, me.preanim(arguments, 1));
3869             return me;
3870         },
3871
3872         /**
3873          * Gets the width of the border(s) for the specified side(s)
3874          * @param {String} side Can be t, l, r, b or any combination of those to add multiple values. For example,
3875          * passing <tt>'lr'</tt> would get the border <b><u>l</u></b>eft width + the border <b><u>r</u></b>ight width.
3876          * @return {Number} The width of the sides passed added together
3877          */
3878         getBorderWidth : function(side){
3879             return this.addStyles(side, borders);
3880         },
3881
3882         /**
3883          * Gets the width of the padding(s) for the specified side(s)
3884          * @param {String} side Can be t, l, r, b or any combination of those to add multiple values. For example,
3885          * passing <tt>'lr'</tt> would get the padding <b><u>l</u></b>eft + the padding <b><u>r</u></b>ight.
3886          * @return {Number} The padding of the sides passed added together
3887          */
3888         getPadding : function(side){
3889             return this.addStyles(side, paddings);
3890         },
3891
3892         /**
3893          *  Store the current overflow setting and clip overflow on the element - use <tt>{@link #unclip}</tt> to remove
3894          * @return {Ext.Element} this
3895          */
3896         clip : function(){
3897             var me = this,
3898                 dom = me.dom;
3899
3900             if(!data(dom, ISCLIPPED)){
3901                 data(dom, ISCLIPPED, true);
3902                 data(dom, ORIGINALCLIP, {
3903                     o: me.getStyle(OVERFLOW),
3904                     x: me.getStyle(OVERFLOWX),
3905                     y: me.getStyle(OVERFLOWY)
3906                 });
3907                 me.setStyle(OVERFLOW, HIDDEN);
3908                 me.setStyle(OVERFLOWX, HIDDEN);
3909                 me.setStyle(OVERFLOWY, HIDDEN);
3910             }
3911             return me;
3912         },
3913
3914         /**
3915          *  Return clipping (overflow) to original clipping before <tt>{@link #clip}</tt> was called
3916          * @return {Ext.Element} this
3917          */
3918         unclip : function(){
3919             var me = this,
3920                 dom = me.dom;
3921
3922             if(data(dom, ISCLIPPED)){
3923                 data(dom, ISCLIPPED, false);
3924                 var o = data(dom, ORIGINALCLIP);
3925                 if(o.o){
3926                     me.setStyle(OVERFLOW, o.o);
3927                 }
3928                 if(o.x){
3929                     me.setStyle(OVERFLOWX, o.x);
3930                 }
3931                 if(o.y){
3932                     me.setStyle(OVERFLOWY, o.y);
3933                 }
3934             }
3935             return me;
3936         },
3937
3938         // private
3939         addStyles : function(sides, styles){
3940             var ttlSize = 0,
3941                 sidesArr = sides.match(wordsRe),
3942                 side,
3943                 size,
3944                 i,
3945                 len = sidesArr.length;
3946             for (i = 0; i < len; i++) {
3947                 side = sidesArr[i];
3948                 size = side && parseInt(this.getStyle(styles[side]), 10);
3949                 if (size) {
3950                     ttlSize += MATH.abs(size);
3951                 }
3952             }
3953             return ttlSize;
3954         },
3955
3956         margins : margins
3957     };
3958 }()
3959 );
3960 /**
3961  * @class Ext.Element
3962  */
3963 (function(){
3964 var D = Ext.lib.Dom,
3965         LEFT = "left",
3966         RIGHT = "right",
3967         TOP = "top",
3968         BOTTOM = "bottom",
3969         POSITION = "position",
3970         STATIC = "static",
3971         RELATIVE = "relative",
3972         AUTO = "auto",
3973         ZINDEX = "z-index";
3974
3975 Ext.Element.addMethods({
3976         /**
3977       * 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).
3978       * @return {Number} The X position of the element
3979       */
3980     getX : function(){
3981         return D.getX(this.dom);
3982     },
3983
3984     /**
3985       * 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).
3986       * @return {Number} The Y position of the element
3987       */
3988     getY : function(){
3989         return D.getY(this.dom);
3990     },
3991
3992     /**
3993       * 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).
3994       * @return {Array} The XY position of the element
3995       */
3996     getXY : function(){
3997         return D.getXY(this.dom);
3998     },
3999
4000     /**
4001       * 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.
4002       * @param {Mixed} element The element to get the offsets from.
4003       * @return {Array} The XY page offsets (e.g. [100, -200])
4004       */
4005     getOffsetsTo : function(el){
4006         var o = this.getXY(),
4007                 e = Ext.fly(el, '_internal').getXY();
4008         return [o[0]-e[0],o[1]-e[1]];
4009     },
4010
4011     /**
4012      * 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).
4013      * @param {Number} The X position of the element
4014      * @param {Boolean/Object} animate (optional) True for the default animation, or a standard Element animation config object
4015      * @return {Ext.Element} this
4016      */
4017     setX : function(x, animate){            
4018             return this.setXY([x, this.getY()], this.animTest(arguments, animate, 1));
4019     },
4020
4021     /**
4022      * 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).
4023      * @param {Number} The Y position of the element
4024      * @param {Boolean/Object} animate (optional) True for the default animation, or a standard Element animation config object
4025      * @return {Ext.Element} this
4026      */
4027     setY : function(y, animate){            
4028             return this.setXY([this.getX(), y], this.animTest(arguments, animate, 1));
4029     },
4030
4031     /**
4032      * Sets the element's left position directly using CSS style (instead of {@link #setX}).
4033      * @param {String} left The left CSS property value
4034      * @return {Ext.Element} this
4035      */
4036     setLeft : function(left){
4037         this.setStyle(LEFT, this.addUnits(left));
4038         return this;
4039     },
4040
4041     /**
4042      * Sets the element's top position directly using CSS style (instead of {@link #setY}).
4043      * @param {String} top The top CSS property value
4044      * @return {Ext.Element} this
4045      */
4046     setTop : function(top){
4047         this.setStyle(TOP, this.addUnits(top));
4048         return this;
4049     },
4050
4051     /**
4052      * Sets the element's CSS right style.
4053      * @param {String} right The right CSS property value
4054      * @return {Ext.Element} this
4055      */
4056     setRight : function(right){
4057         this.setStyle(RIGHT, this.addUnits(right));
4058         return this;
4059     },
4060
4061     /**
4062      * Sets the element's CSS bottom style.
4063      * @param {String} bottom The bottom CSS property value
4064      * @return {Ext.Element} this
4065      */
4066     setBottom : function(bottom){
4067         this.setStyle(BOTTOM, this.addUnits(bottom));
4068         return this;
4069     },
4070
4071     /**
4072      * Sets the position of the element in page coordinates, regardless of how the element is positioned.
4073      * The element must be part of the DOM tree to have page coordinates (display:none or elements not appended return false).
4074      * @param {Array} pos Contains X & Y [x, y] values for new position (coordinates are page-based)
4075      * @param {Boolean/Object} animate (optional) True for the default animation, or a standard Element animation config object
4076      * @return {Ext.Element} this
4077      */
4078     setXY : function(pos, animate){
4079             var me = this;
4080         if(!animate || !me.anim){
4081             D.setXY(me.dom, pos);
4082         }else{
4083             me.anim({points: {to: pos}}, me.preanim(arguments, 1), 'motion');
4084         }
4085         return me;
4086     },
4087
4088     /**
4089      * Sets the position of the element in page coordinates, regardless of how the element is positioned.
4090      * The element must be part of the DOM tree to have page coordinates (display:none or elements not appended return false).
4091      * @param {Number} x X value for new position (coordinates are page-based)
4092      * @param {Number} y Y value for new position (coordinates are page-based)
4093      * @param {Boolean/Object} animate (optional) True for the default animation, or a standard Element animation config object
4094      * @return {Ext.Element} this
4095      */
4096     setLocation : function(x, y, animate){
4097         return this.setXY([x, y], this.animTest(arguments, animate, 2));
4098     },
4099
4100     /**
4101      * Sets the position of the element in page coordinates, regardless of how the element is positioned.
4102      * The element must be part of the DOM tree to have page coordinates (display:none or elements not appended return false).
4103      * @param {Number} x X value for new position (coordinates are page-based)
4104      * @param {Number} y Y value for new position (coordinates are page-based)
4105      * @param {Boolean/Object} animate (optional) True for the default animation, or a standard Element animation config object
4106      * @return {Ext.Element} this
4107      */
4108     moveTo : function(x, y, animate){
4109         return this.setXY([x, y], this.animTest(arguments, animate, 2));        
4110     },    
4111     
4112     /**
4113      * Gets the left X coordinate
4114      * @param {Boolean} local True to get the local css position instead of page coordinate
4115      * @return {Number}
4116      */
4117     getLeft : function(local){
4118             return !local ? this.getX() : parseInt(this.getStyle(LEFT), 10) || 0;
4119     },
4120
4121     /**
4122      * Gets the right X coordinate of the element (element X position + element width)
4123      * @param {Boolean} local True to get the local css position instead of page coordinate
4124      * @return {Number}
4125      */
4126     getRight : function(local){
4127             var me = this;
4128             return !local ? me.getX() + me.getWidth() : (me.getLeft(true) + me.getWidth()) || 0;
4129     },
4130
4131     /**
4132      * Gets the top Y coordinate
4133      * @param {Boolean} local True to get the local css position instead of page coordinate
4134      * @return {Number}
4135      */
4136     getTop : function(local) {
4137             return !local ? this.getY() : parseInt(this.getStyle(TOP), 10) || 0;
4138     },
4139
4140     /**
4141      * Gets the bottom Y coordinate of the element (element Y position + element height)
4142      * @param {Boolean} local True to get the local css position instead of page coordinate
4143      * @return {Number}
4144      */
4145     getBottom : function(local){
4146             var me = this;
4147             return !local ? me.getY() + me.getHeight() : (me.getTop(true) + me.getHeight()) || 0;
4148     },
4149
4150     /**
4151     * Initializes positioning on this element. If a desired position is not passed, it will make the
4152     * the element positioned relative IF it is not already positioned.
4153     * @param {String} pos (optional) Positioning to use "relative", "absolute" or "fixed"
4154     * @param {Number} zIndex (optional) The zIndex to apply
4155     * @param {Number} x (optional) Set the page X position
4156     * @param {Number} y (optional) Set the page Y position
4157     */
4158     position : function(pos, zIndex, x, y){
4159             var me = this;
4160             
4161         if(!pos && me.isStyle(POSITION, STATIC)){           
4162             me.setStyle(POSITION, RELATIVE);           
4163         } else if(pos) {
4164             me.setStyle(POSITION, pos);
4165         }
4166         if(zIndex){
4167             me.setStyle(ZINDEX, zIndex);
4168         }
4169         if(x || y) me.setXY([x || false, y || false]);
4170     },
4171
4172     /**
4173     * Clear positioning back to the default when the document was loaded
4174     * @param {String} value (optional) The value to use for the left,right,top,bottom, defaults to '' (empty string). You could use 'auto'.
4175     * @return {Ext.Element} this
4176      */
4177     clearPositioning : function(value){
4178         value = value || '';
4179         this.setStyle({
4180             left : value,
4181             right : value,
4182             top : value,
4183             bottom : value,
4184             "z-index" : "",
4185             position : STATIC
4186         });
4187         return this;
4188     },
4189
4190     /**
4191     * Gets an object with all CSS positioning properties. Useful along with setPostioning to get
4192     * snapshot before performing an update and then restoring the element.
4193     * @return {Object}
4194     */
4195     getPositioning : function(){
4196         var l = this.getStyle(LEFT);
4197         var t = this.getStyle(TOP);
4198         return {
4199             "position" : this.getStyle(POSITION),
4200             "left" : l,
4201             "right" : l ? "" : this.getStyle(RIGHT),
4202             "top" : t,
4203             "bottom" : t ? "" : this.getStyle(BOTTOM),
4204             "z-index" : this.getStyle(ZINDEX)
4205         };
4206     },
4207     
4208     /**
4209     * Set positioning with an object returned by getPositioning().
4210     * @param {Object} posCfg
4211     * @return {Ext.Element} this
4212      */
4213     setPositioning : function(pc){
4214             var me = this,
4215                 style = me.dom.style;
4216                 
4217         me.setStyle(pc);
4218         
4219         if(pc.right == AUTO){
4220             style.right = "";
4221         }
4222         if(pc.bottom == AUTO){
4223             style.bottom = "";
4224         }
4225         
4226         return me;
4227     },    
4228         
4229     /**
4230      * Translates the passed page coordinates into left/top css values for this element
4231      * @param {Number/Array} x The page x or an array containing [x, y]
4232      * @param {Number} y (optional) The page y, required if x is not an array
4233      * @return {Object} An object with left and top properties. e.g. {left: (value), top: (value)}
4234      */
4235     translatePoints : function(x, y){                
4236             y = isNaN(x[1]) ? y : x[1];
4237         x = isNaN(x[0]) ? x : x[0];
4238         var me = this,
4239                 relative = me.isStyle(POSITION, RELATIVE),
4240                 o = me.getXY(),
4241                 l = parseInt(me.getStyle(LEFT), 10),
4242                 t = parseInt(me.getStyle(TOP), 10);
4243         
4244         l = !isNaN(l) ? l : (relative ? 0 : me.dom.offsetLeft);
4245         t = !isNaN(t) ? t : (relative ? 0 : me.dom.offsetTop);        
4246
4247         return {left: (x - o[0] + l), top: (y - o[1] + t)}; 
4248     },
4249     
4250     animTest : function(args, animate, i) {
4251         return !!animate && this.preanim ? this.preanim(args, i) : false;
4252     }
4253 });
4254 })();/**
4255  * @class Ext.Element
4256  */
4257 Ext.Element.addMethods({
4258     /**
4259      * Returns true if this element is scrollable.
4260      * @return {Boolean}
4261      */
4262     isScrollable : function(){
4263         var dom = this.dom;
4264         return dom.scrollHeight > dom.clientHeight || dom.scrollWidth > dom.clientWidth;
4265     },
4266
4267     /**
4268      * 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().
4269      * @param {String} side Either "left" for scrollLeft values or "top" for scrollTop values.
4270      * @param {Number} value The new scroll value.
4271      * @return {Element} this
4272      */
4273     scrollTo : function(side, value){
4274         this.dom["scroll" + (/top/i.test(side) ? "Top" : "Left")] = value;
4275         return this;
4276     },
4277
4278     /**
4279      * Returns the current scroll position of the element.
4280      * @return {Object} An object containing the scroll position in the format {left: (scrollLeft), top: (scrollTop)}
4281      */
4282     getScroll : function(){
4283         var d = this.dom, 
4284             doc = document,
4285             body = doc.body,
4286             docElement = doc.documentElement,
4287             l,
4288             t,
4289             ret;
4290
4291         if(d == doc || d == body){
4292             if(Ext.isIE && Ext.isStrict){
4293                 l = docElement.scrollLeft; 
4294                 t = docElement.scrollTop;
4295             }else{
4296                 l = window.pageXOffset;
4297                 t = window.pageYOffset;
4298             }
4299             ret = {left: l || (body ? body.scrollLeft : 0), top: t || (body ? body.scrollTop : 0)};
4300         }else{
4301             ret = {left: d.scrollLeft, top: d.scrollTop};
4302         }
4303         return ret;
4304     }
4305 });/**
4306  * @class Ext.Element
4307  */
4308 /**
4309  * Visibility mode constant for use with {@link #setVisibilityMode}. Use visibility to hide element
4310  * @static
4311  * @type Number
4312  */
4313 Ext.Element.VISIBILITY = 1;
4314 /**
4315  * Visibility mode constant for use with {@link #setVisibilityMode}. Use display to hide element
4316  * @static
4317  * @type Number
4318  */
4319 Ext.Element.DISPLAY = 2;
4320
4321 /**
4322  * Visibility mode constant for use with {@link #setVisibilityMode}. Use offsets (x and y positioning offscreen)
4323  * to hide element.
4324  * @static
4325  * @type Number
4326  */
4327 Ext.Element.OFFSETS = 3;
4328
4329
4330 Ext.Element.ASCLASS = 4;
4331
4332 /**
4333  * Defaults to 'x-hide-nosize'
4334  * @static
4335  * @type String
4336  */
4337 Ext.Element.visibilityCls = 'x-hide-nosize';
4338
4339 Ext.Element.addMethods(function(){
4340     var El = Ext.Element,
4341         OPACITY = "opacity",
4342         VISIBILITY = "visibility",
4343         DISPLAY = "display",
4344         HIDDEN = "hidden",
4345         OFFSETS = "offsets",
4346         ASCLASS = "asclass",
4347         NONE = "none",
4348         NOSIZE = 'nosize',
4349         ORIGINALDISPLAY = 'originalDisplay',
4350         VISMODE = 'visibilityMode',
4351         ISVISIBLE = 'isVisible',
4352         data = El.data,
4353         getDisplay = function(dom){
4354             var d = data(dom, ORIGINALDISPLAY);
4355             if(d === undefined){
4356                 data(dom, ORIGINALDISPLAY, d = '');
4357             }
4358             return d;
4359         },
4360         getVisMode = function(dom){
4361             var m = data(dom, VISMODE);
4362             if(m === undefined){
4363                 data(dom, VISMODE, m = 1);
4364             }
4365             return m;
4366         };
4367
4368     return {
4369         /**
4370          * The element's default display mode  (defaults to "")
4371          * @type String
4372          */
4373         originalDisplay : "",
4374         visibilityMode : 1,
4375
4376         /**
4377          * Sets the element's visibility mode. When setVisible() is called it
4378          * will use this to determine whether to set the visibility or the display property.
4379          * @param {Number} visMode Ext.Element.VISIBILITY or Ext.Element.DISPLAY
4380          * @return {Ext.Element} this
4381          */
4382         setVisibilityMode : function(visMode){
4383             data(this.dom, VISMODE, visMode);
4384             return this;
4385         },
4386
4387         /**
4388          * Perform custom animation on this element.
4389          * <div><ul class="mdetail-params">
4390          * <li><u>Animation Properties</u></li>
4391          *
4392          * <p>The Animation Control Object enables gradual transitions for any member of an
4393          * element's style object that takes a numeric value including but not limited to
4394          * these properties:</p><div><ul class="mdetail-params">
4395          * <li><tt>bottom, top, left, right</tt></li>
4396          * <li><tt>height, width</tt></li>
4397          * <li><tt>margin, padding</tt></li>
4398          * <li><tt>borderWidth</tt></li>
4399          * <li><tt>opacity</tt></li>
4400          * <li><tt>fontSize</tt></li>
4401          * <li><tt>lineHeight</tt></li>
4402          * </ul></div>
4403          *
4404          *
4405          * <li><u>Animation Property Attributes</u></li>
4406          *
4407          * <p>Each Animation Property is a config object with optional properties:</p>
4408          * <div><ul class="mdetail-params">
4409          * <li><tt>by</tt>*  : relative change - start at current value, change by this value</li>
4410          * <li><tt>from</tt> : ignore current value, start from this value</li>
4411          * <li><tt>to</tt>*  : start at current value, go to this value</li>
4412          * <li><tt>unit</tt> : any allowable unit specification</li>
4413          * <p>* do not specify both <tt>to</tt> and <tt>by</tt> for an animation property</p>
4414          * </ul></div>
4415          *
4416          * <li><u>Animation Types</u></li>
4417          *
4418          * <p>The supported animation types:</p><div><ul class="mdetail-params">
4419          * <li><tt>'run'</tt> : Default
4420          * <pre><code>
4421 var el = Ext.get('complexEl');
4422 el.animate(
4423     // animation control object
4424     {
4425         borderWidth: {to: 3, from: 0},
4426         opacity: {to: .3, from: 1},
4427         height: {to: 50, from: el.getHeight()},
4428         width: {to: 300, from: el.getWidth()},
4429         top  : {by: - 100, unit: 'px'},
4430     },
4431     0.35,      // animation duration
4432     null,      // callback
4433     'easeOut', // easing method
4434     'run'      // animation type ('run','color','motion','scroll')
4435 );
4436          * </code></pre>
4437          * </li>
4438          * <li><tt>'color'</tt>
4439          * <p>Animates transition of background, text, or border colors.</p>
4440          * <pre><code>
4441 el.animate(
4442     // animation control object
4443     {
4444         color: { to: '#06e' },
4445         backgroundColor: { to: '#e06' }
4446     },
4447     0.35,      // animation duration
4448     null,      // callback
4449     'easeOut', // easing method
4450     'color'    // animation type ('run','color','motion','scroll')
4451 );
4452          * </code></pre>
4453          * </li>
4454          *
4455          * <li><tt>'motion'</tt>
4456          * <p>Animates the motion of an element to/from specific points using optional bezier
4457          * way points during transit.</p>
4458          * <pre><code>
4459 el.animate(
4460     // animation control object
4461     {
4462         borderWidth: {to: 3, from: 0},
4463         opacity: {to: .3, from: 1},
4464         height: {to: 50, from: el.getHeight()},
4465         width: {to: 300, from: el.getWidth()},
4466         top  : {by: - 100, unit: 'px'},
4467         points: {
4468             to: [50, 100],  // go to this point
4469             control: [      // optional bezier way points
4470                 [ 600, 800],
4471                 [-100, 200]
4472             ]
4473         }
4474     },
4475     3000,      // animation duration (milliseconds!)
4476     null,      // callback
4477     'easeOut', // easing method
4478     'motion'   // animation type ('run','color','motion','scroll')
4479 );
4480          * </code></pre>
4481          * </li>
4482          * <li><tt>'scroll'</tt>
4483          * <p>Animate horizontal or vertical scrolling of an overflowing page element.</p>
4484          * <pre><code>
4485 el.animate(
4486     // animation control object
4487     {
4488         scroll: {to: [400, 300]}
4489     },
4490     0.35,      // animation duration
4491     null,      // callback
4492     'easeOut', // easing method
4493     'scroll'   // animation type ('run','color','motion','scroll')
4494 );
4495          * </code></pre>
4496          * </li>
4497          * </ul></div>
4498          *
4499          * </ul></div>
4500          *
4501          * @param {Object} args The animation control args
4502          * @param {Float} duration (optional) How long the animation lasts in seconds (defaults to <tt>.35</tt>)
4503          * @param {Function} onComplete (optional) Function to call when animation completes
4504          * @param {String} easing (optional) {@link Ext.Fx#easing} method to use (defaults to <tt>'easeOut'</tt>)
4505          * @param {String} animType (optional) <tt>'run'</tt> is the default. Can also be <tt>'color'</tt>,
4506          * <tt>'motion'</tt>, or <tt>'scroll'</tt>
4507          * @return {Ext.Element} this
4508          */
4509         animate : function(args, duration, onComplete, easing, animType){
4510             this.anim(args, {duration: duration, callback: onComplete, easing: easing}, animType);
4511             return this;
4512         },
4513
4514         /*
4515          * @private Internal animation call
4516          */
4517         anim : function(args, opt, animType, defaultDur, defaultEase, cb){
4518             animType = animType || 'run';
4519             opt = opt || {};
4520             var me = this,
4521                 anim = Ext.lib.Anim[animType](
4522                     me.dom,
4523                     args,
4524                     (opt.duration || defaultDur) || .35,
4525                     (opt.easing || defaultEase) || 'easeOut',
4526                     function(){
4527                         if(cb) cb.call(me);
4528                         if(opt.callback) opt.callback.call(opt.scope || me, me, opt);
4529                     },
4530                     me
4531                 );
4532             opt.anim = anim;
4533             return anim;
4534         },
4535
4536         // private legacy anim prep
4537         preanim : function(a, i){
4538             return !a[i] ? false : (typeof a[i] == 'object' ? a[i]: {duration: a[i+1], callback: a[i+2], easing: a[i+3]});
4539         },
4540
4541         /**
4542          * Checks whether the element is currently visible using both visibility and display properties.
4543          * @return {Boolean} True if the element is currently visible, else false
4544          */
4545         isVisible : function() {
4546             var me = this,
4547                 dom = me.dom,
4548                 visible = data(dom, ISVISIBLE);
4549
4550             if(typeof visible == 'boolean'){ //return the cached value if registered
4551                 return visible;
4552             }
4553             //Determine the current state based on display states
4554             visible = !me.isStyle(VISIBILITY, HIDDEN) &&
4555                       !me.isStyle(DISPLAY, NONE) &&
4556                       !((getVisMode(dom) == El.ASCLASS) && me.hasClass(me.visibilityCls || El.visibilityCls));
4557
4558             data(dom, ISVISIBLE, visible);
4559             return visible;
4560         },
4561
4562         /**
4563          * Sets the visibility of the element (see details). If the visibilityMode is set to Element.DISPLAY, it will use
4564          * the display property to hide the element, otherwise it uses visibility. The default is to hide and show using the visibility property.
4565          * @param {Boolean} visible Whether the element is visible
4566          * @param {Boolean/Object} animate (optional) True for the default animation, or a standard Element animation config object
4567          * @return {Ext.Element} this
4568          */
4569         setVisible : function(visible, animate){
4570             var me = this, isDisplay, isVisibility, isOffsets, isNosize,
4571                 dom = me.dom,
4572                 visMode = getVisMode(dom);
4573
4574
4575             // hideMode string override
4576             if (typeof animate == 'string'){
4577                 switch (animate) {
4578                     case DISPLAY:
4579                         visMode = El.DISPLAY;
4580                         break;
4581                     case VISIBILITY:
4582                         visMode = El.VISIBILITY;
4583                         break;
4584                     case OFFSETS:
4585                         visMode = El.OFFSETS;
4586                         break;
4587                     case NOSIZE:
4588                     case ASCLASS:
4589                         visMode = El.ASCLASS;
4590                         break;
4591                 }
4592                 me.setVisibilityMode(visMode);
4593                 animate = false;
4594             }
4595
4596             if (!animate || !me.anim) {
4597                 if(visMode == El.ASCLASS ){
4598
4599                     me[visible?'removeClass':'addClass'](me.visibilityCls || El.visibilityCls);
4600
4601                 } else if (visMode == El.DISPLAY){
4602
4603                     return me.setDisplayed(visible);
4604
4605                 } else if (visMode == El.OFFSETS){
4606
4607                     if (!visible){
4608                         me.hideModeStyles = {
4609                             position: me.getStyle('position'),
4610                             top: me.getStyle('top'),
4611                             left: me.getStyle('left')
4612                         };
4613                         me.applyStyles({position: 'absolute', top: '-10000px', left: '-10000px'});
4614                     } else {
4615                         me.applyStyles(me.hideModeStyles || {position: '', top: '', left: ''});
4616                         delete me.hideModeStyles;
4617                     }
4618
4619                 }else{
4620                     me.fixDisplay();
4621                     dom.style.visibility = visible ? "visible" : HIDDEN;
4622                 }
4623             }else{
4624                 // closure for composites
4625                 if(visible){
4626                     me.setOpacity(.01);
4627                     me.setVisible(true);
4628                 }
4629                 me.anim({opacity: { to: (visible?1:0) }},
4630                         me.preanim(arguments, 1),
4631                         null,
4632                         .35,
4633                         'easeIn',
4634                         function(){
4635                             visible || me.setVisible(false).setOpacity(1);
4636                         });
4637             }
4638             data(dom, ISVISIBLE, visible);  //set logical visibility state
4639             return me;
4640         },
4641
4642
4643         /**
4644          * @private
4645          * Determine if the Element has a relevant height and width available based
4646          * upon current logical visibility state
4647          */
4648         hasMetrics  : function(){
4649             var dom = this.dom;
4650             return this.isVisible() || (getVisMode(dom) == El.VISIBILITY);
4651         },
4652
4653         /**
4654          * Toggles the element's visibility or display, depending on visibility mode.
4655          * @param {Boolean/Object} animate (optional) True for the default animation, or a standard Element animation config object
4656          * @return {Ext.Element} this
4657          */
4658         toggle : function(animate){
4659             var me = this;
4660             me.setVisible(!me.isVisible(), me.preanim(arguments, 0));
4661             return me;
4662         },
4663
4664         /**
4665          * Sets the CSS display property. Uses originalDisplay if the specified value is a boolean true.
4666          * @param {Mixed} value Boolean value to display the element using its default display, or a string to set the display directly.
4667          * @return {Ext.Element} this
4668          */
4669         setDisplayed : function(value) {
4670             if(typeof value == "boolean"){
4671                value = value ? getDisplay(this.dom) : NONE;
4672             }
4673             this.setStyle(DISPLAY, value);
4674             return this;
4675         },
4676
4677         // private
4678         fixDisplay : function(){
4679             var me = this;
4680             if(me.isStyle(DISPLAY, NONE)){
4681                 me.setStyle(VISIBILITY, HIDDEN);
4682                 me.setStyle(DISPLAY, getDisplay(this.dom)); // first try reverting to default
4683                 if(me.isStyle(DISPLAY, NONE)){ // if that fails, default to block
4684                     me.setStyle(DISPLAY, "block");
4685                 }
4686             }
4687         },
4688
4689         /**
4690          * Hide this element - Uses display mode to determine whether to use "display" or "visibility". See {@link #setVisible}.
4691          * @param {Boolean/Object} animate (optional) true for the default animation or a standard Element animation config object
4692          * @return {Ext.Element} this
4693          */
4694         hide : function(animate){
4695             // hideMode override
4696             if (typeof animate == 'string'){
4697                 this.setVisible(false, animate);
4698                 return this;
4699             }
4700             this.setVisible(false, this.preanim(arguments, 0));
4701             return this;
4702         },
4703
4704         /**
4705         * Show this element - Uses display mode to determine whether to use "display" or "visibility". See {@link #setVisible}.
4706         * @param {Boolean/Object} animate (optional) true for the default animation or a standard Element animation config object
4707          * @return {Ext.Element} this
4708          */
4709         show : function(animate){
4710             // hideMode override
4711             if (typeof animate == 'string'){
4712                 this.setVisible(true, animate);
4713                 return this;
4714             }
4715             this.setVisible(true, this.preanim(arguments, 0));
4716             return this;
4717         }
4718     };
4719 }());(function(){
4720     // contants
4721     var NULL = null,
4722         UNDEFINED = undefined,
4723         TRUE = true,
4724         FALSE = false,
4725         SETX = "setX",
4726         SETY = "setY",
4727         SETXY = "setXY",
4728         LEFT = "left",
4729         BOTTOM = "bottom",
4730         TOP = "top",
4731         RIGHT = "right",
4732         HEIGHT = "height",
4733         WIDTH = "width",
4734         POINTS = "points",
4735         HIDDEN = "hidden",
4736         ABSOLUTE = "absolute",
4737         VISIBLE = "visible",
4738         MOTION = "motion",
4739         POSITION = "position",
4740         EASEOUT = "easeOut",
4741         /*
4742          * Use a light flyweight here since we are using so many callbacks and are always assured a DOM element
4743          */
4744         flyEl = new Ext.Element.Flyweight(),
4745         queues = {},
4746         getObject = function(o){
4747             return o || {};
4748         },
4749         fly = function(dom){
4750             flyEl.dom = dom;
4751             flyEl.id = Ext.id(dom);
4752             return flyEl;
4753         },
4754         /*
4755          * Queueing now stored outside of the element due to closure issues
4756          */
4757         getQueue = function(id){
4758             if(!queues[id]){
4759                 queues[id] = [];
4760             }
4761             return queues[id];
4762         },
4763         setQueue = function(id, value){
4764             queues[id] = value;
4765         };
4766         
4767 //Notifies Element that fx methods are available
4768 Ext.enableFx = TRUE;
4769
4770 /**
4771  * @class Ext.Fx
4772  * <p>A class to provide basic animation and visual effects support.  <b>Note:</b> This class is automatically applied
4773  * to the {@link Ext.Element} interface when included, so all effects calls should be performed via {@link Ext.Element}.
4774  * Conversely, since the effects are not actually defined in {@link Ext.Element}, Ext.Fx <b>must</b> be
4775  * {@link Ext#enableFx included} in order for the Element effects to work.</p><br/>
4776  * 
4777  * <p><b><u>Method Chaining</u></b></p>
4778  * <p>It is important to note that although the Fx methods and many non-Fx Element methods support "method chaining" in that
4779  * they return the Element object itself as the method return value, it is not always possible to mix the two in a single
4780  * method chain.  The Fx methods use an internal effects queue so that each effect can be properly timed and sequenced.
4781  * Non-Fx methods, on the other hand, have no such internal queueing and will always execute immediately.  For this reason,
4782  * while it may be possible to mix certain Fx and non-Fx method calls in a single chain, it may not always provide the
4783  * expected results and should be done with care.  Also see <tt>{@link #callback}</tt>.</p><br/>
4784  *
4785  * <p><b><u>Anchor Options for Motion Effects</u></b></p>
4786  * <p>Motion effects support 8-way anchoring, meaning that you can choose one of 8 different anchor points on the Element
4787  * that will serve as either the start or end point of the animation.  Following are all of the supported anchor positions:</p>
4788 <pre>
4789 Value  Description
4790 -----  -----------------------------
4791 tl     The top left corner
4792 t      The center of the top edge
4793 tr     The top right corner
4794 l      The center of the left edge
4795 r      The center of the right edge
4796 bl     The bottom left corner
4797 b      The center of the bottom edge
4798 br     The bottom right corner
4799 </pre>
4800  * <b>Note</b>: some Fx methods accept specific custom config parameters.  The options shown in the Config Options
4801  * section below are common options that can be passed to any Fx method unless otherwise noted.</b>
4802  * 
4803  * @cfg {Function} callback A function called when the effect is finished.  Note that effects are queued internally by the
4804  * Fx class, so a callback is not required to specify another effect -- effects can simply be chained together
4805  * and called in sequence (see note for <b><u>Method Chaining</u></b> above), for example:<pre><code>
4806  * el.slideIn().highlight();
4807  * </code></pre>
4808  * The callback is intended for any additional code that should run once a particular effect has completed. The Element
4809  * being operated upon is passed as the first parameter.
4810  * 
4811  * @cfg {Object} scope The scope (<code>this</code> reference) in which the <tt>{@link #callback}</tt> function is executed. Defaults to the browser window.
4812  * 
4813  * @cfg {String} easing A valid Ext.lib.Easing value for the effect:</p><div class="mdetail-params"><ul>
4814  * <li><b><tt>backBoth</tt></b></li>
4815  * <li><b><tt>backIn</tt></b></li>
4816  * <li><b><tt>backOut</tt></b></li>
4817  * <li><b><tt>bounceBoth</tt></b></li>
4818  * <li><b><tt>bounceIn</tt></b></li>
4819  * <li><b><tt>bounceOut</tt></b></li>
4820  * <li><b><tt>easeBoth</tt></b></li>
4821  * <li><b><tt>easeBothStrong</tt></b></li>
4822  * <li><b><tt>easeIn</tt></b></li>
4823  * <li><b><tt>easeInStrong</tt></b></li>
4824  * <li><b><tt>easeNone</tt></b></li>
4825  * <li><b><tt>easeOut</tt></b></li>
4826  * <li><b><tt>easeOutStrong</tt></b></li>
4827  * <li><b><tt>elasticBoth</tt></b></li>
4828  * <li><b><tt>elasticIn</tt></b></li>
4829  * <li><b><tt>elasticOut</tt></b></li>
4830  * </ul></div>
4831  *
4832  * @cfg {String} afterCls A css class to apply after the effect
4833  * @cfg {Number} duration The length of time (in seconds) that the effect should last
4834  * 
4835  * @cfg {Number} endOpacity Only applicable for {@link #fadeIn} or {@link #fadeOut}, a number between
4836  * <tt>0</tt> and <tt>1</tt> inclusive to configure the ending opacity value.
4837  *  
4838  * @cfg {Boolean} remove Whether the Element should be removed from the DOM and destroyed after the effect finishes
4839  * @cfg {Boolean} useDisplay Whether to use the <i>display</i> CSS property instead of <i>visibility</i> when hiding Elements (only applies to 
4840  * effects that end with the element being visually hidden, ignored otherwise)
4841  * @cfg {String/Object/Function} afterStyle A style specification string, e.g. <tt>"width:100px"</tt>, or an object
4842  * in the form <tt>{width:"100px"}</tt>, or a function which returns such a specification that will be applied to the
4843  * Element after the effect finishes.
4844  * @cfg {Boolean} block Whether the effect should block other effects from queueing while it runs
4845  * @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
4846  * @cfg {Boolean} stopFx Whether preceding effects should be stopped and removed before running current effect (only applies to non blocking effects)
4847  */
4848 Ext.Fx = {
4849     
4850     // private - calls the function taking arguments from the argHash based on the key.  Returns the return value of the function.
4851     //           this is useful for replacing switch statements (for example).
4852     switchStatements : function(key, fn, argHash){
4853         return fn.apply(this, argHash[key]);
4854     },
4855     
4856     /**
4857      * Slides the element into view.  An anchor point can be optionally passed to set the point of
4858      * origin for the slide effect.  This function automatically handles wrapping the element with
4859      * a fixed-size container if needed.  See the Fx class overview for valid anchor point options.
4860      * Usage:
4861      *<pre><code>
4862 // default: slide the element in from the top
4863 el.slideIn();
4864
4865 // custom: slide the element in from the right with a 2-second duration
4866 el.slideIn('r', { duration: 2 });
4867
4868 // common config options shown with default values
4869 el.slideIn('t', {
4870     easing: 'easeOut',
4871     duration: .5
4872 });
4873 </code></pre>
4874      * @param {String} anchor (optional) One of the valid Fx anchor positions (defaults to top: 't')
4875      * @param {Object} options (optional) Object literal with any of the Fx config options
4876      * @return {Ext.Element} The Element
4877      */
4878     slideIn : function(anchor, o){ 
4879         o = getObject(o);
4880         var me = this,
4881             dom = me.dom,
4882             st = dom.style,
4883             xy,
4884             r,
4885             b,              
4886             wrap,               
4887             after,
4888             st,
4889             args, 
4890             pt,
4891             bw,
4892             bh;
4893             
4894         anchor = anchor || "t";
4895
4896         me.queueFx(o, function(){            
4897             xy = fly(dom).getXY();
4898             // fix display to visibility
4899             fly(dom).fixDisplay();            
4900             
4901             // restore values after effect
4902             r = fly(dom).getFxRestore();      
4903             b = {x: xy[0], y: xy[1], 0: xy[0], 1: xy[1], width: dom.offsetWidth, height: dom.offsetHeight};
4904             b.right = b.x + b.width;
4905             b.bottom = b.y + b.height;
4906             
4907             // fixed size for slide
4908             fly(dom).setWidth(b.width).setHeight(b.height);            
4909             
4910             // wrap if needed
4911             wrap = fly(dom).fxWrap(r.pos, o, HIDDEN);
4912             
4913             st.visibility = VISIBLE;
4914             st.position = ABSOLUTE;
4915             
4916             // clear out temp styles after slide and unwrap
4917             function after(){
4918                  fly(dom).fxUnwrap(wrap, r.pos, o);
4919                  st.width = r.width;
4920                  st.height = r.height;
4921                  fly(dom).afterFx(o);
4922             }
4923             
4924             // time to calculate the positions        
4925             pt = {to: [b.x, b.y]}; 
4926             bw = {to: b.width};
4927             bh = {to: b.height};
4928                 
4929             function argCalc(wrap, style, ww, wh, sXY, sXYval, s1, s2, w, h, p){                    
4930                 var ret = {};
4931                 fly(wrap).setWidth(ww).setHeight(wh);
4932                 if(fly(wrap)[sXY]){
4933                     fly(wrap)[sXY](sXYval);                  
4934                 }
4935                 style[s1] = style[s2] = "0";                    
4936                 if(w){
4937                     ret.width = w;
4938                 }
4939                 if(h){
4940                     ret.height = h;
4941                 }
4942                 if(p){
4943                     ret.points = p;
4944                 }
4945                 return ret;
4946             };
4947
4948             args = fly(dom).switchStatements(anchor.toLowerCase(), argCalc, {
4949                     t  : [wrap, st, b.width, 0, NULL, NULL, LEFT, BOTTOM, NULL, bh, NULL],
4950                     l  : [wrap, st, 0, b.height, NULL, NULL, RIGHT, TOP, bw, NULL, NULL],
4951                     r  : [wrap, st, b.width, b.height, SETX, b.right, LEFT, TOP, NULL, NULL, pt],
4952                     b  : [wrap, st, b.width, b.height, SETY, b.bottom, LEFT, TOP, NULL, bh, pt],
4953                     tl : [wrap, st, 0, 0, NULL, NULL, RIGHT, BOTTOM, bw, bh, pt],
4954                     bl : [wrap, st, 0, 0, SETY, b.y + b.height, RIGHT, TOP, bw, bh, pt],
4955                     br : [wrap, st, 0, 0, SETXY, [b.right, b.bottom], LEFT, TOP, bw, bh, pt],
4956                     tr : [wrap, st, 0, 0, SETX, b.x + b.width, LEFT, BOTTOM, bw, bh, pt]
4957                 });
4958             
4959             st.visibility = VISIBLE;
4960             fly(wrap).show();
4961
4962             arguments.callee.anim = fly(wrap).fxanim(args,
4963                 o,
4964                 MOTION,
4965                 .5,
4966                 EASEOUT, 
4967                 after);
4968         });
4969         return me;
4970     },
4971     
4972     /**
4973      * Slides the element out of view.  An anchor point can be optionally passed to set the end point
4974      * for the slide effect.  When the effect is completed, the element will be hidden (visibility = 
4975      * 'hidden') but block elements will still take up space in the document.  The element must be removed
4976      * from the DOM using the 'remove' config option if desired.  This function automatically handles 
4977      * wrapping the element with a fixed-size container if needed.  See the Fx class overview for valid anchor point options.
4978      * Usage:
4979      *<pre><code>
4980 // default: slide the element out to the top
4981 el.slideOut();
4982
4983 // custom: slide the element out to the right with a 2-second duration
4984 el.slideOut('r', { duration: 2 });
4985
4986 // common config options shown with default values
4987 el.slideOut('t', {
4988     easing: 'easeOut',
4989     duration: .5,
4990     remove: false,
4991     useDisplay: false
4992 });
4993 </code></pre>
4994      * @param {String} anchor (optional) One of the valid Fx anchor positions (defaults to top: 't')
4995      * @param {Object} options (optional) Object literal with any of the Fx config options
4996      * @return {Ext.Element} The Element
4997      */
4998     slideOut : function(anchor, o){
4999         o = getObject(o);
5000         var me = this,
5001             dom = me.dom,
5002             st = dom.style,
5003             xy = me.getXY(),
5004             wrap,
5005             r,
5006             b,
5007             a,
5008             zero = {to: 0}; 
5009                     
5010         anchor = anchor || "t";
5011
5012         me.queueFx(o, function(){
5013             
5014             // restore values after effect
5015             r = fly(dom).getFxRestore(); 
5016             b = {x: xy[0], y: xy[1], 0: xy[0], 1: xy[1], width: dom.offsetWidth, height: dom.offsetHeight};
5017             b.right = b.x + b.width;
5018             b.bottom = b.y + b.height;
5019                 
5020             // fixed size for slide   
5021             fly(dom).setWidth(b.width).setHeight(b.height);
5022
5023             // wrap if needed
5024             wrap = fly(dom).fxWrap(r.pos, o, VISIBLE);
5025                 
5026             st.visibility = VISIBLE;
5027             st.position = ABSOLUTE;
5028             fly(wrap).setWidth(b.width).setHeight(b.height);            
5029
5030             function after(){
5031                 o.useDisplay ? fly(dom).setDisplayed(FALSE) : fly(dom).hide();                
5032                 fly(dom).fxUnwrap(wrap, r.pos, o);
5033                 st.width = r.width;
5034                 st.height = r.height;
5035                 fly(dom).afterFx(o);
5036             }            
5037             
5038             function argCalc(style, s1, s2, p1, v1, p2, v2, p3, v3){                    
5039                 var ret = {};
5040                 
5041                 style[s1] = style[s2] = "0";
5042                 ret[p1] = v1;               
5043                 if(p2){
5044                     ret[p2] = v2;               
5045                 }
5046                 if(p3){
5047                     ret[p3] = v3;
5048                 }
5049                 
5050                 return ret;
5051             };
5052             
5053             a = fly(dom).switchStatements(anchor.toLowerCase(), argCalc, {
5054                 t  : [st, LEFT, BOTTOM, HEIGHT, zero],
5055                 l  : [st, RIGHT, TOP, WIDTH, zero],
5056                 r  : [st, LEFT, TOP, WIDTH, zero, POINTS, {to : [b.right, b.y]}],
5057                 b  : [st, LEFT, TOP, HEIGHT, zero, POINTS, {to : [b.x, b.bottom]}],
5058                 tl : [st, RIGHT, BOTTOM, WIDTH, zero, HEIGHT, zero],
5059                 bl : [st, RIGHT, TOP, WIDTH, zero, HEIGHT, zero, POINTS, {to : [b.x, b.bottom]}],
5060                 br : [st, LEFT, TOP, WIDTH, zero, HEIGHT, zero, POINTS, {to : [b.x + b.width, b.bottom]}],
5061                 tr : [st, LEFT, BOTTOM, WIDTH, zero, HEIGHT, zero, POINTS, {to : [b.right, b.y]}]
5062             });
5063             
5064             arguments.callee.anim = fly(wrap).fxanim(a,
5065                 o,
5066                 MOTION,
5067                 .5,
5068                 EASEOUT, 
5069                 after);
5070         });
5071         return me;
5072     },
5073
5074     /**
5075      * Fades the element out while slowly expanding it in all directions.  When the effect is completed, the 
5076      * element will be hidden (visibility = 'hidden') but block elements will still take up space in the document. 
5077      * The element must be removed from the DOM using the 'remove' config option if desired.
5078      * Usage:
5079      *<pre><code>
5080 // default
5081 el.puff();
5082
5083 // common config options shown with default values
5084 el.puff({
5085     easing: 'easeOut',
5086     duration: .5,
5087     remove: false,
5088     useDisplay: false
5089 });
5090 </code></pre>
5091      * @param {Object} options (optional) Object literal with any of the Fx config options
5092      * @return {Ext.Element} The Element
5093      */
5094     puff : function(o){
5095         o = getObject(o);
5096         var me = this,
5097             dom = me.dom,
5098             st = dom.style,
5099             width,
5100             height,
5101             r;
5102
5103         me.queueFx(o, function(){
5104             width = fly(dom).getWidth();
5105             height = fly(dom).getHeight();
5106             fly(dom).clearOpacity();
5107             fly(dom).show();
5108
5109             // restore values after effect
5110             r = fly(dom).getFxRestore();                   
5111             
5112             function after(){
5113                 o.useDisplay ? fly(dom).setDisplayed(FALSE) : fly(dom).hide();                  
5114                 fly(dom).clearOpacity();  
5115                 fly(dom).setPositioning(r.pos);
5116                 st.width = r.width;
5117                 st.height = r.height;
5118                 st.fontSize = '';
5119                 fly(dom).afterFx(o);
5120             }   
5121
5122             arguments.callee.anim = fly(dom).fxanim({
5123                     width : {to : fly(dom).adjustWidth(width * 2)},
5124                     height : {to : fly(dom).adjustHeight(height * 2)},
5125                     points : {by : [-width * .5, -height * .5]},
5126                     opacity : {to : 0},
5127                     fontSize: {to : 200, unit: "%"}
5128                 },
5129                 o,
5130                 MOTION,
5131                 .5,
5132                 EASEOUT,
5133                  after);
5134         });
5135         return me;
5136     },
5137
5138     /**
5139      * Blinks the element as if it was clicked and then collapses on its center (similar to switching off a television).
5140      * When the effect is completed, the element will be hidden (visibility = 'hidden') but block elements will still 
5141      * take up space in the document. The element must be removed from the DOM using the 'remove' config option if desired.
5142      * Usage:
5143      *<pre><code>
5144 // default
5145 el.switchOff();
5146
5147 // all config options shown with default values
5148 el.switchOff({
5149     easing: 'easeIn',
5150     duration: .3,
5151     remove: false,
5152     useDisplay: false
5153 });
5154 </code></pre>
5155      * @param {Object} options (optional) Object literal with any of the Fx config options
5156      * @return {Ext.Element} The Element
5157      */
5158     switchOff : function(o){
5159         o = getObject(o);
5160         var me = this,
5161             dom = me.dom,
5162             st = dom.style,
5163             r;
5164
5165         me.queueFx(o, function(){
5166             fly(dom).clearOpacity();
5167             fly(dom).clip();
5168
5169             // restore values after effect
5170             r = fly(dom).getFxRestore();
5171                 
5172             function after(){
5173                 o.useDisplay ? fly(dom).setDisplayed(FALSE) : fly(dom).hide();  
5174                 fly(dom).clearOpacity();
5175                 fly(dom).setPositioning(r.pos);
5176                 st.width = r.width;
5177                 st.height = r.height;   
5178                 fly(dom).afterFx(o);
5179             };
5180
5181             fly(dom).fxanim({opacity : {to : 0.3}}, 
5182                 NULL, 
5183                 NULL, 
5184                 .1, 
5185                 NULL, 
5186                 function(){                                 
5187                     fly(dom).clearOpacity();
5188                         (function(){                            
5189                             fly(dom).fxanim({
5190                                 height : {to : 1},
5191                                 points : {by : [0, fly(dom).getHeight() * .5]}
5192                             }, 
5193                             o, 
5194                             MOTION, 
5195                             0.3, 
5196                             'easeIn', 
5197                             after);
5198                         }).defer(100);
5199                 });
5200         });
5201         return me;
5202     },
5203
5204     /**
5205      * Highlights the Element by setting a color (applies to the background-color by default, but can be
5206      * changed using the "attr" config option) and then fading back to the original color. If no original
5207      * color is available, you should provide the "endColor" config option which will be cleared after the animation.
5208      * Usage:
5209 <pre><code>
5210 // default: highlight background to yellow
5211 el.highlight();
5212
5213 // custom: highlight foreground text to blue for 2 seconds
5214 el.highlight("0000ff", { attr: 'color', duration: 2 });
5215
5216 // common config options shown with default values
5217 el.highlight("ffff9c", {
5218     attr: "background-color", //can be any valid CSS property (attribute) that supports a color value
5219     endColor: (current color) or "ffffff",
5220     easing: 'easeIn',
5221     duration: 1
5222 });
5223 </code></pre>
5224      * @param {String} color (optional) The highlight color. Should be a 6 char hex color without the leading # (defaults to yellow: 'ffff9c')
5225      * @param {Object} options (optional) Object literal with any of the Fx config options
5226      * @return {Ext.Element} The Element
5227      */ 
5228     highlight : function(color, o){
5229         o = getObject(o);
5230         var me = this,
5231             dom = me.dom,
5232             attr = o.attr || "backgroundColor",
5233             a = {},
5234             restore;
5235
5236         me.queueFx(o, function(){
5237             fly(dom).clearOpacity();
5238             fly(dom).show();
5239
5240             function after(){
5241                 dom.style[attr] = restore;
5242                 fly(dom).afterFx(o);
5243             }            
5244             restore = dom.style[attr];
5245             a[attr] = {from: color || "ffff9c", to: o.endColor || fly(dom).getColor(attr) || "ffffff"};
5246             arguments.callee.anim = fly(dom).fxanim(a,
5247                 o,
5248                 'color',
5249                 1,
5250                 'easeIn', 
5251                 after);
5252         });
5253         return me;
5254     },
5255
5256    /**
5257     * Shows a ripple of exploding, attenuating borders to draw attention to an Element.
5258     * Usage:
5259 <pre><code>
5260 // default: a single light blue ripple
5261 el.frame();
5262
5263 // custom: 3 red ripples lasting 3 seconds total
5264 el.frame("ff0000", 3, { duration: 3 });
5265
5266 // common config options shown with default values
5267 el.frame("C3DAF9", 1, {
5268     duration: 1 //duration of each individual ripple.
5269     // Note: Easing is not configurable and will be ignored if included
5270 });
5271 </code></pre>
5272     * @param {String} color (optional) The color of the border.  Should be a 6 char hex color without the leading # (defaults to light blue: 'C3DAF9').
5273     * @param {Number} count (optional) The number of ripples to display (defaults to 1)
5274     * @param {Object} options (optional) Object literal with any of the Fx config options
5275     * @return {Ext.Element} The Element
5276     */
5277     frame : function(color, count, o){
5278         o = getObject(o);
5279         var me = this,
5280             dom = me.dom,
5281             proxy,
5282             active;
5283
5284         me.queueFx(o, function(){
5285             color = color || '#C3DAF9';
5286             if(color.length == 6){
5287                 color = '#' + color;
5288             }            
5289             count = count || 1;
5290             fly(dom).show();
5291
5292             var xy = fly(dom).getXY(),
5293                 b = {x: xy[0], y: xy[1], 0: xy[0], 1: xy[1], width: dom.offsetWidth, height: dom.offsetHeight},
5294                 queue = function(){
5295                     proxy = fly(document.body || document.documentElement).createChild({
5296                         style:{
5297                             position : ABSOLUTE,
5298                             'z-index': 35000, // yee haw
5299                             border : '0px solid ' + color
5300                         }
5301                     });
5302                     return proxy.queueFx({}, animFn);
5303                 };
5304             
5305             
5306             arguments.callee.anim = {
5307                 isAnimated: true,
5308                 stop: function() {
5309                     count = 0;
5310                     proxy.stopFx();
5311                 }
5312             };
5313             
5314             function animFn(){
5315                 var scale = Ext.isBorderBox ? 2 : 1;
5316                 active = proxy.anim({
5317                     top : {from : b.y, to : b.y - 20},
5318                     left : {from : b.x, to : b.x - 20},
5319                     borderWidth : {from : 0, to : 10},
5320                     opacity : {from : 1, to : 0},
5321                     height : {from : b.height, to : b.height + 20 * scale},
5322                     width : {from : b.width, to : b.width + 20 * scale}
5323                 },{
5324                     duration: o.duration || 1,
5325                     callback: function() {
5326                         proxy.remove();
5327                         --count > 0 ? queue() : fly(dom).afterFx(o);
5328                     }
5329                 });
5330                 arguments.callee.anim = {
5331                     isAnimated: true,
5332                     stop: function(){
5333                         active.stop();
5334                     }
5335                 };
5336             };
5337             queue();
5338         });
5339         return me;
5340     },
5341
5342    /**
5343     * Creates a pause before any subsequent queued effects begin.  If there are
5344     * no effects queued after the pause it will have no effect.
5345     * Usage:
5346 <pre><code>
5347 el.pause(1);
5348 </code></pre>
5349     * @param {Number} seconds The length of time to pause (in seconds)
5350     * @return {Ext.Element} The Element
5351     */
5352     pause : function(seconds){        
5353         var dom = this.dom,
5354             t;
5355
5356         this.queueFx({}, function(){
5357             t = setTimeout(function(){
5358                 fly(dom).afterFx({});
5359             }, seconds * 1000);
5360             arguments.callee.anim = {
5361                 isAnimated: true,
5362                 stop: function(){
5363                     clearTimeout(t);
5364                     fly(dom).afterFx({});
5365                 }
5366             };
5367         });
5368         return this;
5369     },
5370
5371    /**
5372     * Fade an element in (from transparent to opaque).  The ending opacity can be specified
5373     * using the <tt>{@link #endOpacity}</tt> config option.
5374     * Usage:
5375 <pre><code>
5376 // default: fade in from opacity 0 to 100%
5377 el.fadeIn();
5378
5379 // custom: fade in from opacity 0 to 75% over 2 seconds
5380 el.fadeIn({ endOpacity: .75, duration: 2});
5381
5382 // common config options shown with default values
5383 el.fadeIn({
5384     endOpacity: 1, //can be any value between 0 and 1 (e.g. .5)
5385     easing: 'easeOut',
5386     duration: .5
5387 });
5388 </code></pre>
5389     * @param {Object} options (optional) Object literal with any of the Fx config options
5390     * @return {Ext.Element} The Element
5391     */
5392     fadeIn : function(o){
5393         o = getObject(o);
5394         var me = this,
5395             dom = me.dom,
5396             to = o.endOpacity || 1;
5397         
5398         me.queueFx(o, function(){
5399             fly(dom).setOpacity(0);
5400             fly(dom).fixDisplay();
5401             dom.style.visibility = VISIBLE;
5402             arguments.callee.anim = fly(dom).fxanim({opacity:{to:to}},
5403                 o, NULL, .5, EASEOUT, function(){
5404                 if(to == 1){
5405                     fly(dom).clearOpacity();
5406                 }
5407                 fly(dom).afterFx(o);
5408             });
5409         });
5410         return me;
5411     },
5412
5413    /**
5414     * Fade an element out (from opaque to transparent).  The ending opacity can be specified
5415     * using the <tt>{@link #endOpacity}</tt> config option.  Note that IE may require
5416     * <tt>{@link #useDisplay}:true</tt> in order to redisplay correctly.
5417     * Usage:
5418 <pre><code>
5419 // default: fade out from the element's current opacity to 0
5420 el.fadeOut();
5421
5422 // custom: fade out from the element's current opacity to 25% over 2 seconds
5423 el.fadeOut({ endOpacity: .25, duration: 2});
5424
5425 // common config options shown with default values
5426 el.fadeOut({
5427     endOpacity: 0, //can be any value between 0 and 1 (e.g. .5)
5428     easing: 'easeOut',
5429     duration: .5,
5430     remove: false,
5431     useDisplay: false
5432 });
5433 </code></pre>
5434     * @param {Object} options (optional) Object literal with any of the Fx config options
5435     * @return {Ext.Element} The Element
5436     */
5437     fadeOut : function(o){
5438         o = getObject(o);
5439         var me = this,
5440             dom = me.dom,
5441             style = dom.style,
5442             to = o.endOpacity || 0;         
5443         
5444         me.queueFx(o, function(){  
5445             arguments.callee.anim = fly(dom).fxanim({ 
5446                 opacity : {to : to}},
5447                 o, 
5448                 NULL, 
5449                 .5, 
5450                 EASEOUT, 
5451                 function(){
5452                     if(to == 0){
5453                         Ext.Element.data(dom, 'visibilityMode') == Ext.Element.DISPLAY || o.useDisplay ? 
5454                             style.display = "none" :
5455                             style.visibility = HIDDEN;
5456                             
5457                         fly(dom).clearOpacity();
5458                     }
5459                     fly(dom).afterFx(o);
5460             });
5461         });
5462         return me;
5463     },
5464
5465    /**
5466     * Animates the transition of an element's dimensions from a starting height/width
5467     * to an ending height/width.  This method is a convenience implementation of {@link shift}.
5468     * Usage:
5469 <pre><code>
5470 // change height and width to 100x100 pixels
5471 el.scale(100, 100);
5472
5473 // common config options shown with default values.  The height and width will default to
5474 // the element&#39;s existing values if passed as null.
5475 el.scale(
5476     [element&#39;s width],
5477     [element&#39;s height], {
5478         easing: 'easeOut',
5479         duration: .35
5480     }
5481 );
5482 </code></pre>
5483     * @param {Number} width  The new width (pass undefined to keep the original width)
5484     * @param {Number} height  The new height (pass undefined to keep the original height)
5485     * @param {Object} options (optional) Object literal with any of the Fx config options
5486     * @return {Ext.Element} The Element
5487     */
5488     scale : function(w, h, o){
5489         this.shift(Ext.apply({}, o, {
5490             width: w,
5491             height: h
5492         }));
5493         return this;
5494     },
5495
5496    /**
5497     * Animates the transition of any combination of an element's dimensions, xy position and/or opacity.
5498     * Any of these properties not specified in the config object will not be changed.  This effect 
5499     * requires that at least one new dimension, position or opacity setting must be passed in on
5500     * the config object in order for the function to have any effect.
5501     * Usage:
5502 <pre><code>
5503 // slide the element horizontally to x position 200 while changing the height and opacity
5504 el.shift({ x: 200, height: 50, opacity: .8 });
5505
5506 // common config options shown with default values.
5507 el.shift({
5508     width: [element&#39;s width],
5509     height: [element&#39;s height],
5510     x: [element&#39;s x position],
5511     y: [element&#39;s y position],
5512     opacity: [element&#39;s opacity],
5513     easing: 'easeOut',
5514     duration: .35
5515 });
5516 </code></pre>
5517     * @param {Object} options  Object literal with any of the Fx config options
5518     * @return {Ext.Element} The Element
5519     */
5520     shift : function(o){
5521         o = getObject(o);
5522         var dom = this.dom,
5523             a = {};
5524                 
5525         this.queueFx(o, function(){
5526             for (var prop in o) {
5527                 if (o[prop] != UNDEFINED) {                                                 
5528                     a[prop] = {to : o[prop]};                   
5529                 }
5530             } 
5531             
5532             a.width ? a.width.to = fly(dom).adjustWidth(o.width) : a;
5533             a.height ? a.height.to = fly(dom).adjustWidth(o.height) : a;   
5534             
5535             if (a.x || a.y || a.xy) {
5536                 a.points = a.xy || 
5537                            {to : [ a.x ? a.x.to : fly(dom).getX(),
5538                                    a.y ? a.y.to : fly(dom).getY()]};                  
5539             }
5540
5541             arguments.callee.anim = fly(dom).fxanim(a,
5542                 o, 
5543                 MOTION, 
5544                 .35, 
5545                 EASEOUT, 
5546                 function(){
5547                     fly(dom).afterFx(o);
5548                 });
5549         });
5550         return this;
5551     },
5552
5553     /**
5554      * Slides the element while fading it out of view.  An anchor point can be optionally passed to set the 
5555      * ending point of the effect.
5556      * Usage:
5557      *<pre><code>
5558 // default: slide the element downward while fading out
5559 el.ghost();
5560
5561 // custom: slide the element out to the right with a 2-second duration
5562 el.ghost('r', { duration: 2 });
5563
5564 // common config options shown with default values
5565 el.ghost('b', {
5566     easing: 'easeOut',
5567     duration: .5,
5568     remove: false,
5569     useDisplay: false
5570 });
5571 </code></pre>
5572      * @param {String} anchor (optional) One of the valid Fx anchor positions (defaults to bottom: 'b')
5573      * @param {Object} options (optional) Object literal with any of the Fx config options
5574      * @return {Ext.Element} The Element
5575      */
5576     ghost : function(anchor, o){
5577         o = getObject(o);
5578         var me = this,
5579             dom = me.dom,
5580             st = dom.style,
5581             a = {opacity: {to: 0}, points: {}},
5582             pt = a.points,
5583             r,
5584             w,
5585             h;
5586             
5587         anchor = anchor || "b";
5588
5589         me.queueFx(o, function(){
5590             // restore values after effect
5591             r = fly(dom).getFxRestore();
5592             w = fly(dom).getWidth();
5593             h = fly(dom).getHeight();
5594             
5595             function after(){
5596                 o.useDisplay ? fly(dom).setDisplayed(FALSE) : fly(dom).hide();   
5597                 fly(dom).clearOpacity();
5598                 fly(dom).setPositioning(r.pos);
5599                 st.width = r.width;
5600                 st.height = r.height;
5601                 fly(dom).afterFx(o);
5602             }
5603                 
5604             pt.by = fly(dom).switchStatements(anchor.toLowerCase(), function(v1,v2){ return [v1, v2];}, {
5605                t  : [0, -h],
5606                l  : [-w, 0],
5607                r  : [w, 0],
5608                b  : [0, h],
5609                tl : [-w, -h],
5610                bl : [-w, h],
5611                br : [w, h],
5612                tr : [w, -h] 
5613             });
5614                 
5615             arguments.callee.anim = fly(dom).fxanim(a,
5616                 o,
5617                 MOTION,
5618                 .5,
5619                 EASEOUT, after);
5620         });
5621         return me;
5622     },
5623
5624     /**
5625      * Ensures that all effects queued after syncFx is called on the element are
5626      * run concurrently.  This is the opposite of {@link #sequenceFx}.
5627      * @return {Ext.Element} The Element
5628      */
5629     syncFx : function(){
5630         var me = this;
5631         me.fxDefaults = Ext.apply(me.fxDefaults || {}, {
5632             block : FALSE,
5633             concurrent : TRUE,
5634             stopFx : FALSE
5635         });
5636         return me;
5637     },
5638
5639     /**
5640      * Ensures that all effects queued after sequenceFx is called on the element are
5641      * run in sequence.  This is the opposite of {@link #syncFx}.
5642      * @return {Ext.Element} The Element
5643      */
5644     sequenceFx : function(){
5645         var me = this;
5646         me.fxDefaults = Ext.apply(me.fxDefaults || {}, {
5647             block : FALSE,
5648             concurrent : FALSE,
5649             stopFx : FALSE
5650         });
5651         return me;
5652     },
5653
5654     /* @private */
5655     nextFx : function(){        
5656         var ef = getQueue(this.dom.id)[0];
5657         if(ef){
5658             ef.call(this);
5659         }
5660     },
5661
5662     /**
5663      * Returns true if the element has any effects actively running or queued, else returns false.
5664      * @return {Boolean} True if element has active effects, else false
5665      */
5666     hasActiveFx : function(){
5667         return getQueue(this.dom.id)[0];
5668     },
5669
5670     /**
5671      * Stops any running effects and clears the element's internal effects queue if it contains
5672      * any additional effects that haven't started yet.
5673      * @return {Ext.Element} The Element
5674      */
5675     stopFx : function(finish){
5676         var me = this,
5677             id = me.dom.id;
5678         if(me.hasActiveFx()){
5679             var cur = getQueue(id)[0];
5680             if(cur && cur.anim){
5681                 if(cur.anim.isAnimated){
5682                     setQueue(id, [cur]); //clear
5683                     cur.anim.stop(finish !== undefined ? finish : TRUE);
5684                 }else{
5685                     setQueue(id, []);
5686                 }
5687             }
5688         }
5689         return me;
5690     },
5691
5692     /* @private */
5693     beforeFx : function(o){
5694         if(this.hasActiveFx() && !o.concurrent){
5695            if(o.stopFx){
5696                this.stopFx();
5697                return TRUE;
5698            }
5699            return FALSE;
5700         }
5701         return TRUE;
5702     },
5703
5704     /**
5705      * Returns true if the element is currently blocking so that no other effect can be queued
5706      * until this effect is finished, else returns false if blocking is not set.  This is commonly
5707      * used to ensure that an effect initiated by a user action runs to completion prior to the
5708      * same effect being restarted (e.g., firing only one effect even if the user clicks several times).
5709      * @return {Boolean} True if blocking, else false
5710      */
5711     hasFxBlock : function(){
5712         var q = getQueue(this.dom.id);
5713         return q && q[0] && q[0].block;
5714     },
5715
5716     /* @private */
5717     queueFx : function(o, fn){
5718         var me = fly(this.dom);
5719         if(!me.hasFxBlock()){
5720             Ext.applyIf(o, me.fxDefaults);
5721             if(!o.concurrent){
5722                 var run = me.beforeFx(o);
5723                 fn.block = o.block;
5724                 getQueue(me.dom.id).push(fn);
5725                 if(run){
5726                     me.nextFx();
5727                 }
5728             }else{
5729                 fn.call(me);
5730             }
5731         }
5732         return me;
5733     },
5734
5735     /* @private */
5736     fxWrap : function(pos, o, vis){ 
5737         var dom = this.dom,
5738             wrap,
5739             wrapXY;
5740         if(!o.wrap || !(wrap = Ext.getDom(o.wrap))){            
5741             if(o.fixPosition){
5742                 wrapXY = fly(dom).getXY();
5743             }
5744             var div = document.createElement("div");
5745             div.style.visibility = vis;
5746             wrap = dom.parentNode.insertBefore(div, dom);
5747             fly(wrap).setPositioning(pos);
5748             if(fly(wrap).isStyle(POSITION, "static")){
5749                 fly(wrap).position("relative");
5750             }
5751             fly(dom).clearPositioning('auto');
5752             fly(wrap).clip();
5753             wrap.appendChild(dom);
5754             if(wrapXY){
5755                 fly(wrap).setXY(wrapXY);
5756             }
5757         }
5758         return wrap;
5759     },
5760
5761     /* @private */
5762     fxUnwrap : function(wrap, pos, o){      
5763         var dom = this.dom;
5764         fly(dom).clearPositioning();
5765         fly(dom).setPositioning(pos);
5766         if(!o.wrap){
5767             var pn = fly(wrap).dom.parentNode;
5768             pn.insertBefore(dom, wrap); 
5769             fly(wrap).remove();
5770         }
5771     },
5772
5773     /* @private */
5774     getFxRestore : function(){
5775         var st = this.dom.style;
5776         return {pos: this.getPositioning(), width: st.width, height : st.height};
5777     },
5778
5779     /* @private */
5780     afterFx : function(o){
5781         var dom = this.dom,
5782             id = dom.id;
5783         if(o.afterStyle){
5784             fly(dom).setStyle(o.afterStyle);            
5785         }
5786         if(o.afterCls){
5787             fly(dom).addClass(o.afterCls);
5788         }
5789         if(o.remove == TRUE){
5790             fly(dom).remove();
5791         }
5792         if(o.callback){
5793             o.callback.call(o.scope, fly(dom));
5794         }
5795         if(!o.concurrent){
5796             getQueue(id).shift();
5797             fly(dom).nextFx();
5798         }
5799     },
5800
5801     /* @private */
5802     fxanim : function(args, opt, animType, defaultDur, defaultEase, cb){
5803         animType = animType || 'run';
5804         opt = opt || {};
5805         var anim = Ext.lib.Anim[animType](
5806                 this.dom, 
5807                 args,
5808                 (opt.duration || defaultDur) || .35,
5809                 (opt.easing || defaultEase) || EASEOUT,
5810                 cb,            
5811                 this
5812             );
5813         opt.anim = anim;
5814         return anim;
5815     }
5816 };
5817
5818 // backwards compat
5819 Ext.Fx.resize = Ext.Fx.scale;
5820
5821 //When included, Ext.Fx is automatically applied to Element so that all basic
5822 //effects are available directly via the Element API
5823 Ext.Element.addMethods(Ext.Fx);
5824 })();
5825 /**
5826  * @class Ext.CompositeElementLite
5827  * <p>This class encapsulates a <i>collection</i> of DOM elements, providing methods to filter
5828  * members, or to perform collective actions upon the whole set.</p>
5829  * <p>Although they are not listed, this class supports all of the methods of {@link Ext.Element} and
5830  * {@link Ext.Fx}. The methods from these classes will be performed on all the elements in this collection.</p>
5831  * Example:<pre><code>
5832 var els = Ext.select("#some-el div.some-class");
5833 // or select directly from an existing element
5834 var el = Ext.get('some-el');
5835 el.select('div.some-class');
5836
5837 els.setWidth(100); // all elements become 100 width
5838 els.hide(true); // all elements fade out and hide
5839 // or
5840 els.setWidth(100).hide(true);
5841 </code>
5842  */
5843 Ext.CompositeElementLite = function(els, root){
5844     /**
5845      * <p>The Array of DOM elements which this CompositeElement encapsulates. Read-only.</p>
5846      * <p>This will not <i>usually</i> be accessed in developers' code, but developers wishing
5847      * to augment the capabilities of the CompositeElementLite class may use it when adding
5848      * methods to the class.</p>
5849      * <p>For example to add the <code>nextAll</code> method to the class to <b>add</b> all
5850      * following siblings of selected elements, the code would be</p><code><pre>
5851 Ext.override(Ext.CompositeElementLite, {
5852     nextAll: function() {
5853         var els = this.elements, i, l = els.length, n, r = [], ri = -1;
5854
5855 //      Loop through all elements in this Composite, accumulating
5856 //      an Array of all siblings.
5857         for (i = 0; i < l; i++) {
5858             for (n = els[i].nextSibling; n; n = n.nextSibling) {
5859                 r[++ri] = n;
5860             }
5861         }
5862
5863 //      Add all found siblings to this Composite
5864         return this.add(r);
5865     }
5866 });</pre></code>
5867      * @type Array
5868      * @property elements
5869      */
5870     this.elements = [];
5871     this.add(els, root);
5872     this.el = new Ext.Element.Flyweight();
5873 };
5874
5875 Ext.CompositeElementLite.prototype = {
5876     isComposite: true,
5877
5878     // private
5879     getElement : function(el){
5880         // Set the shared flyweight dom property to the current element
5881         var e = this.el;
5882         e.dom = el;
5883         e.id = el.id;
5884         return e;
5885     },
5886
5887     // private
5888     transformElement : function(el){
5889         return Ext.getDom(el);
5890     },
5891
5892     /**
5893      * Returns the number of elements in this Composite.
5894      * @return Number
5895      */
5896     getCount : function(){
5897         return this.elements.length;
5898     },
5899     /**
5900      * Adds elements to this Composite object.
5901      * @param {Mixed} els Either an Array of DOM elements to add, or another Composite object who's elements should be added.
5902      * @return {CompositeElement} This Composite object.
5903      */
5904     add : function(els, root){
5905         var me = this,
5906             elements = me.elements;
5907         if(!els){
5908             return this;
5909         }
5910         if(typeof els == "string"){
5911             els = Ext.Element.selectorFunction(els, root);
5912         }else if(els.isComposite){
5913             els = els.elements;
5914         }else if(!Ext.isIterable(els)){
5915             els = [els];
5916         }
5917
5918         for(var i = 0, len = els.length; i < len; ++i){
5919             elements.push(me.transformElement(els[i]));
5920         }
5921         return me;
5922     },
5923
5924     invoke : function(fn, args){
5925         var me = this,
5926             els = me.elements,
5927             len = els.length,
5928             e,
5929             i;
5930
5931         for(i = 0; i < len; i++) {
5932             e = els[i];
5933             if(e){
5934                 Ext.Element.prototype[fn].apply(me.getElement(e), args);
5935             }
5936         }
5937         return me;
5938     },
5939     /**
5940      * Returns a flyweight Element of the dom element object at the specified index
5941      * @param {Number} index
5942      * @return {Ext.Element}
5943      */
5944     item : function(index){
5945         var me = this,
5946             el = me.elements[index],
5947             out = null;
5948
5949         if(el){
5950             out = me.getElement(el);
5951         }
5952         return out;
5953     },
5954
5955     // fixes scope with flyweight
5956     addListener : function(eventName, handler, scope, opt){
5957         var els = this.elements,
5958             len = els.length,
5959             i, e;
5960
5961         for(i = 0; i<len; i++) {
5962             e = els[i];
5963             if(e) {
5964                 Ext.EventManager.on(e, eventName, handler, scope || e, opt);
5965             }
5966         }
5967         return this;
5968     },
5969     /**
5970      * <p>Calls the passed function for each element in this composite.</p>
5971      * @param {Function} fn The function to call. The function is passed the following parameters:<ul>
5972      * <li><b>el</b> : Element<div class="sub-desc">The current Element in the iteration.
5973      * <b>This is the flyweight (shared) Ext.Element instance, so if you require a
5974      * a reference to the dom node, use el.dom.</b></div></li>
5975      * <li><b>c</b> : Composite<div class="sub-desc">This Composite object.</div></li>
5976      * <li><b>idx</b> : Number<div class="sub-desc">The zero-based index in the iteration.</div></li>
5977      * </ul>
5978      * @param {Object} scope (optional) The scope (<i>this</i> reference) in which the function is executed. (defaults to the Element)
5979      * @return {CompositeElement} this
5980      */
5981     each : function(fn, scope){
5982         var me = this,
5983             els = me.elements,
5984             len = els.length,
5985             i, e;
5986
5987         for(i = 0; i<len; i++) {
5988             e = els[i];
5989             if(e){
5990                 e = this.getElement(e);
5991                 if(fn.call(scope || e, e, me, i) === false){
5992                     break;
5993                 }
5994             }
5995         }
5996         return me;
5997     },
5998
5999     /**
6000     * Clears this Composite and adds the elements passed.
6001     * @param {Mixed} els Either an array of DOM elements, or another Composite from which to fill this Composite.
6002     * @return {CompositeElement} this
6003     */
6004     fill : function(els){
6005         var me = this;
6006         me.elements = [];
6007         me.add(els);
6008         return me;
6009     },
6010
6011     /**
6012      * Filters this composite to only elements that match the passed selector.
6013      * @param {String/Function} selector A string CSS selector or a comparison function.
6014      * The comparison function will be called with the following arguments:<ul>
6015      * <li><code>el</code> : Ext.Element<div class="sub-desc">The current DOM element.</div></li>
6016      * <li><code>index</code> : Number<div class="sub-desc">The current index within the collection.</div></li>
6017      * </ul>
6018      * @return {CompositeElement} this
6019      */
6020     filter : function(selector){
6021         var els = [],
6022             me = this,
6023             fn = Ext.isFunction(selector) ? selector
6024                 : function(el){
6025                     return el.is(selector);
6026                 };
6027
6028         me.each(function(el, self, i) {
6029             if (fn(el, i) !== false) {
6030                 els[els.length] = me.transformElement(el);
6031             }
6032         });
6033         
6034         me.elements = els;
6035         return me;
6036     },
6037
6038     /**
6039      * Find the index of the passed element within the composite collection.
6040      * @param el {Mixed} The id of an element, or an Ext.Element, or an HtmlElement to find within the composite collection.
6041      * @return Number The index of the passed Ext.Element in the composite collection, or -1 if not found.
6042      */
6043     indexOf : function(el){
6044         return this.elements.indexOf(this.transformElement(el));
6045     },
6046
6047     /**
6048     * Replaces the specified element with the passed element.
6049     * @param {Mixed} el The id of an element, the Element itself, the index of the element in this composite
6050     * to replace.
6051     * @param {Mixed} replacement The id of an element or the Element itself.
6052     * @param {Boolean} domReplace (Optional) True to remove and replace the element in the document too.
6053     * @return {CompositeElement} this
6054     */
6055     replaceElement : function(el, replacement, domReplace){
6056         var index = !isNaN(el) ? el : this.indexOf(el),
6057             d;
6058         if(index > -1){
6059             replacement = Ext.getDom(replacement);
6060             if(domReplace){
6061                 d = this.elements[index];
6062                 d.parentNode.insertBefore(replacement, d);
6063                 Ext.removeNode(d);
6064             }
6065             this.elements.splice(index, 1, replacement);
6066         }
6067         return this;
6068     },
6069
6070     /**
6071      * Removes all elements.
6072      */
6073     clear : function(){
6074         this.elements = [];
6075     }
6076 };
6077
6078 Ext.CompositeElementLite.prototype.on = Ext.CompositeElementLite.prototype.addListener;
6079
6080 /**
6081  * @private
6082  * Copies all of the functions from Ext.Element's prototype onto CompositeElementLite's prototype.
6083  * This is called twice - once immediately below, and once again after additional Ext.Element
6084  * are added in Ext JS
6085  */
6086 Ext.CompositeElementLite.importElementMethods = function() {
6087     var fnName,
6088         ElProto = Ext.Element.prototype,
6089         CelProto = Ext.CompositeElementLite.prototype;
6090
6091     for (fnName in ElProto) {
6092         if (typeof ElProto[fnName] == 'function'){
6093             (function(fnName) {
6094                 CelProto[fnName] = CelProto[fnName] || function() {
6095                     return this.invoke(fnName, arguments);
6096                 };
6097             }).call(CelProto, fnName);
6098
6099         }
6100     }
6101 };
6102
6103 Ext.CompositeElementLite.importElementMethods();
6104
6105 if(Ext.DomQuery){
6106     Ext.Element.selectorFunction = Ext.DomQuery.select;
6107 }
6108
6109 /**
6110  * Selects elements based on the passed CSS selector to enable {@link Ext.Element Element} methods
6111  * to be applied to many related elements in one statement through the returned {@link Ext.CompositeElement CompositeElement} or
6112  * {@link Ext.CompositeElementLite CompositeElementLite} object.
6113  * @param {String/Array} selector The CSS selector or an array of elements
6114  * @param {HTMLElement/String} root (optional) The root element of the query or id of the root
6115  * @return {CompositeElementLite/CompositeElement}
6116  * @member Ext.Element
6117  * @method select
6118  */
6119 Ext.Element.select = function(selector, root){
6120     var els;
6121     if(typeof selector == "string"){
6122         els = Ext.Element.selectorFunction(selector, root);
6123     }else if(selector.length !== undefined){
6124         els = selector;
6125     }else{
6126         throw "Invalid selector";
6127     }
6128     return new Ext.CompositeElementLite(els);
6129 };
6130 /**
6131  * Selects elements based on the passed CSS selector to enable {@link Ext.Element Element} methods
6132  * to be applied to many related elements in one statement through the returned {@link Ext.CompositeElement CompositeElement} or
6133  * {@link Ext.CompositeElementLite CompositeElementLite} object.
6134  * @param {String/Array} selector The CSS selector or an array of elements
6135  * @param {HTMLElement/String} root (optional) The root element of the query or id of the root
6136  * @return {CompositeElementLite/CompositeElement}
6137  * @member Ext
6138  * @method select
6139  */
6140 Ext.select = Ext.Element.select;
6141 (function(){
6142     var BEFOREREQUEST = "beforerequest",
6143         REQUESTCOMPLETE = "requestcomplete",
6144         REQUESTEXCEPTION = "requestexception",
6145         UNDEFINED = undefined,
6146         LOAD = 'load',
6147         POST = 'POST',
6148         GET = 'GET',
6149         WINDOW = window;
6150
6151     /**
6152      * @class Ext.data.Connection
6153      * @extends Ext.util.Observable
6154      * <p>The class encapsulates a connection to the page's originating domain, allowing requests to be made
6155      * either to a configured URL, or to a URL specified at request time.</p>
6156      * <p>Requests made by this class are asynchronous, and will return immediately. No data from
6157      * the server will be available to the statement immediately following the {@link #request} call.
6158      * To process returned data, use a
6159      * <a href="#request-option-success" ext:member="request-option-success" ext:cls="Ext.data.Connection">success callback</a>
6160      * in the request options object,
6161      * or an {@link #requestcomplete event listener}.</p>
6162      * <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
6163      * is they are <b>not</b> performed using XMLHttpRequests. Instead the form is submitted in the standard
6164      * manner with the DOM <tt>&lt;form></tt> element temporarily modified to have its
6165      * <a href="http://www.w3.org/TR/REC-html40/present/frames.html#adef-target">target</a> set to refer
6166      * to a dynamically generated, hidden <tt>&lt;iframe></tt> which is inserted into the document
6167      * but removed after the return data has been gathered.</p>
6168      * <p>The server response is parsed by the browser to create the document for the IFRAME. If the
6169      * server is using JSON to send the return object, then the
6170      * <a href="http://www.w3.org/Protocols/rfc2616/rfc2616-sec14.html#sec14.17">Content-Type</a> header
6171      * must be set to "text/html" in order to tell the browser to insert the text unchanged into the document body.</p>
6172      * <p>Characters which are significant to an HTML parser must be sent as HTML entities, so encode
6173      * "&lt;" as "&amp;lt;", "&amp;" as "&amp;amp;" etc.</p>
6174      * <p>The response text is retrieved from the document, and a fake XMLHttpRequest object
6175      * is created containing a <tt>responseText</tt> property in order to conform to the
6176      * requirements of event handlers and callbacks.</p>
6177      * <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>
6178      * and some server technologies (notably JEE) may require some custom processing in order to
6179      * retrieve parameter names and parameter values from the packet content.</p>
6180      * <p>Also note that it's not possible to check the response code of the hidden iframe, so the success handler will ALWAYS fire.</p>
6181      * @constructor
6182      * @param {Object} config a configuration object.
6183      */
6184     Ext.data.Connection = function(config){
6185         Ext.apply(this, config);
6186         this.addEvents(
6187             /**
6188              * @event beforerequest
6189              * Fires before a network request is made to retrieve a data object.
6190              * @param {Connection} conn This Connection object.
6191              * @param {Object} options The options config object passed to the {@link #request} method.
6192              */
6193             BEFOREREQUEST,
6194             /**
6195              * @event requestcomplete
6196              * Fires if the request was successfully completed.
6197              * @param {Connection} conn This Connection object.
6198              * @param {Object} response The XHR object containing the response data.
6199              * See <a href="http://www.w3.org/TR/XMLHttpRequest/">The XMLHttpRequest Object</a>
6200              * for details.
6201              * @param {Object} options The options config object passed to the {@link #request} method.
6202              */
6203             REQUESTCOMPLETE,
6204             /**
6205              * @event requestexception
6206              * Fires if an error HTTP status was returned from the server.
6207              * See <a href="http://www.w3.org/Protocols/rfc2616/rfc2616-sec10.html">HTTP Status Code Definitions</a>
6208              * for details of HTTP status codes.
6209              * @param {Connection} conn This Connection object.
6210              * @param {Object} response The XHR object containing the response data.
6211              * See <a href="http://www.w3.org/TR/XMLHttpRequest/">The XMLHttpRequest Object</a>
6212              * for details.
6213              * @param {Object} options The options config object passed to the {@link #request} method.
6214              */
6215             REQUESTEXCEPTION
6216         );
6217         Ext.data.Connection.superclass.constructor.call(this);
6218     };
6219
6220     Ext.extend(Ext.data.Connection, Ext.util.Observable, {
6221         /**
6222          * @cfg {String} url (Optional) <p>The default URL to be used for requests to the server. Defaults to undefined.</p>
6223          * <p>The <code>url</code> config may be a function which <i>returns</i> the URL to use for the Ajax request. The scope
6224          * (<code><b>this</b></code> reference) of the function is the <code>scope</code> option passed to the {@link #request} method.</p>
6225          */
6226         /**
6227          * @cfg {Object} extraParams (Optional) An object containing properties which are used as
6228          * extra parameters to each request made by this object. (defaults to undefined)
6229          */
6230         /**
6231          * @cfg {Object} defaultHeaders (Optional) An object containing request headers which are added
6232          *  to each request made by this object. (defaults to undefined)
6233          */
6234         /**
6235          * @cfg {String} method (Optional) The default HTTP method to be used for requests.
6236          * (defaults to undefined; if not set, but {@link #request} params are present, POST will be used;
6237          * otherwise, GET will be used.)
6238          */
6239         /**
6240          * @cfg {Number} timeout (Optional) The timeout in milliseconds to be used for requests. (defaults to 30000)
6241          */
6242         timeout : 30000,
6243         /**
6244          * @cfg {Boolean} autoAbort (Optional) Whether this request should abort any pending requests. (defaults to false)
6245          * @type Boolean
6246          */
6247         autoAbort:false,
6248
6249         /**
6250          * @cfg {Boolean} disableCaching (Optional) True to add a unique cache-buster param to GET requests. (defaults to true)
6251          * @type Boolean
6252          */
6253         disableCaching: true,
6254
6255         /**
6256          * @cfg {String} disableCachingParam (Optional) Change the parameter which is sent went disabling caching
6257          * through a cache buster. Defaults to '_dc'
6258          * @type String
6259          */
6260         disableCachingParam: '_dc',
6261
6262         /**
6263          * <p>Sends an HTTP request to a remote server.</p>
6264          * <p><b>Important:</b> Ajax server requests are asynchronous, and this call will
6265          * return before the response has been received. Process any returned data
6266          * in a callback function.</p>
6267          * <pre><code>
6268 Ext.Ajax.request({
6269    url: 'ajax_demo/sample.json',
6270    success: function(response, opts) {
6271       var obj = Ext.decode(response.responseText);
6272       console.dir(obj);
6273    },
6274    failure: function(response, opts) {
6275       console.log('server-side failure with status code ' + response.status);
6276    }
6277 });
6278          * </code></pre>
6279          * <p>To execute a callback function in the correct scope, use the <tt>scope</tt> option.</p>
6280          * @param {Object} options An object which may contain the following properties:<ul>
6281          * <li><b>url</b> : String/Function (Optional)<div class="sub-desc">The URL to
6282          * which to send the request, or a function to call which returns a URL string. The scope of the
6283          * function is specified by the <tt>scope</tt> option. Defaults to the configured
6284          * <tt>{@link #url}</tt>.</div></li>
6285          * <li><b>params</b> : Object/String/Function (Optional)<div class="sub-desc">
6286          * An object containing properties which are used as parameters to the
6287          * request, a url encoded string or a function to call to get either. The scope of the function
6288          * is specified by the <tt>scope</tt> option.</div></li>
6289          * <li><b>method</b> : String (Optional)<div class="sub-desc">The HTTP method to use
6290          * for the request. Defaults to the configured method, or if no method was configured,
6291          * "GET" if no parameters are being sent, and "POST" if parameters are being sent.  Note that
6292          * the method name is case-sensitive and should be all caps.</div></li>
6293          * <li><b>callback</b> : Function (Optional)<div class="sub-desc">The
6294          * function to be called upon receipt of the HTTP response. The callback is
6295          * called regardless of success or failure and is passed the following
6296          * parameters:<ul>
6297          * <li><b>options</b> : Object<div class="sub-desc">The parameter to the request call.</div></li>
6298          * <li><b>success</b> : Boolean<div class="sub-desc">True if the request succeeded.</div></li>
6299          * <li><b>response</b> : Object<div class="sub-desc">The XMLHttpRequest object containing the response data.
6300          * See <a href="http://www.w3.org/TR/XMLHttpRequest/">http://www.w3.org/TR/XMLHttpRequest/</a> for details about
6301          * accessing elements of the response.</div></li>
6302          * </ul></div></li>
6303          * <li><a id="request-option-success"></a><b>success</b> : Function (Optional)<div class="sub-desc">The function
6304          * to be called upon success of the request. The callback is passed the following
6305          * parameters:<ul>
6306          * <li><b>response</b> : Object<div class="sub-desc">The XMLHttpRequest object containing the response data.</div></li>
6307          * <li><b>options</b> : Object<div class="sub-desc">The parameter to the request call.</div></li>
6308          * </ul></div></li>
6309          * <li><b>failure</b> : Function (Optional)<div class="sub-desc">The function
6310          * to be called upon failure of the request. The callback is passed the
6311          * following parameters:<ul>
6312          * <li><b>response</b> : Object<div class="sub-desc">The XMLHttpRequest object containing the response data.</div></li>
6313          * <li><b>options</b> : Object<div class="sub-desc">The parameter to the request call.</div></li>
6314          * </ul></div></li>
6315          * <li><b>scope</b> : Object (Optional)<div class="sub-desc">The scope in
6316          * which to execute the callbacks: The "this" object for the callback function. If the <tt>url</tt>, or <tt>params</tt> options were
6317          * specified as functions from which to draw values, then this also serves as the scope for those function calls.
6318          * Defaults to the browser window.</div></li>
6319          * <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>
6320          * <li><b>form</b> : Element/HTMLElement/String (Optional)<div class="sub-desc">The <tt>&lt;form&gt;</tt>
6321          * Element or the id of the <tt>&lt;form&gt;</tt> to pull parameters from.</div></li>
6322          * <li><a id="request-option-isUpload"></a><b>isUpload</b> : Boolean (Optional)<div class="sub-desc"><b>Only meaningful when used
6323          * with the <tt>form</tt> option</b>.
6324          * <p>True if the form object is a file upload (will be set automatically if the form was
6325          * configured with <b><tt>enctype</tt></b> "multipart/form-data").</p>
6326          * <p>File uploads are not performed using normal "Ajax" techniques, that is they are <b>not</b>
6327          * performed using XMLHttpRequests. Instead the form is submitted in the standard manner with the
6328          * DOM <tt>&lt;form></tt> element temporarily modified to have its
6329          * <a href="http://www.w3.org/TR/REC-html40/present/frames.html#adef-target">target</a> set to refer
6330          * to a dynamically generated, hidden <tt>&lt;iframe></tt> which is inserted into the document
6331          * but removed after the return data has been gathered.</p>
6332          * <p>The server response is parsed by the browser to create the document for the IFRAME. If the
6333          * server is using JSON to send the return object, then the
6334          * <a href="http://www.w3.org/Protocols/rfc2616/rfc2616-sec14.html#sec14.17">Content-Type</a> header
6335          * must be set to "text/html" in order to tell the browser to insert the text unchanged into the document body.</p>
6336          * <p>The response text is retrieved from the document, and a fake XMLHttpRequest object
6337          * is created containing a <tt>responseText</tt> property in order to conform to the
6338          * requirements of event handlers and callbacks.</p>
6339          * <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>
6340          * and some server technologies (notably JEE) may require some custom processing in order to
6341          * retrieve parameter names and parameter values from the packet content.</p>
6342          * </div></li>
6343          * <li><b>headers</b> : Object (Optional)<div class="sub-desc">Request
6344          * headers to set for the request.</div></li>
6345          * <li><b>xmlData</b> : Object (Optional)<div class="sub-desc">XML document
6346          * to use for the post. Note: This will be used instead of params for the post
6347          * data. Any params will be appended to the URL.</div></li>
6348          * <li><b>jsonData</b> : Object/String (Optional)<div class="sub-desc">JSON
6349          * data to use as the post. Note: This will be used instead of params for the post
6350          * data. Any params will be appended to the URL.</div></li>
6351          * <li><b>disableCaching</b> : Boolean (Optional)<div class="sub-desc">True
6352          * to add a unique cache-buster param to GET requests.</div></li>
6353          * </ul></p>
6354          * <p>The options object may also contain any other property which might be needed to perform
6355          * postprocessing in a callback because it is passed to callback functions.</p>
6356          * @return {Number} transactionId The id of the server transaction. This may be used
6357          * to cancel the request.
6358          */
6359         request : function(o){
6360             var me = this;
6361             if(me.fireEvent(BEFOREREQUEST, me, o)){
6362                 if (o.el) {
6363                     if(!Ext.isEmpty(o.indicatorText)){
6364                         me.indicatorText = '<div class="loading-indicator">'+o.indicatorText+"</div>";
6365                     }
6366                     if(me.indicatorText) {
6367                         Ext.getDom(o.el).innerHTML = me.indicatorText;
6368                     }
6369                     o.success = (Ext.isFunction(o.success) ? o.success : function(){}).createInterceptor(function(response) {
6370                         Ext.getDom(o.el).innerHTML = response.responseText;
6371                     });
6372                 }
6373
6374                 var p = o.params,
6375                     url = o.url || me.url,
6376                     method,
6377                     cb = {success: me.handleResponse,
6378                           failure: me.handleFailure,
6379                           scope: me,
6380                           argument: {options: o},
6381                           timeout : Ext.num(o.timeout, me.timeout)
6382                     },
6383                     form,
6384                     serForm;
6385
6386
6387                 if (Ext.isFunction(p)) {
6388                     p = p.call(o.scope||WINDOW, o);
6389                 }
6390
6391                 p = Ext.urlEncode(me.extraParams, Ext.isObject(p) ? Ext.urlEncode(p) : p);
6392
6393                 if (Ext.isFunction(url)) {
6394                     url = url.call(o.scope || WINDOW, o);
6395                 }
6396
6397                 if((form = Ext.getDom(o.form))){
6398                     url = url || form.action;
6399                      if(o.isUpload || (/multipart\/form-data/i.test(form.getAttribute("enctype")))) {
6400                          return me.doFormUpload.call(me, o, p, url);
6401                      }
6402                     serForm = Ext.lib.Ajax.serializeForm(form);
6403                     p = p ? (p + '&' + serForm) : serForm;
6404                 }
6405
6406                 method = o.method || me.method || ((p || o.xmlData || o.jsonData) ? POST : GET);
6407
6408                 if(method === GET && (me.disableCaching && o.disableCaching !== false) || o.disableCaching === true){
6409                     var dcp = o.disableCachingParam || me.disableCachingParam;
6410                     url = Ext.urlAppend(url, dcp + '=' + (new Date().getTime()));
6411                 }
6412
6413                 o.headers = Ext.apply(o.headers || {}, me.defaultHeaders || {});
6414
6415                 if(o.autoAbort === true || me.autoAbort) {
6416                     me.abort();
6417                 }
6418
6419                 if((method == GET || o.xmlData || o.jsonData) && p){
6420                     url = Ext.urlAppend(url, p);
6421                     p = '';
6422                 }
6423                 return (me.transId = Ext.lib.Ajax.request(method, url, cb, p, o));
6424             }else{
6425                 return o.callback ? o.callback.apply(o.scope, [o,UNDEFINED,UNDEFINED]) : null;
6426             }
6427         },
6428
6429         /**
6430          * Determine whether this object has a request outstanding.
6431          * @param {Number} transactionId (Optional) defaults to the last transaction
6432          * @return {Boolean} True if there is an outstanding request.
6433          */
6434         isLoading : function(transId){
6435             return transId ? Ext.lib.Ajax.isCallInProgress(transId) : !! this.transId;
6436         },
6437
6438         /**
6439          * Aborts any outstanding request.
6440          * @param {Number} transactionId (Optional) defaults to the last transaction
6441          */
6442         abort : function(transId){
6443             if(transId || this.isLoading()){
6444                 Ext.lib.Ajax.abort(transId || this.transId);
6445             }
6446         },
6447
6448         // private
6449         handleResponse : function(response){
6450             this.transId = false;
6451             var options = response.argument.options;
6452             response.argument = options ? options.argument : null;
6453             this.fireEvent(REQUESTCOMPLETE, this, response, options);
6454             if(options.success){
6455                 options.success.call(options.scope, response, options);
6456             }
6457             if(options.callback){
6458                 options.callback.call(options.scope, options, true, response);
6459             }
6460         },
6461
6462         // private
6463         handleFailure : function(response, e){
6464             this.transId = false;
6465             var options = response.argument.options;
6466             response.argument = options ? options.argument : null;
6467             this.fireEvent(REQUESTEXCEPTION, this, response, options, e);
6468             if(options.failure){
6469                 options.failure.call(options.scope, response, options);
6470             }
6471             if(options.callback){
6472                 options.callback.call(options.scope, options, false, response);
6473             }
6474         },
6475
6476         // private
6477         doFormUpload : function(o, ps, url){
6478             var id = Ext.id(),
6479                 doc = document,
6480                 frame = doc.createElement('iframe'),
6481                 form = Ext.getDom(o.form),
6482                 hiddens = [],
6483                 hd,
6484                 encoding = 'multipart/form-data',
6485                 buf = {
6486                     target: form.target,
6487                     method: form.method,
6488                     encoding: form.encoding,
6489                     enctype: form.enctype,
6490                     action: form.action
6491                 };
6492
6493             /*
6494              * Originally this behaviour was modified for Opera 10 to apply the secure URL after
6495              * the frame had been added to the document. It seems this has since been corrected in
6496              * Opera so the behaviour has been reverted, the URL will be set before being added.
6497              */
6498             Ext.fly(frame).set({
6499                 id: id,
6500                 name: id,
6501                 cls: 'x-hidden',
6502                 src: Ext.SSL_SECURE_URL
6503             }); 
6504
6505             doc.body.appendChild(frame);
6506
6507             // This is required so that IE doesn't pop the response up in a new window.
6508             if(Ext.isIE){
6509                document.frames[id].name = id;
6510             }
6511
6512
6513             Ext.fly(form).set({
6514                 target: id,
6515                 method: POST,
6516                 enctype: encoding,
6517                 encoding: encoding,
6518                 action: url || buf.action
6519             });
6520
6521             // add dynamic params
6522             Ext.iterate(Ext.urlDecode(ps, false), function(k, v){
6523                 hd = doc.createElement('input');
6524                 Ext.fly(hd).set({
6525                     type: 'hidden',
6526                     value: v,
6527                     name: k
6528                 });
6529                 form.appendChild(hd);
6530                 hiddens.push(hd);
6531             });
6532
6533             function cb(){
6534                 var me = this,
6535                     // bogus response object
6536                     r = {responseText : '',
6537                          responseXML : null,
6538                          argument : o.argument},
6539                     doc,
6540                     firstChild;
6541
6542                 try{
6543                     doc = frame.contentWindow.document || frame.contentDocument || WINDOW.frames[id].document;
6544                     if(doc){
6545                         if(doc.body){
6546                             if(/textarea/i.test((firstChild = doc.body.firstChild || {}).tagName)){ // json response wrapped in textarea
6547                                 r.responseText = firstChild.value;
6548                             }else{
6549                                 r.responseText = doc.body.innerHTML;
6550                             }
6551                         }
6552                         //in IE the document may still have a body even if returns XML.
6553                         r.responseXML = doc.XMLDocument || doc;
6554                     }
6555                 }
6556                 catch(e) {}
6557
6558                 Ext.EventManager.removeListener(frame, LOAD, cb, me);
6559
6560                 me.fireEvent(REQUESTCOMPLETE, me, r, o);
6561
6562                 function runCallback(fn, scope, args){
6563                     if(Ext.isFunction(fn)){
6564                         fn.apply(scope, args);
6565                     }
6566                 }
6567
6568                 runCallback(o.success, o.scope, [r, o]);
6569                 runCallback(o.callback, o.scope, [o, true, r]);
6570
6571                 if(!me.debugUploads){
6572                     setTimeout(function(){Ext.removeNode(frame);}, 100);
6573                 }
6574             }
6575
6576             Ext.EventManager.on(frame, LOAD, cb, this);
6577             form.submit();
6578
6579             Ext.fly(form).set(buf);
6580             Ext.each(hiddens, function(h) {
6581                 Ext.removeNode(h);
6582             });
6583         }
6584     });
6585 })();
6586
6587 /**
6588  * @class Ext.Ajax
6589  * @extends Ext.data.Connection
6590  * <p>The global Ajax request class that provides a simple way to make Ajax requests
6591  * with maximum flexibility.</p>
6592  * <p>Since Ext.Ajax is a singleton, you can set common properties/events for it once
6593  * and override them at the request function level only if necessary.</p>
6594  * <p>Common <b>Properties</b> you may want to set are:<div class="mdetail-params"><ul>
6595  * <li><b><tt>{@link #method}</tt></b><p class="sub-desc"></p></li>
6596  * <li><b><tt>{@link #extraParams}</tt></b><p class="sub-desc"></p></li>
6597  * <li><b><tt>{@link #url}</tt></b><p class="sub-desc"></p></li>
6598  * </ul></div>
6599  * <pre><code>
6600 // Default headers to pass in every request
6601 Ext.Ajax.defaultHeaders = {
6602     'Powered-By': 'Ext'
6603 };
6604  * </code></pre>
6605  * </p>
6606  * <p>Common <b>Events</b> you may want to set are:<div class="mdetail-params"><ul>
6607  * <li><b><tt>{@link Ext.data.Connection#beforerequest beforerequest}</tt></b><p class="sub-desc"></p></li>
6608  * <li><b><tt>{@link Ext.data.Connection#requestcomplete requestcomplete}</tt></b><p class="sub-desc"></p></li>
6609  * <li><b><tt>{@link Ext.data.Connection#requestexception requestexception}</tt></b><p class="sub-desc"></p></li>
6610  * </ul></div>
6611  * <pre><code>
6612 // Example: show a spinner during all Ajax requests
6613 Ext.Ajax.on('beforerequest', this.showSpinner, this);
6614 Ext.Ajax.on('requestcomplete', this.hideSpinner, this);
6615 Ext.Ajax.on('requestexception', this.hideSpinner, this);
6616  * </code></pre>
6617  * </p>
6618  * <p>An example request:</p>
6619  * <pre><code>
6620 // Basic request
6621 Ext.Ajax.{@link Ext.data.Connection#request request}({
6622    url: 'foo.php',
6623    success: someFn,
6624    failure: otherFn,
6625    headers: {
6626        'my-header': 'foo'
6627    },
6628    params: { foo: 'bar' }
6629 });
6630
6631 // Simple ajax form submission
6632 Ext.Ajax.{@link Ext.data.Connection#request request}({
6633     form: 'some-form',
6634     params: 'foo=bar'
6635 });
6636  * </code></pre>
6637  * </p>
6638  * @singleton
6639  */
6640 Ext.Ajax = new Ext.data.Connection({
6641     /**
6642      * @cfg {String} url @hide
6643      */
6644     /**
6645      * @cfg {Object} extraParams @hide
6646      */
6647     /**
6648      * @cfg {Object} defaultHeaders @hide
6649      */
6650     /**
6651      * @cfg {String} method (Optional) @hide
6652      */
6653     /**
6654      * @cfg {Number} timeout (Optional) @hide
6655      */
6656     /**
6657      * @cfg {Boolean} autoAbort (Optional) @hide
6658      */
6659
6660     /**
6661      * @cfg {Boolean} disableCaching (Optional) @hide
6662      */
6663
6664     /**
6665      * @property  disableCaching
6666      * True to add a unique cache-buster param to GET requests. (defaults to true)
6667      * @type Boolean
6668      */
6669     /**
6670      * @property  url
6671      * The default URL to be used for requests to the server. (defaults to undefined)
6672      * If the server receives all requests through one URL, setting this once is easier than
6673      * entering it on every request.
6674      * @type String
6675      */
6676     /**
6677      * @property  extraParams
6678      * An object containing properties which are used as extra parameters to each request made
6679      * by this object (defaults to undefined). Session information and other data that you need
6680      * to pass with each request are commonly put here.
6681      * @type Object
6682      */
6683     /**
6684      * @property  defaultHeaders
6685      * An object containing request headers which are added to each request made by this object
6686      * (defaults to undefined).
6687      * @type Object
6688      */
6689     /**
6690      * @property  method
6691      * The default HTTP method to be used for requests. Note that this is case-sensitive and
6692      * should be all caps (defaults to undefined; if not set but params are present will use
6693      * <tt>"POST"</tt>, otherwise will use <tt>"GET"</tt>.)
6694      * @type String
6695      */
6696     /**
6697      * @property  timeout
6698      * The timeout in milliseconds to be used for requests. (defaults to 30000)
6699      * @type Number
6700      */
6701
6702     /**
6703      * @property  autoAbort
6704      * Whether a new request should abort any pending requests. (defaults to false)
6705      * @type Boolean
6706      */
6707     autoAbort : false,
6708
6709     /**
6710      * Serialize the passed form into a url encoded string
6711      * @param {String/HTMLElement} form
6712      * @return {String}
6713      */
6714     serializeForm : function(form){
6715         return Ext.lib.Ajax.serializeForm(form);
6716     }
6717 });
6718 /**
6719  * @class Ext.util.JSON
6720  * Modified version of Douglas Crockford"s json.js that doesn"t
6721  * mess with the Object prototype
6722  * http://www.json.org/js.html
6723  * @singleton
6724  */
6725 Ext.util.JSON = new (function(){
6726     var useHasOwn = !!{}.hasOwnProperty,
6727         isNative = function() {
6728             var useNative = null;
6729
6730             return function() {
6731                 if (useNative === null) {
6732                     useNative = Ext.USE_NATIVE_JSON && window.JSON && JSON.toString() == '[object JSON]';
6733                 }
6734         
6735                 return useNative;
6736             };
6737         }(),
6738         pad = function(n) {
6739             return n < 10 ? "0" + n : n;
6740         },
6741         doDecode = function(json){
6742             return eval("(" + json + ")");    
6743         },
6744         doEncode = function(o){
6745             if(!Ext.isDefined(o) || o === null){
6746                 return "null";
6747             }else if(Ext.isArray(o)){
6748                 return encodeArray(o);
6749             }else if(Ext.isDate(o)){
6750                 return Ext.util.JSON.encodeDate(o);
6751             }else if(Ext.isString(o)){
6752                 return encodeString(o);
6753             }else if(typeof o == "number"){
6754                 //don't use isNumber here, since finite checks happen inside isNumber
6755                 return isFinite(o) ? String(o) : "null";
6756             }else if(Ext.isBoolean(o)){
6757                 return String(o);
6758             }else {
6759                 var a = ["{"], b, i, v;
6760                 for (i in o) {
6761                     // don't encode DOM objects
6762                     if(!o.getElementsByTagName){
6763                         if(!useHasOwn || o.hasOwnProperty(i)) {
6764                             v = o[i];
6765                             switch (typeof v) {
6766                             case "undefined":
6767                             case "function":
6768                             case "unknown":
6769                                 break;
6770                             default:
6771                                 if(b){
6772                                     a.push(',');
6773                                 }
6774                                 a.push(doEncode(i), ":",
6775                                         v === null ? "null" : doEncode(v));
6776                                 b = true;
6777                             }
6778                         }
6779                     }
6780                 }
6781                 a.push("}");
6782                 return a.join("");
6783             }    
6784         },
6785         m = {
6786             "\b": '\\b',
6787             "\t": '\\t',
6788             "\n": '\\n',
6789             "\f": '\\f',
6790             "\r": '\\r',
6791             '"' : '\\"',
6792             "\\": '\\\\'
6793         },
6794         encodeString = function(s){
6795             if (/["\\\x00-\x1f]/.test(s)) {
6796                 return '"' + s.replace(/([\x00-\x1f\\"])/g, function(a, b) {
6797                     var c = m[b];
6798                     if(c){
6799                         return c;
6800                     }
6801                     c = b.charCodeAt();
6802                     return "\\u00" +
6803                         Math.floor(c / 16).toString(16) +
6804                         (c % 16).toString(16);
6805                 }) + '"';
6806             }
6807             return '"' + s + '"';
6808         },
6809         encodeArray = function(o){
6810             var a = ["["], b, i, l = o.length, v;
6811                 for (i = 0; i < l; i += 1) {
6812                     v = o[i];
6813                     switch (typeof v) {
6814                         case "undefined":
6815                         case "function":
6816                         case "unknown":
6817                             break;
6818                         default:
6819                             if (b) {
6820                                 a.push(',');
6821                             }
6822                             a.push(v === null ? "null" : Ext.util.JSON.encode(v));
6823                             b = true;
6824                     }
6825                 }
6826                 a.push("]");
6827                 return a.join("");
6828         };
6829
6830     /**
6831      * <p>Encodes a Date. This returns the actual string which is inserted into the JSON string as the literal expression.
6832      * <b>The returned value includes enclosing double quotation marks.</b></p>
6833      * <p>The default return format is "yyyy-mm-ddThh:mm:ss".</p>
6834      * <p>To override this:</p><pre><code>
6835 Ext.util.JSON.encodeDate = function(d) {
6836     return d.format('"Y-m-d"');
6837 };
6838 </code></pre>
6839      * @param {Date} d The Date to encode
6840      * @return {String} The string literal to use in a JSON string.
6841      */
6842     this.encodeDate = function(o){
6843         return '"' + o.getFullYear() + "-" +
6844                 pad(o.getMonth() + 1) + "-" +
6845                 pad(o.getDate()) + "T" +
6846                 pad(o.getHours()) + ":" +
6847                 pad(o.getMinutes()) + ":" +
6848                 pad(o.getSeconds()) + '"';
6849     };
6850
6851     /**
6852      * Encodes an Object, Array or other value
6853      * @param {Mixed} o The variable to encode
6854      * @return {String} The JSON string
6855      */
6856     this.encode = function() {
6857         var ec;
6858         return function(o) {
6859             if (!ec) {
6860                 // setup encoding function on first access
6861                 ec = isNative() ? JSON.stringify : doEncode;
6862             }
6863             return ec(o);
6864         };
6865     }();
6866
6867
6868     /**
6869      * Decodes (parses) a JSON string to an object. If the JSON is invalid, this function throws a SyntaxError unless the safe option is set.
6870      * @param {String} json The JSON string
6871      * @return {Object} The resulting object
6872      */
6873     this.decode = function() {
6874         var dc;
6875         return function(json) {
6876             if (!dc) {
6877                 // setup decoding function on first access
6878                 dc = isNative() ? JSON.parse : doDecode;
6879             }
6880             return dc(json);
6881         };
6882     }();
6883
6884 })();
6885 /**
6886  * Shorthand for {@link Ext.util.JSON#encode}
6887  * @param {Mixed} o The variable to encode
6888  * @return {String} The JSON string
6889  * @member Ext
6890  * @method encode
6891  */
6892 Ext.encode = Ext.util.JSON.encode;
6893 /**
6894  * Shorthand for {@link Ext.util.JSON#decode}
6895  * @param {String} json The JSON string
6896  * @param {Boolean} safe (optional) Whether to return null or throw an exception if the JSON is invalid.
6897  * @return {Object} The resulting object
6898  * @member Ext
6899  * @method decode
6900  */
6901 Ext.decode = Ext.util.JSON.decode;
6902 /**
6903  * @class Ext.EventManager
6904  * Registers event handlers that want to receive a normalized EventObject instead of the standard browser event and provides
6905  * several useful events directly.
6906  * See {@link Ext.EventObject} for more details on normalized event objects.
6907  * @singleton
6908  */
6909 Ext.EventManager = function(){
6910     var docReadyEvent,
6911         docReadyProcId,
6912         docReadyState = false,
6913         DETECT_NATIVE = Ext.isGecko || Ext.isWebKit || Ext.isSafari,
6914         E = Ext.lib.Event,
6915         D = Ext.lib.Dom,
6916         DOC = document,
6917         WINDOW = window,
6918         DOMCONTENTLOADED = "DOMContentLoaded",
6919         COMPLETE = 'complete',
6920         propRe = /^(?:scope|delay|buffer|single|stopEvent|preventDefault|stopPropagation|normalized|args|delegate)$/,
6921         /*
6922          * This cache is used to hold special js objects, the document and window, that don't have an id. We need to keep
6923          * a reference to them so we can look them up at a later point.
6924          */
6925         specialElCache = [];
6926
6927      function getId(el){
6928         var id = false,
6929             i = 0,
6930             len = specialElCache.length,
6931             skip = false,
6932             o;
6933             
6934         if (el) {
6935             if (el.getElementById || el.navigator) {
6936                 // look up the id
6937                 for(; i < len; ++i){
6938                     o = specialElCache[i];
6939                     if(o.el === el){
6940                         id = o.id;
6941                         break;
6942                     }
6943                 }
6944                 if(!id){
6945                     // for browsers that support it, ensure that give the el the same id
6946                     id = Ext.id(el);
6947                     specialElCache.push({
6948                         id: id,
6949                         el: el
6950                     });
6951                     skip = true;
6952                 }
6953             }else{
6954                 id = Ext.id(el);
6955             }
6956             if(!Ext.elCache[id]){
6957                 Ext.Element.addToCache(new Ext.Element(el), id);
6958                 if(skip){
6959                     Ext.elCache[id].skipGC = true;
6960                 }
6961             }
6962         }
6963         return id;
6964      }
6965
6966     /// There is some jquery work around stuff here that isn't needed in Ext Core.
6967     function addListener(el, ename, fn, task, wrap, scope){
6968         el = Ext.getDom(el);
6969         var id = getId(el),
6970             es = Ext.elCache[id].events,
6971             wfn;
6972
6973         wfn = E.on(el, ename, wrap);
6974         es[ename] = es[ename] || [];
6975
6976         /* 0 = Original Function,
6977            1 = Event Manager Wrapped Function,
6978            2 = Scope,
6979            3 = Adapter Wrapped Function,
6980            4 = Buffered Task
6981         */
6982         es[ename].push([fn, wrap, scope, wfn, task]);
6983
6984         // this is a workaround for jQuery and should somehow be removed from Ext Core in the future
6985         // without breaking ExtJS.
6986
6987         // workaround for jQuery
6988         if(el.addEventListener && ename == "mousewheel"){
6989             var args = ["DOMMouseScroll", wrap, false];
6990             el.addEventListener.apply(el, args);
6991             Ext.EventManager.addListener(WINDOW, 'unload', function(){
6992                 el.removeEventListener.apply(el, args);
6993             });
6994         }
6995
6996         // fix stopped mousedowns on the document
6997         if(el == DOC && ename == "mousedown"){
6998             Ext.EventManager.stoppedMouseDownEvent.addListener(wrap);
6999         }
7000     }
7001
7002     function doScrollChk(){
7003         /* Notes:
7004              'doScroll' will NOT work in a IFRAME/FRAMESET.
7005              The method succeeds but, a DOM query done immediately after -- FAILS.
7006           */
7007         if(window != top){
7008             return false;
7009         }
7010
7011         try{
7012             DOC.documentElement.doScroll('left');
7013         }catch(e){
7014              return false;
7015         }
7016
7017         fireDocReady();
7018         return true;
7019     }
7020     /**
7021      * @return {Boolean} True if the document is in a 'complete' state (or was determined to
7022      * be true by other means). If false, the state is evaluated again until canceled.
7023      */
7024     function checkReadyState(e){
7025
7026         if(Ext.isIE && doScrollChk()){
7027             return true;
7028         }
7029         if(DOC.readyState == COMPLETE){
7030             fireDocReady();
7031             return true;
7032         }
7033         docReadyState || (docReadyProcId = setTimeout(arguments.callee, 2));
7034         return false;
7035     }
7036
7037     var styles;
7038     function checkStyleSheets(e){
7039         styles || (styles = Ext.query('style, link[rel=stylesheet]'));
7040         if(styles.length == DOC.styleSheets.length){
7041             fireDocReady();
7042             return true;
7043         }
7044         docReadyState || (docReadyProcId = setTimeout(arguments.callee, 2));
7045         return false;
7046     }
7047
7048     function OperaDOMContentLoaded(e){
7049         DOC.removeEventListener(DOMCONTENTLOADED, arguments.callee, false);
7050         checkStyleSheets();
7051     }
7052
7053     function fireDocReady(e){
7054         if(!docReadyState){
7055             docReadyState = true; //only attempt listener removal once
7056
7057             if(docReadyProcId){
7058                 clearTimeout(docReadyProcId);
7059             }
7060             if(DETECT_NATIVE) {
7061                 DOC.removeEventListener(DOMCONTENTLOADED, fireDocReady, false);
7062             }
7063             if(Ext.isIE && checkReadyState.bindIE){  //was this was actually set ??
7064                 DOC.detachEvent('onreadystatechange', checkReadyState);
7065             }
7066             E.un(WINDOW, "load", arguments.callee);
7067         }
7068         if(docReadyEvent && !Ext.isReady){
7069             Ext.isReady = true;
7070             docReadyEvent.fire();
7071             docReadyEvent.listeners = [];
7072         }
7073
7074     }
7075
7076     function initDocReady(){
7077         docReadyEvent || (docReadyEvent = new Ext.util.Event());
7078         if (DETECT_NATIVE) {
7079             DOC.addEventListener(DOMCONTENTLOADED, fireDocReady, false);
7080         }
7081         /*
7082          * Handle additional (exceptional) detection strategies here
7083          */
7084         if (Ext.isIE){
7085             //Use readystatechange as a backup AND primary detection mechanism for a FRAME/IFRAME
7086             //See if page is already loaded
7087             if(!checkReadyState()){
7088                 checkReadyState.bindIE = true;
7089                 DOC.attachEvent('onreadystatechange', checkReadyState);
7090             }
7091
7092         }else if(Ext.isOpera ){
7093             /* Notes:
7094                Opera needs special treatment needed here because CSS rules are NOT QUITE
7095                available after DOMContentLoaded is raised.
7096             */
7097
7098             //See if page is already loaded and all styleSheets are in place
7099             (DOC.readyState == COMPLETE && checkStyleSheets()) ||
7100                 DOC.addEventListener(DOMCONTENTLOADED, OperaDOMContentLoaded, false);
7101
7102         }else if (Ext.isWebKit){
7103             //Fallback for older Webkits without DOMCONTENTLOADED support
7104             checkReadyState();
7105         }
7106         // no matter what, make sure it fires on load
7107         E.on(WINDOW, "load", fireDocReady);
7108     }
7109
7110     function createTargeted(h, o){
7111         return function(){
7112             var args = Ext.toArray(arguments);
7113             if(o.target == Ext.EventObject.setEvent(args[0]).target){
7114                 h.apply(this, args);
7115             }
7116         };
7117     }
7118
7119     function createBuffered(h, o, task){
7120         return function(e){
7121             // create new event object impl so new events don't wipe out properties
7122             task.delay(o.buffer, h, null, [new Ext.EventObjectImpl(e)]);
7123         };
7124     }
7125
7126     function createSingle(h, el, ename, fn, scope){
7127         return function(e){
7128             Ext.EventManager.removeListener(el, ename, fn, scope);
7129             h(e);
7130         };
7131     }
7132
7133     function createDelayed(h, o, fn){
7134         return function(e){
7135             var task = new Ext.util.DelayedTask(h);
7136             if(!fn.tasks) {
7137                 fn.tasks = [];
7138             }
7139             fn.tasks.push(task);
7140             task.delay(o.delay || 10, h, null, [new Ext.EventObjectImpl(e)]);
7141         };
7142     }
7143
7144     function listen(element, ename, opt, fn, scope){
7145         var o = (!opt || typeof opt == "boolean") ? {} : opt,
7146             el = Ext.getDom(element), task;
7147
7148         fn = fn || o.fn;
7149         scope = scope || o.scope;
7150
7151         if(!el){
7152             throw "Error listening for \"" + ename + '\". Element "' + element + '" doesn\'t exist.';
7153         }
7154         function h(e){
7155             // prevent errors while unload occurring
7156             if(!Ext){// !window[xname]){  ==> can't we do this?
7157                 return;
7158             }
7159             e = Ext.EventObject.setEvent(e);
7160             var t;
7161             if (o.delegate) {
7162                 if(!(t = e.getTarget(o.delegate, el))){
7163                     return;
7164                 }
7165             } else {
7166                 t = e.target;
7167             }
7168             if (o.stopEvent) {
7169                 e.stopEvent();
7170             }
7171             if (o.preventDefault) {
7172                e.preventDefault();
7173             }
7174             if (o.stopPropagation) {
7175                 e.stopPropagation();
7176             }
7177             if (o.normalized === false) {
7178                 e = e.browserEvent;
7179             }
7180
7181             fn.call(scope || el, e, t, o);
7182         }
7183         if(o.target){
7184             h = createTargeted(h, o);
7185         }
7186         if(o.delay){
7187             h = createDelayed(h, o, fn);
7188         }
7189         if(o.single){
7190             h = createSingle(h, el, ename, fn, scope);
7191         }
7192         if(o.buffer){
7193             task = new Ext.util.DelayedTask(h);
7194             h = createBuffered(h, o, task);
7195         }
7196
7197         addListener(el, ename, fn, task, h, scope);
7198         return h;
7199     }
7200
7201     var pub = {
7202         /**
7203          * Appends an event handler to an element.  The shorthand version {@link #on} is equivalent.  Typically you will
7204          * use {@link Ext.Element#addListener} directly on an Element in favor of calling this version.
7205          * @param {String/HTMLElement} el The html element or id to assign the event handler to.
7206          * @param {String} eventName The name of the event to listen for.
7207          * @param {Function} handler The handler function the event invokes. This function is passed
7208          * the following parameters:<ul>
7209          * <li>evt : EventObject<div class="sub-desc">The {@link Ext.EventObject EventObject} describing the event.</div></li>
7210          * <li>t : Element<div class="sub-desc">The {@link Ext.Element Element} which was the target of the event.
7211          * Note that this may be filtered by using the <tt>delegate</tt> option.</div></li>
7212          * <li>o : Object<div class="sub-desc">The options object from the addListener call.</div></li>
7213          * </ul>
7214          * @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>.
7215          * @param {Object} options (optional) An object containing handler configuration properties.
7216          * This may contain any of the following properties:<ul>
7217          * <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>
7218          * <li>delegate : String<div class="sub-desc">A simple selector to filter the target or look for a descendant of the target</div></li>
7219          * <li>stopEvent : Boolean<div class="sub-desc">True to stop the event. That is stop propagation, and prevent the default action.</div></li>
7220          * <li>preventDefault : Boolean<div class="sub-desc">True to prevent the default action</div></li>
7221          * <li>stopPropagation : Boolean<div class="sub-desc">True to prevent event propagation</div></li>
7222          * <li>normalized : Boolean<div class="sub-desc">False to pass a browser event to the handler function instead of an Ext.EventObject</div></li>
7223          * <li>delay : Number<div class="sub-desc">The number of milliseconds to delay the invocation of the handler after te event fires.</div></li>
7224          * <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>
7225          * <li>buffer : Number<div class="sub-desc">Causes the handler to be scheduled to run in an {@link Ext.util.DelayedTask} delayed
7226          * by the specified number of milliseconds. If the event fires again within that time, the original
7227          * handler is <em>not</em> invoked, but the new handler is scheduled in its place.</div></li>
7228          * <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>
7229          * </ul><br>
7230          * <p>See {@link Ext.Element#addListener} for examples of how to use these options.</p>
7231          */
7232         addListener : function(element, eventName, fn, scope, options){
7233             if(typeof eventName == 'object'){
7234                 var o = eventName, e, val;
7235                 for(e in o){
7236                     val = o[e];
7237                     if(!propRe.test(e)){
7238                         if(Ext.isFunction(val)){
7239                             // shared options
7240                             listen(element, e, o, val, o.scope);
7241                         }else{
7242                             // individual options
7243                             listen(element, e, val);
7244                         }
7245                     }
7246                 }
7247             } else {
7248                 listen(element, eventName, options, fn, scope);
7249             }
7250         },
7251
7252         /**
7253          * Removes an event handler from an element.  The shorthand version {@link #un} is equivalent.  Typically
7254          * you will use {@link Ext.Element#removeListener} directly on an Element in favor of calling this version.
7255          * @param {String/HTMLElement} el The id or html element from which to remove the listener.
7256          * @param {String} eventName The name of the event.
7257          * @param {Function} fn The handler function to remove. <b>This must be a reference to the function passed into the {@link #addListener} call.</b>
7258          * @param {Object} scope If a scope (<b><code>this</code></b> reference) was specified when the listener was added,
7259          * then this must refer to the same object.
7260          */
7261         removeListener : function(el, eventName, fn, scope){
7262             el = Ext.getDom(el);
7263             var id = getId(el),
7264                 f = el && (Ext.elCache[id].events)[eventName] || [],
7265                 wrap, i, l, k, len, fnc;
7266
7267             for (i = 0, len = f.length; i < len; i++) {
7268
7269                 /* 0 = Original Function,
7270                    1 = Event Manager Wrapped Function,
7271                    2 = Scope,
7272                    3 = Adapter Wrapped Function,
7273                    4 = Buffered Task
7274                 */
7275                 if (Ext.isArray(fnc = f[i]) && fnc[0] == fn && (!scope || fnc[2] == scope)) {
7276                     if(fnc[4]) {
7277                         fnc[4].cancel();
7278                     }
7279                     k = fn.tasks && fn.tasks.length;
7280                     if(k) {
7281                         while(k--) {
7282                             fn.tasks[k].cancel();
7283                         }
7284                         delete fn.tasks;
7285                     }
7286                     wrap = fnc[1];
7287                     E.un(el, eventName, E.extAdapter ? fnc[3] : wrap);
7288
7289                     // jQuery workaround that should be removed from Ext Core
7290                     if(wrap && el.addEventListener && eventName == "mousewheel"){
7291                         el.removeEventListener("DOMMouseScroll", wrap, false);
7292                     }
7293
7294                     // fix stopped mousedowns on the document
7295                     if(wrap && el == DOC && eventName == "mousedown"){
7296                         Ext.EventManager.stoppedMouseDownEvent.removeListener(wrap);
7297                     }
7298
7299                     f.splice(i, 1);
7300                     if (f.length === 0) {
7301                         delete Ext.elCache[id].events[eventName];
7302                     }
7303                     for (k in Ext.elCache[id].events) {
7304                         return false;
7305                     }
7306                     Ext.elCache[id].events = {};
7307                     return false;
7308                 }
7309             }
7310         },
7311
7312         /**
7313          * Removes all event handers from an element.  Typically you will use {@link Ext.Element#removeAllListeners}
7314          * directly on an Element in favor of calling this version.
7315          * @param {String/HTMLElement} el The id or html element from which to remove all event handlers.
7316          */
7317         removeAll : function(el){
7318             el = Ext.getDom(el);
7319             var id = getId(el),
7320                 ec = Ext.elCache[id] || {},
7321                 es = ec.events || {},
7322                 f, i, len, ename, fn, k, wrap;
7323
7324             for(ename in es){
7325                 if(es.hasOwnProperty(ename)){
7326                     f = es[ename];
7327                     /* 0 = Original Function,
7328                        1 = Event Manager Wrapped Function,
7329                        2 = Scope,
7330                        3 = Adapter Wrapped Function,
7331                        4 = Buffered Task
7332                     */
7333                     for (i = 0, len = f.length; i < len; i++) {
7334                         fn = f[i];
7335                         if(fn[4]) {
7336                             fn[4].cancel();
7337                         }
7338                         if(fn[0].tasks && (k = fn[0].tasks.length)) {
7339                             while(k--) {
7340                                 fn[0].tasks[k].cancel();
7341                             }
7342                             delete fn.tasks;
7343                         }
7344                         wrap =  fn[1];
7345                         E.un(el, ename, E.extAdapter ? fn[3] : wrap);
7346
7347                         // jQuery workaround that should be removed from Ext Core
7348                         if(el.addEventListener && wrap && ename == "mousewheel"){
7349                             el.removeEventListener("DOMMouseScroll", wrap, false);
7350                         }
7351
7352                         // fix stopped mousedowns on the document
7353                         if(wrap && el == DOC &&  ename == "mousedown"){
7354                             Ext.EventManager.stoppedMouseDownEvent.removeListener(wrap);
7355                         }
7356                     }
7357                 }
7358             }
7359             if (Ext.elCache[id]) {
7360                 Ext.elCache[id].events = {};
7361             }
7362         },
7363
7364         getListeners : function(el, eventName) {
7365             el = Ext.getDom(el);
7366             var id = getId(el),
7367                 ec = Ext.elCache[id] || {},
7368                 es = ec.events || {},
7369                 results = [];
7370             if (es && es[eventName]) {
7371                 return es[eventName];
7372             } else {
7373                 return null;
7374             }
7375         },
7376
7377         purgeElement : function(el, recurse, eventName) {
7378             el = Ext.getDom(el);
7379             var id = getId(el),
7380                 ec = Ext.elCache[id] || {},
7381                 es = ec.events || {},
7382                 i, f, len;
7383             if (eventName) {
7384                 if (es && es.hasOwnProperty(eventName)) {
7385                     f = es[eventName];
7386                     for (i = 0, len = f.length; i < len; i++) {
7387                         Ext.EventManager.removeListener(el, eventName, f[i][0]);
7388                     }
7389                 }
7390             } else {
7391                 Ext.EventManager.removeAll(el);
7392             }
7393             if (recurse && el && el.childNodes) {
7394                 for (i = 0, len = el.childNodes.length; i < len; i++) {
7395                     Ext.EventManager.purgeElement(el.childNodes[i], recurse, eventName);
7396                 }
7397             }
7398         },
7399
7400         _unload : function() {
7401             var el;
7402             for (el in Ext.elCache) {
7403                 Ext.EventManager.removeAll(el);
7404             }
7405             delete Ext.elCache;
7406             delete Ext.Element._flyweights;
7407
7408             // Abort any outstanding Ajax requests
7409             var c,
7410                 conn,
7411                 tid,
7412                 ajax = Ext.lib.Ajax;
7413             (typeof ajax.conn == 'object') ? conn = ajax.conn : conn = {};
7414             for (tid in conn) {
7415                 c = conn[tid];
7416                 if (c) {
7417                     ajax.abort({conn: c, tId: tid});
7418                 }
7419             }
7420         },
7421         /**
7422          * Adds a listener to be notified when the document is ready (before onload and before images are loaded). Can be
7423          * accessed shorthanded as Ext.onReady().
7424          * @param {Function} fn The method the event invokes.
7425          * @param {Object} scope (optional) The scope (<code>this</code> reference) in which the handler function executes. Defaults to the browser window.
7426          * @param {boolean} options (optional) Options object as passed to {@link Ext.Element#addListener}. It is recommended that the options
7427          * <code>{single: true}</code> be used so that the handler is removed on first invocation.
7428          */
7429         onDocumentReady : function(fn, scope, options){
7430             if (Ext.isReady) { // if it already fired or document.body is present
7431                 docReadyEvent || (docReadyEvent = new Ext.util.Event());
7432                 docReadyEvent.addListener(fn, scope, options);
7433                 docReadyEvent.fire();
7434                 docReadyEvent.listeners = [];
7435             } else {
7436                 if (!docReadyEvent) {
7437                     initDocReady();
7438                 }
7439                 options = options || {};
7440                 options.delay = options.delay || 1;
7441                 docReadyEvent.addListener(fn, scope, options);
7442             }
7443         },
7444
7445         /**
7446          * Forces a document ready state transition for the framework.  Used when Ext is loaded
7447          * into a DOM structure AFTER initial page load (Google API or other dynamic load scenario.
7448          * Any pending 'onDocumentReady' handlers will be fired (if not already handled).
7449          */
7450         fireDocReady  : fireDocReady
7451     };
7452      /**
7453      * Appends an event handler to an element.  Shorthand for {@link #addListener}.
7454      * @param {String/HTMLElement} el The html element or id to assign the event handler to
7455      * @param {String} eventName The name of the event to listen for.
7456      * @param {Function} handler The handler function the event invokes.
7457      * @param {Object} scope (optional) (<code>this</code> reference) in which the handler function executes. <b>Defaults to the Element</b>.
7458      * @param {Object} options (optional) An object containing standard {@link #addListener} options
7459      * @member Ext.EventManager
7460      * @method on
7461      */
7462     pub.on = pub.addListener;
7463     /**
7464      * Removes an event handler from an element.  Shorthand for {@link #removeListener}.
7465      * @param {String/HTMLElement} el The id or html element from which to remove the listener.
7466      * @param {String} eventName The name of the event.
7467      * @param {Function} fn The handler function to remove. <b>This must be a reference to the function passed into the {@link #on} call.</b>
7468      * @param {Object} scope If a scope (<b><code>this</code></b> reference) was specified when the listener was added,
7469      * then this must refer to the same object.
7470      * @member Ext.EventManager
7471      * @method un
7472      */
7473     pub.un = pub.removeListener;
7474
7475     pub.stoppedMouseDownEvent = new Ext.util.Event();
7476     return pub;
7477 }();
7478 /**
7479   * Adds a listener to be notified when the document is ready (before onload and before images are loaded). Shorthand of {@link Ext.EventManager#onDocumentReady}.
7480   * @param {Function} fn The method the event invokes.
7481   * @param {Object} scope (optional) The scope (<code>this</code> reference) in which the handler function executes. Defaults to the browser window.
7482   * @param {boolean} options (optional) Options object as passed to {@link Ext.Element#addListener}. It is recommended that the options
7483   * <code>{single: true}</code> be used so that the handler is removed on first invocation.
7484   * @member Ext
7485   * @method onReady
7486  */
7487 Ext.onReady = Ext.EventManager.onDocumentReady;
7488
7489
7490 //Initialize doc classes
7491 (function(){
7492     var initExtCss = function() {
7493         // find the body element
7494         var bd = document.body || document.getElementsByTagName('body')[0];
7495         if (!bd) {
7496             return false;
7497         }
7498         
7499         var cls = [' ',
7500                 Ext.isIE ? "ext-ie " + (Ext.isIE6 ? 'ext-ie6' : (Ext.isIE7 ? 'ext-ie7' : 'ext-ie8'))
7501                 : Ext.isGecko ? "ext-gecko " + (Ext.isGecko2 ? 'ext-gecko2' : 'ext-gecko3')
7502                 : Ext.isOpera ? "ext-opera"
7503                 : Ext.isWebKit ? "ext-webkit" : ""];
7504
7505         if (Ext.isSafari) {
7506             cls.push("ext-safari " + (Ext.isSafari2 ? 'ext-safari2' : (Ext.isSafari3 ? 'ext-safari3' : 'ext-safari4')));
7507         } else if(Ext.isChrome) {
7508             cls.push("ext-chrome");
7509         }
7510
7511         if (Ext.isMac) {
7512             cls.push("ext-mac");
7513         }
7514         if (Ext.isLinux) {
7515             cls.push("ext-linux");
7516         }
7517
7518         // add to the parent to allow for selectors like ".ext-strict .ext-ie"
7519         if (Ext.isStrict || Ext.isBorderBox) {
7520             var p = bd.parentNode;
7521             if (p) {
7522                 Ext.fly(p, '_internal').addClass(((Ext.isStrict && Ext.isIE ) || (!Ext.enableForcedBoxModel && !Ext.isIE)) ? ' ext-strict' : ' ext-border-box');
7523             }
7524         }
7525         // Forced border box model class applied to all elements. Bypassing javascript based box model adjustments
7526         // in favor of css.  This is for non-IE browsers.
7527         if (Ext.enableForcedBoxModel && !Ext.isIE) {
7528             Ext.isForcedBorderBox = true;
7529             cls.push("ext-forced-border-box");
7530         }
7531         
7532         Ext.fly(bd, '_internal').addClass(cls);
7533         return true;
7534     };
7535     
7536     if (!initExtCss()) {
7537         Ext.onReady(initExtCss);
7538     }
7539 })();
7540
7541 /**
7542  * Code used to detect certain browser feature/quirks/bugs at startup.
7543  */
7544 (function(){
7545     var supports = Ext.apply(Ext.supports, {
7546         /**
7547          * In Webkit, there is an issue with getting the margin right property, see
7548          * https://bugs.webkit.org/show_bug.cgi?id=13343
7549          */
7550         correctRightMargin: true,
7551         
7552         /**
7553          * Webkit browsers return rgba(0, 0, 0) when a transparent color is used
7554          */
7555         correctTransparentColor: true,
7556         
7557         /**
7558          * IE uses styleFloat, not cssFloat for the float property.
7559          */
7560         cssFloat: true
7561     });
7562     
7563     var supportTests = function(){
7564             var div = document.createElement('div'),
7565                 doc = document,
7566                 view,
7567                 last;
7568                 
7569             div.innerHTML = '<div style="height:30px;width:50px;"><div style="height:20px;width:20px;"></div></div><div style="float:left;background-color:transparent;">';
7570             doc.body.appendChild(div);
7571             last = div.lastChild;
7572             
7573             if((view = doc.defaultView)){
7574                 if(view.getComputedStyle(div.firstChild.firstChild, null).marginRight != '0px'){
7575                     supports.correctRightMargin = false;
7576                 }
7577                 if(view.getComputedStyle(last, null).backgroundColor != 'transparent'){
7578                     supports.correctTransparentColor = false;
7579                 }
7580             }
7581             supports.cssFloat = !!last.style.cssFloat;
7582             doc.body.removeChild(div);
7583     };
7584     
7585     if (Ext.isReady) {
7586         supportTests();    
7587     } else {
7588         Ext.onReady(supportTests);
7589     }
7590 })();
7591
7592
7593 /**
7594  * @class Ext.EventObject
7595  * Just as {@link Ext.Element} wraps around a native DOM node, Ext.EventObject
7596  * wraps the browser's native event-object normalizing cross-browser differences,
7597  * such as which mouse button is clicked, keys pressed, mechanisms to stop
7598  * event-propagation along with a method to prevent default actions from taking place.
7599  * <p>For example:</p>
7600  * <pre><code>
7601 function handleClick(e, t){ // e is not a standard event object, it is a Ext.EventObject
7602     e.preventDefault();
7603     var target = e.getTarget(); // same as t (the target HTMLElement)
7604     ...
7605 }
7606 var myDiv = {@link Ext#get Ext.get}("myDiv");  // get reference to an {@link Ext.Element}
7607 myDiv.on(         // 'on' is shorthand for addListener
7608     "click",      // perform an action on click of myDiv
7609     handleClick   // reference to the action handler
7610 );
7611 // other methods to do the same:
7612 Ext.EventManager.on("myDiv", 'click', handleClick);
7613 Ext.EventManager.addListener("myDiv", 'click', handleClick);
7614  </code></pre>
7615  * @singleton
7616  */
7617 Ext.EventObject = function(){
7618     var E = Ext.lib.Event,
7619         clickRe = /(dbl)?click/,
7620         // safari keypress events for special keys return bad keycodes
7621         safariKeys = {
7622             3 : 13, // enter
7623             63234 : 37, // left
7624             63235 : 39, // right
7625             63232 : 38, // up
7626             63233 : 40, // down
7627             63276 : 33, // page up
7628             63277 : 34, // page down
7629             63272 : 46, // delete
7630             63273 : 36, // home
7631             63275 : 35  // end
7632         },
7633         // normalize button clicks
7634         btnMap = Ext.isIE ? {1:0,4:1,2:2} : {0:0,1:1,2:2};
7635
7636     Ext.EventObjectImpl = function(e){
7637         if(e){
7638             this.setEvent(e.browserEvent || e);
7639         }
7640     };
7641
7642     Ext.EventObjectImpl.prototype = {
7643            /** @private */
7644         setEvent : function(e){
7645             var me = this;
7646             if(e == me || (e && e.browserEvent)){ // already wrapped
7647                 return e;
7648             }
7649             me.browserEvent = e;
7650             if(e){
7651                 // normalize buttons
7652                 me.button = e.button ? btnMap[e.button] : (e.which ? e.which - 1 : -1);
7653                 if(clickRe.test(e.type) && me.button == -1){
7654                     me.button = 0;
7655                 }
7656                 me.type = e.type;
7657                 me.shiftKey = e.shiftKey;
7658                 // mac metaKey behaves like ctrlKey
7659                 me.ctrlKey = e.ctrlKey || e.metaKey || false;
7660                 me.altKey = e.altKey;
7661                 // in getKey these will be normalized for the mac
7662                 me.keyCode = e.keyCode;
7663                 me.charCode = e.charCode;
7664                 // cache the target for the delayed and or buffered events
7665                 me.target = E.getTarget(e);
7666                 // same for XY
7667                 me.xy = E.getXY(e);
7668             }else{
7669                 me.button = -1;
7670                 me.shiftKey = false;
7671                 me.ctrlKey = false;
7672                 me.altKey = false;
7673                 me.keyCode = 0;
7674                 me.charCode = 0;
7675                 me.target = null;
7676                 me.xy = [0, 0];
7677             }
7678             return me;
7679         },
7680
7681         /**
7682          * Stop the event (preventDefault and stopPropagation)
7683          */
7684         stopEvent : function(){
7685             var me = this;
7686             if(me.browserEvent){
7687                 if(me.browserEvent.type == 'mousedown'){
7688                     Ext.EventManager.stoppedMouseDownEvent.fire(me);
7689                 }
7690                 E.stopEvent(me.browserEvent);
7691             }
7692         },
7693
7694         /**
7695          * Prevents the browsers default handling of the event.
7696          */
7697         preventDefault : function(){
7698             if(this.browserEvent){
7699                 E.preventDefault(this.browserEvent);
7700             }
7701         },
7702
7703         /**
7704          * Cancels bubbling of the event.
7705          */
7706         stopPropagation : function(){
7707             var me = this;
7708             if(me.browserEvent){
7709                 if(me.browserEvent.type == 'mousedown'){
7710                     Ext.EventManager.stoppedMouseDownEvent.fire(me);
7711                 }
7712                 E.stopPropagation(me.browserEvent);
7713             }
7714         },
7715
7716         /**
7717          * Gets the character code for the event.
7718          * @return {Number}
7719          */
7720         getCharCode : function(){
7721             return this.charCode || this.keyCode;
7722         },
7723
7724         /**
7725          * Returns a normalized keyCode for the event.
7726          * @return {Number} The key code
7727          */
7728         getKey : function(){
7729             return this.normalizeKey(this.keyCode || this.charCode);
7730         },
7731
7732         // private
7733         normalizeKey: function(k){
7734             return Ext.isSafari ? (safariKeys[k] || k) : k;
7735         },
7736
7737         /**
7738          * Gets the x coordinate of the event.
7739          * @return {Number}
7740          */
7741         getPageX : function(){
7742             return this.xy[0];
7743         },
7744
7745         /**
7746          * Gets the y coordinate of the event.
7747          * @return {Number}
7748          */
7749         getPageY : function(){
7750             return this.xy[1];
7751         },
7752
7753         /**
7754          * Gets the page coordinates of the event.
7755          * @return {Array} The xy values like [x, y]
7756          */
7757         getXY : function(){
7758             return this.xy;
7759         },
7760
7761         /**
7762          * Gets the target for the event.
7763          * @param {String} selector (optional) A simple selector to filter the target or look for an ancestor of the target
7764          * @param {Number/Mixed} maxDepth (optional) The max depth to
7765                 search as a number or element (defaults to 10 || document.body)
7766          * @param {Boolean} returnEl (optional) True to return a Ext.Element object instead of DOM node
7767          * @return {HTMLelement}
7768          */
7769         getTarget : function(selector, maxDepth, returnEl){
7770             return selector ? Ext.fly(this.target).findParent(selector, maxDepth, returnEl) : (returnEl ? Ext.get(this.target) : this.target);
7771         },
7772
7773         /**
7774          * Gets the related target.
7775          * @return {HTMLElement}
7776          */
7777         getRelatedTarget : function(){
7778             return this.browserEvent ? E.getRelatedTarget(this.browserEvent) : null;
7779         },
7780
7781         /**
7782          * Normalizes mouse wheel delta across browsers
7783          * @return {Number} The delta
7784          */
7785         getWheelDelta : function(){
7786             var e = this.browserEvent;
7787             var delta = 0;
7788             if(e.wheelDelta){ /* IE/Opera. */
7789                 delta = e.wheelDelta/120;
7790             }else if(e.detail){ /* Mozilla case. */
7791                 delta = -e.detail/3;
7792             }
7793             return delta;
7794         },
7795
7796         /**
7797         * 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.
7798         * Example usage:<pre><code>
7799         // Handle click on any child of an element
7800         Ext.getBody().on('click', function(e){
7801             if(e.within('some-el')){
7802                 alert('Clicked on a child of some-el!');
7803             }
7804         });
7805
7806         // Handle click directly on an element, ignoring clicks on child nodes
7807         Ext.getBody().on('click', function(e,t){
7808             if((t.id == 'some-el') && !e.within(t, true)){
7809                 alert('Clicked directly on some-el!');
7810             }
7811         });
7812         </code></pre>
7813          * @param {Mixed} el The id, DOM element or Ext.Element to check
7814          * @param {Boolean} related (optional) true to test if the related target is within el instead of the target
7815          * @param {Boolean} allowEl {optional} true to also check if the passed element is the target or related target
7816          * @return {Boolean}
7817          */
7818         within : function(el, related, allowEl){
7819             if(el){
7820                 var t = this[related ? "getRelatedTarget" : "getTarget"]();
7821                 return t && ((allowEl ? (t == Ext.getDom(el)) : false) || Ext.fly(el).contains(t));
7822             }
7823             return false;
7824         }
7825      };
7826
7827     return new Ext.EventObjectImpl();
7828 }();
7829 /**
7830  * @class Ext.Loader
7831  * @singleton
7832  * Simple class to help load JavaScript files on demand
7833  */
7834 Ext.Loader = Ext.apply({}, {
7835     /**
7836      * Loads a given set of .js files. Calls the callback function when all files have been loaded
7837      * Set preserveOrder to true to ensure non-parallel loading of files if load order is important
7838      * @param {Array} fileList Array of all files to load
7839      * @param {Function} callback Callback to call after all files have been loaded
7840      * @param {Object} scope The scope to call the callback in
7841      * @param {Boolean} preserveOrder True to make files load in serial, one after the other (defaults to false)
7842      */
7843     load: function(fileList, callback, scope, preserveOrder) {
7844         var scope       = scope || this,
7845             head        = document.getElementsByTagName("head")[0],
7846             fragment    = document.createDocumentFragment(),
7847             numFiles    = fileList.length,
7848             loadedFiles = 0,
7849             me          = this;
7850         
7851         /**
7852          * Loads a particular file from the fileList by index. This is used when preserving order
7853          */
7854         var loadFileIndex = function(index) {
7855             head.appendChild(
7856                 me.buildScriptTag(fileList[index], onFileLoaded)
7857             );
7858         };
7859         
7860         /**
7861          * Callback function which is called after each file has been loaded. This calls the callback
7862          * passed to load once the final file in the fileList has been loaded
7863          */
7864         var onFileLoaded = function() {
7865             loadedFiles ++;
7866             
7867             //if this was the last file, call the callback, otherwise load the next file
7868             if (numFiles == loadedFiles && typeof callback == 'function') {
7869                 callback.call(scope);
7870             } else {
7871                 if (preserveOrder === true) {
7872                     loadFileIndex(loadedFiles);
7873                 }
7874             }
7875         };
7876         
7877         if (preserveOrder === true) {
7878             loadFileIndex.call(this, 0);
7879         } else {
7880             //load each file (most browsers will do this in parallel)
7881             Ext.each(fileList, function(file, index) {
7882                 fragment.appendChild(
7883                     this.buildScriptTag(file, onFileLoaded)
7884                 );  
7885             }, this);
7886             
7887             head.appendChild(fragment);
7888         }
7889     },
7890     
7891     /**
7892      * @private
7893      * Creates and returns a script tag, but does not place it into the document. If a callback function
7894      * is passed, this is called when the script has been loaded
7895      * @param {String} filename The name of the file to create a script tag for
7896      * @param {Function} callback Optional callback, which is called when the script has been loaded
7897      * @return {Element} The new script ta
7898      */
7899     buildScriptTag: function(filename, callback) {
7900         var script  = document.createElement('script');
7901         script.type = "text/javascript";
7902         script.src  = filename;
7903         
7904         //IE has a different way of handling &lt;script&gt; loads, so we need to check for it here
7905         if (script.readyState) {
7906             script.onreadystatechange = function() {
7907                 if (script.readyState == "loaded" || script.readyState == "complete") {
7908                     script.onreadystatechange = null;
7909                     callback();
7910                 }
7911             };
7912         } else {
7913             script.onload = callback;
7914         }    
7915         
7916         return script;
7917     }
7918 });