Upgrade to ExtJS 4.0.7 - Released 10/19/2011
[extjs.git] / ext-dev.js
1 /*
2
3 This file is part of Ext JS 4
4
5 Copyright (c) 2011 Sencha Inc
6
7 Contact:  http://www.sencha.com/contact
8
9 GNU General Public License Usage
10 This file may be used under the terms of the GNU General Public License version 3.0 as published by the Free Software Foundation and appearing in the file LICENSE included in the packaging of this file.  Please review the following information to ensure the GNU General Public License version 3.0 requirements will be met: http://www.gnu.org/copyleft/gpl.html.
11
12 If you are unsure which license is appropriate for your use, please contact the sales department at http://www.sencha.com/contact.
13
14 */
15 /**
16  * @class Ext
17  * @singleton
18  */
19 (function() {
20     var global = this,
21         objectPrototype = Object.prototype,
22         toString = objectPrototype.toString,
23         enumerables = true,
24         enumerablesTest = { toString: 1 },
25         i;
26
27     if (typeof Ext === 'undefined') {
28         global.Ext = {};
29     }
30
31     Ext.global = global;
32
33     for (i in enumerablesTest) {
34         enumerables = null;
35     }
36
37     if (enumerables) {
38         enumerables = ['hasOwnProperty', 'valueOf', 'isPrototypeOf', 'propertyIsEnumerable',
39                        'toLocaleString', 'toString', 'constructor'];
40     }
41
42     /**
43      * An array containing extra enumerables for old browsers
44      * @property {String[]}
45      */
46     Ext.enumerables = enumerables;
47
48     /**
49      * Copies all the properties of config to the specified object.
50      * Note that if recursive merging and cloning without referencing the original objects / arrays is needed, use
51      * {@link Ext.Object#merge} instead.
52      * @param {Object} object The receiver of the properties
53      * @param {Object} config The source of the properties
54      * @param {Object} defaults A different object that will also be applied for default values
55      * @return {Object} returns obj
56      */
57     Ext.apply = function(object, config, defaults) {
58         if (defaults) {
59             Ext.apply(object, defaults);
60         }
61
62         if (object && config && typeof config === 'object') {
63             var i, j, k;
64
65             for (i in config) {
66                 object[i] = config[i];
67             }
68
69             if (enumerables) {
70                 for (j = enumerables.length; j--;) {
71                     k = enumerables[j];
72                     if (config.hasOwnProperty(k)) {
73                         object[k] = config[k];
74                     }
75                 }
76             }
77         }
78
79         return object;
80     };
81
82     Ext.buildSettings = Ext.apply({
83         baseCSSPrefix: 'x-',
84         scopeResetCSS: false
85     }, Ext.buildSettings || {});
86
87     Ext.apply(Ext, {
88         /**
89          * A reusable empty function
90          */
91         emptyFn: function() {},
92
93         baseCSSPrefix: Ext.buildSettings.baseCSSPrefix,
94
95         /**
96          * Copies all the properties of config to object if they don't already exist.
97          * @param {Object} object The receiver of the properties
98          * @param {Object} config The source of the properties
99          * @return {Object} returns obj
100          */
101         applyIf: function(object, config) {
102             var property;
103
104             if (object) {
105                 for (property in config) {
106                     if (object[property] === undefined) {
107                         object[property] = config[property];
108                     }
109                 }
110             }
111
112             return object;
113         },
114
115         /**
116          * Iterates either an array or an object. This method delegates to
117          * {@link Ext.Array#each Ext.Array.each} if the given value is iterable, and {@link Ext.Object#each Ext.Object.each} otherwise.
118          *
119          * @param {Object/Array} object The object or array to be iterated.
120          * @param {Function} fn The function to be called for each iteration. See and {@link Ext.Array#each Ext.Array.each} and
121          * {@link Ext.Object#each Ext.Object.each} for detailed lists of arguments passed to this function depending on the given object
122          * type that is being iterated.
123          * @param {Object} scope (Optional) The scope (`this` reference) in which the specified function is executed.
124          * Defaults to the object being iterated itself.
125          * @markdown
126          */
127         iterate: function(object, fn, scope) {
128             if (Ext.isEmpty(object)) {
129                 return;
130             }
131
132             if (scope === undefined) {
133                 scope = object;
134             }
135
136             if (Ext.isIterable(object)) {
137                 Ext.Array.each.call(Ext.Array, object, fn, scope);
138             }
139             else {
140                 Ext.Object.each.call(Ext.Object, object, fn, scope);
141             }
142         }
143     });
144
145     Ext.apply(Ext, {
146
147         /**
148          * This method deprecated. Use {@link Ext#define Ext.define} instead.
149          * @method
150          * @param {Function} superclass
151          * @param {Object} overrides
152          * @return {Function} The subclass constructor from the <tt>overrides</tt> parameter, or a generated one if not provided.
153          * @deprecated 4.0.0 Use {@link Ext#define Ext.define} instead
154          */
155         extend: function() {
156             // inline overrides
157             var objectConstructor = objectPrototype.constructor,
158                 inlineOverrides = function(o) {
159                 for (var m in o) {
160                     if (!o.hasOwnProperty(m)) {
161                         continue;
162                     }
163                     this[m] = o[m];
164                 }
165             };
166
167             return function(subclass, superclass, overrides) {
168                 // First we check if the user passed in just the superClass with overrides
169                 if (Ext.isObject(superclass)) {
170                     overrides = superclass;
171                     superclass = subclass;
172                     subclass = overrides.constructor !== objectConstructor ? overrides.constructor : function() {
173                         superclass.apply(this, arguments);
174                     };
175                 }
176
177                 if (!superclass) {
178                     Ext.Error.raise({
179                         sourceClass: 'Ext',
180                         sourceMethod: 'extend',
181                         msg: 'Attempting to extend from a class which has not been loaded on the page.'
182                     });
183                 }
184
185                 // We create a new temporary class
186                 var F = function() {},
187                     subclassProto, superclassProto = superclass.prototype;
188
189                 F.prototype = superclassProto;
190                 subclassProto = subclass.prototype = new F();
191                 subclassProto.constructor = subclass;
192                 subclass.superclass = superclassProto;
193
194                 if (superclassProto.constructor === objectConstructor) {
195                     superclassProto.constructor = superclass;
196                 }
197
198                 subclass.override = function(overrides) {
199                     Ext.override(subclass, overrides);
200                 };
201
202                 subclassProto.override = inlineOverrides;
203                 subclassProto.proto = subclassProto;
204
205                 subclass.override(overrides);
206                 subclass.extend = function(o) {
207                     return Ext.extend(subclass, o);
208                 };
209
210                 return subclass;
211             };
212         }(),
213
214         /**
215          * Proxy to {@link Ext.Base#override}. Please refer {@link Ext.Base#override} for further details.
216
217     Ext.define('My.cool.Class', {
218         sayHi: function() {
219             alert('Hi!');
220         }
221     }
222
223     Ext.override(My.cool.Class, {
224         sayHi: function() {
225             alert('About to say...');
226
227             this.callOverridden();
228         }
229     });
230
231     var cool = new My.cool.Class();
232     cool.sayHi(); // alerts 'About to say...'
233                   // alerts 'Hi!'
234
235          * Please note that `this.callOverridden()` only works if the class was previously
236          * created with {@link Ext#define)
237          *
238          * @param {Object} cls The class to override
239          * @param {Object} overrides The list of functions to add to origClass. This should be specified as an object literal
240          * containing one or more methods.
241          * @method override
242          * @markdown
243          */
244         override: function(cls, overrides) {
245             if (cls.prototype.$className) {
246                 return cls.override(overrides);
247             }
248             else {
249                 Ext.apply(cls.prototype, overrides);
250             }
251         }
252     });
253
254     // A full set of static methods to do type checking
255     Ext.apply(Ext, {
256
257         /**
258          * Returns the given value itself if it's not empty, as described in {@link Ext#isEmpty}; returns the default
259          * value (second argument) otherwise.
260          *
261          * @param {Object} value The value to test
262          * @param {Object} defaultValue The value to return if the original value is empty
263          * @param {Boolean} allowBlank (optional) true to allow zero length strings to qualify as non-empty (defaults to false)
264          * @return {Object} value, if non-empty, else defaultValue
265          */
266         valueFrom: function(value, defaultValue, allowBlank){
267             return Ext.isEmpty(value, allowBlank) ? defaultValue : value;
268         },
269
270         /**
271          * Returns the type of the given variable in string format. List of possible values are:
272          *
273          * - `undefined`: If the given value is `undefined`
274          * - `null`: If the given value is `null`
275          * - `string`: If the given value is a string
276          * - `number`: If the given value is a number
277          * - `boolean`: If the given value is a boolean value
278          * - `date`: If the given value is a `Date` object
279          * - `function`: If the given value is a function reference
280          * - `object`: If the given value is an object
281          * - `array`: If the given value is an array
282          * - `regexp`: If the given value is a regular expression
283          * - `element`: If the given value is a DOM Element
284          * - `textnode`: If the given value is a DOM text node and contains something other than whitespace
285          * - `whitespace`: If the given value is a DOM text node and contains only whitespace
286          *
287          * @param {Object} value
288          * @return {String}
289          * @markdown
290          */
291         typeOf: function(value) {
292             if (value === null) {
293                 return 'null';
294             }
295
296             var type = typeof value;
297
298             if (type === 'undefined' || type === 'string' || type === 'number' || type === 'boolean') {
299                 return type;
300             }
301
302             var typeToString = toString.call(value);
303
304             switch(typeToString) {
305                 case '[object Array]':
306                     return 'array';
307                 case '[object Date]':
308                     return 'date';
309                 case '[object Boolean]':
310                     return 'boolean';
311                 case '[object Number]':
312                     return 'number';
313                 case '[object RegExp]':
314                     return 'regexp';
315             }
316
317             if (type === 'function') {
318                 return 'function';
319             }
320
321             if (type === 'object') {
322                 if (value.nodeType !== undefined) {
323                     if (value.nodeType === 3) {
324                         return (/\S/).test(value.nodeValue) ? 'textnode' : 'whitespace';
325                     }
326                     else {
327                         return 'element';
328                     }
329                 }
330
331                 return 'object';
332             }
333
334             Ext.Error.raise({
335                 sourceClass: 'Ext',
336                 sourceMethod: 'typeOf',
337                 msg: 'Failed to determine the type of the specified value "' + value + '". This is most likely a bug.'
338             });
339         },
340
341         /**
342          * Returns true if the passed value is empty, false otherwise. The value is deemed to be empty if it is either:
343          *
344          * - `null`
345          * - `undefined`
346          * - a zero-length array
347          * - a zero-length string (Unless the `allowEmptyString` parameter is set to `true`)
348          *
349          * @param {Object} value The value to test
350          * @param {Boolean} allowEmptyString (optional) true to allow empty strings (defaults to false)
351          * @return {Boolean}
352          * @markdown
353          */
354         isEmpty: function(value, allowEmptyString) {
355             return (value === null) || (value === undefined) || (!allowEmptyString ? value === '' : false) || (Ext.isArray(value) && value.length === 0);
356         },
357
358         /**
359          * Returns true if the passed value is a JavaScript Array, false otherwise.
360          *
361          * @param {Object} target The target to test
362          * @return {Boolean}
363          * @method
364          */
365         isArray: ('isArray' in Array) ? Array.isArray : function(value) {
366             return toString.call(value) === '[object Array]';
367         },
368
369         /**
370          * Returns true if the passed value is a JavaScript Date object, false otherwise.
371          * @param {Object} object The object to test
372          * @return {Boolean}
373          */
374         isDate: function(value) {
375             return toString.call(value) === '[object Date]';
376         },
377
378         /**
379          * Returns true if the passed value is a JavaScript Object, false otherwise.
380          * @param {Object} value The value to test
381          * @return {Boolean}
382          * @method
383          */
384         isObject: (toString.call(null) === '[object Object]') ?
385         function(value) {
386             // check ownerDocument here as well to exclude DOM nodes
387             return value !== null && value !== undefined && toString.call(value) === '[object Object]' && value.ownerDocument === undefined;
388         } :
389         function(value) {
390             return toString.call(value) === '[object Object]';
391         },
392
393         /**
394          * Returns true if the passed value is a JavaScript 'primitive', a string, number or boolean.
395          * @param {Object} value The value to test
396          * @return {Boolean}
397          */
398         isPrimitive: function(value) {
399             var type = typeof value;
400
401             return type === 'string' || type === 'number' || type === 'boolean';
402         },
403
404         /**
405          * Returns true if the passed value is a JavaScript Function, false otherwise.
406          * @param {Object} value The value to test
407          * @return {Boolean}
408          * @method
409          */
410         isFunction:
411         // Safari 3.x and 4.x returns 'function' for typeof <NodeList>, hence we need to fall back to using
412         // Object.prorotype.toString (slower)
413         (typeof document !== 'undefined' && typeof document.getElementsByTagName('body') === 'function') ? function(value) {
414             return toString.call(value) === '[object Function]';
415         } : function(value) {
416             return typeof value === 'function';
417         },
418
419         /**
420          * Returns true if the passed value is a number. Returns false for non-finite numbers.
421          * @param {Object} value The value to test
422          * @return {Boolean}
423          */
424         isNumber: function(value) {
425             return typeof value === 'number' && isFinite(value);
426         },
427
428         /**
429          * Validates that a value is numeric.
430          * @param {Object} value Examples: 1, '1', '2.34'
431          * @return {Boolean} True if numeric, false otherwise
432          */
433         isNumeric: function(value) {
434             return !isNaN(parseFloat(value)) && isFinite(value);
435         },
436
437         /**
438          * Returns true if the passed value is a string.
439          * @param {Object} value The value to test
440          * @return {Boolean}
441          */
442         isString: function(value) {
443             return typeof value === 'string';
444         },
445
446         /**
447          * Returns true if the passed value is a boolean.
448          *
449          * @param {Object} value The value to test
450          * @return {Boolean}
451          */
452         isBoolean: function(value) {
453             return typeof value === 'boolean';
454         },
455
456         /**
457          * Returns true if the passed value is an HTMLElement
458          * @param {Object} value The value to test
459          * @return {Boolean}
460          */
461         isElement: function(value) {
462             return value ? value.nodeType === 1 : false;
463         },
464
465         /**
466          * Returns true if the passed value is a TextNode
467          * @param {Object} value The value to test
468          * @return {Boolean}
469          */
470         isTextNode: function(value) {
471             return value ? value.nodeName === "#text" : false;
472         },
473
474         /**
475          * Returns true if the passed value is defined.
476          * @param {Object} value The value to test
477          * @return {Boolean}
478          */
479         isDefined: function(value) {
480             return typeof value !== 'undefined';
481         },
482
483         /**
484          * Returns true if the passed value is iterable, false otherwise
485          * @param {Object} value The value to test
486          * @return {Boolean}
487          */
488         isIterable: function(value) {
489             return (value && typeof value !== 'string') ? value.length !== undefined : false;
490         }
491     });
492
493     Ext.apply(Ext, {
494
495         /**
496          * Clone almost any type of variable including array, object, DOM nodes and Date without keeping the old reference
497          * @param {Object} item The variable to clone
498          * @return {Object} clone
499          */
500         clone: function(item) {
501             if (item === null || item === undefined) {
502                 return item;
503             }
504
505             // DOM nodes
506             // TODO proxy this to Ext.Element.clone to handle automatic id attribute changing
507             // recursively
508             if (item.nodeType && item.cloneNode) {
509                 return item.cloneNode(true);
510             }
511
512             var type = toString.call(item);
513
514             // Date
515             if (type === '[object Date]') {
516                 return new Date(item.getTime());
517             }
518
519             var i, j, k, clone, key;
520
521             // Array
522             if (type === '[object Array]') {
523                 i = item.length;
524
525                 clone = [];
526
527                 while (i--) {
528                     clone[i] = Ext.clone(item[i]);
529                 }
530             }
531             // Object
532             else if (type === '[object Object]' && item.constructor === Object) {
533                 clone = {};
534
535                 for (key in item) {
536                     clone[key] = Ext.clone(item[key]);
537                 }
538
539                 if (enumerables) {
540                     for (j = enumerables.length; j--;) {
541                         k = enumerables[j];
542                         clone[k] = item[k];
543                     }
544                 }
545             }
546
547             return clone || item;
548         },
549
550         /**
551          * @private
552          * Generate a unique reference of Ext in the global scope, useful for sandboxing
553          */
554         getUniqueGlobalNamespace: function() {
555             var uniqueGlobalNamespace = this.uniqueGlobalNamespace;
556
557             if (uniqueGlobalNamespace === undefined) {
558                 var i = 0;
559
560                 do {
561                     uniqueGlobalNamespace = 'ExtBox' + (++i);
562                 } while (Ext.global[uniqueGlobalNamespace] !== undefined);
563
564                 Ext.global[uniqueGlobalNamespace] = Ext;
565                 this.uniqueGlobalNamespace = uniqueGlobalNamespace;
566             }
567
568             return uniqueGlobalNamespace;
569         },
570
571         /**
572          * @private
573          */
574         functionFactory: function() {
575             var args = Array.prototype.slice.call(arguments);
576
577             if (args.length > 0) {
578                 args[args.length - 1] = 'var Ext=window.' + this.getUniqueGlobalNamespace() + ';' +
579                     args[args.length - 1];
580             }
581
582             return Function.prototype.constructor.apply(Function.prototype, args);
583         }
584     });
585
586     /**
587      * Old alias to {@link Ext#typeOf}
588      * @deprecated 4.0.0 Use {@link Ext#typeOf} instead
589      * @method
590      * @alias Ext#typeOf
591      */
592     Ext.type = Ext.typeOf;
593
594 })();
595
596 /**
597  * @author Jacky Nguyen <jacky@sencha.com>
598  * @docauthor Jacky Nguyen <jacky@sencha.com>
599  * @class Ext.Version
600  *
601  * A utility class that wrap around a string version number and provide convenient
602  * method to perform comparison. See also: {@link Ext.Version#compare compare}. Example:
603
604     var version = new Ext.Version('1.0.2beta');
605     console.log("Version is " + version); // Version is 1.0.2beta
606
607     console.log(version.getMajor()); // 1
608     console.log(version.getMinor()); // 0
609     console.log(version.getPatch()); // 2
610     console.log(version.getBuild()); // 0
611     console.log(version.getRelease()); // beta
612
613     console.log(version.isGreaterThan('1.0.1')); // True
614     console.log(version.isGreaterThan('1.0.2alpha')); // True
615     console.log(version.isGreaterThan('1.0.2RC')); // False
616     console.log(version.isGreaterThan('1.0.2')); // False
617     console.log(version.isLessThan('1.0.2')); // True
618
619     console.log(version.match(1.0)); // True
620     console.log(version.match('1.0.2')); // True
621
622  * @markdown
623  */
624 (function() {
625
626 // Current core version
627 var version = '4.0.7', Version;
628     Ext.Version = Version = Ext.extend(Object, {
629
630         /**
631          * @param {String/Number} version The version number in the follow standard format: major[.minor[.patch[.build[release]]]]
632          * Examples: 1.0 or 1.2.3beta or 1.2.3.4RC
633          * @return {Ext.Version} this
634          */
635         constructor: function(version) {
636             var parts, releaseStartIndex;
637
638             if (version instanceof Version) {
639                 return version;
640             }
641
642             this.version = this.shortVersion = String(version).toLowerCase().replace(/_/g, '.').replace(/[\-+]/g, '');
643
644             releaseStartIndex = this.version.search(/([^\d\.])/);
645
646             if (releaseStartIndex !== -1) {
647                 this.release = this.version.substr(releaseStartIndex, version.length);
648                 this.shortVersion = this.version.substr(0, releaseStartIndex);
649             }
650
651             this.shortVersion = this.shortVersion.replace(/[^\d]/g, '');
652
653             parts = this.version.split('.');
654
655             this.major = parseInt(parts.shift() || 0, 10);
656             this.minor = parseInt(parts.shift() || 0, 10);
657             this.patch = parseInt(parts.shift() || 0, 10);
658             this.build = parseInt(parts.shift() || 0, 10);
659
660             return this;
661         },
662
663         /**
664          * Override the native toString method
665          * @private
666          * @return {String} version
667          */
668         toString: function() {
669             return this.version;
670         },
671
672         /**
673          * Override the native valueOf method
674          * @private
675          * @return {String} version
676          */
677         valueOf: function() {
678             return this.version;
679         },
680
681         /**
682          * Returns the major component value
683          * @return {Number} major
684          */
685         getMajor: function() {
686             return this.major || 0;
687         },
688
689         /**
690          * Returns the minor component value
691          * @return {Number} minor
692          */
693         getMinor: function() {
694             return this.minor || 0;
695         },
696
697         /**
698          * Returns the patch component value
699          * @return {Number} patch
700          */
701         getPatch: function() {
702             return this.patch || 0;
703         },
704
705         /**
706          * Returns the build component value
707          * @return {Number} build
708          */
709         getBuild: function() {
710             return this.build || 0;
711         },
712
713         /**
714          * Returns the release component value
715          * @return {Number} release
716          */
717         getRelease: function() {
718             return this.release || '';
719         },
720
721         /**
722          * Returns whether this version if greater than the supplied argument
723          * @param {String/Number} target The version to compare with
724          * @return {Boolean} True if this version if greater than the target, false otherwise
725          */
726         isGreaterThan: function(target) {
727             return Version.compare(this.version, target) === 1;
728         },
729
730         /**
731          * Returns whether this version if smaller than the supplied argument
732          * @param {String/Number} target The version to compare with
733          * @return {Boolean} True if this version if smaller than the target, false otherwise
734          */
735         isLessThan: function(target) {
736             return Version.compare(this.version, target) === -1;
737         },
738
739         /**
740          * Returns whether this version equals to the supplied argument
741          * @param {String/Number} target The version to compare with
742          * @return {Boolean} True if this version equals to the target, false otherwise
743          */
744         equals: function(target) {
745             return Version.compare(this.version, target) === 0;
746         },
747
748         /**
749          * Returns whether this version matches the supplied argument. Example:
750          * <pre><code>
751          * var version = new Ext.Version('1.0.2beta');
752          * console.log(version.match(1)); // True
753          * console.log(version.match(1.0)); // True
754          * console.log(version.match('1.0.2')); // True
755          * console.log(version.match('1.0.2RC')); // False
756          * </code></pre>
757          * @param {String/Number} target The version to compare with
758          * @return {Boolean} True if this version matches the target, false otherwise
759          */
760         match: function(target) {
761             target = String(target);
762             return this.version.substr(0, target.length) === target;
763         },
764
765         /**
766          * Returns this format: [major, minor, patch, build, release]. Useful for comparison
767          * @return {Number[]}
768          */
769         toArray: function() {
770             return [this.getMajor(), this.getMinor(), this.getPatch(), this.getBuild(), this.getRelease()];
771         },
772
773         /**
774          * Returns shortVersion version without dots and release
775          * @return {String}
776          */
777         getShortVersion: function() {
778             return this.shortVersion;
779         }
780     });
781
782     Ext.apply(Version, {
783         // @private
784         releaseValueMap: {
785             'dev': -6,
786             'alpha': -5,
787             'a': -5,
788             'beta': -4,
789             'b': -4,
790             'rc': -3,
791             '#': -2,
792             'p': -1,
793             'pl': -1
794         },
795
796         /**
797          * Converts a version component to a comparable value
798          *
799          * @static
800          * @param {Object} value The value to convert
801          * @return {Object}
802          */
803         getComponentValue: function(value) {
804             return !value ? 0 : (isNaN(value) ? this.releaseValueMap[value] || value : parseInt(value, 10));
805         },
806
807         /**
808          * Compare 2 specified versions, starting from left to right. If a part contains special version strings,
809          * they are handled in the following order:
810          * 'dev' < 'alpha' = 'a' < 'beta' = 'b' < 'RC' = 'rc' < '#' < 'pl' = 'p' < 'anything else'
811          *
812          * @static
813          * @param {String} current The current version to compare to
814          * @param {String} target The target version to compare to
815          * @return {Number} Returns -1 if the current version is smaller than the target version, 1 if greater, and 0 if they're equivalent
816          */
817         compare: function(current, target) {
818             var currentValue, targetValue, i;
819
820             current = new Version(current).toArray();
821             target = new Version(target).toArray();
822
823             for (i = 0; i < Math.max(current.length, target.length); i++) {
824                 currentValue = this.getComponentValue(current[i]);
825                 targetValue = this.getComponentValue(target[i]);
826
827                 if (currentValue < targetValue) {
828                     return -1;
829                 } else if (currentValue > targetValue) {
830                     return 1;
831                 }
832             }
833
834             return 0;
835         }
836     });
837
838     Ext.apply(Ext, {
839         /**
840          * @private
841          */
842         versions: {},
843
844         /**
845          * @private
846          */
847         lastRegisteredVersion: null,
848
849         /**
850          * Set version number for the given package name.
851          *
852          * @param {String} packageName The package name, for example: 'core', 'touch', 'extjs'
853          * @param {String/Ext.Version} version The version, for example: '1.2.3alpha', '2.4.0-dev'
854          * @return {Ext}
855          */
856         setVersion: function(packageName, version) {
857             Ext.versions[packageName] = new Version(version);
858             Ext.lastRegisteredVersion = Ext.versions[packageName];
859
860             return this;
861         },
862
863         /**
864          * Get the version number of the supplied package name; will return the last registered version
865          * (last Ext.setVersion call) if there's no package name given.
866          *
867          * @param {String} packageName (Optional) The package name, for example: 'core', 'touch', 'extjs'
868          * @return {Ext.Version} The version
869          */
870         getVersion: function(packageName) {
871             if (packageName === undefined) {
872                 return Ext.lastRegisteredVersion;
873             }
874
875             return Ext.versions[packageName];
876         },
877
878         /**
879          * Create a closure for deprecated code.
880          *
881     // This means Ext.oldMethod is only supported in 4.0.0beta and older.
882     // If Ext.getVersion('extjs') returns a version that is later than '4.0.0beta', for example '4.0.0RC',
883     // the closure will not be invoked
884     Ext.deprecate('extjs', '4.0.0beta', function() {
885         Ext.oldMethod = Ext.newMethod;
886
887         ...
888     });
889
890          * @param {String} packageName The package name
891          * @param {String} since The last version before it's deprecated
892          * @param {Function} closure The callback function to be executed with the specified version is less than the current version
893          * @param {Object} scope The execution scope (<tt>this</tt>) if the closure
894          * @markdown
895          */
896         deprecate: function(packageName, since, closure, scope) {
897             if (Version.compare(Ext.getVersion(packageName), since) < 1) {
898                 closure.call(scope);
899             }
900         }
901     }); // End Versioning
902
903     Ext.setVersion('core', version);
904
905 })();
906
907 /**
908  * @class Ext.String
909  *
910  * A collection of useful static methods to deal with strings
911  * @singleton
912  */
913
914 Ext.String = {
915     trimRegex: /^[\x09\x0a\x0b\x0c\x0d\x20\xa0\u1680\u180e\u2000\u2001\u2002\u2003\u2004\u2005\u2006\u2007\u2008\u2009\u200a\u2028\u2029\u202f\u205f\u3000]+|[\x09\x0a\x0b\x0c\x0d\x20\xa0\u1680\u180e\u2000\u2001\u2002\u2003\u2004\u2005\u2006\u2007\u2008\u2009\u200a\u2028\u2029\u202f\u205f\u3000]+$/g,
916     escapeRe: /('|\\)/g,
917     formatRe: /\{(\d+)\}/g,
918     escapeRegexRe: /([-.*+?^${}()|[\]\/\\])/g,
919
920     /**
921      * Convert certain characters (&, <, >, and ") to their HTML character equivalents for literal display in web pages.
922      * @param {String} value The string to encode
923      * @return {String} The encoded text
924      * @method
925      */
926     htmlEncode: (function() {
927         var entities = {
928             '&': '&amp;',
929             '>': '&gt;',
930             '<': '&lt;',
931             '"': '&quot;'
932         }, keys = [], p, regex;
933         
934         for (p in entities) {
935             keys.push(p);
936         }
937         
938         regex = new RegExp('(' + keys.join('|') + ')', 'g');
939         
940         return function(value) {
941             return (!value) ? value : String(value).replace(regex, function(match, capture) {
942                 return entities[capture];    
943             });
944         };
945     })(),
946
947     /**
948      * Convert certain characters (&, <, >, and ") from their HTML character equivalents.
949      * @param {String} value The string to decode
950      * @return {String} The decoded text
951      * @method
952      */
953     htmlDecode: (function() {
954         var entities = {
955             '&amp;': '&',
956             '&gt;': '>',
957             '&lt;': '<',
958             '&quot;': '"'
959         }, keys = [], p, regex;
960         
961         for (p in entities) {
962             keys.push(p);
963         }
964         
965         regex = new RegExp('(' + keys.join('|') + '|&#[0-9]{1,5};' + ')', 'g');
966         
967         return function(value) {
968             return (!value) ? value : String(value).replace(regex, function(match, capture) {
969                 if (capture in entities) {
970                     return entities[capture];
971                 } else {
972                     return String.fromCharCode(parseInt(capture.substr(2), 10));
973                 }
974             });
975         };
976     })(),
977
978     /**
979      * Appends content to the query string of a URL, handling logic for whether to place
980      * a question mark or ampersand.
981      * @param {String} url The URL to append to.
982      * @param {String} string The content to append to the URL.
983      * @return (String) The resulting URL
984      */
985     urlAppend : function(url, string) {
986         if (!Ext.isEmpty(string)) {
987             return url + (url.indexOf('?') === -1 ? '?' : '&') + string;
988         }
989
990         return url;
991     },
992
993     /**
994      * Trims whitespace from either end of a string, leaving spaces within the string intact.  Example:
995      * @example
996 var s = '  foo bar  ';
997 alert('-' + s + '-');         //alerts "- foo bar -"
998 alert('-' + Ext.String.trim(s) + '-');  //alerts "-foo bar-"
999
1000      * @param {String} string The string to escape
1001      * @return {String} The trimmed string
1002      */
1003     trim: function(string) {
1004         return string.replace(Ext.String.trimRegex, "");
1005     },
1006
1007     /**
1008      * Capitalize the given string
1009      * @param {String} string
1010      * @return {String}
1011      */
1012     capitalize: function(string) {
1013         return string.charAt(0).toUpperCase() + string.substr(1);
1014     },
1015
1016     /**
1017      * Truncate a string and add an ellipsis ('...') to the end if it exceeds the specified length
1018      * @param {String} value The string to truncate
1019      * @param {Number} length The maximum length to allow before truncating
1020      * @param {Boolean} word True to try to find a common word break
1021      * @return {String} The converted text
1022      */
1023     ellipsis: function(value, len, word) {
1024         if (value && value.length > len) {
1025             if (word) {
1026                 var vs = value.substr(0, len - 2),
1027                 index = Math.max(vs.lastIndexOf(' '), vs.lastIndexOf('.'), vs.lastIndexOf('!'), vs.lastIndexOf('?'));
1028                 if (index !== -1 && index >= (len - 15)) {
1029                     return vs.substr(0, index) + "...";
1030                 }
1031             }
1032             return value.substr(0, len - 3) + "...";
1033         }
1034         return value;
1035     },
1036
1037     /**
1038      * Escapes the passed string for use in a regular expression
1039      * @param {String} string
1040      * @return {String}
1041      */
1042     escapeRegex: function(string) {
1043         return string.replace(Ext.String.escapeRegexRe, "\\$1");
1044     },
1045
1046     /**
1047      * Escapes the passed string for ' and \
1048      * @param {String} string The string to escape
1049      * @return {String} The escaped string
1050      */
1051     escape: function(string) {
1052         return string.replace(Ext.String.escapeRe, "\\$1");
1053     },
1054
1055     /**
1056      * Utility function that allows you to easily switch a string between two alternating values.  The passed value
1057      * is compared to the current string, and if they are equal, the other value that was passed in is returned.  If
1058      * they are already different, the first value passed in is returned.  Note that this method returns the new value
1059      * but does not change the current string.
1060      * <pre><code>
1061     // alternate sort directions
1062     sort = Ext.String.toggle(sort, 'ASC', 'DESC');
1063
1064     // instead of conditional logic:
1065     sort = (sort == 'ASC' ? 'DESC' : 'ASC');
1066        </code></pre>
1067      * @param {String} string The current string
1068      * @param {String} value The value to compare to the current string
1069      * @param {String} other The new value to use if the string already equals the first value passed in
1070      * @return {String} The new value
1071      */
1072     toggle: function(string, value, other) {
1073         return string === value ? other : value;
1074     },
1075
1076     /**
1077      * Pads the left side of a string with a specified character.  This is especially useful
1078      * for normalizing number and date strings.  Example usage:
1079      *
1080      * <pre><code>
1081 var s = Ext.String.leftPad('123', 5, '0');
1082 // s now contains the string: '00123'
1083        </code></pre>
1084      * @param {String} string The original string
1085      * @param {Number} size The total length of the output string
1086      * @param {String} character (optional) The character with which to pad the original string (defaults to empty string " ")
1087      * @return {String} The padded string
1088      */
1089     leftPad: function(string, size, character) {
1090         var result = String(string);
1091         character = character || " ";
1092         while (result.length < size) {
1093             result = character + result;
1094         }
1095         return result;
1096     },
1097
1098     /**
1099      * Allows you to define a tokenized string and pass an arbitrary number of arguments to replace the tokens.  Each
1100      * token must be unique, and must increment in the format {0}, {1}, etc.  Example usage:
1101      * <pre><code>
1102 var cls = 'my-class', text = 'Some text';
1103 var s = Ext.String.format('&lt;div class="{0}">{1}&lt;/div>', cls, text);
1104 // s now contains the string: '&lt;div class="my-class">Some text&lt;/div>'
1105        </code></pre>
1106      * @param {String} string The tokenized string to be formatted
1107      * @param {String} value1 The value to replace token {0}
1108      * @param {String} value2 Etc...
1109      * @return {String} The formatted string
1110      */
1111     format: function(format) {
1112         var args = Ext.Array.toArray(arguments, 1);
1113         return format.replace(Ext.String.formatRe, function(m, i) {
1114             return args[i];
1115         });
1116     },
1117
1118     /**
1119      * Returns a string with a specified number of repititions a given string pattern.
1120      * The pattern be separated by a different string.
1121      *
1122      *      var s = Ext.String.repeat('---', 4); // = '------------'
1123      *      var t = Ext.String.repeat('--', 3, '/'); // = '--/--/--'
1124      *
1125      * @param {String} pattern The pattern to repeat.
1126      * @param {Number} count The number of times to repeat the pattern (may be 0).
1127      * @param {String} sep An option string to separate each pattern.
1128      */
1129     repeat: function(pattern, count, sep) {
1130         for (var buf = [], i = count; i--; ) {
1131             buf.push(pattern);
1132         }
1133         return buf.join(sep || '');
1134     }
1135 };
1136
1137 /**
1138  * @class Ext.Number
1139  *
1140  * A collection of useful static methods to deal with numbers
1141  * @singleton
1142  */
1143
1144 (function() {
1145
1146 var isToFixedBroken = (0.9).toFixed() !== '1';
1147
1148 Ext.Number = {
1149     /**
1150      * Checks whether or not the passed number is within a desired range.  If the number is already within the
1151      * range it is returned, otherwise the min or max value is returned depending on which side of the range is
1152      * exceeded. Note that this method returns the constrained value but does not change the current number.
1153      * @param {Number} number The number to check
1154      * @param {Number} min The minimum number in the range
1155      * @param {Number} max The maximum number in the range
1156      * @return {Number} The constrained value if outside the range, otherwise the current value
1157      */
1158     constrain: function(number, min, max) {
1159         number = parseFloat(number);
1160
1161         if (!isNaN(min)) {
1162             number = Math.max(number, min);
1163         }
1164         if (!isNaN(max)) {
1165             number = Math.min(number, max);
1166         }
1167         return number;
1168     },
1169
1170     /**
1171      * Snaps the passed number between stopping points based upon a passed increment value.
1172      * @param {Number} value The unsnapped value.
1173      * @param {Number} increment The increment by which the value must move.
1174      * @param {Number} minValue The minimum value to which the returned value must be constrained. Overrides the increment..
1175      * @param {Number} maxValue The maximum value to which the returned value must be constrained. Overrides the increment..
1176      * @return {Number} The value of the nearest snap target.
1177      */
1178     snap : function(value, increment, minValue, maxValue) {
1179         var newValue = value,
1180             m;
1181
1182         if (!(increment && value)) {
1183             return value;
1184         }
1185         m = value % increment;
1186         if (m !== 0) {
1187             newValue -= m;
1188             if (m * 2 >= increment) {
1189                 newValue += increment;
1190             } else if (m * 2 < -increment) {
1191                 newValue -= increment;
1192             }
1193         }
1194         return Ext.Number.constrain(newValue, minValue,  maxValue);
1195     },
1196
1197     /**
1198      * Formats a number using fixed-point notation
1199      * @param {Number} value The number to format
1200      * @param {Number} precision The number of digits to show after the decimal point
1201      */
1202     toFixed: function(value, precision) {
1203         if (isToFixedBroken) {
1204             precision = precision || 0;
1205             var pow = Math.pow(10, precision);
1206             return (Math.round(value * pow) / pow).toFixed(precision);
1207         }
1208
1209         return value.toFixed(precision);
1210     },
1211
1212     /**
1213      * Validate that a value is numeric and convert it to a number if necessary. Returns the specified default value if
1214      * it is not.
1215
1216 Ext.Number.from('1.23', 1); // returns 1.23
1217 Ext.Number.from('abc', 1); // returns 1
1218
1219      * @param {Object} value
1220      * @param {Number} defaultValue The value to return if the original value is non-numeric
1221      * @return {Number} value, if numeric, defaultValue otherwise
1222      */
1223     from: function(value, defaultValue) {
1224         if (isFinite(value)) {
1225             value = parseFloat(value);
1226         }
1227
1228         return !isNaN(value) ? value : defaultValue;
1229     }
1230 };
1231
1232 })();
1233
1234 /**
1235  * @deprecated 4.0.0 Please use {@link Ext.Number#from} instead.
1236  * @member Ext
1237  * @method num
1238  * @alias Ext.Number#from
1239  */
1240 Ext.num = function() {
1241     return Ext.Number.from.apply(this, arguments);
1242 };
1243 /**
1244  * @class Ext.Array
1245  * @singleton
1246  * @author Jacky Nguyen <jacky@sencha.com>
1247  * @docauthor Jacky Nguyen <jacky@sencha.com>
1248  *
1249  * A set of useful static methods to deal with arrays; provide missing methods for older browsers.
1250  */
1251 (function() {
1252
1253     var arrayPrototype = Array.prototype,
1254         slice = arrayPrototype.slice,
1255         supportsSplice = function () {
1256             var array = [],
1257                 lengthBefore,
1258                 j = 20;
1259
1260             if (!array.splice) {
1261                 return false;
1262             }
1263
1264             // This detects a bug in IE8 splice method:
1265             // see http://social.msdn.microsoft.com/Forums/en-US/iewebdevelopment/thread/6e946d03-e09f-4b22-a4dd-cd5e276bf05a/
1266
1267             while (j--) {
1268                 array.push("A");
1269             }
1270
1271             array.splice(15, 0, "F", "F", "F", "F", "F","F","F","F","F","F","F","F","F","F","F","F","F","F","F","F","F");
1272
1273             lengthBefore = array.length; //41
1274             array.splice(13, 0, "XXX"); // add one element
1275
1276             if (lengthBefore+1 != array.length) {
1277                 return false;
1278             }
1279             // end IE8 bug
1280
1281             return true;
1282         }(),
1283         supportsForEach = 'forEach' in arrayPrototype,
1284         supportsMap = 'map' in arrayPrototype,
1285         supportsIndexOf = 'indexOf' in arrayPrototype,
1286         supportsEvery = 'every' in arrayPrototype,
1287         supportsSome = 'some' in arrayPrototype,
1288         supportsFilter = 'filter' in arrayPrototype,
1289         supportsSort = function() {
1290             var a = [1,2,3,4,5].sort(function(){ return 0; });
1291             return a[0] === 1 && a[1] === 2 && a[2] === 3 && a[3] === 4 && a[4] === 5;
1292         }(),
1293         supportsSliceOnNodeList = true,
1294         ExtArray;
1295
1296     try {
1297         // IE 6 - 8 will throw an error when using Array.prototype.slice on NodeList
1298         if (typeof document !== 'undefined') {
1299             slice.call(document.getElementsByTagName('body'));
1300         }
1301     } catch (e) {
1302         supportsSliceOnNodeList = false;
1303     }
1304
1305     function fixArrayIndex (array, index) {
1306         return (index < 0) ? Math.max(0, array.length + index)
1307                            : Math.min(array.length, index);
1308     }
1309
1310     /*
1311     Does the same work as splice, but with a slightly more convenient signature. The splice
1312     method has bugs in IE8, so this is the implementation we use on that platform.
1313
1314     The rippling of items in the array can be tricky. Consider two use cases:
1315
1316                   index=2
1317                   removeCount=2
1318                  /=====\
1319         +---+---+---+---+---+---+---+---+
1320         | 0 | 1 | 2 | 3 | 4 | 5 | 6 | 7 |
1321         +---+---+---+---+---+---+---+---+
1322                          /  \/  \/  \/  \
1323                         /   /\  /\  /\   \
1324                        /   /  \/  \/  \   +--------------------------+
1325                       /   /   /\  /\   +--------------------------+   \
1326                      /   /   /  \/  +--------------------------+   \   \
1327                     /   /   /   /+--------------------------+   \   \   \
1328                    /   /   /   /                             \   \   \   \
1329                   v   v   v   v                               v   v   v   v
1330         +---+---+---+---+---+---+       +---+---+---+---+---+---+---+---+---+
1331         | 0 | 1 | 4 | 5 | 6 | 7 |       | 0 | 1 | a | b | c | 4 | 5 | 6 | 7 |
1332         +---+---+---+---+---+---+       +---+---+---+---+---+---+---+---+---+
1333         A                               B        \=========/
1334                                                  insert=[a,b,c]
1335
1336     In case A, it is obvious that copying of [4,5,6,7] must be left-to-right so
1337     that we don't end up with [0,1,6,7,6,7]. In case B, we have the opposite; we
1338     must go right-to-left or else we would end up with [0,1,a,b,c,4,4,4,4].
1339     */
1340     function replaceSim (array, index, removeCount, insert) {
1341         var add = insert ? insert.length : 0,
1342             length = array.length,
1343             pos = fixArrayIndex(array, index);
1344
1345         // we try to use Array.push when we can for efficiency...
1346         if (pos === length) {
1347             if (add) {
1348                 array.push.apply(array, insert);
1349             }
1350         } else {
1351             var remove = Math.min(removeCount, length - pos),
1352                 tailOldPos = pos + remove,
1353                 tailNewPos = tailOldPos + add - remove,
1354                 tailCount = length - tailOldPos,
1355                 lengthAfterRemove = length - remove,
1356                 i;
1357
1358             if (tailNewPos < tailOldPos) { // case A
1359                 for (i = 0; i < tailCount; ++i) {
1360                     array[tailNewPos+i] = array[tailOldPos+i];
1361                 }
1362             } else if (tailNewPos > tailOldPos) { // case B
1363                 for (i = tailCount; i--; ) {
1364                     array[tailNewPos+i] = array[tailOldPos+i];
1365                 }
1366             } // else, add == remove (nothing to do)
1367
1368             if (add && pos === lengthAfterRemove) {
1369                 array.length = lengthAfterRemove; // truncate array
1370                 array.push.apply(array, insert);
1371             } else {
1372                 array.length = lengthAfterRemove + add; // reserves space
1373                 for (i = 0; i < add; ++i) {
1374                     array[pos+i] = insert[i];
1375                 }
1376             }
1377         }
1378
1379         return array;
1380     }
1381
1382     function replaceNative (array, index, removeCount, insert) {
1383         if (insert && insert.length) {
1384             if (index < array.length) {
1385                 array.splice.apply(array, [index, removeCount].concat(insert));
1386             } else {
1387                 array.push.apply(array, insert);
1388             }
1389         } else {
1390             array.splice(index, removeCount);
1391         }
1392         return array;
1393     }
1394
1395     function eraseSim (array, index, removeCount) {
1396         return replaceSim(array, index, removeCount);
1397     }
1398
1399     function eraseNative (array, index, removeCount) {
1400         array.splice(index, removeCount);
1401         return array;
1402     }
1403
1404     function spliceSim (array, index, removeCount) {
1405         var pos = fixArrayIndex(array, index),
1406             removed = array.slice(index, fixArrayIndex(array, pos+removeCount));
1407
1408         if (arguments.length < 4) {
1409             replaceSim(array, pos, removeCount);
1410         } else {
1411             replaceSim(array, pos, removeCount, slice.call(arguments, 3));
1412         }
1413
1414         return removed;
1415     }
1416
1417     function spliceNative (array) {
1418         return array.splice.apply(array, slice.call(arguments, 1));
1419     }
1420
1421     var erase = supportsSplice ? eraseNative : eraseSim,
1422         replace = supportsSplice ? replaceNative : replaceSim,
1423         splice = supportsSplice ? spliceNative : spliceSim;
1424
1425     // NOTE: from here on, use erase, replace or splice (not native methods)...
1426
1427     ExtArray = Ext.Array = {
1428         /**
1429          * Iterates an array or an iterable value and invoke the given callback function for each item.
1430          *
1431          *     var countries = ['Vietnam', 'Singapore', 'United States', 'Russia'];
1432          *
1433          *     Ext.Array.each(countries, function(name, index, countriesItSelf) {
1434          *         console.log(name);
1435          *     });
1436          *
1437          *     var sum = function() {
1438          *         var sum = 0;
1439          *
1440          *         Ext.Array.each(arguments, function(value) {
1441          *             sum += value;
1442          *         });
1443          *
1444          *         return sum;
1445          *     };
1446          *
1447          *     sum(1, 2, 3); // returns 6
1448          *
1449          * The iteration can be stopped by returning false in the function callback.
1450          *
1451          *     Ext.Array.each(countries, function(name, index, countriesItSelf) {
1452          *         if (name === 'Singapore') {
1453          *             return false; // break here
1454          *         }
1455          *     });
1456          *
1457          * {@link Ext#each Ext.each} is alias for {@link Ext.Array#each Ext.Array.each}
1458          *
1459          * @param {Array/NodeList/Object} iterable The value to be iterated. If this
1460          * argument is not iterable, the callback function is called once.
1461          * @param {Function} fn The callback function. If it returns false, the iteration stops and this method returns
1462          * the current `index`.
1463          * @param {Object} fn.item The item at the current `index` in the passed `array`
1464          * @param {Number} fn.index The current `index` within the `array`
1465          * @param {Array} fn.allItems The `array` itself which was passed as the first argument
1466          * @param {Boolean} fn.return Return false to stop iteration.
1467          * @param {Object} scope (Optional) The scope (`this` reference) in which the specified function is executed.
1468          * @param {Boolean} reverse (Optional) Reverse the iteration order (loop from the end to the beginning)
1469          * Defaults false
1470          * @return {Boolean} See description for the `fn` parameter.
1471          */
1472         each: function(array, fn, scope, reverse) {
1473             array = ExtArray.from(array);
1474
1475             var i,
1476                 ln = array.length;
1477
1478             if (reverse !== true) {
1479                 for (i = 0; i < ln; i++) {
1480                     if (fn.call(scope || array[i], array[i], i, array) === false) {
1481                         return i;
1482                     }
1483                 }
1484             }
1485             else {
1486                 for (i = ln - 1; i > -1; i--) {
1487                     if (fn.call(scope || array[i], array[i], i, array) === false) {
1488                         return i;
1489                     }
1490                 }
1491             }
1492
1493             return true;
1494         },
1495
1496         /**
1497          * Iterates an array and invoke the given callback function for each item. Note that this will simply
1498          * delegate to the native Array.prototype.forEach method if supported. It doesn't support stopping the
1499          * iteration by returning false in the callback function like {@link Ext.Array#each}. However, performance
1500          * could be much better in modern browsers comparing with {@link Ext.Array#each}
1501          *
1502          * @param {Array} array The array to iterate
1503          * @param {Function} fn The callback function.
1504          * @param {Object} fn.item The item at the current `index` in the passed `array`
1505          * @param {Number} fn.index The current `index` within the `array`
1506          * @param {Array}  fn.allItems The `array` itself which was passed as the first argument
1507          * @param {Object} scope (Optional) The execution scope (`this`) in which the specified function is executed.
1508          */
1509         forEach: function(array, fn, scope) {
1510             if (supportsForEach) {
1511                 return array.forEach(fn, scope);
1512             }
1513
1514             var i = 0,
1515                 ln = array.length;
1516
1517             for (; i < ln; i++) {
1518                 fn.call(scope, array[i], i, array);
1519             }
1520         },
1521
1522         /**
1523          * Get the index of the provided `item` in the given `array`, a supplement for the
1524          * missing arrayPrototype.indexOf in Internet Explorer.
1525          *
1526          * @param {Array} array The array to check
1527          * @param {Object} item The item to look for
1528          * @param {Number} from (Optional) The index at which to begin the search
1529          * @return {Number} The index of item in the array (or -1 if it is not found)
1530          */
1531         indexOf: function(array, item, from) {
1532             if (supportsIndexOf) {
1533                 return array.indexOf(item, from);
1534             }
1535
1536             var i, length = array.length;
1537
1538             for (i = (from < 0) ? Math.max(0, length + from) : from || 0; i < length; i++) {
1539                 if (array[i] === item) {
1540                     return i;
1541                 }
1542             }
1543
1544             return -1;
1545         },
1546
1547         /**
1548          * Checks whether or not the given `array` contains the specified `item`
1549          *
1550          * @param {Array} array The array to check
1551          * @param {Object} item The item to look for
1552          * @return {Boolean} True if the array contains the item, false otherwise
1553          */
1554         contains: function(array, item) {
1555             if (supportsIndexOf) {
1556                 return array.indexOf(item) !== -1;
1557             }
1558
1559             var i, ln;
1560
1561             for (i = 0, ln = array.length; i < ln; i++) {
1562                 if (array[i] === item) {
1563                     return true;
1564                 }
1565             }
1566
1567             return false;
1568         },
1569
1570         /**
1571          * Converts any iterable (numeric indices and a length property) into a true array.
1572          *
1573          *     function test() {
1574          *         var args = Ext.Array.toArray(arguments),
1575          *             fromSecondToLastArgs = Ext.Array.toArray(arguments, 1);
1576          *
1577          *         alert(args.join(' '));
1578          *         alert(fromSecondToLastArgs.join(' '));
1579          *     }
1580          *
1581          *     test('just', 'testing', 'here'); // alerts 'just testing here';
1582          *                                      // alerts 'testing here';
1583          *
1584          *     Ext.Array.toArray(document.getElementsByTagName('div')); // will convert the NodeList into an array
1585          *     Ext.Array.toArray('splitted'); // returns ['s', 'p', 'l', 'i', 't', 't', 'e', 'd']
1586          *     Ext.Array.toArray('splitted', 0, 3); // returns ['s', 'p', 'l', 'i']
1587          *
1588          * {@link Ext#toArray Ext.toArray} is alias for {@link Ext.Array#toArray Ext.Array.toArray}
1589          *
1590          * @param {Object} iterable the iterable object to be turned into a true Array.
1591          * @param {Number} start (Optional) a zero-based index that specifies the start of extraction. Defaults to 0
1592          * @param {Number} end (Optional) a zero-based index that specifies the end of extraction. Defaults to the last
1593          * index of the iterable value
1594          * @return {Array} array
1595          */
1596         toArray: function(iterable, start, end){
1597             if (!iterable || !iterable.length) {
1598                 return [];
1599             }
1600
1601             if (typeof iterable === 'string') {
1602                 iterable = iterable.split('');
1603             }
1604
1605             if (supportsSliceOnNodeList) {
1606                 return slice.call(iterable, start || 0, end || iterable.length);
1607             }
1608
1609             var array = [],
1610                 i;
1611
1612             start = start || 0;
1613             end = end ? ((end < 0) ? iterable.length + end : end) : iterable.length;
1614
1615             for (i = start; i < end; i++) {
1616                 array.push(iterable[i]);
1617             }
1618
1619             return array;
1620         },
1621
1622         /**
1623          * Plucks the value of a property from each item in the Array. Example:
1624          *
1625          *     Ext.Array.pluck(Ext.query("p"), "className"); // [el1.className, el2.className, ..., elN.className]
1626          *
1627          * @param {Array/NodeList} array The Array of items to pluck the value from.
1628          * @param {String} propertyName The property name to pluck from each element.
1629          * @return {Array} The value from each item in the Array.
1630          */
1631         pluck: function(array, propertyName) {
1632             var ret = [],
1633                 i, ln, item;
1634
1635             for (i = 0, ln = array.length; i < ln; i++) {
1636                 item = array[i];
1637
1638                 ret.push(item[propertyName]);
1639             }
1640
1641             return ret;
1642         },
1643
1644         /**
1645          * Creates a new array with the results of calling a provided function on every element in this array.
1646          *
1647          * @param {Array} array
1648          * @param {Function} fn Callback function for each item
1649          * @param {Object} scope Callback function scope
1650          * @return {Array} results
1651          */
1652         map: function(array, fn, scope) {
1653             if (supportsMap) {
1654                 return array.map(fn, scope);
1655             }
1656
1657             var results = [],
1658                 i = 0,
1659                 len = array.length;
1660
1661             for (; i < len; i++) {
1662                 results[i] = fn.call(scope, array[i], i, array);
1663             }
1664
1665             return results;
1666         },
1667
1668         /**
1669          * Executes the specified function for each array element until the function returns a falsy value.
1670          * If such an item is found, the function will return false immediately.
1671          * Otherwise, it will return true.
1672          *
1673          * @param {Array} array
1674          * @param {Function} fn Callback function for each item
1675          * @param {Object} scope Callback function scope
1676          * @return {Boolean} True if no false value is returned by the callback function.
1677          */
1678         every: function(array, fn, scope) {
1679             if (!fn) {
1680                 Ext.Error.raise('Ext.Array.every must have a callback function passed as second argument.');
1681             }
1682             if (supportsEvery) {
1683                 return array.every(fn, scope);
1684             }
1685
1686             var i = 0,
1687                 ln = array.length;
1688
1689             for (; i < ln; ++i) {
1690                 if (!fn.call(scope, array[i], i, array)) {
1691                     return false;
1692                 }
1693             }
1694
1695             return true;
1696         },
1697
1698         /**
1699          * Executes the specified function for each array element until the function returns a truthy value.
1700          * If such an item is found, the function will return true immediately. Otherwise, it will return false.
1701          *
1702          * @param {Array} array
1703          * @param {Function} fn Callback function for each item
1704          * @param {Object} scope Callback function scope
1705          * @return {Boolean} True if the callback function returns a truthy value.
1706          */
1707         some: function(array, fn, scope) {
1708             if (!fn) {
1709                 Ext.Error.raise('Ext.Array.some must have a callback function passed as second argument.');
1710             }
1711             if (supportsSome) {
1712                 return array.some(fn, scope);
1713             }
1714
1715             var i = 0,
1716                 ln = array.length;
1717
1718             for (; i < ln; ++i) {
1719                 if (fn.call(scope, array[i], i, array)) {
1720                     return true;
1721                 }
1722             }
1723
1724             return false;
1725         },
1726
1727         /**
1728          * Filter through an array and remove empty item as defined in {@link Ext#isEmpty Ext.isEmpty}
1729          *
1730          * See {@link Ext.Array#filter}
1731          *
1732          * @param {Array} array
1733          * @return {Array} results
1734          */
1735         clean: function(array) {
1736             var results = [],
1737                 i = 0,
1738                 ln = array.length,
1739                 item;
1740
1741             for (; i < ln; i++) {
1742                 item = array[i];
1743
1744                 if (!Ext.isEmpty(item)) {
1745                     results.push(item);
1746                 }
1747             }
1748
1749             return results;
1750         },
1751
1752         /**
1753          * Returns a new array with unique items
1754          *
1755          * @param {Array} array
1756          * @return {Array} results
1757          */
1758         unique: function(array) {
1759             var clone = [],
1760                 i = 0,
1761                 ln = array.length,
1762                 item;
1763
1764             for (; i < ln; i++) {
1765                 item = array[i];
1766
1767                 if (ExtArray.indexOf(clone, item) === -1) {
1768                     clone.push(item);
1769                 }
1770             }
1771
1772             return clone;
1773         },
1774
1775         /**
1776          * Creates a new array with all of the elements of this array for which
1777          * the provided filtering function returns true.
1778          *
1779          * @param {Array} array
1780          * @param {Function} fn Callback function for each item
1781          * @param {Object} scope Callback function scope
1782          * @return {Array} results
1783          */
1784         filter: function(array, fn, scope) {
1785             if (supportsFilter) {
1786                 return array.filter(fn, scope);
1787             }
1788
1789             var results = [],
1790                 i = 0,
1791                 ln = array.length;
1792
1793             for (; i < ln; i++) {
1794                 if (fn.call(scope, array[i], i, array)) {
1795                     results.push(array[i]);
1796                 }
1797             }
1798
1799             return results;
1800         },
1801
1802         /**
1803          * Converts a value to an array if it's not already an array; returns:
1804          *
1805          * - An empty array if given value is `undefined` or `null`
1806          * - Itself if given value is already an array
1807          * - An array copy if given value is {@link Ext#isIterable iterable} (arguments, NodeList and alike)
1808          * - An array with one item which is the given value, otherwise
1809          *
1810          * @param {Object} value The value to convert to an array if it's not already is an array
1811          * @param {Boolean} newReference (Optional) True to clone the given array and return a new reference if necessary,
1812          * defaults to false
1813          * @return {Array} array
1814          */
1815         from: function(value, newReference) {
1816             if (value === undefined || value === null) {
1817                 return [];
1818             }
1819
1820             if (Ext.isArray(value)) {
1821                 return (newReference) ? slice.call(value) : value;
1822             }
1823
1824             if (value && value.length !== undefined && typeof value !== 'string') {
1825                 return Ext.toArray(value);
1826             }
1827
1828             return [value];
1829         },
1830
1831         /**
1832          * Removes the specified item from the array if it exists
1833          *
1834          * @param {Array} array The array
1835          * @param {Object} item The item to remove
1836          * @return {Array} The passed array itself
1837          */
1838         remove: function(array, item) {
1839             var index = ExtArray.indexOf(array, item);
1840
1841             if (index !== -1) {
1842                 erase(array, index, 1);
1843             }
1844
1845             return array;
1846         },
1847
1848         /**
1849          * Push an item into the array only if the array doesn't contain it yet
1850          *
1851          * @param {Array} array The array
1852          * @param {Object} item The item to include
1853          */
1854         include: function(array, item) {
1855             if (!ExtArray.contains(array, item)) {
1856                 array.push(item);
1857             }
1858         },
1859
1860         /**
1861          * Clone a flat array without referencing the previous one. Note that this is different
1862          * from Ext.clone since it doesn't handle recursive cloning. It's simply a convenient, easy-to-remember method
1863          * for Array.prototype.slice.call(array)
1864          *
1865          * @param {Array} array The array
1866          * @return {Array} The clone array
1867          */
1868         clone: function(array) {
1869             return slice.call(array);
1870         },
1871
1872         /**
1873          * Merge multiple arrays into one with unique items.
1874          *
1875          * {@link Ext.Array#union} is alias for {@link Ext.Array#merge}
1876          *
1877          * @param {Array} array1
1878          * @param {Array} array2
1879          * @param {Array} etc
1880          * @return {Array} merged
1881          */
1882         merge: function() {
1883             var args = slice.call(arguments),
1884                 array = [],
1885                 i, ln;
1886
1887             for (i = 0, ln = args.length; i < ln; i++) {
1888                 array = array.concat(args[i]);
1889             }
1890
1891             return ExtArray.unique(array);
1892         },
1893
1894         /**
1895          * Merge multiple arrays into one with unique items that exist in all of the arrays.
1896          *
1897          * @param {Array} array1
1898          * @param {Array} array2
1899          * @param {Array} etc
1900          * @return {Array} intersect
1901          */
1902         intersect: function() {
1903             var intersect = [],
1904                 arrays = slice.call(arguments),
1905                 i, j, k, minArray, array, x, y, ln, arraysLn, arrayLn;
1906
1907             if (!arrays.length) {
1908                 return intersect;
1909             }
1910
1911             // Find the smallest array
1912             for (i = x = 0,ln = arrays.length; i < ln,array = arrays[i]; i++) {
1913                 if (!minArray || array.length < minArray.length) {
1914                     minArray = array;
1915                     x = i;
1916                 }
1917             }
1918
1919             minArray = ExtArray.unique(minArray);
1920             erase(arrays, x, 1);
1921
1922             // Use the smallest unique'd array as the anchor loop. If the other array(s) do contain
1923             // an item in the small array, we're likely to find it before reaching the end
1924             // of the inner loop and can terminate the search early.
1925             for (i = 0,ln = minArray.length; i < ln,x = minArray[i]; i++) {
1926                 var count = 0;
1927
1928                 for (j = 0,arraysLn = arrays.length; j < arraysLn,array = arrays[j]; j++) {
1929                     for (k = 0,arrayLn = array.length; k < arrayLn,y = array[k]; k++) {
1930                         if (x === y) {
1931                             count++;
1932                             break;
1933                         }
1934                     }
1935                 }
1936
1937                 if (count === arraysLn) {
1938                     intersect.push(x);
1939                 }
1940             }
1941
1942             return intersect;
1943         },
1944
1945         /**
1946          * Perform a set difference A-B by subtracting all items in array B from array A.
1947          *
1948          * @param {Array} arrayA
1949          * @param {Array} arrayB
1950          * @return {Array} difference
1951          */
1952         difference: function(arrayA, arrayB) {
1953             var clone = slice.call(arrayA),
1954                 ln = clone.length,
1955                 i, j, lnB;
1956
1957             for (i = 0,lnB = arrayB.length; i < lnB; i++) {
1958                 for (j = 0; j < ln; j++) {
1959                     if (clone[j] === arrayB[i]) {
1960                         erase(clone, j, 1);
1961                         j--;
1962                         ln--;
1963                     }
1964                 }
1965             }
1966
1967             return clone;
1968         },
1969
1970         /**
1971          * Returns a shallow copy of a part of an array. This is equivalent to the native
1972          * call "Array.prototype.slice.call(array, begin, end)". This is often used when "array"
1973          * is "arguments" since the arguments object does not supply a slice method but can
1974          * be the context object to Array.prototype.slice.
1975          *
1976          * @param {Array} array The array (or arguments object).
1977          * @param {Number} begin The index at which to begin. Negative values are offsets from
1978          * the end of the array.
1979          * @param {Number} end The index at which to end. The copied items do not include
1980          * end. Negative values are offsets from the end of the array. If end is omitted,
1981          * all items up to the end of the array are copied.
1982          * @return {Array} The copied piece of the array.
1983          */
1984         // Note: IE6 will return [] on slice.call(x, undefined).
1985         slice: ([1,2].slice(1, undefined).length ?
1986             function (array, begin, end) {
1987                 return slice.call(array, begin, end);
1988             } :
1989             // at least IE6 uses arguments.length for variadic signature
1990             function (array, begin, end) {
1991                 // After tested for IE 6, the one below is of the best performance
1992                 // see http://jsperf.com/slice-fix
1993                 if (typeof begin === 'undefined') {
1994                     return slice.call(array);
1995                 }
1996                 if (typeof end === 'undefined') {
1997                     return slice.call(array, begin);
1998                 }
1999                 return slice.call(array, begin, end);
2000             }
2001         ),
2002
2003         /**
2004          * Sorts the elements of an Array.
2005          * By default, this method sorts the elements alphabetically and ascending.
2006          *
2007          * @param {Array} array The array to sort.
2008          * @param {Function} sortFn (optional) The comparison function.
2009          * @return {Array} The sorted array.
2010          */
2011         sort: function(array, sortFn) {
2012             if (supportsSort) {
2013                 if (sortFn) {
2014                     return array.sort(sortFn);
2015                 } else {
2016                     return array.sort();
2017                 }
2018             }
2019
2020             var length = array.length,
2021                 i = 0,
2022                 comparison,
2023                 j, min, tmp;
2024
2025             for (; i < length; i++) {
2026                 min = i;
2027                 for (j = i + 1; j < length; j++) {
2028                     if (sortFn) {
2029                         comparison = sortFn(array[j], array[min]);
2030                         if (comparison < 0) {
2031                             min = j;
2032                         }
2033                     } else if (array[j] < array[min]) {
2034                         min = j;
2035                     }
2036                 }
2037                 if (min !== i) {
2038                     tmp = array[i];
2039                     array[i] = array[min];
2040                     array[min] = tmp;
2041                 }
2042             }
2043
2044             return array;
2045         },
2046
2047         /**
2048          * Recursively flattens into 1-d Array. Injects Arrays inline.
2049          *
2050          * @param {Array} array The array to flatten
2051          * @return {Array} The 1-d array.
2052          */
2053         flatten: function(array) {
2054             var worker = [];
2055
2056             function rFlatten(a) {
2057                 var i, ln, v;
2058
2059                 for (i = 0, ln = a.length; i < ln; i++) {
2060                     v = a[i];
2061
2062                     if (Ext.isArray(v)) {
2063                         rFlatten(v);
2064                     } else {
2065                         worker.push(v);
2066                     }
2067                 }
2068
2069                 return worker;
2070             }
2071
2072             return rFlatten(array);
2073         },
2074
2075         /**
2076          * Returns the minimum value in the Array.
2077          *
2078          * @param {Array/NodeList} array The Array from which to select the minimum value.
2079          * @param {Function} comparisonFn (optional) a function to perform the comparision which determines minimization.
2080          * If omitted the "<" operator will be used. Note: gt = 1; eq = 0; lt = -1
2081          * @return {Object} minValue The minimum value
2082          */
2083         min: function(array, comparisonFn) {
2084             var min = array[0],
2085                 i, ln, item;
2086
2087             for (i = 0, ln = array.length; i < ln; i++) {
2088                 item = array[i];
2089
2090                 if (comparisonFn) {
2091                     if (comparisonFn(min, item) === 1) {
2092                         min = item;
2093                     }
2094                 }
2095                 else {
2096                     if (item < min) {
2097                         min = item;
2098                     }
2099                 }
2100             }
2101
2102             return min;
2103         },
2104
2105         /**
2106          * Returns the maximum value in the Array.
2107          *
2108          * @param {Array/NodeList} array The Array from which to select the maximum value.
2109          * @param {Function} comparisonFn (optional) a function to perform the comparision which determines maximization.
2110          * If omitted the ">" operator will be used. Note: gt = 1; eq = 0; lt = -1
2111          * @return {Object} maxValue The maximum value
2112          */
2113         max: function(array, comparisonFn) {
2114             var max = array[0],
2115                 i, ln, item;
2116
2117             for (i = 0, ln = array.length; i < ln; i++) {
2118                 item = array[i];
2119
2120                 if (comparisonFn) {
2121                     if (comparisonFn(max, item) === -1) {
2122                         max = item;
2123                     }
2124                 }
2125                 else {
2126                     if (item > max) {
2127                         max = item;
2128                     }
2129                 }
2130             }
2131
2132             return max;
2133         },
2134
2135         /**
2136          * Calculates the mean of all items in the array.
2137          *
2138          * @param {Array} array The Array to calculate the mean value of.
2139          * @return {Number} The mean.
2140          */
2141         mean: function(array) {
2142             return array.length > 0 ? ExtArray.sum(array) / array.length : undefined;
2143         },
2144
2145         /**
2146          * Calculates the sum of all items in the given array.
2147          *
2148          * @param {Array} array The Array to calculate the sum value of.
2149          * @return {Number} The sum.
2150          */
2151         sum: function(array) {
2152             var sum = 0,
2153                 i, ln, item;
2154
2155             for (i = 0,ln = array.length; i < ln; i++) {
2156                 item = array[i];
2157
2158                 sum += item;
2159             }
2160
2161             return sum;
2162         },
2163
2164         _replaceSim: replaceSim, // for unit testing
2165         _spliceSim: spliceSim,
2166
2167         /**
2168          * Removes items from an array. This is functionally equivalent to the splice method
2169          * of Array, but works around bugs in IE8's splice method and does not copy the
2170          * removed elements in order to return them (because very often they are ignored).
2171          *
2172          * @param {Array} array The Array on which to replace.
2173          * @param {Number} index The index in the array at which to operate.
2174          * @param {Number} removeCount The number of items to remove at index.
2175          * @return {Array} The array passed.
2176          * @method
2177          */
2178         erase: erase,
2179
2180         /**
2181          * Inserts items in to an array.
2182          *
2183          * @param {Array} array The Array on which to replace.
2184          * @param {Number} index The index in the array at which to operate.
2185          * @param {Array} items The array of items to insert at index.
2186          * @return {Array} The array passed.
2187          */
2188         insert: function (array, index, items) {
2189             return replace(array, index, 0, items);
2190         },
2191
2192         /**
2193          * Replaces items in an array. This is functionally equivalent to the splice method
2194          * of Array, but works around bugs in IE8's splice method and is often more convenient
2195          * to call because it accepts an array of items to insert rather than use a variadic
2196          * argument list.
2197          *
2198          * @param {Array} array The Array on which to replace.
2199          * @param {Number} index The index in the array at which to operate.
2200          * @param {Number} removeCount The number of items to remove at index (can be 0).
2201          * @param {Array} insert (optional) An array of items to insert at index.
2202          * @return {Array} The array passed.
2203          * @method
2204          */
2205         replace: replace,
2206
2207         /**
2208          * Replaces items in an array. This is equivalent to the splice method of Array, but
2209          * works around bugs in IE8's splice method. The signature is exactly the same as the
2210          * splice method except that the array is the first argument. All arguments following
2211          * removeCount are inserted in the array at index.
2212          *
2213          * @param {Array} array The Array on which to replace.
2214          * @param {Number} index The index in the array at which to operate.
2215          * @param {Number} removeCount The number of items to remove at index (can be 0).
2216          * @return {Array} An array containing the removed items.
2217          * @method
2218          */
2219         splice: splice
2220     };
2221
2222     /**
2223      * @method
2224      * @member Ext
2225      * @alias Ext.Array#each
2226      */
2227     Ext.each = ExtArray.each;
2228
2229     /**
2230      * @method
2231      * @member Ext.Array
2232      * @alias Ext.Array#merge
2233      */
2234     ExtArray.union = ExtArray.merge;
2235
2236     /**
2237      * Old alias to {@link Ext.Array#min}
2238      * @deprecated 4.0.0 Use {@link Ext.Array#min} instead
2239      * @method
2240      * @member Ext
2241      * @alias Ext.Array#min
2242      */
2243     Ext.min = ExtArray.min;
2244
2245     /**
2246      * Old alias to {@link Ext.Array#max}
2247      * @deprecated 4.0.0 Use {@link Ext.Array#max} instead
2248      * @method
2249      * @member Ext
2250      * @alias Ext.Array#max
2251      */
2252     Ext.max = ExtArray.max;
2253
2254     /**
2255      * Old alias to {@link Ext.Array#sum}
2256      * @deprecated 4.0.0 Use {@link Ext.Array#sum} instead
2257      * @method
2258      * @member Ext
2259      * @alias Ext.Array#sum
2260      */
2261     Ext.sum = ExtArray.sum;
2262
2263     /**
2264      * Old alias to {@link Ext.Array#mean}
2265      * @deprecated 4.0.0 Use {@link Ext.Array#mean} instead
2266      * @method
2267      * @member Ext
2268      * @alias Ext.Array#mean
2269      */
2270     Ext.mean = ExtArray.mean;
2271
2272     /**
2273      * Old alias to {@link Ext.Array#flatten}
2274      * @deprecated 4.0.0 Use {@link Ext.Array#flatten} instead
2275      * @method
2276      * @member Ext
2277      * @alias Ext.Array#flatten
2278      */
2279     Ext.flatten = ExtArray.flatten;
2280
2281     /**
2282      * Old alias to {@link Ext.Array#clean}
2283      * @deprecated 4.0.0 Use {@link Ext.Array#clean} instead
2284      * @method
2285      * @member Ext
2286      * @alias Ext.Array#clean
2287      */
2288     Ext.clean = ExtArray.clean;
2289
2290     /**
2291      * Old alias to {@link Ext.Array#unique}
2292      * @deprecated 4.0.0 Use {@link Ext.Array#unique} instead
2293      * @method
2294      * @member Ext
2295      * @alias Ext.Array#unique
2296      */
2297     Ext.unique = ExtArray.unique;
2298
2299     /**
2300      * Old alias to {@link Ext.Array#pluck Ext.Array.pluck}
2301      * @deprecated 4.0.0 Use {@link Ext.Array#pluck Ext.Array.pluck} instead
2302      * @method
2303      * @member Ext
2304      * @alias Ext.Array#pluck
2305      */
2306     Ext.pluck = ExtArray.pluck;
2307
2308     /**
2309      * @method
2310      * @member Ext
2311      * @alias Ext.Array#toArray
2312      */
2313     Ext.toArray = function() {
2314         return ExtArray.toArray.apply(ExtArray, arguments);
2315     };
2316 })();
2317
2318 /**
2319  * @class Ext.Function
2320  *
2321  * A collection of useful static methods to deal with function callbacks
2322  * @singleton
2323  */
2324 Ext.Function = {
2325
2326     /**
2327      * A very commonly used method throughout the framework. It acts as a wrapper around another method
2328      * which originally accepts 2 arguments for `name` and `value`.
2329      * The wrapped function then allows "flexible" value setting of either:
2330      *
2331      * - `name` and `value` as 2 arguments
2332      * - one single object argument with multiple key - value pairs
2333      *
2334      * For example:
2335      *
2336      *     var setValue = Ext.Function.flexSetter(function(name, value) {
2337      *         this[name] = value;
2338      *     });
2339      *
2340      *     // Afterwards
2341      *     // Setting a single name - value
2342      *     setValue('name1', 'value1');
2343      *
2344      *     // Settings multiple name - value pairs
2345      *     setValue({
2346      *         name1: 'value1',
2347      *         name2: 'value2',
2348      *         name3: 'value3'
2349      *     });
2350      *
2351      * @param {Function} setter
2352      * @returns {Function} flexSetter
2353      */
2354     flexSetter: function(fn) {
2355         return function(a, b) {
2356             var k, i;
2357
2358             if (a === null) {
2359                 return this;
2360             }
2361
2362             if (typeof a !== 'string') {
2363                 for (k in a) {
2364                     if (a.hasOwnProperty(k)) {
2365                         fn.call(this, k, a[k]);
2366                     }
2367                 }
2368
2369                 if (Ext.enumerables) {
2370                     for (i = Ext.enumerables.length; i--;) {
2371                         k = Ext.enumerables[i];
2372                         if (a.hasOwnProperty(k)) {
2373                             fn.call(this, k, a[k]);
2374                         }
2375                     }
2376                 }
2377             } else {
2378                 fn.call(this, a, b);
2379             }
2380
2381             return this;
2382         };
2383     },
2384
2385     /**
2386      * Create a new function from the provided `fn`, change `this` to the provided scope, optionally
2387      * overrides arguments for the call. (Defaults to the arguments passed by the caller)
2388      *
2389      * {@link Ext#bind Ext.bind} is alias for {@link Ext.Function#bind Ext.Function.bind}
2390      *
2391      * @param {Function} fn The function to delegate.
2392      * @param {Object} scope (optional) The scope (`this` reference) in which the function is executed.
2393      * **If omitted, defaults to the browser window.**
2394      * @param {Array} args (optional) Overrides arguments for the call. (Defaults to the arguments passed by the caller)
2395      * @param {Boolean/Number} appendArgs (optional) if True args are appended to call args instead of overriding,
2396      * if a number the args are inserted at the specified position
2397      * @return {Function} The new function
2398      */
2399     bind: function(fn, scope, args, appendArgs) {
2400         if (arguments.length === 2) {
2401             return function() {
2402                 return fn.apply(scope, arguments);
2403             }
2404         }
2405
2406         var method = fn,
2407             slice = Array.prototype.slice;
2408
2409         return function() {
2410             var callArgs = args || arguments;
2411
2412             if (appendArgs === true) {
2413                 callArgs = slice.call(arguments, 0);
2414                 callArgs = callArgs.concat(args);
2415             }
2416             else if (typeof appendArgs == 'number') {
2417                 callArgs = slice.call(arguments, 0); // copy arguments first
2418                 Ext.Array.insert(callArgs, appendArgs, args);
2419             }
2420
2421             return method.apply(scope || window, callArgs);
2422         };
2423     },
2424
2425     /**
2426      * Create a new function from the provided `fn`, the arguments of which are pre-set to `args`.
2427      * New arguments passed to the newly created callback when it's invoked are appended after the pre-set ones.
2428      * This is especially useful when creating callbacks.
2429      *
2430      * For example:
2431      *
2432      *     var originalFunction = function(){
2433      *         alert(Ext.Array.from(arguments).join(' '));
2434      *     };
2435      *
2436      *     var callback = Ext.Function.pass(originalFunction, ['Hello', 'World']);
2437      *
2438      *     callback(); // alerts 'Hello World'
2439      *     callback('by Me'); // alerts 'Hello World by Me'
2440      *
2441      * {@link Ext#pass Ext.pass} is alias for {@link Ext.Function#pass Ext.Function.pass}
2442      *
2443      * @param {Function} fn The original function
2444      * @param {Array} args The arguments to pass to new callback
2445      * @param {Object} scope (optional) The scope (`this` reference) in which the function is executed.
2446      * @return {Function} The new callback function
2447      */
2448     pass: function(fn, args, scope) {
2449         if (args) {
2450             args = Ext.Array.from(args);
2451         }
2452
2453         return function() {
2454             return fn.apply(scope, args.concat(Ext.Array.toArray(arguments)));
2455         };
2456     },
2457
2458     /**
2459      * Create an alias to the provided method property with name `methodName` of `object`.
2460      * Note that the execution scope will still be bound to the provided `object` itself.
2461      *
2462      * @param {Object/Function} object
2463      * @param {String} methodName
2464      * @return {Function} aliasFn
2465      */
2466     alias: function(object, methodName) {
2467         return function() {
2468             return object[methodName].apply(object, arguments);
2469         };
2470     },
2471
2472     /**
2473      * Creates an interceptor function. The passed function is called before the original one. If it returns false,
2474      * the original one is not called. The resulting function returns the results of the original function.
2475      * The passed function is called with the parameters of the original function. Example usage:
2476      *
2477      *     var sayHi = function(name){
2478      *         alert('Hi, ' + name);
2479      *     }
2480      *
2481      *     sayHi('Fred'); // alerts "Hi, Fred"
2482      *
2483      *     // create a new function that validates input without
2484      *     // directly modifying the original function:
2485      *     var sayHiToFriend = Ext.Function.createInterceptor(sayHi, function(name){
2486      *         return name == 'Brian';
2487      *     });
2488      *
2489      *     sayHiToFriend('Fred');  // no alert
2490      *     sayHiToFriend('Brian'); // alerts "Hi, Brian"
2491      *
2492      * @param {Function} origFn The original function.
2493      * @param {Function} newFn The function to call before the original
2494      * @param {Object} scope (optional) The scope (`this` reference) in which the passed function is executed.
2495      * **If omitted, defaults to the scope in which the original function is called or the browser window.**
2496      * @param {Object} returnValue (optional) The value to return if the passed function return false (defaults to null).
2497      * @return {Function} The new function
2498      */
2499     createInterceptor: function(origFn, newFn, scope, returnValue) {
2500         var method = origFn;
2501         if (!Ext.isFunction(newFn)) {
2502             return origFn;
2503         }
2504         else {
2505             return function() {
2506                 var me = this,
2507                     args = arguments;
2508                 newFn.target = me;
2509                 newFn.method = origFn;
2510                 return (newFn.apply(scope || me || window, args) !== false) ? origFn.apply(me || window, args) : returnValue || null;
2511             };
2512         }
2513     },
2514
2515     /**
2516      * Creates a delegate (callback) which, when called, executes after a specific delay.
2517      *
2518      * @param {Function} fn The function which will be called on a delay when the returned function is called.
2519      * Optionally, a replacement (or additional) argument list may be specified.
2520      * @param {Number} delay The number of milliseconds to defer execution by whenever called.
2521      * @param {Object} scope (optional) The scope (`this` reference) used by the function at execution time.
2522      * @param {Array} args (optional) Override arguments for the call. (Defaults to the arguments passed by the caller)
2523      * @param {Boolean/Number} appendArgs (optional) if True args are appended to call args instead of overriding,
2524      * if a number the args are inserted at the specified position.
2525      * @return {Function} A function which, when called, executes the original function after the specified delay.
2526      */
2527     createDelayed: function(fn, delay, scope, args, appendArgs) {
2528         if (scope || args) {
2529             fn = Ext.Function.bind(fn, scope, args, appendArgs);
2530         }
2531         return function() {
2532             var me = this;
2533             setTimeout(function() {
2534                 fn.apply(me, arguments);
2535             }, delay);
2536         };
2537     },
2538
2539     /**
2540      * Calls this function after the number of millseconds specified, optionally in a specific scope. Example usage:
2541      *
2542      *     var sayHi = function(name){
2543      *         alert('Hi, ' + name);
2544      *     }
2545      *
2546      *     // executes immediately:
2547      *     sayHi('Fred');
2548      *
2549      *     // executes after 2 seconds:
2550      *     Ext.Function.defer(sayHi, 2000, this, ['Fred']);
2551      *
2552      *     // this syntax is sometimes useful for deferring
2553      *     // execution of an anonymous function:
2554      *     Ext.Function.defer(function(){
2555      *         alert('Anonymous');
2556      *     }, 100);
2557      *
2558      * {@link Ext#defer Ext.defer} is alias for {@link Ext.Function#defer Ext.Function.defer}
2559      *
2560      * @param {Function} fn The function to defer.
2561      * @param {Number} millis The number of milliseconds for the setTimeout call
2562      * (if less than or equal to 0 the function is executed immediately)
2563      * @param {Object} scope (optional) The scope (`this` reference) in which the function is executed.
2564      * **If omitted, defaults to the browser window.**
2565      * @param {Array} args (optional) Overrides arguments for the call. (Defaults to the arguments passed by the caller)
2566      * @param {Boolean/Number} appendArgs (optional) if True args are appended to call args instead of overriding,
2567      * if a number the args are inserted at the specified position
2568      * @return {Number} The timeout id that can be used with clearTimeout
2569      */
2570     defer: function(fn, millis, obj, args, appendArgs) {
2571         fn = Ext.Function.bind(fn, obj, args, appendArgs);
2572         if (millis > 0) {
2573             return setTimeout(fn, millis);
2574         }
2575         fn();
2576         return 0;
2577     },
2578
2579     /**
2580      * Create a combined function call sequence of the original function + the passed function.
2581      * The resulting function returns the results of the original function.
2582      * The passed function is called with the parameters of the original function. Example usage:
2583      *
2584      *     var sayHi = function(name){
2585      *         alert('Hi, ' + name);
2586      *     }
2587      *
2588      *     sayHi('Fred'); // alerts "Hi, Fred"
2589      *
2590      *     var sayGoodbye = Ext.Function.createSequence(sayHi, function(name){
2591      *         alert('Bye, ' + name);
2592      *     });
2593      *
2594      *     sayGoodbye('Fred'); // both alerts show
2595      *
2596      * @param {Function} origFn The original function.
2597      * @param {Function} newFn The function to sequence
2598      * @param {Object} scope (optional) The scope (`this` reference) in which the passed function is executed.
2599      * If omitted, defaults to the scope in which the original function is called or the browser window.
2600      * @return {Function} The new function
2601      */
2602     createSequence: function(origFn, newFn, scope) {
2603         if (!Ext.isFunction(newFn)) {
2604             return origFn;
2605         }
2606         else {
2607             return function() {
2608                 var retval = origFn.apply(this || window, arguments);
2609                 newFn.apply(scope || this || window, arguments);
2610                 return retval;
2611             };
2612         }
2613     },
2614
2615     /**
2616      * Creates a delegate function, optionally with a bound scope which, when called, buffers
2617      * the execution of the passed function for the configured number of milliseconds.
2618      * If called again within that period, the impending invocation will be canceled, and the
2619      * timeout period will begin again.
2620      *
2621      * @param {Function} fn The function to invoke on a buffered timer.
2622      * @param {Number} buffer The number of milliseconds by which to buffer the invocation of the
2623      * function.
2624      * @param {Object} scope (optional) The scope (`this` reference) in which
2625      * the passed function is executed. If omitted, defaults to the scope specified by the caller.
2626      * @param {Array} args (optional) Override arguments for the call. Defaults to the arguments
2627      * passed by the caller.
2628      * @return {Function} A function which invokes the passed function after buffering for the specified time.
2629      */
2630     createBuffered: function(fn, buffer, scope, args) {
2631         return function(){
2632             var timerId;
2633             return function() {
2634                 var me = this;
2635                 if (timerId) {
2636                     clearTimeout(timerId);
2637                     timerId = null;
2638                 }
2639                 timerId = setTimeout(function(){
2640                     fn.apply(scope || me, args || arguments);
2641                 }, buffer);
2642             };
2643         }();
2644     },
2645
2646     /**
2647      * Creates a throttled version of the passed function which, when called repeatedly and
2648      * rapidly, invokes the passed function only after a certain interval has elapsed since the
2649      * previous invocation.
2650      *
2651      * This is useful for wrapping functions which may be called repeatedly, such as
2652      * a handler of a mouse move event when the processing is expensive.
2653      *
2654      * @param {Function} fn The function to execute at a regular time interval.
2655      * @param {Number} interval The interval **in milliseconds** on which the passed function is executed.
2656      * @param {Object} scope (optional) The scope (`this` reference) in which
2657      * the passed function is executed. If omitted, defaults to the scope specified by the caller.
2658      * @returns {Function} A function which invokes the passed function at the specified interval.
2659      */
2660     createThrottled: function(fn, interval, scope) {
2661         var lastCallTime, elapsed, lastArgs, timer, execute = function() {
2662             fn.apply(scope || this, lastArgs);
2663             lastCallTime = new Date().getTime();
2664         };
2665
2666         return function() {
2667             elapsed = new Date().getTime() - lastCallTime;
2668             lastArgs = arguments;
2669
2670             clearTimeout(timer);
2671             if (!lastCallTime || (elapsed >= interval)) {
2672                 execute();
2673             } else {
2674                 timer = setTimeout(execute, interval - elapsed);
2675             }
2676         };
2677     },
2678
2679     /**
2680      * Adds behavior to an existing method that is executed before the
2681      * original behavior of the function.  For example:
2682      * 
2683      *     var soup = {
2684      *         contents: [],
2685      *         add: function(ingredient) {
2686      *             this.contents.push(ingredient);
2687      *         }
2688      *     };
2689      *     Ext.Function.interceptBefore(soup, "add", function(ingredient){
2690      *         if (!this.contents.length && ingredient !== "water") {
2691      *             // Always add water to start with
2692      *             this.contents.push("water");
2693      *         }
2694      *     });
2695      *     soup.add("onions");
2696      *     soup.add("salt");
2697      *     soup.contents; // will contain: water, onions, salt
2698      * 
2699      * @param {Object} object The target object
2700      * @param {String} methodName Name of the method to override
2701      * @param {Function} fn Function with the new behavior.  It will
2702      * be called with the same arguments as the original method.  The
2703      * return value of this function will be the return value of the
2704      * new method.
2705      * @return {Function} The new function just created.
2706      */
2707     interceptBefore: function(object, methodName, fn) {
2708         var method = object[methodName] || Ext.emptyFn;
2709
2710         return object[methodName] = function() {
2711             var ret = fn.apply(this, arguments);
2712             method.apply(this, arguments);
2713
2714             return ret;
2715         };
2716     },
2717
2718     /**
2719      * Adds behavior to an existing method that is executed after the
2720      * original behavior of the function.  For example:
2721      * 
2722      *     var soup = {
2723      *         contents: [],
2724      *         add: function(ingredient) {
2725      *             this.contents.push(ingredient);
2726      *         }
2727      *     };
2728      *     Ext.Function.interceptAfter(soup, "add", function(ingredient){
2729      *         // Always add a bit of extra salt
2730      *         this.contents.push("salt");
2731      *     });
2732      *     soup.add("water");
2733      *     soup.add("onions");
2734      *     soup.contents; // will contain: water, salt, onions, salt
2735      * 
2736      * @param {Object} object The target object
2737      * @param {String} methodName Name of the method to override
2738      * @param {Function} fn Function with the new behavior.  It will
2739      * be called with the same arguments as the original method.  The
2740      * return value of this function will be the return value of the
2741      * new method.
2742      * @return {Function} The new function just created.
2743      */
2744     interceptAfter: function(object, methodName, fn) {
2745         var method = object[methodName] || Ext.emptyFn;
2746
2747         return object[methodName] = function() {
2748             method.apply(this, arguments);
2749             return fn.apply(this, arguments);
2750         };
2751     }
2752 };
2753
2754 /**
2755  * @method
2756  * @member Ext
2757  * @alias Ext.Function#defer
2758  */
2759 Ext.defer = Ext.Function.alias(Ext.Function, 'defer');
2760
2761 /**
2762  * @method
2763  * @member Ext
2764  * @alias Ext.Function#pass
2765  */
2766 Ext.pass = Ext.Function.alias(Ext.Function, 'pass');
2767
2768 /**
2769  * @method
2770  * @member Ext
2771  * @alias Ext.Function#bind
2772  */
2773 Ext.bind = Ext.Function.alias(Ext.Function, 'bind');
2774
2775 /**
2776  * @author Jacky Nguyen <jacky@sencha.com>
2777  * @docauthor Jacky Nguyen <jacky@sencha.com>
2778  * @class Ext.Object
2779  *
2780  * A collection of useful static methods to deal with objects.
2781  *
2782  * @singleton
2783  */
2784
2785 (function() {
2786
2787 var ExtObject = Ext.Object = {
2788
2789     /**
2790      * Converts a `name` - `value` pair to an array of objects with support for nested structures. Useful to construct
2791      * query strings. For example:
2792      *
2793      *     var objects = Ext.Object.toQueryObjects('hobbies', ['reading', 'cooking', 'swimming']);
2794      *
2795      *     // objects then equals:
2796      *     [
2797      *         { name: 'hobbies', value: 'reading' },
2798      *         { name: 'hobbies', value: 'cooking' },
2799      *         { name: 'hobbies', value: 'swimming' },
2800      *     ];
2801      *
2802      *     var objects = Ext.Object.toQueryObjects('dateOfBirth', {
2803      *         day: 3,
2804      *         month: 8,
2805      *         year: 1987,
2806      *         extra: {
2807      *             hour: 4
2808      *             minute: 30
2809      *         }
2810      *     }, true); // Recursive
2811      *
2812      *     // objects then equals:
2813      *     [
2814      *         { name: 'dateOfBirth[day]', value: 3 },
2815      *         { name: 'dateOfBirth[month]', value: 8 },
2816      *         { name: 'dateOfBirth[year]', value: 1987 },
2817      *         { name: 'dateOfBirth[extra][hour]', value: 4 },
2818      *         { name: 'dateOfBirth[extra][minute]', value: 30 },
2819      *     ];
2820      *
2821      * @param {String} name
2822      * @param {Object/Array} value
2823      * @param {Boolean} [recursive=false] True to traverse object recursively
2824      * @return {Array}
2825      */
2826     toQueryObjects: function(name, value, recursive) {
2827         var self = ExtObject.toQueryObjects,
2828             objects = [],
2829             i, ln;
2830
2831         if (Ext.isArray(value)) {
2832             for (i = 0, ln = value.length; i < ln; i++) {
2833                 if (recursive) {
2834                     objects = objects.concat(self(name + '[' + i + ']', value[i], true));
2835                 }
2836                 else {
2837                     objects.push({
2838                         name: name,
2839                         value: value[i]
2840                     });
2841                 }
2842             }
2843         }
2844         else if (Ext.isObject(value)) {
2845             for (i in value) {
2846                 if (value.hasOwnProperty(i)) {
2847                     if (recursive) {
2848                         objects = objects.concat(self(name + '[' + i + ']', value[i], true));
2849                     }
2850                     else {
2851                         objects.push({
2852                             name: name,
2853                             value: value[i]
2854                         });
2855                     }
2856                 }
2857             }
2858         }
2859         else {
2860             objects.push({
2861                 name: name,
2862                 value: value
2863             });
2864         }
2865
2866         return objects;
2867     },
2868
2869     /**
2870      * Takes an object and converts it to an encoded query string.
2871      *
2872      * Non-recursive:
2873      *
2874      *     Ext.Object.toQueryString({foo: 1, bar: 2}); // returns "foo=1&bar=2"
2875      *     Ext.Object.toQueryString({foo: null, bar: 2}); // returns "foo=&bar=2"
2876      *     Ext.Object.toQueryString({'some price': '$300'}); // returns "some%20price=%24300"
2877      *     Ext.Object.toQueryString({date: new Date(2011, 0, 1)}); // returns "date=%222011-01-01T00%3A00%3A00%22"
2878      *     Ext.Object.toQueryString({colors: ['red', 'green', 'blue']}); // returns "colors=red&colors=green&colors=blue"
2879      *
2880      * Recursive:
2881      *
2882      *     Ext.Object.toQueryString({
2883      *         username: 'Jacky',
2884      *         dateOfBirth: {
2885      *             day: 1,
2886      *             month: 2,
2887      *             year: 1911
2888      *         },
2889      *         hobbies: ['coding', 'eating', 'sleeping', ['nested', 'stuff']]
2890      *     }, true); // returns the following string (broken down and url-decoded for ease of reading purpose):
2891      *     // username=Jacky
2892      *     //    &dateOfBirth[day]=1&dateOfBirth[month]=2&dateOfBirth[year]=1911
2893      *     //    &hobbies[0]=coding&hobbies[1]=eating&hobbies[2]=sleeping&hobbies[3][0]=nested&hobbies[3][1]=stuff
2894      *
2895      * @param {Object} object The object to encode
2896      * @param {Boolean} [recursive=false] Whether or not to interpret the object in recursive format.
2897      * (PHP / Ruby on Rails servers and similar).
2898      * @return {String} queryString
2899      */
2900     toQueryString: function(object, recursive) {
2901         var paramObjects = [],
2902             params = [],
2903             i, j, ln, paramObject, value;
2904
2905         for (i in object) {
2906             if (object.hasOwnProperty(i)) {
2907                 paramObjects = paramObjects.concat(ExtObject.toQueryObjects(i, object[i], recursive));
2908             }
2909         }
2910
2911         for (j = 0, ln = paramObjects.length; j < ln; j++) {
2912             paramObject = paramObjects[j];
2913             value = paramObject.value;
2914
2915             if (Ext.isEmpty(value)) {
2916                 value = '';
2917             }
2918             else if (Ext.isDate(value)) {
2919                 value = Ext.Date.toString(value);
2920             }
2921
2922             params.push(encodeURIComponent(paramObject.name) + '=' + encodeURIComponent(String(value)));
2923         }
2924
2925         return params.join('&');
2926     },
2927
2928     /**
2929      * Converts a query string back into an object.
2930      *
2931      * Non-recursive:
2932      *
2933      *     Ext.Object.fromQueryString(foo=1&bar=2); // returns {foo: 1, bar: 2}
2934      *     Ext.Object.fromQueryString(foo=&bar=2); // returns {foo: null, bar: 2}
2935      *     Ext.Object.fromQueryString(some%20price=%24300); // returns {'some price': '$300'}
2936      *     Ext.Object.fromQueryString(colors=red&colors=green&colors=blue); // returns {colors: ['red', 'green', 'blue']}
2937      *
2938      * Recursive:
2939      *
2940      *       Ext.Object.fromQueryString("username=Jacky&dateOfBirth[day]=1&dateOfBirth[month]=2&dateOfBirth[year]=1911&hobbies[0]=coding&hobbies[1]=eating&hobbies[2]=sleeping&hobbies[3][0]=nested&hobbies[3][1]=stuff", true);
2941      *     // returns
2942      *     {
2943      *         username: 'Jacky',
2944      *         dateOfBirth: {
2945      *             day: '1',
2946      *             month: '2',
2947      *             year: '1911'
2948      *         },
2949      *         hobbies: ['coding', 'eating', 'sleeping', ['nested', 'stuff']]
2950      *     }
2951      *
2952      * @param {String} queryString The query string to decode
2953      * @param {Boolean} [recursive=false] Whether or not to recursively decode the string. This format is supported by
2954      * PHP / Ruby on Rails servers and similar.
2955      * @return {Object}
2956      */
2957     fromQueryString: function(queryString, recursive) {
2958         var parts = queryString.replace(/^\?/, '').split('&'),
2959             object = {},
2960             temp, components, name, value, i, ln,
2961             part, j, subLn, matchedKeys, matchedName,
2962             keys, key, nextKey;
2963
2964         for (i = 0, ln = parts.length; i < ln; i++) {
2965             part = parts[i];
2966
2967             if (part.length > 0) {
2968                 components = part.split('=');
2969                 name = decodeURIComponent(components[0]);
2970                 value = (components[1] !== undefined) ? decodeURIComponent(components[1]) : '';
2971
2972                 if (!recursive) {
2973                     if (object.hasOwnProperty(name)) {
2974                         if (!Ext.isArray(object[name])) {
2975                             object[name] = [object[name]];
2976                         }
2977
2978                         object[name].push(value);
2979                     }
2980                     else {
2981                         object[name] = value;
2982                     }
2983                 }
2984                 else {
2985                     matchedKeys = name.match(/(\[):?([^\]]*)\]/g);
2986                     matchedName = name.match(/^([^\[]+)/);
2987
2988                     if (!matchedName) {
2989                         Ext.Error.raise({
2990                             sourceClass: "Ext.Object",
2991                             sourceMethod: "fromQueryString",
2992                             queryString: queryString,
2993                             recursive: recursive,
2994                             msg: 'Malformed query string given, failed parsing name from "' + part + '"'
2995                         });
2996                     }
2997
2998                     name = matchedName[0];
2999                     keys = [];
3000
3001                     if (matchedKeys === null) {
3002                         object[name] = value;
3003                         continue;
3004                     }
3005
3006                     for (j = 0, subLn = matchedKeys.length; j < subLn; j++) {
3007                         key = matchedKeys[j];
3008                         key = (key.length === 2) ? '' : key.substring(1, key.length - 1);
3009                         keys.push(key);
3010                     }
3011
3012                     keys.unshift(name);
3013
3014                     temp = object;
3015
3016                     for (j = 0, subLn = keys.length; j < subLn; j++) {
3017                         key = keys[j];
3018
3019                         if (j === subLn - 1) {
3020                             if (Ext.isArray(temp) && key === '') {
3021                                 temp.push(value);
3022                             }
3023                             else {
3024                                 temp[key] = value;
3025                             }
3026                         }
3027                         else {
3028                             if (temp[key] === undefined || typeof temp[key] === 'string') {
3029                                 nextKey = keys[j+1];
3030
3031                                 temp[key] = (Ext.isNumeric(nextKey) || nextKey === '') ? [] : {};
3032                             }
3033
3034                             temp = temp[key];
3035                         }
3036                     }
3037                 }
3038             }
3039         }
3040
3041         return object;
3042     },
3043
3044     /**
3045      * Iterates through an object and invokes the given callback function for each iteration.
3046      * The iteration can be stopped by returning `false` in the callback function. For example:
3047      *
3048      *     var person = {
3049      *         name: 'Jacky'
3050      *         hairColor: 'black'
3051      *         loves: ['food', 'sleeping', 'wife']
3052      *     };
3053      *
3054      *     Ext.Object.each(person, function(key, value, myself) {
3055      *         console.log(key + ":" + value);
3056      *
3057      *         if (key === 'hairColor') {
3058      *             return false; // stop the iteration
3059      *         }
3060      *     });
3061      *
3062      * @param {Object} object The object to iterate
3063      * @param {Function} fn The callback function.
3064      * @param {String} fn.key
3065      * @param {Object} fn.value
3066      * @param {Object} fn.object The object itself
3067      * @param {Object} [scope] The execution scope (`this`) of the callback function
3068      */
3069     each: function(object, fn, scope) {
3070         for (var property in object) {
3071             if (object.hasOwnProperty(property)) {
3072                 if (fn.call(scope || object, property, object[property], object) === false) {
3073                     return;
3074                 }
3075             }
3076         }
3077     },
3078
3079     /**
3080      * Merges any number of objects recursively without referencing them or their children.
3081      *
3082      *     var extjs = {
3083      *         companyName: 'Ext JS',
3084      *         products: ['Ext JS', 'Ext GWT', 'Ext Designer'],
3085      *         isSuperCool: true
3086      *         office: {
3087      *             size: 2000,
3088      *             location: 'Palo Alto',
3089      *             isFun: true
3090      *         }
3091      *     };
3092      *
3093      *     var newStuff = {
3094      *         companyName: 'Sencha Inc.',
3095      *         products: ['Ext JS', 'Ext GWT', 'Ext Designer', 'Sencha Touch', 'Sencha Animator'],
3096      *         office: {
3097      *             size: 40000,
3098      *             location: 'Redwood City'
3099      *         }
3100      *     };
3101      *
3102      *     var sencha = Ext.Object.merge(extjs, newStuff);
3103      *
3104      *     // extjs and sencha then equals to
3105      *     {
3106      *         companyName: 'Sencha Inc.',
3107      *         products: ['Ext JS', 'Ext GWT', 'Ext Designer', 'Sencha Touch', 'Sencha Animator'],
3108      *         isSuperCool: true
3109      *         office: {
3110      *             size: 30000,
3111      *             location: 'Redwood City'
3112      *             isFun: true
3113      *         }
3114      *     }
3115      *
3116      * @param {Object...} object Any number of objects to merge.
3117      * @return {Object} merged The object that is created as a result of merging all the objects passed in.
3118      */
3119     merge: function(source, key, value) {
3120         if (typeof key === 'string') {
3121             if (value && value.constructor === Object) {
3122                 if (source[key] && source[key].constructor === Object) {
3123                     ExtObject.merge(source[key], value);
3124                 }
3125                 else {
3126                     source[key] = Ext.clone(value);
3127                 }
3128             }
3129             else {
3130                 source[key] = value;
3131             }
3132
3133             return source;
3134         }
3135
3136         var i = 1,
3137             ln = arguments.length,
3138             object, property;
3139
3140         for (; i < ln; i++) {
3141             object = arguments[i];
3142
3143             for (property in object) {
3144                 if (object.hasOwnProperty(property)) {
3145                     ExtObject.merge(source, property, object[property]);
3146                 }
3147             }
3148         }
3149
3150         return source;
3151     },
3152
3153     /**
3154      * Returns the first matching key corresponding to the given value.
3155      * If no matching value is found, null is returned.
3156      *
3157      *     var person = {
3158      *         name: 'Jacky',
3159      *         loves: 'food'
3160      *     };
3161      *
3162      *     alert(Ext.Object.getKey(person, 'food')); // alerts 'loves'
3163      *
3164      * @param {Object} object
3165      * @param {Object} value The value to find
3166      */
3167     getKey: function(object, value) {
3168         for (var property in object) {
3169             if (object.hasOwnProperty(property) && object[property] === value) {
3170                 return property;
3171             }
3172         }
3173
3174         return null;
3175     },
3176
3177     /**
3178      * Gets all values of the given object as an array.
3179      *
3180      *     var values = Ext.Object.getValues({
3181      *         name: 'Jacky',
3182      *         loves: 'food'
3183      *     }); // ['Jacky', 'food']
3184      *
3185      * @param {Object} object
3186      * @return {Array} An array of values from the object
3187      */
3188     getValues: function(object) {
3189         var values = [],
3190             property;
3191
3192         for (property in object) {
3193             if (object.hasOwnProperty(property)) {
3194                 values.push(object[property]);
3195             }
3196         }
3197
3198         return values;
3199     },
3200
3201     /**
3202      * Gets all keys of the given object as an array.
3203      *
3204      *     var values = Ext.Object.getKeys({
3205      *         name: 'Jacky',
3206      *         loves: 'food'
3207      *     }); // ['name', 'loves']
3208      *
3209      * @param {Object} object
3210      * @return {String[]} An array of keys from the object
3211      * @method
3212      */
3213     getKeys: ('keys' in Object.prototype) ? Object.keys : function(object) {
3214         var keys = [],
3215             property;
3216
3217         for (property in object) {
3218             if (object.hasOwnProperty(property)) {
3219                 keys.push(property);
3220             }
3221         }
3222
3223         return keys;
3224     },
3225
3226     /**
3227      * Gets the total number of this object's own properties
3228      *
3229      *     var size = Ext.Object.getSize({
3230      *         name: 'Jacky',
3231      *         loves: 'food'
3232      *     }); // size equals 2
3233      *
3234      * @param {Object} object
3235      * @return {Number} size
3236      */
3237     getSize: function(object) {
3238         var size = 0,
3239             property;
3240
3241         for (property in object) {
3242             if (object.hasOwnProperty(property)) {
3243                 size++;
3244             }
3245         }
3246
3247         return size;
3248     }
3249 };
3250
3251
3252 /**
3253  * A convenient alias method for {@link Ext.Object#merge}.
3254  *
3255  * @member Ext
3256  * @method merge
3257  * @alias Ext.Object#merge
3258  */
3259 Ext.merge = Ext.Object.merge;
3260
3261 /**
3262  * Alias for {@link Ext.Object#toQueryString}.
3263  *
3264  * @member Ext
3265  * @method urlEncode
3266  * @alias Ext.Object#toQueryString
3267  * @deprecated 4.0.0 Use {@link Ext.Object#toQueryString} instead
3268  */
3269 Ext.urlEncode = function() {
3270     var args = Ext.Array.from(arguments),
3271         prefix = '';
3272
3273     // Support for the old `pre` argument
3274     if ((typeof args[1] === 'string')) {
3275         prefix = args[1] + '&';
3276         args[1] = false;
3277     }
3278
3279     return prefix + Ext.Object.toQueryString.apply(Ext.Object, args);
3280 };
3281
3282 /**
3283  * Alias for {@link Ext.Object#fromQueryString}.
3284  *
3285  * @member Ext
3286  * @method urlDecode
3287  * @alias Ext.Object#fromQueryString
3288  * @deprecated 4.0.0 Use {@link Ext.Object#fromQueryString} instead
3289  */
3290 Ext.urlDecode = function() {
3291     return Ext.Object.fromQueryString.apply(Ext.Object, arguments);
3292 };
3293
3294 })();
3295
3296 /**
3297  * @class Ext.Date
3298  * A set of useful static methods to deal with date
3299  * Note that if Ext.Date is required and loaded, it will copy all methods / properties to
3300  * this object for convenience
3301  *
3302  * The date parsing and formatting syntax contains a subset of
3303  * <a href="http://www.php.net/date">PHP's date() function</a>, and the formats that are
3304  * supported will provide results equivalent to their PHP versions.
3305  *
3306  * The following is a list of all currently supported formats:
3307  * <pre class="">
3308 Format  Description                                                               Example returned values
3309 ------  -----------------------------------------------------------------------   -----------------------
3310   d     Day of the month, 2 digits with leading zeros                             01 to 31
3311   D     A short textual representation of the day of the week                     Mon to Sun
3312   j     Day of the month without leading zeros                                    1 to 31
3313   l     A full textual representation of the day of the week                      Sunday to Saturday
3314   N     ISO-8601 numeric representation of the day of the week                    1 (for Monday) through 7 (for Sunday)
3315   S     English ordinal suffix for the day of the month, 2 characters             st, nd, rd or th. Works well with j
3316   w     Numeric representation of the day of the week                             0 (for Sunday) to 6 (for Saturday)
3317   z     The day of the year (starting from 0)                                     0 to 364 (365 in leap years)
3318   W     ISO-8601 week number of year, weeks starting on Monday                    01 to 53
3319   F     A full textual representation of a month, such as January or March        January to December
3320   m     Numeric representation of a month, with leading zeros                     01 to 12
3321   M     A short textual representation of a month                                 Jan to Dec
3322   n     Numeric representation of a month, without leading zeros                  1 to 12
3323   t     Number of days in the given month                                         28 to 31
3324   L     Whether it&#39;s a leap year                                                  1 if it is a leap year, 0 otherwise.
3325   o     ISO-8601 year number (identical to (Y), but if the ISO week number (W)    Examples: 1998 or 2004
3326         belongs to the previous or next year, that year is used instead)
3327   Y     A full numeric representation of a year, 4 digits                         Examples: 1999 or 2003
3328   y     A two digit representation of a year                                      Examples: 99 or 03
3329   a     Lowercase Ante meridiem and Post meridiem                                 am or pm
3330   A     Uppercase Ante meridiem and Post meridiem                                 AM or PM
3331   g     12-hour format of an hour without leading zeros                           1 to 12
3332   G     24-hour format of an hour without leading zeros                           0 to 23
3333   h     12-hour format of an hour with leading zeros                              01 to 12
3334   H     24-hour format of an hour with leading zeros                              00 to 23
3335   i     Minutes, with leading zeros                                               00 to 59
3336   s     Seconds, with leading zeros                                               00 to 59
3337   u     Decimal fraction of a second                                              Examples:
3338         (minimum 1 digit, arbitrary number of digits allowed)                     001 (i.e. 0.001s) or
3339                                                                                   100 (i.e. 0.100s) or
3340                                                                                   999 (i.e. 0.999s) or
3341                                                                                   999876543210 (i.e. 0.999876543210s)
3342   O     Difference to Greenwich time (GMT) in hours and minutes                   Example: +1030
3343   P     Difference to Greenwich time (GMT) with colon between hours and minutes   Example: -08:00
3344   T     Timezone abbreviation of the machine running the code                     Examples: EST, MDT, PDT ...
3345   Z     Timezone offset in seconds (negative if west of UTC, positive if east)    -43200 to 50400
3346   c     ISO 8601 date
3347         Notes:                                                                    Examples:
3348         1) If unspecified, the month / day defaults to the current month / day,   1991 or
3349            the time defaults to midnight, while the timezone defaults to the      1992-10 or
3350            browser's timezone. If a time is specified, it must include both hours 1993-09-20 or
3351            and minutes. The "T" delimiter, seconds, milliseconds and timezone     1994-08-19T16:20+01:00 or
3352            are optional.                                                          1995-07-18T17:21:28-02:00 or
3353         2) The decimal fraction of a second, if specified, must contain at        1996-06-17T18:22:29.98765+03:00 or
3354            least 1 digit (there is no limit to the maximum number                 1997-05-16T19:23:30,12345-0400 or
3355            of digits allowed), and may be delimited by either a '.' or a ','      1998-04-15T20:24:31.2468Z or
3356         Refer to the examples on the right for the various levels of              1999-03-14T20:24:32Z or
3357         date-time granularity which are supported, or see                         2000-02-13T21:25:33
3358         http://www.w3.org/TR/NOTE-datetime for more info.                         2001-01-12 22:26:34
3359   U     Seconds since the Unix Epoch (January 1 1970 00:00:00 GMT)                1193432466 or -2138434463
3360   MS    Microsoft AJAX serialized dates                                           \/Date(1238606590509)\/ (i.e. UTC milliseconds since epoch) or
3361                                                                                   \/Date(1238606590509+0800)\/
3362 </pre>
3363  *
3364  * Example usage (note that you must escape format specifiers with '\\' to render them as character literals):
3365  * <pre><code>
3366 // Sample date:
3367 // 'Wed Jan 10 2007 15:05:01 GMT-0600 (Central Standard Time)'
3368
3369 var dt = new Date('1/10/2007 03:05:01 PM GMT-0600');
3370 console.log(Ext.Date.format(dt, 'Y-m-d'));                          // 2007-01-10
3371 console.log(Ext.Date.format(dt, 'F j, Y, g:i a'));                  // January 10, 2007, 3:05 pm
3372 console.log(Ext.Date.format(dt, 'l, \\t\\he jS \\of F Y h:i:s A')); // Wednesday, the 10th of January 2007 03:05:01 PM
3373 </code></pre>
3374  *
3375  * Here are some standard date/time patterns that you might find helpful.  They
3376  * are not part of the source of Ext.Date, but to use them you can simply copy this
3377  * block of code into any script that is included after Ext.Date and they will also become
3378  * globally available on the Date object.  Feel free to add or remove patterns as needed in your code.
3379  * <pre><code>
3380 Ext.Date.patterns = {
3381     ISO8601Long:"Y-m-d H:i:s",
3382     ISO8601Short:"Y-m-d",
3383     ShortDate: "n/j/Y",
3384     LongDate: "l, F d, Y",
3385     FullDateTime: "l, F d, Y g:i:s A",
3386     MonthDay: "F d",
3387     ShortTime: "g:i A",
3388     LongTime: "g:i:s A",
3389     SortableDateTime: "Y-m-d\\TH:i:s",
3390     UniversalSortableDateTime: "Y-m-d H:i:sO",
3391     YearMonth: "F, Y"
3392 };
3393 </code></pre>
3394  *
3395  * Example usage:
3396  * <pre><code>
3397 var dt = new Date();
3398 console.log(Ext.Date.format(dt, Ext.Date.patterns.ShortDate));
3399 </code></pre>
3400  * <p>Developer-written, custom formats may be used by supplying both a formatting and a parsing function
3401  * which perform to specialized requirements. The functions are stored in {@link #parseFunctions} and {@link #formatFunctions}.</p>
3402  * @singleton
3403  */
3404
3405 /*
3406  * Most of the date-formatting functions below are the excellent work of Baron Schwartz.
3407  * (see http://www.xaprb.com/blog/2005/12/12/javascript-closures-for-runtime-efficiency/)
3408  * They generate precompiled functions from format patterns instead of parsing and
3409  * processing each pattern every time a date is formatted. These functions are available
3410  * on every Date object.
3411  */
3412
3413 (function() {
3414
3415 // create private copy of Ext's Ext.util.Format.format() method
3416 // - to remove unnecessary dependency
3417 // - to resolve namespace conflict with MS-Ajax's implementation
3418 function xf(format) {
3419     var args = Array.prototype.slice.call(arguments, 1);
3420     return format.replace(/\{(\d+)\}/g, function(m, i) {
3421         return args[i];
3422     });
3423 }
3424
3425 Ext.Date = {
3426     /**
3427      * Returns the current timestamp
3428      * @return {Date} The current timestamp
3429      * @method
3430      */
3431     now: Date.now || function() {
3432         return +new Date();
3433     },
3434
3435     /**
3436      * @private
3437      * Private for now
3438      */
3439     toString: function(date) {
3440         var pad = Ext.String.leftPad;
3441
3442         return date.getFullYear() + "-"
3443             + pad(date.getMonth() + 1, 2, '0') + "-"
3444             + pad(date.getDate(), 2, '0') + "T"
3445             + pad(date.getHours(), 2, '0') + ":"
3446             + pad(date.getMinutes(), 2, '0') + ":"
3447             + pad(date.getSeconds(), 2, '0');
3448     },
3449
3450     /**
3451      * Returns the number of milliseconds between two dates
3452      * @param {Date} dateA The first date
3453      * @param {Date} dateB (optional) The second date, defaults to now
3454      * @return {Number} The difference in milliseconds
3455      */
3456     getElapsed: function(dateA, dateB) {
3457         return Math.abs(dateA - (dateB || new Date()));
3458     },
3459
3460     /**
3461      * Global flag which determines if strict date parsing should be used.
3462      * Strict date parsing will not roll-over invalid dates, which is the
3463      * default behaviour of javascript Date objects.
3464      * (see {@link #parse} for more information)
3465      * Defaults to <tt>false</tt>.
3466      * @type Boolean
3467     */
3468     useStrict: false,
3469
3470     // private
3471     formatCodeToRegex: function(character, currentGroup) {
3472         // Note: currentGroup - position in regex result array (see notes for Ext.Date.parseCodes below)
3473         var p = utilDate.parseCodes[character];
3474
3475         if (p) {
3476           p = typeof p == 'function'? p() : p;
3477           utilDate.parseCodes[character] = p; // reassign function result to prevent repeated execution
3478         }
3479
3480         return p ? Ext.applyIf({
3481           c: p.c ? xf(p.c, currentGroup || "{0}") : p.c
3482         }, p) : {
3483             g: 0,
3484             c: null,
3485             s: Ext.String.escapeRegex(character) // treat unrecognised characters as literals
3486         };
3487     },
3488
3489     /**
3490      * <p>An object hash in which each property is a date parsing function. The property name is the
3491      * format string which that function parses.</p>
3492      * <p>This object is automatically populated with date parsing functions as
3493      * date formats are requested for Ext standard formatting strings.</p>
3494      * <p>Custom parsing functions may be inserted into this object, keyed by a name which from then on
3495      * may be used as a format string to {@link #parse}.<p>
3496      * <p>Example:</p><pre><code>
3497 Ext.Date.parseFunctions['x-date-format'] = myDateParser;
3498 </code></pre>
3499      * <p>A parsing function should return a Date object, and is passed the following parameters:<div class="mdetail-params"><ul>
3500      * <li><code>date</code> : String<div class="sub-desc">The date string to parse.</div></li>
3501      * <li><code>strict</code> : Boolean<div class="sub-desc">True to validate date strings while parsing
3502      * (i.e. prevent javascript Date "rollover") (The default must be false).
3503      * Invalid date strings should return null when parsed.</div></li>
3504      * </ul></div></p>
3505      * <p>To enable Dates to also be <i>formatted</i> according to that format, a corresponding
3506      * formatting function must be placed into the {@link #formatFunctions} property.
3507      * @property parseFunctions
3508      * @type Object
3509      */
3510     parseFunctions: {
3511         "MS": function(input, strict) {
3512             // note: the timezone offset is ignored since the MS Ajax server sends
3513             // a UTC milliseconds-since-Unix-epoch value (negative values are allowed)
3514             var re = new RegExp('\\/Date\\(([-+])?(\\d+)(?:[+-]\\d{4})?\\)\\/');
3515             var r = (input || '').match(re);
3516             return r? new Date(((r[1] || '') + r[2]) * 1) : null;
3517         }
3518     },
3519     parseRegexes: [],
3520
3521     /**
3522      * <p>An object hash in which each property is a date formatting function. The property name is the
3523      * format string which corresponds to the produced formatted date string.</p>
3524      * <p>This object is automatically populated with date formatting functions as
3525      * date formats are requested for Ext standard formatting strings.</p>
3526      * <p>Custom formatting functions may be inserted into this object, keyed by a name which from then on
3527      * may be used as a format string to {@link #format}. Example:</p><pre><code>
3528 Ext.Date.formatFunctions['x-date-format'] = myDateFormatter;
3529 </code></pre>
3530      * <p>A formatting function should return a string representation of the passed Date object, and is passed the following parameters:<div class="mdetail-params"><ul>
3531      * <li><code>date</code> : Date<div class="sub-desc">The Date to format.</div></li>
3532      * </ul></div></p>
3533      * <p>To enable date strings to also be <i>parsed</i> according to that format, a corresponding
3534      * parsing function must be placed into the {@link #parseFunctions} property.
3535      * @property formatFunctions
3536      * @type Object
3537      */
3538     formatFunctions: {
3539         "MS": function() {
3540             // UTC milliseconds since Unix epoch (MS-AJAX serialized date format (MRSF))
3541             return '\\/Date(' + this.getTime() + ')\\/';
3542         }
3543     },
3544
3545     y2kYear : 50,
3546
3547     /**
3548      * Date interval constant
3549      * @type String
3550      */
3551     MILLI : "ms",
3552
3553     /**
3554      * Date interval constant
3555      * @type String
3556      */
3557     SECOND : "s",
3558
3559     /**
3560      * Date interval constant
3561      * @type String
3562      */
3563     MINUTE : "mi",
3564
3565     /** Date interval constant
3566      * @type String
3567      */
3568     HOUR : "h",
3569
3570     /**
3571      * Date interval constant
3572      * @type String
3573      */
3574     DAY : "d",
3575
3576     /**
3577      * Date interval constant
3578      * @type String
3579      */
3580     MONTH : "mo",
3581
3582     /**
3583      * Date interval constant
3584      * @type String
3585      */
3586     YEAR : "y",
3587
3588     /**
3589      * <p>An object hash containing default date values used during date parsing.</p>
3590      * <p>The following properties are available:<div class="mdetail-params"><ul>
3591      * <li><code>y</code> : Number<div class="sub-desc">The default year value. (defaults to undefined)</div></li>
3592      * <li><code>m</code> : Number<div class="sub-desc">The default 1-based month value. (defaults to undefined)</div></li>
3593      * <li><code>d</code> : Number<div class="sub-desc">The default day value. (defaults to undefined)</div></li>
3594      * <li><code>h</code> : Number<div class="sub-desc">The default hour value. (defaults to undefined)</div></li>
3595      * <li><code>i</code> : Number<div class="sub-desc">The default minute value. (defaults to undefined)</div></li>
3596      * <li><code>s</code> : Number<div class="sub-desc">The default second value. (defaults to undefined)</div></li>
3597      * <li><code>ms</code> : Number<div class="sub-desc">The default millisecond value. (defaults to undefined)</div></li>
3598      * </ul></div></p>
3599      * <p>Override these properties to customize the default date values used by the {@link #parse} method.</p>
3600      * <p><b>Note: In countries which experience Daylight Saving Time (i.e. DST), the <tt>h</tt>, <tt>i</tt>, <tt>s</tt>
3601      * and <tt>ms</tt> properties may coincide with the exact time in which DST takes effect.
3602      * It is the responsiblity of the developer to account for this.</b></p>
3603      * Example Usage:
3604      * <pre><code>
3605 // set default day value to the first day of the month
3606 Ext.Date.defaults.d = 1;
3607
3608 // parse a February date string containing only year and month values.
3609 // setting the default day value to 1 prevents weird date rollover issues
3610 // when attempting to parse the following date string on, for example, March 31st 2009.
3611 Ext.Date.parse('2009-02', 'Y-m'); // returns a Date object representing February 1st 2009
3612 </code></pre>
3613      * @property defaults
3614      * @type Object
3615      */
3616     defaults: {},
3617
3618     /**
3619      * @property {String[]} dayNames
3620      * An array of textual day names.
3621      * Override these values for international dates.
3622      * Example:
3623      * <pre><code>
3624 Ext.Date.dayNames = [
3625     'SundayInYourLang',
3626     'MondayInYourLang',
3627     ...
3628 ];
3629 </code></pre>
3630      */
3631     dayNames : [
3632         "Sunday",
3633         "Monday",
3634         "Tuesday",
3635         "Wednesday",
3636         "Thursday",
3637         "Friday",
3638         "Saturday"
3639     ],
3640
3641     /**
3642      * @property {String[]} monthNames
3643      * An array of textual month names.
3644      * Override these values for international dates.
3645      * Example:
3646      * <pre><code>
3647 Ext.Date.monthNames = [
3648     'JanInYourLang',
3649     'FebInYourLang',
3650     ...
3651 ];
3652 </code></pre>
3653      */
3654     monthNames : [
3655         "January",
3656         "February",
3657         "March",
3658         "April",
3659         "May",
3660         "June",
3661         "July",
3662         "August",
3663         "September",
3664         "October",
3665         "November",
3666         "December"
3667     ],
3668
3669     /**
3670      * @property {Object} monthNumbers
3671      * An object hash of zero-based javascript month numbers (with short month names as keys. note: keys are case-sensitive).
3672      * Override these values for international dates.
3673      * Example:
3674      * <pre><code>
3675 Ext.Date.monthNumbers = {
3676     'ShortJanNameInYourLang':0,
3677     'ShortFebNameInYourLang':1,
3678     ...
3679 };
3680 </code></pre>
3681      */
3682     monthNumbers : {
3683         Jan:0,
3684         Feb:1,
3685         Mar:2,
3686         Apr:3,
3687         May:4,
3688         Jun:5,
3689         Jul:6,
3690         Aug:7,
3691         Sep:8,
3692         Oct:9,
3693         Nov:10,
3694         Dec:11
3695     },
3696     /**
3697      * @property {String} defaultFormat
3698      * <p>The date format string that the {@link Ext.util.Format#dateRenderer}
3699      * and {@link Ext.util.Format#date} functions use.  See {@link Ext.Date} for details.</p>
3700      * <p>This may be overridden in a locale file.</p>
3701      */
3702     defaultFormat : "m/d/Y",
3703     /**
3704      * Get the short month name for the given month number.
3705      * Override this function for international dates.
3706      * @param {Number} month A zero-based javascript month number.
3707      * @return {String} The short month name.
3708      */
3709     getShortMonthName : function(month) {
3710         return utilDate.monthNames[month].substring(0, 3);
3711     },
3712
3713     /**
3714      * Get the short day name for the given day number.
3715      * Override this function for international dates.
3716      * @param {Number} day A zero-based javascript day number.
3717      * @return {String} The short day name.
3718      */
3719     getShortDayName : function(day) {
3720         return utilDate.dayNames[day].substring(0, 3);
3721     },
3722
3723     /**
3724      * Get the zero-based javascript month number for the given short/full month name.
3725      * Override this function for international dates.
3726      * @param {String} name The short/full month name.
3727      * @return {Number} The zero-based javascript month number.
3728      */
3729     getMonthNumber : function(name) {
3730         // handle camel casing for english month names (since the keys for the Ext.Date.monthNumbers hash are case sensitive)
3731         return utilDate.monthNumbers[name.substring(0, 1).toUpperCase() + name.substring(1, 3).toLowerCase()];
3732     },
3733
3734     /**
3735      * Checks if the specified format contains hour information
3736      * @param {String} format The format to check
3737      * @return {Boolean} True if the format contains hour information
3738      * @method
3739      */
3740     formatContainsHourInfo : (function(){
3741         var stripEscapeRe = /(\\.)/g,
3742             hourInfoRe = /([gGhHisucUOPZ]|MS)/;
3743         return function(format){
3744             return hourInfoRe.test(format.replace(stripEscapeRe, ''));
3745         };
3746     })(),
3747
3748     /**
3749      * Checks if the specified format contains information about
3750      * anything other than the time.
3751      * @param {String} format The format to check
3752      * @return {Boolean} True if the format contains information about
3753      * date/day information.
3754      * @method
3755      */
3756     formatContainsDateInfo : (function(){
3757         var stripEscapeRe = /(\\.)/g,
3758             dateInfoRe = /([djzmnYycU]|MS)/;
3759
3760         return function(format){
3761             return dateInfoRe.test(format.replace(stripEscapeRe, ''));
3762         };
3763     })(),
3764
3765     /**
3766      * The base format-code to formatting-function hashmap used by the {@link #format} method.
3767      * Formatting functions are strings (or functions which return strings) which
3768      * will return the appropriate value when evaluated in the context of the Date object
3769      * from which the {@link #format} method is called.
3770      * Add to / override these mappings for custom date formatting.
3771      * Note: Ext.Date.format() treats characters as literals if an appropriate mapping cannot be found.
3772      * Example:
3773      * <pre><code>
3774 Ext.Date.formatCodes.x = "Ext.util.Format.leftPad(this.getDate(), 2, '0')";
3775 console.log(Ext.Date.format(new Date(), 'X'); // returns the current day of the month
3776 </code></pre>
3777      * @type Object
3778      */
3779     formatCodes : {
3780         d: "Ext.String.leftPad(this.getDate(), 2, '0')",
3781         D: "Ext.Date.getShortDayName(this.getDay())", // get localised short day name
3782         j: "this.getDate()",
3783         l: "Ext.Date.dayNames[this.getDay()]",
3784         N: "(this.getDay() ? this.getDay() : 7)",
3785         S: "Ext.Date.getSuffix(this)",
3786         w: "this.getDay()",
3787         z: "Ext.Date.getDayOfYear(this)",
3788         W: "Ext.String.leftPad(Ext.Date.getWeekOfYear(this), 2, '0')",
3789         F: "Ext.Date.monthNames[this.getMonth()]",
3790         m: "Ext.String.leftPad(this.getMonth() + 1, 2, '0')",
3791         M: "Ext.Date.getShortMonthName(this.getMonth())", // get localised short month name
3792         n: "(this.getMonth() + 1)",
3793         t: "Ext.Date.getDaysInMonth(this)",
3794         L: "(Ext.Date.isLeapYear(this) ? 1 : 0)",
3795         o: "(this.getFullYear() + (Ext.Date.getWeekOfYear(this) == 1 && this.getMonth() > 0 ? +1 : (Ext.Date.getWeekOfYear(this) >= 52 && this.getMonth() < 11 ? -1 : 0)))",
3796         Y: "Ext.String.leftPad(this.getFullYear(), 4, '0')",
3797         y: "('' + this.getFullYear()).substring(2, 4)",
3798         a: "(this.getHours() < 12 ? 'am' : 'pm')",
3799         A: "(this.getHours() < 12 ? 'AM' : 'PM')",
3800         g: "((this.getHours() % 12) ? this.getHours() % 12 : 12)",
3801         G: "this.getHours()",
3802         h: "Ext.String.leftPad((this.getHours() % 12) ? this.getHours() % 12 : 12, 2, '0')",
3803         H: "Ext.String.leftPad(this.getHours(), 2, '0')",
3804         i: "Ext.String.leftPad(this.getMinutes(), 2, '0')",
3805         s: "Ext.String.leftPad(this.getSeconds(), 2, '0')",
3806         u: "Ext.String.leftPad(this.getMilliseconds(), 3, '0')",
3807         O: "Ext.Date.getGMTOffset(this)",
3808         P: "Ext.Date.getGMTOffset(this, true)",
3809         T: "Ext.Date.getTimezone(this)",
3810         Z: "(this.getTimezoneOffset() * -60)",
3811
3812         c: function() { // ISO-8601 -- GMT format
3813             for (var c = "Y-m-dTH:i:sP", code = [], i = 0, l = c.length; i < l; ++i) {
3814                 var e = c.charAt(i);
3815                 code.push(e == "T" ? "'T'" : utilDate.getFormatCode(e)); // treat T as a character literal
3816             }
3817             return code.join(" + ");
3818         },
3819         /*
3820         c: function() { // ISO-8601 -- UTC format
3821             return [
3822               "this.getUTCFullYear()", "'-'",
3823               "Ext.util.Format.leftPad(this.getUTCMonth() + 1, 2, '0')", "'-'",
3824               "Ext.util.Format.leftPad(this.getUTCDate(), 2, '0')",
3825               "'T'",
3826               "Ext.util.Format.leftPad(this.getUTCHours(), 2, '0')", "':'",
3827               "Ext.util.Format.leftPad(this.getUTCMinutes(), 2, '0')", "':'",
3828               "Ext.util.Format.leftPad(this.getUTCSeconds(), 2, '0')",
3829               "'Z'"
3830             ].join(" + ");
3831         },
3832         */
3833
3834         U: "Math.round(this.getTime() / 1000)"
3835     },
3836
3837     /**
3838      * Checks if the passed Date parameters will cause a javascript Date "rollover".
3839      * @param {Number} year 4-digit year
3840      * @param {Number} month 1-based month-of-year
3841      * @param {Number} day Day of month
3842      * @param {Number} hour (optional) Hour
3843      * @param {Number} minute (optional) Minute
3844      * @param {Number} second (optional) Second
3845      * @param {Number} millisecond (optional) Millisecond
3846      * @return {Boolean} true if the passed parameters do not cause a Date "rollover", false otherwise.
3847      */
3848     isValid : function(y, m, d, h, i, s, ms) {
3849         // setup defaults
3850         h = h || 0;
3851         i = i || 0;
3852         s = s || 0;
3853         ms = ms || 0;
3854
3855         // Special handling for year < 100
3856         var dt = utilDate.add(new Date(y < 100 ? 100 : y, m - 1, d, h, i, s, ms), utilDate.YEAR, y < 100 ? y - 100 : 0);
3857
3858         return y == dt.getFullYear() &&
3859             m == dt.getMonth() + 1 &&
3860             d == dt.getDate() &&
3861             h == dt.getHours() &&
3862             i == dt.getMinutes() &&
3863             s == dt.getSeconds() &&
3864             ms == dt.getMilliseconds();
3865     },
3866
3867     /**
3868      * Parses the passed string using the specified date format.
3869      * Note that this function expects normal calendar dates, meaning that months are 1-based (i.e. 1 = January).
3870      * The {@link #defaults} hash will be used for any date value (i.e. year, month, day, hour, minute, second or millisecond)
3871      * which cannot be found in the passed string. If a corresponding default date value has not been specified in the {@link #defaults} hash,
3872      * the current date's year, month, day or DST-adjusted zero-hour time value will be used instead.
3873      * Keep in mind that the input date string must precisely match the specified format string
3874      * in order for the parse operation to be successful (failed parse operations return a null value).
3875      * <p>Example:</p><pre><code>
3876 //dt = Fri May 25 2007 (current date)
3877 var dt = new Date();
3878
3879 //dt = Thu May 25 2006 (today&#39;s month/day in 2006)
3880 dt = Ext.Date.parse("2006", "Y");
3881
3882 //dt = Sun Jan 15 2006 (all date parts specified)
3883 dt = Ext.Date.parse("2006-01-15", "Y-m-d");
3884
3885 //dt = Sun Jan 15 2006 15:20:01
3886 dt = Ext.Date.parse("2006-01-15 3:20:01 PM", "Y-m-d g:i:s A");
3887
3888 // attempt to parse Sun Feb 29 2006 03:20:01 in strict mode
3889 dt = Ext.Date.parse("2006-02-29 03:20:01", "Y-m-d H:i:s", true); // returns null
3890 </code></pre>
3891      * @param {String} input The raw date string.
3892      * @param {String} format The expected date string format.
3893      * @param {Boolean} strict (optional) True to validate date strings while parsing (i.e. prevents javascript Date "rollover")
3894                         (defaults to false). Invalid date strings will return null when parsed.
3895      * @return {Date} The parsed Date.
3896      */
3897     parse : function(input, format, strict) {
3898         var p = utilDate.parseFunctions;
3899         if (p[format] == null) {
3900             utilDate.createParser(format);
3901         }
3902         return p[format](input, Ext.isDefined(strict) ? strict : utilDate.useStrict);
3903     },
3904
3905     // Backwards compat
3906     parseDate: function(input, format, strict){
3907         return utilDate.parse(input, format, strict);
3908     },
3909
3910
3911     // private
3912     getFormatCode : function(character) {
3913         var f = utilDate.formatCodes[character];
3914
3915         if (f) {
3916           f = typeof f == 'function'? f() : f;
3917           utilDate.formatCodes[character] = f; // reassign function result to prevent repeated execution
3918         }
3919
3920         // note: unknown characters are treated as literals
3921         return f || ("'" + Ext.String.escape(character) + "'");
3922     },
3923
3924     // private
3925     createFormat : function(format) {
3926         var code = [],
3927             special = false,
3928             ch = '';
3929
3930         for (var i = 0; i < format.length; ++i) {
3931             ch = format.charAt(i);
3932             if (!special && ch == "\\") {
3933                 special = true;
3934             } else if (special) {
3935                 special = false;
3936                 code.push("'" + Ext.String.escape(ch) + "'");
3937             } else {
3938                 code.push(utilDate.getFormatCode(ch));
3939             }
3940         }
3941         utilDate.formatFunctions[format] = Ext.functionFactory("return " + code.join('+'));
3942     },
3943
3944     // private
3945     createParser : (function() {
3946         var code = [
3947             "var dt, y, m, d, h, i, s, ms, o, z, zz, u, v,",
3948                 "def = Ext.Date.defaults,",
3949                 "results = String(input).match(Ext.Date.parseRegexes[{0}]);", // either null, or an array of matched strings
3950
3951             "if(results){",
3952                 "{1}",
3953
3954                 "if(u != null){", // i.e. unix time is defined
3955                     "v = new Date(u * 1000);", // give top priority to UNIX time
3956                 "}else{",
3957                     // create Date object representing midnight of the current day;
3958                     // this will provide us with our date defaults
3959                     // (note: clearTime() handles Daylight Saving Time automatically)
3960                     "dt = Ext.Date.clearTime(new Date);",
3961
3962                     // date calculations (note: these calculations create a dependency on Ext.Number.from())
3963                     "y = Ext.Number.from(y, Ext.Number.from(def.y, dt.getFullYear()));",
3964                     "m = Ext.Number.from(m, Ext.Number.from(def.m - 1, dt.getMonth()));",
3965                     "d = Ext.Number.from(d, Ext.Number.from(def.d, dt.getDate()));",
3966
3967                     // time calculations (note: these calculations create a dependency on Ext.Number.from())
3968                     "h  = Ext.Number.from(h, Ext.Number.from(def.h, dt.getHours()));",
3969                     "i  = Ext.Number.from(i, Ext.Number.from(def.i, dt.getMinutes()));",
3970                     "s  = Ext.Number.from(s, Ext.Number.from(def.s, dt.getSeconds()));",
3971                     "ms = Ext.Number.from(ms, Ext.Number.from(def.ms, dt.getMilliseconds()));",
3972
3973                     "if(z >= 0 && y >= 0){",
3974                         // both the year and zero-based day of year are defined and >= 0.
3975                         // these 2 values alone provide sufficient info to create a full date object
3976
3977                         // create Date object representing January 1st for the given year
3978                         // handle years < 100 appropriately
3979                         "v = Ext.Date.add(new Date(y < 100 ? 100 : y, 0, 1, h, i, s, ms), Ext.Date.YEAR, y < 100 ? y - 100 : 0);",
3980
3981                         // then add day of year, checking for Date "rollover" if necessary
3982                         "v = !strict? v : (strict === true && (z <= 364 || (Ext.Date.isLeapYear(v) && z <= 365))? Ext.Date.add(v, Ext.Date.DAY, z) : null);",
3983                     "}else if(strict === true && !Ext.Date.isValid(y, m + 1, d, h, i, s, ms)){", // check for Date "rollover"
3984                         "v = null;", // invalid date, so return null
3985                     "}else{",
3986                         // plain old Date object
3987                         // handle years < 100 properly
3988                         "v = Ext.Date.add(new Date(y < 100 ? 100 : y, m, d, h, i, s, ms), Ext.Date.YEAR, y < 100 ? y - 100 : 0);",
3989                     "}",
3990                 "}",
3991             "}",
3992
3993             "if(v){",
3994                 // favour UTC offset over GMT offset
3995                 "if(zz != null){",
3996                     // reset to UTC, then add offset
3997                     "v = Ext.Date.add(v, Ext.Date.SECOND, -v.getTimezoneOffset() * 60 - zz);",
3998                 "}else if(o){",
3999                     // reset to GMT, then add offset
4000                     "v = Ext.Date.add(v, Ext.Date.MINUTE, -v.getTimezoneOffset() + (sn == '+'? -1 : 1) * (hr * 60 + mn));",
4001                 "}",
4002             "}",
4003
4004             "return v;"
4005         ].join('\n');
4006
4007         return function(format) {
4008             var regexNum = utilDate.parseRegexes.length,
4009                 currentGroup = 1,
4010                 calc = [],
4011                 regex = [],
4012                 special = false,
4013                 ch = "";
4014
4015             for (var i = 0; i < format.length; ++i) {
4016                 ch = format.charAt(i);
4017                 if (!special && ch == "\\") {
4018                     special = true;
4019                 } else if (special) {
4020                     special = false;
4021                     regex.push(Ext.String.escape(ch));
4022                 } else {
4023                     var obj = utilDate.formatCodeToRegex(ch, currentGroup);
4024                     currentGroup += obj.g;
4025                     regex.push(obj.s);
4026                     if (obj.g && obj.c) {
4027                         calc.push(obj.c);
4028                     }
4029                 }
4030             }
4031
4032             utilDate.parseRegexes[regexNum] = new RegExp("^" + regex.join('') + "$", 'i');
4033             utilDate.parseFunctions[format] = Ext.functionFactory("input", "strict", xf(code, regexNum, calc.join('')));
4034         };
4035     })(),
4036
4037     // private
4038     parseCodes : {
4039         /*
4040          * Notes:
4041          * g = {Number} calculation group (0 or 1. only group 1 contributes to date calculations.)
4042          * c = {String} calculation method (required for group 1. null for group 0. {0} = currentGroup - position in regex result array)
4043          * s = {String} regex pattern. all matches are stored in results[], and are accessible by the calculation mapped to 'c'
4044          */
4045         d: {
4046             g:1,
4047             c:"d = parseInt(results[{0}], 10);\n",
4048             s:"(\\d{2})" // day of month with leading zeroes (01 - 31)
4049         },
4050         j: {
4051             g:1,
4052             c:"d = parseInt(results[{0}], 10);\n",
4053             s:"(\\d{1,2})" // day of month without leading zeroes (1 - 31)
4054         },
4055         D: function() {
4056             for (var a = [], i = 0; i < 7; a.push(utilDate.getShortDayName(i)), ++i); // get localised short day names
4057             return {
4058                 g:0,
4059                 c:null,
4060                 s:"(?:" + a.join("|") +")"
4061             };
4062         },
4063         l: function() {
4064             return {
4065                 g:0,
4066                 c:null,
4067                 s:"(?:" + utilDate.dayNames.join("|") + ")"
4068             };
4069         },
4070         N: {
4071             g:0,
4072             c:null,
4073             s:"[1-7]" // ISO-8601 day number (1 (monday) - 7 (sunday))
4074         },
4075         S: {
4076             g:0,
4077             c:null,
4078             s:"(?:st|nd|rd|th)"
4079         },
4080         w: {
4081             g:0,
4082             c:null,
4083             s:"[0-6]" // javascript day number (0 (sunday) - 6 (saturday))
4084         },
4085         z: {
4086             g:1,
4087             c:"z = parseInt(results[{0}], 10);\n",
4088             s:"(\\d{1,3})" // day of the year (0 - 364 (365 in leap years))
4089         },
4090         W: {
4091             g:0,
4092             c:null,
4093             s:"(?:\\d{2})" // ISO-8601 week number (with leading zero)
4094         },
4095         F: function() {
4096             return {
4097                 g:1,
4098                 c:"m = parseInt(Ext.Date.getMonthNumber(results[{0}]), 10);\n", // get localised month number
4099                 s:"(" + utilDate.monthNames.join("|") + ")"
4100             };
4101         },
4102         M: function() {
4103             for (var a = [], i = 0; i < 12; a.push(utilDate.getShortMonthName(i)), ++i); // get localised short month names
4104             return Ext.applyIf({
4105                 s:"(" + a.join("|") + ")"
4106             }, utilDate.formatCodeToRegex("F"));
4107         },
4108         m: {
4109             g:1,
4110             c:"m = parseInt(results[{0}], 10) - 1;\n",
4111             s:"(\\d{2})" // month number with leading zeros (01 - 12)
4112         },
4113         n: {
4114             g:1,
4115             c:"m = parseInt(results[{0}], 10) - 1;\n",
4116             s:"(\\d{1,2})" // month number without leading zeros (1 - 12)
4117         },
4118         t: {
4119             g:0,
4120             c:null,
4121             s:"(?:\\d{2})" // no. of days in the month (28 - 31)
4122         },
4123         L: {
4124             g:0,
4125             c:null,
4126             s:"(?:1|0)"
4127         },
4128         o: function() {
4129             return utilDate.formatCodeToRegex("Y");
4130         },
4131         Y: {
4132             g:1,
4133             c:"y = parseInt(results[{0}], 10);\n",
4134             s:"(\\d{4})" // 4-digit year
4135         },
4136         y: {
4137             g:1,
4138             c:"var ty = parseInt(results[{0}], 10);\n"
4139                 + "y = ty > Ext.Date.y2kYear ? 1900 + ty : 2000 + ty;\n", // 2-digit year
4140             s:"(\\d{1,2})"
4141         },
4142         /*
4143          * In the am/pm parsing routines, we allow both upper and lower case
4144          * even though it doesn't exactly match the spec. It gives much more flexibility
4145          * in being able to specify case insensitive regexes.
4146          */
4147         a: {
4148             g:1,
4149             c:"if (/(am)/i.test(results[{0}])) {\n"
4150                 + "if (!h || h == 12) { h = 0; }\n"
4151                 + "} else { if (!h || h < 12) { h = (h || 0) + 12; }}",
4152             s:"(am|pm|AM|PM)"
4153         },
4154         A: {
4155             g:1,
4156             c:"if (/(am)/i.test(results[{0}])) {\n"
4157                 + "if (!h || h == 12) { h = 0; }\n"
4158                 + "} else { if (!h || h < 12) { h = (h || 0) + 12; }}",
4159             s:"(AM|PM|am|pm)"
4160         },
4161         g: function() {
4162             return utilDate.formatCodeToRegex("G");
4163         },
4164         G: {
4165             g:1,
4166             c:"h = parseInt(results[{0}], 10);\n",
4167             s:"(\\d{1,2})" // 24-hr format of an hour without leading zeroes (0 - 23)
4168         },
4169         h: function() {
4170             return utilDate.formatCodeToRegex("H");
4171         },
4172         H: {
4173             g:1,
4174             c:"h = parseInt(results[{0}], 10);\n",
4175             s:"(\\d{2})" //  24-hr format of an hour with leading zeroes (00 - 23)
4176         },
4177         i: {
4178             g:1,
4179             c:"i = parseInt(results[{0}], 10);\n",
4180             s:"(\\d{2})" // minutes with leading zeros (00 - 59)
4181         },
4182         s: {
4183             g:1,
4184             c:"s = parseInt(results[{0}], 10);\n",
4185             s:"(\\d{2})" // seconds with leading zeros (00 - 59)
4186         },
4187         u: {
4188             g:1,
4189             c:"ms = results[{0}]; ms = parseInt(ms, 10)/Math.pow(10, ms.length - 3);\n",
4190             s:"(\\d+)" // decimal fraction of a second (minimum = 1 digit, maximum = unlimited)
4191         },
4192         O: {
4193             g:1,
4194             c:[
4195                 "o = results[{0}];",
4196                 "var sn = o.substring(0,1),", // get + / - sign
4197                     "hr = o.substring(1,3)*1 + Math.floor(o.substring(3,5) / 60),", // get hours (performs minutes-to-hour conversion also, just in case)
4198                     "mn = o.substring(3,5) % 60;", // get minutes
4199                 "o = ((-12 <= (hr*60 + mn)/60) && ((hr*60 + mn)/60 <= 14))? (sn + Ext.String.leftPad(hr, 2, '0') + Ext.String.leftPad(mn, 2, '0')) : null;\n" // -12hrs <= GMT offset <= 14hrs
4200             ].join("\n"),
4201             s: "([+\-]\\d{4})" // GMT offset in hrs and mins
4202         },
4203         P: {
4204             g:1,
4205             c:[
4206                 "o = results[{0}];",
4207                 "var sn = o.substring(0,1),", // get + / - sign
4208                     "hr = o.substring(1,3)*1 + Math.floor(o.substring(4,6) / 60),", // get hours (performs minutes-to-hour conversion also, just in case)
4209                     "mn = o.substring(4,6) % 60;", // get minutes
4210                 "o = ((-12 <= (hr*60 + mn)/60) && ((hr*60 + mn)/60 <= 14))? (sn + Ext.String.leftPad(hr, 2, '0') + Ext.String.leftPad(mn, 2, '0')) : null;\n" // -12hrs <= GMT offset <= 14hrs
4211             ].join("\n"),
4212             s: "([+\-]\\d{2}:\\d{2})" // GMT offset in hrs and mins (with colon separator)
4213         },
4214         T: {
4215             g:0,
4216             c:null,
4217             s:"[A-Z]{1,4}" // timezone abbrev. may be between 1 - 4 chars
4218         },
4219         Z: {
4220             g:1,
4221             c:"zz = results[{0}] * 1;\n" // -43200 <= UTC offset <= 50400
4222                   + "zz = (-43200 <= zz && zz <= 50400)? zz : null;\n",
4223             s:"([+\-]?\\d{1,5})" // leading '+' sign is optional for UTC offset
4224         },
4225         c: function() {
4226             var calc = [],
4227                 arr = [
4228                     utilDate.formatCodeToRegex("Y", 1), // year
4229                     utilDate.formatCodeToRegex("m", 2), // month
4230                     utilDate.formatCodeToRegex("d", 3), // day
4231                     utilDate.formatCodeToRegex("h", 4), // hour
4232                     utilDate.formatCodeToRegex("i", 5), // minute
4233                     utilDate.formatCodeToRegex("s", 6), // second
4234                     {c:"ms = results[7] || '0'; ms = parseInt(ms, 10)/Math.pow(10, ms.length - 3);\n"}, // decimal fraction of a second (minimum = 1 digit, maximum = unlimited)
4235                     {c:[ // allow either "Z" (i.e. UTC) or "-0530" or "+08:00" (i.e. UTC offset) timezone delimiters. assumes local timezone if no timezone is specified
4236                         "if(results[8]) {", // timezone specified
4237                             "if(results[8] == 'Z'){",
4238                                 "zz = 0;", // UTC
4239                             "}else if (results[8].indexOf(':') > -1){",
4240                                 utilDate.formatCodeToRegex("P", 8).c, // timezone offset with colon separator
4241                             "}else{",
4242                                 utilDate.formatCodeToRegex("O", 8).c, // timezone offset without colon separator
4243                             "}",
4244                         "}"
4245                     ].join('\n')}
4246                 ];
4247
4248             for (var i = 0, l = arr.length; i < l; ++i) {
4249                 calc.push(arr[i].c);
4250             }
4251
4252             return {
4253                 g:1,
4254                 c:calc.join(""),
4255                 s:[
4256                     arr[0].s, // year (required)
4257                     "(?:", "-", arr[1].s, // month (optional)
4258                         "(?:", "-", arr[2].s, // day (optional)
4259                             "(?:",
4260                                 "(?:T| )?", // time delimiter -- either a "T" or a single blank space
4261                                 arr[3].s, ":", arr[4].s,  // hour AND minute, delimited by a single colon (optional). MUST be preceded by either a "T" or a single blank space
4262                                 "(?::", arr[5].s, ")?", // seconds (optional)
4263                                 "(?:(?:\\.|,)(\\d+))?", // decimal fraction of a second (e.g. ",12345" or ".98765") (optional)
4264                                 "(Z|(?:[-+]\\d{2}(?::)?\\d{2}))?", // "Z" (UTC) or "-0530" (UTC offset without colon delimiter) or "+08:00" (UTC offset with colon delimiter) (optional)
4265                             ")?",
4266                         ")?",
4267                     ")?"
4268                 ].join("")
4269             };
4270         },
4271         U: {
4272             g:1,
4273             c:"u = parseInt(results[{0}], 10);\n",
4274             s:"(-?\\d+)" // leading minus sign indicates seconds before UNIX epoch
4275         }
4276     },
4277
4278     //Old Ext.Date prototype methods.
4279     // private
4280     dateFormat: function(date, format) {
4281         return utilDate.format(date, format);
4282     },
4283
4284     /**
4285      * Formats a date given the supplied format string.
4286      * @param {Date} date The date to format
4287      * @param {String} format The format string
4288      * @return {String} The formatted date
4289      */
4290     format: function(date, format) {
4291         if (utilDate.formatFunctions[format] == null) {
4292             utilDate.createFormat(format);
4293         }
4294         var result = utilDate.formatFunctions[format].call(date);
4295         return result + '';
4296     },
4297
4298     /**
4299      * Get the timezone abbreviation of the current date (equivalent to the format specifier 'T').
4300      *
4301      * Note: The date string returned by the javascript Date object's toString() method varies
4302      * between browsers (e.g. FF vs IE) and system region settings (e.g. IE in Asia vs IE in America).
4303      * For a given date string e.g. "Thu Oct 25 2007 22:55:35 GMT+0800 (Malay Peninsula Standard Time)",
4304      * getTimezone() first tries to get the timezone abbreviation from between a pair of parentheses
4305      * (which may or may not be present), failing which it proceeds to get the timezone abbreviation
4306      * from the GMT offset portion of the date string.
4307      * @param {Date} date The date
4308      * @return {String} The abbreviated timezone name (e.g. 'CST', 'PDT', 'EDT', 'MPST' ...).
4309      */
4310     getTimezone : function(date) {
4311         // the following list shows the differences between date strings from different browsers on a WinXP SP2 machine from an Asian locale:
4312         //
4313         // Opera  : "Thu, 25 Oct 2007 22:53:45 GMT+0800" -- shortest (weirdest) date string of the lot
4314         // Safari : "Thu Oct 25 2007 22:55:35 GMT+0800 (Malay Peninsula Standard Time)" -- value in parentheses always gives the correct timezone (same as FF)
4315         // FF     : "Thu Oct 25 2007 22:55:35 GMT+0800 (Malay Peninsula Standard Time)" -- value in parentheses always gives the correct timezone
4316         // IE     : "Thu Oct 25 22:54:35 UTC+0800 2007" -- (Asian system setting) look for 3-4 letter timezone abbrev
4317         // IE     : "Thu Oct 25 17:06:37 PDT 2007" -- (American system setting) look for 3-4 letter timezone abbrev
4318         //
4319         // this crazy regex attempts to guess the correct timezone abbreviation despite these differences.
4320         // step 1: (?:\((.*)\) -- find timezone in parentheses
4321         // step 2: ([A-Z]{1,4})(?:[\-+][0-9]{4})?(?: -?\d+)?) -- if nothing was found in step 1, find timezone from timezone offset portion of date string
4322         // step 3: remove all non uppercase characters found in step 1 and 2
4323         return date.toString().replace(/^.* (?:\((.*)\)|([A-Z]{1,4})(?:[\-+][0-9]{4})?(?: -?\d+)?)$/, "$1$2").replace(/[^A-Z]/g, "");
4324     },
4325
4326     /**
4327      * Get the offset from GMT of the current date (equivalent to the format specifier 'O').
4328      * @param {Date} date The date
4329      * @param {Boolean} colon (optional) true to separate the hours and minutes with a colon (defaults to false).
4330      * @return {String} The 4-character offset string prefixed with + or - (e.g. '-0600').
4331      */
4332     getGMTOffset : function(date, colon) {
4333         var offset = date.getTimezoneOffset();
4334         return (offset > 0 ? "-" : "+")
4335             + Ext.String.leftPad(Math.floor(Math.abs(offset) / 60), 2, "0")
4336             + (colon ? ":" : "")
4337             + Ext.String.leftPad(Math.abs(offset % 60), 2, "0");
4338     },
4339
4340     /**
4341      * Get the numeric day number of the year, adjusted for leap year.
4342      * @param {Date} date The date
4343      * @return {Number} 0 to 364 (365 in leap years).
4344      */
4345     getDayOfYear: function(date) {
4346         var num = 0,
4347             d = Ext.Date.clone(date),
4348             m = date.getMonth(),
4349             i;
4350
4351         for (i = 0, d.setDate(1), d.setMonth(0); i < m; d.setMonth(++i)) {
4352             num += utilDate.getDaysInMonth(d);
4353         }
4354         return num + date.getDate() - 1;
4355     },
4356
4357     /**
4358      * Get the numeric ISO-8601 week number of the year.
4359      * (equivalent to the format specifier 'W', but without a leading zero).
4360      * @param {Date} date The date
4361      * @return {Number} 1 to 53
4362      * @method
4363      */
4364     getWeekOfYear : (function() {
4365         // adapted from http://www.merlyn.demon.co.uk/weekcalc.htm
4366         var ms1d = 864e5, // milliseconds in a day
4367             ms7d = 7 * ms1d; // milliseconds in a week
4368
4369         return function(date) { // return a closure so constants get calculated only once
4370             var DC3 = Date.UTC(date.getFullYear(), date.getMonth(), date.getDate() + 3) / ms1d, // an Absolute Day Number
4371                 AWN = Math.floor(DC3 / 7), // an Absolute Week Number
4372                 Wyr = new Date(AWN * ms7d).getUTCFullYear();
4373
4374             return AWN - Math.floor(Date.UTC(Wyr, 0, 7) / ms7d) + 1;
4375         };
4376     })(),
4377
4378     /**
4379      * Checks if the current date falls within a leap year.
4380      * @param {Date} date The date
4381      * @return {Boolean} True if the current date falls within a leap year, false otherwise.
4382      */
4383     isLeapYear : function(date) {
4384         var year = date.getFullYear();
4385         return !!((year & 3) == 0 && (year % 100 || (year % 400 == 0 && year)));
4386     },
4387
4388     /**
4389      * Get the first day of the current month, adjusted for leap year.  The returned value
4390      * is the numeric day index within the week (0-6) which can be used in conjunction with
4391      * the {@link #monthNames} array to retrieve the textual day name.
4392      * Example:
4393      * <pre><code>
4394 var dt = new Date('1/10/2007'),
4395     firstDay = Ext.Date.getFirstDayOfMonth(dt);
4396 console.log(Ext.Date.dayNames[firstDay]); //output: 'Monday'
4397      * </code></pre>
4398      * @param {Date} date The date
4399      * @return {Number} The day number (0-6).
4400      */
4401     getFirstDayOfMonth : function(date) {
4402         var day = (date.getDay() - (date.getDate() - 1)) % 7;
4403         return (day < 0) ? (day + 7) : day;
4404     },
4405
4406     /**
4407      * Get the last day of the current month, adjusted for leap year.  The returned value
4408      * is the numeric day index within the week (0-6) which can be used in conjunction with
4409      * the {@link #monthNames} array to retrieve the textual day name.
4410      * Example:
4411      * <pre><code>
4412 var dt = new Date('1/10/2007'),
4413     lastDay = Ext.Date.getLastDayOfMonth(dt);
4414 console.log(Ext.Date.dayNames[lastDay]); //output: 'Wednesday'
4415      * </code></pre>
4416      * @param {Date} date The date
4417      * @return {Number} The day number (0-6).
4418      */
4419     getLastDayOfMonth : function(date) {
4420         return utilDate.getLastDateOfMonth(date).getDay();
4421     },
4422
4423
4424     /**
4425      * Get the date of the first day of the month in which this date resides.
4426      * @param {Date} date The date
4427      * @return {Date}
4428      */
4429     getFirstDateOfMonth : function(date) {
4430         return new Date(date.getFullYear(), date.getMonth(), 1);
4431     },
4432
4433     /**
4434      * Get the date of the last day of the month in which this date resides.
4435      * @param {Date} date The date
4436      * @return {Date}
4437      */
4438     getLastDateOfMonth : function(date) {
4439         return new Date(date.getFullYear(), date.getMonth(), utilDate.getDaysInMonth(date));
4440     },
4441
4442     /**
4443      * Get the number of days in the current month, adjusted for leap year.
4444      * @param {Date} date The date
4445      * @return {Number} The number of days in the month.
4446      * @method
4447      */
4448     getDaysInMonth: (function() {
4449         var daysInMonth = [31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31];
4450
4451         return function(date) { // return a closure for efficiency
4452             var m = date.getMonth();
4453
4454             return m == 1 && utilDate.isLeapYear(date) ? 29 : daysInMonth[m];
4455         };
4456     })(),
4457
4458     /**
4459      * Get the English ordinal suffix of the current day (equivalent to the format specifier 'S').
4460      * @param {Date} date The date
4461      * @return {String} 'st, 'nd', 'rd' or 'th'.
4462      */
4463     getSuffix : function(date) {
4464         switch (date.getDate()) {
4465             case 1:
4466             case 21:
4467             case 31:
4468                 return "st";
4469             case 2:
4470             case 22:
4471                 return "nd";
4472             case 3:
4473             case 23:
4474                 return "rd";
4475             default:
4476                 return "th";
4477         }
4478     },
4479
4480     /**
4481      * Creates and returns a new Date instance with the exact same date value as the called instance.
4482      * Dates are copied and passed by reference, so if a copied date variable is modified later, the original
4483      * variable will also be changed.  When the intention is to create a new variable that will not
4484      * modify the original instance, you should create a clone.
4485      *
4486      * Example of correctly cloning a date:
4487      * <pre><code>
4488 //wrong way:
4489 var orig = new Date('10/1/2006');
4490 var copy = orig;
4491 copy.setDate(5);
4492 console.log(orig);  //returns 'Thu Oct 05 2006'!
4493
4494 //correct way:
4495 var orig = new Date('10/1/2006'),
4496     copy = Ext.Date.clone(orig);
4497 copy.setDate(5);
4498 console.log(orig);  //returns 'Thu Oct 01 2006'
4499      * </code></pre>
4500      * @param {Date} date The date
4501      * @return {Date} The new Date instance.
4502      */
4503     clone : function(date) {
4504         return new Date(date.getTime());
4505     },
4506
4507     /**
4508      * Checks if the current date is affected by Daylight Saving Time (DST).
4509      * @param {Date} date The date
4510      * @return {Boolean} True if the current date is affected by DST.
4511      */
4512     isDST : function(date) {
4513         // adapted from http://sencha.com/forum/showthread.php?p=247172#post247172
4514         // courtesy of @geoffrey.mcgill
4515         return new Date(date.getFullYear(), 0, 1).getTimezoneOffset() != date.getTimezoneOffset();
4516     },
4517
4518     /**
4519      * Attempts to clear all time information from this Date by setting the time to midnight of the same day,
4520      * automatically adjusting for Daylight Saving Time (DST) where applicable.
4521      * (note: DST timezone information for the browser's host operating system is assumed to be up-to-date)
4522      * @param {Date} date The date
4523      * @param {Boolean} clone true to create a clone of this date, clear the time and return it (defaults to false).
4524      * @return {Date} this or the clone.
4525      */
4526     clearTime : function(date, clone) {
4527         if (clone) {
4528             return Ext.Date.clearTime(Ext.Date.clone(date));
4529         }
4530
4531         // get current date before clearing time
4532         var d = date.getDate();
4533
4534         // clear time
4535         date.setHours(0);
4536         date.setMinutes(0);
4537         date.setSeconds(0);
4538         date.setMilliseconds(0);
4539
4540         if (date.getDate() != d) { // account for DST (i.e. day of month changed when setting hour = 0)
4541             // note: DST adjustments are assumed to occur in multiples of 1 hour (this is almost always the case)
4542             // refer to http://www.timeanddate.com/time/aboutdst.html for the (rare) exceptions to this rule
4543
4544             // increment hour until cloned date == current date
4545             for (var hr = 1, c = utilDate.add(date, Ext.Date.HOUR, hr); c.getDate() != d; hr++, c = utilDate.add(date, Ext.Date.HOUR, hr));
4546
4547             date.setDate(d);
4548             date.setHours(c.getHours());
4549         }
4550
4551         return date;
4552     },
4553
4554     /**
4555      * Provides a convenient method for performing basic date arithmetic. This method
4556      * does not modify the Date instance being called - it creates and returns
4557      * a new Date instance containing the resulting date value.
4558      *
4559      * Examples:
4560      * <pre><code>
4561 // Basic usage:
4562 var dt = Ext.Date.add(new Date('10/29/2006'), Ext.Date.DAY, 5);
4563 console.log(dt); //returns 'Fri Nov 03 2006 00:00:00'
4564
4565 // Negative values will be subtracted:
4566 var dt2 = Ext.Date.add(new Date('10/1/2006'), Ext.Date.DAY, -5);
4567 console.log(dt2); //returns 'Tue Sep 26 2006 00:00:00'
4568
4569      * </code></pre>
4570      *
4571      * @param {Date} date The date to modify
4572      * @param {String} interval A valid date interval enum value.
4573      * @param {Number} value The amount to add to the current date.
4574      * @return {Date} The new Date instance.
4575      */
4576     add : function(date, interval, value) {
4577         var d = Ext.Date.clone(date),
4578             Date = Ext.Date;
4579         if (!interval || value === 0) return d;
4580
4581         switch(interval.toLowerCase()) {
4582             case Ext.Date.MILLI:
4583                 d.setMilliseconds(d.getMilliseconds() + value);
4584                 break;
4585             case Ext.Date.SECOND:
4586                 d.setSeconds(d.getSeconds() + value);
4587                 break;
4588             case Ext.Date.MINUTE:
4589                 d.setMinutes(d.getMinutes() + value);
4590                 break;
4591             case Ext.Date.HOUR:
4592                 d.setHours(d.getHours() + value);
4593                 break;
4594             case Ext.Date.DAY:
4595                 d.setDate(d.getDate() + value);
4596                 break;
4597             case Ext.Date.MONTH:
4598                 var day = date.getDate();
4599                 if (day > 28) {
4600                     day = Math.min(day, Ext.Date.getLastDateOfMonth(Ext.Date.add(Ext.Date.getFirstDateOfMonth(date), 'mo', value)).getDate());
4601                 }
4602                 d.setDate(day);
4603                 d.setMonth(date.getMonth() + value);
4604                 break;
4605             case Ext.Date.YEAR:
4606                 d.setFullYear(date.getFullYear() + value);
4607                 break;
4608         }
4609         return d;
4610     },
4611
4612     /**
4613      * Checks if a date falls on or between the given start and end dates.
4614      * @param {Date} date The date to check
4615      * @param {Date} start Start date
4616      * @param {Date} end End date
4617      * @return {Boolean} true if this date falls on or between the given start and end dates.
4618      */
4619     between : function(date, start, end) {
4620         var t = date.getTime();
4621         return start.getTime() <= t && t <= end.getTime();
4622     },
4623
4624     //Maintains compatibility with old static and prototype window.Date methods.
4625     compat: function() {
4626         var nativeDate = window.Date,
4627             p, u,
4628             statics = ['useStrict', 'formatCodeToRegex', 'parseFunctions', 'parseRegexes', 'formatFunctions', 'y2kYear', 'MILLI', 'SECOND', 'MINUTE', 'HOUR', 'DAY', 'MONTH', 'YEAR', 'defaults', 'dayNames', 'monthNames', 'monthNumbers', 'getShortMonthName', 'getShortDayName', 'getMonthNumber', 'formatCodes', 'isValid', 'parseDate', 'getFormatCode', 'createFormat', 'createParser', 'parseCodes'],
4629             proto = ['dateFormat', 'format', 'getTimezone', 'getGMTOffset', 'getDayOfYear', 'getWeekOfYear', 'isLeapYear', 'getFirstDayOfMonth', 'getLastDayOfMonth', 'getDaysInMonth', 'getSuffix', 'clone', 'isDST', 'clearTime', 'add', 'between'];
4630
4631         //Append statics
4632         Ext.Array.forEach(statics, function(s) {
4633             nativeDate[s] = utilDate[s];
4634         });
4635
4636         //Append to prototype
4637         Ext.Array.forEach(proto, function(s) {
4638             nativeDate.prototype[s] = function() {
4639                 var args = Array.prototype.slice.call(arguments);
4640                 args.unshift(this);
4641                 return utilDate[s].apply(utilDate, args);
4642             };
4643         });
4644     }
4645 };
4646
4647 var utilDate = Ext.Date;
4648
4649 })();
4650
4651 /**
4652  * @author Jacky Nguyen <jacky@sencha.com>
4653  * @docauthor Jacky Nguyen <jacky@sencha.com>
4654  * @class Ext.Base
4655  *
4656  * The root of all classes created with {@link Ext#define}.
4657  *
4658  * Ext.Base is the building block of all Ext classes. All classes in Ext inherit from Ext.Base.
4659  * All prototype and static members of this class are inherited by all other classes.
4660  */
4661 (function(flexSetter) {
4662
4663 var Base = Ext.Base = function() {};
4664     Base.prototype = {
4665         $className: 'Ext.Base',
4666
4667         $class: Base,
4668
4669         /**
4670          * Get the reference to the current class from which this object was instantiated. Unlike {@link Ext.Base#statics},
4671          * `this.self` is scope-dependent and it's meant to be used for dynamic inheritance. See {@link Ext.Base#statics}
4672          * for a detailed comparison
4673          *
4674          *     Ext.define('My.Cat', {
4675          *         statics: {
4676          *             speciesName: 'Cat' // My.Cat.speciesName = 'Cat'
4677          *         },
4678          *
4679          *         constructor: function() {
4680          *             alert(this.self.speciesName); / dependent on 'this'
4681          *
4682          *             return this;
4683          *         },
4684          *
4685          *         clone: function() {
4686          *             return new this.self();
4687          *         }
4688          *     });
4689          *
4690          *
4691          *     Ext.define('My.SnowLeopard', {
4692          *         extend: 'My.Cat',
4693          *         statics: {
4694          *             speciesName: 'Snow Leopard'         // My.SnowLeopard.speciesName = 'Snow Leopard'
4695          *         }
4696          *     });
4697          *
4698          *     var cat = new My.Cat();                     // alerts 'Cat'
4699          *     var snowLeopard = new My.SnowLeopard();     // alerts 'Snow Leopard'
4700          *
4701          *     var clone = snowLeopard.clone();
4702          *     alert(Ext.getClassName(clone));             // alerts 'My.SnowLeopard'
4703          *
4704          * @type Ext.Class
4705          * @protected
4706          */
4707         self: Base,
4708
4709         // Default constructor, simply returns `this`
4710         constructor: function() {
4711             return this;
4712         },
4713
4714         //<feature classSystem.config>
4715         /**
4716          * Initialize configuration for this class. a typical example:
4717          *
4718          *     Ext.define('My.awesome.Class', {
4719          *         // The default config
4720          *         config: {
4721          *             name: 'Awesome',
4722          *             isAwesome: true
4723          *         },
4724          *
4725          *         constructor: function(config) {
4726          *             this.initConfig(config);
4727          *
4728          *             return this;
4729          *         }
4730          *     });
4731          *
4732          *     var awesome = new My.awesome.Class({
4733          *         name: 'Super Awesome'
4734          *     });
4735          *
4736          *     alert(awesome.getName()); // 'Super Awesome'
4737          *
4738          * @protected
4739          * @param {Object} config
4740          * @return {Object} mixins The mixin prototypes as key - value pairs
4741          */
4742         initConfig: function(config) {
4743             if (!this.$configInited) {
4744                 this.config = Ext.Object.merge({}, this.config || {}, config || {});
4745
4746                 this.applyConfig(this.config);
4747
4748                 this.$configInited = true;
4749             }
4750
4751             return this;
4752         },
4753
4754         /**
4755          * @private
4756          */
4757         setConfig: function(config) {
4758             this.applyConfig(config || {});
4759
4760             return this;
4761         },
4762
4763         /**
4764          * @private
4765          */
4766         applyConfig: flexSetter(function(name, value) {
4767             var setter = 'set' + Ext.String.capitalize(name);
4768
4769             if (typeof this[setter] === 'function') {
4770                 this[setter].call(this, value);
4771             }
4772
4773             return this;
4774         }),
4775         //</feature>
4776
4777         /**
4778          * Call the parent's overridden method. For example:
4779          *
4780          *     Ext.define('My.own.A', {
4781          *         constructor: function(test) {
4782          *             alert(test);
4783          *         }
4784          *     });
4785          *
4786          *     Ext.define('My.own.B', {
4787          *         extend: 'My.own.A',
4788          *
4789          *         constructor: function(test) {
4790          *             alert(test);
4791          *
4792          *             this.callParent([test + 1]);
4793          *         }
4794          *     });
4795          *
4796          *     Ext.define('My.own.C', {
4797          *         extend: 'My.own.B',
4798          *
4799          *         constructor: function() {
4800          *             alert("Going to call parent's overriden constructor...");
4801          *
4802          *             this.callParent(arguments);
4803          *         }
4804          *     });
4805          *
4806          *     var a = new My.own.A(1); // alerts '1'
4807          *     var b = new My.own.B(1); // alerts '1', then alerts '2'
4808          *     var c = new My.own.C(2); // alerts "Going to call parent's overriden constructor..."
4809          *                              // alerts '2', then alerts '3'
4810          *
4811          * @protected
4812          * @param {Array/Arguments} args The arguments, either an array or the `arguments` object
4813          * from the current method, for example: `this.callParent(arguments)`
4814          * @return {Object} Returns the result from the superclass' method
4815          */
4816         callParent: function(args) {
4817             var method = this.callParent.caller,
4818                 parentClass, methodName;
4819
4820             if (!method.$owner) {
4821                 if (!method.caller) {
4822                     Ext.Error.raise({
4823                         sourceClass: Ext.getClassName(this),
4824                         sourceMethod: "callParent",
4825                         msg: "Attempting to call a protected method from the public scope, which is not allowed"
4826                     });
4827                 }
4828
4829                 method = method.caller;
4830             }
4831
4832             parentClass = method.$owner.superclass;
4833             methodName = method.$name;
4834
4835             if (!(methodName in parentClass)) {
4836                 Ext.Error.raise({
4837                     sourceClass: Ext.getClassName(this),
4838                     sourceMethod: methodName,
4839                     msg: "this.callParent() was called but there's no such method (" + methodName +
4840                          ") found in the parent class (" + (Ext.getClassName(parentClass) || 'Object') + ")"
4841                  });
4842             }
4843
4844             return parentClass[methodName].apply(this, args || []);
4845         },
4846
4847
4848         /**
4849          * Get the reference to the class from which this object was instantiated. Note that unlike {@link Ext.Base#self},
4850          * `this.statics()` is scope-independent and it always returns the class from which it was called, regardless of what
4851          * `this` points to during run-time
4852          *
4853          *     Ext.define('My.Cat', {
4854          *         statics: {
4855          *             totalCreated: 0,
4856          *             speciesName: 'Cat' // My.Cat.speciesName = 'Cat'
4857          *         },
4858          *
4859          *         constructor: function() {
4860          *             var statics = this.statics();
4861          *
4862          *             alert(statics.speciesName);     // always equals to 'Cat' no matter what 'this' refers to
4863          *                                             // equivalent to: My.Cat.speciesName
4864          *
4865          *             alert(this.self.speciesName);   // dependent on 'this'
4866          *
4867          *             statics.totalCreated++;
4868          *
4869          *             return this;
4870          *         },
4871          *
4872          *         clone: function() {
4873          *             var cloned = new this.self;                      // dependent on 'this'
4874          *
4875          *             cloned.groupName = this.statics().speciesName;   // equivalent to: My.Cat.speciesName
4876          *
4877          *             return cloned;
4878          *         }
4879          *     });
4880          *
4881          *
4882          *     Ext.define('My.SnowLeopard', {
4883          *         extend: 'My.Cat',
4884          *
4885          *         statics: {
4886          *             speciesName: 'Snow Leopard'     // My.SnowLeopard.speciesName = 'Snow Leopard'
4887          *         },
4888          *
4889          *         constructor: function() {
4890          *             this.callParent();
4891          *         }
4892          *     });
4893          *
4894          *     var cat = new My.Cat();                 // alerts 'Cat', then alerts 'Cat'
4895          *
4896          *     var snowLeopard = new My.SnowLeopard(); // alerts 'Cat', then alerts 'Snow Leopard'
4897          *
4898          *     var clone = snowLeopard.clone();
4899          *     alert(Ext.getClassName(clone));         // alerts 'My.SnowLeopard'
4900          *     alert(clone.groupName);                 // alerts 'Cat'
4901          *
4902          *     alert(My.Cat.totalCreated);             // alerts 3
4903          *
4904          * @protected
4905          * @return {Ext.Class}
4906          */
4907         statics: function() {
4908             var method = this.statics.caller,
4909                 self = this.self;
4910
4911             if (!method) {
4912                 return self;
4913             }
4914
4915             return method.$owner;
4916         },
4917
4918         /**
4919          * Call the original method that was previously overridden with {@link Ext.Base#override}
4920          *
4921          *     Ext.define('My.Cat', {
4922          *         constructor: function() {
4923          *             alert("I'm a cat!");
4924          *
4925          *             return this;
4926          *         }
4927          *     });
4928          *
4929          *     My.Cat.override({
4930          *         constructor: function() {
4931          *             alert("I'm going to be a cat!");
4932          *
4933          *             var instance = this.callOverridden();
4934          *
4935          *             alert("Meeeeoooowwww");
4936          *
4937          *             return instance;
4938          *         }
4939          *     });
4940          *
4941          *     var kitty = new My.Cat(); // alerts "I'm going to be a cat!"
4942          *                               // alerts "I'm a cat!"
4943          *                               // alerts "Meeeeoooowwww"
4944          *
4945          * @param {Array/Arguments} args The arguments, either an array or the `arguments` object
4946          * @return {Object} Returns the result after calling the overridden method
4947          * @protected
4948          */
4949         callOverridden: function(args) {
4950             var method = this.callOverridden.caller;
4951
4952             if (!method.$owner) {
4953                 Ext.Error.raise({
4954                     sourceClass: Ext.getClassName(this),
4955                     sourceMethod: "callOverridden",
4956                     msg: "Attempting to call a protected method from the public scope, which is not allowed"
4957                 });
4958             }
4959
4960             if (!method.$previous) {
4961                 Ext.Error.raise({
4962                     sourceClass: Ext.getClassName(this),
4963                     sourceMethod: "callOverridden",
4964                     msg: "this.callOverridden was called in '" + method.$name +
4965                          "' but this method has never been overridden"
4966                  });
4967             }
4968
4969             return method.$previous.apply(this, args || []);
4970         },
4971
4972         destroy: function() {}
4973     };
4974
4975     // These static properties will be copied to every newly created class with {@link Ext#define}
4976     Ext.apply(Ext.Base, {
4977         /**
4978          * Create a new instance of this Class.
4979          *
4980          *     Ext.define('My.cool.Class', {
4981          *         ...
4982          *     });
4983          *
4984          *     My.cool.Class.create({
4985          *         someConfig: true
4986          *     });
4987          *
4988          * All parameters are passed to the constructor of the class.
4989          *
4990          * @return {Object} the created instance.
4991          * @static
4992          * @inheritable
4993          */
4994         create: function() {
4995             return Ext.create.apply(Ext, [this].concat(Array.prototype.slice.call(arguments, 0)));
4996         },
4997
4998         /**
4999          * @private
5000          * @inheritable
5001          */
5002         own: function(name, value) {
5003             if (typeof value == 'function') {
5004                 this.ownMethod(name, value);
5005             }
5006             else {
5007                 this.prototype[name] = value;
5008             }
5009         },
5010
5011         /**
5012          * @private
5013          * @inheritable
5014          */
5015         ownMethod: function(name, fn) {
5016             var originalFn;
5017
5018             if (typeof fn.$owner !== 'undefined' && fn !== Ext.emptyFn) {
5019                 originalFn = fn;
5020
5021                 fn = function() {
5022                     return originalFn.apply(this, arguments);
5023                 };
5024             }
5025
5026             var className;
5027             className = Ext.getClassName(this);
5028             if (className) {
5029                 fn.displayName = className + '#' + name;
5030             }
5031             fn.$owner = this;
5032             fn.$name = name;
5033
5034             this.prototype[name] = fn;
5035         },
5036
5037         /**
5038          * Add / override static properties of this class.
5039          *
5040          *     Ext.define('My.cool.Class', {
5041          *         ...
5042          *     });
5043          *
5044          *     My.cool.Class.addStatics({
5045          *         someProperty: 'someValue',      // My.cool.Class.someProperty = 'someValue'
5046          *         method1: function() { ... },    // My.cool.Class.method1 = function() { ... };
5047          *         method2: function() { ... }     // My.cool.Class.method2 = function() { ... };
5048          *     });
5049          *
5050          * @param {Object} members
5051          * @return {Ext.Base} this
5052          * @static
5053          * @inheritable
5054          */
5055         addStatics: function(members) {
5056             for (var name in members) {
5057                 if (members.hasOwnProperty(name)) {
5058                     this[name] = members[name];
5059                 }
5060             }
5061
5062             return this;
5063         },
5064
5065         /**
5066          * @private
5067          * @param {Object} members
5068          */
5069         addInheritableStatics: function(members) {
5070             var inheritableStatics,
5071                 hasInheritableStatics,
5072                 prototype = this.prototype,
5073                 name, member;
5074
5075             inheritableStatics = prototype.$inheritableStatics;
5076             hasInheritableStatics = prototype.$hasInheritableStatics;
5077
5078             if (!inheritableStatics) {
5079                 inheritableStatics = prototype.$inheritableStatics = [];
5080                 hasInheritableStatics = prototype.$hasInheritableStatics = {};
5081             }
5082
5083             var className = Ext.getClassName(this);
5084
5085             for (name in members) {
5086                 if (members.hasOwnProperty(name)) {
5087                     member = members[name];
5088                     if (typeof member == 'function') {
5089                         member.displayName = className + '.' + name;
5090                     }
5091                     this[name] = member;
5092
5093                     if (!hasInheritableStatics[name]) {
5094                         hasInheritableStatics[name] = true;
5095                         inheritableStatics.push(name);
5096                     }
5097                 }
5098             }
5099
5100             return this;
5101         },
5102
5103         /**
5104          * Add methods / properties to the prototype of this class.
5105          *
5106          *     Ext.define('My.awesome.Cat', {
5107          *         constructor: function() {
5108          *             ...
5109          *         }
5110          *     });
5111          *
5112          *      My.awesome.Cat.implement({
5113          *          meow: function() {
5114          *             alert('Meowww...');
5115          *          }
5116          *      });
5117          *
5118          *      var kitty = new My.awesome.Cat;
5119          *      kitty.meow();
5120          *
5121          * @param {Object} members
5122          * @static
5123          * @inheritable
5124          */
5125         implement: function(members) {
5126             var prototype = this.prototype,
5127                 enumerables = Ext.enumerables,
5128                 name, i, member;
5129             var className = Ext.getClassName(this);
5130             for (name in members) {
5131                 if (members.hasOwnProperty(name)) {
5132                     member = members[name];
5133
5134                     if (typeof member === 'function') {
5135                         member.$owner = this;
5136                         member.$name = name;
5137                         if (className) {
5138                             member.displayName = className + '#' + name;
5139                         }
5140                     }
5141
5142                     prototype[name] = member;
5143                 }
5144             }
5145
5146             if (enumerables) {
5147                 for (i = enumerables.length; i--;) {
5148                     name = enumerables[i];
5149
5150                     if (members.hasOwnProperty(name)) {
5151                         member = members[name];
5152                         member.$owner = this;
5153                         member.$name = name;
5154                         prototype[name] = member;
5155                     }
5156                 }
5157             }
5158         },
5159
5160         /**
5161          * Borrow another class' members to the prototype of this class.
5162          *
5163          *     Ext.define('Bank', {
5164          *         money: '$$$',
5165          *         printMoney: function() {
5166          *             alert('$$$$$$$');
5167          *         }
5168          *     });
5169          *
5170          *     Ext.define('Thief', {
5171          *         ...
5172          *     });
5173          *
5174          *     Thief.borrow(Bank, ['money', 'printMoney']);
5175          *
5176          *     var steve = new Thief();
5177          *
5178          *     alert(steve.money); // alerts '$$$'
5179          *     steve.printMoney(); // alerts '$$$$$$$'
5180          *
5181          * @param {Ext.Base} fromClass The class to borrow members from
5182          * @param {String/String[]} members The names of the members to borrow
5183          * @return {Ext.Base} this
5184          * @static
5185          * @inheritable
5186          */
5187         borrow: function(fromClass, members) {
5188             var fromPrototype = fromClass.prototype,
5189                 i, ln, member;
5190
5191             members = Ext.Array.from(members);
5192
5193             for (i = 0, ln = members.length; i < ln; i++) {
5194                 member = members[i];
5195
5196                 this.own(member, fromPrototype[member]);
5197             }
5198
5199             return this;
5200         },
5201
5202         /**
5203          * Override prototype members of this class. Overridden methods can be invoked via
5204          * {@link Ext.Base#callOverridden}
5205          *
5206          *     Ext.define('My.Cat', {
5207          *         constructor: function() {
5208          *             alert("I'm a cat!");
5209          *
5210          *             return this;
5211          *         }
5212          *     });
5213          *
5214          *     My.Cat.override({
5215          *         constructor: function() {
5216          *             alert("I'm going to be a cat!");
5217          *
5218          *             var instance = this.callOverridden();
5219          *
5220          *             alert("Meeeeoooowwww");
5221          *
5222          *             return instance;
5223          *         }
5224          *     });
5225          *
5226          *     var kitty = new My.Cat(); // alerts "I'm going to be a cat!"
5227          *                               // alerts "I'm a cat!"
5228          *                               // alerts "Meeeeoooowwww"
5229          *
5230          * @param {Object} members
5231          * @return {Ext.Base} this
5232          * @static
5233          * @inheritable
5234          */
5235         override: function(members) {
5236             var prototype = this.prototype,
5237                 enumerables = Ext.enumerables,
5238                 name, i, member, previous;
5239
5240             if (arguments.length === 2) {
5241                 name = members;
5242                 member = arguments[1];
5243
5244                 if (typeof member == 'function') {
5245                     if (typeof prototype[name] == 'function') {
5246                         previous = prototype[name];
5247                         member.$previous = previous;
5248                     }
5249
5250                     this.ownMethod(name, member);
5251                 }
5252                 else {
5253                     prototype[name] = member;
5254                 }
5255
5256                 return this;
5257             }
5258
5259             for (name in members) {
5260                 if (members.hasOwnProperty(name)) {
5261                     member = members[name];
5262
5263                     if (typeof member === 'function') {
5264                         if (typeof prototype[name] === 'function') {
5265                             previous = prototype[name];
5266                             member.$previous = previous;
5267                         }
5268
5269                         this.ownMethod(name, member);
5270                     }
5271                     else {
5272                         prototype[name] = member;
5273                     }
5274                 }
5275             }
5276
5277             if (enumerables) {
5278                 for (i = enumerables.length; i--;) {
5279                     name = enumerables[i];
5280
5281                     if (members.hasOwnProperty(name)) {
5282                         if (typeof prototype[name] !== 'undefined') {
5283                             previous = prototype[name];
5284                             members[name].$previous = previous;
5285                         }
5286
5287                         this.ownMethod(name, members[name]);
5288                     }
5289                 }
5290             }
5291
5292             return this;
5293         },
5294
5295         //<feature classSystem.mixins>
5296         /**
5297          * Used internally by the mixins pre-processor
5298          * @private
5299          * @inheritable
5300          */
5301         mixin: function(name, cls) {
5302             var mixin = cls.prototype,
5303                 my = this.prototype,
5304                 key, fn;
5305
5306             for (key in mixin) {
5307                 if (mixin.hasOwnProperty(key)) {
5308                     if (typeof my[key] === 'undefined' && key !== 'mixins' && key !== 'mixinId') {
5309                         if (typeof mixin[key] === 'function') {
5310                             fn = mixin[key];
5311
5312                             if (typeof fn.$owner === 'undefined') {
5313                                 this.ownMethod(key, fn);
5314                             }
5315                             else {
5316                                 my[key] = fn;
5317                             }
5318                         }
5319                         else {
5320                             my[key] = mixin[key];
5321                         }
5322                     }
5323                     //<feature classSystem.config>
5324                     else if (key === 'config' && my.config && mixin.config) {
5325                         Ext.Object.merge(my.config, mixin.config);
5326                     }
5327                     //</feature>
5328                 }
5329             }
5330
5331             if (typeof mixin.onClassMixedIn !== 'undefined') {
5332                 mixin.onClassMixedIn.call(cls, this);
5333             }
5334
5335             if (!my.hasOwnProperty('mixins')) {
5336                 if ('mixins' in my) {
5337                     my.mixins = Ext.Object.merge({}, my.mixins);
5338                 }
5339                 else {
5340                     my.mixins = {};
5341                 }
5342             }
5343
5344             my.mixins[name] = mixin;
5345         },
5346         //</feature>
5347
5348         /**
5349          * Get the current class' name in string format.
5350          *
5351          *     Ext.define('My.cool.Class', {
5352          *         constructor: function() {
5353          *             alert(this.self.getName()); // alerts 'My.cool.Class'
5354          *         }
5355          *     });
5356          *
5357          *     My.cool.Class.getName(); // 'My.cool.Class'
5358          *
5359          * @return {String} className
5360          * @static
5361          * @inheritable
5362          */
5363         getName: function() {
5364             return Ext.getClassName(this);
5365         },
5366
5367         /**
5368          * Create aliases for existing prototype methods. Example:
5369          *
5370          *     Ext.define('My.cool.Class', {
5371          *         method1: function() { ... },
5372          *         method2: function() { ... }
5373          *     });
5374          *
5375          *     var test = new My.cool.Class();
5376          *
5377          *     My.cool.Class.createAlias({
5378          *         method3: 'method1',
5379          *         method4: 'method2'
5380          *     });
5381          *
5382          *     test.method3(); // test.method1()
5383          *
5384          *     My.cool.Class.createAlias('method5', 'method3');
5385          *
5386          *     test.method5(); // test.method3() -> test.method1()
5387          *
5388          * @param {String/Object} alias The new method name, or an object to set multiple aliases. See
5389          * {@link Ext.Function#flexSetter flexSetter}
5390          * @param {String/Object} origin The original method name
5391          * @static
5392          * @inheritable
5393          * @method
5394          */
5395         createAlias: flexSetter(function(alias, origin) {
5396             this.prototype[alias] = function() {
5397                 return this[origin].apply(this, arguments);
5398             }
5399         })
5400     });
5401
5402 })(Ext.Function.flexSetter);
5403
5404 /**
5405  * @author Jacky Nguyen <jacky@sencha.com>
5406  * @docauthor Jacky Nguyen <jacky@sencha.com>
5407  * @class Ext.Class
5408  *
5409  * Handles class creation throughout the framework. This is a low level factory that is used by Ext.ClassManager and generally
5410  * should not be used directly. If you choose to use Ext.Class you will lose out on the namespace, aliasing and depency loading
5411  * features made available by Ext.ClassManager. The only time you would use Ext.Class directly is to create an anonymous class.
5412  *
5413  * If you wish to create a class you should use {@link Ext#define Ext.define} which aliases
5414  * {@link Ext.ClassManager#create Ext.ClassManager.create} to enable namespacing and dynamic dependency resolution.
5415  *
5416  * Ext.Class is the factory and **not** the superclass of everything. For the base class that **all** Ext classes inherit
5417  * from, see {@link Ext.Base}.
5418  */
5419 (function() {
5420
5421     var Class,
5422         Base = Ext.Base,
5423         baseStaticProperties = [],
5424         baseStaticProperty;
5425
5426     for (baseStaticProperty in Base) {
5427         if (Base.hasOwnProperty(baseStaticProperty)) {
5428             baseStaticProperties.push(baseStaticProperty);
5429         }
5430     }
5431
5432     /**
5433      * @method constructor
5434      * Creates new class.
5435      * @param {Object} classData An object represent the properties of this class
5436      * @param {Function} createdFn (Optional) The callback function to be executed when this class is fully created.
5437      * Note that the creation process can be asynchronous depending on the pre-processors used.
5438      * @return {Ext.Base} The newly created class
5439      */
5440     Ext.Class = Class = function(newClass, classData, onClassCreated) {
5441         if (typeof newClass != 'function') {
5442             onClassCreated = classData;
5443             classData = newClass;
5444             newClass = function() {
5445                 return this.constructor.apply(this, arguments);
5446             };
5447         }
5448
5449         if (!classData) {
5450             classData = {};
5451         }
5452
5453         var preprocessorStack = classData.preprocessors || Class.getDefaultPreprocessors(),
5454             registeredPreprocessors = Class.getPreprocessors(),
5455             index = 0,
5456             preprocessors = [],
5457             preprocessor, staticPropertyName, process, i, j, ln;
5458
5459         for (i = 0, ln = baseStaticProperties.length; i < ln; i++) {
5460             staticPropertyName = baseStaticProperties[i];
5461             newClass[staticPropertyName] = Base[staticPropertyName];
5462         }
5463
5464         delete classData.preprocessors;
5465
5466         for (j = 0, ln = preprocessorStack.length; j < ln; j++) {
5467             preprocessor = preprocessorStack[j];
5468
5469             if (typeof preprocessor == 'string') {
5470                 preprocessor = registeredPreprocessors[preprocessor];
5471
5472                 if (!preprocessor.always) {
5473                     if (classData.hasOwnProperty(preprocessor.name)) {
5474                         preprocessors.push(preprocessor.fn);
5475                     }
5476                 }
5477                 else {
5478                     preprocessors.push(preprocessor.fn);
5479                 }
5480             }
5481             else {
5482                 preprocessors.push(preprocessor);
5483             }
5484         }
5485
5486         classData.onClassCreated = onClassCreated || Ext.emptyFn;
5487
5488         classData.onBeforeClassCreated = function(cls, data) {
5489             onClassCreated = data.onClassCreated;
5490
5491             delete data.onBeforeClassCreated;
5492             delete data.onClassCreated;
5493
5494             cls.implement(data);
5495
5496             onClassCreated.call(cls, cls);
5497         };
5498
5499         process = function(cls, data) {
5500             preprocessor = preprocessors[index++];
5501
5502             if (!preprocessor) {
5503                 data.onBeforeClassCreated.apply(this, arguments);
5504                 return;
5505             }
5506
5507             if (preprocessor.call(this, cls, data, process) !== false) {
5508                 process.apply(this, arguments);
5509             }
5510         };
5511
5512         process.call(Class, newClass, classData);
5513
5514         return newClass;
5515     };
5516
5517     Ext.apply(Class, {
5518
5519         /** @private */
5520         preprocessors: {},
5521
5522         /**
5523          * Register a new pre-processor to be used during the class creation process
5524          *
5525          * @member Ext.Class
5526          * @param {String} name The pre-processor's name
5527          * @param {Function} fn The callback function to be executed. Typical format:
5528          *
5529          *     function(cls, data, fn) {
5530          *         // Your code here
5531          *
5532          *         // Execute this when the processing is finished.
5533          *         // Asynchronous processing is perfectly ok
5534          *         if (fn) {
5535          *             fn.call(this, cls, data);
5536          *         }
5537          *     });
5538          *
5539          * @param {Function} fn.cls The created class
5540          * @param {Object} fn.data The set of properties passed in {@link Ext.Class} constructor
5541          * @param {Function} fn.fn The callback function that **must** to be executed when this pre-processor finishes,
5542          * regardless of whether the processing is synchronous or aynchronous
5543          *
5544          * @return {Ext.Class} this
5545          * @static
5546          */
5547         registerPreprocessor: function(name, fn, always) {
5548             this.preprocessors[name] = {
5549                 name: name,
5550                 always: always ||  false,
5551                 fn: fn
5552             };
5553
5554             return this;
5555         },
5556
5557         /**
5558          * Retrieve a pre-processor callback function by its name, which has been registered before
5559          *
5560          * @param {String} name
5561          * @return {Function} preprocessor
5562          * @static
5563          */
5564         getPreprocessor: function(name) {
5565             return this.preprocessors[name];
5566         },
5567
5568         getPreprocessors: function() {
5569             return this.preprocessors;
5570         },
5571
5572         /**
5573          * Retrieve the array stack of default pre-processors
5574          *
5575          * @return {Function[]} defaultPreprocessors
5576          * @static
5577          */
5578         getDefaultPreprocessors: function() {
5579             return this.defaultPreprocessors || [];
5580         },
5581
5582         /**
5583          * Set the default array stack of default pre-processors
5584          *
5585          * @param {Function/Function[]} preprocessors
5586          * @return {Ext.Class} this
5587          * @static
5588          */
5589         setDefaultPreprocessors: function(preprocessors) {
5590             this.defaultPreprocessors = Ext.Array.from(preprocessors);
5591
5592             return this;
5593         },
5594
5595         /**
5596          * Inserts this pre-processor at a specific position in the stack, optionally relative to
5597          * any existing pre-processor. For example:
5598          *
5599          *     Ext.Class.registerPreprocessor('debug', function(cls, data, fn) {
5600          *         // Your code here
5601          *
5602          *         if (fn) {
5603          *             fn.call(this, cls, data);
5604          *         }
5605          *     }).setDefaultPreprocessorPosition('debug', 'last');
5606          *
5607          * @param {String} name The pre-processor name. Note that it needs to be registered with
5608          * {@link #registerPreprocessor registerPreprocessor} before this
5609          * @param {String} offset The insertion position. Four possible values are:
5610          * 'first', 'last', or: 'before', 'after' (relative to the name provided in the third argument)
5611          * @param {String} relativeName
5612          * @return {Ext.Class} this
5613          * @static
5614          */
5615         setDefaultPreprocessorPosition: function(name, offset, relativeName) {
5616             var defaultPreprocessors = this.defaultPreprocessors,
5617                 index;
5618
5619             if (typeof offset == 'string') {
5620                 if (offset === 'first') {
5621                     defaultPreprocessors.unshift(name);
5622
5623                     return this;
5624                 }
5625                 else if (offset === 'last') {
5626                     defaultPreprocessors.push(name);
5627
5628                     return this;
5629                 }
5630
5631                 offset = (offset === 'after') ? 1 : -1;
5632             }
5633
5634             index = Ext.Array.indexOf(defaultPreprocessors, relativeName);
5635
5636             if (index !== -1) {
5637                 Ext.Array.splice(defaultPreprocessors, Math.max(0, index + offset), 0, name);
5638             }
5639
5640             return this;
5641         }
5642     });
5643
5644     /**
5645      * @cfg {String} extend
5646      * The parent class that this class extends. For example:
5647      *
5648      *     Ext.define('Person', {
5649      *         say: function(text) { alert(text); }
5650      *     });
5651      *
5652      *     Ext.define('Developer', {
5653      *         extend: 'Person',
5654      *         say: function(text) { this.callParent(["print "+text]); }
5655      *     });
5656      */
5657     Class.registerPreprocessor('extend', function(cls, data) {
5658         var extend = data.extend,
5659             base = Ext.Base,
5660             basePrototype = base.prototype,
5661             prototype = function() {},
5662             parent, i, k, ln, staticName, parentStatics,
5663             parentPrototype, clsPrototype;
5664
5665         if (extend && extend !== Object) {
5666             parent = extend;
5667         }
5668         else {
5669             parent = base;
5670         }
5671
5672         parentPrototype = parent.prototype;
5673
5674         prototype.prototype = parentPrototype;
5675         clsPrototype = cls.prototype = new prototype();
5676
5677         if (!('$class' in parent)) {
5678             for (i in basePrototype) {
5679                 if (!parentPrototype[i]) {
5680                     parentPrototype[i] = basePrototype[i];
5681                 }
5682             }
5683         }
5684
5685         clsPrototype.self = cls;
5686
5687         cls.superclass = clsPrototype.superclass = parentPrototype;
5688
5689         delete data.extend;
5690
5691         //<feature classSystem.inheritableStatics>
5692         // Statics inheritance
5693         parentStatics = parentPrototype.$inheritableStatics;
5694
5695         if (parentStatics) {
5696             for (k = 0, ln = parentStatics.length; k < ln; k++) {
5697                 staticName = parentStatics[k];
5698
5699                 if (!cls.hasOwnProperty(staticName)) {
5700                     cls[staticName] = parent[staticName];
5701                 }
5702             }
5703         }
5704         //</feature>
5705
5706         //<feature classSystem.config>
5707         // Merge the parent class' config object without referencing it
5708         if (parentPrototype.config) {
5709             clsPrototype.config = Ext.Object.merge({}, parentPrototype.config);
5710         }
5711         else {
5712             clsPrototype.config = {};
5713         }
5714         //</feature>
5715
5716         //<feature classSystem.onClassExtended>
5717         if (clsPrototype.$onExtended) {
5718             clsPrototype.$onExtended.call(cls, cls, data);
5719         }
5720
5721         if (data.onClassExtended) {
5722             clsPrototype.$onExtended = data.onClassExtended;
5723             delete data.onClassExtended;
5724         }
5725         //</feature>
5726
5727     }, true);
5728
5729     //<feature classSystem.statics>
5730     /**
5731      * @cfg {Object} statics
5732      * List of static methods for this class. For example:
5733      *
5734      *     Ext.define('Computer', {
5735      *          statics: {
5736      *              factory: function(brand) {
5737      *                  // 'this' in static methods refer to the class itself
5738      *                  return new this(brand);
5739      *              }
5740      *          },
5741      *
5742      *          constructor: function() { ... }
5743      *     });
5744      *
5745      *     var dellComputer = Computer.factory('Dell');
5746      */
5747     Class.registerPreprocessor('statics', function(cls, data) {
5748         cls.addStatics(data.statics);
5749
5750         delete data.statics;
5751     });
5752     //</feature>
5753
5754     //<feature classSystem.inheritableStatics>
5755     /**
5756      * @cfg {Object} inheritableStatics
5757      * List of inheritable static methods for this class.
5758      * Otherwise just like {@link #statics} but subclasses inherit these methods.
5759      */
5760     Class.registerPreprocessor('inheritableStatics', function(cls, data) {
5761         cls.addInheritableStatics(data.inheritableStatics);
5762
5763         delete data.inheritableStatics;
5764     });
5765     //</feature>
5766
5767     //<feature classSystem.config>
5768     /**
5769      * @cfg {Object} config
5770      * List of configuration options with their default values, for which automatically
5771      * accessor methods are generated.  For example:
5772      *
5773      *     Ext.define('SmartPhone', {
5774      *          config: {
5775      *              hasTouchScreen: false,
5776      *              operatingSystem: 'Other',
5777      *              price: 500
5778      *          },
5779      *          constructor: function(cfg) {
5780      *              this.initConfig(cfg);
5781      *          }
5782      *     });
5783      *
5784      *     var iPhone = new SmartPhone({
5785      *          hasTouchScreen: true,
5786      *          operatingSystem: 'iOS'
5787      *     });
5788      *
5789      *     iPhone.getPrice(); // 500;
5790      *     iPhone.getOperatingSystem(); // 'iOS'
5791      *     iPhone.getHasTouchScreen(); // true;
5792      *     iPhone.hasTouchScreen(); // true
5793      */
5794     Class.registerPreprocessor('config', function(cls, data) {
5795         var prototype = cls.prototype;
5796
5797         Ext.Object.each(data.config, function(name) {
5798             var cName = name.charAt(0).toUpperCase() + name.substr(1),
5799                 pName = name,
5800                 apply = 'apply' + cName,
5801                 setter = 'set' + cName,
5802                 getter = 'get' + cName;
5803
5804             if (!(apply in prototype) && !data.hasOwnProperty(apply)) {
5805                 data[apply] = function(val) {
5806                     return val;
5807                 };
5808             }
5809
5810             if (!(setter in prototype) && !data.hasOwnProperty(setter)) {
5811                 data[setter] = function(val) {
5812                     var ret = this[apply].call(this, val, this[pName]);
5813
5814                     if (typeof ret != 'undefined') {
5815                         this[pName] = ret;
5816                     }
5817
5818                     return this;
5819                 };
5820             }
5821
5822             if (!(getter in prototype) && !data.hasOwnProperty(getter)) {
5823                 data[getter] = function() {
5824                     return this[pName];
5825                 };
5826             }
5827         });
5828
5829         Ext.Object.merge(prototype.config, data.config);
5830         delete data.config;
5831     });
5832     //</feature>
5833
5834     //<feature classSystem.mixins>
5835     /**
5836      * @cfg {Object} mixins
5837      * List of classes to mix into this class. For example:
5838      *
5839      *     Ext.define('CanSing', {
5840      *          sing: function() {
5841      *              alert("I'm on the highway to hell...")
5842      *          }
5843      *     });
5844      *
5845      *     Ext.define('Musician', {
5846      *          extend: 'Person',
5847      *
5848      *          mixins: {
5849      *              canSing: 'CanSing'
5850      *          }
5851      *     })
5852      */
5853     Class.registerPreprocessor('mixins', function(cls, data) {
5854         var mixins = data.mixins,
5855             name, mixin, i, ln;
5856
5857         delete data.mixins;
5858
5859         Ext.Function.interceptBefore(data, 'onClassCreated', function(cls) {
5860             if (mixins instanceof Array) {
5861                 for (i = 0,ln = mixins.length; i < ln; i++) {
5862                     mixin = mixins[i];
5863                     name = mixin.prototype.mixinId || mixin.$className;
5864
5865                     cls.mixin(name, mixin);
5866                 }
5867             }
5868             else {
5869                 for (name in mixins) {
5870                     if (mixins.hasOwnProperty(name)) {
5871                         cls.mixin(name, mixins[name]);
5872                     }
5873                 }
5874             }
5875         });
5876     });
5877
5878     //</feature>
5879
5880     Class.setDefaultPreprocessors([
5881         'extend'
5882         //<feature classSystem.statics>
5883         ,'statics'
5884         //</feature>
5885         //<feature classSystem.inheritableStatics>
5886         ,'inheritableStatics'
5887         //</feature>
5888         //<feature classSystem.config>
5889         ,'config'
5890         //</feature>
5891         //<feature classSystem.mixins>
5892         ,'mixins'
5893         //</feature>
5894     ]);
5895
5896     //<feature classSystem.backwardsCompatible>
5897     // Backwards compatible
5898     Ext.extend = function(subclass, superclass, members) {
5899         if (arguments.length === 2 && Ext.isObject(superclass)) {
5900             members = superclass;
5901             superclass = subclass;
5902             subclass = null;
5903         }
5904
5905         var cls;
5906
5907         if (!superclass) {
5908             Ext.Error.raise("Attempting to extend from a class which has not been loaded on the page.");
5909         }
5910
5911         members.extend = superclass;
5912         members.preprocessors = [
5913             'extend'
5914             //<feature classSystem.statics>
5915             ,'statics'
5916             //</feature>
5917             //<feature classSystem.inheritableStatics>
5918             ,'inheritableStatics'
5919             //</feature>
5920             //<feature classSystem.mixins>
5921             ,'mixins'
5922             //</feature>
5923             //<feature classSystem.config>
5924             ,'config'
5925             //</feature>
5926         ];
5927
5928         if (subclass) {
5929             cls = new Class(subclass, members);
5930         }
5931         else {
5932             cls = new Class(members);
5933         }
5934
5935         cls.prototype.override = function(o) {
5936             for (var m in o) {
5937                 if (o.hasOwnProperty(m)) {
5938                     this[m] = o[m];
5939                 }
5940             }
5941         };
5942
5943         return cls;
5944     };
5945     //</feature>
5946
5947 })();
5948
5949 /**
5950  * @author Jacky Nguyen <jacky@sencha.com>
5951  * @docauthor Jacky Nguyen <jacky@sencha.com>
5952  * @class Ext.ClassManager
5953  *
5954  * Ext.ClassManager manages all classes and handles mapping from string class name to
5955  * actual class objects throughout the whole framework. It is not generally accessed directly, rather through
5956  * these convenient shorthands:
5957  *
5958  * - {@link Ext#define Ext.define}
5959  * - {@link Ext#create Ext.create}
5960  * - {@link Ext#widget Ext.widget}
5961  * - {@link Ext#getClass Ext.getClass}
5962  * - {@link Ext#getClassName Ext.getClassName}
5963  *
5964  * # Basic syntax:
5965  *
5966  *     Ext.define(className, properties);
5967  *
5968  * in which `properties` is an object represent a collection of properties that apply to the class. See
5969  * {@link Ext.ClassManager#create} for more detailed instructions.
5970  *
5971  *     Ext.define('Person', {
5972  *          name: 'Unknown',
5973  *
5974  *          constructor: function(name) {
5975  *              if (name) {
5976  *                  this.name = name;
5977  *              }
5978  *
5979  *              return this;
5980  *          },
5981  *
5982  *          eat: function(foodType) {
5983  *              alert("I'm eating: " + foodType);
5984  *
5985  *              return this;
5986  *          }
5987  *     });
5988  *
5989  *     var aaron = new Person("Aaron");
5990  *     aaron.eat("Sandwich"); // alert("I'm eating: Sandwich");
5991  *
5992  * Ext.Class has a powerful set of extensible {@link Ext.Class#registerPreprocessor pre-processors} which takes care of
5993  * everything related to class creation, including but not limited to inheritance, mixins, configuration, statics, etc.
5994  *
5995  * # Inheritance:
5996  *
5997  *     Ext.define('Developer', {
5998  *          extend: 'Person',
5999  *
6000  *          constructor: function(name, isGeek) {
6001  *              this.isGeek = isGeek;
6002  *
6003  *              // Apply a method from the parent class' prototype
6004  *              this.callParent([name]);
6005  *
6006  *              return this;
6007  *
6008  *          },
6009  *
6010  *          code: function(language) {
6011  *              alert("I'm coding in: " + language);
6012  *
6013  *              this.eat("Bugs");
6014  *
6015  *              return this;
6016  *          }
6017  *     });
6018  *
6019  *     var jacky = new Developer("Jacky", true);
6020  *     jacky.code("JavaScript"); // alert("I'm coding in: JavaScript");
6021  *                               // alert("I'm eating: Bugs");
6022  *
6023  * See {@link Ext.Base#callParent} for more details on calling superclass' methods
6024  *
6025  * # Mixins:
6026  *
6027  *     Ext.define('CanPlayGuitar', {
6028  *          playGuitar: function() {
6029  *             alert("F#...G...D...A");
6030  *          }
6031  *     });
6032  *
6033  *     Ext.define('CanComposeSongs', {
6034  *          composeSongs: function() { ... }
6035  *     });
6036  *
6037  *     Ext.define('CanSing', {
6038  *          sing: function() {
6039  *              alert("I'm on the highway to hell...")
6040  *          }
6041  *     });
6042  *
6043  *     Ext.define('Musician', {
6044  *          extend: 'Person',
6045  *
6046  *          mixins: {
6047  *              canPlayGuitar: 'CanPlayGuitar',
6048  *              canComposeSongs: 'CanComposeSongs',
6049  *              canSing: 'CanSing'
6050  *          }
6051  *     })
6052  *
6053  *     Ext.define('CoolPerson', {
6054  *          extend: 'Person',
6055  *
6056  *          mixins: {
6057  *              canPlayGuitar: 'CanPlayGuitar',
6058  *              canSing: 'CanSing'
6059  *          },
6060  *
6061  *          sing: function() {
6062  *              alert("Ahem....");
6063  *
6064  *              this.mixins.canSing.sing.call(this);
6065  *
6066  *              alert("[Playing guitar at the same time...]");
6067  *
6068  *              this.playGuitar();
6069  *          }
6070  *     });
6071  *
6072  *     var me = new CoolPerson("Jacky");
6073  *
6074  *     me.sing(); // alert("Ahem...");
6075  *                // alert("I'm on the highway to hell...");
6076  *                // alert("[Playing guitar at the same time...]");
6077  *                // alert("F#...G...D...A");
6078  *
6079  * # Config:
6080  *
6081  *     Ext.define('SmartPhone', {
6082  *          config: {
6083  *              hasTouchScreen: false,
6084  *              operatingSystem: 'Other',
6085  *              price: 500
6086  *          },
6087  *
6088  *          isExpensive: false,
6089  *
6090  *          constructor: function(config) {
6091  *              this.initConfig(config);
6092  *
6093  *              return this;
6094  *          },
6095  *
6096  *          applyPrice: function(price) {
6097  *              this.isExpensive = (price > 500);
6098  *
6099  *              return price;
6100  *          },
6101  *
6102  *          applyOperatingSystem: function(operatingSystem) {
6103  *              if (!(/^(iOS|Android|BlackBerry)$/i).test(operatingSystem)) {
6104  *                  return 'Other';
6105  *              }
6106  *
6107  *              return operatingSystem;
6108  *          }
6109  *     });
6110  *
6111  *     var iPhone = new SmartPhone({
6112  *          hasTouchScreen: true,
6113  *          operatingSystem: 'iOS'
6114  *     });
6115  *
6116  *     iPhone.getPrice(); // 500;
6117  *     iPhone.getOperatingSystem(); // 'iOS'
6118  *     iPhone.getHasTouchScreen(); // true;
6119  *     iPhone.hasTouchScreen(); // true
6120  *
6121  *     iPhone.isExpensive; // false;
6122  *     iPhone.setPrice(600);
6123  *     iPhone.getPrice(); // 600
6124  *     iPhone.isExpensive; // true;
6125  *
6126  *     iPhone.setOperatingSystem('AlienOS');
6127  *     iPhone.getOperatingSystem(); // 'Other'
6128  *
6129  * # Statics:
6130  *
6131  *     Ext.define('Computer', {
6132  *          statics: {
6133  *              factory: function(brand) {
6134  *                 // 'this' in static methods refer to the class itself
6135  *                  return new this(brand);
6136  *              }
6137  *          },
6138  *
6139  *          constructor: function() { ... }
6140  *     });
6141  *
6142  *     var dellComputer = Computer.factory('Dell');
6143  *
6144  * Also see {@link Ext.Base#statics} and {@link Ext.Base#self} for more details on accessing
6145  * static properties within class methods
6146  *
6147  * @singleton
6148  */
6149 (function(Class, alias) {
6150
6151     var slice = Array.prototype.slice;
6152
6153     var Manager = Ext.ClassManager = {
6154
6155         /**
6156          * @property {Object} classes
6157          * All classes which were defined through the ClassManager. Keys are the
6158          * name of the classes and the values are references to the classes.
6159          * @private
6160          */
6161         classes: {},
6162
6163         /**
6164          * @private
6165          */
6166         existCache: {},
6167
6168         /**
6169          * @private
6170          */
6171         namespaceRewrites: [{
6172             from: 'Ext.',
6173             to: Ext
6174         }],
6175
6176         /**
6177          * @private
6178          */
6179         maps: {
6180             alternateToName: {},
6181             aliasToName: {},
6182             nameToAliases: {}
6183         },
6184
6185         /** @private */
6186         enableNamespaceParseCache: true,
6187
6188         /** @private */
6189         namespaceParseCache: {},
6190
6191         /** @private */
6192         instantiators: [],
6193
6194         /** @private */
6195         instantiationCounts: {},
6196
6197         /**
6198          * Checks if a class has already been created.
6199          *
6200          * @param {String} className
6201          * @return {Boolean} exist
6202          */
6203         isCreated: function(className) {
6204             var i, ln, part, root, parts;
6205
6206             if (typeof className !== 'string' || className.length < 1) {
6207                 Ext.Error.raise({
6208                     sourceClass: "Ext.ClassManager",
6209                     sourceMethod: "exist",
6210                     msg: "Invalid classname, must be a string and must not be empty"
6211                 });
6212             }
6213
6214             if (this.classes.hasOwnProperty(className) || this.existCache.hasOwnProperty(className)) {
6215                 return true;
6216             }
6217
6218             root = Ext.global;
6219             parts = this.parseNamespace(className);
6220
6221             for (i = 0, ln = parts.length; i < ln; i++) {
6222                 part = parts[i];
6223
6224                 if (typeof part !== 'string') {
6225                     root = part;
6226                 } else {
6227                     if (!root || !root[part]) {
6228                         return false;
6229                     }
6230
6231                     root = root[part];
6232                 }
6233             }
6234
6235             Ext.Loader.historyPush(className);
6236
6237             this.existCache[className] = true;
6238
6239             return true;
6240         },
6241
6242         /**
6243          * Supports namespace rewriting
6244          * @private
6245          */
6246         parseNamespace: function(namespace) {
6247             if (typeof namespace !== 'string') {
6248                 Ext.Error.raise({
6249                     sourceClass: "Ext.ClassManager",
6250                     sourceMethod: "parseNamespace",
6251                     msg: "Invalid namespace, must be a string"
6252                 });
6253             }
6254
6255             var cache = this.namespaceParseCache;
6256
6257             if (this.enableNamespaceParseCache) {
6258                 if (cache.hasOwnProperty(namespace)) {
6259                     return cache[namespace];
6260                 }
6261             }
6262
6263             var parts = [],
6264                 rewrites = this.namespaceRewrites,
6265                 rewrite, from, to, i, ln, root = Ext.global;
6266
6267             for (i = 0, ln = rewrites.length; i < ln; i++) {
6268                 rewrite = rewrites[i];
6269                 from = rewrite.from;
6270                 to = rewrite.to;
6271
6272                 if (namespace === from || namespace.substring(0, from.length) === from) {
6273                     namespace = namespace.substring(from.length);
6274
6275                     if (typeof to !== 'string') {
6276                         root = to;
6277                     } else {
6278                         parts = parts.concat(to.split('.'));
6279                     }
6280
6281                     break;
6282                 }
6283             }
6284
6285             parts.push(root);
6286
6287             parts = parts.concat(namespace.split('.'));
6288
6289             if (this.enableNamespaceParseCache) {
6290                 cache[namespace] = parts;
6291             }
6292
6293             return parts;
6294         },
6295
6296         /**
6297          * Creates a namespace and assign the `value` to the created object
6298          *
6299          *     Ext.ClassManager.setNamespace('MyCompany.pkg.Example', someObject);
6300          *
6301          *     alert(MyCompany.pkg.Example === someObject); // alerts true
6302          *
6303          * @param {String} name
6304          * @param {Object} value
6305          */
6306         setNamespace: function(name, value) {
6307             var root = Ext.global,
6308                 parts = this.parseNamespace(name),
6309                 ln = parts.length - 1,
6310                 leaf = parts[ln],
6311                 i, part;
6312
6313             for (i = 0; i < ln; i++) {
6314                 part = parts[i];
6315
6316                 if (typeof part !== 'string') {
6317                     root = part;
6318                 } else {
6319                     if (!root[part]) {
6320                         root[part] = {};
6321                     }
6322
6323                     root = root[part];
6324                 }
6325             }
6326
6327             root[leaf] = value;
6328
6329             return root[leaf];
6330         },
6331
6332         /**
6333          * The new Ext.ns, supports namespace rewriting
6334          * @private
6335          */
6336         createNamespaces: function() {
6337             var root = Ext.global,
6338                 parts, part, i, j, ln, subLn;
6339
6340             for (i = 0, ln = arguments.length; i < ln; i++) {
6341                 parts = this.parseNamespace(arguments[i]);
6342
6343                 for (j = 0, subLn = parts.length; j < subLn; j++) {
6344                     part = parts[j];
6345
6346                     if (typeof part !== 'string') {
6347                         root = part;
6348                     } else {
6349                         if (!root[part]) {
6350                             root[part] = {};
6351                         }
6352
6353                         root = root[part];
6354                     }
6355                 }
6356             }
6357
6358             return root;
6359         },
6360
6361         /**
6362          * Sets a name reference to a class.
6363          *
6364          * @param {String} name
6365          * @param {Object} value
6366          * @return {Ext.ClassManager} this
6367          */
6368         set: function(name, value) {
6369             var targetName = this.getName(value);
6370
6371             this.classes[name] = this.setNamespace(name, value);
6372
6373             if (targetName && targetName !== name) {
6374                 this.maps.alternateToName[name] = targetName;
6375             }
6376
6377             return this;
6378         },
6379
6380         /**
6381          * Retrieve a class by its name.
6382          *
6383          * @param {String} name
6384          * @return {Ext.Class} class
6385          */
6386         get: function(name) {
6387             if (this.classes.hasOwnProperty(name)) {
6388                 return this.classes[name];
6389             }
6390
6391             var root = Ext.global,
6392                 parts = this.parseNamespace(name),
6393                 part, i, ln;
6394
6395             for (i = 0, ln = parts.length; i < ln; i++) {
6396                 part = parts[i];
6397
6398                 if (typeof part !== 'string') {
6399                     root = part;
6400                 } else {
6401                     if (!root || !root[part]) {
6402                         return null;
6403                     }
6404
6405                     root = root[part];
6406                 }
6407             }
6408
6409             return root;
6410         },
6411
6412         /**
6413          * Register the alias for a class.
6414          *
6415          * @param {Ext.Class/String} cls a reference to a class or a className
6416          * @param {String} alias Alias to use when referring to this class
6417          */
6418         setAlias: function(cls, alias) {
6419             var aliasToNameMap = this.maps.aliasToName,
6420                 nameToAliasesMap = this.maps.nameToAliases,
6421                 className;
6422
6423             if (typeof cls === 'string') {
6424                 className = cls;
6425             } else {
6426                 className = this.getName(cls);
6427             }
6428
6429             if (alias && aliasToNameMap[alias] !== className) {
6430                 if (aliasToNameMap.hasOwnProperty(alias) && Ext.isDefined(Ext.global.console)) {
6431                     Ext.global.console.log("[Ext.ClassManager] Overriding existing alias: '" + alias + "' " +
6432                         "of: '" + aliasToNameMap[alias] + "' with: '" + className + "'. Be sure it's intentional.");
6433                 }
6434
6435                 aliasToNameMap[alias] = className;
6436             }
6437
6438             if (!nameToAliasesMap[className]) {
6439                 nameToAliasesMap[className] = [];
6440             }
6441
6442             if (alias) {
6443                 Ext.Array.include(nameToAliasesMap[className], alias);
6444             }
6445
6446             return this;
6447         },
6448
6449         /**
6450          * Get a reference to the class by its alias.
6451          *
6452          * @param {String} alias
6453          * @return {Ext.Class} class
6454          */
6455         getByAlias: function(alias) {
6456             return this.get(this.getNameByAlias(alias));
6457         },
6458
6459         /**
6460          * Get the name of a class by its alias.
6461          *
6462          * @param {String} alias
6463          * @return {String} className
6464          */
6465         getNameByAlias: function(alias) {
6466             return this.maps.aliasToName[alias] || '';
6467         },
6468
6469         /**
6470          * Get the name of a class by its alternate name.
6471          *
6472          * @param {String} alternate
6473          * @return {String} className
6474          */
6475         getNameByAlternate: function(alternate) {
6476             return this.maps.alternateToName[alternate] || '';
6477         },
6478
6479         /**
6480          * Get the aliases of a class by the class name
6481          *
6482          * @param {String} name
6483          * @return {String[]} aliases
6484          */
6485         getAliasesByName: function(name) {
6486             return this.maps.nameToAliases[name] || [];
6487         },
6488
6489         /**
6490          * Get the name of the class by its reference or its instance.
6491          *
6492          *     Ext.ClassManager.getName(Ext.Action); // returns "Ext.Action"
6493          *
6494          * {@link Ext#getClassName Ext.getClassName} is alias for {@link Ext.ClassManager#getName Ext.ClassManager.getName}.
6495          *
6496          * @param {Ext.Class/Object} object
6497          * @return {String} className
6498          */
6499         getName: function(object) {
6500             return object && object.$className || '';
6501         },
6502
6503         /**
6504          * Get the class of the provided object; returns null if it's not an instance
6505          * of any class created with Ext.define.
6506          *
6507          *     var component = new Ext.Component();
6508          *
6509          *     Ext.ClassManager.getClass(component); // returns Ext.Component
6510          *
6511          * {@link Ext#getClass Ext.getClass} is alias for {@link Ext.ClassManager#getClass Ext.ClassManager.getClass}.
6512          *
6513          * @param {Object} object
6514          * @return {Ext.Class} class
6515          */
6516         getClass: function(object) {
6517             return object && object.self || null;
6518         },
6519
6520         /**
6521          * Defines a class.
6522          *
6523          * {@link Ext#define Ext.define} and {@link Ext.ClassManager#create Ext.ClassManager.create} are almost aliases
6524          * of each other, with the only exception that Ext.define allows definition of {@link Ext.Class#override overrides}.
6525          * To avoid trouble, always use Ext.define.
6526          *
6527          *     Ext.define('My.awesome.Class', {
6528          *         someProperty: 'something',
6529          *         someMethod: function() { ... }
6530          *         ...
6531          *
6532          *     }, function() {
6533          *         alert('Created!');
6534          *         alert(this === My.awesome.Class); // alerts true
6535          *
6536          *         var myInstance = new this();
6537          *     });
6538          *
6539          * @param {String} className The class name to create in string dot-namespaced format, for example:
6540          * `My.very.awesome.Class`, `FeedViewer.plugin.CoolPager`. It is highly recommended to follow this simple convention:
6541          *
6542          * - The root and the class name are 'CamelCased'
6543          * - Everything else is lower-cased
6544          *
6545          * @param {Object} data The key-value pairs of properties to apply to this class. Property names can be of any valid
6546          * strings, except those in the reserved list below:
6547          *
6548          * - {@link Ext.Base#self self}
6549          * - {@link Ext.Class#alias alias}
6550          * - {@link Ext.Class#alternateClassName alternateClassName}
6551          * - {@link Ext.Class#config config}
6552          * - {@link Ext.Class#extend extend}
6553          * - {@link Ext.Class#inheritableStatics inheritableStatics}
6554          * - {@link Ext.Class#mixins mixins}
6555          * - {@link Ext.Class#override override} (only when using {@link Ext#define Ext.define})
6556          * - {@link Ext.Class#requires requires}
6557          * - {@link Ext.Class#singleton singleton}
6558          * - {@link Ext.Class#statics statics}
6559          * - {@link Ext.Class#uses uses}
6560          *
6561          * @param {Function} [createdFn] callback to execute after the class is created, the execution scope of which
6562          * (`this`) will be the newly created class itself.
6563          *
6564          * @return {Ext.Base}
6565          */
6566         create: function(className, data, createdFn) {
6567             var manager = this;
6568
6569             if (typeof className !== 'string') {
6570                 Ext.Error.raise({
6571                     sourceClass: "Ext",
6572                     sourceMethod: "define",
6573                     msg: "Invalid class name '" + className + "' specified, must be a non-empty string"
6574                 });
6575             }
6576
6577             data.$className = className;
6578
6579             return new Class(data, function() {
6580                 var postprocessorStack = data.postprocessors || manager.defaultPostprocessors,
6581                     registeredPostprocessors = manager.postprocessors,
6582                     index = 0,
6583                     postprocessors = [],
6584                     postprocessor, process, i, ln;
6585
6586                 delete data.postprocessors;
6587
6588                 for (i = 0, ln = postprocessorStack.length; i < ln; i++) {
6589                     postprocessor = postprocessorStack[i];
6590
6591                     if (typeof postprocessor === 'string') {
6592                         postprocessor = registeredPostprocessors[postprocessor];
6593
6594                         if (!postprocessor.always) {
6595                             if (data[postprocessor.name] !== undefined) {
6596                                 postprocessors.push(postprocessor.fn);
6597                             }
6598                         }
6599                         else {
6600                             postprocessors.push(postprocessor.fn);
6601                         }
6602                     }
6603                     else {
6604                         postprocessors.push(postprocessor);
6605                     }
6606                 }
6607
6608                 process = function(clsName, cls, clsData) {
6609                     postprocessor = postprocessors[index++];
6610
6611                     if (!postprocessor) {
6612                         manager.set(className, cls);
6613
6614                         Ext.Loader.historyPush(className);
6615
6616                         if (createdFn) {
6617                             createdFn.call(cls, cls);
6618                         }
6619
6620                         return;
6621                     }
6622
6623                     if (postprocessor.call(this, clsName, cls, clsData, process) !== false) {
6624                         process.apply(this, arguments);
6625                     }
6626                 };
6627
6628                 process.call(manager, className, this, data);
6629             });
6630         },
6631
6632         /**
6633          * Instantiate a class by its alias.
6634          *
6635          * If {@link Ext.Loader} is {@link Ext.Loader#setConfig enabled} and the class has not been defined yet, it will
6636          * attempt to load the class via synchronous loading.
6637          *
6638          *     var window = Ext.ClassManager.instantiateByAlias('widget.window', { width: 600, height: 800, ... });
6639          *
6640          * {@link Ext#createByAlias Ext.createByAlias} is alias for {@link Ext.ClassManager#instantiateByAlias Ext.ClassManager.instantiateByAlias}.
6641          *
6642          * @param {String} alias
6643          * @param {Object...} args Additional arguments after the alias will be passed to the
6644          * class constructor.
6645          * @return {Object} instance
6646          */
6647         instantiateByAlias: function() {
6648             var alias = arguments[0],
6649                 args = slice.call(arguments),
6650                 className = this.getNameByAlias(alias);
6651
6652             if (!className) {
6653                 className = this.maps.aliasToName[alias];
6654
6655                 if (!className) {
6656                     Ext.Error.raise({
6657                         sourceClass: "Ext",
6658                         sourceMethod: "createByAlias",
6659                         msg: "Cannot create an instance of unrecognized alias: " + alias
6660                     });
6661                 }
6662
6663                 if (Ext.global.console) {
6664                     Ext.global.console.warn("[Ext.Loader] Synchronously loading '" + className + "'; consider adding " +
6665                          "Ext.require('" + alias + "') above Ext.onReady");
6666                 }
6667
6668                 Ext.syncRequire(className);
6669             }
6670
6671             args[0] = className;
6672
6673             return this.instantiate.apply(this, args);
6674         },
6675
6676         /**
6677          * Instantiate a class by either full name, alias or alternate name.
6678          *
6679          * If {@link Ext.Loader} is {@link Ext.Loader#setConfig enabled} and the class has not been defined yet, it will
6680          * attempt to load the class via synchronous loading.
6681          *
6682          * For example, all these three lines return the same result:
6683          *
6684          *     // alias
6685          *     var window = Ext.ClassManager.instantiate('widget.window', { width: 600, height: 800, ... });
6686          *
6687          *     // alternate name
6688          *     var window = Ext.ClassManager.instantiate('Ext.Window', { width: 600, height: 800, ... });
6689          *
6690          *     // full class name
6691          *     var window = Ext.ClassManager.instantiate('Ext.window.Window', { width: 600, height: 800, ... });
6692          *
6693          * {@link Ext#create Ext.create} is alias for {@link Ext.ClassManager#instantiate Ext.ClassManager.instantiate}.
6694          *
6695          * @param {String} name
6696          * @param {Object...} args Additional arguments after the name will be passed to the class' constructor.
6697          * @return {Object} instance
6698          */
6699         instantiate: function() {
6700             var name = arguments[0],
6701                 args = slice.call(arguments, 1),
6702                 alias = name,
6703                 possibleName, cls;
6704
6705             if (typeof name !== 'function') {
6706                 if ((typeof name !== 'string' || name.length < 1)) {
6707                     Ext.Error.raise({
6708                         sourceClass: "Ext",
6709                         sourceMethod: "create",
6710                         msg: "Invalid class name or alias '" + name + "' specified, must be a non-empty string"
6711                     });
6712                 }
6713
6714                 cls = this.get(name);
6715             }
6716             else {
6717                 cls = name;
6718             }
6719
6720             // No record of this class name, it's possibly an alias, so look it up
6721             if (!cls) {
6722                 possibleName = this.getNameByAlias(name);
6723
6724                 if (possibleName) {
6725                     name = possibleName;
6726
6727                     cls = this.get(name);
6728                 }
6729             }
6730
6731             // Still no record of this class name, it's possibly an alternate name, so look it up
6732             if (!cls) {
6733                 possibleName = this.getNameByAlternate(name);
6734
6735                 if (possibleName) {
6736                     name = possibleName;
6737
6738                     cls = this.get(name);
6739                 }
6740             }
6741
6742             // Still not existing at this point, try to load it via synchronous mode as the last resort
6743             if (!cls) {
6744                 if (Ext.global.console) {
6745                     Ext.global.console.warn("[Ext.Loader] Synchronously loading '" + name + "'; consider adding " +
6746                          "Ext.require('" + ((possibleName) ? alias : name) + "') above Ext.onReady");
6747                 }
6748
6749                 Ext.syncRequire(name);
6750
6751                 cls = this.get(name);
6752             }
6753
6754             if (!cls) {
6755                 Ext.Error.raise({
6756                     sourceClass: "Ext",
6757                     sourceMethod: "create",
6758                     msg: "Cannot create an instance of unrecognized class name / alias: " + alias
6759                 });
6760             }
6761
6762             if (typeof cls !== 'function') {
6763                 Ext.Error.raise({
6764                     sourceClass: "Ext",
6765                     sourceMethod: "create",
6766                     msg: "'" + name + "' is a singleton and cannot be instantiated"
6767                 });
6768             }
6769
6770             if (!this.instantiationCounts[name]) {
6771                 this.instantiationCounts[name] = 0;
6772             }
6773
6774             this.instantiationCounts[name]++;
6775
6776             return this.getInstantiator(args.length)(cls, args);
6777         },
6778
6779         /**
6780          * @private
6781          * @param name
6782          * @param args
6783          */
6784         dynInstantiate: function(name, args) {
6785             args = Ext.Array.from(args, true);
6786             args.unshift(name);
6787
6788             return this.instantiate.apply(this, args);
6789         },
6790
6791         /**
6792          * @private
6793          * @param length
6794          */
6795         getInstantiator: function(length) {
6796             if (!this.instantiators[length]) {
6797                 var i = length,
6798                     args = [];
6799
6800                 for (i = 0; i < length; i++) {
6801                     args.push('a['+i+']');
6802                 }
6803
6804                 this.instantiators[length] = new Function('c', 'a', 'return new c('+args.join(',')+')');
6805             }
6806
6807             return this.instantiators[length];
6808         },
6809
6810         /**
6811          * @private
6812          */
6813         postprocessors: {},
6814
6815         /**
6816          * @private
6817          */
6818         defaultPostprocessors: [],
6819
6820         /**
6821          * Register a post-processor function.
6822          *
6823          * @param {String} name
6824          * @param {Function} postprocessor
6825          */
6826         registerPostprocessor: function(name, fn, always) {
6827             this.postprocessors[name] = {
6828                 name: name,
6829                 always: always ||  false,
6830                 fn: fn
6831             };
6832
6833             return this;
6834         },
6835
6836         /**
6837          * Set the default post processors array stack which are applied to every class.
6838          *
6839          * @param {String/String[]} The name of a registered post processor or an array of registered names.
6840          * @return {Ext.ClassManager} this
6841          */
6842         setDefaultPostprocessors: function(postprocessors) {
6843             this.defaultPostprocessors = Ext.Array.from(postprocessors);
6844
6845             return this;
6846         },
6847
6848         /**
6849          * Insert this post-processor at a specific position in the stack, optionally relative to
6850          * any existing post-processor
6851          *
6852          * @param {String} name The post-processor name. Note that it needs to be registered with
6853          * {@link Ext.ClassManager#registerPostprocessor} before this
6854          * @param {String} offset The insertion position. Four possible values are:
6855          * 'first', 'last', or: 'before', 'after' (relative to the name provided in the third argument)
6856          * @param {String} relativeName
6857          * @return {Ext.ClassManager} this
6858          */
6859         setDefaultPostprocessorPosition: function(name, offset, relativeName) {
6860             var defaultPostprocessors = this.defaultPostprocessors,
6861                 index;
6862
6863             if (typeof offset === 'string') {
6864                 if (offset === 'first') {
6865                     defaultPostprocessors.unshift(name);
6866
6867                     return this;
6868                 }
6869                 else if (offset === 'last') {
6870                     defaultPostprocessors.push(name);
6871
6872                     return this;
6873                 }
6874
6875                 offset = (offset === 'after') ? 1 : -1;
6876             }
6877
6878             index = Ext.Array.indexOf(defaultPostprocessors, relativeName);
6879
6880             if (index !== -1) {
6881                 Ext.Array.splice(defaultPostprocessors, Math.max(0, index + offset), 0, name);
6882             }
6883
6884             return this;
6885         },
6886
6887         /**
6888          * Converts a string expression to an array of matching class names. An expression can either refers to class aliases
6889          * or class names. Expressions support wildcards:
6890          *
6891          *     // returns ['Ext.window.Window']
6892          *     var window = Ext.ClassManager.getNamesByExpression('widget.window');
6893          *
6894          *     // returns ['widget.panel', 'widget.window', ...]
6895          *     var allWidgets = Ext.ClassManager.getNamesByExpression('widget.*');
6896          *
6897          *     // returns ['Ext.data.Store', 'Ext.data.ArrayProxy', ...]
6898          *     var allData = Ext.ClassManager.getNamesByExpression('Ext.data.*');
6899          *
6900          * @param {String} expression
6901          * @return {String[]} classNames
6902          */
6903         getNamesByExpression: function(expression) {
6904             var nameToAliasesMap = this.maps.nameToAliases,
6905                 names = [],
6906                 name, alias, aliases, possibleName, regex, i, ln;
6907
6908             if (typeof expression !== 'string' || expression.length < 1) {
6909                 Ext.Error.raise({
6910                     sourceClass: "Ext.ClassManager",
6911                     sourceMethod: "getNamesByExpression",
6912                     msg: "Expression " + expression + " is invalid, must be a non-empty string"
6913                 });
6914             }
6915
6916             if (expression.indexOf('*') !== -1) {
6917                 expression = expression.replace(/\*/g, '(.*?)');
6918                 regex = new RegExp('^' + expression + '$');
6919
6920                 for (name in nameToAliasesMap) {
6921                     if (nameToAliasesMap.hasOwnProperty(name)) {
6922                         aliases = nameToAliasesMap[name];
6923
6924                         if (name.search(regex) !== -1) {
6925                             names.push(name);
6926                         }
6927                         else {
6928                             for (i = 0, ln = aliases.length; i < ln; i++) {
6929                                 alias = aliases[i];
6930
6931                                 if (alias.search(regex) !== -1) {
6932                                     names.push(name);
6933                                     break;
6934                                 }
6935                             }
6936                         }
6937                     }
6938                 }
6939
6940             } else {
6941                 possibleName = this.getNameByAlias(expression);
6942
6943                 if (possibleName) {
6944                     names.push(possibleName);
6945                 } else {
6946                     possibleName = this.getNameByAlternate(expression);
6947
6948                     if (possibleName) {
6949                         names.push(possibleName);
6950                     } else {
6951                         names.push(expression);
6952                     }
6953                 }
6954             }
6955
6956             return names;
6957         }
6958     };
6959
6960     var defaultPostprocessors = Manager.defaultPostprocessors;
6961     //<feature classSystem.alias>
6962
6963     /**
6964      * @cfg {String[]} alias
6965      * @member Ext.Class
6966      * List of short aliases for class names.  Most useful for defining xtypes for widgets:
6967      *
6968      *     Ext.define('MyApp.CoolPanel', {
6969      *         extend: 'Ext.panel.Panel',
6970      *         alias: ['widget.coolpanel'],
6971      *         title: 'Yeah!'
6972      *     });
6973      *
6974      *     // Using Ext.create
6975      *     Ext.widget('widget.coolpanel');
6976      *     // Using the shorthand for widgets and in xtypes
6977      *     Ext.widget('panel', {
6978      *         items: [
6979      *             {xtype: 'coolpanel', html: 'Foo'},
6980      *             {xtype: 'coolpanel', html: 'Bar'}
6981      *         ]
6982      *     });
6983      */
6984     Manager.registerPostprocessor('alias', function(name, cls, data) {
6985         var aliases = data.alias,
6986             i, ln;
6987
6988         delete data.alias;
6989
6990         for (i = 0, ln = aliases.length; i < ln; i++) {
6991             alias = aliases[i];
6992
6993             this.setAlias(cls, alias);
6994         }
6995     });
6996
6997     /**
6998      * @cfg {Boolean} singleton
6999      * @member Ext.Class
7000      * When set to true, the class will be instantiated as singleton.  For example:
7001      *
7002      *     Ext.define('Logger', {
7003      *         singleton: true,
7004      *         log: function(msg) {
7005      *             console.log(msg);
7006      *         }
7007      *     });
7008      *
7009      *     Logger.log('Hello');
7010      */
7011     Manager.registerPostprocessor('singleton', function(name, cls, data, fn) {
7012         fn.call(this, name, new cls(), data);
7013         return false;
7014     });
7015
7016     /**
7017      * @cfg {String/String[]} alternateClassName
7018      * @member Ext.Class
7019      * Defines alternate names for this class.  For example:
7020      *
7021      *     Ext.define('Developer', {
7022      *         alternateClassName: ['Coder', 'Hacker'],
7023      *         code: function(msg) {
7024      *             alert('Typing... ' + msg);
7025      *         }
7026      *     });
7027      *
7028      *     var joe = Ext.create('Developer');
7029      *     joe.code('stackoverflow');
7030      *
7031      *     var rms = Ext.create('Hacker');
7032      *     rms.code('hack hack');
7033      */
7034     Manager.registerPostprocessor('alternateClassName', function(name, cls, data) {
7035         var alternates = data.alternateClassName,
7036             i, ln, alternate;
7037
7038         if (!(alternates instanceof Array)) {
7039             alternates = [alternates];
7040         }
7041
7042         for (i = 0, ln = alternates.length; i < ln; i++) {
7043             alternate = alternates[i];
7044
7045             if (typeof alternate !== 'string') {
7046                 Ext.Error.raise({
7047                     sourceClass: "Ext",
7048                     sourceMethod: "define",
7049                     msg: "Invalid alternate of: '" + alternate + "' for class: '" + name + "'; must be a valid string"
7050                 });
7051             }
7052
7053             this.set(alternate, cls);
7054         }
7055     });
7056
7057     Manager.setDefaultPostprocessors(['alias', 'singleton', 'alternateClassName']);
7058
7059     Ext.apply(Ext, {
7060         /**
7061          * @method
7062          * @member Ext
7063          * @alias Ext.ClassManager#instantiate
7064          */
7065         create: alias(Manager, 'instantiate'),
7066
7067         /**
7068          * @private
7069          * API to be stablized
7070          *
7071          * @param {Object} item
7072          * @param {String} namespace
7073          */
7074         factory: function(item, namespace) {
7075             if (item instanceof Array) {
7076                 var i, ln;
7077
7078                 for (i = 0, ln = item.length; i < ln; i++) {
7079                     item[i] = Ext.factory(item[i], namespace);
7080                 }
7081
7082                 return item;
7083             }
7084
7085             var isString = (typeof item === 'string');
7086
7087             if (isString || (item instanceof Object && item.constructor === Object)) {
7088                 var name, config = {};
7089
7090                 if (isString) {
7091                     name = item;
7092                 }
7093                 else {
7094                     name = item.className;
7095                     config = item;
7096                     delete config.className;
7097                 }
7098
7099                 if (namespace !== undefined && name.indexOf(namespace) === -1) {
7100                     name = namespace + '.' + Ext.String.capitalize(name);
7101                 }
7102
7103                 return Ext.create(name, config);
7104             }
7105
7106             if (typeof item === 'function') {
7107                 return Ext.create(item);
7108             }
7109
7110             return item;
7111         },
7112
7113         /**
7114          * Convenient shorthand to create a widget by its xtype, also see {@link Ext.ClassManager#instantiateByAlias}
7115          *
7116          *     var button = Ext.widget('button'); // Equivalent to Ext.create('widget.button')
7117          *     var panel = Ext.widget('panel'); // Equivalent to Ext.create('widget.panel')
7118          *
7119          * @method
7120          * @member Ext
7121          * @param {String} name  xtype of the widget to create.
7122          * @param {Object...} args  arguments for the widget constructor.
7123          * @return {Object} widget instance
7124          */
7125         widget: function(name) {
7126             var args = slice.call(arguments);
7127             args[0] = 'widget.' + name;
7128
7129             return Manager.instantiateByAlias.apply(Manager, args);
7130         },
7131
7132         /**
7133          * @method
7134          * @member Ext
7135          * @alias Ext.ClassManager#instantiateByAlias
7136          */
7137         createByAlias: alias(Manager, 'instantiateByAlias'),
7138
7139         /**
7140          * @cfg {String} override
7141          * @member Ext.Class
7142          * 
7143          * Defines an override applied to a class. Note that **overrides can only be created using
7144          * {@link Ext#define}.** {@link Ext.ClassManager#create} only creates classes.
7145          * 
7146          * To define an override, include the override property. The content of an override is
7147          * aggregated with the specified class in order to extend or modify that class. This can be
7148          * as simple as setting default property values or it can extend and/or replace methods.
7149          * This can also extend the statics of the class.
7150          *
7151          * One use for an override is to break a large class into manageable pieces.
7152          *
7153          *      // File: /src/app/Panel.js
7154          *
7155          *      Ext.define('My.app.Panel', {
7156          *          extend: 'Ext.panel.Panel',
7157          *          requires: [
7158          *              'My.app.PanelPart2',
7159          *              'My.app.PanelPart3'
7160          *          ]
7161          *
7162          *          constructor: function (config) {
7163          *              this.callSuper(arguments); // calls Ext.panel.Panel's constructor
7164          *              //...
7165          *          },
7166          *
7167          *          statics: {
7168          *              method: function () {
7169          *                  return 'abc';
7170          *              }
7171          *          }
7172          *      });
7173          *
7174          *      // File: /src/app/PanelPart2.js
7175          *      Ext.define('My.app.PanelPart2', {
7176          *          override: 'My.app.Panel',
7177          *
7178          *          constructor: function (config) {
7179          *              this.callSuper(arguments); // calls My.app.Panel's constructor
7180          *              //...
7181          *          }
7182          *      });
7183          *
7184          * Another use of overrides is to provide optional parts of classes that can be
7185          * independently required. In this case, the class may even be unaware of the
7186          * override altogether.
7187          *
7188          *      Ext.define('My.ux.CoolTip', {
7189          *          override: 'Ext.tip.ToolTip',
7190          *
7191          *          constructor: function (config) {
7192          *              this.callSuper(arguments); // calls Ext.tip.ToolTip's constructor
7193          *              //...
7194          *          }
7195          *      });
7196          *
7197          * The above override can now be required as normal.
7198          *
7199          *      Ext.define('My.app.App', {
7200          *          requires: [
7201          *              'My.ux.CoolTip'
7202          *          ]
7203          *      });
7204          *
7205          * Overrides can also contain statics:
7206          *
7207          *      Ext.define('My.app.BarMod', {
7208          *          override: 'Ext.foo.Bar',
7209          *
7210          *          statics: {
7211          *              method: function (x) {
7212          *                  return this.callSuper([x * 2]); // call Ext.foo.Bar.method
7213          *              }
7214          *          }
7215          *      });
7216          *
7217          * IMPORTANT: An override is only included in a build if the class it overrides is
7218          * required. Otherwise, the override, like the target class, is not included.
7219          */
7220         
7221         /**
7222          * @method
7223          *
7224          * @member Ext
7225          * @alias Ext.ClassManager#create
7226          */
7227         define: function (className, data, createdFn) {
7228             if (!data.override) {
7229                 return Manager.create.apply(Manager, arguments);
7230             }
7231
7232             var requires = data.requires,
7233                 uses = data.uses,
7234                 overrideName = className;
7235
7236             className = data.override;
7237
7238             // hoist any 'requires' or 'uses' from the body onto the faux class:
7239             data = Ext.apply({}, data);
7240             delete data.requires;
7241             delete data.uses;
7242             delete data.override;
7243
7244             // make sure className is in the requires list:
7245             if (typeof requires == 'string') {
7246                 requires = [ className, requires ];
7247             } else if (requires) {
7248                 requires = requires.slice(0);
7249                 requires.unshift(className);
7250             } else {
7251                 requires = [ className ];
7252             }
7253
7254 // TODO - we need to rework this to allow the override to not require the target class
7255 //  and rather 'wait' for it in such a way that if the target class is not in the build,
7256 //  neither are any of its overrides.
7257 //
7258 //  Also, this should process the overrides for a class ASAP (ideally before any derived
7259 //  classes) if the target class 'requires' the overrides. Without some special handling, the
7260 //  overrides so required will be processed before the class and have to be bufferred even
7261 //  in a build.
7262 //
7263 // TODO - we should probably support the "config" processor on an override (to config new
7264 //  functionaliy like Aria) and maybe inheritableStatics (although static is now supported
7265 //  by callSuper). If inheritableStatics causes those statics to be included on derived class
7266 //  constructors, that probably means "no" to this since an override can come after other
7267 //  classes extend the target.
7268             return Manager.create(overrideName, {
7269                     requires: requires,
7270                     uses: uses,
7271                     isPartial: true,
7272                     constructor: function () {
7273                         throw new Error("Cannot create override '" + overrideName + "'");
7274                     }
7275                 }, function () {
7276                     var cls = Manager.get(className);
7277                     if (cls.override) { // if (normal class)
7278                         cls.override(data);
7279                     } else { // else (singleton)
7280                         cls.self.override(data);
7281                     }
7282
7283                     if (createdFn) {
7284                         // called once the override is applied and with the context of the
7285                         // overridden class (the override itself is a meaningless, name-only
7286                         // thing).
7287                         createdFn.call(cls);
7288                     }
7289                 });
7290         },
7291
7292         /**
7293          * @method
7294          * @member Ext
7295          * @alias Ext.ClassManager#getName
7296          */
7297         getClassName: alias(Manager, 'getName'),
7298
7299         /**
7300          * Returns the displayName property or className or object.
7301          * When all else fails, returns "Anonymous".
7302          * @param {Object} object
7303          * @return {String}
7304          */
7305         getDisplayName: function(object) {
7306             if (object.displayName) {
7307                 return object.displayName;
7308             }
7309
7310             if (object.$name && object.$class) {
7311                 return Ext.getClassName(object.$class) + '#' + object.$name;
7312             }
7313
7314             if (object.$className) {
7315                 return object.$className;
7316             }
7317
7318             return 'Anonymous';
7319         },
7320
7321         /**
7322          * @method
7323          * @member Ext
7324          * @alias Ext.ClassManager#getClass
7325          */
7326         getClass: alias(Manager, 'getClass'),
7327
7328         /**
7329          * Creates namespaces to be used for scoping variables and classes so that they are not global.
7330          * Specifying the last node of a namespace implicitly creates all other nodes. Usage:
7331          *
7332          *     Ext.namespace('Company', 'Company.data');
7333          *
7334          *     // equivalent and preferable to the above syntax
7335          *     Ext.namespace('Company.data');
7336          *
7337          *     Company.Widget = function() { ... };
7338          *
7339          *     Company.data.CustomStore = function(config) { ... };
7340          *
7341          * @method
7342          * @member Ext
7343          * @param {String} namespace1
7344          * @param {String} namespace2
7345          * @param {String} etc
7346          * @return {Object} The namespace object. (If multiple arguments are passed, this will be the last namespace created)
7347          */
7348         namespace: alias(Manager, 'createNamespaces')
7349     });
7350
7351     /**
7352      * Old name for {@link Ext#widget}.
7353      * @deprecated 4.0.0 Use {@link Ext#widget} instead.
7354      * @method
7355      * @member Ext
7356      * @alias Ext#widget
7357      */
7358     Ext.createWidget = Ext.widget;
7359
7360     /**
7361      * Convenient alias for {@link Ext#namespace Ext.namespace}
7362      * @method
7363      * @member Ext
7364      * @alias Ext#namespace
7365      */
7366     Ext.ns = Ext.namespace;
7367
7368     Class.registerPreprocessor('className', function(cls, data) {
7369         if (data.$className) {
7370             cls.$className = data.$className;
7371             cls.displayName = cls.$className;
7372         }
7373     }, true);
7374
7375     Class.setDefaultPreprocessorPosition('className', 'first');
7376
7377     Class.registerPreprocessor('xtype', function(cls, data) {
7378         var xtypes = Ext.Array.from(data.xtype),
7379             widgetPrefix = 'widget.',
7380             aliases = Ext.Array.from(data.alias),
7381             i, ln, xtype;
7382
7383         data.xtype = xtypes[0];
7384         data.xtypes = xtypes;
7385
7386         aliases = data.alias = Ext.Array.from(data.alias);
7387
7388         for (i = 0,ln = xtypes.length; i < ln; i++) {
7389             xtype = xtypes[i];
7390
7391             if (typeof xtype != 'string' || xtype.length < 1) {
7392                 throw new Error("[Ext.define] Invalid xtype of: '" + xtype + "' for class: '" + name + "'; must be a valid non-empty string");
7393             }
7394
7395             aliases.push(widgetPrefix + xtype);
7396         }
7397
7398         data.alias = aliases;
7399     });
7400
7401     Class.setDefaultPreprocessorPosition('xtype', 'last');
7402
7403     Class.registerPreprocessor('alias', function(cls, data) {
7404         var aliases = Ext.Array.from(data.alias),
7405             xtypes = Ext.Array.from(data.xtypes),
7406             widgetPrefix = 'widget.',
7407             widgetPrefixLength = widgetPrefix.length,
7408             i, ln, alias, xtype;
7409
7410         for (i = 0, ln = aliases.length; i < ln; i++) {
7411             alias = aliases[i];
7412
7413             if (typeof alias != 'string') {
7414                 throw new Error("[Ext.define] Invalid alias of: '" + alias + "' for class: '" + name + "'; must be a valid string");
7415             }
7416
7417             if (alias.substring(0, widgetPrefixLength) === widgetPrefix) {
7418                 xtype = alias.substring(widgetPrefixLength);
7419                 Ext.Array.include(xtypes, xtype);
7420
7421                 if (!cls.xtype) {
7422                     cls.xtype = data.xtype = xtype;
7423                 }
7424             }
7425         }
7426
7427         data.alias = aliases;
7428         data.xtypes = xtypes;
7429     });
7430
7431     Class.setDefaultPreprocessorPosition('alias', 'last');
7432
7433 })(Ext.Class, Ext.Function.alias);
7434
7435 /**
7436  * @class Ext.Loader
7437  * @singleton
7438  * @author Jacky Nguyen <jacky@sencha.com>
7439  * @docauthor Jacky Nguyen <jacky@sencha.com>
7440  *
7441  * Ext.Loader is the heart of the new dynamic dependency loading capability in Ext JS 4+. It is most commonly used
7442  * via the {@link Ext#require} shorthand. Ext.Loader supports both asynchronous and synchronous loading
7443  * approaches, and leverage their advantages for the best development flow. We'll discuss about the pros and cons
7444  * of each approach:
7445  *
7446  * # Asynchronous Loading
7447  *
7448  * - Advantages:
7449  *       + Cross-domain
7450  *       + No web server needed: you can run the application via the file system protocol
7451  *     (i.e: `file://path/to/your/index.html`)
7452  *       + Best possible debugging experience: error messages come with the exact file name and line number
7453  *
7454  * - Disadvantages:
7455  *       + Dependencies need to be specified before-hand
7456  *
7457  * ### Method 1: Explicitly include what you need:
7458  *
7459  *     // Syntax
7460  *     Ext.require({String/Array} expressions);
7461  *
7462  *     // Example: Single alias
7463  *     Ext.require('widget.window');
7464  *
7465  *     // Example: Single class name
7466  *     Ext.require('Ext.window.Window');
7467  *
7468  *     // Example: Multiple aliases / class names mix
7469  *     Ext.require(['widget.window', 'layout.border', 'Ext.data.Connection']);
7470  *
7471  *     // Wildcards
7472  *     Ext.require(['widget.*', 'layout.*', 'Ext.data.*']);
7473  *
7474  * ### Method 2: Explicitly exclude what you don't need:
7475  *
7476  *     // Syntax: Note that it must be in this chaining format.
7477  *     Ext.exclude({String/Array} expressions)
7478  *        .require({String/Array} expressions);
7479  *
7480  *     // Include everything except Ext.data.*
7481  *     Ext.exclude('Ext.data.*').require('*'); 
7482  *
7483  *     // Include all widgets except widget.checkbox*,
7484  *     // which will match widget.checkbox, widget.checkboxfield, widget.checkboxgroup, etc.
7485  *     Ext.exclude('widget.checkbox*').require('widget.*');
7486  *
7487  * # Synchronous Loading on Demand
7488  *
7489  * - Advantages:
7490  *       + There's no need to specify dependencies before-hand, which is always the convenience of including
7491  *     ext-all.js before
7492  *
7493  * - Disadvantages:
7494  *       + Not as good debugging experience since file name won't be shown (except in Firebug at the moment)
7495  *       + Must be from the same domain due to XHR restriction
7496  *       + Need a web server, same reason as above
7497  *
7498  * There's one simple rule to follow: Instantiate everything with Ext.create instead of the `new` keyword
7499  *
7500  *     Ext.create('widget.window', { ... }); // Instead of new Ext.window.Window({...});
7501  *
7502  *     Ext.create('Ext.window.Window', {}); // Same as above, using full class name instead of alias
7503  *
7504  *     Ext.widget('window', {}); // Same as above, all you need is the traditional `xtype`
7505  *
7506  * Behind the scene, {@link Ext.ClassManager} will automatically check whether the given class name / alias has already
7507  * existed on the page. If it's not, Ext.Loader will immediately switch itself to synchronous mode and automatic load
7508  * the given class and all its dependencies.
7509  *
7510  * # Hybrid Loading - The Best of Both Worlds
7511  *
7512  * It has all the advantages combined from asynchronous and synchronous loading. The development flow is simple:
7513  *
7514  * ### Step 1: Start writing your application using synchronous approach.
7515  *
7516  * Ext.Loader will automatically fetch all dependencies on demand as they're needed during run-time. For example:
7517  *
7518  *     Ext.onReady(function(){
7519  *         var window = Ext.createWidget('window', {
7520  *             width: 500,
7521  *             height: 300,
7522  *             layout: {
7523  *                 type: 'border',
7524  *                 padding: 5
7525  *             },
7526  *             title: 'Hello Dialog',
7527  *             items: [{
7528  *                 title: 'Navigation',
7529  *                 collapsible: true,
7530  *                 region: 'west',
7531  *                 width: 200,
7532  *                 html: 'Hello',
7533  *                 split: true
7534  *             }, {
7535  *                 title: 'TabPanel',
7536  *                 region: 'center'
7537  *             }]
7538  *         });
7539  *
7540  *         window.show();
7541  *     })
7542  *
7543  * ### Step 2: Along the way, when you need better debugging ability, watch the console for warnings like these:
7544  *
7545  *     [Ext.Loader] Synchronously loading 'Ext.window.Window'; consider adding Ext.require('Ext.window.Window') before your application's code ClassManager.js:432
7546  *     [Ext.Loader] Synchronously loading 'Ext.layout.container.Border'; consider adding Ext.require('Ext.layout.container.Border') before your application's code
7547  *
7548  * Simply copy and paste the suggested code above `Ext.onReady`, e.g.:
7549  *
7550  *     Ext.require('Ext.window.Window');
7551  *     Ext.require('Ext.layout.container.Border');
7552  *
7553  *     Ext.onReady(...);
7554  *
7555  * Everything should now load via asynchronous mode.
7556  *
7557  * # Deployment
7558  *
7559  * It's important to note that dynamic loading should only be used during development on your local machines.
7560  * During production, all dependencies should be combined into one single JavaScript file. Ext.Loader makes
7561  * the whole process of transitioning from / to between development / maintenance and production as easy as
7562  * possible. Internally {@link Ext.Loader#history Ext.Loader.history} maintains the list of all dependencies
7563  * your application needs in the exact loading sequence. It's as simple as concatenating all files in this
7564  * array into one, then include it on top of your application.
7565  *
7566  * This process will be automated with Sencha Command, to be released and documented towards Ext JS 4 Final.
7567  */
7568 (function(Manager, Class, flexSetter, alias) {
7569
7570     var
7571         dependencyProperties = ['extend', 'mixins', 'requires'],
7572         Loader;
7573
7574     Loader = Ext.Loader = {
7575         /**
7576          * @private
7577          */
7578         documentHead: typeof document !== 'undefined' && (document.head || document.getElementsByTagName('head')[0]),
7579
7580         /**
7581          * Flag indicating whether there are still files being loaded
7582          * @private
7583          */
7584         isLoading: false,
7585
7586         /**
7587          * Maintain the queue for all dependencies. Each item in the array is an object of the format:
7588          * {
7589          *      requires: [...], // The required classes for this queue item
7590          *      callback: function() { ... } // The function to execute when all classes specified in requires exist
7591          * }
7592          * @private
7593          */
7594         queue: [],
7595
7596         /**
7597          * Maintain the list of files that have already been handled so that they never get double-loaded
7598          * @private
7599          */
7600         isFileLoaded: {},
7601
7602         /**
7603          * Maintain the list of listeners to execute when all required scripts are fully loaded
7604          * @private
7605          */
7606         readyListeners: [],
7607
7608         /**
7609          * Contains optional dependencies to be loaded last
7610          * @private
7611          */
7612         optionalRequires: [],
7613
7614         /**
7615          * Map of fully qualified class names to an array of dependent classes.
7616          * @private
7617          */
7618         requiresMap: {},
7619
7620         /**
7621          * @private
7622          */
7623         numPendingFiles: 0,
7624
7625         /**
7626          * @private
7627          */
7628         numLoadedFiles: 0,
7629
7630         /** @private */
7631         hasFileLoadError: false,
7632
7633         /**
7634          * @private
7635          */
7636         classNameToFilePathMap: {},
7637
7638         /**
7639          * @property {String[]} history
7640          * An array of class names to keep track of the dependency loading order.
7641          * This is not guaranteed to be the same everytime due to the asynchronous nature of the Loader.
7642          */
7643         history: [],
7644
7645         /**
7646          * Configuration
7647          * @private
7648          */
7649         config: {
7650             /**
7651              * @cfg {Boolean} enabled
7652              * Whether or not to enable the dynamic dependency loading feature.
7653              */
7654             enabled: false,
7655
7656             /**
7657              * @cfg {Boolean} disableCaching
7658              * Appends current timestamp to script files to prevent caching.
7659              */
7660             disableCaching: true,
7661
7662             /**
7663              * @cfg {String} disableCachingParam
7664              * The get parameter name for the cache buster's timestamp.
7665              */
7666             disableCachingParam: '_dc',
7667
7668             /**
7669              * @cfg {Object} paths
7670              * The mapping from namespaces to file paths
7671              *
7672              *     {
7673              *         'Ext': '.', // This is set by default, Ext.layout.container.Container will be
7674              *                     // loaded from ./layout/Container.js
7675              *
7676              *         'My': './src/my_own_folder' // My.layout.Container will be loaded from
7677              *                                     // ./src/my_own_folder/layout/Container.js
7678              *     }
7679              *
7680              * Note that all relative paths are relative to the current HTML document.
7681              * If not being specified, for example, `Other.awesome.Class`
7682              * will simply be loaded from `./Other/awesome/Class.js`
7683              */
7684             paths: {
7685                 'Ext': '.'
7686             }
7687         },
7688
7689         /**
7690          * Set the configuration for the loader. This should be called right after ext-core.js
7691          * (or ext-core-debug.js) is included in the page, e.g.:
7692          *
7693          *     <script type="text/javascript" src="ext-core-debug.js"></script>
7694          *     <script type="text/javascript">
7695          *       Ext.Loader.setConfig({
7696          *           enabled: true,
7697          *           paths: {
7698          *               'My': 'my_own_path'
7699          *           }
7700          *       });
7701          *     <script>
7702          *     <script type="text/javascript">
7703          *       Ext.require(...);
7704          *
7705          *       Ext.onReady(function() {
7706          *           // application code here
7707          *       });
7708          *     </script>
7709          *
7710          * Refer to config options of {@link Ext.Loader} for the list of possible properties.
7711          *
7712          * @param {String/Object} name  Name of the value to override, or a config object to override multiple values.
7713          * @param {Object} value  (optional) The new value to set, needed if first parameter is String.
7714          * @return {Ext.Loader} this
7715          */
7716         setConfig: function(name, value) {
7717             if (Ext.isObject(name) && arguments.length === 1) {
7718                 Ext.Object.merge(this.config, name);
7719             }
7720             else {
7721                 this.config[name] = (Ext.isObject(value)) ? Ext.Object.merge(this.config[name], value) : value;
7722             }
7723
7724             return this;
7725         },
7726
7727         /**
7728          * Get the config value corresponding to the specified name.
7729          * If no name is given, will return the config object.
7730          * @param {String} name The config property name
7731          * @return {Object}
7732          */
7733         getConfig: function(name) {
7734             if (name) {
7735                 return this.config[name];
7736             }
7737
7738             return this.config;
7739         },
7740
7741         /**
7742          * Sets the path of a namespace. For Example:
7743          *
7744          *     Ext.Loader.setPath('Ext', '.');
7745          *
7746          * @param {String/Object} name See {@link Ext.Function#flexSetter flexSetter}
7747          * @param {String} path See {@link Ext.Function#flexSetter flexSetter}
7748          * @return {Ext.Loader} this
7749          * @method
7750          */
7751         setPath: flexSetter(function(name, path) {
7752             this.config.paths[name] = path;
7753
7754             return this;
7755         }),
7756
7757         /**
7758          * Translates a className to a file path by adding the the proper prefix and converting the .'s to /'s.
7759          * For example:
7760          *
7761          *     Ext.Loader.setPath('My', '/path/to/My');
7762          *
7763          *     alert(Ext.Loader.getPath('My.awesome.Class')); // alerts '/path/to/My/awesome/Class.js'
7764          *
7765          * Note that the deeper namespace levels, if explicitly set, are always resolved first. For example:
7766          *
7767          *     Ext.Loader.setPath({
7768          *         'My': '/path/to/lib',
7769          *         'My.awesome': '/other/path/for/awesome/stuff',
7770          *         'My.awesome.more': '/more/awesome/path'
7771          *     });
7772          *
7773          *     alert(Ext.Loader.getPath('My.awesome.Class')); // alerts '/other/path/for/awesome/stuff/Class.js'
7774          *
7775          *     alert(Ext.Loader.getPath('My.awesome.more.Class')); // alerts '/more/awesome/path/Class.js'
7776          *
7777          *     alert(Ext.Loader.getPath('My.cool.Class')); // alerts '/path/to/lib/cool/Class.js'
7778          *
7779          *     alert(Ext.Loader.getPath('Unknown.strange.Stuff')); // alerts 'Unknown/strange/Stuff.js'
7780          *
7781          * @param {String} className
7782          * @return {String} path
7783          */
7784         getPath: function(className) {
7785             var path = '',
7786                 paths = this.config.paths,
7787                 prefix = this.getPrefix(className);
7788
7789             if (prefix.length > 0) {
7790                 if (prefix === className) {
7791                     return paths[prefix];
7792                 }
7793
7794                 path = paths[prefix];
7795                 className = className.substring(prefix.length + 1);
7796             }
7797
7798             if (path.length > 0) {
7799                 path += '/';
7800             }
7801
7802             return path.replace(/\/\.\//g, '/') + className.replace(/\./g, "/") + '.js';
7803         },
7804
7805         /**
7806          * @private
7807          * @param {String} className
7808          */
7809         getPrefix: function(className) {
7810             var paths = this.config.paths,
7811                 prefix, deepestPrefix = '';
7812
7813             if (paths.hasOwnProperty(className)) {
7814                 return className;
7815             }
7816
7817             for (prefix in paths) {
7818                 if (paths.hasOwnProperty(prefix) && prefix + '.' === className.substring(0, prefix.length + 1)) {
7819                     if (prefix.length > deepestPrefix.length) {
7820                         deepestPrefix = prefix;
7821                     }
7822                 }
7823             }
7824
7825             return deepestPrefix;
7826         },
7827
7828         /**
7829          * Refresh all items in the queue. If all dependencies for an item exist during looping,
7830          * it will execute the callback and call refreshQueue again. Triggers onReady when the queue is
7831          * empty
7832          * @private
7833          */
7834         refreshQueue: function() {
7835             var ln = this.queue.length,
7836                 i, item, j, requires;
7837
7838             if (ln === 0) {
7839                 this.triggerReady();
7840                 return;
7841             }
7842
7843             for (i = 0; i < ln; i++) {
7844                 item = this.queue[i];
7845
7846                 if (item) {
7847                     requires = item.requires;
7848
7849                     // Don't bother checking when the number of files loaded
7850                     // is still less than the array length
7851                     if (requires.length > this.numLoadedFiles) {
7852                         continue;
7853                     }
7854
7855                     j = 0;
7856
7857                     do {
7858                         if (Manager.isCreated(requires[j])) {
7859                             // Take out from the queue
7860                             Ext.Array.erase(requires, j, 1);
7861                         }
7862                         else {
7863                             j++;
7864                         }
7865                     } while (j < requires.length);
7866
7867                     if (item.requires.length === 0) {
7868                         Ext.Array.erase(this.queue, i, 1);
7869                         item.callback.call(item.scope);
7870                         this.refreshQueue();
7871                         break;
7872                     }
7873                 }
7874             }
7875
7876             return this;
7877         },
7878
7879         /**
7880          * Inject a script element to document's head, call onLoad and onError accordingly
7881          * @private
7882          */
7883         injectScriptElement: function(url, onLoad, onError, scope) {
7884             var script = document.createElement('script'),
7885                 me = this,
7886                 onLoadFn = function() {
7887                     me.cleanupScriptElement(script);
7888                     onLoad.call(scope);
7889                 },
7890                 onErrorFn = function() {
7891                     me.cleanupScriptElement(script);
7892                     onError.call(scope);
7893                 };
7894
7895             script.type = 'text/javascript';
7896             script.src = url;
7897             script.onload = onLoadFn;
7898             script.onerror = onErrorFn;
7899             script.onreadystatechange = function() {
7900                 if (this.readyState === 'loaded' || this.readyState === 'complete') {
7901                     onLoadFn();
7902                 }
7903             };
7904
7905             this.documentHead.appendChild(script);
7906
7907             return script;
7908         },
7909
7910         /**
7911          * @private
7912          */
7913         cleanupScriptElement: function(script) {
7914             script.onload = null;
7915             script.onreadystatechange = null;
7916             script.onerror = null;
7917
7918             return this;
7919         },
7920
7921         /**
7922          * Load a script file, supports both asynchronous and synchronous approaches
7923          *
7924          * @param {String} url
7925          * @param {Function} onLoad
7926          * @param {Object} scope
7927          * @param {Boolean} synchronous
7928          * @private
7929          */
7930         loadScriptFile: function(url, onLoad, onError, scope, synchronous) {
7931             var me = this,
7932                 noCacheUrl = url + (this.getConfig('disableCaching') ? ('?' + this.getConfig('disableCachingParam') + '=' + Ext.Date.now()) : ''),
7933                 fileName = url.split('/').pop(),
7934                 isCrossOriginRestricted = false,
7935                 xhr, status, onScriptError;
7936
7937             scope = scope || this;
7938
7939             this.isLoading = true;
7940
7941             if (!synchronous) {
7942                 onScriptError = function() {
7943                     onError.call(scope, "Failed loading '" + url + "', please verify that the file exists", synchronous);
7944                 };
7945
7946                 if (!Ext.isReady && Ext.onDocumentReady) {
7947                     Ext.onDocumentReady(function() {
7948                         me.injectScriptElement(noCacheUrl, onLoad, onScriptError, scope);
7949                     });
7950                 }
7951                 else {
7952                     this.injectScriptElement(noCacheUrl, onLoad, onScriptError, scope);
7953                 }
7954             }
7955             else {
7956                 if (typeof XMLHttpRequest !== 'undefined') {
7957                     xhr = new XMLHttpRequest();
7958                 } else {
7959                     xhr = new ActiveXObject('Microsoft.XMLHTTP');
7960                 }
7961
7962                 try {
7963                     xhr.open('GET', noCacheUrl, false);
7964                     xhr.send(null);
7965                 } catch (e) {
7966                     isCrossOriginRestricted = true;
7967                 }
7968
7969                 status = (xhr.status === 1223) ? 204 : xhr.status;
7970
7971                 if (!isCrossOriginRestricted) {
7972                     isCrossOriginRestricted = (status === 0);
7973                 }
7974
7975                 if (isCrossOriginRestricted
7976                 ) {
7977                     onError.call(this, "Failed loading synchronously via XHR: '" + url + "'; It's likely that the file is either " +
7978                                        "being loaded from a different domain or from the local file system whereby cross origin " +
7979                                        "requests are not allowed due to security reasons. Use asynchronous loading with " +
7980                                        "Ext.require instead.", synchronous);
7981                 }
7982                 else if (status >= 200 && status < 300
7983                 ) {
7984                     // Firebug friendly, file names are still shown even though they're eval'ed code
7985                     new Function(xhr.responseText + "\n//@ sourceURL=" + fileName)();
7986
7987                     onLoad.call(scope);
7988                 }
7989                 else {
7990                     onError.call(this, "Failed loading synchronously via XHR: '" + url + "'; please " +
7991                                        "verify that the file exists. " +
7992                                        "XHR status code: " + status, synchronous);
7993                 }
7994
7995                 // Prevent potential IE memory leak
7996                 xhr = null;
7997             }
7998         },
7999
8000         /**
8001          * Explicitly exclude files from being loaded. Useful when used in conjunction with a broad include expression.
8002          * Can be chained with more `require` and `exclude` methods, e.g.:
8003          *
8004          *     Ext.exclude('Ext.data.*').require('*');
8005          *
8006          *     Ext.exclude('widget.button*').require('widget.*');
8007          *
8008          * {@link Ext#exclude Ext.exclude} is alias for {@link Ext.Loader#exclude Ext.Loader.exclude} for convenience.
8009          *
8010          * @param {String/String[]} excludes
8011          * @return {Object} object contains `require` method for chaining
8012          */
8013         exclude: function(excludes) {
8014             var me = this;
8015
8016             return {
8017                 require: function(expressions, fn, scope) {
8018                     return me.require(expressions, fn, scope, excludes);
8019                 },
8020
8021                 syncRequire: function(expressions, fn, scope) {
8022                     return me.syncRequire(expressions, fn, scope, excludes);
8023                 }
8024             };
8025         },
8026
8027         /**
8028          * Synchronously loads all classes by the given names and all their direct dependencies;
8029          * optionally executes the given callback function when finishes, within the optional scope.
8030          *
8031          * {@link Ext#syncRequire Ext.syncRequire} is alias for {@link Ext.Loader#syncRequire Ext.Loader.syncRequire} for convenience.
8032          *
8033          * @param {String/String[]} expressions Can either be a string or an array of string
8034          * @param {Function} fn (Optional) The callback function
8035          * @param {Object} scope (Optional) The execution scope (`this`) of the callback function
8036          * @param {String/String[]} excludes (Optional) Classes to be excluded, useful when being used with expressions
8037          */
8038         syncRequire: function() {
8039             this.syncModeEnabled = true;
8040             this.require.apply(this, arguments);
8041             this.refreshQueue();
8042             this.syncModeEnabled = false;
8043         },
8044
8045         /**
8046          * Loads all classes by the given names and all their direct dependencies;
8047          * optionally executes the given callback function when finishes, within the optional scope.
8048          *
8049          * {@link Ext#require Ext.require} is alias for {@link Ext.Loader#require Ext.Loader.require} for convenience.
8050          *
8051          * @param {String/String[]} expressions Can either be a string or an array of string
8052          * @param {Function} fn (Optional) The callback function
8053          * @param {Object} scope (Optional) The execution scope (`this`) of the callback function
8054          * @param {String/String[]} excludes (Optional) Classes to be excluded, useful when being used with expressions
8055          */
8056         require: function(expressions, fn, scope, excludes) {
8057             var filePath, expression, exclude, className, excluded = {},
8058                 excludedClassNames = [],
8059                 possibleClassNames = [],
8060                 possibleClassName, classNames = [],
8061                 i, j, ln, subLn;
8062
8063             expressions = Ext.Array.from(expressions);
8064             excludes = Ext.Array.from(excludes);
8065
8066             fn = fn || Ext.emptyFn;
8067
8068             scope = scope || Ext.global;
8069
8070             for (i = 0, ln = excludes.length; i < ln; i++) {
8071                 exclude = excludes[i];
8072
8073                 if (typeof exclude === 'string' && exclude.length > 0) {
8074                     excludedClassNames = Manager.getNamesByExpression(exclude);
8075
8076                     for (j = 0, subLn = excludedClassNames.length; j < subLn; j++) {
8077                         excluded[excludedClassNames[j]] = true;
8078                     }
8079                 }
8080             }
8081
8082             for (i = 0, ln = expressions.length; i < ln; i++) {
8083                 expression = expressions[i];
8084
8085                 if (typeof expression === 'string' && expression.length > 0) {
8086                     possibleClassNames = Manager.getNamesByExpression(expression);
8087
8088                     for (j = 0, subLn = possibleClassNames.length; j < subLn; j++) {
8089                         possibleClassName = possibleClassNames[j];
8090
8091                         if (!excluded.hasOwnProperty(possibleClassName) && !Manager.isCreated(possibleClassName)) {
8092                             Ext.Array.include(classNames, possibleClassName);
8093                         }
8094                     }
8095                 }
8096             }
8097
8098             // If the dynamic dependency feature is not being used, throw an error
8099             // if the dependencies are not defined
8100             if (!this.config.enabled) {
8101                 if (classNames.length > 0) {
8102                     Ext.Error.raise({
8103                         sourceClass: "Ext.Loader",
8104                         sourceMethod: "require",
8105                         msg: "Ext.Loader is not enabled, so dependencies cannot be resolved dynamically. " +
8106                              "Missing required class" + ((classNames.length > 1) ? "es" : "") + ": " + classNames.join(', ')
8107                     });
8108                 }
8109             }
8110
8111             if (classNames.length === 0) {
8112                 fn.call(scope);
8113                 return this;
8114             }
8115
8116             this.queue.push({
8117                 requires: classNames,
8118                 callback: fn,
8119                 scope: scope
8120             });
8121
8122             classNames = classNames.slice();
8123
8124             for (i = 0, ln = classNames.length; i < ln; i++) {
8125                 className = classNames[i];
8126
8127                 if (!this.isFileLoaded.hasOwnProperty(className)) {
8128                     this.isFileLoaded[className] = false;
8129
8130                     filePath = this.getPath(className);
8131
8132                     this.classNameToFilePathMap[className] = filePath;
8133
8134                     this.numPendingFiles++;
8135
8136                     this.loadScriptFile(
8137                         filePath,
8138                         Ext.Function.pass(this.onFileLoaded, [className, filePath], this),
8139                         Ext.Function.pass(this.onFileLoadError, [className, filePath]),
8140                         this,
8141                         this.syncModeEnabled
8142                     );
8143                 }
8144             }
8145
8146             return this;
8147         },
8148
8149         /**
8150          * @private
8151          * @param {String} className
8152          * @param {String} filePath
8153          */
8154         onFileLoaded: function(className, filePath) {
8155             this.numLoadedFiles++;
8156
8157             this.isFileLoaded[className] = true;
8158
8159             this.numPendingFiles--;
8160
8161             if (this.numPendingFiles === 0) {
8162                 this.refreshQueue();
8163             }
8164
8165             if (this.numPendingFiles <= 1) {
8166                 window.status = "Finished loading all dependencies, onReady fired!";
8167             }
8168             else {
8169                 window.status = "Loading dependencies, " + this.numPendingFiles + " files left...";
8170             }
8171
8172             if (!this.syncModeEnabled && this.numPendingFiles === 0 && this.isLoading && !this.hasFileLoadError) {
8173                 var queue = this.queue,
8174                     requires,
8175                     i, ln, j, subLn, missingClasses = [], missingPaths = [];
8176
8177                 for (i = 0, ln = queue.length; i < ln; i++) {
8178                     requires = queue[i].requires;
8179
8180                     for (j = 0, subLn = requires.length; j < ln; j++) {
8181                         if (this.isFileLoaded[requires[j]]) {
8182                             missingClasses.push(requires[j]);
8183                         }
8184                     }
8185                 }
8186
8187                 if (missingClasses.length < 1) {
8188                     return;
8189                 }
8190
8191                 missingClasses = Ext.Array.filter(missingClasses, function(item) {
8192                     return !this.requiresMap.hasOwnProperty(item);
8193                 }, this);
8194
8195                 for (i = 0,ln = missingClasses.length; i < ln; i++) {
8196                     missingPaths.push(this.classNameToFilePathMap[missingClasses[i]]);
8197                 }
8198
8199                 Ext.Error.raise({
8200                     sourceClass: "Ext.Loader",
8201                     sourceMethod: "onFileLoaded",
8202                     msg: "The following classes are not declared even if their files have been " +
8203                             "loaded: '" + missingClasses.join("', '") + "'. Please check the source code of their " +
8204                             "corresponding files for possible typos: '" + missingPaths.join("', '") + "'"
8205                 });
8206             }
8207         },
8208
8209         /**
8210          * @private
8211          */
8212         onFileLoadError: function(className, filePath, errorMessage, isSynchronous) {
8213             this.numPendingFiles--;
8214             this.hasFileLoadError = true;
8215
8216             Ext.Error.raise({
8217                 sourceClass: "Ext.Loader",
8218                 classToLoad: className,
8219                 loadPath: filePath,
8220                 loadingType: isSynchronous ? 'synchronous' : 'async',
8221                 msg: errorMessage
8222             });
8223         },
8224
8225         /**
8226          * @private
8227          */
8228         addOptionalRequires: function(requires) {
8229             var optionalRequires = this.optionalRequires,
8230                 i, ln, require;
8231
8232             requires = Ext.Array.from(requires);
8233
8234             for (i = 0, ln = requires.length; i < ln; i++) {
8235                 require = requires[i];
8236
8237                 Ext.Array.include(optionalRequires, require);
8238             }
8239
8240             return this;
8241         },
8242
8243         /**
8244          * @private
8245          */
8246         triggerReady: function(force) {
8247             var readyListeners = this.readyListeners,
8248                 optionalRequires, listener;
8249
8250             if (this.isLoading || force) {
8251                 this.isLoading = false;
8252
8253                 if (this.optionalRequires.length) {
8254                     // Clone then empty the array to eliminate potential recursive loop issue
8255                     optionalRequires = Ext.Array.clone(this.optionalRequires);
8256
8257                     // Empty the original array
8258                     this.optionalRequires.length = 0;
8259
8260                     this.require(optionalRequires, Ext.Function.pass(this.triggerReady, [true], this), this);
8261                     return this;
8262                 }
8263
8264                 while (readyListeners.length) {
8265                     listener = readyListeners.shift();
8266                     listener.fn.call(listener.scope);
8267
8268                     if (this.isLoading) {
8269                         return this;
8270                     }
8271                 }
8272             }
8273
8274             return this;
8275         },
8276
8277         /**
8278          * Adds new listener to be executed when all required scripts are fully loaded.
8279          *
8280          * @param {Function} fn The function callback to be executed
8281          * @param {Object} scope The execution scope (`this`) of the callback function
8282          * @param {Boolean} withDomReady Whether or not to wait for document dom ready as well
8283          */
8284         onReady: function(fn, scope, withDomReady, options) {
8285             var oldFn;
8286
8287             if (withDomReady !== false && Ext.onDocumentReady) {
8288                 oldFn = fn;
8289
8290                 fn = function() {
8291                     Ext.onDocumentReady(oldFn, scope, options);
8292                 };
8293             }
8294
8295             if (!this.isLoading) {
8296                 fn.call(scope);
8297             }
8298             else {
8299                 this.readyListeners.push({
8300                     fn: fn,
8301                     scope: scope
8302                 });
8303             }
8304         },
8305
8306         /**
8307          * @private
8308          * @param {String} className
8309          */
8310         historyPush: function(className) {
8311             if (className && this.isFileLoaded.hasOwnProperty(className)) {
8312                 Ext.Array.include(this.history, className);
8313             }
8314
8315             return this;
8316         }
8317     };
8318
8319     /**
8320      * @member Ext
8321      * @method require
8322      * @alias Ext.Loader#require
8323      */
8324     Ext.require = alias(Loader, 'require');
8325
8326     /**
8327      * @member Ext
8328      * @method syncRequire
8329      * @alias Ext.Loader#syncRequire
8330      */
8331     Ext.syncRequire = alias(Loader, 'syncRequire');
8332
8333     /**
8334      * @member Ext
8335      * @method exclude
8336      * @alias Ext.Loader#exclude
8337      */
8338     Ext.exclude = alias(Loader, 'exclude');
8339
8340     /**
8341      * @member Ext
8342      * @method onReady
8343      * @alias Ext.Loader#onReady
8344      */
8345     Ext.onReady = function(fn, scope, options) {
8346         Loader.onReady(fn, scope, true, options);
8347     };
8348
8349     /**
8350      * @cfg {String[]} requires
8351      * @member Ext.Class
8352      * List of classes that have to be loaded before instantiating this class.
8353      * For example:
8354      *
8355      *     Ext.define('Mother', {
8356      *         requires: ['Child'],
8357      *         giveBirth: function() {
8358      *             // we can be sure that child class is available.
8359      *             return new Child();
8360      *         }
8361      *     });
8362      */
8363     Class.registerPreprocessor('loader', function(cls, data, continueFn) {
8364         var me = this,
8365             dependencies = [],
8366             className = Manager.getName(cls),
8367             i, j, ln, subLn, value, propertyName, propertyValue;
8368
8369         /*
8370         Basically loop through the dependencyProperties, look for string class names and push
8371         them into a stack, regardless of whether the property's value is a string, array or object. For example:
8372         {
8373               extend: 'Ext.MyClass',
8374               requires: ['Ext.some.OtherClass'],
8375               mixins: {
8376                   observable: 'Ext.util.Observable';
8377               }
8378         }
8379         which will later be transformed into:
8380         {
8381               extend: Ext.MyClass,
8382               requires: [Ext.some.OtherClass],
8383               mixins: {
8384                   observable: Ext.util.Observable;
8385               }
8386         }
8387         */
8388
8389         for (i = 0, ln = dependencyProperties.length; i < ln; i++) {
8390             propertyName = dependencyProperties[i];
8391
8392             if (data.hasOwnProperty(propertyName)) {
8393                 propertyValue = data[propertyName];
8394
8395                 if (typeof propertyValue === 'string') {
8396                     dependencies.push(propertyValue);
8397                 }
8398                 else if (propertyValue instanceof Array) {
8399                     for (j = 0, subLn = propertyValue.length; j < subLn; j++) {
8400                         value = propertyValue[j];
8401
8402                         if (typeof value === 'string') {
8403                             dependencies.push(value);
8404                         }
8405                     }
8406                 }
8407                 else if (typeof propertyValue != 'function') {
8408                     for (j in propertyValue) {
8409                         if (propertyValue.hasOwnProperty(j)) {
8410                             value = propertyValue[j];
8411
8412                             if (typeof value === 'string') {
8413                                 dependencies.push(value);
8414                             }
8415                         }
8416                     }
8417                 }
8418             }
8419         }
8420
8421         if (dependencies.length === 0) {
8422 //            Loader.historyPush(className);
8423             return;
8424         }
8425
8426         var deadlockPath = [],
8427             requiresMap = Loader.requiresMap,
8428             detectDeadlock;
8429
8430         /*
8431         Automatically detect deadlocks before-hand,
8432         will throw an error with detailed path for ease of debugging. Examples of deadlock cases:
8433
8434         - A extends B, then B extends A
8435         - A requires B, B requires C, then C requires A
8436
8437         The detectDeadlock function will recursively transverse till the leaf, hence it can detect deadlocks
8438         no matter how deep the path is.
8439         */
8440
8441         if (className) {
8442             requiresMap[className] = dependencies;
8443
8444             detectDeadlock = function(cls) {
8445                 deadlockPath.push(cls);
8446
8447                 if (requiresMap[cls]) {
8448                     if (Ext.Array.contains(requiresMap[cls], className)) {
8449                         Ext.Error.raise({
8450                             sourceClass: "Ext.Loader",
8451                             msg: "Deadlock detected while loading dependencies! '" + className + "' and '" +
8452                                 deadlockPath[1] + "' " + "mutually require each other. Path: " +
8453                                 deadlockPath.join(' -> ') + " -> " + deadlockPath[0]
8454                         });
8455                     }
8456
8457                     for (i = 0, ln = requiresMap[cls].length; i < ln; i++) {
8458                         detectDeadlock(requiresMap[cls][i]);
8459                     }
8460                 }
8461             };
8462
8463             detectDeadlock(className);
8464         }
8465
8466
8467         Loader.require(dependencies, function() {
8468             for (i = 0, ln = dependencyProperties.length; i < ln; i++) {
8469                 propertyName = dependencyProperties[i];
8470
8471                 if (data.hasOwnProperty(propertyName)) {
8472                     propertyValue = data[propertyName];
8473
8474                     if (typeof propertyValue === 'string') {
8475                         data[propertyName] = Manager.get(propertyValue);
8476                     }
8477                     else if (propertyValue instanceof Array) {
8478                         for (j = 0, subLn = propertyValue.length; j < subLn; j++) {
8479                             value = propertyValue[j];
8480
8481                             if (typeof value === 'string') {
8482                                 data[propertyName][j] = Manager.get(value);
8483                             }
8484                         }
8485                     }
8486                     else if (typeof propertyValue != 'function') {
8487                         for (var k in propertyValue) {
8488                             if (propertyValue.hasOwnProperty(k)) {
8489                                 value = propertyValue[k];
8490
8491                                 if (typeof value === 'string') {
8492                                     data[propertyName][k] = Manager.get(value);
8493                                 }
8494                             }
8495                         }
8496                     }
8497                 }
8498             }
8499
8500             continueFn.call(me, cls, data);
8501         });
8502
8503         return false;
8504     }, true);
8505
8506     Class.setDefaultPreprocessorPosition('loader', 'after', 'className');
8507
8508     /**
8509      * @cfg {String[]} uses
8510      * @member Ext.Class
8511      * List of classes to load together with this class.  These aren't neccessarily loaded before
8512      * this class is instantiated. For example:
8513      *
8514      *     Ext.define('Mother', {
8515      *         uses: ['Child'],
8516      *         giveBirth: function() {
8517      *             // This code might, or might not work:
8518      *             // return new Child();
8519      *
8520      *             // Instead use Ext.create() to load the class at the spot if not loaded already:
8521      *             return Ext.create('Child');
8522      *         }
8523      *     });
8524      */
8525     Manager.registerPostprocessor('uses', function(name, cls, data) {
8526         var uses = Ext.Array.from(data.uses),
8527             items = [],
8528             i, ln, item;
8529
8530         for (i = 0, ln = uses.length; i < ln; i++) {
8531             item = uses[i];
8532
8533             if (typeof item === 'string') {
8534                 items.push(item);
8535             }
8536         }
8537
8538         Loader.addOptionalRequires(items);
8539     });
8540
8541     Manager.setDefaultPostprocessorPosition('uses', 'last');
8542
8543 })(Ext.ClassManager, Ext.Class, Ext.Function.flexSetter, Ext.Function.alias);
8544
8545 /**
8546  * @author Brian Moeskau <brian@sencha.com>
8547  * @docauthor Brian Moeskau <brian@sencha.com>
8548  *
8549  * A wrapper class for the native JavaScript Error object that adds a few useful capabilities for handling
8550  * errors in an Ext application. When you use Ext.Error to {@link #raise} an error from within any class that
8551  * uses the Ext 4 class system, the Error class can automatically add the source class and method from which
8552  * the error was raised. It also includes logic to automatically log the eroor to the console, if available,
8553  * with additional metadata about the error. In all cases, the error will always be thrown at the end so that
8554  * execution will halt.
8555  *
8556  * Ext.Error also offers a global error {@link #handle handling} method that can be overridden in order to
8557  * handle application-wide errors in a single spot. You can optionally {@link #ignore} errors altogether,
8558  * although in a real application it's usually a better idea to override the handling function and perform
8559  * logging or some other method of reporting the errors in a way that is meaningful to the application.
8560  *
8561  * At its simplest you can simply raise an error as a simple string from within any code:
8562  *
8563  * Example usage:
8564  *
8565  *     Ext.Error.raise('Something bad happened!');
8566  *
8567  * If raised from plain JavaScript code, the error will be logged to the console (if available) and the message
8568  * displayed. In most cases however you'll be raising errors from within a class, and it may often be useful to add
8569  * additional metadata about the error being raised.  The {@link #raise} method can also take a config object.
8570  * In this form the `msg` attribute becomes the error description, and any other data added to the config gets
8571  * added to the error object and, if the console is available, logged to the console for inspection.
8572  *
8573  * Example usage:
8574  *
8575  *     Ext.define('Ext.Foo', {
8576  *         doSomething: function(option){
8577  *             if (someCondition === false) {
8578  *                 Ext.Error.raise({
8579  *                     msg: 'You cannot do that!',
8580  *                     option: option,   // whatever was passed into the method
8581  *                     'error code': 100 // other arbitrary info
8582  *                 });
8583  *             }
8584  *         }
8585  *     });
8586  *
8587  * If a console is available (that supports the `console.dir` function) you'll see console output like:
8588  *
8589  *     An error was raised with the following data:
8590  *     option:         Object { foo: "bar"}
8591  *         foo:        "bar"
8592  *     error code:     100
8593  *     msg:            "You cannot do that!"
8594  *     sourceClass:   "Ext.Foo"
8595  *     sourceMethod:  "doSomething"
8596  *
8597  *     uncaught exception: You cannot do that!
8598  *
8599  * As you can see, the error will report exactly where it was raised and will include as much information as the
8600  * raising code can usefully provide.
8601  *
8602  * If you want to handle all application errors globally you can simply override the static {@link #handle} method
8603  * and provide whatever handling logic you need. If the method returns true then the error is considered handled
8604  * and will not be thrown to the browser. If anything but true is returned then the error will be thrown normally.
8605  *
8606  * Example usage:
8607  *
8608  *     Ext.Error.handle = function(err) {
8609  *         if (err.someProperty == 'NotReallyAnError') {
8610  *             // maybe log something to the application here if applicable
8611  *             return true;
8612  *         }
8613  *         // any non-true return value (including none) will cause the error to be thrown
8614  *     }
8615  *
8616  */
8617 Ext.Error = Ext.extend(Error, {
8618     statics: {
8619         /**
8620          * @property {Boolean} ignore
8621          * Static flag that can be used to globally disable error reporting to the browser if set to true
8622          * (defaults to false). Note that if you ignore Ext errors it's likely that some other code may fail
8623          * and throw a native JavaScript error thereafter, so use with caution. In most cases it will probably
8624          * be preferable to supply a custom error {@link #handle handling} function instead.
8625          *
8626          * Example usage:
8627          *
8628          *     Ext.Error.ignore = true;
8629          *
8630          * @static
8631          */
8632         ignore: false,
8633
8634         /**
8635          * @property {Boolean} notify
8636          * Static flag that can be used to globally control error notification to the user. Unlike
8637          * Ex.Error.ignore, this does not effect exceptions. They are still thrown. This value can be
8638          * set to false to disable the alert notification (default is true for IE6 and IE7).
8639          *
8640          * Only the first error will generate an alert. Internally this flag is set to false when the
8641          * first error occurs prior to displaying the alert.
8642          *
8643          * This flag is not used in a release build.
8644          *
8645          * Example usage:
8646          *
8647          *     Ext.Error.notify = false;
8648          *
8649          * @static
8650          */
8651         //notify: Ext.isIE6 || Ext.isIE7,
8652
8653         /**
8654          * Raise an error that can include additional data and supports automatic console logging if available.
8655          * You can pass a string error message or an object with the `msg` attribute which will be used as the
8656          * error message. The object can contain any other name-value attributes (or objects) to be logged
8657          * along with the error.
8658          *
8659          * Note that after displaying the error message a JavaScript error will ultimately be thrown so that
8660          * execution will halt.
8661          *
8662          * Example usage:
8663          *
8664          *     Ext.Error.raise('A simple string error message');
8665          *
8666          *     // or...
8667          *
8668          *     Ext.define('Ext.Foo', {
8669          *         doSomething: function(option){
8670          *             if (someCondition === false) {
8671          *                 Ext.Error.raise({
8672          *                     msg: 'You cannot do that!',
8673          *                     option: option,   // whatever was passed into the method
8674          *                     'error code': 100 // other arbitrary info
8675          *                 });
8676          *             }
8677          *         }
8678          *     });
8679          *
8680          * @param {String/Object} err The error message string, or an object containing the attribute "msg" that will be
8681          * used as the error message. Any other data included in the object will also be logged to the browser console,
8682          * if available.
8683          * @static
8684          */
8685         raise: function(err){
8686             err = err || {};
8687             if (Ext.isString(err)) {
8688                 err = { msg: err };
8689             }
8690
8691             var method = this.raise.caller;
8692
8693             if (method) {
8694                 if (method.$name) {
8695                     err.sourceMethod = method.$name;
8696                 }
8697                 if (method.$owner) {
8698                     err.sourceClass = method.$owner.$className;
8699                 }
8700             }
8701
8702             if (Ext.Error.handle(err) !== true) {
8703                 var msg = Ext.Error.prototype.toString.call(err);
8704
8705                 Ext.log({
8706                     msg: msg,
8707                     level: 'error',
8708                     dump: err,
8709                     stack: true
8710                 });
8711
8712                 throw new Ext.Error(err);
8713             }
8714         },
8715
8716         /**
8717          * Globally handle any Ext errors that may be raised, optionally providing custom logic to
8718          * handle different errors individually. Return true from the function to bypass throwing the
8719          * error to the browser, otherwise the error will be thrown and execution will halt.
8720          *
8721          * Example usage:
8722          *
8723          *     Ext.Error.handle = function(err) {
8724          *         if (err.someProperty == 'NotReallyAnError') {
8725          *             // maybe log something to the application here if applicable
8726          *             return true;
8727          *         }
8728          *         // any non-true return value (including none) will cause the error to be thrown
8729          *     }
8730          *
8731          * @param {Ext.Error} err The Ext.Error object being raised. It will contain any attributes that were originally
8732          * raised with it, plus properties about the method and class from which the error originated (if raised from a
8733          * class that uses the Ext 4 class system).
8734          * @static
8735          */
8736         handle: function(){
8737             return Ext.Error.ignore;
8738         }
8739     },
8740
8741     // This is the standard property that is the name of the constructor.
8742     name: 'Ext.Error',
8743
8744     /**
8745      * Creates new Error object.
8746      * @param {String/Object} config The error message string, or an object containing the
8747      * attribute "msg" that will be used as the error message. Any other data included in
8748      * the object will be applied to the error instance and logged to the browser console, if available.
8749      */
8750     constructor: function(config){
8751         if (Ext.isString(config)) {
8752             config = { msg: config };
8753         }
8754
8755         var me = this;
8756
8757         Ext.apply(me, config);
8758
8759         me.message = me.message || me.msg; // 'message' is standard ('msg' is non-standard)
8760         // note: the above does not work in old WebKit (me.message is readonly) (Safari 4)
8761     },
8762
8763     /**
8764      * Provides a custom string representation of the error object. This is an override of the base JavaScript
8765      * `Object.toString` method, which is useful so that when logged to the browser console, an error object will
8766      * be displayed with a useful message instead of `[object Object]`, the default `toString` result.
8767      *
8768      * The default implementation will include the error message along with the raising class and method, if available,
8769      * but this can be overridden with a custom implementation either at the prototype level (for all errors) or on
8770      * a particular error instance, if you want to provide a custom description that will show up in the console.
8771      * @return {String} The error message. If raised from within the Ext 4 class system, the error message will also
8772      * include the raising class and method names, if available.
8773      */
8774     toString: function(){
8775         var me = this,
8776             className = me.className ? me.className  : '',
8777             methodName = me.methodName ? '.' + me.methodName + '(): ' : '',
8778             msg = me.msg || '(No description provided)';
8779
8780         return className + methodName + msg;
8781     }
8782 });
8783
8784 /*
8785  * This mechanism is used to notify the user of the first error encountered on the page. This
8786  * was previously internal to Ext.Error.raise and is a desirable feature since errors often
8787  * slip silently under the radar. It cannot live in Ext.Error.raise since there are times
8788  * where exceptions are handled in a try/catch.
8789  */
8790 (function () {
8791     var prevOnError, timer, errors = 0,
8792         extraordinarilyBad = /(out of stack)|(too much recursion)|(stack overflow)|(out of memory)/i,
8793         win = Ext.global;
8794
8795     if (typeof window === 'undefined') {
8796         return; // build system or some such environment...
8797     }
8798
8799     // This method is called to notify the user of the current error status.
8800     function notify () {
8801         var counters = Ext.log.counters,
8802             supports = Ext.supports,
8803             hasOnError = supports && supports.WindowOnError; // TODO - timing
8804
8805         // Put log counters to the status bar (for most browsers):
8806         if (counters && (counters.error + counters.warn + counters.info + counters.log)) {
8807             var msg = [ 'Logged Errors:',counters.error, 'Warnings:',counters.warn,
8808                         'Info:',counters.info, 'Log:',counters.log].join(' ');
8809             if (errors) {
8810                 msg = '*** Errors: ' + errors + ' - ' + msg;
8811             } else if (counters.error) {
8812                 msg = '*** ' + msg;
8813             }
8814             win.status = msg;
8815         }
8816
8817         // Display an alert on the first error:
8818         if (!Ext.isDefined(Ext.Error.notify)) {
8819             Ext.Error.notify = Ext.isIE6 || Ext.isIE7; // TODO - timing
8820         }
8821         if (Ext.Error.notify && (hasOnError ? errors : (counters && counters.error))) {
8822             Ext.Error.notify = false;
8823
8824             if (timer) {
8825                 win.clearInterval(timer); // ticks can queue up so stop...
8826                 timer = null;
8827             }
8828
8829             alert('Unhandled error on page: See console or log');
8830             poll();
8831         }
8832     }
8833
8834     // Sets up polling loop. This is the only way to know about errors in some browsers
8835     // (Opera/Safari) and is the only way to update the status bar for warnings and other
8836     // non-errors.
8837     function poll () {
8838         timer = win.setInterval(notify, 1000);
8839     }
8840
8841     // window.onerror sounds ideal but it prevents the built-in error dialog from doing
8842     // its (better) thing.
8843     poll();
8844 })();
8845
8846
8847
8848 /*
8849
8850 This file is part of Ext JS 4
8851
8852 Copyright (c) 2011 Sencha Inc
8853
8854 Contact:  http://www.sencha.com/contact
8855
8856 GNU General Public License Usage
8857 This file may be used under the terms of the GNU General Public License version 3.0 as published by the Free Software Foundation and appearing in the file LICENSE included in the packaging of this file.  Please review the following information to ensure the GNU General Public License version 3.0 requirements will be met: http://www.gnu.org/copyleft/gpl.html.
8858
8859 If you are unsure which license is appropriate for your use, please contact the sales department at http://www.sencha.com/contact.
8860
8861 */
8862 /**
8863  * @class Ext.JSON
8864  * Modified version of Douglas Crockford's JSON.js that doesn't
8865  * mess with the Object prototype
8866  * http://www.json.org/js.html
8867  * @singleton
8868  */
8869 Ext.JSON = new(function() {
8870     var useHasOwn = !! {}.hasOwnProperty,
8871     isNative = function() {
8872         var useNative = null;
8873
8874         return function() {
8875             if (useNative === null) {
8876                 useNative = Ext.USE_NATIVE_JSON && window.JSON && JSON.toString() == '[object JSON]';
8877             }
8878
8879             return useNative;
8880         };
8881     }(),
8882     pad = function(n) {
8883         return n < 10 ? "0" + n : n;
8884     },
8885     doDecode = function(json) {
8886         return eval("(" + json + ')');
8887     },
8888     doEncode = function(o) {
8889         if (!Ext.isDefined(o) || o === null) {
8890             return "null";
8891         } else if (Ext.isArray(o)) {
8892             return encodeArray(o);
8893         } else if (Ext.isDate(o)) {
8894             return Ext.JSON.encodeDate(o);
8895         } else if (Ext.isString(o)) {
8896             return encodeString(o);
8897         } else if (typeof o == "number") {
8898             //don't use isNumber here, since finite checks happen inside isNumber
8899             return isFinite(o) ? String(o) : "null";
8900         } else if (Ext.isBoolean(o)) {
8901             return String(o);
8902         } else if (Ext.isObject(o)) {
8903             return encodeObject(o);
8904         } else if (typeof o === "function") {
8905             return "null";
8906         }
8907         return 'undefined';
8908     },
8909     m = {
8910         "\b": '\\b',
8911         "\t": '\\t',
8912         "\n": '\\n',
8913         "\f": '\\f',
8914         "\r": '\\r',
8915         '"': '\\"',
8916         "\\": '\\\\',
8917         '\x0b': '\\u000b' //ie doesn't handle \v
8918     },
8919     charToReplace = /[\\\"\x00-\x1f\x7f-\uffff]/g,
8920     encodeString = function(s) {
8921         return '"' + s.replace(charToReplace, function(a) {
8922             var c = m[a];
8923             return typeof c === 'string' ? c : '\\u' + ('0000' + a.charCodeAt(0).toString(16)).slice(-4);
8924         }) + '"';
8925     },
8926     encodeArray = function(o) {
8927         var a = ["[", ""],
8928         // Note empty string in case there are no serializable members.
8929         len = o.length,
8930         i;
8931         for (i = 0; i < len; i += 1) {
8932             a.push(doEncode(o[i]), ',');
8933         }
8934         // Overwrite trailing comma (or empty string)
8935         a[a.length - 1] = ']';
8936         return a.join("");
8937     },
8938     encodeObject = function(o) {
8939         var a = ["{", ""],
8940         // Note empty string in case there are no serializable members.
8941         i;
8942         for (i in o) {
8943             if (!useHasOwn || o.hasOwnProperty(i)) {
8944                 a.push(doEncode(i), ":", doEncode(o[i]), ',');
8945             }
8946         }
8947         // Overwrite trailing comma (or empty string)
8948         a[a.length - 1] = '}';
8949         return a.join("");
8950     };
8951
8952     /**
8953      * <p>Encodes a Date. This returns the actual string which is inserted into the JSON string as the literal expression.
8954      * <b>The returned value includes enclosing double quotation marks.</b></p>
8955      * <p>The default return format is "yyyy-mm-ddThh:mm:ss".</p>
8956      * <p>To override this:</p><pre><code>
8957 Ext.JSON.encodeDate = function(d) {
8958     return Ext.Date.format(d, '"Y-m-d"');
8959 };
8960      </code></pre>
8961      * @param {Date} d The Date to encode
8962      * @return {String} The string literal to use in a JSON string.
8963      */
8964     this.encodeDate = function(o) {
8965         return '"' + o.getFullYear() + "-"
8966         + pad(o.getMonth() + 1) + "-"
8967         + pad(o.getDate()) + "T"
8968         + pad(o.getHours()) + ":"
8969         + pad(o.getMinutes()) + ":"
8970         + pad(o.getSeconds()) + '"';
8971     };
8972
8973     /**
8974      * Encodes an Object, Array or other value
8975      * @param {Object} o The variable to encode
8976      * @return {String} The JSON string
8977      */
8978     this.encode = function() {
8979         var ec;
8980         return function(o) {
8981             if (!ec) {
8982                 // setup encoding function on first access
8983                 ec = isNative() ? JSON.stringify : doEncode;
8984             }
8985             return ec(o);
8986         };
8987     }();
8988
8989
8990     /**
8991      * Decodes (parses) a JSON string to an object. If the JSON is invalid, this function throws a SyntaxError unless the safe option is set.
8992      * @param {String} json The JSON string
8993      * @param {Boolean} safe (optional) Whether to return null or throw an exception if the JSON is invalid.
8994      * @return {Object} The resulting object
8995      */
8996     this.decode = function() {
8997         var dc;
8998         return function(json, safe) {
8999             if (!dc) {
9000                 // setup decoding function on first access
9001                 dc = isNative() ? JSON.parse : doDecode;
9002             }
9003             try {
9004                 return dc(json);
9005             } catch (e) {
9006                 if (safe === true) {
9007                     return null;
9008                 }
9009                 Ext.Error.raise({
9010                     sourceClass: "Ext.JSON",
9011                     sourceMethod: "decode",
9012                     msg: "You're trying to decode an invalid JSON String: " + json
9013                 });
9014             }
9015         };
9016     }();
9017
9018 })();
9019 /**
9020  * Shorthand for {@link Ext.JSON#encode}
9021  * @member Ext
9022  * @method encode
9023  * @alias Ext.JSON#encode
9024  */
9025 Ext.encode = Ext.JSON.encode;
9026 /**
9027  * Shorthand for {@link Ext.JSON#decode}
9028  * @member Ext
9029  * @method decode
9030  * @alias Ext.JSON#decode
9031  */
9032 Ext.decode = Ext.JSON.decode;
9033
9034
9035 /**
9036  * @class Ext
9037
9038  The Ext namespace (global object) encapsulates all classes, singletons, and utility methods provided by Sencha's libraries.</p>
9039  Most user interface Components are at a lower level of nesting in the namespace, but many common utility functions are provided
9040  as direct properties of the Ext namespace.
9041
9042  Also many frequently used methods from other classes are provided as shortcuts within the Ext namespace.
9043  For example {@link Ext#getCmp Ext.getCmp} aliases {@link Ext.ComponentManager#get Ext.ComponentManager.get}.
9044
9045  Many applications are initiated with {@link Ext#onReady Ext.onReady} which is called once the DOM is ready.
9046  This ensures all scripts have been loaded, preventing dependency issues. For example
9047
9048      Ext.onReady(function(){
9049          new Ext.Component({
9050              renderTo: document.body,
9051              html: 'DOM ready!'
9052          });
9053      });
9054
9055 For more information about how to use the Ext classes, see
9056
9057 - <a href="http://www.sencha.com/learn/">The Learning Center</a>
9058 - <a href="http://www.sencha.com/learn/Ext_FAQ">The FAQ</a>
9059 - <a href="http://www.sencha.com/forum/">The forums</a>
9060
9061  * @singleton
9062  * @markdown
9063  */
9064 Ext.apply(Ext, {
9065     userAgent: navigator.userAgent.toLowerCase(),
9066     cache: {},
9067     idSeed: 1000,
9068     windowId: 'ext-window',
9069     documentId: 'ext-document',
9070
9071     /**
9072      * True when the document is fully initialized and ready for action
9073      * @type Boolean
9074      */
9075     isReady: false,
9076
9077     /**
9078      * True to automatically uncache orphaned Ext.Elements periodically
9079      * @type Boolean
9080      */
9081     enableGarbageCollector: true,
9082
9083     /**
9084      * True to automatically purge event listeners during garbageCollection.
9085      * @type Boolean
9086      */
9087     enableListenerCollection: true,
9088
9089     /**
9090      * Generates unique ids. If the element already has an id, it is unchanged
9091      * @param {HTMLElement/Ext.Element} el (optional) The element to generate an id for
9092      * @param {String} prefix (optional) Id prefix (defaults "ext-gen")
9093      * @return {String} The generated Id.
9094      */
9095     id: function(el, prefix) {
9096         var me = this,
9097             sandboxPrefix = '';
9098         el = Ext.getDom(el, true) || {};
9099         if (el === document) {
9100             el.id = me.documentId;
9101         }
9102         else if (el === window) {
9103             el.id = me.windowId;
9104         }
9105         if (!el.id) {
9106             if (me.isSandboxed) {
9107                 if (!me.uniqueGlobalNamespace) {
9108                     me.getUniqueGlobalNamespace();
9109                 }
9110                 sandboxPrefix = me.uniqueGlobalNamespace + '-';
9111             }
9112             el.id = sandboxPrefix + (prefix || "ext-gen") + (++Ext.idSeed);
9113         }
9114         return el.id;
9115     },
9116
9117     /**
9118      * Returns the current document body as an {@link Ext.Element}.
9119      * @return Ext.Element The document body
9120      */
9121     getBody: function() {
9122         return Ext.get(document.body || false);
9123     },
9124
9125     /**
9126      * Returns the current document head as an {@link Ext.Element}.
9127      * @return Ext.Element The document head
9128      * @method
9129      */
9130     getHead: function() {
9131         var head;
9132
9133         return function() {
9134             if (head == undefined) {
9135                 head = Ext.get(document.getElementsByTagName("head")[0]);
9136             }
9137
9138             return head;
9139         };
9140     }(),
9141
9142     /**
9143      * Returns the current HTML document object as an {@link Ext.Element}.
9144      * @return Ext.Element The document
9145      */
9146     getDoc: function() {
9147         return Ext.get(document);
9148     },
9149
9150     /**
9151      * This is shorthand reference to {@link Ext.ComponentManager#get}.
9152      * Looks up an existing {@link Ext.Component Component} by {@link Ext.Component#id id}
9153      * @param {String} id The component {@link Ext.Component#id id}
9154      * @return Ext.Component The Component, <tt>undefined</tt> if not found, or <tt>null</tt> if a
9155      * Class was found.
9156     */
9157     getCmp: function(id) {
9158         return Ext.ComponentManager.get(id);
9159     },
9160
9161     /**
9162      * Returns the current orientation of the mobile device
9163      * @return {String} Either 'portrait' or 'landscape'
9164      */
9165     getOrientation: function() {
9166         return window.innerHeight > window.innerWidth ? 'portrait' : 'landscape';
9167     },
9168
9169     /**
9170      * Attempts to destroy any objects passed to it by removing all event listeners, removing them from the
9171      * DOM (if applicable) and calling their destroy functions (if available).  This method is primarily
9172      * intended for arguments of type {@link Ext.Element} and {@link Ext.Component}, but any subclass of
9173      * {@link Ext.util.Observable} can be passed in.  Any number of elements and/or components can be
9174      * passed into this function in a single call as separate arguments.
9175      * @param {Ext.Element/Ext.Component/Ext.Element[]/Ext.Component[]...} arg1
9176      * An {@link Ext.Element}, {@link Ext.Component}, or an Array of either of these to destroy
9177      */
9178     destroy: function() {
9179         var ln = arguments.length,
9180         i, arg;
9181
9182         for (i = 0; i < ln; i++) {
9183             arg = arguments[i];
9184             if (arg) {
9185                 if (Ext.isArray(arg)) {
9186                     this.destroy.apply(this, arg);
9187                 }
9188                 else if (Ext.isFunction(arg.destroy)) {
9189                     arg.destroy();
9190                 }
9191                 else if (arg.dom) {
9192                     arg.remove();
9193                 }
9194             }
9195         }
9196     },
9197
9198     /**
9199      * Execute a callback function in a particular scope. If no function is passed the call is ignored.
9200      *
9201      * For example, these lines are equivalent:
9202      *
9203      *     Ext.callback(myFunc, this, [arg1, arg2]);
9204      *     Ext.isFunction(myFunc) && myFunc.apply(this, [arg1, arg2]);
9205      *
9206      * @param {Function} callback The callback to execute
9207      * @param {Object} scope (optional) The scope to execute in
9208      * @param {Array} args (optional) The arguments to pass to the function
9209      * @param {Number} delay (optional) Pass a number to delay the call by a number of milliseconds.
9210      */
9211     callback: function(callback, scope, args, delay){
9212         if(Ext.isFunction(callback)){
9213             args = args || [];
9214             scope = scope || window;
9215             if (delay) {
9216                 Ext.defer(callback, delay, scope, args);
9217             } else {
9218                 callback.apply(scope, args);
9219             }
9220         }
9221     },
9222
9223     /**
9224      * Convert certain characters (&, <, >, and ') to their HTML character equivalents for literal display in web pages.
9225      * @param {String} value The string to encode
9226      * @return {String} The encoded text
9227      */
9228     htmlEncode : function(value) {
9229         return Ext.String.htmlEncode(value);
9230     },
9231
9232     /**
9233      * Convert certain characters (&, <, >, and ') from their HTML character equivalents.
9234      * @param {String} value The string to decode
9235      * @return {String} The decoded text
9236      */
9237     htmlDecode : function(value) {
9238          return Ext.String.htmlDecode(value);
9239     },
9240
9241     /**
9242      * Appends content to the query string of a URL, handling logic for whether to place
9243      * a question mark or ampersand.
9244      * @param {String} url The URL to append to.
9245      * @param {String} s The content to append to the URL.
9246      * @return (String) The resulting URL
9247      */
9248     urlAppend : function(url, s) {
9249         if (!Ext.isEmpty(s)) {
9250             return url + (url.indexOf('?') === -1 ? '?' : '&') + s;
9251         }
9252         return url;
9253     }
9254 });
9255
9256
9257 Ext.ns = Ext.namespace;
9258
9259 // for old browsers
9260 window.undefined = window.undefined;
9261
9262 /**
9263  * @class Ext
9264  * Ext core utilities and functions.
9265  * @singleton
9266  */
9267 (function(){
9268 /*
9269 FF 3.6      - Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US; rv:1.9.2.17) Gecko/20110420 Firefox/3.6.17
9270 FF 4.0.1    - Mozilla/5.0 (Windows NT 5.1; rv:2.0.1) Gecko/20100101 Firefox/4.0.1
9271 FF 5.0      - Mozilla/5.0 (Windows NT 6.1; WOW64; rv:5.0) Gecko/20100101 Firefox/5.0
9272
9273 IE6         - Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; SV1;)
9274 IE7         - Mozilla/4.0 (compatible; MSIE 7.0; Windows NT 5.1; SV1;)
9275 IE8         - Mozilla/4.0 (compatible; MSIE 8.0; Windows NT 5.1; Trident/4.0)
9276 IE9         - Mozilla/5.0 (compatible; MSIE 9.0; Windows NT 6.1; WOW64; Trident/5.0; SLCC2; .NET CLR 2.0.50727; .NET CLR 3.5.30729; .NET CLR 3.0.30729; Media Center PC 6.0; .NET4.0C; .NET4.0E)
9277
9278 Chrome 11   - Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/534.24 (KHTML, like Gecko) Chrome/11.0.696.60 Safari/534.24
9279
9280 Safari 5    - Mozilla/5.0 (Windows; U; Windows NT 6.1; en-US) AppleWebKit/533.21.1 (KHTML, like Gecko) Version/5.0.5 Safari/533.21.1
9281
9282 Opera 11.11 - Opera/9.80 (Windows NT 6.1; U; en) Presto/2.8.131 Version/11.11
9283 */
9284     var check = function(regex){
9285             return regex.test(Ext.userAgent);
9286         },
9287         isStrict = document.compatMode == "CSS1Compat",
9288         version = function (is, regex) {
9289             var m;
9290             return (is && (m = regex.exec(Ext.userAgent))) ? parseFloat(m[1]) : 0;
9291         },
9292         docMode = document.documentMode,
9293         isOpera = check(/opera/),
9294         isOpera10_5 = isOpera && check(/version\/10\.5/),
9295         isChrome = check(/\bchrome\b/),
9296         isWebKit = check(/webkit/),
9297         isSafari = !isChrome && check(/safari/),
9298         isSafari2 = isSafari && check(/applewebkit\/4/), // unique to Safari 2
9299         isSafari3 = isSafari && check(/version\/3/),
9300         isSafari4 = isSafari && check(/version\/4/),
9301         isSafari5 = isSafari && check(/version\/5/),
9302         isIE = !isOpera && check(/msie/),
9303         isIE7 = isIE && (check(/msie 7/) || docMode == 7),
9304         isIE8 = isIE && (check(/msie 8/) && docMode != 7 && docMode != 9 || docMode == 8),
9305         isIE9 = isIE && (check(/msie 9/) && docMode != 7 && docMode != 8 || docMode == 9),
9306         isIE6 = isIE && check(/msie 6/),
9307         isGecko = !isWebKit && check(/gecko/),
9308         isGecko3 = isGecko && check(/rv:1\.9/),
9309         isGecko4 = isGecko && check(/rv:2\.0/),
9310         isGecko5 = isGecko && check(/rv:5\./),
9311         isFF3_0 = isGecko3 && check(/rv:1\.9\.0/),
9312         isFF3_5 = isGecko3 && check(/rv:1\.9\.1/),
9313         isFF3_6 = isGecko3 && check(/rv:1\.9\.2/),
9314         isWindows = check(/windows|win32/),
9315         isMac = check(/macintosh|mac os x/),
9316         isLinux = check(/linux/),
9317         scrollbarSize = null,
9318         chromeVersion = version(true, /\bchrome\/(\d+\.\d+)/),
9319         firefoxVersion = version(true, /\bfirefox\/(\d+\.\d+)/),
9320         ieVersion = version(isIE, /msie (\d+\.\d+)/),
9321         operaVersion = version(isOpera, /version\/(\d+\.\d+)/),
9322         safariVersion = version(isSafari, /version\/(\d+\.\d+)/),
9323         webKitVersion = version(isWebKit, /webkit\/(\d+\.\d+)/),
9324         isSecure = /^https/i.test(window.location.protocol);
9325
9326     // remove css image flicker
9327     try {
9328         document.execCommand("BackgroundImageCache", false, true);
9329     } catch(e) {}
9330
9331     function dumpObject (object) {
9332         var member, members = [];
9333
9334         // Cannot use Ext.encode since it can recurse endlessly (if we're lucky)
9335         // ...and the data could be prettier!
9336         Ext.Object.each(object, function (name, value) {
9337             if (typeof(value) === "function") {
9338                 return;
9339             }
9340
9341             if (!Ext.isDefined(value) || value === null ||
9342                     Ext.isDate(value) ||
9343                     Ext.isString(value) || (typeof(value) == "number") ||
9344                     Ext.isBoolean(value)) {
9345                 member = Ext.encode(value);
9346             } else if (Ext.isArray(value)) {
9347                 member = '[ ]';
9348             } else if (Ext.isObject(value)) {
9349                 member = '{ }';
9350             } else {
9351                 member = 'undefined';
9352             }
9353             members.push(Ext.encode(name) + ': ' + member);
9354         });
9355
9356         if (members.length) {
9357             return ' \nData: {\n  ' + members.join(',\n  ') + '\n}';
9358         }
9359         return '';
9360     }
9361
9362     function log (message) {
9363         var options, dump,
9364             con = Ext.global.console,
9365             level = 'log',
9366             indent = log.indent || 0,
9367             stack;
9368
9369         log.indent = indent;
9370
9371         if (!Ext.isString(message)) {
9372             options = message;
9373             message = options.msg || '';
9374             level = options.level || level;
9375             dump = options.dump;
9376             stack = options.stack;
9377
9378             if (options.indent) {
9379                 ++log.indent;
9380             } else if (options.outdent) {
9381                 log.indent = indent = Math.max(indent - 1, 0);
9382             }
9383
9384             if (dump && !(con && con.dir)) {
9385                 message += dumpObject(dump);
9386                 dump = null;
9387             }
9388         }
9389
9390         if (arguments.length > 1) {
9391             message += Array.prototype.slice.call(arguments, 1).join('');
9392         }
9393
9394         message = indent ? Ext.String.repeat('   ', indent) + message : message;
9395         // w/o console, all messages are equal, so munge the level into the message:
9396         if (level != 'log') {
9397             message = '[' + level.charAt(0).toUpperCase() + '] ' + message;
9398         }
9399
9400         // Not obvious, but 'console' comes and goes when Firebug is turned on/off, so
9401         // an early test may fail either direction if Firebug is toggled.
9402         //
9403         if (con) { // if (Firebug-like console)
9404             if (con[level]) {
9405                 con[level](message);
9406             } else {
9407                 con.log(message);
9408             }
9409
9410             if (dump) {
9411                 con.dir(dump);
9412             }
9413
9414             if (stack && con.trace) {
9415                 // Firebug's console.error() includes a trace already...
9416                 if (!con.firebug || level != 'error') {
9417                     con.trace();
9418                 }
9419             }
9420         } else {
9421             if (Ext.isOpera) {
9422                 opera.postError(message);
9423             } else {
9424                 var out = log.out,
9425                     max = log.max;
9426
9427                 if (out.length >= max) {
9428                     // this formula allows out.max to change (via debugger), where the
9429                     // more obvious "max/4" would not quite be the same
9430                     Ext.Array.erase(out, 0, out.length - 3 * Math.floor(max / 4)); // keep newest 75%
9431                 }
9432
9433                 out.push(message);
9434             }
9435         }
9436
9437         // Mostly informational, but the Ext.Error notifier uses them:
9438         ++log.count;
9439         ++log.counters[level];
9440     }
9441
9442     log.count = 0;
9443     log.counters = { error: 0, warn: 0, info: 0, log: 0 };
9444     log.out = [];
9445     log.max = 250;
9446     log.show = function () {
9447         window.open('','extlog').document.write([
9448             '<html><head><script type="text/javascript">',
9449                 'var lastCount = 0;',
9450                 'function update () {',
9451                     'var ext = window.opener.Ext,',
9452                         'extlog = ext && ext.log;',
9453                     'if (extlog && extlog.out && lastCount != extlog.count) {',
9454                         'lastCount = extlog.count;',
9455                         'var s = "<tt>" + extlog.out.join("<br>").replace(/[ ]/g, "&nbsp;") + "</tt>";',
9456                         'document.body.innerHTML = s;',
9457                     '}',
9458                     'setTimeout(update, 1000);',
9459                 '}',
9460                 'setTimeout(update, 1000);',
9461             '</script></head><body></body></html>'].join(''));
9462     };
9463
9464     Ext.setVersion('extjs', '4.0.7');
9465     Ext.apply(Ext, {
9466         /**
9467          * URL to a blank file used by Ext when in secure mode for iframe src and onReady src to prevent
9468          * the IE insecure content warning (<tt>'about:blank'</tt>, except for IE in secure mode, which is <tt>'javascript:""'</tt>).
9469          * @type String
9470          */
9471         SSL_SECURE_URL : isSecure && isIE ? 'javascript:""' : 'about:blank',
9472
9473         /**
9474          * True if the {@link Ext.fx.Anim} Class is available
9475          * @type Boolean
9476          * @property enableFx
9477          */
9478
9479         /**
9480          * True to scope the reset CSS to be just applied to Ext components. Note that this wraps root containers
9481          * with an additional element. Also remember that when you turn on this option, you have to use ext-all-scoped {
9482          * unless you use the bootstrap.js to load your javascript, in which case it will be handled for you.
9483          * @type Boolean
9484          */
9485         scopeResetCSS : Ext.buildSettings.scopeResetCSS,
9486
9487         /**
9488          * EXPERIMENTAL - True to cascade listener removal to child elements when an element is removed.
9489          * Currently not optimized for performance.
9490          * @type Boolean
9491          */
9492         enableNestedListenerRemoval : false,
9493
9494         /**
9495          * Indicates whether to use native browser parsing for JSON methods.
9496          * This option is ignored if the browser does not support native JSON methods.
9497          * <b>Note: Native JSON methods will not work with objects that have functions.
9498          * Also, property names must be quoted, otherwise the data will not parse.</b> (Defaults to false)
9499          * @type Boolean
9500          */
9501         USE_NATIVE_JSON : false,
9502
9503         /**
9504          * Return the dom node for the passed String (id), dom node, or Ext.Element.
9505          * Optional 'strict' flag is needed for IE since it can return 'name' and
9506          * 'id' elements by using getElementById.
9507          * Here are some examples:
9508          * <pre><code>
9509 // gets dom node based on id
9510 var elDom = Ext.getDom('elId');
9511 // gets dom node based on the dom node
9512 var elDom1 = Ext.getDom(elDom);
9513
9514 // If we don&#39;t know if we are working with an
9515 // Ext.Element or a dom node use Ext.getDom
9516 function(el){
9517     var dom = Ext.getDom(el);
9518     // do something with the dom node
9519 }
9520          * </code></pre>
9521          * <b>Note</b>: the dom node to be found actually needs to exist (be rendered, etc)
9522          * when this method is called to be successful.
9523          * @param {String/HTMLElement/Ext.Element} el
9524          * @return HTMLElement
9525          */
9526         getDom : function(el, strict) {
9527             if (!el || !document) {
9528                 return null;
9529             }
9530             if (el.dom) {
9531                 return el.dom;
9532             } else {
9533                 if (typeof el == 'string') {
9534                     var e = document.getElementById(el);
9535                     // IE returns elements with the 'name' and 'id' attribute.
9536                     // we do a strict check to return the element with only the id attribute
9537                     if (e && isIE && strict) {
9538                         if (el == e.getAttribute('id')) {
9539                             return e;
9540                         } else {
9541                             return null;
9542                         }
9543                     }
9544                     return e;
9545                 } else {
9546                     return el;
9547                 }
9548             }
9549         },
9550
9551         /**
9552          * Removes a DOM node from the document.
9553          * <p>Removes this element from the document, removes all DOM event listeners, and deletes the cache reference.
9554          * All DOM event listeners are removed from this element. If {@link Ext#enableNestedListenerRemoval Ext.enableNestedListenerRemoval} is
9555          * <code>true</code>, then DOM event listeners are also removed from all child nodes. The body node
9556          * will be ignored if passed in.</p>
9557          * @param {HTMLElement} node The node to remove
9558          * @method
9559          */
9560         removeNode : isIE6 || isIE7 ? function() {
9561             var d;
9562             return function(n){
9563                 if(n && n.tagName != 'BODY'){
9564                     (Ext.enableNestedListenerRemoval) ? Ext.EventManager.purgeElement(n) : Ext.EventManager.removeAll(n);
9565                     d = d || document.createElement('div');
9566                     d.appendChild(n);
9567                     d.innerHTML = '';
9568                     delete Ext.cache[n.id];
9569                 }
9570             };
9571         }() : function(n) {
9572             if (n && n.parentNode && n.tagName != 'BODY') {
9573                 (Ext.enableNestedListenerRemoval) ? Ext.EventManager.purgeElement(n) : Ext.EventManager.removeAll(n);
9574                 n.parentNode.removeChild(n);
9575                 delete Ext.cache[n.id];
9576             }
9577         },
9578
9579         isStrict: isStrict,
9580
9581         isIEQuirks: isIE && !isStrict,
9582
9583         /**
9584          * True if the detected browser is Opera.
9585          * @type Boolean
9586          */
9587         isOpera : isOpera,
9588
9589         /**
9590          * True if the detected browser is Opera 10.5x.
9591          * @type Boolean
9592          */
9593         isOpera10_5 : isOpera10_5,
9594
9595         /**
9596          * True if the detected browser uses WebKit.
9597          * @type Boolean
9598          */
9599         isWebKit : isWebKit,
9600
9601         /**
9602          * True if the detected browser is Chrome.
9603          * @type Boolean
9604          */
9605         isChrome : isChrome,
9606
9607         /**
9608          * True if the detected browser is Safari.
9609          * @type Boolean
9610          */
9611         isSafari : isSafari,
9612
9613         /**
9614          * True if the detected browser is Safari 3.x.
9615          * @type Boolean
9616          */
9617         isSafari3 : isSafari3,
9618
9619         /**
9620          * True if the detected browser is Safari 4.x.
9621          * @type Boolean
9622          */
9623         isSafari4 : isSafari4,
9624
9625         /**
9626          * True if the detected browser is Safari 5.x.
9627          * @type Boolean
9628          */
9629         isSafari5 : isSafari5,
9630
9631         /**
9632          * True if the detected browser is Safari 2.x.
9633          * @type Boolean
9634          */
9635         isSafari2 : isSafari2,
9636
9637         /**
9638          * True if the detected browser is Internet Explorer.
9639          * @type Boolean
9640          */
9641         isIE : isIE,
9642
9643         /**
9644          * True if the detected browser is Internet Explorer 6.x.
9645          * @type Boolean
9646          */
9647         isIE6 : isIE6,
9648
9649         /**
9650          * True if the detected browser is Internet Explorer 7.x.
9651          * @type Boolean
9652          */
9653         isIE7 : isIE7,
9654
9655         /**
9656          * True if the detected browser is Internet Explorer 8.x.
9657          * @type Boolean
9658          */
9659         isIE8 : isIE8,
9660
9661         /**
9662          * True if the detected browser is Internet Explorer 9.x.
9663          * @type Boolean
9664          */
9665         isIE9 : isIE9,
9666
9667         /**
9668          * True if the detected browser uses the Gecko layout engine (e.g. Mozilla, Firefox).
9669          * @type Boolean
9670          */
9671         isGecko : isGecko,
9672
9673         /**
9674          * True if the detected browser uses a Gecko 1.9+ layout engine (e.g. Firefox 3.x).
9675          * @type Boolean
9676          */
9677         isGecko3 : isGecko3,
9678
9679         /**
9680          * True if the detected browser uses a Gecko 2.0+ layout engine (e.g. Firefox 4.x).
9681          * @type Boolean
9682          */
9683         isGecko4 : isGecko4,
9684
9685         /**
9686          * True if the detected browser uses a Gecko 5.0+ layout engine (e.g. Firefox 5.x).
9687          * @type Boolean
9688          */
9689         isGecko5 : isGecko5,
9690
9691         /**
9692          * True if the detected browser uses FireFox 3.0
9693          * @type Boolean
9694          */
9695         isFF3_0 : isFF3_0,
9696
9697         /**
9698          * True if the detected browser uses FireFox 3.5
9699          * @type Boolean
9700          */
9701         isFF3_5 : isFF3_5,
9702
9703         /**
9704          * True if the detected browser uses FireFox 3.6
9705          * @type Boolean
9706          */
9707         isFF3_6 : isFF3_6,
9708
9709         /**
9710          * True if the detected browser uses FireFox 4
9711          * @type Boolean
9712          */
9713         isFF4 : 4 <= firefoxVersion && firefoxVersion < 5,
9714
9715         /**
9716          * True if the detected browser uses FireFox 5
9717          * @type Boolean
9718          */
9719         isFF5 : 5 <= firefoxVersion && firefoxVersion < 6,
9720
9721         /**
9722          * True if the detected platform is Linux.
9723          * @type Boolean
9724          */
9725         isLinux : isLinux,
9726
9727         /**
9728          * True if the detected platform is Windows.
9729          * @type Boolean
9730          */
9731         isWindows : isWindows,
9732
9733         /**
9734          * True if the detected platform is Mac OS.
9735          * @type Boolean
9736          */
9737         isMac : isMac,
9738
9739         /**
9740          * The current version of Chrome (0 if the browser is not Chrome).
9741          * @type Number
9742          */
9743         chromeVersion: chromeVersion,
9744
9745         /**
9746          * The current version of Firefox (0 if the browser is not Firefox).
9747          * @type Number
9748          */
9749         firefoxVersion: firefoxVersion,
9750
9751         /**
9752          * The current version of IE (0 if the browser is not IE). This does not account
9753          * for the documentMode of the current page, which is factored into {@link #isIE7},
9754          * {@link #isIE8} and {@link #isIE9}. Thus this is not always true:
9755          *
9756          *      Ext.isIE8 == (Ext.ieVersion == 8)
9757          *
9758          * @type Number
9759          * @markdown
9760          */
9761         ieVersion: ieVersion,
9762
9763         /**
9764          * The current version of Opera (0 if the browser is not Opera).
9765          * @type Number
9766          */
9767         operaVersion: operaVersion,
9768
9769         /**
9770          * The current version of Safari (0 if the browser is not Safari).
9771          * @type Number
9772          */
9773         safariVersion: safariVersion,
9774
9775         /**
9776          * The current version of WebKit (0 if the browser does not use WebKit).
9777          * @type Number
9778          */
9779         webKitVersion: webKitVersion,
9780
9781         /**
9782          * True if the page is running over SSL
9783          * @type Boolean
9784          */
9785         isSecure: isSecure,
9786
9787         /**
9788          * URL to a 1x1 transparent gif image used by Ext to create inline icons with CSS background images.
9789          * In older versions of IE, this defaults to "http://sencha.com/s.gif" and you should change this to a URL on your server.
9790          * For other browsers it uses an inline data URL.
9791          * @type String
9792          */
9793         BLANK_IMAGE_URL : (isIE6 || isIE7) ? '/' + '/www.sencha.com/s.gif' : 'data:image/gif;base64,R0lGODlhAQABAID/AMDAwAAAACH5BAEAAAAALAAAAAABAAEAAAICRAEAOw==',
9794
9795         /**
9796          * <p>Utility method for returning a default value if the passed value is empty.</p>
9797          * <p>The value is deemed to be empty if it is<div class="mdetail-params"><ul>
9798          * <li>null</li>
9799          * <li>undefined</li>
9800          * <li>an empty array</li>
9801          * <li>a zero length string (Unless the <tt>allowBlank</tt> parameter is <tt>true</tt>)</li>
9802          * </ul></div>
9803          * @param {Object} value The value to test
9804          * @param {Object} defaultValue The value to return if the original value is empty
9805          * @param {Boolean} allowBlank (optional) true to allow zero length strings to qualify as non-empty (defaults to false)
9806          * @return {Object} value, if non-empty, else defaultValue
9807          * @deprecated 4.0.0 Use {@link Ext#valueFrom} instead
9808          */
9809         value : function(v, defaultValue, allowBlank){
9810             return Ext.isEmpty(v, allowBlank) ? defaultValue : v;
9811         },
9812
9813         /**
9814          * Escapes the passed string for use in a regular expression
9815          * @param {String} str
9816          * @return {String}
9817          * @deprecated 4.0.0 Use {@link Ext.String#escapeRegex} instead
9818          */
9819         escapeRe : function(s) {
9820             return s.replace(/([-.*+?^${}()|[\]\/\\])/g, "\\$1");
9821         },
9822
9823         /**
9824          * Applies event listeners to elements by selectors when the document is ready.
9825          * The event name is specified with an <tt>&#64;</tt> suffix.
9826          * <pre><code>
9827 Ext.addBehaviors({
9828     // add a listener for click on all anchors in element with id foo
9829     '#foo a&#64;click' : function(e, t){
9830         // do something
9831     },
9832
9833     // add the same listener to multiple selectors (separated by comma BEFORE the &#64;)
9834     '#foo a, #bar span.some-class&#64;mouseover' : function(){
9835         // do something
9836     }
9837 });
9838          * </code></pre>
9839          * @param {Object} obj The list of behaviors to apply
9840          */
9841         addBehaviors : function(o){
9842             if(!Ext.isReady){
9843                 Ext.onReady(function(){
9844                     Ext.addBehaviors(o);
9845                 });
9846             } else {
9847                 var cache = {}, // simple cache for applying multiple behaviors to same selector does query multiple times
9848                     parts,
9849                     b,
9850                     s;
9851                 for (b in o) {
9852                     if ((parts = b.split('@'))[1]) { // for Object prototype breakers
9853                         s = parts[0];
9854                         if(!cache[s]){
9855                             cache[s] = Ext.select(s);
9856                         }
9857                         cache[s].on(parts[1], o[b]);
9858                     }
9859                 }
9860                 cache = null;
9861             }
9862         },
9863
9864         /**
9865          * Returns the size of the browser scrollbars. This can differ depending on
9866          * operating system settings, such as the theme or font size.
9867          * @param {Boolean} force (optional) true to force a recalculation of the value.
9868          * @return {Object} An object containing the width of a vertical scrollbar and the
9869          * height of a horizontal scrollbar.
9870          */
9871         getScrollbarSize: function (force) {
9872             if(!Ext.isReady){
9873                 return 0;
9874             }
9875
9876             if(force === true || scrollbarSize === null){
9877                 // BrowserBug: IE9
9878                 // When IE9 positions an element offscreen via offsets, the offsetWidth is
9879                 // inaccurately reported. For IE9 only, we render on screen before removing.
9880                 var cssClass = Ext.isIE9 ? '' : Ext.baseCSSPrefix + 'hide-offsets',
9881                     // Append our div, do our calculation and then remove it
9882                     div = Ext.getBody().createChild('<div class="' + cssClass + '" style="width:100px;height:50px;overflow:hidden;"><div style="height:200px;"></div></div>'),
9883                     child = div.child('div', true),
9884                     w1 = child.offsetWidth;
9885
9886                 div.setStyle('overflow', (Ext.isWebKit || Ext.isGecko) ? 'auto' : 'scroll');
9887
9888                 var w2 = child.offsetWidth, width = w1 - w2;
9889                 div.remove();
9890
9891                 // We assume width == height for now. TODO: is this always true?
9892                 scrollbarSize = { width: width, height: width };
9893             }
9894
9895             return scrollbarSize;
9896         },
9897
9898         /**
9899          * Utility method for getting the width of the browser's vertical scrollbar. This
9900          * can differ depending on operating system settings, such as the theme or font size.
9901          *
9902          * This method is deprected in favor of {@link #getScrollbarSize}.
9903          *
9904          * @param {Boolean} force (optional) true to force a recalculation of the value.
9905          * @return {Number} The width of a vertical scrollbar.
9906          * @deprecated
9907          */
9908         getScrollBarWidth: function(force){
9909             var size = Ext.getScrollbarSize(force);
9910             return size.width + 2; // legacy fudge factor
9911         },
9912
9913         /**
9914          * Copies a set of named properties fom the source object to the destination object.
9915          *
9916          * Example:
9917          *
9918          *     ImageComponent = Ext.extend(Ext.Component, {
9919          *         initComponent: function() {
9920          *             this.autoEl = { tag: 'img' };
9921          *             MyComponent.superclass.initComponent.apply(this, arguments);
9922          *             this.initialBox = Ext.copyTo({}, this.initialConfig, 'x,y,width,height');
9923          *         }
9924          *     });
9925          *
9926          * Important note: To borrow class prototype methods, use {@link Ext.Base#borrow} instead.
9927          *
9928          * @param {Object} dest The destination object.
9929          * @param {Object} source The source object.
9930          * @param {String/String[]} names Either an Array of property names, or a comma-delimited list
9931          * of property names to copy.
9932          * @param {Boolean} usePrototypeKeys (Optional) Defaults to false. Pass true to copy keys off of the prototype as well as the instance.
9933          * @return {Object} The modified object.
9934          */
9935         copyTo : function(dest, source, names, usePrototypeKeys){
9936             if(typeof names == 'string'){
9937                 names = names.split(/[,;\s]/);
9938             }
9939             Ext.each(names, function(name){
9940                 if(usePrototypeKeys || source.hasOwnProperty(name)){
9941                     dest[name] = source[name];
9942                 }
9943             }, this);
9944             return dest;
9945         },
9946
9947         /**
9948          * Attempts to destroy and then remove a set of named properties of the passed object.
9949          * @param {Object} o The object (most likely a Component) who's properties you wish to destroy.
9950          * @param {String...} args One or more names of the properties to destroy and remove from the object.
9951          */
9952         destroyMembers : function(o){
9953             for (var i = 1, a = arguments, len = a.length; i < len; i++) {
9954                 Ext.destroy(o[a[i]]);
9955                 delete o[a[i]];
9956             }
9957         },
9958
9959         /**
9960          * Logs a message. If a console is present it will be used. On Opera, the method
9961          * "opera.postError" is called. In other cases, the message is logged to an array
9962          * "Ext.log.out". An attached debugger can watch this array and view the log. The
9963          * log buffer is limited to a maximum of "Ext.log.max" entries (defaults to 250).
9964          * The `Ext.log.out` array can also be written to a popup window by entering the
9965          * following in the URL bar (a "bookmarklet"):
9966          *
9967          *    javascript:void(Ext.log.show());
9968          *
9969          * If additional parameters are passed, they are joined and appended to the message.
9970          * A technique for tracing entry and exit of a function is this:
9971          *
9972          *      function foo () {
9973          *          Ext.log({ indent: 1 }, '>> foo');
9974          *
9975          *          // log statements in here or methods called from here will be indented
9976          *          // by one step
9977          *
9978          *          Ext.log({ outdent: 1 }, '<< foo');
9979          *      }
9980          *
9981          * This method does nothing in a release build.
9982          *
9983          * @param {String/Object} message The message to log or an options object with any
9984          * of the following properties:
9985          *
9986          *  - `msg`: The message to log (required).
9987          *  - `level`: One of: "error", "warn", "info" or "log" (the default is "log").
9988          *  - `dump`: An object to dump to the log as part of the message.
9989          *  - `stack`: True to include a stack trace in the log.
9990          *  - `indent`: Cause subsequent log statements to be indented one step.
9991          *  - `outdent`: Cause this and following statements to be one step less indented.
9992          * @markdown
9993          */
9994         log :
9995             log ||
9996             Ext.emptyFn,
9997
9998         /**
9999          * Partitions the set into two sets: a true set and a false set.
10000          * Example:
10001          * Example2:
10002          * <pre><code>
10003 // Example 1:
10004 Ext.partition([true, false, true, true, false]); // [[true, true, true], [false, false]]
10005
10006 // Example 2:
10007 Ext.partition(
10008     Ext.query("p"),
10009     function(val){
10010         return val.className == "class1"
10011     }
10012 );
10013 // true are those paragraph elements with a className of "class1",
10014 // false set are those that do not have that className.
10015          * </code></pre>
10016          * @param {Array/NodeList} arr The array to partition
10017          * @param {Function} truth (optional) a function to determine truth.  If this is omitted the element
10018          * itself must be able to be evaluated for its truthfulness.
10019          * @return {Array} [array of truish values, array of falsy values]
10020          * @deprecated 4.0.0 Will be removed in the next major version
10021          */
10022         partition : function(arr, truth){
10023             var ret = [[],[]];
10024             Ext.each(arr, function(v, i, a) {
10025                 ret[ (truth && truth(v, i, a)) || (!truth && v) ? 0 : 1].push(v);
10026             });
10027             return ret;
10028         },
10029
10030         /**
10031          * Invokes a method on each item in an Array.
10032          * <pre><code>
10033 // Example:
10034 Ext.invoke(Ext.query("p"), "getAttribute", "id");
10035 // [el1.getAttribute("id"), el2.getAttribute("id"), ..., elN.getAttribute("id")]
10036          * </code></pre>
10037          * @param {Array/NodeList} arr The Array of items to invoke the method on.
10038          * @param {String} methodName The method name to invoke.
10039          * @param {Object...} args Arguments to send into the method invocation.
10040          * @return {Array} The results of invoking the method on each item in the array.
10041          * @deprecated 4.0.0 Will be removed in the next major version
10042          */
10043         invoke : function(arr, methodName){
10044             var ret = [],
10045                 args = Array.prototype.slice.call(arguments, 2);
10046             Ext.each(arr, function(v,i) {
10047                 if (v && typeof v[methodName] == 'function') {
10048                     ret.push(v[methodName].apply(v, args));
10049                 } else {
10050                     ret.push(undefined);
10051                 }
10052             });
10053             return ret;
10054         },
10055
10056         /**
10057          * <p>Zips N sets together.</p>
10058          * <pre><code>
10059 // Example 1:
10060 Ext.zip([1,2,3],[4,5,6]); // [[1,4],[2,5],[3,6]]
10061 // Example 2:
10062 Ext.zip(
10063     [ "+", "-", "+"],
10064     [  12,  10,  22],
10065     [  43,  15,  96],
10066     function(a, b, c){
10067         return "$" + a + "" + b + "." + c
10068     }
10069 ); // ["$+12.43", "$-10.15", "$+22.96"]
10070          * </code></pre>
10071          * @param {Array/NodeList...} arr This argument may be repeated. Array(s) to contribute values.
10072          * @param {Function} zipper (optional) The last item in the argument list. This will drive how the items are zipped together.
10073          * @return {Array} The zipped set.
10074          * @deprecated 4.0.0 Will be removed in the next major version
10075          */
10076         zip : function(){
10077             var parts = Ext.partition(arguments, function( val ){ return typeof val != 'function'; }),
10078                 arrs = parts[0],
10079                 fn = parts[1][0],
10080                 len = Ext.max(Ext.pluck(arrs, "length")),
10081                 ret = [];
10082
10083             for (var i = 0; i < len; i++) {
10084                 ret[i] = [];
10085                 if(fn){
10086                     ret[i] = fn.apply(fn, Ext.pluck(arrs, i));
10087                 }else{
10088                     for (var j = 0, aLen = arrs.length; j < aLen; j++){
10089                         ret[i].push( arrs[j][i] );
10090                     }
10091                 }
10092             }
10093             return ret;
10094         },
10095
10096         /**
10097          * Turns an array into a sentence, joined by a specified connector - e.g.:
10098          * Ext.toSentence(['Adama', 'Tigh', 'Roslin']); //'Adama, Tigh and Roslin'
10099          * Ext.toSentence(['Adama', 'Tigh', 'Roslin'], 'or'); //'Adama, Tigh or Roslin'
10100          * @param {String[]} items The array to create a sentence from
10101          * @param {String} connector The string to use to connect the last two words. Usually 'and' or 'or' - defaults to 'and'.
10102          * @return {String} The sentence string
10103          * @deprecated 4.0.0 Will be removed in the next major version
10104          */
10105         toSentence: function(items, connector) {
10106             var length = items.length;
10107
10108             if (length <= 1) {
10109                 return items[0];
10110             } else {
10111                 var head = items.slice(0, length - 1),
10112                     tail = items[length - 1];
10113
10114                 return Ext.util.Format.format("{0} {1} {2}", head.join(", "), connector || 'and', tail);
10115             }
10116         },
10117
10118         /**
10119          * By default, Ext intelligently decides whether floating elements should be shimmed. If you are using flash,
10120          * you may want to set this to true.
10121          * @type Boolean
10122          */
10123         useShims: isIE6
10124     });
10125 })();
10126
10127 /**
10128  * Loads Ext.app.Application class and starts it up with given configuration after the page is ready.
10129  *
10130  * See Ext.app.Application for details.
10131  *
10132  * @param {Object} config
10133  */
10134 Ext.application = function(config) {
10135     Ext.require('Ext.app.Application');
10136
10137     Ext.onReady(function() {
10138         Ext.create('Ext.app.Application', config);
10139     });
10140 };
10141
10142 /**
10143  * @class Ext.util.Format
10144
10145 This class is a centralized place for formatting functions. It includes
10146 functions to format various different types of data, such as text, dates and numeric values.
10147
10148 __Localization__
10149 This class contains several options for localization. These can be set once the library has loaded,
10150 all calls to the functions from that point will use the locale settings that were specified.
10151 Options include:
10152 - thousandSeparator
10153 - decimalSeparator
10154 - currenyPrecision
10155 - currencySign
10156 - currencyAtEnd
10157 This class also uses the default date format defined here: {@link Ext.Date#defaultFormat}.
10158
10159 __Using with renderers__
10160 There are two helper functions that return a new function that can be used in conjunction with
10161 grid renderers:
10162
10163     columns: [{
10164         dataIndex: 'date',
10165         renderer: Ext.util.Format.dateRenderer('Y-m-d')
10166     }, {
10167         dataIndex: 'time',
10168         renderer: Ext.util.Format.numberRenderer('0.000')
10169     }]
10170
10171 Functions that only take a single argument can also be passed directly:
10172     columns: [{
10173         dataIndex: 'cost',
10174         renderer: Ext.util.Format.usMoney
10175     }, {
10176         dataIndex: 'productCode',
10177         renderer: Ext.util.Format.uppercase
10178     }]
10179
10180 __Using with XTemplates__
10181 XTemplates can also directly use Ext.util.Format functions:
10182
10183     new Ext.XTemplate([
10184         'Date: {startDate:date("Y-m-d")}',
10185         'Cost: {cost:usMoney}'
10186     ]);
10187
10188  * @markdown
10189  * @singleton
10190  */
10191 (function() {
10192     Ext.ns('Ext.util');
10193
10194     Ext.util.Format = {};
10195     var UtilFormat     = Ext.util.Format,
10196         stripTagsRE    = /<\/?[^>]+>/gi,
10197         stripScriptsRe = /(?:<script.*?>)((\n|\r|.)*?)(?:<\/script>)/ig,
10198         nl2brRe        = /\r?\n/g,
10199
10200         // A RegExp to remove from a number format string, all characters except digits and '.'
10201         formatCleanRe  = /[^\d\.]/g,
10202
10203         // A RegExp to remove from a number format string, all characters except digits and the local decimal separator.
10204         // Created on first use. The local decimal separator character must be initialized for this to be created.
10205         I18NFormatCleanRe;
10206
10207     Ext.apply(UtilFormat, {
10208         /**
10209          * @property {String} thousandSeparator
10210          * <p>The character that the {@link #number} function uses as a thousand separator.</p>
10211          * <p>This may be overridden in a locale file.</p>
10212          */
10213         thousandSeparator: ',',
10214
10215         /**
10216          * @property {String} decimalSeparator
10217          * <p>The character that the {@link #number} function uses as a decimal point.</p>
10218          * <p>This may be overridden in a locale file.</p>
10219          */
10220         decimalSeparator: '.',
10221
10222         /**
10223          * @property {Number} currencyPrecision
10224          * <p>The number of decimal places that the {@link #currency} function displays.</p>
10225          * <p>This may be overridden in a locale file.</p>
10226          */
10227         currencyPrecision: 2,
10228
10229         /**
10230          * @property {String} currencySign
10231          * <p>The currency sign that the {@link #currency} function displays.</p>
10232          * <p>This may be overridden in a locale file.</p>
10233          */
10234         currencySign: '$',
10235
10236         /**
10237          * @property {Boolean} currencyAtEnd
10238          * <p>This may be set to <code>true</code> to make the {@link #currency} function
10239          * append the currency sign to the formatted value.</p>
10240          * <p>This may be overridden in a locale file.</p>
10241          */
10242         currencyAtEnd: false,
10243
10244         /**
10245          * Checks a reference and converts it to empty string if it is undefined
10246          * @param {Object} value Reference to check
10247          * @return {Object} Empty string if converted, otherwise the original value
10248          */
10249         undef : function(value) {
10250             return value !== undefined ? value : "";
10251         },
10252
10253         /**
10254          * Checks a reference and converts it to the default value if it's empty
10255          * @param {Object} value Reference to check
10256          * @param {String} defaultValue The value to insert of it's undefined (defaults to "")
10257          * @return {String}
10258          */
10259         defaultValue : function(value, defaultValue) {
10260             return value !== undefined && value !== '' ? value : defaultValue;
10261         },
10262
10263         /**
10264          * Returns a substring from within an original string
10265          * @param {String} value The original text
10266          * @param {Number} start The start index of the substring
10267          * @param {Number} length The length of the substring
10268          * @return {String} The substring
10269          */
10270         substr : function(value, start, length) {
10271             return String(value).substr(start, length);
10272         },
10273
10274         /**
10275          * Converts a string to all lower case letters
10276          * @param {String} value The text to convert
10277          * @return {String} The converted text
10278          */
10279         lowercase : function(value) {
10280             return String(value).toLowerCase();
10281         },
10282
10283         /**
10284          * Converts a string to all upper case letters
10285          * @param {String} value The text to convert
10286          * @return {String} The converted text
10287          */
10288         uppercase : function(value) {
10289             return String(value).toUpperCase();
10290         },
10291
10292         /**
10293          * Format a number as US currency
10294          * @param {Number/String} value The numeric value to format
10295          * @return {String} The formatted currency string
10296          */
10297         usMoney : function(v) {
10298             return UtilFormat.currency(v, '$', 2);
10299         },
10300
10301         /**
10302          * Format a number as a currency
10303          * @param {Number/String} value The numeric value to format
10304          * @param {String} sign The currency sign to use (defaults to {@link #currencySign})
10305          * @param {Number} decimals The number of decimals to use for the currency (defaults to {@link #currencyPrecision})
10306          * @param {Boolean} end True if the currency sign should be at the end of the string (defaults to {@link #currencyAtEnd})
10307          * @return {String} The formatted currency string
10308          */
10309         currency: function(v, currencySign, decimals, end) {
10310             var negativeSign = '',
10311                 format = ",0",
10312                 i = 0;
10313             v = v - 0;
10314             if (v < 0) {
10315                 v = -v;
10316                 negativeSign = '-';
10317             }
10318             decimals = decimals || UtilFormat.currencyPrecision;
10319             format += format + (decimals > 0 ? '.' : '');
10320             for (; i < decimals; i++) {
10321                 format += '0';
10322             }
10323             v = UtilFormat.number(v, format);
10324             if ((end || UtilFormat.currencyAtEnd) === true) {
10325                 return Ext.String.format("{0}{1}{2}", negativeSign, v, currencySign || UtilFormat.currencySign);
10326             } else {
10327                 return Ext.String.format("{0}{1}{2}", negativeSign, currencySign || UtilFormat.currencySign, v);
10328             }
10329         },
10330
10331         /**
10332          * Formats the passed date using the specified format pattern.
10333          * @param {String/Date} value The value to format. If a string is passed, it is converted to a Date by the Javascript
10334          * Date object's <a href="http://www.w3schools.com/jsref/jsref_parse.asp">parse()</a> method.
10335          * @param {String} format (Optional) Any valid date format string. Defaults to {@link Ext.Date#defaultFormat}.
10336          * @return {String} The formatted date string.
10337          */
10338         date: function(v, format) {
10339             if (!v) {
10340                 return "";
10341             }
10342             if (!Ext.isDate(v)) {
10343                 v = new Date(Date.parse(v));
10344             }
10345             return Ext.Date.dateFormat(v, format || Ext.Date.defaultFormat);
10346         },
10347
10348         /**
10349          * Returns a date rendering function that can be reused to apply a date format multiple times efficiently
10350          * @param {String} format Any valid date format string. Defaults to {@link Ext.Date#defaultFormat}.
10351          * @return {Function} The date formatting function
10352          */
10353         dateRenderer : function(format) {
10354             return function(v) {
10355                 return UtilFormat.date(v, format);
10356             };
10357         },
10358
10359         /**
10360          * Strips all HTML tags
10361          * @param {Object} value The text from which to strip tags
10362          * @return {String} The stripped text
10363          */
10364         stripTags : function(v) {
10365             return !v ? v : String(v).replace(stripTagsRE, "");
10366         },
10367
10368         /**
10369          * Strips all script tags
10370          * @param {Object} value The text from which to strip script tags
10371          * @return {String} The stripped text
10372          */
10373         stripScripts : function(v) {
10374             return !v ? v : String(v).replace(stripScriptsRe, "");
10375         },
10376
10377         /**
10378          * Simple format for a file size (xxx bytes, xxx KB, xxx MB)
10379          * @param {Number/String} size The numeric value to format
10380          * @return {String} The formatted file size
10381          */
10382         fileSize : function(size) {
10383             if (size < 1024) {
10384                 return size + " bytes";
10385             } else if (size < 1048576) {
10386                 return (Math.round(((size*10) / 1024))/10) + " KB";
10387             } else {
10388                 return (Math.round(((size*10) / 1048576))/10) + " MB";
10389             }
10390         },
10391
10392         /**
10393          * It does simple math for use in a template, for example:<pre><code>
10394          * var tpl = new Ext.Template('{value} * 10 = {value:math("* 10")}');
10395          * </code></pre>
10396          * @return {Function} A function that operates on the passed value.
10397          * @method
10398          */
10399         math : function(){
10400             var fns = {};
10401
10402             return function(v, a){
10403                 if (!fns[a]) {
10404                     fns[a] = Ext.functionFactory('v', 'return v ' + a + ';');
10405                 }
10406                 return fns[a](v);
10407             };
10408         }(),
10409
10410         /**
10411          * Rounds the passed number to the required decimal precision.
10412          * @param {Number/String} value The numeric value to round.
10413          * @param {Number} precision The number of decimal places to which to round the first parameter's value.
10414          * @return {Number} The rounded value.
10415          */
10416         round : function(value, precision) {
10417             var result = Number(value);
10418             if (typeof precision == 'number') {
10419                 precision = Math.pow(10, precision);
10420                 result = Math.round(value * precision) / precision;
10421             }
10422             return result;
10423         },
10424
10425         /**
10426          * <p>Formats the passed number according to the passed format string.</p>
10427          * <p>The number of digits after the decimal separator character specifies the number of
10428          * decimal places in the resulting string. The <u>local-specific</u> decimal character is used in the result.</p>
10429          * <p>The <i>presence</i> of a thousand separator character in the format string specifies that
10430          * the <u>locale-specific</u> thousand separator (if any) is inserted separating thousand groups.</p>
10431          * <p>By default, "," is expected as the thousand separator, and "." is expected as the decimal separator.</p>
10432          * <p><b>New to Ext JS 4</b></p>
10433          * <p>Locale-specific characters are always used in the formatted output when inserting
10434          * thousand and decimal separators.</p>
10435          * <p>The format string must specify separator characters according to US/UK conventions ("," as the
10436          * thousand separator, and "." as the decimal separator)</p>
10437          * <p>To allow specification of format strings according to local conventions for separator characters, add
10438          * the string <code>/i</code> to the end of the format string.</p>
10439          * <div style="margin-left:40px">examples (123456.789):
10440          * <div style="margin-left:10px">
10441          * 0 - (123456) show only digits, no precision<br>
10442          * 0.00 - (123456.78) show only digits, 2 precision<br>
10443          * 0.0000 - (123456.7890) show only digits, 4 precision<br>
10444          * 0,000 - (123,456) show comma and digits, no precision<br>
10445          * 0,000.00 - (123,456.78) show comma and digits, 2 precision<br>
10446          * 0,0.00 - (123,456.78) shortcut method, show comma and digits, 2 precision<br>
10447          * To allow specification of the formatting string using UK/US grouping characters (,) and decimal (.) for international numbers, add /i to the end.
10448          * For example: 0.000,00/i
10449          * </div></div>
10450          * @param {Number} v The number to format.
10451          * @param {String} format The way you would like to format this text.
10452          * @return {String} The formatted number.
10453          */
10454         number: function(v, formatString) {
10455             if (!formatString) {
10456                 return v;
10457             }
10458             v = Ext.Number.from(v, NaN);
10459             if (isNaN(v)) {
10460                 return '';
10461             }
10462             var comma = UtilFormat.thousandSeparator,
10463                 dec   = UtilFormat.decimalSeparator,
10464                 i18n  = false,
10465                 neg   = v < 0,
10466                 hasComma,
10467                 psplit;
10468
10469             v = Math.abs(v);
10470
10471             // The "/i" suffix allows caller to use a locale-specific formatting string.
10472             // Clean the format string by removing all but numerals and the decimal separator.
10473             // Then split the format string into pre and post decimal segments according to *what* the
10474             // decimal separator is. If they are specifying "/i", they are using the local convention in the format string.
10475             if (formatString.substr(formatString.length - 2) == '/i') {
10476                 if (!I18NFormatCleanRe) {
10477                     I18NFormatCleanRe = new RegExp('[^\\d\\' + UtilFormat.decimalSeparator + ']','g');
10478                 }
10479                 formatString = formatString.substr(0, formatString.length - 2);
10480                 i18n   = true;
10481                 hasComma = formatString.indexOf(comma) != -1;
10482                 psplit = formatString.replace(I18NFormatCleanRe, '').split(dec);
10483             } else {
10484                 hasComma = formatString.indexOf(',') != -1;
10485                 psplit = formatString.replace(formatCleanRe, '').split('.');
10486             }
10487
10488             if (1 < psplit.length) {
10489                 v = v.toFixed(psplit[1].length);
10490             } else if(2 < psplit.length) {
10491                 Ext.Error.raise({
10492                     sourceClass: "Ext.util.Format",
10493                     sourceMethod: "number",
10494                     value: v,
10495                     formatString: formatString,
10496                     msg: "Invalid number format, should have no more than 1 decimal"
10497                 });
10498             } else {
10499                 v = v.toFixed(0);
10500             }
10501
10502             var fnum = v.toString();
10503
10504             psplit = fnum.split('.');
10505
10506             if (hasComma) {
10507                 var cnum = psplit[0],
10508                     parr = [],
10509                     j    = cnum.length,
10510                     m    = Math.floor(j / 3),
10511                     n    = cnum.length % 3 || 3,
10512                     i;
10513
10514                 for (i = 0; i < j; i += n) {
10515                     if (i !== 0) {
10516                         n = 3;
10517                     }
10518
10519                     parr[parr.length] = cnum.substr(i, n);
10520                     m -= 1;
10521                 }
10522                 fnum = parr.join(comma);
10523                 if (psplit[1]) {
10524                     fnum += dec + psplit[1];
10525                 }
10526             } else {
10527                 if (psplit[1]) {
10528                     fnum = psplit[0] + dec + psplit[1];
10529                 }
10530             }
10531
10532             if (neg) {
10533                 /*
10534                  * Edge case. If we have a very small negative number it will get rounded to 0,
10535                  * however the initial check at the top will still report as negative. Replace
10536                  * everything but 1-9 and check if the string is empty to determine a 0 value.
10537                  */
10538                 neg = fnum.replace(/[^1-9]/g, '') !== '';
10539             }
10540
10541             return (neg ? '-' : '') + formatString.replace(/[\d,?\.?]+/, fnum);
10542         },
10543
10544         /**
10545          * Returns a number rendering function that can be reused to apply a number format multiple times efficiently
10546          * @param {String} format Any valid number format string for {@link #number}
10547          * @return {Function} The number formatting function
10548          */
10549         numberRenderer : function(format) {
10550             return function(v) {
10551                 return UtilFormat.number(v, format);
10552             };
10553         },
10554
10555         /**
10556          * Selectively do a plural form of a word based on a numeric value. For example, in a template,
10557          * {commentCount:plural("Comment")}  would result in "1 Comment" if commentCount was 1 or would be "x Comments"
10558          * if the value is 0 or greater than 1.
10559          * @param {Number} value The value to compare against
10560          * @param {String} singular The singular form of the word
10561          * @param {String} plural (optional) The plural form of the word (defaults to the singular with an "s")
10562          */
10563         plural : function(v, s, p) {
10564             return v +' ' + (v == 1 ? s : (p ? p : s+'s'));
10565         },
10566
10567         /**
10568          * Converts newline characters to the HTML tag &lt;br/>
10569          * @param {String} The string value to format.
10570          * @return {String} The string with embedded &lt;br/> tags in place of newlines.
10571          */
10572         nl2br : function(v) {
10573             return Ext.isEmpty(v) ? '' : v.replace(nl2brRe, '<br/>');
10574         },
10575
10576         /**
10577          * Alias for {@link Ext.String#capitalize}.
10578          * @method
10579          * @alias Ext.String#capitalize
10580          */
10581         capitalize: Ext.String.capitalize,
10582
10583         /**
10584          * Alias for {@link Ext.String#ellipsis}.
10585          * @method
10586          * @alias Ext.String#ellipsis
10587          */
10588         ellipsis: Ext.String.ellipsis,
10589
10590         /**
10591          * Alias for {@link Ext.String#format}.
10592          * @method
10593          * @alias Ext.String#format
10594          */
10595         format: Ext.String.format,
10596
10597         /**
10598          * Alias for {@link Ext.String#htmlDecode}.
10599          * @method
10600          * @alias Ext.String#htmlDecode
10601          */
10602         htmlDecode: Ext.String.htmlDecode,
10603
10604         /**
10605          * Alias for {@link Ext.String#htmlEncode}.
10606          * @method
10607          * @alias Ext.String#htmlEncode
10608          */
10609         htmlEncode: Ext.String.htmlEncode,
10610
10611         /**
10612          * Alias for {@link Ext.String#leftPad}.
10613          * @method
10614          * @alias Ext.String#leftPad
10615          */
10616         leftPad: Ext.String.leftPad,
10617
10618         /**
10619          * Alias for {@link Ext.String#trim}.
10620          * @method
10621          * @alias Ext.String#trim
10622          */
10623         trim : Ext.String.trim,
10624
10625         /**
10626          * Parses a number or string representing margin sizes into an object. Supports CSS-style margin declarations
10627          * (e.g. 10, "10", "10 10", "10 10 10" and "10 10 10 10" are all valid options and would return the same result)
10628          * @param {Number/String} v The encoded margins
10629          * @return {Object} An object with margin sizes for top, right, bottom and left
10630          */
10631         parseBox : function(box) {
10632             if (Ext.isNumber(box)) {
10633                 box = box.toString();
10634             }
10635             var parts  = box.split(' '),
10636                 ln = parts.length;
10637
10638             if (ln == 1) {
10639                 parts[1] = parts[2] = parts[3] = parts[0];
10640             }
10641             else if (ln == 2) {
10642                 parts[2] = parts[0];
10643                 parts[3] = parts[1];
10644             }
10645             else if (ln == 3) {
10646                 parts[3] = parts[1];
10647             }
10648
10649             return {
10650                 top   :parseInt(parts[0], 10) || 0,
10651                 right :parseInt(parts[1], 10) || 0,
10652                 bottom:parseInt(parts[2], 10) || 0,
10653                 left  :parseInt(parts[3], 10) || 0
10654             };
10655         },
10656
10657         /**
10658          * Escapes the passed string for use in a regular expression
10659          * @param {String} str
10660          * @return {String}
10661          */
10662         escapeRegex : function(s) {
10663             return s.replace(/([\-.*+?\^${}()|\[\]\/\\])/g, "\\$1");
10664         }
10665     });
10666 })();
10667
10668 /**
10669  * @class Ext.util.TaskRunner
10670  * Provides the ability to execute one or more arbitrary tasks in a multithreaded
10671  * manner.  Generally, you can use the singleton {@link Ext.TaskManager} instead, but
10672  * if needed, you can create separate instances of TaskRunner.  Any number of
10673  * separate tasks can be started at any time and will run independently of each
10674  * other. Example usage:
10675  * <pre><code>
10676 // Start a simple clock task that updates a div once per second
10677 var updateClock = function(){
10678     Ext.fly('clock').update(new Date().format('g:i:s A'));
10679
10680 var task = {
10681     run: updateClock,
10682     interval: 1000 //1 second
10683 }
10684 var runner = new Ext.util.TaskRunner();
10685 runner.start(task);
10686
10687 // equivalent using TaskManager
10688 Ext.TaskManager.start({
10689     run: updateClock,
10690     interval: 1000
10691 });
10692
10693  * </code></pre>
10694  * <p>See the {@link #start} method for details about how to configure a task object.</p>
10695  * Also see {@link Ext.util.DelayedTask}. 
10696  * 
10697  * @constructor
10698  * @param {Number} [interval=10] The minimum precision in milliseconds supported by this TaskRunner instance
10699  */
10700 Ext.ns('Ext.util');
10701
10702 Ext.util.TaskRunner = function(interval) {
10703     interval = interval || 10;
10704     var tasks = [],
10705     removeQueue = [],
10706     id = 0,
10707     running = false,
10708
10709     // private
10710     stopThread = function() {
10711         running = false;
10712         clearInterval(id);
10713         id = 0;
10714     },
10715
10716     // private
10717     startThread = function() {
10718         if (!running) {
10719             running = true;
10720             id = setInterval(runTasks, interval);
10721         }
10722     },
10723
10724     // private
10725     removeTask = function(t) {
10726         removeQueue.push(t);
10727         if (t.onStop) {
10728             t.onStop.apply(t.scope || t);
10729         }
10730     },
10731
10732     // private
10733     runTasks = function() {
10734         var rqLen = removeQueue.length,
10735             now = new Date().getTime(),
10736             i;
10737
10738         if (rqLen > 0) {
10739             for (i = 0; i < rqLen; i++) {
10740                 Ext.Array.remove(tasks, removeQueue[i]);
10741             }
10742             removeQueue = [];
10743             if (tasks.length < 1) {
10744                 stopThread();
10745                 return;
10746             }
10747         }
10748         i = 0;
10749         var t,
10750             itime,
10751             rt,
10752             len = tasks.length;
10753         for (; i < len; ++i) {
10754             t = tasks[i];
10755             itime = now - t.taskRunTime;
10756             if (t.interval <= itime) {
10757                 rt = t.run.apply(t.scope || t, t.args || [++t.taskRunCount]);
10758                 t.taskRunTime = now;
10759                 if (rt === false || t.taskRunCount === t.repeat) {
10760                     removeTask(t);
10761                     return;
10762                 }
10763             }
10764             if (t.duration && t.duration <= (now - t.taskStartTime)) {
10765                 removeTask(t);
10766             }
10767         }
10768     };
10769
10770     /**
10771      * Starts a new task.
10772      * @method start
10773      * @param {Object} task <p>A config object that supports the following properties:<ul>
10774      * <li><code>run</code> : Function<div class="sub-desc"><p>The function to execute each time the task is invoked. The
10775      * function will be called at each interval and passed the <code>args</code> argument if specified, and the
10776      * current invocation count if not.</p>
10777      * <p>If a particular scope (<code>this</code> reference) is required, be sure to specify it using the <code>scope</code> argument.</p>
10778      * <p>Return <code>false</code> from this function to terminate the task.</p></div></li>
10779      * <li><code>interval</code> : Number<div class="sub-desc">The frequency in milliseconds with which the task
10780      * should be invoked.</div></li>
10781      * <li><code>args</code> : Array<div class="sub-desc">(optional) An array of arguments to be passed to the function
10782      * specified by <code>run</code>. If not specified, the current invocation count is passed.</div></li>
10783      * <li><code>scope</code> : Object<div class="sub-desc">(optional) The scope (<tt>this</tt> reference) in which to execute the
10784      * <code>run</code> function. Defaults to the task config object.</div></li>
10785      * <li><code>duration</code> : Number<div class="sub-desc">(optional) The length of time in milliseconds to invoke
10786      * the task before stopping automatically (defaults to indefinite).</div></li>
10787      * <li><code>repeat</code> : Number<div class="sub-desc">(optional) The number of times to invoke the task before
10788      * stopping automatically (defaults to indefinite).</div></li>
10789      * </ul></p>
10790      * <p>Before each invocation, Ext injects the property <code>taskRunCount</code> into the task object so
10791      * that calculations based on the repeat count can be performed.</p>
10792      * @return {Object} The task
10793      */
10794     this.start = function(task) {
10795         tasks.push(task);
10796         task.taskStartTime = new Date().getTime();
10797         task.taskRunTime = 0;
10798         task.taskRunCount = 0;
10799         startThread();
10800         return task;
10801     };
10802
10803     /**
10804      * Stops an existing running task.
10805      * @method stop
10806      * @param {Object} task The task to stop
10807      * @return {Object} The task
10808      */
10809     this.stop = function(task) {
10810         removeTask(task);
10811         return task;
10812     };
10813
10814     /**
10815      * Stops all tasks that are currently running.
10816      * @method stopAll
10817      */
10818     this.stopAll = function() {
10819         stopThread();
10820         for (var i = 0, len = tasks.length; i < len; i++) {
10821             if (tasks[i].onStop) {
10822                 tasks[i].onStop();
10823             }
10824         }
10825         tasks = [];
10826         removeQueue = [];
10827     };
10828 };
10829
10830 /**
10831  * @class Ext.TaskManager
10832  * @extends Ext.util.TaskRunner
10833  * A static {@link Ext.util.TaskRunner} instance that can be used to start and stop arbitrary tasks.  See
10834  * {@link Ext.util.TaskRunner} for supported methods and task config properties.
10835  * <pre><code>
10836 // Start a simple clock task that updates a div once per second
10837 var task = {
10838     run: function(){
10839         Ext.fly('clock').update(new Date().format('g:i:s A'));
10840     },
10841     interval: 1000 //1 second
10842 }
10843 Ext.TaskManager.start(task);
10844 </code></pre>
10845  * <p>See the {@link #start} method for details about how to configure a task object.</p>
10846  * @singleton
10847  */
10848 Ext.TaskManager = Ext.create('Ext.util.TaskRunner');
10849 /**
10850  * @class Ext.is
10851  * 
10852  * Determines information about the current platform the application is running on.
10853  * 
10854  * @singleton
10855  */
10856 Ext.is = {
10857     init : function(navigator) {
10858         var platforms = this.platforms,
10859             ln = platforms.length,
10860             i, platform;
10861
10862         navigator = navigator || window.navigator;
10863
10864         for (i = 0; i < ln; i++) {
10865             platform = platforms[i];
10866             this[platform.identity] = platform.regex.test(navigator[platform.property]);
10867         }
10868
10869         /**
10870          * @property Desktop True if the browser is running on a desktop machine
10871          * @type {Boolean}
10872          */
10873         this.Desktop = this.Mac || this.Windows || (this.Linux && !this.Android);
10874         /**
10875          * @property Tablet True if the browser is running on a tablet (iPad)
10876          */
10877         this.Tablet = this.iPad;
10878         /**
10879          * @property Phone True if the browser is running on a phone.
10880          * @type {Boolean}
10881          */
10882         this.Phone = !this.Desktop && !this.Tablet;
10883         /**
10884          * @property iOS True if the browser is running on iOS
10885          * @type {Boolean}
10886          */
10887         this.iOS = this.iPhone || this.iPad || this.iPod;
10888         
10889         /**
10890          * @property Standalone Detects when application has been saved to homescreen.
10891          * @type {Boolean}
10892          */
10893         this.Standalone = !!window.navigator.standalone;
10894     },
10895     
10896     /**
10897      * @property iPhone True when the browser is running on a iPhone
10898      * @type {Boolean}
10899      */
10900     platforms: [{
10901         property: 'platform',
10902         regex: /iPhone/i,
10903         identity: 'iPhone'
10904     },
10905     
10906     /**
10907      * @property iPod True when the browser is running on a iPod
10908      * @type {Boolean}
10909      */
10910     {
10911         property: 'platform',
10912         regex: /iPod/i,
10913         identity: 'iPod'
10914     },
10915     
10916     /**
10917      * @property iPad True when the browser is running on a iPad
10918      * @type {Boolean}
10919      */
10920     {
10921         property: 'userAgent',
10922         regex: /iPad/i,
10923         identity: 'iPad'
10924     },
10925     
10926     /**
10927      * @property Blackberry True when the browser is running on a Blackberry
10928      * @type {Boolean}
10929      */
10930     {
10931         property: 'userAgent',
10932         regex: /Blackberry/i,
10933         identity: 'Blackberry'
10934     },
10935     
10936     /**
10937      * @property Android True when the browser is running on an Android device
10938      * @type {Boolean}
10939      */
10940     {
10941         property: 'userAgent',
10942         regex: /Android/i,
10943         identity: 'Android'
10944     },
10945     
10946     /**
10947      * @property Mac True when the browser is running on a Mac
10948      * @type {Boolean}
10949      */
10950     {
10951         property: 'platform',
10952         regex: /Mac/i,
10953         identity: 'Mac'
10954     },
10955     
10956     /**
10957      * @property Windows True when the browser is running on Windows
10958      * @type {Boolean}
10959      */
10960     {
10961         property: 'platform',
10962         regex: /Win/i,
10963         identity: 'Windows'
10964     },
10965     
10966     /**
10967      * @property Linux True when the browser is running on Linux
10968      * @type {Boolean}
10969      */
10970     {
10971         property: 'platform',
10972         regex: /Linux/i,
10973         identity: 'Linux'
10974     }]
10975 };
10976
10977 Ext.is.init();
10978
10979 /**
10980  * @class Ext.supports
10981  *
10982  * Determines information about features are supported in the current environment
10983  * 
10984  * @singleton
10985  */
10986 Ext.supports = {
10987     init : function() {
10988         var doc = document,
10989             div = doc.createElement('div'),
10990             tests = this.tests,
10991             ln = tests.length,
10992             i, test;
10993
10994         div.innerHTML = [
10995             '<div style="height:30px;width:50px;">',
10996                 '<div style="height:20px;width:20px;"></div>',
10997             '</div>',
10998             '<div style="width: 200px; height: 200px; position: relative; padding: 5px;">',
10999                 '<div style="position: absolute; top: 0; left: 0; width: 100%; height: 100%;"></div>',
11000             '</div>',
11001             '<div style="float:left; background-color:transparent;"></div>'
11002         ].join('');
11003
11004         doc.body.appendChild(div);
11005
11006         for (i = 0; i < ln; i++) {
11007             test = tests[i];
11008             this[test.identity] = test.fn.call(this, doc, div);
11009         }
11010
11011         doc.body.removeChild(div);
11012     },
11013
11014     /**
11015      * @property CSS3BoxShadow True if document environment supports the CSS3 box-shadow style.
11016      * @type {Boolean}
11017      */
11018     CSS3BoxShadow: Ext.isDefined(document.documentElement.style.boxShadow),
11019
11020     /**
11021      * @property ClassList True if document environment supports the HTML5 classList API.
11022      * @type {Boolean}
11023      */
11024     ClassList: !!document.documentElement.classList,
11025
11026     /**
11027      * @property OrientationChange True if the device supports orientation change
11028      * @type {Boolean}
11029      */
11030     OrientationChange: ((typeof window.orientation != 'undefined') && ('onorientationchange' in window)),
11031     
11032     /**
11033      * @property DeviceMotion True if the device supports device motion (acceleration and rotation rate)
11034      * @type {Boolean}
11035      */
11036     DeviceMotion: ('ondevicemotion' in window),
11037     
11038     /**
11039      * @property Touch True if the device supports touch
11040      * @type {Boolean}
11041      */
11042     // is.Desktop is needed due to the bug in Chrome 5.0.375, Safari 3.1.2
11043     // and Safari 4.0 (they all have 'ontouchstart' in the window object).
11044     Touch: ('ontouchstart' in window) && (!Ext.is.Desktop),
11045
11046     tests: [
11047         /**
11048          * @property Transitions True if the device supports CSS3 Transitions
11049          * @type {Boolean}
11050          */
11051         {
11052             identity: 'Transitions',
11053             fn: function(doc, div) {
11054                 var prefix = [
11055                         'webkit',
11056                         'Moz',
11057                         'o',
11058                         'ms',
11059                         'khtml'
11060                     ],
11061                     TE = 'TransitionEnd',
11062                     transitionEndName = [
11063                         prefix[0] + TE,
11064                         'transitionend', //Moz bucks the prefixing convention
11065                         prefix[2] + TE,
11066                         prefix[3] + TE,
11067                         prefix[4] + TE
11068                     ],
11069                     ln = prefix.length,
11070                     i = 0,
11071                     out = false;
11072                 div = Ext.get(div);
11073                 for (; i < ln; i++) {
11074                     if (div.getStyle(prefix[i] + "TransitionProperty")) {
11075                         Ext.supports.CSS3Prefix = prefix[i];
11076                         Ext.supports.CSS3TransitionEnd = transitionEndName[i];
11077                         out = true;
11078                         break;
11079                     }
11080                 }
11081                 return out;
11082             }
11083         },
11084         
11085         /**
11086          * @property RightMargin True if the device supports right margin.
11087          * See https://bugs.webkit.org/show_bug.cgi?id=13343 for why this is needed.
11088          * @type {Boolean}
11089          */
11090         {
11091             identity: 'RightMargin',
11092             fn: function(doc, div) {
11093                 var view = doc.defaultView;
11094                 return !(view && view.getComputedStyle(div.firstChild.firstChild, null).marginRight != '0px');
11095             }
11096         },
11097
11098         /**
11099          * @property DisplayChangeInputSelectionBug True if INPUT elements lose their
11100          * selection when their display style is changed. Essentially, if a text input
11101          * has focus and its display style is changed, the I-beam disappears.
11102          * 
11103          * This bug is encountered due to the work around in place for the {@link #RightMargin}
11104          * bug. This has been observed in Safari 4.0.4 and older, and appears to be fixed
11105          * in Safari 5. It's not clear if Safari 4.1 has the bug, but it has the same WebKit
11106          * version number as Safari 5 (according to http://unixpapa.com/js/gecko.html).
11107          */
11108         {
11109             identity: 'DisplayChangeInputSelectionBug',
11110             fn: function() {
11111                 var webKitVersion = Ext.webKitVersion;
11112                 // WebKit but older than Safari 5 or Chrome 6:
11113                 return 0 < webKitVersion && webKitVersion < 533;
11114             }
11115         },
11116
11117         /**
11118          * @property DisplayChangeTextAreaSelectionBug True if TEXTAREA elements lose their
11119          * selection when their display style is changed. Essentially, if a text area has
11120          * focus and its display style is changed, the I-beam disappears.
11121          *
11122          * This bug is encountered due to the work around in place for the {@link #RightMargin}
11123          * bug. This has been observed in Chrome 10 and Safari 5 and older, and appears to
11124          * be fixed in Chrome 11.
11125          */
11126         {
11127             identity: 'DisplayChangeTextAreaSelectionBug',
11128             fn: function() {
11129                 var webKitVersion = Ext.webKitVersion;
11130
11131                 /*
11132                 Has bug w/textarea:
11133
11134                 (Chrome) Mozilla/5.0 (Macintosh; U; Intel Mac OS X 10_6_7; en-US)
11135                             AppleWebKit/534.16 (KHTML, like Gecko) Chrome/10.0.648.127
11136                             Safari/534.16
11137                 (Safari) Mozilla/5.0 (Macintosh; U; Intel Mac OS X 10_6_7; en-us)
11138                             AppleWebKit/533.21.1 (KHTML, like Gecko) Version/5.0.5
11139                             Safari/533.21.1
11140
11141                 No bug:
11142
11143                 (Chrome) Mozilla/5.0 (Macintosh; Intel Mac OS X 10_6_7)
11144                             AppleWebKit/534.24 (KHTML, like Gecko) Chrome/11.0.696.57
11145                             Safari/534.24
11146                 */
11147                 return 0 < webKitVersion && webKitVersion < 534.24;
11148             }
11149         },
11150
11151         /**
11152          * @property TransparentColor True if the device supports transparent color
11153          * @type {Boolean}
11154          */
11155         {
11156             identity: 'TransparentColor',
11157             fn: function(doc, div, view) {
11158                 view = doc.defaultView;
11159                 return !(view && view.getComputedStyle(div.lastChild, null).backgroundColor != 'transparent');
11160             }
11161         },
11162
11163         /**
11164          * @property ComputedStyle True if the browser supports document.defaultView.getComputedStyle()
11165          * @type {Boolean}
11166          */
11167         {
11168             identity: 'ComputedStyle',
11169             fn: function(doc, div, view) {
11170                 view = doc.defaultView;
11171                 return view && view.getComputedStyle;
11172             }
11173         },
11174         
11175         /**
11176          * @property SVG True if the device supports SVG
11177          * @type {Boolean}
11178          */
11179         {
11180             identity: 'Svg',
11181             fn: function(doc) {
11182                 return !!doc.createElementNS && !!doc.createElementNS( "http:/" + "/www.w3.org/2000/svg", "svg").createSVGRect;
11183             }
11184         },
11185     
11186         /**
11187          * @property Canvas True if the device supports Canvas
11188          * @type {Boolean}
11189          */
11190         {
11191             identity: 'Canvas',
11192             fn: function(doc) {
11193                 return !!doc.createElement('canvas').getContext;
11194             }
11195         },
11196         
11197         /**
11198          * @property VML True if the device supports VML
11199          * @type {Boolean}
11200          */
11201         {
11202             identity: 'Vml',
11203             fn: function(doc) {
11204                 var d = doc.createElement("div");
11205                 d.innerHTML = "<!--[if vml]><br><br><![endif]-->";
11206                 return (d.childNodes.length == 2);
11207             }
11208         },
11209         
11210         /**
11211          * @property Float True if the device supports CSS float
11212          * @type {Boolean}
11213          */
11214         {
11215             identity: 'Float',
11216             fn: function(doc, div) {
11217                 return !!div.lastChild.style.cssFloat;
11218             }
11219         },
11220         
11221         /**
11222          * @property AudioTag True if the device supports the HTML5 audio tag
11223          * @type {Boolean}
11224          */
11225         {
11226             identity: 'AudioTag',
11227             fn: function(doc) {
11228                 return !!doc.createElement('audio').canPlayType;
11229             }
11230         },
11231         
11232         /**
11233          * @property History True if the device supports HTML5 history
11234          * @type {Boolean}
11235          */
11236         {
11237             identity: 'History',
11238             fn: function() {
11239                 return !!(window.history && history.pushState);
11240             }
11241         },
11242         
11243         /**
11244          * @property CSS3DTransform True if the device supports CSS3DTransform
11245          * @type {Boolean}
11246          */
11247         {
11248             identity: 'CSS3DTransform',
11249             fn: function() {
11250                 return (typeof WebKitCSSMatrix != 'undefined' && new WebKitCSSMatrix().hasOwnProperty('m41'));
11251             }
11252         },
11253
11254                 /**
11255          * @property CSS3LinearGradient True if the device supports CSS3 linear gradients
11256          * @type {Boolean}
11257          */
11258         {
11259             identity: 'CSS3LinearGradient',
11260             fn: function(doc, div) {
11261                 var property = 'background-image:',
11262                     webkit   = '-webkit-gradient(linear, left top, right bottom, from(black), to(white))',
11263                     w3c      = 'linear-gradient(left top, black, white)',
11264                     moz      = '-moz-' + w3c,
11265                     options  = [property + webkit, property + w3c, property + moz];
11266                 
11267                 div.style.cssText = options.join(';');
11268                 
11269                 return ("" + div.style.backgroundImage).indexOf('gradient') !== -1;
11270             }
11271         },
11272         
11273         /**
11274          * @property CSS3BorderRadius True if the device supports CSS3 border radius
11275          * @type {Boolean}
11276          */
11277         {
11278             identity: 'CSS3BorderRadius',
11279             fn: function(doc, div) {
11280                 var domPrefixes = ['borderRadius', 'BorderRadius', 'MozBorderRadius', 'WebkitBorderRadius', 'OBorderRadius', 'KhtmlBorderRadius'],
11281                     pass = false,
11282                     i;
11283                 for (i = 0; i < domPrefixes.length; i++) {
11284                     if (document.body.style[domPrefixes[i]] !== undefined) {
11285                         return true;
11286                     }
11287                 }
11288                 return pass;
11289             }
11290         },
11291         
11292         /**
11293          * @property GeoLocation True if the device supports GeoLocation
11294          * @type {Boolean}
11295          */
11296         {
11297             identity: 'GeoLocation',
11298             fn: function() {
11299                 return (typeof navigator != 'undefined' && typeof navigator.geolocation != 'undefined') || (typeof google != 'undefined' && typeof google.gears != 'undefined');
11300             }
11301         },
11302         /**
11303          * @property MouseEnterLeave True if the browser supports mouseenter and mouseleave events
11304          * @type {Boolean}
11305          */
11306         {
11307             identity: 'MouseEnterLeave',
11308             fn: function(doc, div){
11309                 return ('onmouseenter' in div && 'onmouseleave' in div);
11310             }
11311         },
11312         /**
11313          * @property MouseWheel True if the browser supports the mousewheel event
11314          * @type {Boolean}
11315          */
11316         {
11317             identity: 'MouseWheel',
11318             fn: function(doc, div) {
11319                 return ('onmousewheel' in div);
11320             }
11321         },
11322         /**
11323          * @property Opacity True if the browser supports normal css opacity
11324          * @type {Boolean}
11325          */
11326         {
11327             identity: 'Opacity',
11328             fn: function(doc, div){
11329                 // Not a strict equal comparison in case opacity can be converted to a number.
11330                 if (Ext.isIE6 || Ext.isIE7 || Ext.isIE8) {
11331                     return false;
11332                 }
11333                 div.firstChild.style.cssText = 'opacity:0.73';
11334                 return div.firstChild.style.opacity == '0.73';
11335             }
11336         },
11337         /**
11338          * @property Placeholder True if the browser supports the HTML5 placeholder attribute on inputs
11339          * @type {Boolean}
11340          */
11341         {
11342             identity: 'Placeholder',
11343             fn: function(doc) {
11344                 return 'placeholder' in doc.createElement('input');
11345             }
11346         },
11347         
11348         /**
11349          * @property Direct2DBug True if when asking for an element's dimension via offsetWidth or offsetHeight, 
11350          * getBoundingClientRect, etc. the browser returns the subpixel width rounded to the nearest pixel.
11351          * @type {Boolean}
11352          */
11353         {
11354             identity: 'Direct2DBug',
11355             fn: function() {
11356                 return Ext.isString(document.body.style.msTransformOrigin);
11357             }
11358         },
11359         /**
11360          * @property BoundingClientRect True if the browser supports the getBoundingClientRect method on elements
11361          * @type {Boolean}
11362          */
11363         {
11364             identity: 'BoundingClientRect',
11365             fn: function(doc, div) {
11366                 return Ext.isFunction(div.getBoundingClientRect);
11367             }
11368         },
11369         {
11370             identity: 'IncludePaddingInWidthCalculation',
11371             fn: function(doc, div){
11372                 var el = Ext.get(div.childNodes[1].firstChild);
11373                 return el.getWidth() == 210;
11374             }
11375         },
11376         {
11377             identity: 'IncludePaddingInHeightCalculation',
11378             fn: function(doc, div){
11379                 var el = Ext.get(div.childNodes[1].firstChild);
11380                 return el.getHeight() == 210;
11381             }
11382         },
11383         
11384         /**
11385          * @property ArraySort True if the Array sort native method isn't bugged.
11386          * @type {Boolean}
11387          */
11388         {
11389             identity: 'ArraySort',
11390             fn: function() {
11391                 var a = [1,2,3,4,5].sort(function(){ return 0; });
11392                 return a[0] === 1 && a[1] === 2 && a[2] === 3 && a[3] === 4 && a[4] === 5;
11393             }
11394         },
11395         /**
11396          * @property Range True if browser support document.createRange native method.
11397          * @type {Boolean}
11398          */
11399         {
11400             identity: 'Range',
11401             fn: function() {
11402                 return !!document.createRange;
11403             }
11404         },
11405         /**
11406          * @property CreateContextualFragment True if browser support CreateContextualFragment range native methods.
11407          * @type {Boolean}
11408          */
11409         {
11410             identity: 'CreateContextualFragment',
11411             fn: function() {
11412                 var range = Ext.supports.Range ? document.createRange() : false;
11413                 
11414                 return range && !!range.createContextualFragment;
11415             }
11416         },
11417
11418         /**
11419          * @property WindowOnError True if browser supports window.onerror.
11420          * @type {Boolean}
11421          */
11422         {
11423             identity: 'WindowOnError',
11424             fn: function () {
11425                 // sadly, we cannot feature detect this...
11426                 return Ext.isIE || Ext.isGecko || Ext.webKitVersion >= 534.16; // Chrome 10+
11427             }
11428         }
11429     ]
11430 };
11431
11432
11433
11434 /*
11435
11436 This file is part of Ext JS 4
11437
11438 Copyright (c) 2011 Sencha Inc
11439
11440 Contact:  http://www.sencha.com/contact
11441
11442 GNU General Public License Usage
11443 This file may be used under the terms of the GNU General Public License version 3.0 as published by the Free Software Foundation and appearing in the file LICENSE included in the packaging of this file.  Please review the following information to ensure the GNU General Public License version 3.0 requirements will be met: http://www.gnu.org/copyleft/gpl.html.
11444
11445 If you are unsure which license is appropriate for your use, please contact the sales department at http://www.sencha.com/contact.
11446
11447 */
11448 /**
11449  * @class Ext.DomHelper
11450  * @alternateClassName Ext.core.DomHelper
11451  *
11452  * <p>The DomHelper class provides a layer of abstraction from DOM and transparently supports creating
11453  * elements via DOM or using HTML fragments. It also has the ability to create HTML fragment templates
11454  * from your DOM building code.</p>
11455  *
11456  * <p><b><u>DomHelper element specification object</u></b></p>
11457  * <p>A specification object is used when creating elements. Attributes of this object
11458  * are assumed to be element attributes, except for 4 special attributes:
11459  * <div class="mdetail-params"><ul>
11460  * <li><b><tt>tag</tt></b> : <div class="sub-desc">The tag name of the element</div></li>
11461  * <li><b><tt>children</tt></b> : or <tt>cn</tt><div class="sub-desc">An array of the
11462  * same kind of element definition objects to be created and appended. These can be nested
11463  * as deep as you want.</div></li>
11464  * <li><b><tt>cls</tt></b> : <div class="sub-desc">The class attribute of the element.
11465  * This will end up being either the "class" attribute on a HTML fragment or className
11466  * for a DOM node, depending on whether DomHelper is using fragments or DOM.</div></li>
11467  * <li><b><tt>html</tt></b> : <div class="sub-desc">The innerHTML for the element</div></li>
11468  * </ul></div></p>
11469  * <p><b>NOTE:</b> For other arbitrary attributes, the value will currently <b>not</b> be automatically
11470  * HTML-escaped prior to building the element's HTML string. This means that if your attribute value
11471  * contains special characters that would not normally be allowed in a double-quoted attribute value,
11472  * you <b>must</b> manually HTML-encode it beforehand (see {@link Ext.String#htmlEncode}) or risk
11473  * malformed HTML being created. This behavior may change in a future release.</p>
11474  *
11475  * <p><b><u>Insertion methods</u></b></p>
11476  * <p>Commonly used insertion methods:
11477  * <div class="mdetail-params"><ul>
11478  * <li><tt>{@link #append}</tt> : <div class="sub-desc"></div></li>
11479  * <li><tt>{@link #insertBefore}</tt> : <div class="sub-desc"></div></li>
11480  * <li><tt>{@link #insertAfter}</tt> : <div class="sub-desc"></div></li>
11481  * <li><tt>{@link #overwrite}</tt> : <div class="sub-desc"></div></li>
11482  * <li><tt>{@link #createTemplate}</tt> : <div class="sub-desc"></div></li>
11483  * <li><tt>{@link #insertHtml}</tt> : <div class="sub-desc"></div></li>
11484  * </ul></div></p>
11485  *
11486  * <p><b><u>Example</u></b></p>
11487  * <p>This is an example, where an unordered list with 3 children items is appended to an existing
11488  * element with id <tt>'my-div'</tt>:<br>
11489  <pre><code>
11490 var dh = Ext.DomHelper; // create shorthand alias
11491 // specification object
11492 var spec = {
11493     id: 'my-ul',
11494     tag: 'ul',
11495     cls: 'my-list',
11496     // append children after creating
11497     children: [     // may also specify 'cn' instead of 'children'
11498         {tag: 'li', id: 'item0', html: 'List Item 0'},
11499         {tag: 'li', id: 'item1', html: 'List Item 1'},
11500         {tag: 'li', id: 'item2', html: 'List Item 2'}
11501     ]
11502 };
11503 var list = dh.append(
11504     'my-div', // the context element 'my-div' can either be the id or the actual node
11505     spec      // the specification object
11506 );
11507  </code></pre></p>
11508  * <p>Element creation specification parameters in this class may also be passed as an Array of
11509  * specification objects. This can be used to insert multiple sibling nodes into an existing
11510  * container very efficiently. For example, to add more list items to the example above:<pre><code>
11511 dh.append('my-ul', [
11512     {tag: 'li', id: 'item3', html: 'List Item 3'},
11513     {tag: 'li', id: 'item4', html: 'List Item 4'}
11514 ]);
11515  * </code></pre></p>
11516  *
11517  * <p><b><u>Templating</u></b></p>
11518  * <p>The real power is in the built-in templating. Instead of creating or appending any elements,
11519  * <tt>{@link #createTemplate}</tt> returns a Template object which can be used over and over to
11520  * insert new elements. Revisiting the example above, we could utilize templating this time:
11521  * <pre><code>
11522 // create the node
11523 var list = dh.append('my-div', {tag: 'ul', cls: 'my-list'});
11524 // get template
11525 var tpl = dh.createTemplate({tag: 'li', id: 'item{0}', html: 'List Item {0}'});
11526
11527 for(var i = 0; i < 5, i++){
11528     tpl.append(list, [i]); // use template to append to the actual node
11529 }
11530  * </code></pre></p>
11531  * <p>An example using a template:<pre><code>
11532 var html = '<a id="{0}" href="{1}" class="nav">{2}</a>';
11533
11534 var tpl = new Ext.DomHelper.createTemplate(html);
11535 tpl.append('blog-roll', ['link1', 'http://www.edspencer.net/', "Ed&#39;s Site"]);
11536 tpl.append('blog-roll', ['link2', 'http://www.dustindiaz.com/', "Dustin&#39;s Site"]);
11537  * </code></pre></p>
11538  *
11539  * <p>The same example using named parameters:<pre><code>
11540 var html = '<a id="{id}" href="{url}" class="nav">{text}</a>';
11541
11542 var tpl = new Ext.DomHelper.createTemplate(html);
11543 tpl.append('blog-roll', {
11544     id: 'link1',
11545     url: 'http://www.edspencer.net/',
11546     text: "Ed&#39;s Site"
11547 });
11548 tpl.append('blog-roll', {
11549     id: 'link2',
11550     url: 'http://www.dustindiaz.com/',
11551     text: "Dustin&#39;s Site"
11552 });
11553  * </code></pre></p>
11554  *
11555  * <p><b><u>Compiling Templates</u></b></p>
11556  * <p>Templates are applied using regular expressions. The performance is great, but if
11557  * you are adding a bunch of DOM elements using the same template, you can increase
11558  * performance even further by {@link Ext.Template#compile "compiling"} the template.
11559  * The way "{@link Ext.Template#compile compile()}" works is the template is parsed and
11560  * broken up at the different variable points and a dynamic function is created and eval'ed.
11561  * The generated function performs string concatenation of these parts and the passed
11562  * variables instead of using regular expressions.
11563  * <pre><code>
11564 var html = '<a id="{id}" href="{url}" class="nav">{text}</a>';
11565
11566 var tpl = new Ext.DomHelper.createTemplate(html);
11567 tpl.compile();
11568
11569 //... use template like normal
11570  * </code></pre></p>
11571  *
11572  * <p><b><u>Performance Boost</u></b></p>
11573  * <p>DomHelper will transparently create HTML fragments when it can. Using HTML fragments instead
11574  * of DOM can significantly boost performance.</p>
11575  * <p>Element creation specification parameters may also be strings. If {@link #useDom} is <tt>false</tt>,
11576  * then the string is used as innerHTML. If {@link #useDom} is <tt>true</tt>, a string specification
11577  * results in the creation of a text node. Usage:</p>
11578  * <pre><code>
11579 Ext.DomHelper.useDom = true; // force it to use DOM; reduces performance
11580  * </code></pre>
11581  * @singleton
11582  */
11583 Ext.ns('Ext.core');
11584 Ext.core.DomHelper = Ext.DomHelper = function(){
11585     var tempTableEl = null,
11586         emptyTags = /^(?:br|frame|hr|img|input|link|meta|range|spacer|wbr|area|param|col)$/i,
11587         tableRe = /^table|tbody|tr|td$/i,
11588         confRe = /tag|children|cn|html$/i,
11589         tableElRe = /td|tr|tbody/i,
11590         endRe = /end/i,
11591         pub,
11592         // kill repeat to save bytes
11593         afterbegin = 'afterbegin',
11594         afterend = 'afterend',
11595         beforebegin = 'beforebegin',
11596         beforeend = 'beforeend',
11597         ts = '<table>',
11598         te = '</table>',
11599         tbs = ts+'<tbody>',
11600         tbe = '</tbody>'+te,
11601         trs = tbs + '<tr>',
11602         tre = '</tr>'+tbe;
11603
11604     // private
11605     function doInsert(el, o, returnElement, pos, sibling, append){
11606         el = Ext.getDom(el);
11607         var newNode;
11608         if (pub.useDom) {
11609             newNode = createDom(o, null);
11610             if (append) {
11611                 el.appendChild(newNode);
11612             } else {
11613                 (sibling == 'firstChild' ? el : el.parentNode).insertBefore(newNode, el[sibling] || el);
11614             }
11615         } else {
11616             newNode = Ext.DomHelper.insertHtml(pos, el, Ext.DomHelper.createHtml(o));
11617         }
11618         return returnElement ? Ext.get(newNode, true) : newNode;
11619     }
11620
11621     function createDom(o, parentNode){
11622         var el,
11623             doc = document,
11624             useSet,
11625             attr,
11626             val,
11627             cn;
11628
11629         if (Ext.isArray(o)) {                       // Allow Arrays of siblings to be inserted
11630             el = doc.createDocumentFragment(); // in one shot using a DocumentFragment
11631             for (var i = 0, l = o.length; i < l; i++) {
11632                 createDom(o[i], el);
11633             }
11634         } else if (typeof o == 'string') {         // Allow a string as a child spec.
11635             el = doc.createTextNode(o);
11636         } else {
11637             el = doc.createElement( o.tag || 'div' );
11638             useSet = !!el.setAttribute; // In IE some elements don't have setAttribute
11639             for (attr in o) {
11640                 if(!confRe.test(attr)){
11641                     val = o[attr];
11642                     if(attr == 'cls'){
11643                         el.className = val;
11644                     }else{
11645                         if(useSet){
11646                             el.setAttribute(attr, val);
11647                         }else{
11648                             el[attr] = val;
11649                         }
11650                     }
11651                 }
11652             }
11653             Ext.DomHelper.applyStyles(el, o.style);
11654
11655             if ((cn = o.children || o.cn)) {
11656                 createDom(cn, el);
11657             } else if (o.html) {
11658                 el.innerHTML = o.html;
11659             }
11660         }
11661         if(parentNode){
11662            parentNode.appendChild(el);
11663         }
11664         return el;
11665     }
11666
11667     // build as innerHTML where available
11668     function createHtml(o){
11669         var b = '',
11670             attr,
11671             val,
11672             key,
11673             cn,
11674             i;
11675
11676         if(typeof o == "string"){
11677             b = o;
11678         } else if (Ext.isArray(o)) {
11679             for (i=0; i < o.length; i++) {
11680                 if(o[i]) {
11681                     b += createHtml(o[i]);
11682                 }
11683             }
11684         } else {
11685             b += '<' + (o.tag = o.tag || 'div');
11686             for (attr in o) {
11687                 val = o[attr];
11688                 if(!confRe.test(attr)){
11689                     if (typeof val == "object") {
11690                         b += ' ' + attr + '="';
11691                         for (key in val) {
11692                             b += key + ':' + val[key] + ';';
11693                         }
11694                         b += '"';
11695                     }else{
11696                         b += ' ' + ({cls : 'class', htmlFor : 'for'}[attr] || attr) + '="' + val + '"';
11697                     }
11698                 }
11699             }
11700             // Now either just close the tag or try to add children and close the tag.
11701             if (emptyTags.test(o.tag)) {
11702                 b += '/>';
11703             } else {
11704                 b += '>';
11705                 if ((cn = o.children || o.cn)) {
11706                     b += createHtml(cn);
11707                 } else if(o.html){
11708                     b += o.html;
11709                 }
11710                 b += '</' + o.tag + '>';
11711             }
11712         }
11713         return b;
11714     }
11715
11716     function ieTable(depth, s, h, e){
11717         tempTableEl.innerHTML = [s, h, e].join('');
11718         var i = -1,
11719             el = tempTableEl,
11720             ns;
11721         while(++i < depth){
11722             el = el.firstChild;
11723         }
11724 //      If the result is multiple siblings, then encapsulate them into one fragment.
11725         ns = el.nextSibling;
11726         if (ns){
11727             var df = document.createDocumentFragment();
11728             while(el){
11729                 ns = el.nextSibling;
11730                 df.appendChild(el);
11731                 el = ns;
11732             }
11733             el = df;
11734         }
11735         return el;
11736     }
11737
11738     /**
11739      * @ignore
11740      * Nasty code for IE's broken table implementation
11741      */
11742     function insertIntoTable(tag, where, el, html) {
11743         var node,
11744             before;
11745
11746         tempTableEl = tempTableEl || document.createElement('div');
11747
11748         if(tag == 'td' && (where == afterbegin || where == beforeend) ||
11749            !tableElRe.test(tag) && (where == beforebegin || where == afterend)) {
11750             return null;
11751         }
11752         before = where == beforebegin ? el :
11753                  where == afterend ? el.nextSibling :
11754                  where == afterbegin ? el.firstChild : null;
11755
11756         if (where == beforebegin || where == afterend) {
11757             el = el.parentNode;
11758         }
11759
11760         if (tag == 'td' || (tag == 'tr' && (where == beforeend || where == afterbegin))) {
11761             node = ieTable(4, trs, html, tre);
11762         } else if ((tag == 'tbody' && (where == beforeend || where == afterbegin)) ||
11763                    (tag == 'tr' && (where == beforebegin || where == afterend))) {
11764             node = ieTable(3, tbs, html, tbe);
11765         } else {
11766             node = ieTable(2, ts, html, te);
11767         }
11768         el.insertBefore(node, before);
11769         return node;
11770     }
11771
11772     /**
11773      * @ignore
11774      * Fix for IE9 createContextualFragment missing method
11775      */
11776     function createContextualFragment(html){
11777         var div = document.createElement("div"),
11778             fragment = document.createDocumentFragment(),
11779             i = 0,
11780             length, childNodes;
11781
11782         div.innerHTML = html;
11783         childNodes = div.childNodes;
11784         length = childNodes.length;
11785
11786         for (; i < length; i++) {
11787             fragment.appendChild(childNodes[i].cloneNode(true));
11788         }
11789
11790         return fragment;
11791     }
11792
11793     pub = {
11794         /**
11795          * Returns the markup for the passed Element(s) config.
11796          * @param {Object} o The DOM object spec (and children)
11797          * @return {String}
11798          */
11799         markup : function(o){
11800             return createHtml(o);
11801         },
11802
11803         /**
11804          * Applies a style specification to an element.
11805          * @param {String/HTMLElement} el The element to apply styles to
11806          * @param {String/Object/Function} styles A style specification string e.g. 'width:100px', or object in the form {width:'100px'}, or
11807          * a function which returns such a specification.
11808          */
11809         applyStyles : function(el, styles){
11810             if (styles) {
11811                 el = Ext.fly(el);
11812                 if (typeof styles == "function") {
11813                     styles = styles.call();
11814                 }
11815                 if (typeof styles == "string") {
11816                     styles = Ext.Element.parseStyles(styles);
11817                 }
11818                 if (typeof styles == "object") {
11819                     el.setStyle(styles);
11820                 }
11821             }
11822         },
11823
11824         /**
11825          * Inserts an HTML fragment into the DOM.
11826          * @param {String} where Where to insert the html in relation to el - beforeBegin, afterBegin, beforeEnd, afterEnd.
11827          *
11828          * For example take the following HTML: `<div>Contents</div>`
11829          *
11830          * Using different `where` values inserts element to the following places:
11831          *
11832          * - beforeBegin: `<HERE><div>Contents</div>`
11833          * - afterBegin: `<div><HERE>Contents</div>`
11834          * - beforeEnd: `<div>Contents<HERE></div>`
11835          * - afterEnd: `<div>Contents</div><HERE>`
11836          *
11837          * @param {HTMLElement/TextNode} el The context element
11838          * @param {String} html The HTML fragment
11839          * @return {HTMLElement} The new node
11840          */
11841         insertHtml : function(where, el, html){
11842             var hash = {},
11843                 hashVal,
11844                 range,
11845                 rangeEl,
11846                 setStart,
11847                 frag,
11848                 rs;
11849
11850             where = where.toLowerCase();
11851             // add these here because they are used in both branches of the condition.
11852             hash[beforebegin] = ['BeforeBegin', 'previousSibling'];
11853             hash[afterend] = ['AfterEnd', 'nextSibling'];
11854
11855             // if IE and context element is an HTMLElement
11856             if (el.insertAdjacentHTML) {
11857                 if(tableRe.test(el.tagName) && (rs = insertIntoTable(el.tagName.toLowerCase(), where, el, html))){
11858                     return rs;
11859                 }
11860
11861                 // add these two to the hash.
11862                 hash[afterbegin] = ['AfterBegin', 'firstChild'];
11863                 hash[beforeend] = ['BeforeEnd', 'lastChild'];
11864                 if ((hashVal = hash[where])) {
11865                     el.insertAdjacentHTML(hashVal[0], html);
11866                     return el[hashVal[1]];
11867                 }
11868             // if (not IE and context element is an HTMLElement) or TextNode
11869             } else {
11870                 // we cannot insert anything inside a textnode so...
11871                 if (Ext.isTextNode(el)) {
11872                     where = where === 'afterbegin' ? 'beforebegin' : where;
11873                     where = where === 'beforeend' ? 'afterend' : where;
11874                 }
11875                 range = Ext.supports.CreateContextualFragment ? el.ownerDocument.createRange() : undefined;
11876                 setStart = 'setStart' + (endRe.test(where) ? 'After' : 'Before');
11877                 if (hash[where]) {
11878                     if (range) {
11879                         range[setStart](el);
11880                         frag = range.createContextualFragment(html);
11881                     } else {
11882                         frag = createContextualFragment(html);
11883                     }
11884                     el.parentNode.insertBefore(frag, where == beforebegin ? el : el.nextSibling);
11885                     return el[(where == beforebegin ? 'previous' : 'next') + 'Sibling'];
11886                 } else {
11887                     rangeEl = (where == afterbegin ? 'first' : 'last') + 'Child';
11888                     if (el.firstChild) {
11889                         if (range) {
11890                             range[setStart](el[rangeEl]);
11891                             frag = range.createContextualFragment(html);
11892                         } else {
11893                             frag = createContextualFragment(html);
11894                         }
11895
11896                         if(where == afterbegin){
11897                             el.insertBefore(frag, el.firstChild);
11898                         }else{
11899                             el.appendChild(frag);
11900                         }
11901                     } else {
11902                         el.innerHTML = html;
11903                     }
11904                     return el[rangeEl];
11905                 }
11906             }
11907             Ext.Error.raise({
11908                 sourceClass: 'Ext.DomHelper',
11909                 sourceMethod: 'insertHtml',
11910                 htmlToInsert: html,
11911                 targetElement: el,
11912                 msg: 'Illegal insertion point reached: "' + where + '"'
11913             });
11914         },
11915
11916         /**
11917          * Creates new DOM element(s) and inserts them before el.
11918          * @param {String/HTMLElement/Ext.Element} el The context element
11919          * @param {Object/String} o The DOM object spec (and children) or raw HTML blob
11920          * @param {Boolean} returnElement (optional) true to return a Ext.Element
11921          * @return {HTMLElement/Ext.Element} The new node
11922          */
11923         insertBefore : function(el, o, returnElement){
11924             return doInsert(el, o, returnElement, beforebegin);
11925         },
11926
11927         /**
11928          * Creates new DOM element(s) and inserts them after el.
11929          * @param {String/HTMLElement/Ext.Element} el The context element
11930          * @param {Object} o The DOM object spec (and children)
11931          * @param {Boolean} returnElement (optional) true to return a Ext.Element
11932          * @return {HTMLElement/Ext.Element} The new node
11933          */
11934         insertAfter : function(el, o, returnElement){
11935             return doInsert(el, o, returnElement, afterend, 'nextSibling');
11936         },
11937
11938         /**
11939          * Creates new DOM element(s) and inserts them as the first child of el.
11940          * @param {String/HTMLElement/Ext.Element} el The context element
11941          * @param {Object/String} o The DOM object spec (and children) or raw HTML blob
11942          * @param {Boolean} returnElement (optional) true to return a Ext.Element
11943          * @return {HTMLElement/Ext.Element} The new node
11944          */
11945         insertFirst : function(el, o, returnElement){
11946             return doInsert(el, o, returnElement, afterbegin, 'firstChild');
11947         },
11948
11949         /**
11950          * Creates new DOM element(s) and appends them to el.
11951          * @param {String/HTMLElement/Ext.Element} el The context element
11952          * @param {Object/String} o The DOM object spec (and children) or raw HTML blob
11953          * @param {Boolean} returnElement (optional) true to return a Ext.Element
11954          * @return {HTMLElement/Ext.Element} The new node
11955          */
11956         append : function(el, o, returnElement){
11957             return doInsert(el, o, returnElement, beforeend, '', true);
11958         },
11959
11960         /**
11961          * Creates new DOM element(s) and overwrites the contents of el with them.
11962          * @param {String/HTMLElement/Ext.Element} el The context element
11963          * @param {Object/String} o The DOM object spec (and children) or raw HTML blob
11964          * @param {Boolean} returnElement (optional) true to return a Ext.Element
11965          * @return {HTMLElement/Ext.Element} The new node
11966          */
11967         overwrite : function(el, o, returnElement){
11968             el = Ext.getDom(el);
11969             el.innerHTML = createHtml(o);
11970             return returnElement ? Ext.get(el.firstChild) : el.firstChild;
11971         },
11972
11973         createHtml : createHtml,
11974
11975         /**
11976          * Creates new DOM element(s) without inserting them to the document.
11977          * @param {Object/String} o The DOM object spec (and children) or raw HTML blob
11978          * @return {HTMLElement} The new uninserted node
11979          * @method
11980          */
11981         createDom: createDom,
11982
11983         /** True to force the use of DOM instead of html fragments @type Boolean */
11984         useDom : false,
11985
11986         /**
11987          * Creates a new Ext.Template from the DOM object spec.
11988          * @param {Object} o The DOM object spec (and children)
11989          * @return {Ext.Template} The new template
11990          */
11991         createTemplate : function(o){
11992             var html = Ext.DomHelper.createHtml(o);
11993             return Ext.create('Ext.Template', html);
11994         }
11995     };
11996     return pub;
11997 }();
11998
11999 /*
12000  * This is code is also distributed under MIT license for use
12001  * with jQuery and prototype JavaScript libraries.
12002  */
12003 /**
12004  * @class Ext.DomQuery
12005 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).
12006 <p>
12007 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>
12008
12009 <p>
12010 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.
12011 </p>
12012 <h4>Element Selectors:</h4>
12013 <ul class="list">
12014     <li> <b>*</b> any element</li>
12015     <li> <b>E</b> an element with the tag E</li>
12016     <li> <b>E F</b> All descendent elements of E that have the tag F</li>
12017     <li> <b>E > F</b> or <b>E/F</b> all direct children elements of E that have the tag F</li>
12018     <li> <b>E + F</b> all elements with the tag F that are immediately preceded by an element with the tag E</li>
12019     <li> <b>E ~ F</b> all elements with the tag F that are preceded by a sibling element with the tag E</li>
12020 </ul>
12021 <h4>Attribute Selectors:</h4>
12022 <p>The use of &#64; and quotes are optional. For example, div[&#64;foo='bar'] is also a valid attribute selector.</p>
12023 <ul class="list">
12024     <li> <b>E[foo]</b> has an attribute "foo"</li>
12025     <li> <b>E[foo=bar]</b> has an attribute "foo" that equals "bar"</li>
12026     <li> <b>E[foo^=bar]</b> has an attribute "foo" that starts with "bar"</li>
12027     <li> <b>E[foo$=bar]</b> has an attribute "foo" that ends with "bar"</li>
12028     <li> <b>E[foo*=bar]</b> has an attribute "foo" that contains the substring "bar"</li>
12029     <li> <b>E[foo%=2]</b> has an attribute "foo" that is evenly divisible by 2</li>
12030     <li> <b>E[foo!=bar]</b> attribute "foo" does not equal "bar"</li>
12031 </ul>
12032 <h4>Pseudo Classes:</h4>
12033 <ul class="list">
12034     <li> <b>E:first-child</b> E is the first child of its parent</li>
12035     <li> <b>E:last-child</b> E is the last child of its parent</li>
12036     <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>
12037     <li> <b>E:nth-child(odd)</b> E is an odd child of its parent</li>
12038     <li> <b>E:nth-child(even)</b> E is an even child of its parent</li>
12039     <li> <b>E:only-child</b> E is the only child of its parent</li>
12040     <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>
12041     <li> <b>E:first</b> the first E in the resultset</li>
12042     <li> <b>E:last</b> the last E in the resultset</li>
12043     <li> <b>E:nth(<i>n</i>)</b> the <i>n</i>th E in the resultset (1 based)</li>
12044     <li> <b>E:odd</b> shortcut for :nth-child(odd)</li>
12045     <li> <b>E:even</b> shortcut for :nth-child(even)</li>
12046     <li> <b>E:contains(foo)</b> E's innerHTML contains the substring "foo"</li>
12047     <li> <b>E:nodeValue(foo)</b> E contains a textNode with a nodeValue that equals "foo"</li>
12048     <li> <b>E:not(S)</b> an E element that does not match simple selector S</li>
12049     <li> <b>E:has(S)</b> an E element that has a descendent that matches simple selector S</li>
12050     <li> <b>E:next(S)</b> an E element whose next sibling matches simple selector S</li>
12051     <li> <b>E:prev(S)</b> an E element whose previous sibling matches simple selector S</li>
12052     <li> <b>E:any(S1|S2|S2)</b> an E element which matches any of the simple selectors S1, S2 or S3//\\</li>
12053 </ul>
12054 <h4>CSS Value Selectors:</h4>
12055 <ul class="list">
12056     <li> <b>E{display=none}</b> css value "display" that equals "none"</li>
12057     <li> <b>E{display^=none}</b> css value "display" that starts with "none"</li>
12058     <li> <b>E{display$=none}</b> css value "display" that ends with "none"</li>
12059     <li> <b>E{display*=none}</b> css value "display" that contains the substring "none"</li>
12060     <li> <b>E{display%=2}</b> css value "display" that is evenly divisible by 2</li>
12061     <li> <b>E{display!=none}</b> css value "display" that does not equal "none"</li>
12062 </ul>
12063  * @singleton
12064  */
12065 Ext.ns('Ext.core');
12066
12067 Ext.core.DomQuery = Ext.DomQuery = function(){
12068     var cache = {},
12069         simpleCache = {},
12070         valueCache = {},
12071         nonSpace = /\S/,
12072         trimRe = /^\s+|\s+$/g,
12073         tplRe = /\{(\d+)\}/g,
12074         modeRe = /^(\s?[\/>+~]\s?|\s|$)/,
12075         tagTokenRe = /^(#)?([\w-\*]+)/,
12076         nthRe = /(\d*)n\+?(\d*)/,
12077         nthRe2 = /\D/,
12078         startIdRe = /^\s*\#/,
12079         // This is for IE MSXML which does not support expandos.
12080     // IE runs the same speed using setAttribute, however FF slows way down
12081     // and Safari completely fails so they need to continue to use expandos.
12082     isIE = window.ActiveXObject ? true : false,
12083     key = 30803;
12084
12085     // this eval is stop the compressor from
12086     // renaming the variable to something shorter
12087     eval("var batch = 30803;");
12088
12089     // Retrieve the child node from a particular
12090     // parent at the specified index.
12091     function child(parent, index){
12092         var i = 0,
12093             n = parent.firstChild;
12094         while(n){
12095             if(n.nodeType == 1){
12096                if(++i == index){
12097                    return n;
12098                }
12099             }
12100             n = n.nextSibling;
12101         }
12102         return null;
12103     }
12104
12105     // retrieve the next element node
12106     function next(n){
12107         while((n = n.nextSibling) && n.nodeType != 1);
12108         return n;
12109     }
12110
12111     // retrieve the previous element node
12112     function prev(n){
12113         while((n = n.previousSibling) && n.nodeType != 1);
12114         return n;
12115     }
12116
12117     // Mark each child node with a nodeIndex skipping and
12118     // removing empty text nodes.
12119     function children(parent){
12120         var n = parent.firstChild,
12121         nodeIndex = -1,
12122         nextNode;
12123         while(n){
12124             nextNode = n.nextSibling;
12125             // clean worthless empty nodes.
12126             if(n.nodeType == 3 && !nonSpace.test(n.nodeValue)){
12127             parent.removeChild(n);
12128             }else{
12129             // add an expando nodeIndex
12130             n.nodeIndex = ++nodeIndex;
12131             }
12132             n = nextNode;
12133         }
12134         return this;
12135     }
12136
12137
12138     // nodeSet - array of nodes
12139     // cls - CSS Class
12140     function byClassName(nodeSet, cls){
12141         if(!cls){
12142             return nodeSet;
12143         }
12144         var result = [], ri = -1;
12145         for(var i = 0, ci; ci = nodeSet[i]; i++){
12146             if((' '+ci.className+' ').indexOf(cls) != -1){
12147                 result[++ri] = ci;
12148             }
12149         }
12150         return result;
12151     };
12152
12153     function attrValue(n, attr){
12154         // if its an array, use the first node.
12155         if(!n.tagName && typeof n.length != "undefined"){
12156             n = n[0];
12157         }
12158         if(!n){
12159             return null;
12160         }
12161
12162         if(attr == "for"){
12163             return n.htmlFor;
12164         }
12165         if(attr == "class" || attr == "className"){
12166             return n.className;
12167         }
12168         return n.getAttribute(attr) || n[attr];
12169
12170     };
12171
12172
12173     // ns - nodes
12174     // mode - false, /, >, +, ~
12175     // tagName - defaults to "*"
12176     function getNodes(ns, mode, tagName){
12177         var result = [], ri = -1, cs;
12178         if(!ns){
12179             return result;
12180         }
12181         tagName = tagName || "*";
12182         // convert to array
12183         if(typeof ns.getElementsByTagName != "undefined"){
12184             ns = [ns];
12185         }
12186
12187         // no mode specified, grab all elements by tagName
12188         // at any depth
12189         if(!mode){
12190             for(var i = 0, ni; ni = ns[i]; i++){
12191                 cs = ni.getElementsByTagName(tagName);
12192                 for(var j = 0, ci; ci = cs[j]; j++){
12193                     result[++ri] = ci;
12194                 }
12195             }
12196         // Direct Child mode (/ or >)
12197         // E > F or E/F all direct children elements of E that have the tag
12198         } else if(mode == "/" || mode == ">"){
12199             var utag = tagName.toUpperCase();
12200             for(var i = 0, ni, cn; ni = ns[i]; i++){
12201                 cn = ni.childNodes;
12202                 for(var j = 0, cj; cj = cn[j]; j++){
12203                     if(cj.nodeName == utag || cj.nodeName == tagName  || tagName == '*'){
12204                         result[++ri] = cj;
12205                     }
12206                 }
12207             }
12208         // Immediately Preceding mode (+)
12209         // E + F all elements with the tag F that are immediately preceded by an element with the tag E
12210         }else if(mode == "+"){
12211             var utag = tagName.toUpperCase();
12212             for(var i = 0, n; n = ns[i]; i++){
12213                 while((n = n.nextSibling) && n.nodeType != 1);
12214                 if(n && (n.nodeName == utag || n.nodeName == tagName || tagName == '*')){
12215                     result[++ri] = n;
12216                 }
12217             }
12218         // Sibling mode (~)
12219         // E ~ F all elements with the tag F that are preceded by a sibling element with the tag E
12220         }else if(mode == "~"){
12221             var utag = tagName.toUpperCase();
12222             for(var i = 0, n; n = ns[i]; i++){
12223                 while((n = n.nextSibling)){
12224                     if (n.nodeName == utag || n.nodeName == tagName || tagName == '*'){
12225                         result[++ri] = n;
12226                     }
12227                 }
12228             }
12229         }
12230         return result;
12231     }
12232
12233     function concat(a, b){
12234         if(b.slice){
12235             return a.concat(b);
12236         }
12237         for(var i = 0, l = b.length; i < l; i++){
12238             a[a.length] = b[i];
12239         }
12240         return a;
12241     }
12242
12243     function byTag(cs, tagName){
12244         if(cs.tagName || cs == document){
12245             cs = [cs];
12246         }
12247         if(!tagName){
12248             return cs;
12249         }
12250         var result = [], ri = -1;
12251         tagName = tagName.toLowerCase();
12252         for(var i = 0, ci; ci = cs[i]; i++){
12253             if(ci.nodeType == 1 && ci.tagName.toLowerCase() == tagName){
12254                 result[++ri] = ci;
12255             }
12256         }
12257         return result;
12258     }
12259
12260     function byId(cs, id){
12261         if(cs.tagName || cs == document){
12262             cs = [cs];
12263         }
12264         if(!id){
12265             return cs;
12266         }
12267         var result = [], ri = -1;
12268         for(var i = 0, ci; ci = cs[i]; i++){
12269             if(ci && ci.id == id){
12270                 result[++ri] = ci;
12271                 return result;
12272             }
12273         }
12274         return result;
12275     }
12276
12277     // operators are =, !=, ^=, $=, *=, %=, |= and ~=
12278     // custom can be "{"
12279     function byAttribute(cs, attr, value, op, custom){
12280         var result = [],
12281             ri = -1,
12282             useGetStyle = custom == "{",
12283             fn = Ext.DomQuery.operators[op],
12284             a,
12285             xml,
12286             hasXml;
12287
12288         for(var i = 0, ci; ci = cs[i]; i++){
12289             // skip non-element nodes.
12290             if(ci.nodeType != 1){
12291                 continue;
12292             }
12293             // only need to do this for the first node
12294             if(!hasXml){
12295                 xml = Ext.DomQuery.isXml(ci);
12296                 hasXml = true;
12297             }
12298
12299             // we only need to change the property names if we're dealing with html nodes, not XML
12300             if(!xml){
12301                 if(useGetStyle){
12302                     a = Ext.DomQuery.getStyle(ci, attr);
12303                 } else if (attr == "class" || attr == "className"){
12304                     a = ci.className;
12305                 } else if (attr == "for"){
12306                     a = ci.htmlFor;
12307                 } else if (attr == "href"){
12308                     // getAttribute href bug
12309                     // http://www.glennjones.net/Post/809/getAttributehrefbug.htm
12310                     a = ci.getAttribute("href", 2);
12311                 } else{
12312                     a = ci.getAttribute(attr);
12313                 }
12314             }else{
12315                 a = ci.getAttribute(attr);
12316             }
12317             if((fn && fn(a, value)) || (!fn && a)){
12318                 result[++ri] = ci;
12319             }
12320         }
12321         return result;
12322     }
12323
12324     function byPseudo(cs, name, value){
12325         return Ext.DomQuery.pseudos[name](cs, value);
12326     }
12327
12328     function nodupIEXml(cs){
12329         var d = ++key,
12330             r;
12331         cs[0].setAttribute("_nodup", d);
12332         r = [cs[0]];
12333         for(var i = 1, len = cs.length; i < len; i++){
12334             var c = cs[i];
12335             if(!c.getAttribute("_nodup") != d){
12336                 c.setAttribute("_nodup", d);
12337                 r[r.length] = c;
12338             }
12339         }
12340         for(var i = 0, len = cs.length; i < len; i++){
12341             cs[i].removeAttribute("_nodup");
12342         }
12343         return r;
12344     }
12345
12346     function nodup(cs){
12347         if(!cs){
12348             return [];
12349         }
12350         var len = cs.length, c, i, r = cs, cj, ri = -1;
12351         if(!len || typeof cs.nodeType != "undefined" || len == 1){
12352             return cs;
12353         }
12354         if(isIE && typeof cs[0].selectSingleNode != "undefined"){
12355             return nodupIEXml(cs);
12356         }
12357         var d = ++key;
12358         cs[0]._nodup = d;
12359         for(i = 1; c = cs[i]; i++){
12360             if(c._nodup != d){
12361                 c._nodup = d;
12362             }else{
12363                 r = [];
12364                 for(var j = 0; j < i; j++){
12365                     r[++ri] = cs[j];
12366                 }
12367                 for(j = i+1; cj = cs[j]; j++){
12368                     if(cj._nodup != d){
12369                         cj._nodup = d;
12370                         r[++ri] = cj;
12371                     }
12372                 }
12373                 return r;
12374             }
12375         }
12376         return r;
12377     }
12378
12379     function quickDiffIEXml(c1, c2){
12380         var d = ++key,
12381             r = [];
12382         for(var i = 0, len = c1.length; i < len; i++){
12383             c1[i].setAttribute("_qdiff", d);
12384         }
12385         for(var i = 0, len = c2.length; i < len; i++){
12386             if(c2[i].getAttribute("_qdiff") != d){
12387                 r[r.length] = c2[i];
12388             }
12389         }
12390         for(var i = 0, len = c1.length; i < len; i++){
12391            c1[i].removeAttribute("_qdiff");
12392         }
12393         return r;
12394     }
12395
12396     function quickDiff(c1, c2){
12397         var len1 = c1.length,
12398             d = ++key,
12399             r = [];
12400         if(!len1){
12401             return c2;
12402         }
12403         if(isIE && typeof c1[0].selectSingleNode != "undefined"){
12404             return quickDiffIEXml(c1, c2);
12405         }
12406         for(var i = 0; i < len1; i++){
12407             c1[i]._qdiff = d;
12408         }
12409         for(var i = 0, len = c2.length; i < len; i++){
12410             if(c2[i]._qdiff != d){
12411                 r[r.length] = c2[i];
12412             }
12413         }
12414         return r;
12415     }
12416
12417     function quickId(ns, mode, root, id){
12418         if(ns == root){
12419            var d = root.ownerDocument || root;
12420            return d.getElementById(id);
12421         }
12422         ns = getNodes(ns, mode, "*");
12423         return byId(ns, id);
12424     }
12425
12426     return {
12427         getStyle : function(el, name){
12428             return Ext.fly(el).getStyle(name);
12429         },
12430         /**
12431          * Compiles a selector/xpath query into a reusable function. The returned function
12432          * takes one parameter "root" (optional), which is the context node from where the query should start.
12433          * @param {String} selector The selector/xpath query
12434          * @param {String} type (optional) Either "select" (the default) or "simple" for a simple selector match
12435          * @return {Function}
12436          */
12437         compile : function(path, type){
12438             type = type || "select";
12439
12440             // setup fn preamble
12441             var fn = ["var f = function(root){\n var mode; ++batch; var n = root || document;\n"],
12442                 mode,
12443                 lastPath,
12444                 matchers = Ext.DomQuery.matchers,
12445                 matchersLn = matchers.length,
12446                 modeMatch,
12447                 // accept leading mode switch
12448                 lmode = path.match(modeRe);
12449
12450             if(lmode && lmode[1]){
12451                 fn[fn.length] = 'mode="'+lmode[1].replace(trimRe, "")+'";';
12452                 path = path.replace(lmode[1], "");
12453             }
12454
12455             // strip leading slashes
12456             while(path.substr(0, 1)=="/"){
12457                 path = path.substr(1);
12458             }
12459
12460             while(path && lastPath != path){
12461                 lastPath = path;
12462                 var tokenMatch = path.match(tagTokenRe);
12463                 if(type == "select"){
12464                     if(tokenMatch){
12465                         // ID Selector
12466                         if(tokenMatch[1] == "#"){
12467                             fn[fn.length] = 'n = quickId(n, mode, root, "'+tokenMatch[2]+'");';
12468                         }else{
12469                             fn[fn.length] = 'n = getNodes(n, mode, "'+tokenMatch[2]+'");';
12470                         }
12471                         path = path.replace(tokenMatch[0], "");
12472                     }else if(path.substr(0, 1) != '@'){
12473                         fn[fn.length] = 'n = getNodes(n, mode, "*");';
12474                     }
12475                 // type of "simple"
12476                 }else{
12477                     if(tokenMatch){
12478                         if(tokenMatch[1] == "#"){
12479                             fn[fn.length] = 'n = byId(n, "'+tokenMatch[2]+'");';
12480                         }else{
12481                             fn[fn.length] = 'n = byTag(n, "'+tokenMatch[2]+'");';
12482                         }
12483                         path = path.replace(tokenMatch[0], "");
12484                     }
12485                 }
12486                 while(!(modeMatch = path.match(modeRe))){
12487                     var matched = false;
12488                     for(var j = 0; j < matchersLn; j++){
12489                         var t = matchers[j];
12490                         var m = path.match(t.re);
12491                         if(m){
12492                             fn[fn.length] = t.select.replace(tplRe, function(x, i){
12493                                 return m[i];
12494                             });
12495                             path = path.replace(m[0], "");
12496                             matched = true;
12497                             break;
12498                         }
12499                     }
12500                     // prevent infinite loop on bad selector
12501                     if(!matched){
12502                         Ext.Error.raise({
12503                             sourceClass: 'Ext.DomQuery',
12504                             sourceMethod: 'compile',
12505                             msg: 'Error parsing selector. Parsing failed at "' + path + '"'
12506                         });
12507                     }
12508                 }
12509                 if(modeMatch[1]){
12510                     fn[fn.length] = 'mode="'+modeMatch[1].replace(trimRe, "")+'";';
12511                     path = path.replace(modeMatch[1], "");
12512                 }
12513             }
12514             // close fn out
12515             fn[fn.length] = "return nodup(n);\n}";
12516
12517             // eval fn and return it
12518             eval(fn.join(""));
12519             return f;
12520         },
12521
12522         /**
12523          * Selects an array of DOM nodes using JavaScript-only implementation.
12524          *
12525          * Use {@link #select} to take advantage of browsers built-in support for CSS selectors.
12526          *
12527          * @param {String} selector The selector/xpath query (can be a comma separated list of selectors)
12528          * @param {HTMLElement/String} root (optional) The start of the query (defaults to document).
12529          * @return {HTMLElement[]} An Array of DOM elements which match the selector. If there are
12530          * no matches, and empty Array is returned.
12531          */
12532         jsSelect: function(path, root, type){
12533             // set root to doc if not specified.
12534             root = root || document;
12535
12536             if(typeof root == "string"){
12537                 root = document.getElementById(root);
12538             }
12539             var paths = path.split(","),
12540                 results = [];
12541
12542             // loop over each selector
12543             for(var i = 0, len = paths.length; i < len; i++){
12544                 var subPath = paths[i].replace(trimRe, "");
12545                 // compile and place in cache
12546                 if(!cache[subPath]){
12547                     cache[subPath] = Ext.DomQuery.compile(subPath);
12548                     if(!cache[subPath]){
12549                         Ext.Error.raise({
12550                             sourceClass: 'Ext.DomQuery',
12551                             sourceMethod: 'jsSelect',
12552                             msg: subPath + ' is not a valid selector'
12553                         });
12554                     }
12555                 }
12556                 var result = cache[subPath](root);
12557                 if(result && result != document){
12558                     results = results.concat(result);
12559                 }
12560             }
12561
12562             // if there were multiple selectors, make sure dups
12563             // are eliminated
12564             if(paths.length > 1){
12565                 return nodup(results);
12566             }
12567             return results;
12568         },
12569
12570         isXml: function(el) {
12571             var docEl = (el ? el.ownerDocument || el : 0).documentElement;
12572             return docEl ? docEl.nodeName !== "HTML" : false;
12573         },
12574
12575         /**
12576          * Selects an array of DOM nodes by CSS/XPath selector.
12577          *
12578          * Uses [document.querySelectorAll][0] if browser supports that, otherwise falls back to
12579          * {@link Ext.DomQuery#jsSelect} to do the work.
12580          *
12581          * Aliased as {@link Ext#query}.
12582          *
12583          * [0]: https://developer.mozilla.org/en/DOM/document.querySelectorAll
12584          *
12585          * @param {String} path The selector/xpath query
12586          * @param {HTMLElement} root (optional) The start of the query (defaults to document).
12587          * @return {HTMLElement[]} An array of DOM elements (not a NodeList as returned by `querySelectorAll`).
12588          * Empty array when no matches.
12589          * @method
12590          */
12591         select : document.querySelectorAll ? function(path, root, type) {
12592             root = root || document;
12593             /* 
12594              * Safari 3.x can't handle uppercase or unicode characters when in quirks mode.
12595              */
12596             if (!Ext.DomQuery.isXml(root) && !(Ext.isSafari3 && !Ext.isStrict)) { 
12597                 try {
12598                     /*
12599                      * This checking here is to "fix" the behaviour of querySelectorAll
12600                      * for non root document queries. The way qsa works is intentional,
12601                      * however it's definitely not the expected way it should work.
12602                      * More info: http://ejohn.org/blog/thoughts-on-queryselectorall/
12603                      *
12604                      * We only modify the path for single selectors (ie, no multiples),
12605                      * without a full parser it makes it difficult to do this correctly.
12606                      */
12607                     var isDocumentRoot = root.nodeType === 9,
12608                         _path = path,
12609                         _root = root;
12610
12611                     if (!isDocumentRoot && path.indexOf(',') === -1 && !startIdRe.test(path)) {
12612                         _path = '#' + Ext.id(root) + ' ' + path;
12613                         _root = root.parentNode;
12614                     }
12615                     return Ext.Array.toArray(_root.querySelectorAll(_path));
12616                 }
12617                 catch (e) {
12618                 }
12619             }
12620             return Ext.DomQuery.jsSelect.call(this, path, root, type);
12621         } : function(path, root, type) {
12622             return Ext.DomQuery.jsSelect.call(this, path, root, type);
12623         },
12624
12625         /**
12626          * Selects a single element.
12627          * @param {String} selector The selector/xpath query
12628          * @param {HTMLElement} root (optional) The start of the query (defaults to document).
12629          * @return {HTMLElement} The DOM element which matched the selector.
12630          */
12631         selectNode : function(path, root){
12632             return Ext.DomQuery.select(path, root)[0];
12633         },
12634
12635         /**
12636          * Selects the value of a node, optionally replacing null with the defaultValue.
12637          * @param {String} selector The selector/xpath query
12638          * @param {HTMLElement} root (optional) The start of the query (defaults to document).
12639          * @param {String} defaultValue (optional) When specified, this is return as empty value.
12640          * @return {String}
12641          */
12642         selectValue : function(path, root, defaultValue){
12643             path = path.replace(trimRe, "");
12644             if(!valueCache[path]){
12645                 valueCache[path] = Ext.DomQuery.compile(path, "select");
12646             }
12647             var n = valueCache[path](root), v;
12648             n = n[0] ? n[0] : n;
12649
12650             // overcome a limitation of maximum textnode size
12651             // Rumored to potentially crash IE6 but has not been confirmed.
12652             // http://reference.sitepoint.com/javascript/Node/normalize
12653             // https://developer.mozilla.org/En/DOM/Node.normalize
12654             if (typeof n.normalize == 'function') n.normalize();
12655
12656             v = (n && n.firstChild ? n.firstChild.nodeValue : null);
12657             return ((v === null||v === undefined||v==='') ? defaultValue : v);
12658         },
12659
12660         /**
12661          * Selects the value of a node, parsing integers and floats. Returns the defaultValue, or 0 if none is specified.
12662          * @param {String} selector The selector/xpath query
12663          * @param {HTMLElement} root (optional) The start of the query (defaults to document).
12664          * @param {Number} defaultValue (optional) When specified, this is return as empty value.
12665          * @return {Number}
12666          */
12667         selectNumber : function(path, root, defaultValue){
12668             var v = Ext.DomQuery.selectValue(path, root, defaultValue || 0);
12669             return parseFloat(v);
12670         },
12671
12672         /**
12673          * Returns true if the passed element(s) match the passed simple selector (e.g. div.some-class or span:first-child)
12674          * @param {String/HTMLElement/HTMLElement[]} el An element id, element or array of elements
12675          * @param {String} selector The simple selector to test
12676          * @return {Boolean}
12677          */
12678         is : function(el, ss){
12679             if(typeof el == "string"){
12680                 el = document.getElementById(el);
12681             }
12682             var isArray = Ext.isArray(el),
12683                 result = Ext.DomQuery.filter(isArray ? el : [el], ss);
12684             return isArray ? (result.length == el.length) : (result.length > 0);
12685         },
12686
12687         /**
12688          * Filters an array of elements to only include matches of a simple selector (e.g. div.some-class or span:first-child)
12689          * @param {HTMLElement[]} el An array of elements to filter
12690          * @param {String} selector The simple selector to test
12691          * @param {Boolean} nonMatches If true, it returns the elements that DON'T match
12692          * the selector instead of the ones that match
12693          * @return {HTMLElement[]} An Array of DOM elements which match the selector. If there are
12694          * no matches, and empty Array is returned.
12695          */
12696         filter : function(els, ss, nonMatches){
12697             ss = ss.replace(trimRe, "");
12698             if(!simpleCache[ss]){
12699                 simpleCache[ss] = Ext.DomQuery.compile(ss, "simple");
12700             }
12701             var result = simpleCache[ss](els);
12702             return nonMatches ? quickDiff(result, els) : result;
12703         },
12704
12705         /**
12706          * Collection of matching regular expressions and code snippets.
12707          * Each capture group within () will be replace the {} in the select
12708          * statement as specified by their index.
12709          */
12710         matchers : [{
12711                 re: /^\.([\w-]+)/,
12712                 select: 'n = byClassName(n, " {1} ");'
12713             }, {
12714                 re: /^\:([\w-]+)(?:\(((?:[^\s>\/]*|.*?))\))?/,
12715                 select: 'n = byPseudo(n, "{1}", "{2}");'
12716             },{
12717                 re: /^(?:([\[\{])(?:@)?([\w-]+)\s?(?:(=|.=)\s?['"]?(.*?)["']?)?[\]\}])/,
12718                 select: 'n = byAttribute(n, "{2}", "{4}", "{3}", "{1}");'
12719             }, {
12720                 re: /^#([\w-]+)/,
12721                 select: 'n = byId(n, "{1}");'
12722             },{
12723                 re: /^@([\w-]+)/,
12724                 select: 'return {firstChild:{nodeValue:attrValue(n, "{1}")}};'
12725             }
12726         ],
12727
12728         /**
12729          * Collection of operator comparison functions. The default operators are =, !=, ^=, $=, *=, %=, |= and ~=.
12730          * 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;.
12731          */
12732         operators : {
12733             "=" : function(a, v){
12734                 return a == v;
12735             },
12736             "!=" : function(a, v){
12737                 return a != v;
12738             },
12739             "^=" : function(a, v){
12740                 return a && a.substr(0, v.length) == v;
12741             },
12742             "$=" : function(a, v){
12743                 return a && a.substr(a.length-v.length) == v;
12744             },
12745             "*=" : function(a, v){
12746                 return a && a.indexOf(v) !== -1;
12747             },
12748             "%=" : function(a, v){
12749                 return (a % v) == 0;
12750             },
12751             "|=" : function(a, v){
12752                 return a && (a == v || a.substr(0, v.length+1) == v+'-');
12753             },
12754             "~=" : function(a, v){
12755                 return a && (' '+a+' ').indexOf(' '+v+' ') != -1;
12756             }
12757         },
12758
12759         /**
12760 Object hash of "pseudo class" filter functions which are used when filtering selections.
12761 Each function is passed two parameters:
12762
12763 - **c** : Array
12764     An Array of DOM elements to filter.
12765
12766 - **v** : String
12767     The argument (if any) supplied in the selector.
12768
12769 A filter function returns an Array of DOM elements which conform to the pseudo class.
12770 In addition to the provided pseudo classes listed above such as `first-child` and `nth-child`,
12771 developers may add additional, custom psuedo class filters to select elements according to application-specific requirements.
12772
12773 For example, to filter `a` elements to only return links to __external__ resources:
12774
12775     Ext.DomQuery.pseudos.external = function(c, v){
12776         var r = [], ri = -1;
12777         for(var i = 0, ci; ci = c[i]; i++){
12778             // Include in result set only if it's a link to an external resource
12779             if(ci.hostname != location.hostname){
12780                 r[++ri] = ci;
12781             }
12782         }
12783         return r;
12784     };
12785
12786 Then external links could be gathered with the following statement:
12787
12788     var externalLinks = Ext.select("a:external");
12789
12790         * @markdown
12791         */
12792         pseudos : {
12793             "first-child" : function(c){
12794                 var r = [], ri = -1, n;
12795                 for(var i = 0, ci; ci = n = c[i]; i++){
12796                     while((n = n.previousSibling) && n.nodeType != 1);
12797                     if(!n){
12798                         r[++ri] = ci;
12799                     }
12800                 }
12801                 return r;
12802             },
12803
12804             "last-child" : function(c){
12805                 var r = [], ri = -1, n;
12806                 for(var i = 0, ci; ci = n = c[i]; i++){
12807                     while((n = n.nextSibling) && n.nodeType != 1);
12808                     if(!n){
12809                         r[++ri] = ci;
12810                     }
12811                 }
12812                 return r;
12813             },
12814
12815             "nth-child" : function(c, a) {
12816                 var r = [], ri = -1,
12817                     m = nthRe.exec(a == "even" && "2n" || a == "odd" && "2n+1" || !nthRe2.test(a) && "n+" + a || a),
12818                     f = (m[1] || 1) - 0, l = m[2] - 0;
12819                 for(var i = 0, n; n = c[i]; i++){
12820                     var pn = n.parentNode;
12821                     if (batch != pn._batch) {
12822                         var j = 0;
12823                         for(var cn = pn.firstChild; cn; cn = cn.nextSibling){
12824                             if(cn.nodeType == 1){
12825                                cn.nodeIndex = ++j;
12826                             }
12827                         }
12828                         pn._batch = batch;
12829                     }
12830                     if (f == 1) {
12831                         if (l == 0 || n.nodeIndex == l){
12832                             r[++ri] = n;
12833                         }
12834                     } else if ((n.nodeIndex + l) % f == 0){
12835                         r[++ri] = n;
12836                     }
12837                 }
12838
12839                 return r;
12840             },
12841
12842             "only-child" : function(c){
12843                 var r = [], ri = -1;;
12844                 for(var i = 0, ci; ci = c[i]; i++){
12845                     if(!prev(ci) && !next(ci)){
12846                         r[++ri] = ci;
12847                     }
12848                 }
12849                 return r;
12850             },
12851
12852             "empty" : function(c){
12853                 var r = [], ri = -1;
12854                 for(var i = 0, ci; ci = c[i]; i++){
12855                     var cns = ci.childNodes, j = 0, cn, empty = true;
12856                     while(cn = cns[j]){
12857                         ++j;
12858                         if(cn.nodeType == 1 || cn.nodeType == 3){
12859                             empty = false;
12860                             break;
12861                         }
12862                     }
12863                     if(empty){
12864                         r[++ri] = ci;
12865                     }
12866                 }
12867                 return r;
12868             },
12869
12870             "contains" : function(c, v){
12871                 var r = [], ri = -1;
12872                 for(var i = 0, ci; ci = c[i]; i++){
12873                     if((ci.textContent||ci.innerText||'').indexOf(v) != -1){
12874                         r[++ri] = ci;
12875                     }
12876                 }
12877                 return r;
12878             },
12879
12880             "nodeValue" : function(c, v){
12881                 var r = [], ri = -1;
12882                 for(var i = 0, ci; ci = c[i]; i++){
12883                     if(ci.firstChild && ci.firstChild.nodeValue == v){
12884                         r[++ri] = ci;
12885                     }
12886                 }
12887                 return r;
12888             },
12889
12890             "checked" : function(c){
12891                 var r = [], ri = -1;
12892                 for(var i = 0, ci; ci = c[i]; i++){
12893                     if(ci.checked == true){
12894                         r[++ri] = ci;
12895                     }
12896                 }
12897                 return r;
12898             },
12899
12900             "not" : function(c, ss){
12901                 return Ext.DomQuery.filter(c, ss, true);
12902             },
12903
12904             "any" : function(c, selectors){
12905                 var ss = selectors.split('|'),
12906                     r = [], ri = -1, s;
12907                 for(var i = 0, ci; ci = c[i]; i++){
12908                     for(var j = 0; s = ss[j]; j++){
12909                         if(Ext.DomQuery.is(ci, s)){
12910                             r[++ri] = ci;
12911                             break;
12912                         }
12913                     }
12914                 }
12915                 return r;
12916             },
12917
12918             "odd" : function(c){
12919                 return this["nth-child"](c, "odd");
12920             },
12921
12922             "even" : function(c){
12923                 return this["nth-child"](c, "even");
12924             },
12925
12926             "nth" : function(c, a){
12927                 return c[a-1] || [];
12928             },
12929
12930             "first" : function(c){
12931                 return c[0] || [];
12932             },
12933
12934             "last" : function(c){
12935                 return c[c.length-1] || [];
12936             },
12937
12938             "has" : function(c, ss){
12939                 var s = Ext.DomQuery.select,
12940                     r = [], ri = -1;
12941                 for(var i = 0, ci; ci = c[i]; i++){
12942                     if(s(ss, ci).length > 0){
12943                         r[++ri] = ci;
12944                     }
12945                 }
12946                 return r;
12947             },
12948
12949             "next" : function(c, ss){
12950                 var is = Ext.DomQuery.is,
12951                     r = [], ri = -1;
12952                 for(var i = 0, ci; ci = c[i]; i++){
12953                     var n = next(ci);
12954                     if(n && is(n, ss)){
12955                         r[++ri] = ci;
12956                     }
12957                 }
12958                 return r;
12959             },
12960
12961             "prev" : function(c, ss){
12962                 var is = Ext.DomQuery.is,
12963                     r = [], ri = -1;
12964                 for(var i = 0, ci; ci = c[i]; i++){
12965                     var n = prev(ci);
12966                     if(n && is(n, ss)){
12967                         r[++ri] = ci;
12968                     }
12969                 }
12970                 return r;
12971             }
12972         }
12973     };
12974 }();
12975
12976 /**
12977  * Shorthand of {@link Ext.DomQuery#select}
12978  * @member Ext
12979  * @method query
12980  * @alias Ext.DomQuery#select
12981  */
12982 Ext.query = Ext.DomQuery.select;
12983
12984 /**
12985  * @class Ext.Element
12986  * @alternateClassName Ext.core.Element
12987  *
12988  * Encapsulates a DOM element, adding simple DOM manipulation facilities, normalizing for browser differences.
12989  *
12990  * All instances of this class inherit the methods of {@link Ext.fx.Anim} making visual effects easily available to all
12991  * DOM elements.
12992  *
12993  * Note that the events documented in this class are not Ext events, they encapsulate browser events. Some older browsers
12994  * may not support the full range of events. Which events are supported is beyond the control of Ext JS.
12995  *
12996  * Usage:
12997  *
12998  *     // by id
12999  *     var el = Ext.get("my-div");
13000  *
13001  *     // by DOM element reference
13002  *     var el = Ext.get(myDivElement);
13003  *
13004  * # Animations
13005  *
13006  * When an element is manipulated, by default there is no animation.
13007  *
13008  *     var el = Ext.get("my-div");
13009  *
13010  *     // no animation
13011  *     el.setWidth(100);
13012  *
13013  * Many of the functions for manipulating an element have an optional "animate" parameter. This parameter can be
13014  * specified as boolean (true) for default animation effects.
13015  *
13016  *     // default animation
13017  *     el.setWidth(100, true);
13018  *
13019  * To configure the effects, an object literal with animation options to use as the Element animation configuration
13020  * object can also be specified. Note that the supported Element animation configuration options are a subset of the
13021  * {@link Ext.fx.Anim} animation options specific to Fx effects. The supported Element animation configuration options
13022  * are:
13023  *
13024  *     Option    Default   Description
13025  *     --------- --------  ---------------------------------------------
13026  *     {@link Ext.fx.Anim#duration duration}  .35       The duration of the animation in seconds
13027  *     {@link Ext.fx.Anim#easing easing}    easeOut   The easing method
13028  *     {@link Ext.fx.Anim#callback callback}  none      A function to execute when the anim completes
13029  *     {@link Ext.fx.Anim#scope scope}     this      The scope (this) of the callback function
13030  *
13031  * Usage:
13032  *
13033  *     // Element animation options object
13034  *     var opt = {
13035  *         {@link Ext.fx.Anim#duration duration}: 1,
13036  *         {@link Ext.fx.Anim#easing easing}: 'elasticIn',
13037  *         {@link Ext.fx.Anim#callback callback}: this.foo,
13038  *         {@link Ext.fx.Anim#scope scope}: this
13039  *     };
13040  *     // animation with some options set
13041  *     el.setWidth(100, opt);
13042  *
13043  * The Element animation object being used for the animation will be set on the options object as "anim", which allows
13044  * you to stop or manipulate the animation. Here is an example:
13045  *
13046  *     // using the "anim" property to get the Anim object
13047  *     if(opt.anim.isAnimated()){
13048  *         opt.anim.stop();
13049  *     }
13050  *
13051  * # Composite (Collections of) Elements
13052  *
13053  * For working with collections of Elements, see {@link Ext.CompositeElement}
13054  *
13055  * @constructor
13056  * Creates new Element directly.
13057  * @param {String/HTMLElement} element
13058  * @param {Boolean} forceNew (optional) By default the constructor checks to see if there is already an instance of this
13059  * element in the cache and if there is it returns the same instance. This will skip that check (useful for extending
13060  * this class).
13061  * @return {Object}
13062  */
13063  (function() {
13064     var DOC = document,
13065         EC = Ext.cache;
13066
13067     Ext.Element = Ext.core.Element = function(element, forceNew) {
13068         var dom = typeof element == "string" ? DOC.getElementById(element) : element,
13069         id;
13070
13071         if (!dom) {
13072             return null;
13073         }
13074
13075         id = dom.id;
13076
13077         if (!forceNew && id && EC[id]) {
13078             // element object already exists
13079             return EC[id].el;
13080         }
13081
13082         /**
13083          * @property {HTMLElement} dom
13084          * The DOM element
13085          */
13086         this.dom = dom;
13087
13088         /**
13089          * @property {String} id
13090          * The DOM element ID
13091          */
13092         this.id = id || Ext.id(dom);
13093     };
13094
13095     var DH = Ext.DomHelper,
13096     El = Ext.Element;
13097
13098
13099     El.prototype = {
13100         /**
13101          * Sets the passed attributes as attributes of this element (a style attribute can be a string, object or function)
13102          * @param {Object} o The object with the attributes
13103          * @param {Boolean} useSet (optional) false to override the default setAttribute to use expandos.
13104          * @return {Ext.Element} this
13105          */
13106         set: function(o, useSet) {
13107             var el = this.dom,
13108                 attr,
13109                 val;
13110             useSet = (useSet !== false) && !!el.setAttribute;
13111
13112             for (attr in o) {
13113                 if (o.hasOwnProperty(attr)) {
13114                     val = o[attr];
13115                     if (attr == 'style') {
13116                         DH.applyStyles(el, val);
13117                     } else if (attr == 'cls') {
13118                         el.className = val;
13119                     } else if (useSet) {
13120                         el.setAttribute(attr, val);
13121                     } else {
13122                         el[attr] = val;
13123                     }
13124                 }
13125             }
13126             return this;
13127         },
13128
13129         //  Mouse events
13130         /**
13131          * @event click
13132          * Fires when a mouse click is detected within the element.
13133          * @param {Ext.EventObject} e The {@link Ext.EventObject} encapsulating the DOM event.
13134          * @param {HTMLElement} t The target of the event.
13135          */
13136         /**
13137          * @event contextmenu
13138          * Fires when a right click is detected within the element.
13139          * @param {Ext.EventObject} e The {@link Ext.EventObject} encapsulating the DOM event.
13140          * @param {HTMLElement} t The target of the event.
13141          */
13142         /**
13143          * @event dblclick
13144          * Fires when a mouse double click is detected within the element.
13145          * @param {Ext.EventObject} e The {@link Ext.EventObject} encapsulating the DOM event.
13146          * @param {HTMLElement} t The target of the event.
13147          */
13148         /**
13149          * @event mousedown
13150          * Fires when a mousedown is detected within the element.
13151          * @param {Ext.EventObject} e The {@link Ext.EventObject} encapsulating the DOM event.
13152          * @param {HTMLElement} t The target of the event.
13153          */
13154         /**
13155          * @event mouseup
13156          * Fires when a mouseup is detected within the element.
13157          * @param {Ext.EventObject} e The {@link Ext.EventObject} encapsulating the DOM event.
13158          * @param {HTMLElement} t The target of the event.
13159          */
13160         /**
13161          * @event mouseover
13162          * Fires when a mouseover is detected within the element.
13163          * @param {Ext.EventObject} e The {@link Ext.EventObject} encapsulating the DOM event.
13164          * @param {HTMLElement} t The target of the event.
13165          */
13166         /**
13167          * @event mousemove
13168          * Fires when a mousemove is detected with the element.
13169          * @param {Ext.EventObject} e The {@link Ext.EventObject} encapsulating the DOM event.
13170          * @param {HTMLElement} t The target of the event.
13171          */
13172         /**
13173          * @event mouseout
13174          * Fires when a mouseout is detected with the element.
13175          * @param {Ext.EventObject} e The {@link Ext.EventObject} encapsulating the DOM event.
13176          * @param {HTMLElement} t The target of the event.
13177          */
13178         /**
13179          * @event mouseenter
13180          * Fires when the mouse enters the element.
13181          * @param {Ext.EventObject} e The {@link Ext.EventObject} encapsulating the DOM event.
13182          * @param {HTMLElement} t The target of the event.
13183          */
13184         /**
13185          * @event mouseleave
13186          * Fires when the mouse leaves the element.
13187          * @param {Ext.EventObject} e The {@link Ext.EventObject} encapsulating the DOM event.
13188          * @param {HTMLElement} t The target of the event.
13189          */
13190
13191         //  Keyboard events
13192         /**
13193          * @event keypress
13194          * Fires when a keypress is detected within the element.
13195          * @param {Ext.EventObject} e The {@link Ext.EventObject} encapsulating the DOM event.
13196          * @param {HTMLElement} t The target of the event.
13197          */
13198         /**
13199          * @event keydown
13200          * Fires when a keydown is detected within the element.
13201          * @param {Ext.EventObject} e The {@link Ext.EventObject} encapsulating the DOM event.
13202          * @param {HTMLElement} t The target of the event.
13203          */
13204         /**
13205          * @event keyup
13206          * Fires when a keyup is detected within the element.
13207          * @param {Ext.EventObject} e The {@link Ext.EventObject} encapsulating the DOM event.
13208          * @param {HTMLElement} t The target of the event.
13209          */
13210
13211
13212         //  HTML frame/object events
13213         /**
13214          * @event load
13215          * Fires when the user agent finishes loading all content within the element. Only supported by window, frames,
13216          * objects and images.
13217          * @param {Ext.EventObject} e The {@link Ext.EventObject} encapsulating the DOM event.
13218          * @param {HTMLElement} t The target of the event.
13219          */
13220         /**
13221          * @event unload
13222          * Fires when the user agent removes all content from a window or frame. For elements, it fires when the target
13223          * element or any of its content has been removed.
13224          * @param {Ext.EventObject} e The {@link Ext.EventObject} encapsulating the DOM event.
13225          * @param {HTMLElement} t The target of the event.
13226          */
13227         /**
13228          * @event abort
13229          * Fires when an object/image is stopped from loading before completely loaded.
13230          * @param {Ext.EventObject} e The {@link Ext.EventObject} encapsulating the DOM event.
13231          * @param {HTMLElement} t The target of the event.
13232          */
13233         /**
13234          * @event error
13235          * Fires when an object/image/frame cannot be loaded properly.
13236          * @param {Ext.EventObject} e The {@link Ext.EventObject} encapsulating the DOM event.
13237          * @param {HTMLElement} t The target of the event.
13238          */
13239         /**
13240          * @event resize
13241          * Fires when a document view is resized.
13242          * @param {Ext.EventObject} e The {@link Ext.EventObject} encapsulating the DOM event.
13243          * @param {HTMLElement} t The target of the event.
13244          */
13245         /**
13246          * @event scroll
13247          * Fires when a document view is scrolled.
13248          * @param {Ext.EventObject} e The {@link Ext.EventObject} encapsulating the DOM event.
13249          * @param {HTMLElement} t The target of the event.
13250          */
13251
13252         //  Form events
13253         /**
13254          * @event select
13255          * Fires when a user selects some text in a text field, including input and textarea.
13256          * @param {Ext.EventObject} e The {@link Ext.EventObject} encapsulating the DOM event.
13257          * @param {HTMLElement} t The target of the event.
13258          */
13259         /**
13260          * @event change
13261          * Fires when a control loses the input focus and its value has been modified since gaining focus.
13262          * @param {Ext.EventObject} e The {@link Ext.EventObject} encapsulating the DOM event.
13263          * @param {HTMLElement} t The target of the event.
13264          */
13265         /**
13266          * @event submit
13267          * Fires when a form is submitted.
13268          * @param {Ext.EventObject} e The {@link Ext.EventObject} encapsulating the DOM event.
13269          * @param {HTMLElement} t The target of the event.
13270          */
13271         /**
13272          * @event reset
13273          * Fires when a form is reset.
13274          * @param {Ext.EventObject} e The {@link Ext.EventObject} encapsulating the DOM event.
13275          * @param {HTMLElement} t The target of the event.
13276          */
13277         /**
13278          * @event focus
13279          * Fires when an element receives focus either via the pointing device or by tab navigation.
13280          * @param {Ext.EventObject} e The {@link Ext.EventObject} encapsulating the DOM event.
13281          * @param {HTMLElement} t The target of the event.
13282          */
13283         /**
13284          * @event blur
13285          * Fires when an element loses focus either via the pointing device or by tabbing navigation.
13286          * @param {Ext.EventObject} e The {@link Ext.EventObject} encapsulating the DOM event.
13287          * @param {HTMLElement} t The target of the event.
13288          */
13289
13290         //  User Interface events
13291         /**
13292          * @event DOMFocusIn
13293          * Where supported. Similar to HTML focus event, but can be applied to any focusable element.
13294          * @param {Ext.EventObject} e The {@link Ext.EventObject} encapsulating the DOM event.
13295          * @param {HTMLElement} t The target of the event.
13296          */
13297         /**
13298          * @event DOMFocusOut
13299          * Where supported. Similar to HTML blur event, but can be applied to any focusable element.
13300          * @param {Ext.EventObject} e The {@link Ext.EventObject} encapsulating the DOM event.
13301          * @param {HTMLElement} t The target of the event.
13302          */
13303         /**
13304          * @event DOMActivate
13305          * Where supported. Fires when an element is activated, for instance, through a mouse click or a keypress.
13306          * @param {Ext.EventObject} e The {@link Ext.EventObject} encapsulating the DOM event.
13307          * @param {HTMLElement} t The target of the event.
13308          */
13309
13310         //  DOM Mutation events
13311         /**
13312          * @event DOMSubtreeModified
13313          * Where supported. Fires when the subtree is modified.
13314          * @param {Ext.EventObject} e The {@link Ext.EventObject} encapsulating the DOM event.
13315          * @param {HTMLElement} t The target of the event.
13316          */
13317         /**
13318          * @event DOMNodeInserted
13319          * Where supported. Fires when a node has been added as a child of another node.
13320          * @param {Ext.EventObject} e The {@link Ext.EventObject} encapsulating the DOM event.
13321          * @param {HTMLElement} t The target of the event.
13322          */
13323         /**
13324          * @event DOMNodeRemoved
13325          * Where supported. Fires when a descendant node of the element is removed.
13326          * @param {Ext.EventObject} e The {@link Ext.EventObject} encapsulating the DOM event.
13327          * @param {HTMLElement} t The target of the event.
13328          */
13329         /**
13330          * @event DOMNodeRemovedFromDocument
13331          * Where supported. Fires when a node is being removed from a document.
13332          * @param {Ext.EventObject} e The {@link Ext.EventObject} encapsulating the DOM event.
13333          * @param {HTMLElement} t The target of the event.
13334          */
13335         /**
13336          * @event DOMNodeInsertedIntoDocument
13337          * Where supported. Fires when a node is being inserted into a document.
13338          * @param {Ext.EventObject} e The {@link Ext.EventObject} encapsulating the DOM event.
13339          * @param {HTMLElement} t The target of the event.
13340          */
13341         /**
13342          * @event DOMAttrModified
13343          * Where supported. Fires when an attribute has been modified.
13344          * @param {Ext.EventObject} e The {@link Ext.EventObject} encapsulating the DOM event.
13345          * @param {HTMLElement} t The target of the event.
13346          */
13347         /**
13348          * @event DOMCharacterDataModified
13349          * Where supported. Fires when the character data has been modified.
13350          * @param {Ext.EventObject} e The {@link Ext.EventObject} encapsulating the DOM event.
13351          * @param {HTMLElement} t The target of the event.
13352          */
13353
13354         /**
13355          * @property {String} defaultUnit
13356          * The default unit to append to CSS values where a unit isn't provided.
13357          */
13358         defaultUnit: "px",
13359
13360         /**
13361          * Returns true if this element matches the passed simple selector (e.g. div.some-class or span:first-child)
13362          * @param {String} selector The simple selector to test
13363          * @return {Boolean} True if this element matches the selector, else false
13364          */
13365         is: function(simpleSelector) {
13366             return Ext.DomQuery.is(this.dom, simpleSelector);
13367         },
13368
13369         /**
13370          * Tries to focus the element. Any exceptions are caught and ignored.
13371          * @param {Number} defer (optional) Milliseconds to defer the focus
13372          * @return {Ext.Element} this
13373          */
13374         focus: function(defer,
13375                         /* private */
13376                         dom) {
13377             var me = this;
13378             dom = dom || me.dom;
13379             try {
13380                 if (Number(defer)) {
13381                     Ext.defer(me.focus, defer, null, [null, dom]);
13382                 } else {
13383                     dom.focus();
13384                 }
13385             } catch(e) {}
13386             return me;
13387         },
13388
13389         /**
13390          * Tries to blur the element. Any exceptions are caught and ignored.
13391          * @return {Ext.Element} this
13392          */
13393         blur: function() {
13394             try {
13395                 this.dom.blur();
13396             } catch(e) {}
13397             return this;
13398         },
13399
13400         /**
13401          * Returns the value of the "value" attribute
13402          * @param {Boolean} asNumber true to parse the value as a number
13403          * @return {String/Number}
13404          */
13405         getValue: function(asNumber) {
13406             var val = this.dom.value;
13407             return asNumber ? parseInt(val, 10) : val;
13408         },
13409
13410         /**
13411          * Appends an event handler to this element.
13412          *
13413          * @param {String} eventName The name of event to handle.
13414          *
13415          * @param {Function} fn The handler function the event invokes. This function is passed the following parameters:
13416          *
13417          * - **evt** : EventObject
13418          *
13419          *   The {@link Ext.EventObject EventObject} describing the event.
13420          *
13421          * - **el** : HtmlElement
13422          *
13423          *   The DOM element which was the target of the event. Note that this may be filtered by using the delegate option.
13424          *
13425          * - **o** : Object
13426          *
13427          *   The options object from the addListener call.
13428          *
13429          * @param {Object} scope (optional) The scope (**this** reference) in which the handler function is executed. **If
13430          * omitted, defaults to this Element.**
13431          *
13432          * @param {Object} options (optional) An object containing handler configuration properties. This may contain any of
13433          * the following properties:
13434          *
13435          * - **scope** Object :
13436          *
13437          *   The scope (**this** reference) in which the handler function is executed. **If omitted, defaults to this
13438          *   Element.**
13439          *
13440          * - **delegate** String:
13441          *
13442          *   A simple selector to filter the target or look for a descendant of the target. See below for additional details.
13443          *
13444          * - **stopEvent** Boolean:
13445          *
13446          *   True to stop the event. That is stop propagation, and prevent the default action.
13447          *
13448          * - **preventDefault** Boolean:
13449          *
13450          *   True to prevent the default action
13451          *
13452          * - **stopPropagation** Boolean:
13453          *
13454          *   True to prevent event propagation
13455          *
13456          * - **normalized** Boolean:
13457          *
13458          *   False to pass a browser event to the handler function instead of an Ext.EventObject
13459          *
13460          * - **target** Ext.Element:
13461          *
13462          *   Only call the handler if the event was fired on the target Element, _not_ if the event was bubbled up from a
13463          *   child node.
13464          *
13465          * - **delay** Number:
13466          *
13467          *   The number of milliseconds to delay the invocation of the handler after the event fires.
13468          *
13469          * - **single** Boolean:
13470          *
13471          *   True to add a handler to handle just the next firing of the event, and then remove itself.
13472          *
13473          * - **buffer** Number:
13474          *
13475          *   Causes the handler to be scheduled to run in an {@link Ext.util.DelayedTask} delayed by the specified number of
13476          *   milliseconds. If the event fires again within that time, the original handler is _not_ invoked, but the new
13477          *   handler is scheduled in its place.
13478          *
13479          * **Combining Options**
13480          *
13481          * In the following examples, the shorthand form {@link #on} is used rather than the more verbose addListener. The
13482          * two are equivalent. Using the options argument, it is possible to combine different types of listeners:
13483          *
13484          * A delayed, one-time listener that auto stops the event and adds a custom argument (forumId) to the options
13485          * object. The options object is available as the third parameter in the handler function.
13486          *
13487          * Code:
13488          *
13489          *     el.on('click', this.onClick, this, {
13490          *         single: true,
13491          *         delay: 100,
13492          *         stopEvent : true,
13493          *         forumId: 4
13494          *     });
13495          *
13496          * **Attaching multiple handlers in 1 call**
13497          *
13498          * The method also allows for a single argument to be passed which is a config object containing properties which
13499          * specify multiple handlers.
13500          *
13501          * Code:
13502          *
13503          *     el.on({
13504          *         'click' : {
13505          *             fn: this.onClick,
13506          *             scope: this,
13507          *             delay: 100
13508          *         },
13509          *         'mouseover' : {
13510          *             fn: this.onMouseOver,
13511          *             scope: this
13512          *         },
13513          *         'mouseout' : {
13514          *             fn: this.onMouseOut,
13515          *             scope: this
13516          *         }
13517          *     });
13518          *
13519          * Or a shorthand syntax:
13520          *
13521          * Code:
13522          *
13523          *     el.on({
13524          *         'click' : this.onClick,
13525          *         'mouseover' : this.onMouseOver,
13526          *         'mouseout' : this.onMouseOut,
13527          *         scope: this
13528          *     });
13529          *
13530          * **delegate**
13531          *
13532          * This is a configuration option that you can pass along when registering a handler for an event to assist with
13533          * event delegation. Event delegation is a technique that is used to reduce memory consumption and prevent exposure
13534          * to memory-leaks. By registering an event for a container element as opposed to each element within a container.
13535          * By setting this configuration option to a simple selector, the target element will be filtered to look for a
13536          * descendant of the target. For example:
13537          *
13538          *     // using this markup:
13539          *     <div id='elId'>
13540          *         <p id='p1'>paragraph one</p>
13541          *         <p id='p2' class='clickable'>paragraph two</p>
13542          *         <p id='p3'>paragraph three</p>
13543          *     </div>
13544          *
13545          *     // utilize event delegation to registering just one handler on the container element:
13546          *     el = Ext.get('elId');
13547          *     el.on(
13548          *         'click',
13549          *         function(e,t) {
13550          *             // handle click
13551          *             console.info(t.id); // 'p2'
13552          *         },
13553          *         this,
13554          *         {
13555          *             // filter the target element to be a descendant with the class 'clickable'
13556          *             delegate: '.clickable'
13557          *         }
13558          *     );
13559          *
13560          * @return {Ext.Element} this
13561          */
13562         addListener: function(eventName, fn, scope, options) {
13563             Ext.EventManager.on(this.dom, eventName, fn, scope || this, options);
13564             return this;
13565         },
13566
13567         /**
13568          * Removes an event handler from this element.
13569          *
13570          * **Note**: if a *scope* was explicitly specified when {@link #addListener adding} the listener,
13571          * the same scope must be specified here.
13572          *
13573          * Example:
13574          *
13575          *     el.removeListener('click', this.handlerFn);
13576          *     // or
13577          *     el.un('click', this.handlerFn);
13578          *
13579          * @param {String} eventName The name of the event from which to remove the handler.
13580          * @param {Function} fn The handler function to remove. **This must be a reference to the function passed into the
13581          * {@link #addListener} call.**
13582          * @param {Object} scope If a scope (**this** reference) was specified when the listener was added, then this must
13583          * refer to the same object.
13584          * @return {Ext.Element} this
13585          */
13586         removeListener: function(eventName, fn, scope) {
13587             Ext.EventManager.un(this.dom, eventName, fn, scope || this);
13588             return this;
13589         },
13590
13591         /**
13592          * Removes all previous added listeners from this element
13593          * @return {Ext.Element} this
13594          */
13595         removeAllListeners: function() {
13596             Ext.EventManager.removeAll(this.dom);
13597             return this;
13598         },
13599
13600         /**
13601          * Recursively removes all previous added listeners from this element and its children
13602          * @return {Ext.Element} this
13603          */
13604         purgeAllListeners: function() {
13605             Ext.EventManager.purgeElement(this);
13606             return this;
13607         },
13608
13609         /**
13610          * Test if size has a unit, otherwise appends the passed unit string, or the default for this Element.
13611          * @param size {Mixed} The size to set
13612          * @param units {String} The units to append to a numeric size value
13613          * @private
13614          */
13615         addUnits: function(size, units) {
13616
13617             // Most common case first: Size is set to a number
13618             if (Ext.isNumber(size)) {
13619                 return size + (units || this.defaultUnit || 'px');
13620             }
13621
13622             // Size set to a value which means "auto"
13623             if (size === "" || size == "auto" || size == null) {
13624                 return size || '';
13625             }
13626
13627             // Otherwise, warn if it's not a valid CSS measurement
13628             if (!unitPattern.test(size)) {
13629                 if (Ext.isDefined(Ext.global.console)) {
13630                     Ext.global.console.warn("Warning, size detected as NaN on Element.addUnits.");
13631                 }
13632                 return size || '';
13633             }
13634             return size;
13635         },
13636
13637         /**
13638          * Tests various css rules/browsers to determine if this element uses a border box
13639          * @return {Boolean}
13640          */
13641         isBorderBox: function() {
13642             return Ext.isBorderBox || noBoxAdjust[(this.dom.tagName || "").toLowerCase()];
13643         },
13644
13645         /**
13646          * Removes this element's dom reference. Note that event and cache removal is handled at {@link Ext#removeNode
13647          * Ext.removeNode}
13648          */
13649         remove: function() {
13650             var me = this,
13651             dom = me.dom;
13652
13653             if (dom) {
13654                 delete me.dom;
13655                 Ext.removeNode(dom);
13656             }
13657         },
13658
13659         /**
13660          * Sets up event handlers to call the passed functions when the mouse is moved into and out of the Element.
13661          * @param {Function} overFn The function to call when the mouse enters the Element.
13662          * @param {Function} outFn The function to call when the mouse leaves the Element.
13663          * @param {Object} scope (optional) The scope (`this` reference) in which the functions are executed. Defaults
13664          * to the Element's DOM element.
13665          * @param {Object} options (optional) Options for the listener. See {@link Ext.util.Observable#addListener the
13666          * options parameter}.
13667          * @return {Ext.Element} this
13668          */
13669         hover: function(overFn, outFn, scope, options) {
13670             var me = this;
13671             me.on('mouseenter', overFn, scope || me.dom, options);
13672             me.on('mouseleave', outFn, scope || me.dom, options);
13673             return me;
13674         },
13675
13676         /**
13677          * Returns true if this element is an ancestor of the passed element
13678          * @param {HTMLElement/String} el The element to check
13679          * @return {Boolean} True if this element is an ancestor of el, else false
13680          */
13681         contains: function(el) {
13682             return ! el ? false: Ext.Element.isAncestor(this.dom, el.dom ? el.dom: el);
13683         },
13684
13685         /**
13686          * Returns the value of a namespaced attribute from the element's underlying DOM node.
13687          * @param {String} namespace The namespace in which to look for the attribute
13688          * @param {String} name The attribute name
13689          * @return {String} The attribute value
13690          */
13691         getAttributeNS: function(ns, name) {
13692             return this.getAttribute(name, ns);
13693         },
13694
13695         /**
13696          * Returns the value of an attribute from the element's underlying DOM node.
13697          * @param {String} name The attribute name
13698          * @param {String} namespace (optional) The namespace in which to look for the attribute
13699          * @return {String} The attribute value
13700          * @method
13701          */
13702         getAttribute: (Ext.isIE && !(Ext.isIE9 && document.documentMode === 9)) ?
13703         function(name, ns) {
13704             var d = this.dom,
13705             type;
13706             if(ns) {
13707                 type = typeof d[ns + ":" + name];
13708                 if (type != 'undefined' && type != 'unknown') {
13709                     return d[ns + ":" + name] || null;
13710                 }
13711                 return null;
13712             }
13713             if (name === "for") {
13714                 name = "htmlFor";
13715             }
13716             return d[name] || null;
13717         }: function(name, ns) {
13718             var d = this.dom;
13719             if (ns) {
13720                return d.getAttributeNS(ns, name) || d.getAttribute(ns + ":" + name);
13721             }
13722             return  d.getAttribute(name) || d[name] || null;
13723         },
13724
13725         /**
13726          * Update the innerHTML of this element
13727          * @param {String} html The new HTML
13728          * @return {Ext.Element} this
13729          */
13730         update: function(html) {
13731             if (this.dom) {
13732                 this.dom.innerHTML = html;
13733             }
13734             return this;
13735         }
13736     };
13737
13738     var ep = El.prototype;
13739
13740     El.addMethods = function(o) {
13741         Ext.apply(ep, o);
13742     };
13743
13744     /**
13745      * @method
13746      * @alias Ext.Element#addListener
13747      * Shorthand for {@link #addListener}.
13748      */
13749     ep.on = ep.addListener;
13750
13751     /**
13752      * @method
13753      * @alias Ext.Element#removeListener
13754      * Shorthand for {@link #removeListener}.
13755      */
13756     ep.un = ep.removeListener;
13757
13758     /**
13759      * @method
13760      * @alias Ext.Element#removeAllListeners
13761      * Alias for {@link #removeAllListeners}.
13762      */
13763     ep.clearListeners = ep.removeAllListeners;
13764
13765     /**
13766      * @method destroy
13767      * @member Ext.Element
13768      * Removes this element's dom reference. Note that event and cache removal is handled at {@link Ext#removeNode
13769      * Ext.removeNode}. Alias to {@link #remove}.
13770      */
13771     ep.destroy = ep.remove;
13772
13773     /**
13774      * @property {Boolean} autoBoxAdjust
13775      * true to automatically adjust width and height settings for box-model issues (default to true)
13776      */
13777     ep.autoBoxAdjust = true;
13778
13779     // private
13780     var unitPattern = /\d+(px|em|%|en|ex|pt|in|cm|mm|pc)$/i,
13781     docEl;
13782
13783     /**
13784      * Retrieves Ext.Element objects. {@link Ext#get} is an alias for {@link Ext.Element#get}.
13785      *
13786      * **This method does not retrieve {@link Ext.Component Component}s.** This method retrieves Ext.Element
13787      * objects which encapsulate DOM elements. To retrieve a Component by its ID, use {@link Ext.ComponentManager#get}.
13788      *
13789      * Uses simple caching to consistently return the same object. Automatically fixes if an object was recreated with
13790      * the same id via AJAX or DOM.
13791      *
13792      * @param {String/HTMLElement/Ext.Element} el The id of the node, a DOM Node or an existing Element.
13793      * @return {Ext.Element} The Element object (or null if no matching element was found)
13794      * @static
13795      */
13796     El.get = function(el) {
13797         var ex,
13798         elm,
13799         id;
13800         if (!el) {
13801             return null;
13802         }
13803         if (typeof el == "string") {
13804             // element id
13805             if (! (elm = DOC.getElementById(el))) {
13806                 return null;
13807             }
13808             if (EC[el] && EC[el].el) {
13809                 ex = EC[el].el;
13810                 ex.dom = elm;
13811             } else {
13812                 ex = El.addToCache(new El(elm));
13813             }
13814             return ex;
13815         } else if (el.tagName) {
13816             // dom element
13817             if (! (id = el.id)) {
13818                 id = Ext.id(el);
13819             }
13820             if (EC[id] && EC[id].el) {
13821                 ex = EC[id].el;
13822                 ex.dom = el;
13823             } else {
13824                 ex = El.addToCache(new El(el));
13825             }
13826             return ex;
13827         } else if (el instanceof El) {
13828             if (el != docEl) {
13829                 // refresh dom element in case no longer valid,
13830                 // catch case where it hasn't been appended
13831                 // If an el instance is passed, don't pass to getElementById without some kind of id
13832                 if (Ext.isIE && (el.id == undefined || el.id == '')) {
13833                     el.dom = el.dom;
13834                 } else {
13835                     el.dom = DOC.getElementById(el.id) || el.dom;
13836                 }
13837             }
13838             return el;
13839         } else if (el.isComposite) {
13840             return el;
13841         } else if (Ext.isArray(el)) {
13842             return El.select(el);
13843         } else if (el == DOC) {
13844             // create a bogus element object representing the document object
13845             if (!docEl) {
13846                 var f = function() {};
13847                 f.prototype = El.prototype;
13848                 docEl = new f();
13849                 docEl.dom = DOC;
13850             }
13851             return docEl;
13852         }
13853         return null;
13854     };
13855
13856     /**
13857      * Retrieves Ext.Element objects like {@link Ext#get} but is optimized for sub-elements.
13858      * This is helpful for performance, because in IE (prior to IE 9), `getElementById` uses
13859      * an non-optimized search. In those browsers, starting the search for an element with a
13860      * matching ID at a parent of that element will greatly speed up the process.
13861      *
13862      * Unlike {@link Ext#get}, this method only accepts ID's. If the ID is not a child of
13863      * this element, it will still be found if it exists in the document, but will be slower
13864      * than calling {@link Ext#get} directly.
13865      *
13866      * @param {String} id The id of the element to get.
13867      * @return {Ext.Element} The Element object (or null if no matching element was found)
13868      * @member Ext.Element
13869      * @method getById
13870      * @markdown
13871      */
13872     ep.getById = (!Ext.isIE6 && !Ext.isIE7 && !Ext.isIE8) ? El.get :
13873         function (id) {
13874             var dom = this.dom,
13875                 cached, el, ret;
13876
13877             if (dom) {
13878                 el = dom.all[id];
13879                 if (el) {
13880                     // calling El.get here is a real hit (2x slower) because it has to
13881                     // redetermine that we are giving it a dom el.
13882                     cached = EC[id];
13883                     if (cached && cached.el) {
13884                         ret = cached.el;
13885                         ret.dom = el;
13886                     } else {
13887                         ret = El.addToCache(new El(el));
13888                     }
13889                     return ret;
13890                 }
13891             }
13892
13893             return El.get(id);
13894         };
13895
13896     El.addToCache = function(el, id) {
13897         if (el) {
13898             id = id || el.id;
13899             EC[id] = {
13900                 el: el,
13901                 data: {},
13902                 events: {}
13903             };
13904         }
13905         return el;
13906     };
13907
13908     // private method for getting and setting element data
13909     El.data = function(el, key, value) {
13910         el = El.get(el);
13911         if (!el) {
13912             return null;
13913         }
13914         var c = EC[el.id].data;
13915         if (arguments.length == 2) {
13916             return c[key];
13917         } else {
13918             return (c[key] = value);
13919         }
13920     };
13921
13922     // private
13923     // Garbage collection - uncache elements/purge listeners on orphaned elements
13924     // so we don't hold a reference and cause the browser to retain them
13925     function garbageCollect() {
13926         if (!Ext.enableGarbageCollector) {
13927             clearInterval(El.collectorThreadId);
13928         } else {
13929             var eid,
13930             el,
13931             d,
13932             o;
13933
13934             for (eid in EC) {
13935                 if (!EC.hasOwnProperty(eid)) {
13936                     continue;
13937                 }
13938                 o = EC[eid];
13939                 if (o.skipGarbageCollection) {
13940                     continue;
13941                 }
13942                 el = o.el;
13943                 d = el.dom;
13944                 // -------------------------------------------------------
13945                 // Determining what is garbage:
13946                 // -------------------------------------------------------
13947                 // !d
13948                 // dom node is null, definitely garbage
13949                 // -------------------------------------------------------
13950                 // !d.parentNode
13951                 // no parentNode == direct orphan, definitely garbage
13952                 // -------------------------------------------------------
13953                 // !d.offsetParent && !document.getElementById(eid)
13954                 // display none elements have no offsetParent so we will
13955                 // also try to look it up by it's id. However, check
13956                 // offsetParent first so we don't do unneeded lookups.
13957                 // This enables collection of elements that are not orphans
13958                 // directly, but somewhere up the line they have an orphan
13959                 // parent.
13960                 // -------------------------------------------------------
13961                 if (!d || !d.parentNode || (!d.offsetParent && !DOC.getElementById(eid))) {
13962                     if (d && Ext.enableListenerCollection) {
13963                         Ext.EventManager.removeAll(d);
13964                     }
13965                     delete EC[eid];
13966                 }
13967             }
13968             // Cleanup IE Object leaks
13969             if (Ext.isIE) {
13970                 var t = {};
13971                 for (eid in EC) {
13972                     if (!EC.hasOwnProperty(eid)) {
13973                         continue;
13974                     }
13975                     t[eid] = EC[eid];
13976                 }
13977                 EC = Ext.cache = t;
13978             }
13979         }
13980     }
13981     El.collectorThreadId = setInterval(garbageCollect, 30000);
13982
13983     var flyFn = function() {};
13984     flyFn.prototype = El.prototype;
13985
13986     // dom is optional
13987     El.Flyweight = function(dom) {
13988         this.dom = dom;
13989     };
13990
13991     El.Flyweight.prototype = new flyFn();
13992     El.Flyweight.prototype.isFlyweight = true;
13993     El._flyweights = {};
13994
13995     /**
13996      * Gets the globally shared flyweight Element, with the passed node as the active element. Do not store a reference
13997      * to this element - the dom node can be overwritten by other code. {@link Ext#fly} is alias for
13998      * {@link Ext.Element#fly}.
13999      *
14000      * Use this to make one-time references to DOM elements which are not going to be accessed again either by
14001      * application code, or by Ext's classes. If accessing an element which will be processed regularly, then {@link
14002      * Ext#get Ext.get} will be more appropriate to take advantage of the caching provided by the Ext.Element
14003      * class.
14004      *
14005      * @param {String/HTMLElement} el The dom node or id
14006      * @param {String} named (optional) Allows for creation of named reusable flyweights to prevent conflicts (e.g.
14007      * internally Ext uses "_global")
14008      * @return {Ext.Element} The shared Element object (or null if no matching element was found)
14009      * @static
14010      */
14011     El.fly = function(el, named) {
14012         var ret = null;
14013         named = named || '_global';
14014         el = Ext.getDom(el);
14015         if (el) {
14016             (El._flyweights[named] = El._flyweights[named] || new El.Flyweight()).dom = el;
14017             ret = El._flyweights[named];
14018         }
14019         return ret;
14020     };
14021
14022     /**
14023      * @member Ext
14024      * @method get
14025      * @alias Ext.Element#get
14026      */
14027     Ext.get = El.get;
14028
14029     /**
14030      * @member Ext
14031      * @method fly
14032      * @alias Ext.Element#fly
14033      */
14034     Ext.fly = El.fly;
14035
14036     // speedy lookup for elements never to box adjust
14037     var noBoxAdjust = Ext.isStrict ? {
14038         select: 1
14039     }: {
14040         input: 1,
14041         select: 1,
14042         textarea: 1
14043     };
14044     if (Ext.isIE || Ext.isGecko) {
14045         noBoxAdjust['button'] = 1;
14046     }
14047 })();
14048
14049 /**
14050  * @class Ext.Element
14051  */
14052 Ext.Element.addMethods({
14053     /**
14054      * 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)
14055      * @param {String} selector The simple selector to test
14056      * @param {Number/String/HTMLElement/Ext.Element} maxDepth (optional)
14057      * The max depth to search as a number or element (defaults to 50 || document.body)
14058      * @param {Boolean} returnEl (optional) True to return a Ext.Element object instead of DOM node
14059      * @return {HTMLElement} The matching DOM node (or null if no match was found)
14060      */
14061     findParent : function(simpleSelector, maxDepth, returnEl) {
14062         var p = this.dom,
14063             b = document.body,
14064             depth = 0,
14065             stopEl;
14066
14067         maxDepth = maxDepth || 50;
14068         if (isNaN(maxDepth)) {
14069             stopEl = Ext.getDom(maxDepth);
14070             maxDepth = Number.MAX_VALUE;
14071         }
14072         while (p && p.nodeType == 1 && depth < maxDepth && p != b && p != stopEl) {
14073             if (Ext.DomQuery.is(p, simpleSelector)) {
14074                 return returnEl ? Ext.get(p) : p;
14075             }
14076             depth++;
14077             p = p.parentNode;
14078         }
14079         return null;
14080     },
14081
14082     /**
14083      * Looks at parent nodes for a match of the passed simple selector (e.g. div.some-class or span:first-child)
14084      * @param {String} selector The simple selector to test
14085      * @param {Number/String/HTMLElement/Ext.Element} maxDepth (optional)
14086      * The max depth to search as a number or element (defaults to 10 || document.body)
14087      * @param {Boolean} returnEl (optional) True to return a Ext.Element object instead of DOM node
14088      * @return {HTMLElement} The matching DOM node (or null if no match was found)
14089      */
14090     findParentNode : function(simpleSelector, maxDepth, returnEl) {
14091         var p = Ext.fly(this.dom.parentNode, '_internal');
14092         return p ? p.findParent(simpleSelector, maxDepth, returnEl) : null;
14093     },
14094
14095     /**
14096      * Walks up the dom looking for a parent node that matches the passed simple selector (e.g. div.some-class or span:first-child).
14097      * This is a shortcut for findParentNode() that always returns an Ext.Element.
14098      * @param {String} selector The simple selector to test
14099      * @param {Number/String/HTMLElement/Ext.Element} maxDepth (optional)
14100      * The max depth to search as a number or element (defaults to 10 || document.body)
14101      * @return {Ext.Element} The matching DOM node (or null if no match was found)
14102      */
14103     up : function(simpleSelector, maxDepth) {
14104         return this.findParentNode(simpleSelector, maxDepth, true);
14105     },
14106
14107     /**
14108      * Creates a {@link Ext.CompositeElement} for child nodes based on the passed CSS selector (the selector should not contain an id).
14109      * @param {String} selector The CSS selector
14110      * @return {Ext.CompositeElement/Ext.CompositeElement} The composite element
14111      */
14112     select : function(selector) {
14113         return Ext.Element.select(selector, false,  this.dom);
14114     },
14115
14116     /**
14117      * Selects child nodes based on the passed CSS selector (the selector should not contain an id).
14118      * @param {String} selector The CSS selector
14119      * @return {HTMLElement[]} An array of the matched nodes
14120      */
14121     query : function(selector) {
14122         return Ext.DomQuery.select(selector, this.dom);
14123     },
14124
14125     /**
14126      * Selects a single child at any depth below this element based on the passed CSS selector (the selector should not contain an id).
14127      * @param {String} selector The CSS selector
14128      * @param {Boolean} returnDom (optional) True to return the DOM node instead of Ext.Element (defaults to false)
14129      * @return {HTMLElement/Ext.Element} The child Ext.Element (or DOM node if returnDom = true)
14130      */
14131     down : function(selector, returnDom) {
14132         var n = Ext.DomQuery.selectNode(selector, this.dom);
14133         return returnDom ? n : Ext.get(n);
14134     },
14135
14136     /**
14137      * Selects a single *direct* child based on the passed CSS selector (the selector should not contain an id).
14138      * @param {String} selector The CSS selector
14139      * @param {Boolean} returnDom (optional) True to return the DOM node instead of Ext.Element (defaults to false)
14140      * @return {HTMLElement/Ext.Element} The child Ext.Element (or DOM node if returnDom = true)
14141      */
14142     child : function(selector, returnDom) {
14143         var node,
14144             me = this,
14145             id;
14146         id = Ext.get(me).id;
14147         // Escape . or :
14148         id = id.replace(/[\.:]/g, "\\$0");
14149         node = Ext.DomQuery.selectNode('#' + id + " > " + selector, me.dom);
14150         return returnDom ? node : Ext.get(node);
14151     },
14152
14153      /**
14154      * Gets the parent node for this element, optionally chaining up trying to match a selector
14155      * @param {String} selector (optional) Find a parent node that matches the passed simple selector
14156      * @param {Boolean} returnDom (optional) True to return a raw dom node instead of an Ext.Element
14157      * @return {Ext.Element/HTMLElement} The parent node or null
14158      */
14159     parent : function(selector, returnDom) {
14160         return this.matchNode('parentNode', 'parentNode', selector, returnDom);
14161     },
14162
14163      /**
14164      * Gets the next sibling, skipping text nodes
14165      * @param {String} selector (optional) Find the next sibling that matches the passed simple selector
14166      * @param {Boolean} returnDom (optional) True to return a raw dom node instead of an Ext.Element
14167      * @return {Ext.Element/HTMLElement} The next sibling or null
14168      */
14169     next : function(selector, returnDom) {
14170         return this.matchNode('nextSibling', 'nextSibling', selector, returnDom);
14171     },
14172
14173     /**
14174      * Gets the previous sibling, skipping text nodes
14175      * @param {String} selector (optional) Find the previous sibling that matches the passed simple selector
14176      * @param {Boolean} returnDom (optional) True to return a raw dom node instead of an Ext.Element
14177      * @return {Ext.Element/HTMLElement} The previous sibling or null
14178      */
14179     prev : function(selector, returnDom) {
14180         return this.matchNode('previousSibling', 'previousSibling', selector, returnDom);
14181     },
14182
14183
14184     /**
14185      * Gets the first child, skipping text nodes
14186      * @param {String} selector (optional) Find the next sibling that matches the passed simple selector
14187      * @param {Boolean} returnDom (optional) True to return a raw dom node instead of an Ext.Element
14188      * @return {Ext.Element/HTMLElement} The first child or null
14189      */
14190     first : function(selector, returnDom) {
14191         return this.matchNode('nextSibling', 'firstChild', selector, returnDom);
14192     },
14193
14194     /**
14195      * Gets the last child, skipping text nodes
14196      * @param {String} selector (optional) Find the previous sibling that matches the passed simple selector
14197      * @param {Boolean} returnDom (optional) True to return a raw dom node instead of an Ext.Element
14198      * @return {Ext.Element/HTMLElement} The last child or null
14199      */
14200     last : function(selector, returnDom) {
14201         return this.matchNode('previousSibling', 'lastChild', selector, returnDom);
14202     },
14203
14204     matchNode : function(dir, start, selector, returnDom) {
14205         if (!this.dom) {
14206             return null;
14207         }
14208
14209         var n = this.dom[start];
14210         while (n) {
14211             if (n.nodeType == 1 && (!selector || Ext.DomQuery.is(n, selector))) {
14212                 return !returnDom ? Ext.get(n) : n;
14213             }
14214             n = n[dir];
14215         }
14216         return null;
14217     }
14218 });
14219
14220 /**
14221  * @class Ext.Element
14222  */
14223 Ext.Element.addMethods({
14224     /**
14225      * Appends the passed element(s) to this element
14226      * @param {String/HTMLElement/Ext.Element} el
14227      * The id of the node, a DOM Node or an existing Element.
14228      * @return {Ext.Element} this
14229      */
14230     appendChild : function(el) {
14231         return Ext.get(el).appendTo(this);
14232     },
14233
14234     /**
14235      * Appends this element to the passed element
14236      * @param {String/HTMLElement/Ext.Element} el The new parent element.
14237      * The id of the node, a DOM Node or an existing Element.
14238      * @return {Ext.Element} this
14239      */
14240     appendTo : function(el) {
14241         Ext.getDom(el).appendChild(this.dom);
14242         return this;
14243     },
14244
14245     /**
14246      * Inserts this element before the passed element in the DOM
14247      * @param {String/HTMLElement/Ext.Element} el The element before which this element will be inserted.
14248      * The id of the node, a DOM Node or an existing Element.
14249      * @return {Ext.Element} this
14250      */
14251     insertBefore : function(el) {
14252         el = Ext.getDom(el);
14253         el.parentNode.insertBefore(this.dom, el);
14254         return this;
14255     },
14256
14257     /**
14258      * Inserts this element after the passed element in the DOM
14259      * @param {String/HTMLElement/Ext.Element} el The element to insert after.
14260      * The id of the node, a DOM Node or an existing Element.
14261      * @return {Ext.Element} this
14262      */
14263     insertAfter : function(el) {
14264         el = Ext.getDom(el);
14265         el.parentNode.insertBefore(this.dom, el.nextSibling);
14266         return this;
14267     },
14268
14269     /**
14270      * Inserts (or creates) an element (or DomHelper config) as the first child of this element
14271      * @param {String/HTMLElement/Ext.Element/Object} el The id or element to insert or a DomHelper config
14272      * to create and insert
14273      * @return {Ext.Element} The new child
14274      */
14275     insertFirst : function(el, returnDom) {
14276         el = el || {};
14277         if (el.nodeType || el.dom || typeof el == 'string') { // element
14278             el = Ext.getDom(el);
14279             this.dom.insertBefore(el, this.dom.firstChild);
14280             return !returnDom ? Ext.get(el) : el;
14281         }
14282         else { // dh config
14283             return this.createChild(el, this.dom.firstChild, returnDom);
14284         }
14285     },
14286
14287     /**
14288      * Inserts (or creates) the passed element (or DomHelper config) as a sibling of this element
14289      * @param {String/HTMLElement/Ext.Element/Object/Array} el The id, element to insert or a DomHelper config
14290      * to create and insert *or* an array of any of those.
14291      * @param {String} where (optional) 'before' or 'after' defaults to before
14292      * @param {Boolean} returnDom (optional) True to return the .;ll;l,raw DOM element instead of Ext.Element
14293      * @return {Ext.Element} The inserted Element. If an array is passed, the last inserted element is returned.
14294      */
14295     insertSibling: function(el, where, returnDom){
14296         var me = this, rt,
14297         isAfter = (where || 'before').toLowerCase() == 'after',
14298         insertEl;
14299
14300         if(Ext.isArray(el)){
14301             insertEl = me;
14302             Ext.each(el, function(e) {
14303                 rt = Ext.fly(insertEl, '_internal').insertSibling(e, where, returnDom);
14304                 if(isAfter){
14305                     insertEl = rt;
14306                 }
14307             });
14308             return rt;
14309         }
14310
14311         el = el || {};
14312
14313         if(el.nodeType || el.dom){
14314             rt = me.dom.parentNode.insertBefore(Ext.getDom(el), isAfter ? me.dom.nextSibling : me.dom);
14315             if (!returnDom) {
14316                 rt = Ext.get(rt);
14317             }
14318         }else{
14319             if (isAfter && !me.dom.nextSibling) {
14320                 rt = Ext.DomHelper.append(me.dom.parentNode, el, !returnDom);
14321             } else {
14322                 rt = Ext.DomHelper[isAfter ? 'insertAfter' : 'insertBefore'](me.dom, el, !returnDom);
14323             }
14324         }
14325         return rt;
14326     },
14327
14328     /**
14329      * Replaces the passed element with this element
14330      * @param {String/HTMLElement/Ext.Element} el The element to replace.
14331      * The id of the node, a DOM Node or an existing Element.
14332      * @return {Ext.Element} this
14333      */
14334     replace : function(el) {
14335         el = Ext.get(el);
14336         this.insertBefore(el);
14337         el.remove();
14338         return this;
14339     },
14340     
14341     /**
14342      * Replaces this element with the passed element
14343      * @param {String/HTMLElement/Ext.Element/Object} el The new element (id of the node, a DOM Node
14344      * or an existing Element) or a DomHelper config of an element to create
14345      * @return {Ext.Element} this
14346      */
14347     replaceWith: function(el){
14348         var me = this;
14349             
14350         if(el.nodeType || el.dom || typeof el == 'string'){
14351             el = Ext.get(el);
14352             me.dom.parentNode.insertBefore(el, me.dom);
14353         }else{
14354             el = Ext.DomHelper.insertBefore(me.dom, el);
14355         }
14356         
14357         delete Ext.cache[me.id];
14358         Ext.removeNode(me.dom);      
14359         me.id = Ext.id(me.dom = el);
14360         Ext.Element.addToCache(me.isFlyweight ? new Ext.Element(me.dom) : me);     
14361         return me;
14362     },
14363     
14364     /**
14365      * Creates the passed DomHelper config and appends it to this element or optionally inserts it before the passed child element.
14366      * @param {Object} config DomHelper element config object.  If no tag is specified (e.g., {tag:'input'}) then a div will be
14367      * automatically generated with the specified attributes.
14368      * @param {HTMLElement} insertBefore (optional) a child element of this element
14369      * @param {Boolean} returnDom (optional) true to return the dom node instead of creating an Element
14370      * @return {Ext.Element} The new child element
14371      */
14372     createChild : function(config, insertBefore, returnDom) {
14373         config = config || {tag:'div'};
14374         if (insertBefore) {
14375             return Ext.DomHelper.insertBefore(insertBefore, config, returnDom !== true);
14376         }
14377         else {
14378             return Ext.DomHelper[!this.dom.firstChild ? 'insertFirst' : 'append'](this.dom, config,  returnDom !== true);
14379         }
14380     },
14381
14382     /**
14383      * Creates and wraps this element with another element
14384      * @param {Object} config (optional) DomHelper element config object for the wrapper element or null for an empty div
14385      * @param {Boolean} returnDom (optional) True to return the raw DOM element instead of Ext.Element
14386      * @return {HTMLElement/Ext.Element} The newly created wrapper element
14387      */
14388     wrap : function(config, returnDom) {
14389         var newEl = Ext.DomHelper.insertBefore(this.dom, config || {tag: "div"}, !returnDom),
14390             d = newEl.dom || newEl;
14391
14392         d.appendChild(this.dom);
14393         return newEl;
14394     },
14395
14396     /**
14397      * Inserts an html fragment into this element
14398      * @param {String} where Where to insert the html in relation to this element - beforeBegin, afterBegin, beforeEnd, afterEnd.
14399      * See {@link Ext.DomHelper#insertHtml} for details.
14400      * @param {String} html The HTML fragment
14401      * @param {Boolean} returnEl (optional) True to return an Ext.Element (defaults to false)
14402      * @return {HTMLElement/Ext.Element} The inserted node (or nearest related if more than 1 inserted)
14403      */
14404     insertHtml : function(where, html, returnEl) {
14405         var el = Ext.DomHelper.insertHtml(where, this.dom, html);
14406         return returnEl ? Ext.get(el) : el;
14407     }
14408 });
14409
14410 /**
14411  * @class Ext.Element
14412  */
14413 (function(){
14414     // local style camelizing for speed
14415     var ELEMENT = Ext.Element,
14416         supports = Ext.supports,
14417         view = document.defaultView,
14418         opacityRe = /alpha\(opacity=(.*)\)/i,
14419         trimRe = /^\s+|\s+$/g,
14420         spacesRe = /\s+/,
14421         wordsRe = /\w/g,
14422         adjustDirect2DTableRe = /table-row|table-.*-group/,
14423         INTERNAL = '_internal',
14424         PADDING = 'padding',
14425         MARGIN = 'margin',
14426         BORDER = 'border',
14427         LEFT = '-left',
14428         RIGHT = '-right',
14429         TOP = '-top',
14430         BOTTOM = '-bottom',
14431         WIDTH = '-width',
14432         MATH = Math,
14433         HIDDEN = 'hidden',
14434         ISCLIPPED = 'isClipped',
14435         OVERFLOW = 'overflow',
14436         OVERFLOWX = 'overflow-x',
14437         OVERFLOWY = 'overflow-y',
14438         ORIGINALCLIP = 'originalClip',
14439         // special markup used throughout Ext when box wrapping elements
14440         borders = {l: BORDER + LEFT + WIDTH, r: BORDER + RIGHT + WIDTH, t: BORDER + TOP + WIDTH, b: BORDER + BOTTOM + WIDTH},
14441         paddings = {l: PADDING + LEFT, r: PADDING + RIGHT, t: PADDING + TOP, b: PADDING + BOTTOM},
14442         margins = {l: MARGIN + LEFT, r: MARGIN + RIGHT, t: MARGIN + TOP, b: MARGIN + BOTTOM},
14443         data = ELEMENT.data;
14444
14445     ELEMENT.boxMarkup = '<div class="{0}-tl"><div class="{0}-tr"><div class="{0}-tc"></div></div></div><div class="{0}-ml"><div class="{0}-mr"><div class="{0}-mc"></div></div></div><div class="{0}-bl"><div class="{0}-br"><div class="{0}-bc"></div></div></div>';
14446
14447     // These property values are read from the parentNode if they cannot be read
14448     // from the child:
14449     ELEMENT.inheritedProps = {
14450         fontSize: 1,
14451         fontStyle: 1,
14452         opacity: 1
14453     };
14454
14455     Ext.override(ELEMENT, {
14456
14457         /**
14458          * TODO: Look at this
14459          */
14460         // private  ==> used by Fx
14461         adjustWidth : function(width) {
14462             var me = this,
14463                 isNum = (typeof width == 'number');
14464
14465             if(isNum && me.autoBoxAdjust && !me.isBorderBox()){
14466                width -= (me.getBorderWidth("lr") + me.getPadding("lr"));
14467             }
14468             return (isNum && width < 0) ? 0 : width;
14469         },
14470
14471         // private   ==> used by Fx
14472         adjustHeight : function(height) {
14473             var me = this,
14474                 isNum = (typeof height == "number");
14475
14476             if(isNum && me.autoBoxAdjust && !me.isBorderBox()){
14477                height -= (me.getBorderWidth("tb") + me.getPadding("tb"));
14478             }
14479             return (isNum && height < 0) ? 0 : height;
14480         },
14481
14482
14483         /**
14484          * Adds one or more CSS classes to the element. Duplicate classes are automatically filtered out.
14485          * @param {String/String[]} className The CSS classes to add separated by space, or an array of classes
14486          * @return {Ext.Element} this
14487          */
14488         addCls : function(className){
14489             var me = this,
14490                 cls = [],
14491                 space = ((me.dom.className.replace(trimRe, '') == '') ? "" : " "),
14492                 i, len, v;
14493             if (className === undefined) {
14494                 return me;
14495             }
14496             // Separate case is for speed
14497             if (Object.prototype.toString.call(className) !== '[object Array]') {
14498                 if (typeof className === 'string') {
14499                     className = className.replace(trimRe, '').split(spacesRe);
14500                     if (className.length === 1) {
14501                         className = className[0];
14502                         if (!me.hasCls(className)) {
14503                             me.dom.className += space + className;
14504                         }
14505                     } else {
14506                         this.addCls(className);
14507                     }
14508                 }
14509             } else {
14510                 for (i = 0, len = className.length; i < len; i++) {
14511                     v = className[i];
14512                     if (typeof v == 'string' && (' ' + me.dom.className + ' ').indexOf(' ' + v + ' ') == -1) {
14513                         cls.push(v);
14514                     }
14515                 }
14516                 if (cls.length) {
14517                     me.dom.className += space + cls.join(" ");
14518                 }
14519             }
14520             return me;
14521         },
14522
14523         /**
14524          * Removes one or more CSS classes from the element.
14525          * @param {String/String[]} className The CSS classes to remove separated by space, or an array of classes
14526          * @return {Ext.Element} this
14527          */
14528         removeCls : function(className){
14529             var me = this,
14530                 i, idx, len, cls, elClasses;
14531             if (className === undefined) {
14532                 return me;
14533             }
14534             if (Object.prototype.toString.call(className) !== '[object Array]') {
14535                 className = className.replace(trimRe, '').split(spacesRe);
14536             }
14537             if (me.dom && me.dom.className) {
14538                 elClasses = me.dom.className.replace(trimRe, '').split(spacesRe);
14539                 for (i = 0, len = className.length; i < len; i++) {
14540                     cls = className[i];
14541                     if (typeof cls == 'string') {
14542                         cls = cls.replace(trimRe, '');
14543                         idx = Ext.Array.indexOf(elClasses, cls);
14544                         if (idx != -1) {
14545                             Ext.Array.erase(elClasses, idx, 1);
14546                         }
14547                     }
14548                 }
14549                 me.dom.className = elClasses.join(" ");
14550             }
14551             return me;
14552         },
14553
14554         /**
14555          * Adds one or more CSS classes to this element and removes the same class(es) from all siblings.
14556          * @param {String/String[]} className The CSS class to add, or an array of classes
14557          * @return {Ext.Element} this
14558          */
14559         radioCls : function(className){
14560             var cn = this.dom.parentNode.childNodes,
14561                 v, i, len;
14562             className = Ext.isArray(className) ? className : [className];
14563             for (i = 0, len = cn.length; i < len; i++) {
14564                 v = cn[i];
14565                 if (v && v.nodeType == 1) {
14566                     Ext.fly(v, '_internal').removeCls(className);
14567                 }
14568             }
14569             return this.addCls(className);
14570         },
14571
14572         /**
14573          * Toggles the specified CSS class on this element (removes it if it already exists, otherwise adds it).
14574          * @param {String} className The CSS class to toggle
14575          * @return {Ext.Element} this
14576          * @method
14577          */
14578         toggleCls : Ext.supports.ClassList ?
14579             function(className) {
14580                 this.dom.classList.toggle(Ext.String.trim(className));
14581                 return this;
14582             } :
14583             function(className) {
14584                 return this.hasCls(className) ? this.removeCls(className) : this.addCls(className);
14585             },
14586
14587         /**
14588          * Checks if the specified CSS class exists on this element's DOM node.
14589          * @param {String} className The CSS class to check for
14590          * @return {Boolean} True if the class exists, else false
14591          * @method
14592          */
14593         hasCls : Ext.supports.ClassList ?
14594             function(className) {
14595                 if (!className) {
14596                     return false;
14597                 }
14598                 className = className.split(spacesRe);
14599                 var ln = className.length,
14600                     i = 0;
14601                 for (; i < ln; i++) {
14602                     if (className[i] && this.dom.classList.contains(className[i])) {
14603                         return true;
14604                     }
14605                 }
14606                 return false;
14607             } :
14608             function(className){
14609                 return className && (' ' + this.dom.className + ' ').indexOf(' ' + className + ' ') != -1;
14610             },
14611
14612         /**
14613          * Replaces a CSS class on the element with another.  If the old name does not exist, the new name will simply be added.
14614          * @param {String} oldClassName The CSS class to replace
14615          * @param {String} newClassName The replacement CSS class
14616          * @return {Ext.Element} this
14617          */
14618         replaceCls : function(oldClassName, newClassName){
14619             return this.removeCls(oldClassName).addCls(newClassName);
14620         },
14621
14622         isStyle : function(style, val) {
14623             return this.getStyle(style) == val;
14624         },
14625
14626         /**
14627          * Normalizes currentStyle and computedStyle.
14628          * @param {String} property The style property whose value is returned.
14629          * @return {String} The current value of the style property for this element.
14630          * @method
14631          */
14632         getStyle : function() {
14633             return view && view.getComputedStyle ?
14634                 function(prop){
14635                     var el = this.dom,
14636                         v, cs, out, display, cleaner;
14637
14638                     if(el == document){
14639                         return null;
14640                     }
14641                     prop = ELEMENT.normalize(prop);
14642                     out = (v = el.style[prop]) ? v :
14643                            (cs = view.getComputedStyle(el, "")) ? cs[prop] : null;
14644
14645                     // Ignore cases when the margin is correctly reported as 0, the bug only shows
14646                     // numbers larger.
14647                     if(prop == 'marginRight' && out != '0px' && !supports.RightMargin){
14648                         cleaner = ELEMENT.getRightMarginFixCleaner(el);
14649                         display = this.getStyle('display');
14650                         el.style.display = 'inline-block';
14651                         out = view.getComputedStyle(el, '').marginRight;
14652                         el.style.display = display;
14653                         cleaner();
14654                     }
14655
14656                     if(prop == 'backgroundColor' && out == 'rgba(0, 0, 0, 0)' && !supports.TransparentColor){
14657                         out = 'transparent';
14658                     }
14659                     return out;
14660                 } :
14661                 function (prop) {
14662                     var el = this.dom,
14663                         m, cs;
14664
14665                     if (el == document) {
14666                         return null;
14667                     }
14668                     prop = ELEMENT.normalize(prop);
14669
14670                     do {
14671                         if (prop == 'opacity') {
14672                             if (el.style.filter.match) {
14673                                 m = el.style.filter.match(opacityRe);
14674                                 if(m){
14675                                     var fv = parseFloat(m[1]);
14676                                     if(!isNaN(fv)){
14677                                         return fv ? fv / 100 : 0;
14678                                     }
14679                                 }
14680                             }
14681                             return 1;
14682                         }
14683
14684                         // the try statement does have a cost, so we avoid it unless we are
14685                         // on IE6
14686                         if (!Ext.isIE6) {
14687                             return el.style[prop] || ((cs = el.currentStyle) ? cs[prop] : null);
14688                         }
14689
14690                         try {
14691                             return el.style[prop] || ((cs = el.currentStyle) ? cs[prop] : null);
14692                         } catch (e) {
14693                             // in some cases, IE6 will throw Invalid Argument for properties
14694                             // like fontSize (see in /examples/tabs/tabs.html).
14695                         }
14696
14697                         if (!ELEMENT.inheritedProps[prop]) {
14698                             break;
14699                         }
14700
14701                         el = el.parentNode;
14702                         // this is _not_ perfect, but we can only hope that the style we
14703                         // need is inherited from a parentNode. If not and since IE won't
14704                         // give us the info we need, we are never going to be 100% right.
14705                     } while (el);
14706
14707                     Ext.log({
14708                         level: 'warn',
14709                         msg: 'Failed to get ' + this.dom.id + '.currentStyle.' + prop
14710                     });
14711                     return null;
14712                 }
14713         }(),
14714
14715         /**
14716          * Return the CSS color for the specified CSS attribute. rgb, 3 digit (like #fff) and valid values
14717          * are convert to standard 6 digit hex color.
14718          * @param {String} attr The css attribute
14719          * @param {String} defaultValue The default value to use when a valid color isn't found
14720          * @param {String} prefix (optional) defaults to #. Use an empty string when working with
14721          * color anims.
14722          */
14723         getColor : function(attr, defaultValue, prefix){
14724             var v = this.getStyle(attr),
14725                 color = prefix || prefix === '' ? prefix : '#',
14726                 h;
14727
14728             if(!v || (/transparent|inherit/.test(v))) {
14729                 return defaultValue;
14730             }
14731             if(/^r/.test(v)){
14732                 Ext.each(v.slice(4, v.length -1).split(','), function(s){
14733                     h = parseInt(s, 10);
14734                     color += (h < 16 ? '0' : '') + h.toString(16);
14735                 });
14736             }else{
14737                 v = v.replace('#', '');
14738                 color += v.length == 3 ? v.replace(/^(\w)(\w)(\w)$/, '$1$1$2$2$3$3') : v;
14739             }
14740             return(color.length > 5 ? color.toLowerCase() : defaultValue);
14741         },
14742
14743         /**
14744          * Wrapper for setting style properties, also takes single object parameter of multiple styles.
14745          * @param {String/Object} property The style property to be set, or an object of multiple styles.
14746          * @param {String} value (optional) The value to apply to the given property, or null if an object was passed.
14747          * @return {Ext.Element} this
14748          */
14749         setStyle : function(prop, value){
14750             var me = this,
14751                 tmp, style;
14752
14753             if (!me.dom) {
14754                 return me;
14755             }
14756             if (typeof prop === 'string') {
14757                 tmp = {};
14758                 tmp[prop] = value;
14759                 prop = tmp;
14760             }
14761             for (style in prop) {
14762                 if (prop.hasOwnProperty(style)) {
14763                     value = Ext.value(prop[style], '');
14764                     if (style == 'opacity') {
14765                         me.setOpacity(value);
14766                     }
14767                     else {
14768                         me.dom.style[ELEMENT.normalize(style)] = value;
14769                     }
14770                 }
14771             }
14772             return me;
14773         },
14774
14775         /**
14776          * Set the opacity of the element
14777          * @param {Number} opacity The new opacity. 0 = transparent, .5 = 50% visibile, 1 = fully visible, etc
14778          * @param {Boolean/Object} animate (optional) a standard Element animation config object or <tt>true</tt> for
14779          * the default animation (<tt>{duration: .35, easing: 'easeIn'}</tt>)
14780          * @return {Ext.Element} this
14781          */
14782         setOpacity: function(opacity, animate) {
14783             var me = this,
14784                 dom = me.dom,
14785                 val,
14786                 style;
14787
14788             if (!me.dom) {
14789                 return me;
14790             }
14791
14792             style = me.dom.style;
14793
14794             if (!animate || !me.anim) {
14795                 if (!Ext.supports.Opacity) {
14796                     opacity = opacity < 1 ? 'alpha(opacity=' + opacity * 100 + ')': '';
14797                     val = style.filter.replace(opacityRe, '').replace(trimRe, '');
14798
14799                     style.zoom = 1;
14800                     style.filter = val + (val.length > 0 ? ' ': '') + opacity;
14801                 }
14802                 else {
14803                     style.opacity = opacity;
14804                 }
14805             }
14806             else {
14807                 if (!Ext.isObject(animate)) {
14808                     animate = {
14809                         duration: 350,
14810                         easing: 'ease-in'
14811                     };
14812                 }
14813                 me.animate(Ext.applyIf({
14814                     to: {
14815                         opacity: opacity
14816                     }
14817                 },
14818                 animate));
14819             }
14820             return me;
14821         },
14822
14823
14824         /**
14825          * Clears any opacity settings from this element. Required in some cases for IE.
14826          * @return {Ext.Element} this
14827          */
14828         clearOpacity : function(){
14829             var style = this.dom.style;
14830             if(!Ext.supports.Opacity){
14831                 if(!Ext.isEmpty(style.filter)){
14832                     style.filter = style.filter.replace(opacityRe, '').replace(trimRe, '');
14833                 }
14834             }else{
14835                 style.opacity = style['-moz-opacity'] = style['-khtml-opacity'] = '';
14836             }
14837             return this;
14838         },
14839
14840         /**
14841          * @private
14842          * Returns 1 if the browser returns the subpixel dimension rounded to the lowest pixel.
14843          * @return {Number} 0 or 1
14844          */
14845         adjustDirect2DDimension: function(dimension) {
14846             var me = this,
14847                 dom = me.dom,
14848                 display = me.getStyle('display'),
14849                 inlineDisplay = dom.style['display'],
14850                 inlinePosition = dom.style['position'],
14851                 originIndex = dimension === 'width' ? 0 : 1,
14852                 floating;
14853
14854             if (display === 'inline') {
14855                 dom.style['display'] = 'inline-block';
14856             }
14857
14858             dom.style['position'] = display.match(adjustDirect2DTableRe) ? 'absolute' : 'static';
14859
14860             // floating will contain digits that appears after the decimal point
14861             // if height or width are set to auto we fallback to msTransformOrigin calculation
14862             floating = (parseFloat(me.getStyle(dimension)) || parseFloat(dom.currentStyle.msTransformOrigin.split(' ')[originIndex]) * 2) % 1;
14863
14864             dom.style['position'] = inlinePosition;
14865
14866             if (display === 'inline') {
14867                 dom.style['display'] = inlineDisplay;
14868             }
14869
14870             return floating;
14871         },
14872
14873         /**
14874          * Returns the offset height of the element
14875          * @param {Boolean} contentHeight (optional) true to get the height minus borders and padding
14876          * @return {Number} The element's height
14877          */
14878         getHeight: function(contentHeight, preciseHeight) {
14879             var me = this,
14880                 dom = me.dom,
14881                 hidden = Ext.isIE && me.isStyle('display', 'none'),
14882                 height, overflow, style, floating;
14883
14884             // IE Quirks mode acts more like a max-size measurement unless overflow is hidden during measurement.
14885             // We will put the overflow back to it's original value when we are done measuring.
14886             if (Ext.isIEQuirks) {
14887                 style = dom.style;
14888                 overflow = style.overflow;
14889                 me.setStyle({ overflow: 'hidden'});
14890             }
14891
14892             height = dom.offsetHeight;
14893
14894             height = MATH.max(height, hidden ? 0 : dom.clientHeight) || 0;
14895
14896             // IE9 Direct2D dimension rounding bug
14897             if (!hidden && Ext.supports.Direct2DBug) {
14898                 floating = me.adjustDirect2DDimension('height');
14899                 if (preciseHeight) {
14900                     height += floating;
14901                 }
14902                 else if (floating > 0 && floating < 0.5) {
14903                     height++;
14904                 }
14905             }
14906
14907             if (contentHeight) {
14908                 height -= (me.getBorderWidth("tb") + me.getPadding("tb"));
14909             }
14910
14911             if (Ext.isIEQuirks) {
14912                 me.setStyle({ overflow: overflow});
14913             }
14914
14915             if (height < 0) {
14916                 height = 0;
14917             }
14918             return height;
14919         },
14920
14921         /**
14922          * Returns the offset width of the element
14923          * @param {Boolean} contentWidth (optional) true to get the width minus borders and padding
14924          * @return {Number} The element's width
14925          */
14926         getWidth: function(contentWidth, preciseWidth) {
14927             var me = this,
14928                 dom = me.dom,
14929                 hidden = Ext.isIE && me.isStyle('display', 'none'),
14930                 rect, width, overflow, style, floating, parentPosition;
14931
14932             // IE Quirks mode acts more like a max-size measurement unless overflow is hidden during measurement.
14933             // We will put the overflow back to it's original value when we are done measuring.
14934             if (Ext.isIEQuirks) {
14935                 style = dom.style;
14936                 overflow = style.overflow;
14937                 me.setStyle({overflow: 'hidden'});
14938             }
14939
14940             // Fix Opera 10.5x width calculation issues
14941             if (Ext.isOpera10_5) {
14942                 if (dom.parentNode.currentStyle.position === 'relative') {
14943                     parentPosition = dom.parentNode.style.position;
14944                     dom.parentNode.style.position = 'static';
14945                     width = dom.offsetWidth;
14946                     dom.parentNode.style.position = parentPosition;
14947                 }
14948                 width = Math.max(width || 0, dom.offsetWidth);
14949
14950             // Gecko will in some cases report an offsetWidth that is actually less than the width of the
14951             // text contents, because it measures fonts with sub-pixel precision but rounds the calculated
14952             // value down. Using getBoundingClientRect instead of offsetWidth allows us to get the precise
14953             // subpixel measurements so we can force them to always be rounded up. See
14954             // https://bugzilla.mozilla.org/show_bug.cgi?id=458617
14955             } else if (Ext.supports.BoundingClientRect) {
14956                 rect = dom.getBoundingClientRect();
14957                 width = rect.right - rect.left;
14958                 width = preciseWidth ? width : Math.ceil(width);
14959             } else {
14960                 width = dom.offsetWidth;
14961             }
14962
14963             width = MATH.max(width, hidden ? 0 : dom.clientWidth) || 0;
14964
14965             // IE9 Direct2D dimension rounding bug
14966             if (!hidden && Ext.supports.Direct2DBug) {
14967                 floating = me.adjustDirect2DDimension('width');
14968                 if (preciseWidth) {
14969                     width += floating;
14970                 }
14971                 else if (floating > 0 && floating < 0.5) {
14972                     width++;
14973                 }
14974             }
14975
14976             if (contentWidth) {
14977                 width -= (me.getBorderWidth("lr") + me.getPadding("lr"));
14978             }
14979
14980             if (Ext.isIEQuirks) {
14981                 me.setStyle({ overflow: overflow});
14982             }
14983
14984             if (width < 0) {
14985                 width = 0;
14986             }
14987             return width;
14988         },
14989
14990         /**
14991          * Set the width of this Element.
14992          * @param {Number/String} width The new width. This may be one of:<div class="mdetail-params"><ul>
14993          * <li>A Number specifying the new width in this Element's {@link #defaultUnit}s (by default, pixels).</li>
14994          * <li>A String used to set the CSS width style. Animation may <b>not</b> be used.
14995          * </ul></div>
14996          * @param {Boolean/Object} animate (optional) true for the default animation or a standard Element animation config object
14997          * @return {Ext.Element} this
14998          */
14999         setWidth : function(width, animate){
15000             var me = this;
15001             width = me.adjustWidth(width);
15002             if (!animate || !me.anim) {
15003                 me.dom.style.width = me.addUnits(width);
15004             }
15005             else {
15006                 if (!Ext.isObject(animate)) {
15007                     animate = {};
15008                 }
15009                 me.animate(Ext.applyIf({
15010                     to: {
15011                         width: width
15012                     }
15013                 }, animate));
15014             }
15015             return me;
15016         },
15017
15018         /**
15019          * Set the height of this Element.
15020          * <pre><code>
15021 // change the height to 200px and animate with default configuration
15022 Ext.fly('elementId').setHeight(200, true);
15023
15024 // change the height to 150px and animate with a custom configuration
15025 Ext.fly('elId').setHeight(150, {
15026     duration : .5, // animation will have a duration of .5 seconds
15027     // will change the content to "finished"
15028     callback: function(){ this.{@link #update}("finished"); }
15029 });
15030          * </code></pre>
15031          * @param {Number/String} height The new height. This may be one of:<div class="mdetail-params"><ul>
15032          * <li>A Number specifying the new height in this Element's {@link #defaultUnit}s (by default, pixels.)</li>
15033          * <li>A String used to set the CSS height style. Animation may <b>not</b> be used.</li>
15034          * </ul></div>
15035          * @param {Boolean/Object} animate (optional) true for the default animation or a standard Element animation config object
15036          * @return {Ext.Element} this
15037          */
15038          setHeight : function(height, animate){
15039             var me = this;
15040             height = me.adjustHeight(height);
15041             if (!animate || !me.anim) {
15042                 me.dom.style.height = me.addUnits(height);
15043             }
15044             else {
15045                 if (!Ext.isObject(animate)) {
15046                     animate = {};
15047                 }
15048                 me.animate(Ext.applyIf({
15049                     to: {
15050                         height: height
15051                     }
15052                 }, animate));
15053             }
15054             return me;
15055         },
15056
15057         /**
15058          * Gets the width of the border(s) for the specified side(s)
15059          * @param {String} side Can be t, l, r, b or any combination of those to add multiple values. For example,
15060          * passing <tt>'lr'</tt> would get the border <b><u>l</u></b>eft width + the border <b><u>r</u></b>ight width.
15061          * @return {Number} The width of the sides passed added together
15062          */
15063         getBorderWidth : function(side){
15064             return this.addStyles(side, borders);
15065         },
15066
15067         /**
15068          * Gets the width of the padding(s) for the specified side(s)
15069          * @param {String} side Can be t, l, r, b or any combination of those to add multiple values. For example,
15070          * passing <tt>'lr'</tt> would get the padding <b><u>l</u></b>eft + the padding <b><u>r</u></b>ight.
15071          * @return {Number} The padding of the sides passed added together
15072          */
15073         getPadding : function(side){
15074             return this.addStyles(side, paddings);
15075         },
15076
15077         /**
15078          *  Store the current overflow setting and clip overflow on the element - use <tt>{@link #unclip}</tt> to remove
15079          * @return {Ext.Element} this
15080          */
15081         clip : function(){
15082             var me = this,
15083                 dom = me.dom;
15084
15085             if(!data(dom, ISCLIPPED)){
15086                 data(dom, ISCLIPPED, true);
15087                 data(dom, ORIGINALCLIP, {
15088                     o: me.getStyle(OVERFLOW),
15089                     x: me.getStyle(OVERFLOWX),
15090                     y: me.getStyle(OVERFLOWY)
15091                 });
15092                 me.setStyle(OVERFLOW, HIDDEN);
15093                 me.setStyle(OVERFLOWX, HIDDEN);
15094                 me.setStyle(OVERFLOWY, HIDDEN);
15095             }
15096             return me;
15097         },
15098
15099         /**
15100          *  Return clipping (overflow) to original clipping before <tt>{@link #clip}</tt> was called
15101          * @return {Ext.Element} this
15102          */
15103         unclip : function(){
15104             var me = this,
15105                 dom = me.dom,
15106                 clip;
15107
15108             if(data(dom, ISCLIPPED)){
15109                 data(dom, ISCLIPPED, false);
15110                 clip = data(dom, ORIGINALCLIP);
15111                 if(clip.o){
15112                     me.setStyle(OVERFLOW, clip.o);
15113                 }
15114                 if(clip.x){
15115                     me.setStyle(OVERFLOWX, clip.x);
15116                 }
15117                 if(clip.y){
15118                     me.setStyle(OVERFLOWY, clip.y);
15119                 }
15120             }
15121             return me;
15122         },
15123
15124         // private
15125         addStyles : function(sides, styles){
15126             var totalSize = 0,
15127                 sidesArr = sides.match(wordsRe),
15128                 i = 0,
15129                 len = sidesArr.length,
15130                 side, size;
15131             for (; i < len; i++) {
15132                 side = sidesArr[i];
15133                 size = side && parseInt(this.getStyle(styles[side]), 10);
15134                 if (size) {
15135                     totalSize += MATH.abs(size);
15136                 }
15137             }
15138             return totalSize;
15139         },
15140
15141         margins : margins,
15142
15143         /**
15144          * More flexible version of {@link #setStyle} for setting style properties.
15145          * @param {String/Object/Function} styles A style specification string, e.g. "width:100px", or object in the form {width:"100px"}, or
15146          * a function which returns such a specification.
15147          * @return {Ext.Element} this
15148          */
15149         applyStyles : function(style){
15150             Ext.DomHelper.applyStyles(this.dom, style);
15151             return this;
15152         },
15153
15154         /**
15155          * Returns an object with properties matching the styles requested.
15156          * For example, el.getStyles('color', 'font-size', 'width') might return
15157          * {'color': '#FFFFFF', 'font-size': '13px', 'width': '100px'}.
15158          * @param {String} style1 A style name
15159          * @param {String} style2 A style name
15160          * @param {String} etc.
15161          * @return {Object} The style object
15162          */
15163         getStyles : function(){
15164             var styles = {},
15165                 len = arguments.length,
15166                 i = 0, style;
15167
15168             for(; i < len; ++i) {
15169                 style = arguments[i];
15170                 styles[style] = this.getStyle(style);
15171             }
15172             return styles;
15173         },
15174
15175        /**
15176         * <p>Wraps the specified element with a special 9 element markup/CSS block that renders by default as
15177         * a gray container with a gradient background, rounded corners and a 4-way shadow.</p>
15178         * <p>This special markup is used throughout Ext when box wrapping elements ({@link Ext.button.Button},
15179         * {@link Ext.panel.Panel} when <tt>{@link Ext.panel.Panel#frame frame=true}</tt>, {@link Ext.window.Window}).  The markup
15180         * is of this form:</p>
15181         * <pre><code>
15182     Ext.Element.boxMarkup =
15183     &#39;&lt;div class="{0}-tl">&lt;div class="{0}-tr">&lt;div class="{0}-tc">&lt;/div>&lt;/div>&lt;/div>
15184      &lt;div class="{0}-ml">&lt;div class="{0}-mr">&lt;div class="{0}-mc">&lt;/div>&lt;/div>&lt;/div>
15185      &lt;div class="{0}-bl">&lt;div class="{0}-br">&lt;div class="{0}-bc">&lt;/div>&lt;/div>&lt;/div>&#39;;
15186         * </code></pre>
15187         * <p>Example usage:</p>
15188         * <pre><code>
15189     // Basic box wrap
15190     Ext.get("foo").boxWrap();
15191
15192     // You can also add a custom class and use CSS inheritance rules to customize the box look.
15193     // 'x-box-blue' is a built-in alternative -- look at the related CSS definitions as an example
15194     // for how to create a custom box wrap style.
15195     Ext.get("foo").boxWrap().addCls("x-box-blue");
15196         * </code></pre>
15197         * @param {String} class (optional) A base CSS class to apply to the containing wrapper element
15198         * (defaults to <tt>'x-box'</tt>). Note that there are a number of CSS rules that are dependent on
15199         * this name to make the overall effect work, so if you supply an alternate base class, make sure you
15200         * also supply all of the necessary rules.
15201         * @return {Ext.Element} The outermost wrapping element of the created box structure.
15202         */
15203         boxWrap : function(cls){
15204             cls = cls || Ext.baseCSSPrefix + 'box';
15205             var el = Ext.get(this.insertHtml("beforeBegin", "<div class='" + cls + "'>" + Ext.String.format(ELEMENT.boxMarkup, cls) + "</div>"));
15206             Ext.DomQuery.selectNode('.' + cls + '-mc', el.dom).appendChild(this.dom);
15207             return el;
15208         },
15209
15210         /**
15211          * Set the size of this Element. If animation is true, both width and height will be animated concurrently.
15212          * @param {Number/String} width The new width. This may be one of:<div class="mdetail-params"><ul>
15213          * <li>A Number specifying the new width in this Element's {@link #defaultUnit}s (by default, pixels).</li>
15214          * <li>A String used to set the CSS width style. Animation may <b>not</b> be used.
15215          * <li>A size object in the format <code>{width: widthValue, height: heightValue}</code>.</li>
15216          * </ul></div>
15217          * @param {Number/String} height The new height. This may be one of:<div class="mdetail-params"><ul>
15218          * <li>A Number specifying the new height in this Element's {@link #defaultUnit}s (by default, pixels).</li>
15219          * <li>A String used to set the CSS height style. Animation may <b>not</b> be used.</li>
15220          * </ul></div>
15221          * @param {Boolean/Object} animate (optional) true for the default animation or a standard Element animation config object
15222          * @return {Ext.Element} this
15223          */
15224         setSize : function(width, height, animate){
15225             var me = this;
15226             if (Ext.isObject(width)) { // in case of object from getSize()
15227                 animate = height;
15228                 height = width.height;
15229                 width = width.width;
15230             }
15231             width = me.adjustWidth(width);
15232             height = me.adjustHeight(height);
15233             if(!animate || !me.anim){
15234                 // Must touch some property before setting style.width/height on non-quirk IE6,7, or the
15235                 // properties will not reflect the changes on the style immediately
15236                 if (!Ext.isIEQuirks && (Ext.isIE6 || Ext.isIE7)) {
15237                     me.dom.offsetTop;
15238                 }
15239                 me.dom.style.width = me.addUnits(width);
15240                 me.dom.style.height = me.addUnits(height);
15241             }
15242             else {
15243                 if (animate === true) {
15244                     animate = {};
15245                 }
15246                 me.animate(Ext.applyIf({
15247                     to: {
15248                         width: width,
15249                         height: height
15250                     }
15251                 }, animate));
15252             }
15253             return me;
15254         },
15255
15256         /**
15257          * Returns either the offsetHeight or the height of this element based on CSS height adjusted by padding or borders
15258          * when needed to simulate offsetHeight when offsets aren't available. This may not work on display:none elements
15259          * if a height has not been set using CSS.
15260          * @return {Number}
15261          */
15262         getComputedHeight : function(){
15263             var me = this,
15264                 h = Math.max(me.dom.offsetHeight, me.dom.clientHeight);
15265             if(!h){
15266                 h = parseFloat(me.getStyle('height')) || 0;
15267                 if(!me.isBorderBox()){
15268                     h += me.getFrameWidth('tb');
15269                 }
15270             }
15271             return h;
15272         },
15273
15274         /**
15275          * Returns either the offsetWidth or the width of this element based on CSS width adjusted by padding or borders
15276          * when needed to simulate offsetWidth when offsets aren't available. This may not work on display:none elements
15277          * if a width has not been set using CSS.
15278          * @return {Number}
15279          */
15280         getComputedWidth : function(){
15281             var me = this,
15282                 w = Math.max(me.dom.offsetWidth, me.dom.clientWidth);
15283
15284             if(!w){
15285                 w = parseFloat(me.getStyle('width')) || 0;
15286                 if(!me.isBorderBox()){
15287                     w += me.getFrameWidth('lr');
15288                 }
15289             }
15290             return w;
15291         },
15292
15293         /**
15294          * Returns the sum width of the padding and borders for the passed "sides". See getBorderWidth()
15295          for more information about the sides.
15296          * @param {String} sides
15297          * @return {Number}
15298          */
15299         getFrameWidth : function(sides, onlyContentBox){
15300             return onlyContentBox && this.isBorderBox() ? 0 : (this.getPadding(sides) + this.getBorderWidth(sides));
15301         },
15302
15303         /**
15304          * Sets up event handlers to add and remove a css class when the mouse is over this element
15305          * @param {String} className
15306          * @return {Ext.Element} this
15307          */
15308         addClsOnOver : function(className){
15309             var dom = this.dom;
15310             this.hover(
15311                 function(){
15312                     Ext.fly(dom, INTERNAL).addCls(className);
15313                 },
15314                 function(){
15315                     Ext.fly(dom, INTERNAL).removeCls(className);
15316                 }
15317             );
15318             return this;
15319         },
15320
15321         /**
15322          * Sets up event handlers to add and remove a css class when this element has the focus
15323          * @param {String} className
15324          * @return {Ext.Element} this
15325          */
15326         addClsOnFocus : function(className){
15327             var me = this,
15328                 dom = me.dom;
15329             me.on("focus", function(){
15330                 Ext.fly(dom, INTERNAL).addCls(className);
15331             });
15332             me.on("blur", function(){
15333                 Ext.fly(dom, INTERNAL).removeCls(className);
15334             });
15335             return me;
15336         },
15337
15338         /**
15339          * Sets up event handlers to add and remove a css class when the mouse is down and then up on this element (a click effect)
15340          * @param {String} className
15341          * @return {Ext.Element} this
15342          */
15343         addClsOnClick : function(className){
15344             var dom = this.dom;
15345             this.on("mousedown", function(){
15346                 Ext.fly(dom, INTERNAL).addCls(className);
15347                 var d = Ext.getDoc(),
15348                     fn = function(){
15349                         Ext.fly(dom, INTERNAL).removeCls(className);
15350                         d.removeListener("mouseup", fn);
15351                     };
15352                 d.on("mouseup", fn);
15353             });
15354             return this;
15355         },
15356
15357         /**
15358          * <p>Returns the dimensions of the element available to lay content out in.<p>
15359          * <p>If the element (or any ancestor element) has CSS style <code>display : none</code>, the dimensions will be zero.</p>
15360          * example:<pre><code>
15361         var vpSize = Ext.getBody().getViewSize();
15362
15363         // all Windows created afterwards will have a default value of 90% height and 95% width
15364         Ext.Window.override({
15365             width: vpSize.width * 0.9,
15366             height: vpSize.height * 0.95
15367         });
15368         // To handle window resizing you would have to hook onto onWindowResize.
15369         * </code></pre>
15370         *
15371         * getViewSize utilizes clientHeight/clientWidth which excludes sizing of scrollbars.
15372         * To obtain the size including scrollbars, use getStyleSize
15373         *
15374         * Sizing of the document body is handled at the adapter level which handles special cases for IE and strict modes, etc.
15375         */
15376
15377         getViewSize : function(){
15378             var me = this,
15379                 dom = me.dom,
15380                 isDoc = (dom == Ext.getDoc().dom || dom == Ext.getBody().dom),
15381                 style, overflow, ret;
15382
15383             // If the body, use static methods
15384             if (isDoc) {
15385                 ret = {
15386                     width : ELEMENT.getViewWidth(),
15387                     height : ELEMENT.getViewHeight()
15388                 };
15389
15390             // Else use clientHeight/clientWidth
15391             }
15392             else {
15393                 // IE 6 & IE Quirks mode acts more like a max-size measurement unless overflow is hidden during measurement.
15394                 // We will put the overflow back to it's original value when we are done measuring.
15395                 if (Ext.isIE6 || Ext.isIEQuirks) {
15396                     style = dom.style;
15397                     overflow = style.overflow;
15398                     me.setStyle({ overflow: 'hidden'});
15399                 }
15400                 ret = {
15401                     width : dom.clientWidth,
15402                     height : dom.clientHeight
15403                 };
15404                 if (Ext.isIE6 || Ext.isIEQuirks) {
15405                     me.setStyle({ overflow: overflow });
15406                 }
15407             }
15408             return ret;
15409         },
15410
15411         /**
15412         * <p>Returns the dimensions of the element available to lay content out in.<p>
15413         *
15414         * getStyleSize utilizes prefers style sizing if present, otherwise it chooses the larger of offsetHeight/clientHeight and offsetWidth/clientWidth.
15415         * To obtain the size excluding scrollbars, use getViewSize
15416         *
15417         * Sizing of the document body is handled at the adapter level which handles special cases for IE and strict modes, etc.
15418         */
15419
15420         getStyleSize : function(){
15421             var me = this,
15422                 doc = document,
15423                 d = this.dom,
15424                 isDoc = (d == doc || d == doc.body),
15425                 s = d.style,
15426                 w, h;
15427
15428             // If the body, use static methods
15429             if (isDoc) {
15430                 return {
15431                     width : ELEMENT.getViewWidth(),
15432                     height : ELEMENT.getViewHeight()
15433                 };
15434             }
15435             // Use Styles if they are set
15436             if(s.width && s.width != 'auto'){
15437                 w = parseFloat(s.width);
15438                 if(me.isBorderBox()){
15439                    w -= me.getFrameWidth('lr');
15440                 }
15441             }
15442             // Use Styles if they are set
15443             if(s.height && s.height != 'auto'){
15444                 h = parseFloat(s.height);
15445                 if(me.isBorderBox()){
15446                    h -= me.getFrameWidth('tb');
15447                 }
15448             }
15449             // Use getWidth/getHeight if style not set.
15450             return {width: w || me.getWidth(true), height: h || me.getHeight(true)};
15451         },
15452
15453         /**
15454          * Returns the size of the element.
15455          * @param {Boolean} contentSize (optional) true to get the width/size minus borders and padding
15456          * @return {Object} An object containing the element's size {width: (element width), height: (element height)}
15457          */
15458         getSize : function(contentSize){
15459             return {width: this.getWidth(contentSize), height: this.getHeight(contentSize)};
15460         },
15461
15462         /**
15463          * Forces the browser to repaint this element
15464          * @return {Ext.Element} this
15465          */
15466         repaint : function(){
15467             var dom = this.dom;
15468             this.addCls(Ext.baseCSSPrefix + 'repaint');
15469             setTimeout(function(){
15470                 Ext.fly(dom).removeCls(Ext.baseCSSPrefix + 'repaint');
15471             }, 1);
15472             return this;
15473         },
15474
15475         /**
15476          * Enable text selection for this element (normalized across browsers)
15477          * @return {Ext.Element} this
15478          */
15479         selectable : function() {
15480             var me = this;
15481             me.dom.unselectable = "off";
15482             // Prevent it from bubles up and enables it to be selectable
15483             me.on('selectstart', function (e) {
15484                 e.stopPropagation();
15485                 return true;
15486             });
15487             me.applyStyles("-moz-user-select: text; -khtml-user-select: text;");
15488             me.removeCls(Ext.baseCSSPrefix + 'unselectable');
15489             return me;
15490         },
15491
15492         /**
15493          * Disables text selection for this element (normalized across browsers)
15494          * @return {Ext.Element} this
15495          */
15496         unselectable : function(){
15497             var me = this;
15498             me.dom.unselectable = "on";
15499
15500             me.swallowEvent("selectstart", true);
15501             me.applyStyles("-moz-user-select:-moz-none;-khtml-user-select:none;");
15502             me.addCls(Ext.baseCSSPrefix + 'unselectable');
15503
15504             return me;
15505         },
15506
15507         /**
15508          * Returns an object with properties top, left, right and bottom representing the margins of this element unless sides is passed,
15509          * then it returns the calculated width of the sides (see getPadding)
15510          * @param {String} sides (optional) Any combination of l, r, t, b to get the sum of those sides
15511          * @return {Object/Number}
15512          */
15513         getMargin : function(side){
15514             var me = this,
15515                 hash = {t:"top", l:"left", r:"right", b: "bottom"},
15516                 o = {},
15517                 key;
15518
15519             if (!side) {
15520                 for (key in me.margins){
15521                     o[hash[key]] = parseFloat(me.getStyle(me.margins[key])) || 0;
15522                 }
15523                 return o;
15524             } else {
15525                 return me.addStyles.call(me, side, me.margins);
15526             }
15527         }
15528     });
15529 })();
15530 /**
15531  * @class Ext.Element
15532  */
15533 /**
15534  * Visibility mode constant for use with {@link #setVisibilityMode}. Use visibility to hide element
15535  * @static
15536  * @type Number
15537  */
15538 Ext.Element.VISIBILITY = 1;
15539 /**
15540  * Visibility mode constant for use with {@link #setVisibilityMode}. Use display to hide element
15541  * @static
15542  * @type Number
15543  */
15544 Ext.Element.DISPLAY = 2;
15545
15546 /**
15547  * Visibility mode constant for use with {@link #setVisibilityMode}. Use offsets (x and y positioning offscreen)
15548  * to hide element.
15549  * @static
15550  * @type Number
15551  */
15552 Ext.Element.OFFSETS = 3;
15553
15554
15555 Ext.Element.ASCLASS = 4;
15556
15557 /**
15558  * Defaults to 'x-hide-nosize'
15559  * @static
15560  * @type String
15561  */
15562 Ext.Element.visibilityCls = Ext.baseCSSPrefix + 'hide-nosize';
15563
15564 Ext.Element.addMethods(function(){
15565     var El = Ext.Element,
15566         OPACITY = "opacity",
15567         VISIBILITY = "visibility",
15568         DISPLAY = "display",
15569         HIDDEN = "hidden",
15570         OFFSETS = "offsets",
15571         ASCLASS = "asclass",
15572         NONE = "none",
15573         NOSIZE = 'nosize',
15574         ORIGINALDISPLAY = 'originalDisplay',
15575         VISMODE = 'visibilityMode',
15576         ISVISIBLE = 'isVisible',
15577         data = El.data,
15578         getDisplay = function(dom){
15579             var d = data(dom, ORIGINALDISPLAY);
15580             if(d === undefined){
15581                 data(dom, ORIGINALDISPLAY, d = '');
15582             }
15583             return d;
15584         },
15585         getVisMode = function(dom){
15586             var m = data(dom, VISMODE);
15587             if(m === undefined){
15588                 data(dom, VISMODE, m = 1);
15589             }
15590             return m;
15591         };
15592
15593     return {
15594         /**
15595          * @property {String} originalDisplay
15596          * The element's default display mode
15597          */
15598         originalDisplay : "",
15599         visibilityMode : 1,
15600
15601         /**
15602          * Sets the element's visibility mode. When setVisible() is called it
15603          * will use this to determine whether to set the visibility or the display property.
15604          * @param {Number} visMode Ext.Element.VISIBILITY or Ext.Element.DISPLAY
15605          * @return {Ext.Element} this
15606          */
15607         setVisibilityMode : function(visMode){
15608             data(this.dom, VISMODE, visMode);
15609             return this;
15610         },
15611
15612         /**
15613          * Checks whether the element is currently visible using both visibility and display properties.
15614          * @return {Boolean} True if the element is currently visible, else false
15615          */
15616         isVisible : function() {
15617             var me = this,
15618                 dom = me.dom,
15619                 visible = data(dom, ISVISIBLE);
15620
15621             if(typeof visible == 'boolean'){ //return the cached value if registered
15622                 return visible;
15623             }
15624             //Determine the current state based on display states
15625             visible = !me.isStyle(VISIBILITY, HIDDEN) &&
15626                       !me.isStyle(DISPLAY, NONE) &&
15627                       !((getVisMode(dom) == El.ASCLASS) && me.hasCls(me.visibilityCls || El.visibilityCls));
15628
15629             data(dom, ISVISIBLE, visible);
15630             return visible;
15631         },
15632
15633         /**
15634          * Sets the visibility of the element (see details). If the visibilityMode is set to Element.DISPLAY, it will use
15635          * the display property to hide the element, otherwise it uses visibility. The default is to hide and show using the visibility property.
15636          * @param {Boolean} visible Whether the element is visible
15637          * @param {Boolean/Object} animate (optional) True for the default animation, or a standard Element animation config object
15638          * @return {Ext.Element} this
15639          */
15640         setVisible : function(visible, animate){
15641             var me = this, isDisplay, isVisibility, isOffsets, isNosize,
15642                 dom = me.dom,
15643                 visMode = getVisMode(dom);
15644
15645
15646             // hideMode string override
15647             if (typeof animate == 'string'){
15648                 switch (animate) {
15649                     case DISPLAY:
15650                         visMode = El.DISPLAY;
15651                         break;
15652                     case VISIBILITY:
15653                         visMode = El.VISIBILITY;
15654                         break;
15655                     case OFFSETS:
15656                         visMode = El.OFFSETS;
15657                         break;
15658                     case NOSIZE:
15659                     case ASCLASS:
15660                         visMode = El.ASCLASS;
15661                         break;
15662                 }
15663                 me.setVisibilityMode(visMode);
15664                 animate = false;
15665             }
15666
15667             if (!animate || !me.anim) {
15668                 if(visMode == El.ASCLASS ){
15669
15670                     me[visible?'removeCls':'addCls'](me.visibilityCls || El.visibilityCls);
15671
15672                 } else if (visMode == El.DISPLAY){
15673
15674                     return me.setDisplayed(visible);
15675
15676                 } else if (visMode == El.OFFSETS){
15677
15678                     if (!visible){
15679                         // Remember position for restoring, if we are not already hidden by offsets.
15680                         if (!me.hideModeStyles) {
15681                             me.hideModeStyles = {
15682                                 position: me.getStyle('position'),
15683                                 top: me.getStyle('top'),
15684                                 left: me.getStyle('left')
15685                             };
15686                         }
15687                         me.applyStyles({position: 'absolute', top: '-10000px', left: '-10000px'});
15688                     }
15689
15690                     // Only "restore" as position if we have actually been hidden using offsets.
15691                     // Calling setVisible(true) on a positioned element should not reposition it.
15692                     else if (me.hideModeStyles) {
15693                         me.applyStyles(me.hideModeStyles || {position: '', top: '', left: ''});
15694                         delete me.hideModeStyles;
15695                     }
15696
15697                 }else{
15698                     me.fixDisplay();
15699                     // Show by clearing visibility style. Explicitly setting to "visible" overrides parent visibility setting.
15700                     dom.style.visibility = visible ? '' : HIDDEN;
15701                 }
15702             }else{
15703                 // closure for composites
15704                 if(visible){
15705                     me.setOpacity(0.01);
15706                     me.setVisible(true);
15707                 }
15708                 if (!Ext.isObject(animate)) {
15709                     animate = {
15710                         duration: 350,
15711                         easing: 'ease-in'
15712                     };
15713                 }
15714                 me.animate(Ext.applyIf({
15715                     callback: function() {
15716                         visible || me.setVisible(false).setOpacity(1);
15717                     },
15718                     to: {
15719                         opacity: (visible) ? 1 : 0
15720                     }
15721                 }, animate));
15722             }
15723             data(dom, ISVISIBLE, visible);  //set logical visibility state
15724             return me;
15725         },
15726
15727
15728         /**
15729          * @private
15730          * Determine if the Element has a relevant height and width available based
15731          * upon current logical visibility state
15732          */
15733         hasMetrics  : function(){
15734             var dom = this.dom;
15735             return this.isVisible() || (getVisMode(dom) == El.OFFSETS) || (getVisMode(dom) == El.VISIBILITY);
15736         },
15737
15738         /**
15739          * Toggles the element's visibility or display, depending on visibility mode.
15740          * @param {Boolean/Object} animate (optional) True for the default animation, or a standard Element animation config object
15741          * @return {Ext.Element} this
15742          */
15743         toggle : function(animate){
15744             var me = this;
15745             me.setVisible(!me.isVisible(), me.anim(animate));
15746             return me;
15747         },
15748
15749         /**
15750          * Sets the CSS display property. Uses originalDisplay if the specified value is a boolean true.
15751          * @param {Boolean/String} value Boolean value to display the element using its default display, or a string to set the display directly.
15752          * @return {Ext.Element} this
15753          */
15754         setDisplayed : function(value) {
15755             if(typeof value == "boolean"){
15756                value = value ? getDisplay(this.dom) : NONE;
15757             }
15758             this.setStyle(DISPLAY, value);
15759             return this;
15760         },
15761
15762         // private
15763         fixDisplay : function(){
15764             var me = this;
15765             if (me.isStyle(DISPLAY, NONE)) {
15766                 me.setStyle(VISIBILITY, HIDDEN);
15767                 me.setStyle(DISPLAY, getDisplay(this.dom)); // first try reverting to default
15768                 if (me.isStyle(DISPLAY, NONE)) { // if that fails, default to block
15769                     me.setStyle(DISPLAY, "block");
15770                 }
15771             }
15772         },
15773
15774         /**
15775          * Hide this element - Uses display mode to determine whether to use "display" or "visibility". See {@link #setVisible}.
15776          * @param {Boolean/Object} animate (optional) true for the default animation or a standard Element animation config object
15777          * @return {Ext.Element} this
15778          */
15779         hide : function(animate){
15780             // hideMode override
15781             if (typeof animate == 'string'){
15782                 this.setVisible(false, animate);
15783                 return this;
15784             }
15785             this.setVisible(false, this.anim(animate));
15786             return this;
15787         },
15788
15789         /**
15790         * Show this element - Uses display mode to determine whether to use "display" or "visibility". See {@link #setVisible}.
15791         * @param {Boolean/Object} animate (optional) true for the default animation or a standard Element animation config object
15792          * @return {Ext.Element} this
15793          */
15794         show : function(animate){
15795             // hideMode override
15796             if (typeof animate == 'string'){
15797                 this.setVisible(true, animate);
15798                 return this;
15799             }
15800             this.setVisible(true, this.anim(animate));
15801             return this;
15802         }
15803     };
15804 }());
15805 /**
15806  * @class Ext.Element
15807  */
15808 Ext.applyIf(Ext.Element.prototype, {
15809     // @private override base Ext.util.Animate mixin for animate for backwards compatibility
15810     animate: function(config) {
15811         var me = this;
15812         if (!me.id) {
15813             me = Ext.get(me.dom);
15814         }
15815         if (Ext.fx.Manager.hasFxBlock(me.id)) {
15816             return me;
15817         }
15818         Ext.fx.Manager.queueFx(Ext.create('Ext.fx.Anim', me.anim(config)));
15819         return this;
15820     },
15821
15822     // @private override base Ext.util.Animate mixin for animate for backwards compatibility
15823     anim: function(config) {
15824         if (!Ext.isObject(config)) {
15825             return (config) ? {} : false;
15826         }
15827
15828         var me = this,
15829             duration = config.duration || Ext.fx.Anim.prototype.duration,
15830             easing = config.easing || 'ease',
15831             animConfig;
15832
15833         if (config.stopAnimation) {
15834             me.stopAnimation();
15835         }
15836
15837         Ext.applyIf(config, Ext.fx.Manager.getFxDefaults(me.id));
15838
15839         // Clear any 'paused' defaults.
15840         Ext.fx.Manager.setFxDefaults(me.id, {
15841             delay: 0
15842         });
15843
15844         animConfig = {
15845             target: me,
15846             remove: config.remove,
15847             alternate: config.alternate || false,
15848             duration: duration,
15849             easing: easing,
15850             callback: config.callback,
15851             listeners: config.listeners,
15852             iterations: config.iterations || 1,
15853             scope: config.scope,
15854             block: config.block,
15855             concurrent: config.concurrent,
15856             delay: config.delay || 0,
15857             paused: true,
15858             keyframes: config.keyframes,
15859             from: config.from || {},
15860             to: Ext.apply({}, config)
15861         };
15862         Ext.apply(animConfig.to, config.to);
15863
15864         // Anim API properties - backward compat
15865         delete animConfig.to.to;
15866         delete animConfig.to.from;
15867         delete animConfig.to.remove;
15868         delete animConfig.to.alternate;
15869         delete animConfig.to.keyframes;
15870         delete animConfig.to.iterations;
15871         delete animConfig.to.listeners;
15872         delete animConfig.to.target;
15873         delete animConfig.to.paused;
15874         delete animConfig.to.callback;
15875         delete animConfig.to.scope;
15876         delete animConfig.to.duration;
15877         delete animConfig.to.easing;
15878         delete animConfig.to.concurrent;
15879         delete animConfig.to.block;
15880         delete animConfig.to.stopAnimation;
15881         delete animConfig.to.delay;
15882         return animConfig;
15883     },
15884
15885     /**
15886      * Slides the element into view. An anchor point can be optionally passed to set the point of origin for the slide
15887      * effect. This function automatically handles wrapping the element with a fixed-size container if needed. See the
15888      * Fx class overview for valid anchor point options. Usage:
15889      *
15890      *     // default: slide the element in from the top
15891      *     el.slideIn();
15892      *
15893      *     // custom: slide the element in from the right with a 2-second duration
15894      *     el.slideIn('r', { duration: 2000 });
15895      *
15896      *     // common config options shown with default values
15897      *     el.slideIn('t', {
15898      *         easing: 'easeOut',
15899      *         duration: 500
15900      *     });
15901      *
15902      * @param {String} [anchor='t'] One of the valid Fx anchor positions
15903      * @param {Object} [options] Object literal with any of the Fx config options
15904      * @return {Ext.Element} The Element
15905      */
15906     slideIn: function(anchor, obj, slideOut) {
15907         var me = this,
15908             elStyle = me.dom.style,
15909             beforeAnim, wrapAnim;
15910
15911         anchor = anchor || "t";
15912         obj = obj || {};
15913
15914         beforeAnim = function() {
15915             var animScope = this,
15916                 listeners = obj.listeners,
15917                 box, position, restoreSize, wrap, anim;
15918
15919             if (!slideOut) {
15920                 me.fixDisplay();
15921             }
15922
15923             box = me.getBox();
15924             if ((anchor == 't' || anchor == 'b') && box.height === 0) {
15925                 box.height = me.dom.scrollHeight;
15926             }
15927             else if ((anchor == 'l' || anchor == 'r') && box.width === 0) {
15928                 box.width = me.dom.scrollWidth;
15929             }
15930
15931             position = me.getPositioning();
15932             me.setSize(box.width, box.height);
15933
15934             wrap = me.wrap({
15935                 style: {
15936                     visibility: slideOut ? 'visible' : 'hidden'
15937                 }
15938             });
15939             wrap.setPositioning(position);
15940             if (wrap.isStyle('position', 'static')) {
15941                 wrap.position('relative');
15942             }
15943             me.clearPositioning('auto');
15944             wrap.clip();
15945
15946             // This element is temporarily positioned absolute within its wrapper.
15947             // Restore to its default, CSS-inherited visibility setting.
15948             // We cannot explicitly poke visibility:visible into its style because that overrides the visibility of the wrap.
15949             me.setStyle({
15950                 visibility: '',
15951                 position: 'absolute'
15952             });
15953             if (slideOut) {
15954                 wrap.setSize(box.width, box.height);
15955             }
15956
15957             switch (anchor) {
15958                 case 't':
15959                     anim = {
15960                         from: {
15961                             width: box.width + 'px',
15962                             height: '0px'
15963                         },
15964                         to: {
15965                             width: box.width + 'px',
15966                             height: box.height + 'px'
15967                         }
15968                     };
15969                     elStyle.bottom = '0px';
15970                     break;
15971                 case 'l':
15972                     anim = {
15973                         from: {
15974                             width: '0px',
15975                             height: box.height + 'px'
15976                         },
15977                         to: {
15978                             width: box.width + 'px',
15979                             height: box.height + 'px'
15980                         }
15981                     };
15982                     elStyle.right = '0px';
15983                     break;
15984                 case 'r':
15985                     anim = {
15986                         from: {
15987                             x: box.x + box.width,
15988                             width: '0px',
15989                             height: box.height + 'px'
15990                         },
15991                         to: {
15992                             x: box.x,
15993                             width: box.width + 'px',
15994                             height: box.height + 'px'
15995                         }
15996                     };
15997                     break;
15998                 case 'b':
15999                     anim = {
16000                         from: {
16001                             y: box.y + box.height,
16002                             width: box.width + 'px',
16003                             height: '0px'
16004                         },
16005                         to: {
16006                             y: box.y,
16007                             width: box.width + 'px',
16008                             height: box.height + 'px'
16009                         }
16010                     };
16011                     break;
16012                 case 'tl':
16013                     anim = {
16014                         from: {
16015                             x: box.x,
16016                             y: box.y,
16017                             width: '0px',
16018                             height: '0px'
16019                         },
16020                         to: {
16021                             width: box.width + 'px',
16022                             height: box.height + 'px'
16023                         }
16024                     };
16025                     elStyle.bottom = '0px';
16026                     elStyle.right = '0px';
16027                     break;
16028                 case 'bl':
16029                     anim = {
16030                         from: {
16031                             x: box.x + box.width,
16032                             width: '0px',
16033                             height: '0px'
16034                         },
16035                         to: {
16036                             x: box.x,
16037                             width: box.width + 'px',
16038                             height: box.height + 'px'
16039                         }
16040                     };
16041                     elStyle.right = '0px';
16042                     break;
16043                 case 'br':
16044                     anim = {
16045                         from: {
16046                             x: box.x + box.width,
16047                             y: box.y + box.height,
16048                             width: '0px',
16049                             height: '0px'
16050                         },
16051                         to: {
16052                             x: box.x,
16053                             y: box.y,
16054                             width: box.width + 'px',
16055                             height: box.height + 'px'
16056                         }
16057                     };
16058                     break;
16059                 case 'tr':
16060                     anim = {
16061                         from: {
16062                             y: box.y + box.height,
16063                             width: '0px',
16064                             height: '0px'
16065                         },
16066                         to: {
16067                             y: box.y,
16068                             width: box.width + 'px',
16069                             height: box.height + 'px'
16070                         }
16071                     };
16072                     elStyle.bottom = '0px';
16073                     break;
16074             }
16075
16076             wrap.show();
16077             wrapAnim = Ext.apply({}, obj);
16078             delete wrapAnim.listeners;
16079             wrapAnim = Ext.create('Ext.fx.Anim', Ext.applyIf(wrapAnim, {
16080                 target: wrap,
16081                 duration: 500,
16082                 easing: 'ease-out',
16083                 from: slideOut ? anim.to : anim.from,
16084                 to: slideOut ? anim.from : anim.to
16085             }));
16086
16087             // In the absence of a callback, this listener MUST be added first
16088             wrapAnim.on('afteranimate', function() {
16089                 if (slideOut) {
16090                     me.setPositioning(position);
16091                     if (obj.useDisplay) {
16092                         me.setDisplayed(false);
16093                     } else {
16094                         me.hide();
16095                     }
16096                 }
16097                 else {
16098                     me.clearPositioning();
16099                     me.setPositioning(position);
16100                 }
16101                 if (wrap.dom) {
16102                     wrap.dom.parentNode.insertBefore(me.dom, wrap.dom);
16103                     wrap.remove();
16104                 }
16105                 me.setSize(box.width, box.height);
16106                 animScope.end();
16107             });
16108             // Add configured listeners after
16109             if (listeners) {
16110                 wrapAnim.on(listeners);
16111             }
16112         };
16113
16114         me.animate({
16115             duration: obj.duration ? obj.duration * 2 : 1000,
16116             listeners: {
16117                 beforeanimate: {
16118                     fn: beforeAnim
16119                 },
16120                 afteranimate: {
16121                     fn: function() {
16122                         if (wrapAnim && wrapAnim.running) {
16123                             wrapAnim.end();
16124                         }
16125                     }
16126                 }
16127             }
16128         });
16129         return me;
16130     },
16131
16132
16133     /**
16134      * Slides the element out of view. An anchor point can be optionally passed to set the end point for the slide
16135      * effect. When the effect is completed, the element will be hidden (visibility = 'hidden') but block elements will
16136      * still take up space in the document. The element must be removed from the DOM using the 'remove' config option if
16137      * desired. This function automatically handles wrapping the element with a fixed-size container if needed. See the
16138      * Fx class overview for valid anchor point options. Usage:
16139      *
16140      *     // default: slide the element out to the top
16141      *     el.slideOut();
16142      *
16143      *     // custom: slide the element out to the right with a 2-second duration
16144      *     el.slideOut('r', { duration: 2000 });
16145      *
16146      *     // common config options shown with default values
16147      *     el.slideOut('t', {
16148      *         easing: 'easeOut',
16149      *         duration: 500,
16150      *         remove: false,
16151      *         useDisplay: false
16152      *     });
16153      *
16154      * @param {String} [anchor='t'] One of the valid Fx anchor positions
16155      * @param {Object} [options] Object literal with any of the Fx config options
16156      * @return {Ext.Element} The Element
16157      */
16158     slideOut: function(anchor, o) {
16159         return this.slideIn(anchor, o, true);
16160     },
16161
16162     /**
16163      * Fades the element out while slowly expanding it in all directions. When the effect is completed, the element will
16164      * be hidden (visibility = 'hidden') but block elements will still take up space in the document. Usage:
16165      *
16166      *     // default
16167      *     el.puff();
16168      *
16169      *     // common config options shown with default values
16170      *     el.puff({
16171      *         easing: 'easeOut',
16172      *         duration: 500,
16173      *         useDisplay: false
16174      *     });
16175      *
16176      * @param {Object} options (optional) Object literal with any of the Fx config options
16177      * @return {Ext.Element} The Element
16178      */
16179     puff: function(obj) {
16180         var me = this,
16181             beforeAnim;
16182         obj = Ext.applyIf(obj || {}, {
16183             easing: 'ease-out',
16184             duration: 500,
16185             useDisplay: false
16186         });
16187
16188         beforeAnim = function() {
16189             me.clearOpacity();
16190             me.show();
16191
16192             var box = me.getBox(),
16193                 fontSize = me.getStyle('fontSize'),
16194                 position = me.getPositioning();
16195             this.to = {
16196                 width: box.width * 2,
16197                 height: box.height * 2,
16198                 x: box.x - (box.width / 2),
16199                 y: box.y - (box.height /2),
16200                 opacity: 0,
16201                 fontSize: '200%'
16202             };
16203             this.on('afteranimate',function() {
16204                 if (me.dom) {
16205                     if (obj.useDisplay) {
16206                         me.setDisplayed(false);
16207                     } else {
16208                         me.hide();
16209                     }
16210                     me.clearOpacity();
16211                     me.setPositioning(position);
16212                     me.setStyle({fontSize: fontSize});
16213                 }
16214             });
16215         };
16216
16217         me.animate({
16218             duration: obj.duration,
16219             easing: obj.easing,
16220             listeners: {
16221                 beforeanimate: {
16222                     fn: beforeAnim
16223                 }
16224             }
16225         });
16226         return me;
16227     },
16228
16229     /**
16230      * Blinks the element as if it was clicked and then collapses on its center (similar to switching off a television).
16231      * When the effect is completed, the element will be hidden (visibility = 'hidden') but block elements will still
16232      * take up space in the document. The element must be removed from the DOM using the 'remove' config option if
16233      * desired. Usage:
16234      *
16235      *     // default
16236      *     el.switchOff();
16237      *
16238      *     // all config options shown with default values
16239      *     el.switchOff({
16240      *         easing: 'easeIn',
16241      *         duration: .3,
16242      *         remove: false,
16243      *         useDisplay: false
16244      *     });
16245      *
16246      * @param {Object} options (optional) Object literal with any of the Fx config options
16247      * @return {Ext.Element} The Element
16248      */
16249     switchOff: function(obj) {
16250         var me = this,
16251             beforeAnim;
16252
16253         obj = Ext.applyIf(obj || {}, {
16254             easing: 'ease-in',
16255             duration: 500,
16256             remove: false,
16257             useDisplay: false
16258         });
16259
16260         beforeAnim = function() {
16261             var animScope = this,
16262                 size = me.getSize(),
16263                 xy = me.getXY(),
16264                 keyframe, position;
16265             me.clearOpacity();
16266             me.clip();
16267             position = me.getPositioning();
16268
16269             keyframe = Ext.create('Ext.fx.Animator', {
16270                 target: me,
16271                 duration: obj.duration,
16272                 easing: obj.easing,
16273                 keyframes: {
16274                     33: {
16275                         opacity: 0.3
16276                     },
16277                     66: {
16278                         height: 1,
16279                         y: xy[1] + size.height / 2
16280                     },
16281                     100: {
16282                         width: 1,
16283                         x: xy[0] + size.width / 2
16284                     }
16285                 }
16286             });
16287             keyframe.on('afteranimate', function() {
16288                 if (obj.useDisplay) {
16289                     me.setDisplayed(false);
16290                 } else {
16291                     me.hide();
16292                 }
16293                 me.clearOpacity();
16294                 me.setPositioning(position);
16295                 me.setSize(size);
16296                 animScope.end();
16297             });
16298         };
16299         me.animate({
16300             duration: (obj.duration * 2),
16301             listeners: {
16302                 beforeanimate: {
16303                     fn: beforeAnim
16304                 }
16305             }
16306         });
16307         return me;
16308     },
16309
16310     /**
16311      * Shows a ripple of exploding, attenuating borders to draw attention to an Element. Usage:
16312      *
16313      *     // default: a single light blue ripple
16314      *     el.frame();
16315      *
16316      *     // custom: 3 red ripples lasting 3 seconds total
16317      *     el.frame("#ff0000", 3, { duration: 3 });
16318      *
16319      *     // common config options shown with default values
16320      *     el.frame("#C3DAF9", 1, {
16321      *         duration: 1 //duration of each individual ripple.
16322      *         // Note: Easing is not configurable and will be ignored if included
16323      *     });
16324      *
16325      * @param {String} [color='C3DAF9'] The color of the border. Should be a 6 char hex color without the leading #
16326      * (defaults to light blue).
16327      * @param {Number} [count=1] The number of ripples to display
16328      * @param {Object} [options] Object literal with any of the Fx config options
16329      * @return {Ext.Element} The Element
16330      */
16331     frame : function(color, count, obj){
16332         var me = this,
16333             beforeAnim;
16334
16335         color = color || '#C3DAF9';
16336         count = count || 1;
16337         obj = obj || {};
16338
16339         beforeAnim = function() {
16340             me.show();
16341             var animScope = this,
16342                 box = me.getBox(),
16343                 proxy = Ext.getBody().createChild({
16344                     style: {
16345                         position : 'absolute',
16346                         'pointer-events': 'none',
16347                         'z-index': 35000,
16348                         border : '0px solid ' + color
16349                     }
16350                 }),
16351                 proxyAnim;
16352             proxyAnim = Ext.create('Ext.fx.Anim', {
16353                 target: proxy,
16354                 duration: obj.duration || 1000,
16355                 iterations: count,
16356                 from: {
16357                     top: box.y,
16358                     left: box.x,
16359                     borderWidth: 0,
16360                     opacity: 1,
16361                     height: box.height,
16362                     width: box.width
16363                 },
16364                 to: {
16365                     top: box.y - 20,
16366                     left: box.x - 20,
16367                     borderWidth: 10,
16368                     opacity: 0,
16369                     height: box.height + 40,
16370                     width: box.width + 40
16371                 }
16372             });
16373             proxyAnim.on('afteranimate', function() {
16374                 proxy.remove();
16375                 animScope.end();
16376             });
16377         };
16378
16379         me.animate({
16380             duration: (obj.duration * 2) || 2000,
16381             listeners: {
16382                 beforeanimate: {
16383                     fn: beforeAnim
16384                 }
16385             }
16386         });
16387         return me;
16388     },
16389
16390     /**
16391      * Slides the element while fading it out of view. An anchor point can be optionally passed to set the ending point
16392      * of the effect. Usage:
16393      *
16394      *     // default: slide the element downward while fading out
16395      *     el.ghost();
16396      *
16397      *     // custom: slide the element out to the right with a 2-second duration
16398      *     el.ghost('r', { duration: 2000 });
16399      *
16400      *     // common config options shown with default values
16401      *     el.ghost('b', {
16402      *         easing: 'easeOut',
16403      *         duration: 500
16404      *     });
16405      *
16406      * @param {String} [anchor='b'] One of the valid Fx anchor positions
16407      * @param {Object} [options] Object literal with any of the Fx config options
16408      * @return {Ext.Element} The Element
16409      */
16410     ghost: function(anchor, obj) {
16411         var me = this,
16412             beforeAnim;
16413
16414         anchor = anchor || "b";
16415         beforeAnim = function() {
16416             var width = me.getWidth(),
16417                 height = me.getHeight(),
16418                 xy = me.getXY(),
16419                 position = me.getPositioning(),
16420                 to = {
16421                     opacity: 0
16422                 };
16423             switch (anchor) {
16424                 case 't':
16425                     to.y = xy[1] - height;
16426                     break;
16427                 case 'l':
16428                     to.x = xy[0] - width;
16429                     break;
16430                 case 'r':
16431                     to.x = xy[0] + width;
16432                     break;
16433                 case 'b':
16434                     to.y = xy[1] + height;
16435                     break;
16436                 case 'tl':
16437                     to.x = xy[0] - width;
16438                     to.y = xy[1] - height;
16439                     break;
16440                 case 'bl':
16441                     to.x = xy[0] - width;
16442                     to.y = xy[1] + height;
16443                     break;
16444                 case 'br':
16445                     to.x = xy[0] + width;
16446                     to.y = xy[1] + height;
16447                     break;
16448                 case 'tr':
16449                     to.x = xy[0] + width;
16450                     to.y = xy[1] - height;
16451                     break;
16452             }
16453             this.to = to;
16454             this.on('afteranimate', function () {
16455                 if (me.dom) {
16456                     me.hide();
16457                     me.clearOpacity();
16458                     me.setPositioning(position);
16459                 }
16460             });
16461         };
16462
16463         me.animate(Ext.applyIf(obj || {}, {
16464             duration: 500,
16465             easing: 'ease-out',
16466             listeners: {
16467                 beforeanimate: {
16468                     fn: beforeAnim
16469                 }
16470             }
16471         }));
16472         return me;
16473     },
16474
16475     /**
16476      * Highlights the Element by setting a color (applies to the background-color by default, but can be changed using
16477      * the "attr" config option) and then fading back to the original color. If no original color is available, you
16478      * should provide the "endColor" config option which will be cleared after the animation. Usage:
16479      *
16480      *     // default: highlight background to yellow
16481      *     el.highlight();
16482      *
16483      *     // custom: highlight foreground text to blue for 2 seconds
16484      *     el.highlight("0000ff", { attr: 'color', duration: 2000 });
16485      *
16486      *     // common config options shown with default values
16487      *     el.highlight("ffff9c", {
16488      *         attr: "backgroundColor", //can be any valid CSS property (attribute) that supports a color value
16489      *         endColor: (current color) or "ffffff",
16490      *         easing: 'easeIn',
16491      *         duration: 1000
16492      *     });
16493      *
16494      * @param {String} [color='ffff9c'] The highlight color. Should be a 6 char hex color without the leading #
16495      * @param {Object} [options] Object literal with any of the Fx config options
16496      * @return {Ext.Element} The Element
16497      */
16498     highlight: function(color, o) {
16499         var me = this,
16500             dom = me.dom,
16501             from = {},
16502             restore, to, attr, lns, event, fn;
16503
16504         o = o || {};
16505         lns = o.listeners || {};
16506         attr = o.attr || 'backgroundColor';
16507         from[attr] = color || 'ffff9c';
16508
16509         if (!o.to) {
16510             to = {};
16511             to[attr] = o.endColor || me.getColor(attr, 'ffffff', '');
16512         }
16513         else {
16514             to = o.to;
16515         }
16516
16517         // Don't apply directly on lns, since we reference it in our own callbacks below
16518         o.listeners = Ext.apply(Ext.apply({}, lns), {
16519             beforeanimate: function() {
16520                 restore = dom.style[attr];
16521                 me.clearOpacity();
16522                 me.show();
16523
16524                 event = lns.beforeanimate;
16525                 if (event) {
16526                     fn = event.fn || event;
16527                     return fn.apply(event.scope || lns.scope || window, arguments);
16528                 }
16529             },
16530             afteranimate: function() {
16531                 if (dom) {
16532                     dom.style[attr] = restore;
16533                 }
16534
16535                 event = lns.afteranimate;
16536                 if (event) {
16537                     fn = event.fn || event;
16538                     fn.apply(event.scope || lns.scope || window, arguments);
16539                 }
16540             }
16541         });
16542
16543         me.animate(Ext.apply({}, o, {
16544             duration: 1000,
16545             easing: 'ease-in',
16546             from: from,
16547             to: to
16548         }));
16549         return me;
16550     },
16551
16552    /**
16553     * @deprecated 4.0
16554     * Creates a pause before any subsequent queued effects begin. If there are no effects queued after the pause it will
16555     * have no effect. Usage:
16556     *
16557     *     el.pause(1);
16558     *
16559     * @param {Number} seconds The length of time to pause (in seconds)
16560     * @return {Ext.Element} The Element
16561     */
16562     pause: function(ms) {
16563         var me = this;
16564         Ext.fx.Manager.setFxDefaults(me.id, {
16565             delay: ms
16566         });
16567         return me;
16568     },
16569
16570     /**
16571      * Fade an element in (from transparent to opaque). The ending opacity can be specified using the `opacity`
16572      * config option. Usage:
16573      *
16574      *     // default: fade in from opacity 0 to 100%
16575      *     el.fadeIn();
16576      *
16577      *     // custom: fade in from opacity 0 to 75% over 2 seconds
16578      *     el.fadeIn({ opacity: .75, duration: 2000});
16579      *
16580      *     // common config options shown with default values
16581      *     el.fadeIn({
16582      *         opacity: 1, //can be any value between 0 and 1 (e.g. .5)
16583      *         easing: 'easeOut',
16584      *         duration: 500
16585      *     });
16586      *
16587      * @param {Object} options (optional) Object literal with any of the Fx config options
16588      * @return {Ext.Element} The Element
16589      */
16590     fadeIn: function(o) {
16591         this.animate(Ext.apply({}, o, {
16592             opacity: 1
16593         }));
16594         return this;
16595     },
16596
16597     /**
16598      * Fade an element out (from opaque to transparent). The ending opacity can be specified using the `opacity`
16599      * config option. Note that IE may require `useDisplay:true` in order to redisplay correctly.
16600      * Usage:
16601      *
16602      *     // default: fade out from the element's current opacity to 0
16603      *     el.fadeOut();
16604      *
16605      *     // custom: fade out from the element's current opacity to 25% over 2 seconds
16606      *     el.fadeOut({ opacity: .25, duration: 2000});
16607      *
16608      *     // common config options shown with default values
16609      *     el.fadeOut({
16610      *         opacity: 0, //can be any value between 0 and 1 (e.g. .5)
16611      *         easing: 'easeOut',
16612      *         duration: 500,
16613      *         remove: false,
16614      *         useDisplay: false
16615      *     });
16616      *
16617      * @param {Object} options (optional) Object literal with any of the Fx config options
16618      * @return {Ext.Element} The Element
16619      */
16620     fadeOut: function(o) {
16621         this.animate(Ext.apply({}, o, {
16622             opacity: 0
16623         }));
16624         return this;
16625     },
16626
16627     /**
16628      * @deprecated 4.0
16629      * Animates the transition of an element's dimensions from a starting height/width to an ending height/width. This
16630      * method is a convenience implementation of {@link #shift}. Usage:
16631      *
16632      *     // change height and width to 100x100 pixels
16633      *     el.scale(100, 100);
16634      *
16635      *     // common config options shown with default values.  The height and width will default to
16636      *     // the element's existing values if passed as null.
16637      *     el.scale(
16638      *         [element's width],
16639      *         [element's height], {
16640      *             easing: 'easeOut',
16641      *             duration: .35
16642      *         }
16643      *     );
16644      *
16645      * @param {Number} width The new width (pass undefined to keep the original width)
16646      * @param {Number} height The new height (pass undefined to keep the original height)
16647      * @param {Object} options (optional) Object literal with any of the Fx config options
16648      * @return {Ext.Element} The Element
16649      */
16650     scale: function(w, h, o) {
16651         this.animate(Ext.apply({}, o, {
16652             width: w,
16653             height: h
16654         }));
16655         return this;
16656     },
16657
16658     /**
16659      * @deprecated 4.0
16660      * Animates the transition of any combination of an element's dimensions, xy position and/or opacity. Any of these
16661      * properties not specified in the config object will not be changed. This effect requires that at least one new
16662      * dimension, position or opacity setting must be passed in on the config object in order for the function to have
16663      * any effect. Usage:
16664      *
16665      *     // slide the element horizontally to x position 200 while changing the height and opacity
16666      *     el.shift({ x: 200, height: 50, opacity: .8 });
16667      *
16668      *     // common config options shown with default values.
16669      *     el.shift({
16670      *         width: [element's width],
16671      *         height: [element's height],
16672      *         x: [element's x position],
16673      *         y: [element's y position],
16674      *         opacity: [element's opacity],
16675      *         easing: 'easeOut',
16676      *         duration: .35
16677      *     });
16678      *
16679      * @param {Object} options Object literal with any of the Fx config options
16680      * @return {Ext.Element} The Element
16681      */
16682     shift: function(config) {
16683         this.animate(config);
16684         return this;
16685     }
16686 });
16687
16688 /**
16689  * @class Ext.Element
16690  */
16691 Ext.applyIf(Ext.Element, {
16692     unitRe: /\d+(px|em|%|en|ex|pt|in|cm|mm|pc)$/i,
16693     camelRe: /(-[a-z])/gi,
16694     opacityRe: /alpha\(opacity=(.*)\)/i,
16695     cssRe: /([a-z0-9-]+)\s*:\s*([^;\s]+(?:\s*[^;\s]+)*);?/gi,
16696     propertyCache: {},
16697     defaultUnit : "px",
16698     borders: {l: 'border-left-width', r: 'border-right-width', t: 'border-top-width', b: 'border-bottom-width'},
16699     paddings: {l: 'padding-left', r: 'padding-right', t: 'padding-top', b: 'padding-bottom'},
16700     margins: {l: 'margin-left', r: 'margin-right', t: 'margin-top', b: 'margin-bottom'},
16701
16702     // Reference the prototype's version of the method. Signatures are identical.
16703     addUnits : Ext.Element.prototype.addUnits,
16704
16705     /**
16706      * Parses a number or string representing margin sizes into an object. Supports CSS-style margin declarations
16707      * (e.g. 10, "10", "10 10", "10 10 10" and "10 10 10 10" are all valid options and would return the same result)
16708      * @static
16709      * @param {Number/String} box The encoded margins
16710      * @return {Object} An object with margin sizes for top, right, bottom and left
16711      */
16712     parseBox : function(box) {
16713         if (Ext.isObject(box)) {
16714             return {
16715                 top: box.top || 0,
16716                 right: box.right || 0,
16717                 bottom: box.bottom || 0,
16718                 left: box.left || 0
16719             };
16720         } else {
16721             if (typeof box != 'string') {
16722                 box = box.toString();
16723             }
16724             var parts  = box.split(' '),
16725                 ln = parts.length;
16726     
16727             if (ln == 1) {
16728                 parts[1] = parts[2] = parts[3] = parts[0];
16729             }
16730             else if (ln == 2) {
16731                 parts[2] = parts[0];
16732                 parts[3] = parts[1];
16733             }
16734             else if (ln == 3) {
16735                 parts[3] = parts[1];
16736             }
16737     
16738             return {
16739                 top   :parseFloat(parts[0]) || 0,
16740                 right :parseFloat(parts[1]) || 0,
16741                 bottom:parseFloat(parts[2]) || 0,
16742                 left  :parseFloat(parts[3]) || 0
16743             };
16744         }
16745         
16746     },
16747     
16748     /**
16749      * Parses a number or string representing margin sizes into an object. Supports CSS-style margin declarations
16750      * (e.g. 10, "10", "10 10", "10 10 10" and "10 10 10 10" are all valid options and would return the same result)
16751      * @static
16752      * @param {Number/String} box The encoded margins
16753      * @param {String} units The type of units to add
16754      * @return {String} An string with unitized (px if units is not specified) metrics for top, right, bottom and left
16755      */
16756     unitizeBox : function(box, units) {
16757         var A = this.addUnits,
16758             B = this.parseBox(box);
16759             
16760         return A(B.top, units) + ' ' +
16761                A(B.right, units) + ' ' +
16762                A(B.bottom, units) + ' ' +
16763                A(B.left, units);
16764         
16765     },
16766
16767     // private
16768     camelReplaceFn : function(m, a) {
16769         return a.charAt(1).toUpperCase();
16770     },
16771
16772     /**
16773      * Normalizes CSS property keys from dash delimited to camel case JavaScript Syntax.
16774      * For example:
16775      * <ul>
16776      *  <li>border-width -> borderWidth</li>
16777      *  <li>padding-top -> paddingTop</li>
16778      * </ul>
16779      * @static
16780      * @param {String} prop The property to normalize
16781      * @return {String} The normalized string
16782      */
16783     normalize : function(prop) {
16784         if (prop == 'float') {
16785             prop = Ext.supports.Float ? 'cssFloat' : 'styleFloat';
16786         }
16787         return this.propertyCache[prop] || (this.propertyCache[prop] = prop.replace(this.camelRe, this.camelReplaceFn));
16788     },
16789
16790     /**
16791      * Retrieves the document height
16792      * @static
16793      * @return {Number} documentHeight
16794      */
16795     getDocumentHeight: function() {
16796         return Math.max(!Ext.isStrict ? document.body.scrollHeight : document.documentElement.scrollHeight, this.getViewportHeight());
16797     },
16798
16799     /**
16800      * Retrieves the document width
16801      * @static
16802      * @return {Number} documentWidth
16803      */
16804     getDocumentWidth: function() {
16805         return Math.max(!Ext.isStrict ? document.body.scrollWidth : document.documentElement.scrollWidth, this.getViewportWidth());
16806     },
16807
16808     /**
16809      * Retrieves the viewport height of the window.
16810      * @static
16811      * @return {Number} viewportHeight
16812      */
16813     getViewportHeight: function(){
16814         return window.innerHeight;
16815     },
16816
16817     /**
16818      * Retrieves the viewport width of the window.
16819      * @static
16820      * @return {Number} viewportWidth
16821      */
16822     getViewportWidth : function() {
16823         return window.innerWidth;
16824     },
16825
16826     /**
16827      * Retrieves the viewport size of the window.
16828      * @static
16829      * @return {Object} object containing width and height properties
16830      */
16831     getViewSize : function() {
16832         return {
16833             width: window.innerWidth,
16834             height: window.innerHeight
16835         };
16836     },
16837
16838     /**
16839      * Retrieves the current orientation of the window. This is calculated by
16840      * determing if the height is greater than the width.
16841      * @static
16842      * @return {String} Orientation of window: 'portrait' or 'landscape'
16843      */
16844     getOrientation : function() {
16845         if (Ext.supports.OrientationChange) {
16846             return (window.orientation == 0) ? 'portrait' : 'landscape';
16847         }
16848         
16849         return (window.innerHeight > window.innerWidth) ? 'portrait' : 'landscape';
16850     },
16851
16852     /** 
16853      * Returns the top Element that is located at the passed coordinates
16854      * @static
16855      * @param {Number} x The x coordinate
16856      * @param {Number} y The y coordinate
16857      * @return {String} The found Element
16858      */
16859     fromPoint: function(x, y) {
16860         return Ext.get(document.elementFromPoint(x, y));
16861     },
16862     
16863     /**
16864      * Converts a CSS string into an object with a property for each style.
16865      * <p>
16866      * The sample code below would return an object with 2 properties, one
16867      * for background-color and one for color.</p>
16868      * <pre><code>
16869 var css = 'background-color: red;color: blue; ';
16870 console.log(Ext.Element.parseStyles(css));
16871      * </code></pre>
16872      * @static
16873      * @param {String} styles A CSS string
16874      * @return {Object} styles
16875      */
16876     parseStyles: function(styles){
16877         var out = {},
16878             cssRe = this.cssRe,
16879             matches;
16880             
16881         if (styles) {
16882             // Since we're using the g flag on the regex, we need to set the lastIndex.
16883             // This automatically happens on some implementations, but not others, see:
16884             // http://stackoverflow.com/questions/2645273/javascript-regular-expression-literal-persists-between-function-calls
16885             // http://blog.stevenlevithan.com/archives/fixing-javascript-regexp
16886             cssRe.lastIndex = 0;
16887             while ((matches = cssRe.exec(styles))) {
16888                 out[matches[1]] = matches[2];
16889             }
16890         }
16891         return out;
16892     }
16893 });
16894
16895 /**
16896  * @class Ext.CompositeElementLite
16897  * <p>This class encapsulates a <i>collection</i> of DOM elements, providing methods to filter
16898  * members, or to perform collective actions upon the whole set.</p>
16899  * <p>Although they are not listed, this class supports all of the methods of {@link Ext.Element} and
16900  * {@link Ext.fx.Anim}. The methods from these classes will be performed on all the elements in this collection.</p>
16901  * Example:<pre><code>
16902 var els = Ext.select("#some-el div.some-class");
16903 // or select directly from an existing element
16904 var el = Ext.get('some-el');
16905 el.select('div.some-class');
16906
16907 els.setWidth(100); // all elements become 100 width
16908 els.hide(true); // all elements fade out and hide
16909 // or
16910 els.setWidth(100).hide(true);
16911 </code></pre>
16912  */
16913 Ext.CompositeElementLite = function(els, root){
16914     /**
16915      * <p>The Array of DOM elements which this CompositeElement encapsulates. Read-only.</p>
16916      * <p>This will not <i>usually</i> be accessed in developers' code, but developers wishing
16917      * to augment the capabilities of the CompositeElementLite class may use it when adding
16918      * methods to the class.</p>
16919      * <p>For example to add the <code>nextAll</code> method to the class to <b>add</b> all
16920      * following siblings of selected elements, the code would be</p><code><pre>
16921 Ext.override(Ext.CompositeElementLite, {
16922     nextAll: function() {
16923         var els = this.elements, i, l = els.length, n, r = [], ri = -1;
16924
16925 //      Loop through all elements in this Composite, accumulating
16926 //      an Array of all siblings.
16927         for (i = 0; i < l; i++) {
16928             for (n = els[i].nextSibling; n; n = n.nextSibling) {
16929                 r[++ri] = n;
16930             }
16931         }
16932
16933 //      Add all found siblings to this Composite
16934         return this.add(r);
16935     }
16936 });</pre></code>
16937      * @property {HTMLElement} elements
16938      */
16939     this.elements = [];
16940     this.add(els, root);
16941     this.el = new Ext.Element.Flyweight();
16942 };
16943
16944 Ext.CompositeElementLite.prototype = {
16945     isComposite: true,
16946
16947     // private
16948     getElement : function(el){
16949         // Set the shared flyweight dom property to the current element
16950         var e = this.el;
16951         e.dom = el;
16952         e.id = el.id;
16953         return e;
16954     },
16955
16956     // private
16957     transformElement : function(el){
16958         return Ext.getDom(el);
16959     },
16960
16961     /**
16962      * Returns the number of elements in this Composite.
16963      * @return Number
16964      */
16965     getCount : function(){
16966         return this.elements.length;
16967     },
16968     /**
16969      * Adds elements to this Composite object.
16970      * @param {HTMLElement[]/Ext.CompositeElement} els Either an Array of DOM elements to add, or another Composite object who's elements should be added.
16971      * @return {Ext.CompositeElement} This Composite object.
16972      */
16973     add : function(els, root){
16974         var me = this,
16975             elements = me.elements;
16976         if(!els){
16977             return this;
16978         }
16979         if(typeof els == "string"){
16980             els = Ext.Element.selectorFunction(els, root);
16981         }else if(els.isComposite){
16982             els = els.elements;
16983         }else if(!Ext.isIterable(els)){
16984             els = [els];
16985         }
16986
16987         for(var i = 0, len = els.length; i < len; ++i){
16988             elements.push(me.transformElement(els[i]));
16989         }
16990         return me;
16991     },
16992
16993     invoke : function(fn, args){
16994         var me = this,
16995             els = me.elements,
16996             len = els.length,
16997             e,
16998             i;
16999
17000         for(i = 0; i < len; i++) {
17001             e = els[i];
17002             if(e){
17003                 Ext.Element.prototype[fn].apply(me.getElement(e), args);
17004             }
17005         }
17006         return me;
17007     },
17008     /**
17009      * Returns a flyweight Element of the dom element object at the specified index
17010      * @param {Number} index
17011      * @return {Ext.Element}
17012      */
17013     item : function(index){
17014         var me = this,
17015             el = me.elements[index],
17016             out = null;
17017
17018         if(el){
17019             out = me.getElement(el);
17020         }
17021         return out;
17022     },
17023
17024     // fixes scope with flyweight
17025     addListener : function(eventName, handler, scope, opt){
17026         var els = this.elements,
17027             len = els.length,
17028             i, e;
17029
17030         for(i = 0; i<len; i++) {
17031             e = els[i];
17032             if(e) {
17033                 Ext.EventManager.on(e, eventName, handler, scope || e, opt);
17034             }
17035         }
17036         return this;
17037     },
17038     /**
17039      * <p>Calls the passed function for each element in this composite.</p>
17040      * @param {Function} fn The function to call. The function is passed the following parameters:<ul>
17041      * <li><b>el</b> : Element<div class="sub-desc">The current Element in the iteration.
17042      * <b>This is the flyweight (shared) Ext.Element instance, so if you require a
17043      * a reference to the dom node, use el.dom.</b></div></li>
17044      * <li><b>c</b> : Composite<div class="sub-desc">This Composite object.</div></li>
17045      * <li><b>idx</b> : Number<div class="sub-desc">The zero-based index in the iteration.</div></li>
17046      * </ul>
17047      * @param {Object} [scope] The scope (<i>this</i> reference) in which the function is executed. (defaults to the Element)
17048      * @return {Ext.CompositeElement} this
17049      */
17050     each : function(fn, scope){
17051         var me = this,
17052             els = me.elements,
17053             len = els.length,
17054             i, e;
17055
17056         for(i = 0; i<len; i++) {
17057             e = els[i];
17058             if(e){
17059                 e = this.getElement(e);
17060                 if(fn.call(scope || e, e, me, i) === false){
17061                     break;
17062                 }
17063             }
17064         }
17065         return me;
17066     },
17067
17068     /**
17069     * Clears this Composite and adds the elements passed.
17070     * @param {HTMLElement[]/Ext.CompositeElement} els Either an array of DOM elements, or another Composite from which to fill this Composite.
17071     * @return {Ext.CompositeElement} this
17072     */
17073     fill : function(els){
17074         var me = this;
17075         me.elements = [];
17076         me.add(els);
17077         return me;
17078     },
17079
17080     /**
17081      * Filters this composite to only elements that match the passed selector.
17082      * @param {String/Function} selector A string CSS selector or a comparison function.
17083      * The comparison function will be called with the following arguments:<ul>
17084      * <li><code>el</code> : Ext.Element<div class="sub-desc">The current DOM element.</div></li>
17085      * <li><code>index</code> : Number<div class="sub-desc">The current index within the collection.</div></li>
17086      * </ul>
17087      * @return {Ext.CompositeElement} this
17088      */
17089     filter : function(selector){
17090         var els = [],
17091             me = this,
17092             fn = Ext.isFunction(selector) ? selector
17093                 : function(el){
17094                     return el.is(selector);
17095                 };
17096
17097         me.each(function(el, self, i) {
17098             if (fn(el, i) !== false) {
17099                 els[els.length] = me.transformElement(el);
17100             }
17101         });
17102
17103         me.elements = els;
17104         return me;
17105     },
17106
17107     /**
17108      * Find the index of the passed element within the composite collection.
17109      * @param el {Mixed} The id of an element, or an Ext.Element, or an HtmlElement to find within the composite collection.
17110      * @return Number The index of the passed Ext.Element in the composite collection, or -1 if not found.
17111      */
17112     indexOf : function(el){
17113         return Ext.Array.indexOf(this.elements, this.transformElement(el));
17114     },
17115
17116     /**
17117     * Replaces the specified element with the passed element.
17118     * @param {String/HTMLElement/Ext.Element/Number} el The id of an element, the Element itself, the index of the element in this composite
17119     * to replace.
17120     * @param {String/Ext.Element} replacement The id of an element or the Element itself.
17121     * @param {Boolean} domReplace (Optional) True to remove and replace the element in the document too.
17122     * @return {Ext.CompositeElement} this
17123     */
17124     replaceElement : function(el, replacement, domReplace){
17125         var index = !isNaN(el) ? el : this.indexOf(el),
17126             d;
17127         if(index > -1){
17128             replacement = Ext.getDom(replacement);
17129             if(domReplace){
17130                 d = this.elements[index];
17131                 d.parentNode.insertBefore(replacement, d);
17132                 Ext.removeNode(d);
17133             }
17134             Ext.Array.splice(this.elements, index, 1, replacement);
17135         }
17136         return this;
17137     },
17138
17139     /**
17140      * Removes all elements.
17141      */
17142     clear : function(){
17143         this.elements = [];
17144     }
17145 };
17146
17147 Ext.CompositeElementLite.prototype.on = Ext.CompositeElementLite.prototype.addListener;
17148
17149 /**
17150  * @private
17151  * Copies all of the functions from Ext.Element's prototype onto CompositeElementLite's prototype.
17152  * This is called twice - once immediately below, and once again after additional Ext.Element
17153  * are added in Ext JS
17154  */
17155 Ext.CompositeElementLite.importElementMethods = function() {
17156     var fnName,
17157         ElProto = Ext.Element.prototype,
17158         CelProto = Ext.CompositeElementLite.prototype;
17159
17160     for (fnName in ElProto) {
17161         if (typeof ElProto[fnName] == 'function'){
17162             (function(fnName) {
17163                 CelProto[fnName] = CelProto[fnName] || function() {
17164                     return this.invoke(fnName, arguments);
17165                 };
17166             }).call(CelProto, fnName);
17167
17168         }
17169     }
17170 };
17171
17172 Ext.CompositeElementLite.importElementMethods();
17173
17174 if(Ext.DomQuery){
17175     Ext.Element.selectorFunction = Ext.DomQuery.select;
17176 }
17177
17178 /**
17179  * Selects elements based on the passed CSS selector to enable {@link Ext.Element Element} methods
17180  * to be applied to many related elements in one statement through the returned {@link Ext.CompositeElement CompositeElement} or
17181  * {@link Ext.CompositeElementLite CompositeElementLite} object.
17182  * @param {String/HTMLElement[]} selector The CSS selector or an array of elements
17183  * @param {HTMLElement/String} root (optional) The root element of the query or id of the root
17184  * @return {Ext.CompositeElementLite/Ext.CompositeElement}
17185  * @member Ext.Element
17186  * @method select
17187  */
17188 Ext.Element.select = function(selector, root){
17189     var els;
17190     if(typeof selector == "string"){
17191         els = Ext.Element.selectorFunction(selector, root);
17192     }else if(selector.length !== undefined){
17193         els = selector;
17194     }else{
17195         Ext.Error.raise({
17196             sourceClass: "Ext.Element",
17197             sourceMethod: "select",
17198             selector: selector,
17199             root: root,
17200             msg: "Invalid selector specified: " + selector
17201         });
17202     }
17203     return new Ext.CompositeElementLite(els);
17204 };
17205 /**
17206  * Selects elements based on the passed CSS selector to enable {@link Ext.Element Element} methods
17207  * to be applied to many related elements in one statement through the returned {@link Ext.CompositeElement CompositeElement} or
17208  * {@link Ext.CompositeElementLite CompositeElementLite} object.
17209  * @param {String/HTMLElement[]} selector The CSS selector or an array of elements
17210  * @param {HTMLElement/String} root (optional) The root element of the query or id of the root
17211  * @return {Ext.CompositeElementLite/Ext.CompositeElement}
17212  * @member Ext
17213  * @method select
17214  */
17215 Ext.select = Ext.Element.select;
17216
17217 /**
17218  * @class Ext.util.DelayedTask
17219  * 
17220  * The DelayedTask class provides a convenient way to "buffer" the execution of a method,
17221  * performing setTimeout where a new timeout cancels the old timeout. When called, the
17222  * task will wait the specified time period before executing. If durng that time period,
17223  * the task is called again, the original call will be cancelled. This continues so that
17224  * the function is only called a single time for each iteration.
17225  * 
17226  * This method is especially useful for things like detecting whether a user has finished
17227  * typing in a text field. An example would be performing validation on a keypress. You can
17228  * use this class to buffer the keypress events for a certain number of milliseconds, and
17229  * perform only if they stop for that amount of time.  
17230  * 
17231  * ## Usage
17232  * 
17233  *     var task = new Ext.util.DelayedTask(function(){
17234  *         alert(Ext.getDom('myInputField').value.length);
17235  *     });
17236  *     
17237  *     // Wait 500ms before calling our function. If the user presses another key
17238  *     // during that 500ms, it will be cancelled and we'll wait another 500ms.
17239  *     Ext.get('myInputField').on('keypress', function(){
17240  *         task.{@link #delay}(500);
17241  *     });
17242  * 
17243  * Note that we are using a DelayedTask here to illustrate a point. The configuration
17244  * option `buffer` for {@link Ext.util.Observable#addListener addListener/on} will
17245  * also setup a delayed task for you to buffer events.
17246  * 
17247  * @constructor The parameters to this constructor serve as defaults and are not required.
17248  * @param {Function} fn (optional) The default function to call. If not specified here, it must be specified during the {@link #delay} call.
17249  * @param {Object} scope (optional) The default scope (The <code><b>this</b></code> reference) in which the
17250  * function is called. If not specified, <code>this</code> will refer to the browser window.
17251  * @param {Array} args (optional) The default Array of arguments.
17252  */
17253 Ext.util.DelayedTask = function(fn, scope, args) {
17254     var me = this,
17255         id,
17256         call = function() {
17257             clearInterval(id);
17258             id = null;
17259             fn.apply(scope, args || []);
17260         };
17261
17262     /**
17263      * Cancels any pending timeout and queues a new one
17264      * @param {Number} delay The milliseconds to delay
17265      * @param {Function} newFn (optional) Overrides function passed to constructor
17266      * @param {Object} newScope (optional) Overrides scope passed to constructor. Remember that if no scope
17267      * is specified, <code>this</code> will refer to the browser window.
17268      * @param {Array} newArgs (optional) Overrides args passed to constructor
17269      */
17270     this.delay = function(delay, newFn, newScope, newArgs) {
17271         me.cancel();
17272         fn = newFn || fn;
17273         scope = newScope || scope;
17274         args = newArgs || args;
17275         id = setInterval(call, delay);
17276     };
17277
17278     /**
17279      * Cancel the last queued timeout
17280      */
17281     this.cancel = function(){
17282         if (id) {
17283             clearInterval(id);
17284             id = null;
17285         }
17286     };
17287 };
17288 Ext.require('Ext.util.DelayedTask', function() {
17289
17290     Ext.util.Event = Ext.extend(Object, (function() {
17291         function createBuffered(handler, listener, o, scope) {
17292             listener.task = new Ext.util.DelayedTask();
17293             return function() {
17294                 listener.task.delay(o.buffer, handler, scope, Ext.Array.toArray(arguments));
17295             };
17296         }
17297
17298         function createDelayed(handler, listener, o, scope) {
17299             return function() {
17300                 var task = new Ext.util.DelayedTask();
17301                 if (!listener.tasks) {
17302                     listener.tasks = [];
17303                 }
17304                 listener.tasks.push(task);
17305                 task.delay(o.delay || 10, handler, scope, Ext.Array.toArray(arguments));
17306             };
17307         }
17308
17309         function createSingle(handler, listener, o, scope) {
17310             return function() {
17311                 listener.ev.removeListener(listener.fn, scope);
17312                 return handler.apply(scope, arguments);
17313             };
17314         }
17315
17316         return {
17317             isEvent: true,
17318
17319             constructor: function(observable, name) {
17320                 this.name = name;
17321                 this.observable = observable;
17322                 this.listeners = [];
17323             },
17324
17325             addListener: function(fn, scope, options) {
17326                 var me = this,
17327                     listener;
17328                     scope = scope || me.observable;
17329
17330                 if (!fn) {
17331                     Ext.Error.raise({
17332                         sourceClass: Ext.getClassName(this.observable),
17333                         sourceMethod: "addListener",
17334                         msg: "The specified callback function is undefined"
17335                     });
17336                 }
17337
17338                 if (!me.isListening(fn, scope)) {
17339                     listener = me.createListener(fn, scope, options);
17340                     if (me.firing) {
17341                         // if we are currently firing this event, don't disturb the listener loop
17342                         me.listeners = me.listeners.slice(0);
17343                     }
17344                     me.listeners.push(listener);
17345                 }
17346             },
17347
17348             createListener: function(fn, scope, o) {
17349                 o = o || {};
17350                 scope = scope || this.observable;
17351
17352                 var listener = {
17353                         fn: fn,
17354                         scope: scope,
17355                         o: o,
17356                         ev: this
17357                     },
17358                     handler = fn;
17359
17360                 // The order is important. The 'single' wrapper must be wrapped by the 'buffer' and 'delayed' wrapper
17361                 // because the event removal that the single listener does destroys the listener's DelayedTask(s)
17362                 if (o.single) {
17363                     handler = createSingle(handler, listener, o, scope);
17364                 }
17365                 if (o.delay) {
17366                     handler = createDelayed(handler, listener, o, scope);
17367                 }
17368                 if (o.buffer) {
17369                     handler = createBuffered(handler, listener, o, scope);
17370                 }
17371
17372                 listener.fireFn = handler;
17373                 return listener;
17374             },
17375
17376             findListener: function(fn, scope) {
17377                 var listeners = this.listeners,
17378                 i = listeners.length,
17379                 listener,
17380                 s;
17381
17382                 while (i--) {
17383                     listener = listeners[i];
17384                     if (listener) {
17385                         s = listener.scope;
17386                         if (listener.fn == fn && (s == scope || s == this.observable)) {
17387                             return i;
17388                         }
17389                     }
17390                 }
17391
17392                 return - 1;
17393             },
17394
17395             isListening: function(fn, scope) {
17396                 return this.findListener(fn, scope) !== -1;
17397             },
17398
17399             removeListener: function(fn, scope) {
17400                 var me = this,
17401                     index,
17402                     listener,
17403                     k;
17404                 index = me.findListener(fn, scope);
17405                 if (index != -1) {
17406                     listener = me.listeners[index];
17407
17408                     if (me.firing) {
17409                         me.listeners = me.listeners.slice(0);
17410                     }
17411
17412                     // cancel and remove a buffered handler that hasn't fired yet
17413                     if (listener.task) {
17414                         listener.task.cancel();
17415                         delete listener.task;
17416                     }
17417
17418                     // cancel and remove all delayed handlers that haven't fired yet
17419                     k = listener.tasks && listener.tasks.length;
17420                     if (k) {
17421                         while (k--) {
17422                             listener.tasks[k].cancel();
17423                         }
17424                         delete listener.tasks;
17425                     }
17426
17427                     // remove this listener from the listeners array
17428                     Ext.Array.erase(me.listeners, index, 1);
17429                     return true;
17430                 }
17431
17432                 return false;
17433             },
17434
17435             // Iterate to stop any buffered/delayed events
17436             clearListeners: function() {
17437                 var listeners = this.listeners,
17438                     i = listeners.length;
17439
17440                 while (i--) {
17441                     this.removeListener(listeners[i].fn, listeners[i].scope);
17442                 }
17443             },
17444
17445             fire: function() {
17446                 var me = this,
17447                     listeners = me.listeners,
17448                     count = listeners.length,
17449                     i,
17450                     args,
17451                     listener;
17452
17453                 if (count > 0) {
17454                     me.firing = true;
17455                     for (i = 0; i < count; i++) {
17456                         listener = listeners[i];
17457                         args = arguments.length ? Array.prototype.slice.call(arguments, 0) : [];
17458                         if (listener.o) {
17459                             args.push(listener.o);
17460                         }
17461                         if (listener && listener.fireFn.apply(listener.scope || me.observable, args) === false) {
17462                             return (me.firing = false);
17463                         }
17464                     }
17465                 }
17466                 me.firing = false;
17467                 return true;
17468             }
17469         };
17470     })());
17471 });
17472
17473 /**
17474  * @class Ext.EventManager
17475  * Registers event handlers that want to receive a normalized EventObject instead of the standard browser event and provides
17476  * several useful events directly.
17477  * See {@link Ext.EventObject} for more details on normalized event objects.
17478  * @singleton
17479  */
17480 Ext.EventManager = {
17481
17482     // --------------------- onReady ---------------------
17483
17484     /**
17485      * Check if we have bound our global onReady listener
17486      * @private
17487      */
17488     hasBoundOnReady: false,
17489
17490     /**
17491      * Check if fireDocReady has been called
17492      * @private
17493      */
17494     hasFiredReady: false,
17495
17496     /**
17497      * Timer for the document ready event in old IE versions
17498      * @private
17499      */
17500     readyTimeout: null,
17501
17502     /**
17503      * Checks if we have bound an onreadystatechange event
17504      * @private
17505      */
17506     hasOnReadyStateChange: false,
17507
17508     /**
17509      * Holds references to any onReady functions
17510      * @private
17511      */
17512     readyEvent: new Ext.util.Event(),
17513
17514     /**
17515      * Check the ready state for old IE versions
17516      * @private
17517      * @return {Boolean} True if the document is ready
17518      */
17519     checkReadyState: function(){
17520         var me = Ext.EventManager;
17521
17522         if(window.attachEvent){
17523             // See here for reference: http://javascript.nwbox.com/IEContentLoaded/
17524             // licensed courtesy of http://developer.yahoo.com/yui/license.html
17525             if (window != top) {
17526                 return false;
17527             }
17528             try{
17529                 document.documentElement.doScroll('left');
17530             }catch(e){
17531                 return false;
17532             }
17533             me.fireDocReady();
17534             return true;
17535         }
17536         if (document.readyState == 'complete') {
17537             me.fireDocReady();
17538             return true;
17539         }
17540         me.readyTimeout = setTimeout(arguments.callee, 2);
17541         return false;
17542     },
17543
17544     /**
17545      * Binds the appropriate browser event for checking if the DOM has loaded.
17546      * @private
17547      */
17548     bindReadyEvent: function(){
17549         var me = Ext.EventManager;
17550         if (me.hasBoundOnReady) {
17551             return;
17552         }
17553
17554         if (document.addEventListener) {
17555             document.addEventListener('DOMContentLoaded', me.fireDocReady, false);
17556             // fallback, load will ~always~ fire
17557             window.addEventListener('load', me.fireDocReady, false);
17558         } else {
17559             // check if the document is ready, this will also kick off the scroll checking timer
17560             if (!me.checkReadyState()) {
17561                 document.attachEvent('onreadystatechange', me.checkReadyState);
17562                 me.hasOnReadyStateChange = true;
17563             }
17564             // fallback, onload will ~always~ fire
17565             window.attachEvent('onload', me.fireDocReady, false);
17566         }
17567         me.hasBoundOnReady = true;
17568     },
17569
17570     /**
17571      * We know the document is loaded, so trigger any onReady events.
17572      * @private
17573      */
17574     fireDocReady: function(){
17575         var me = Ext.EventManager;
17576
17577         // only unbind these events once
17578         if (!me.hasFiredReady) {
17579             me.hasFiredReady = true;
17580
17581             if (document.addEventListener) {
17582                 document.removeEventListener('DOMContentLoaded', me.fireDocReady, false);
17583                 window.removeEventListener('load', me.fireDocReady, false);
17584             } else {
17585                 if (me.readyTimeout !== null) {
17586                     clearTimeout(me.readyTimeout);
17587                 }
17588                 if (me.hasOnReadyStateChange) {
17589                     document.detachEvent('onreadystatechange', me.checkReadyState);
17590                 }
17591                 window.detachEvent('onload', me.fireDocReady);
17592             }
17593             Ext.supports.init();
17594         }
17595         if (!Ext.isReady) {
17596             Ext.isReady = true;
17597             me.onWindowUnload();
17598             me.readyEvent.fire();
17599         }
17600     },
17601
17602     /**
17603      * Adds a listener to be notified when the document is ready (before onload and before images are loaded). Can be
17604      * accessed shorthanded as Ext.onReady().
17605      * @param {Function} fn The method the event invokes.
17606      * @param {Object} scope (optional) The scope (<code>this</code> reference) in which the handler function executes. Defaults to the browser window.
17607      * @param {Boolean} options (optional) Options object as passed to {@link Ext.Element#addListener}.
17608      */
17609     onDocumentReady: function(fn, scope, options){
17610         options = options || {};
17611         var me = Ext.EventManager,
17612             readyEvent = me.readyEvent;
17613
17614         // force single to be true so our event is only ever fired once.
17615         options.single = true;
17616
17617         // Document already loaded, let's just fire it
17618         if (Ext.isReady) {
17619             readyEvent.addListener(fn, scope, options);
17620             readyEvent.fire();
17621         } else {
17622             options.delay = options.delay || 1;
17623             readyEvent.addListener(fn, scope, options);
17624             me.bindReadyEvent();
17625         }
17626     },
17627
17628
17629     // --------------------- event binding ---------------------
17630
17631     /**
17632      * Contains a list of all document mouse downs, so we can ensure they fire even when stopEvent is called.
17633      * @private
17634      */
17635     stoppedMouseDownEvent: new Ext.util.Event(),
17636
17637     /**
17638      * Options to parse for the 4th argument to addListener.
17639      * @private
17640      */
17641     propRe: /^(?:scope|delay|buffer|single|stopEvent|preventDefault|stopPropagation|normalized|args|delegate|freezeEvent)$/,
17642
17643     /**
17644      * Get the id of the element. If one has not been assigned, automatically assign it.
17645      * @param {HTMLElement/Ext.Element} element The element to get the id for.
17646      * @return {String} id
17647      */
17648     getId : function(element) {
17649         var skipGarbageCollection = false,
17650             id;
17651
17652         element = Ext.getDom(element);
17653
17654         if (element === document || element === window) {
17655             id = element === document ? Ext.documentId : Ext.windowId;
17656         }
17657         else {
17658             id = Ext.id(element);
17659         }
17660         // skip garbage collection for special elements (window, document, iframes)
17661         if (element && (element.getElementById || element.navigator)) {
17662             skipGarbageCollection = true;
17663         }
17664
17665         if (!Ext.cache[id]){
17666             Ext.Element.addToCache(new Ext.Element(element), id);
17667             if (skipGarbageCollection) {
17668                 Ext.cache[id].skipGarbageCollection = true;
17669             }
17670         }
17671         return id;
17672     },
17673
17674     /**
17675      * Convert a "config style" listener into a set of flat arguments so they can be passed to addListener
17676      * @private
17677      * @param {Object} element The element the event is for
17678      * @param {Object} event The event configuration
17679      * @param {Object} isRemove True if a removal should be performed, otherwise an add will be done.
17680      */
17681     prepareListenerConfig: function(element, config, isRemove){
17682         var me = this,
17683             propRe = me.propRe,
17684             key, value, args;
17685
17686         // loop over all the keys in the object
17687         for (key in config) {
17688             if (config.hasOwnProperty(key)) {
17689                 // if the key is something else then an event option
17690                 if (!propRe.test(key)) {
17691                     value = config[key];
17692                     // if the value is a function it must be something like click: function(){}, scope: this
17693                     // which means that there might be multiple event listeners with shared options
17694                     if (Ext.isFunction(value)) {
17695                         // shared options
17696                         args = [element, key, value, config.scope, config];
17697                     } else {
17698                         // if its not a function, it must be an object like click: {fn: function(){}, scope: this}
17699                         args = [element, key, value.fn, value.scope, value];
17700                     }
17701
17702                     if (isRemove === true) {
17703                         me.removeListener.apply(this, args);
17704                     } else {
17705                         me.addListener.apply(me, args);
17706                     }
17707                 }
17708             }
17709         }
17710     },
17711
17712     /**
17713      * Normalize cross browser event differences
17714      * @private
17715      * @param {Object} eventName The event name
17716      * @param {Object} fn The function to execute
17717      * @return {Object} The new event name/function
17718      */
17719     normalizeEvent: function(eventName, fn){
17720         if (/mouseenter|mouseleave/.test(eventName) && !Ext.supports.MouseEnterLeave) {
17721             if (fn) {
17722                 fn = Ext.Function.createInterceptor(fn, this.contains, this);
17723             }
17724             eventName = eventName == 'mouseenter' ? 'mouseover' : 'mouseout';
17725         } else if (eventName == 'mousewheel' && !Ext.supports.MouseWheel && !Ext.isOpera){
17726             eventName = 'DOMMouseScroll';
17727         }
17728         return {
17729             eventName: eventName,
17730             fn: fn
17731         };
17732     },
17733
17734     /**
17735      * Checks whether the event's relatedTarget is contained inside (or <b>is</b>) the element.
17736      * @private
17737      * @param {Object} event
17738      */
17739     contains: function(event){
17740         var parent = event.browserEvent.currentTarget,
17741             child = this.getRelatedTarget(event);
17742
17743         if (parent && parent.firstChild) {
17744             while (child) {
17745                 if (child === parent) {
17746                     return false;
17747                 }
17748                 child = child.parentNode;
17749                 if (child && (child.nodeType != 1)) {
17750                     child = null;
17751                 }
17752             }
17753         }
17754         return true;
17755     },
17756
17757     /**
17758     * Appends an event handler to an element.  The shorthand version {@link #on} is equivalent.  Typically you will
17759     * use {@link Ext.Element#addListener} directly on an Element in favor of calling this version.
17760     * @param {String/HTMLElement} el The html element or id to assign the event handler to.
17761     * @param {String} eventName The name of the event to listen for.
17762     * @param {Function} handler The handler function the event invokes. This function is passed
17763     * the following parameters:<ul>
17764     * <li>evt : EventObject<div class="sub-desc">The {@link Ext.EventObject EventObject} describing the event.</div></li>
17765     * <li>t : Element<div class="sub-desc">The {@link Ext.Element Element} which was the target of the event.
17766     * Note that this may be filtered by using the <tt>delegate</tt> option.</div></li>
17767     * <li>o : Object<div class="sub-desc">The options object from the addListener call.</div></li>
17768     * </ul>
17769     * @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>.
17770     * @param {Object} options (optional) An object containing handler configuration properties.
17771     * This may contain any of the following properties:<ul>
17772     * <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>
17773     * <li>delegate : String<div class="sub-desc">A simple selector to filter the target or look for a descendant of the target</div></li>
17774     * <li>stopEvent : Boolean<div class="sub-desc">True to stop the event. That is stop propagation, and prevent the default action.</div></li>
17775     * <li>preventDefault : Boolean<div class="sub-desc">True to prevent the default action</div></li>
17776     * <li>stopPropagation : Boolean<div class="sub-desc">True to prevent event propagation</div></li>
17777     * <li>normalized : Boolean<div class="sub-desc">False to pass a browser event to the handler function instead of an Ext.EventObject</div></li>
17778     * <li>delay : Number<div class="sub-desc">The number of milliseconds to delay the invocation of the handler after te event fires.</div></li>
17779     * <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>
17780     * <li>buffer : Number<div class="sub-desc">Causes the handler to be scheduled to run in an {@link Ext.util.DelayedTask} delayed
17781     * by the specified number of milliseconds. If the event fires again within that time, the original
17782     * handler is <em>not</em> invoked, but the new handler is scheduled in its place.</div></li>
17783     * <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>
17784     * </ul><br>
17785     * <p>See {@link Ext.Element#addListener} for examples of how to use these options.</p>
17786     */
17787     addListener: function(element, eventName, fn, scope, options){
17788         // Check if we've been passed a "config style" event.
17789         if (typeof eventName !== 'string') {
17790             this.prepareListenerConfig(element, eventName);
17791             return;
17792         }
17793
17794         var dom = Ext.getDom(element),
17795             bind,
17796             wrap;
17797
17798         if (!dom){
17799             Ext.Error.raise({
17800                 sourceClass: 'Ext.EventManager',
17801                 sourceMethod: 'addListener',
17802                 targetElement: element,
17803                 eventName: eventName,
17804                 msg: 'Error adding "' + eventName + '\" listener for nonexistent element "' + element + '"'
17805             });
17806         }
17807         if (!fn) {
17808             Ext.Error.raise({
17809                 sourceClass: 'Ext.EventManager',
17810                 sourceMethod: 'addListener',
17811                 targetElement: element,
17812                 eventName: eventName,
17813                 msg: 'Error adding "' + eventName + '\" listener. The handler function is undefined.'
17814             });
17815         }
17816
17817         // create the wrapper function
17818         options = options || {};
17819
17820         bind = this.normalizeEvent(eventName, fn);
17821         wrap = this.createListenerWrap(dom, eventName, bind.fn, scope, options);
17822
17823
17824         if (dom.attachEvent) {
17825             dom.attachEvent('on' + bind.eventName, wrap);
17826         } else {
17827             dom.addEventListener(bind.eventName, wrap, options.capture || false);
17828         }
17829
17830         if (dom == document && eventName == 'mousedown') {
17831             this.stoppedMouseDownEvent.addListener(wrap);
17832         }
17833
17834         // add all required data into the event cache
17835         this.getEventListenerCache(dom, eventName).push({
17836             fn: fn,
17837             wrap: wrap,
17838             scope: scope
17839         });
17840     },
17841
17842     /**
17843     * Removes an event handler from an element.  The shorthand version {@link #un} is equivalent.  Typically
17844     * you will use {@link Ext.Element#removeListener} directly on an Element in favor of calling this version.
17845     * @param {String/HTMLElement} el The id or html element from which to remove the listener.
17846     * @param {String} eventName The name of the event.
17847     * @param {Function} fn The handler function to remove. <b>This must be a reference to the function passed into the {@link #addListener} call.</b>
17848     * @param {Object} scope If a scope (<b><code>this</code></b> reference) was specified when the listener was added,
17849     * then this must refer to the same object.
17850     */
17851     removeListener : function(element, eventName, fn, scope) {
17852         // handle our listener config object syntax
17853         if (typeof eventName !== 'string') {
17854             this.prepareListenerConfig(element, eventName, true);
17855             return;
17856         }
17857
17858         var dom = Ext.getDom(element),
17859             cache = this.getEventListenerCache(dom, eventName),
17860             bindName = this.normalizeEvent(eventName).eventName,
17861             i = cache.length, j,
17862             listener, wrap, tasks;
17863
17864
17865         while (i--) {
17866             listener = cache[i];
17867
17868             if (listener && (!fn || listener.fn == fn) && (!scope || listener.scope === scope)) {
17869                 wrap = listener.wrap;
17870
17871                 // clear buffered calls
17872                 if (wrap.task) {
17873                     clearTimeout(wrap.task);
17874                     delete wrap.task;
17875                 }
17876
17877                 // clear delayed calls
17878                 j = wrap.tasks && wrap.tasks.length;
17879                 if (j) {
17880                     while (j--) {
17881                         clearTimeout(wrap.tasks[j]);
17882                     }
17883                     delete wrap.tasks;
17884                 }
17885
17886                 if (dom.detachEvent) {
17887                     dom.detachEvent('on' + bindName, wrap);
17888                 } else {
17889                     dom.removeEventListener(bindName, wrap, false);
17890                 }
17891
17892                 if (wrap && dom == document && eventName == 'mousedown') {
17893                     this.stoppedMouseDownEvent.removeListener(wrap);
17894                 }
17895
17896                 // remove listener from cache
17897                 Ext.Array.erase(cache, i, 1);
17898             }
17899         }
17900     },
17901
17902     /**
17903     * Removes all event handers from an element.  Typically you will use {@link Ext.Element#removeAllListeners}
17904     * directly on an Element in favor of calling this version.
17905     * @param {String/HTMLElement} el The id or html element from which to remove all event handlers.
17906     */
17907     removeAll : function(element){
17908         var dom = Ext.getDom(element),
17909             cache, ev;
17910         if (!dom) {
17911             return;
17912         }
17913         cache = this.getElementEventCache(dom);
17914
17915         for (ev in cache) {
17916             if (cache.hasOwnProperty(ev)) {
17917                 this.removeListener(dom, ev);
17918             }
17919         }
17920         Ext.cache[dom.id].events = {};
17921     },
17922
17923     /**
17924      * Recursively removes all previous added listeners from an element and its children. Typically you will use {@link Ext.Element#purgeAllListeners}
17925      * directly on an Element in favor of calling this version.
17926      * @param {String/HTMLElement} el The id or html element from which to remove all event handlers.
17927      * @param {String} eventName (optional) The name of the event.
17928      */
17929     purgeElement : function(element, eventName) {
17930         var dom = Ext.getDom(element),
17931             i = 0, len;
17932
17933         if(eventName) {
17934             this.removeListener(dom, eventName);
17935         }
17936         else {
17937             this.removeAll(dom);
17938         }
17939
17940         if(dom && dom.childNodes) {
17941             for(len = element.childNodes.length; i < len; i++) {
17942                 this.purgeElement(element.childNodes[i], eventName);
17943             }
17944         }
17945     },
17946
17947     /**
17948      * Create the wrapper function for the event
17949      * @private
17950      * @param {HTMLElement} dom The dom element
17951      * @param {String} ename The event name
17952      * @param {Function} fn The function to execute
17953      * @param {Object} scope The scope to execute callback in
17954      * @param {Object} options The options
17955      * @return {Function} the wrapper function
17956      */
17957     createListenerWrap : function(dom, ename, fn, scope, options) {
17958         options = options || {};
17959
17960         var f, gen;
17961
17962         return function wrap(e, args) {
17963             // Compile the implementation upon first firing
17964             if (!gen) {
17965                 f = ['if(!Ext) {return;}'];
17966
17967                 if(options.buffer || options.delay || options.freezeEvent) {
17968                     f.push('e = new Ext.EventObjectImpl(e, ' + (options.freezeEvent ? 'true' : 'false' ) + ');');
17969                 } else {
17970                     f.push('e = Ext.EventObject.setEvent(e);');
17971                 }
17972
17973                 if (options.delegate) {
17974                     f.push('var t = e.getTarget("' + options.delegate + '", this);');
17975                     f.push('if(!t) {return;}');
17976                 } else {
17977                     f.push('var t = e.target;');
17978                 }
17979
17980                 if (options.target) {
17981                     f.push('if(e.target !== options.target) {return;}');
17982                 }
17983
17984                 if(options.stopEvent) {
17985                     f.push('e.stopEvent();');
17986                 } else {
17987                     if(options.preventDefault) {
17988                         f.push('e.preventDefault();');
17989                     }
17990                     if(options.stopPropagation) {
17991                         f.push('e.stopPropagation();');
17992                     }
17993                 }
17994
17995                 if(options.normalized === false) {
17996                     f.push('e = e.browserEvent;');
17997                 }
17998
17999                 if(options.buffer) {
18000                     f.push('(wrap.task && clearTimeout(wrap.task));');
18001                     f.push('wrap.task = setTimeout(function(){');
18002                 }
18003
18004                 if(options.delay) {
18005                     f.push('wrap.tasks = wrap.tasks || [];');
18006                     f.push('wrap.tasks.push(setTimeout(function(){');
18007                 }
18008
18009                 // finally call the actual handler fn
18010                 f.push('fn.call(scope || dom, e, t, options);');
18011
18012                 if(options.single) {
18013                     f.push('Ext.EventManager.removeListener(dom, ename, fn, scope);');
18014                 }
18015
18016                 if(options.delay) {
18017                     f.push('}, ' + options.delay + '));');
18018                 }
18019
18020                 if(options.buffer) {
18021                     f.push('}, ' + options.buffer + ');');
18022                 }
18023
18024                 gen = Ext.functionFactory('e', 'options', 'fn', 'scope', 'ename', 'dom', 'wrap', 'args', f.join('\n'));
18025             }
18026
18027             gen.call(dom, e, options, fn, scope, ename, dom, wrap, args);
18028         };
18029     },
18030
18031     /**
18032      * Get the event cache for a particular element for a particular event
18033      * @private
18034      * @param {HTMLElement} element The element
18035      * @param {Object} eventName The event name
18036      * @return {Array} The events for the element
18037      */
18038     getEventListenerCache : function(element, eventName) {
18039         if (!element) {
18040             return [];
18041         }
18042
18043         var eventCache = this.getElementEventCache(element);
18044         return eventCache[eventName] || (eventCache[eventName] = []);
18045     },
18046
18047     /**
18048      * Gets the event cache for the object
18049      * @private
18050      * @param {HTMLElement} element The element
18051      * @return {Object} The event cache for the object
18052      */
18053     getElementEventCache : function(element) {
18054         if (!element) {
18055             return {};
18056         }
18057         var elementCache = Ext.cache[this.getId(element)];
18058         return elementCache.events || (elementCache.events = {});
18059     },
18060
18061     // --------------------- utility methods ---------------------
18062     mouseLeaveRe: /(mouseout|mouseleave)/,
18063     mouseEnterRe: /(mouseover|mouseenter)/,
18064
18065     /**
18066      * Stop the event (preventDefault and stopPropagation)
18067      * @param {Event} The event to stop
18068      */
18069     stopEvent: function(event) {
18070         this.stopPropagation(event);
18071         this.preventDefault(event);
18072     },
18073
18074     /**
18075      * Cancels bubbling of the event.
18076      * @param {Event} The event to stop bubbling.
18077      */
18078     stopPropagation: function(event) {
18079         event = event.browserEvent || event;
18080         if (event.stopPropagation) {
18081             event.stopPropagation();
18082         } else {
18083             event.cancelBubble = true;
18084         }
18085     },
18086
18087     /**
18088      * Prevents the browsers default handling of the event.
18089      * @param {Event} The event to prevent the default
18090      */
18091     preventDefault: function(event) {
18092         event = event.browserEvent || event;
18093         if (event.preventDefault) {
18094             event.preventDefault();
18095         } else {
18096             event.returnValue = false;
18097             // Some keys events require setting the keyCode to -1 to be prevented
18098             try {
18099               // all ctrl + X and F1 -> F12
18100               if (event.ctrlKey || event.keyCode > 111 && event.keyCode < 124) {
18101                   event.keyCode = -1;
18102               }
18103             } catch (e) {
18104                 // see this outdated document http://support.microsoft.com/kb/934364/en-us for more info
18105             }
18106         }
18107     },
18108
18109     /**
18110      * Gets the related target from the event.
18111      * @param {Object} event The event
18112      * @return {HTMLElement} The related target.
18113      */
18114     getRelatedTarget: function(event) {
18115         event = event.browserEvent || event;
18116         var target = event.relatedTarget;
18117         if (!target) {
18118             if (this.mouseLeaveRe.test(event.type)) {
18119                 target = event.toElement;
18120             } else if (this.mouseEnterRe.test(event.type)) {
18121                 target = event.fromElement;
18122             }
18123         }
18124         return this.resolveTextNode(target);
18125     },
18126
18127     /**
18128      * Gets the x coordinate from the event
18129      * @param {Object} event The event
18130      * @return {Number} The x coordinate
18131      */
18132     getPageX: function(event) {
18133         return this.getXY(event)[0];
18134     },
18135
18136     /**
18137      * Gets the y coordinate from the event
18138      * @param {Object} event The event
18139      * @return {Number} The y coordinate
18140      */
18141     getPageY: function(event) {
18142         return this.getXY(event)[1];
18143     },
18144
18145     /**
18146      * Gets the x & y coordinate from the event
18147      * @param {Object} event The event
18148      * @return {Number[]} The x/y coordinate
18149      */
18150     getPageXY: function(event) {
18151         event = event.browserEvent || event;
18152         var x = event.pageX,
18153             y = event.pageY,
18154             doc = document.documentElement,
18155             body = document.body;
18156
18157         // pageX/pageY not available (undefined, not null), use clientX/clientY instead
18158         if (!x && x !== 0) {
18159             x = event.clientX + (doc && doc.scrollLeft || body && body.scrollLeft || 0) - (doc && doc.clientLeft || body && body.clientLeft || 0);
18160             y = event.clientY + (doc && doc.scrollTop  || body && body.scrollTop  || 0) - (doc && doc.clientTop  || body && body.clientTop  || 0);
18161         }
18162         return [x, y];
18163     },
18164
18165     /**
18166      * Gets the target of the event.
18167      * @param {Object} event The event
18168      * @return {HTMLElement} target
18169      */
18170     getTarget: function(event) {
18171         event = event.browserEvent || event;
18172         return this.resolveTextNode(event.target || event.srcElement);
18173     },
18174
18175     /**
18176      * Resolve any text nodes accounting for browser differences.
18177      * @private
18178      * @param {HTMLElement} node The node
18179      * @return {HTMLElement} The resolved node
18180      */
18181     // technically no need to browser sniff this, however it makes no sense to check this every time, for every event, whether the string is equal.
18182     resolveTextNode: Ext.isGecko ?
18183         function(node) {
18184             if (!node) {
18185                 return;
18186             }
18187             // work around firefox bug, https://bugzilla.mozilla.org/show_bug.cgi?id=101197
18188             var s = HTMLElement.prototype.toString.call(node);
18189             if (s == '[xpconnect wrapped native prototype]' || s == '[object XULElement]') {
18190                 return;
18191             }
18192                 return node.nodeType == 3 ? node.parentNode: node;
18193             }: function(node) {
18194                 return node && node.nodeType == 3 ? node.parentNode: node;
18195             },
18196
18197     // --------------------- custom event binding ---------------------
18198
18199     // Keep track of the current width/height
18200     curWidth: 0,
18201     curHeight: 0,
18202
18203     /**
18204      * Adds a listener to be notified when the browser window is resized and provides resize event buffering (100 milliseconds),
18205      * passes new viewport width and height to handlers.
18206      * @param {Function} fn      The handler function the window resize event invokes.
18207      * @param {Object}   scope   The scope (<code>this</code> reference) in which the handler function executes. Defaults to the browser window.
18208      * @param {Boolean}  options Options object as passed to {@link Ext.Element#addListener}
18209      */
18210     onWindowResize: function(fn, scope, options){
18211         var resize = this.resizeEvent;
18212         if(!resize){
18213             this.resizeEvent = resize = new Ext.util.Event();
18214             this.on(window, 'resize', this.fireResize, this, {buffer: 100});
18215         }
18216         resize.addListener(fn, scope, options);
18217     },
18218
18219     /**
18220      * Fire the resize event.
18221      * @private
18222      */
18223     fireResize: function(){
18224         var me = this,
18225             w = Ext.Element.getViewWidth(),
18226             h = Ext.Element.getViewHeight();
18227
18228          //whacky problem in IE where the resize event will sometimes fire even though the w/h are the same.
18229          if(me.curHeight != h || me.curWidth != w){
18230              me.curHeight = h;
18231              me.curWidth = w;
18232              me.resizeEvent.fire(w, h);
18233          }
18234     },
18235
18236     /**
18237      * Removes the passed window resize listener.
18238      * @param {Function} fn        The method the event invokes
18239      * @param {Object}   scope    The scope of handler
18240      */
18241     removeResizeListener: function(fn, scope){
18242         if (this.resizeEvent) {
18243             this.resizeEvent.removeListener(fn, scope);
18244         }
18245     },
18246
18247     onWindowUnload: function() {
18248         var unload = this.unloadEvent;
18249         if (!unload) {
18250             this.unloadEvent = unload = new Ext.util.Event();
18251             this.addListener(window, 'unload', this.fireUnload, this);
18252         }
18253     },
18254
18255     /**
18256      * Fires the unload event for items bound with onWindowUnload
18257      * @private
18258      */
18259     fireUnload: function() {
18260         // wrap in a try catch, could have some problems during unload
18261         try {
18262             this.removeUnloadListener();
18263             // Work around FF3 remembering the last scroll position when refreshing the grid and then losing grid view
18264             if (Ext.isGecko3) {
18265                 var gridviews = Ext.ComponentQuery.query('gridview'),
18266                     i = 0,
18267                     ln = gridviews.length;
18268                 for (; i < ln; i++) {
18269                     gridviews[i].scrollToTop();
18270                 }
18271             }
18272             // Purge all elements in the cache
18273             var el,
18274                 cache = Ext.cache;
18275             for (el in cache) {
18276                 if (cache.hasOwnProperty(el)) {
18277                     Ext.EventManager.removeAll(el);
18278                 }
18279             }
18280         } catch(e) {
18281         }
18282     },
18283
18284     /**
18285      * Removes the passed window unload listener.
18286      * @param {Function} fn        The method the event invokes
18287      * @param {Object}   scope    The scope of handler
18288      */
18289     removeUnloadListener: function(){
18290         if (this.unloadEvent) {
18291             this.removeListener(window, 'unload', this.fireUnload);
18292         }
18293     },
18294
18295     /**
18296      * note 1: IE fires ONLY the keydown event on specialkey autorepeat
18297      * note 2: Safari < 3.1, Gecko (Mac/Linux) & Opera fire only the keypress event on specialkey autorepeat
18298      * (research done by Jan Wolter at http://unixpapa.com/js/key.html)
18299      * @private
18300      */
18301     useKeyDown: Ext.isWebKit ?
18302                    parseInt(navigator.userAgent.match(/AppleWebKit\/(\d+)/)[1], 10) >= 525 :
18303                    !((Ext.isGecko && !Ext.isWindows) || Ext.isOpera),
18304
18305     /**
18306      * Indicates which event to use for getting key presses.
18307      * @return {String} The appropriate event name.
18308      */
18309     getKeyEvent: function(){
18310         return this.useKeyDown ? 'keydown' : 'keypress';
18311     }
18312 };
18313
18314 /**
18315  * Alias for {@link Ext.Loader#onReady Ext.Loader.onReady} with withDomReady set to true
18316  * @member Ext
18317  * @method onReady
18318  */
18319 Ext.onReady = function(fn, scope, options) {
18320     Ext.Loader.onReady(fn, scope, true, options);
18321 };
18322
18323 /**
18324  * Alias for {@link Ext.EventManager#onDocumentReady Ext.EventManager.onDocumentReady}
18325  * @member Ext
18326  * @method onDocumentReady
18327  */
18328 Ext.onDocumentReady = Ext.EventManager.onDocumentReady;
18329
18330 /**
18331  * Alias for {@link Ext.EventManager#addListener Ext.EventManager.addListener}
18332  * @member Ext.EventManager
18333  * @method on
18334  */
18335 Ext.EventManager.on = Ext.EventManager.addListener;
18336
18337 /**
18338  * Alias for {@link Ext.EventManager#removeListener Ext.EventManager.removeListener}
18339  * @member Ext.EventManager
18340  * @method un
18341  */
18342 Ext.EventManager.un = Ext.EventManager.removeListener;
18343
18344 (function(){
18345     var initExtCss = function() {
18346         // find the body element
18347         var bd = document.body || document.getElementsByTagName('body')[0],
18348             baseCSSPrefix = Ext.baseCSSPrefix,
18349             cls = [baseCSSPrefix + 'body'],
18350             htmlCls = [],
18351             html;
18352
18353         if (!bd) {
18354             return false;
18355         }
18356
18357         html = bd.parentNode;
18358
18359         function add (c) {
18360             cls.push(baseCSSPrefix + c);
18361         }
18362
18363         //Let's keep this human readable!
18364         if (Ext.isIE) {
18365             add('ie');
18366
18367             // very often CSS needs to do checks like "IE7+" or "IE6 or 7". To help
18368             // reduce the clutter (since CSS/SCSS cannot do these tests), we add some
18369             // additional classes:
18370             //
18371             //      x-ie7p      : IE7+      :  7 <= ieVer
18372             //      x-ie7m      : IE7-      :  ieVer <= 7
18373             //      x-ie8p      : IE8+      :  8 <= ieVer
18374             //      x-ie8m      : IE8-      :  ieVer <= 8
18375             //      x-ie9p      : IE9+      :  9 <= ieVer
18376             //      x-ie78      : IE7 or 8  :  7 <= ieVer <= 8
18377             //
18378             if (Ext.isIE6) {
18379                 add('ie6');
18380             } else { // ignore pre-IE6 :)
18381                 add('ie7p');
18382
18383                 if (Ext.isIE7) {
18384                     add('ie7');
18385                 } else {
18386                     add('ie8p');
18387
18388                     if (Ext.isIE8) {
18389                         add('ie8');
18390                     } else {
18391                         add('ie9p');
18392
18393                         if (Ext.isIE9) {
18394                             add('ie9');
18395                         }
18396                     }
18397                 }
18398             }
18399
18400             if (Ext.isIE6 || Ext.isIE7) {
18401                 add('ie7m');
18402             }
18403             if (Ext.isIE6 || Ext.isIE7 || Ext.isIE8) {
18404                 add('ie8m');
18405             }
18406             if (Ext.isIE7 || Ext.isIE8) {
18407                 add('ie78');
18408             }
18409         }
18410         if (Ext.isGecko) {
18411             add('gecko');
18412             if (Ext.isGecko3) {
18413                 add('gecko3');
18414             }
18415             if (Ext.isGecko4) {
18416                 add('gecko4');
18417             }
18418             if (Ext.isGecko5) {
18419                 add('gecko5');
18420             }
18421         }
18422         if (Ext.isOpera) {
18423             add('opera');
18424         }
18425         if (Ext.isWebKit) {
18426             add('webkit');
18427         }
18428         if (Ext.isSafari) {
18429             add('safari');
18430             if (Ext.isSafari2) {
18431                 add('safari2');
18432             }
18433             if (Ext.isSafari3) {
18434                 add('safari3');
18435             }
18436             if (Ext.isSafari4) {
18437                 add('safari4');
18438             }
18439             if (Ext.isSafari5) {
18440                 add('safari5');
18441             }
18442         }
18443         if (Ext.isChrome) {
18444             add('chrome');
18445         }
18446         if (Ext.isMac) {
18447             add('mac');
18448         }
18449         if (Ext.isLinux) {
18450             add('linux');
18451         }
18452         if (!Ext.supports.CSS3BorderRadius) {
18453             add('nbr');
18454         }
18455         if (!Ext.supports.CSS3LinearGradient) {
18456             add('nlg');
18457         }
18458         if (!Ext.scopeResetCSS) {
18459             add('reset');
18460         }
18461
18462         // add to the parent to allow for selectors x-strict x-border-box, also set the isBorderBox property correctly
18463         if (html) {
18464             if (Ext.isStrict && (Ext.isIE6 || Ext.isIE7)) {
18465                 Ext.isBorderBox = false;
18466             }
18467             else {
18468                 Ext.isBorderBox = true;
18469             }
18470
18471             htmlCls.push(baseCSSPrefix + (Ext.isBorderBox ? 'border-box' : 'strict'));
18472             if (!Ext.isStrict) {
18473                 htmlCls.push(baseCSSPrefix + 'quirks');
18474             }
18475             Ext.fly(html, '_internal').addCls(htmlCls);
18476         }
18477
18478         Ext.fly(bd, '_internal').addCls(cls);
18479         return true;
18480     };
18481
18482     Ext.onReady(initExtCss);
18483 })();
18484
18485 /**
18486  * @class Ext.EventObject
18487
18488 Just as {@link Ext.Element} wraps around a native DOM node, Ext.EventObject
18489 wraps the browser's native event-object normalizing cross-browser differences,
18490 such as which mouse button is clicked, keys pressed, mechanisms to stop
18491 event-propagation along with a method to prevent default actions from taking place.
18492
18493 For example:
18494
18495     function handleClick(e, t){ // e is not a standard event object, it is a Ext.EventObject
18496         e.preventDefault();
18497         var target = e.getTarget(); // same as t (the target HTMLElement)
18498         ...
18499     }
18500
18501     var myDiv = {@link Ext#get Ext.get}("myDiv");  // get reference to an {@link Ext.Element}
18502     myDiv.on(         // 'on' is shorthand for addListener
18503         "click",      // perform an action on click of myDiv
18504         handleClick   // reference to the action handler
18505     );
18506
18507     // other methods to do the same:
18508     Ext.EventManager.on("myDiv", 'click', handleClick);
18509     Ext.EventManager.addListener("myDiv", 'click', handleClick);
18510
18511  * @singleton
18512  * @markdown
18513  */
18514 Ext.define('Ext.EventObjectImpl', {
18515     uses: ['Ext.util.Point'],
18516
18517     /** Key constant @type Number */
18518     BACKSPACE: 8,
18519     /** Key constant @type Number */
18520     TAB: 9,
18521     /** Key constant @type Number */
18522     NUM_CENTER: 12,
18523     /** Key constant @type Number */
18524     ENTER: 13,
18525     /** Key constant @type Number */
18526     RETURN: 13,
18527     /** Key constant @type Number */
18528     SHIFT: 16,
18529     /** Key constant @type Number */
18530     CTRL: 17,
18531     /** Key constant @type Number */
18532     ALT: 18,
18533     /** Key constant @type Number */
18534     PAUSE: 19,
18535     /** Key constant @type Number */
18536     CAPS_LOCK: 20,
18537     /** Key constant @type Number */
18538     ESC: 27,
18539     /** Key constant @type Number */
18540     SPACE: 32,
18541     /** Key constant @type Number */
18542     PAGE_UP: 33,
18543     /** Key constant @type Number */
18544     PAGE_DOWN: 34,
18545     /** Key constant @type Number */
18546     END: 35,
18547     /** Key constant @type Number */
18548     HOME: 36,
18549     /** Key constant @type Number */
18550     LEFT: 37,
18551     /** Key constant @type Number */
18552     UP: 38,
18553     /** Key constant @type Number */
18554     RIGHT: 39,
18555     /** Key constant @type Number */
18556     DOWN: 40,
18557     /** Key constant @type Number */
18558     PRINT_SCREEN: 44,
18559     /** Key constant @type Number */
18560     INSERT: 45,
18561     /** Key constant @type Number */
18562     DELETE: 46,
18563     /** Key constant @type Number */
18564     ZERO: 48,
18565     /** Key constant @type Number */
18566     ONE: 49,
18567     /** Key constant @type Number */
18568     TWO: 50,
18569     /** Key constant @type Number */
18570     THREE: 51,
18571     /** Key constant @type Number */
18572     FOUR: 52,
18573     /** Key constant @type Number */
18574     FIVE: 53,
18575     /** Key constant @type Number */
18576     SIX: 54,
18577     /** Key constant @type Number */
18578     SEVEN: 55,
18579     /** Key constant @type Number */
18580     EIGHT: 56,
18581     /** Key constant @type Number */
18582     NINE: 57,
18583     /** Key constant @type Number */
18584     A: 65,
18585     /** Key constant @type Number */
18586     B: 66,
18587     /** Key constant @type Number */
18588     C: 67,
18589     /** Key constant @type Number */
18590     D: 68,
18591     /** Key constant @type Number */
18592     E: 69,
18593     /** Key constant @type Number */
18594     F: 70,
18595     /** Key constant @type Number */
18596     G: 71,
18597     /** Key constant @type Number */
18598     H: 72,
18599     /** Key constant @type Number */
18600     I: 73,
18601     /** Key constant @type Number */
18602     J: 74,
18603     /** Key constant @type Number */
18604     K: 75,
18605     /** Key constant @type Number */
18606     L: 76,
18607     /** Key constant @type Number */
18608     M: 77,
18609     /** Key constant @type Number */
18610     N: 78,
18611     /** Key constant @type Number */
18612     O: 79,
18613     /** Key constant @type Number */
18614     P: 80,
18615     /** Key constant @type Number */
18616     Q: 81,
18617     /** Key constant @type Number */
18618     R: 82,
18619     /** Key constant @type Number */
18620     S: 83,
18621     /** Key constant @type Number */
18622     T: 84,
18623     /** Key constant @type Number */
18624     U: 85,
18625     /** Key constant @type Number */
18626     V: 86,
18627     /** Key constant @type Number */
18628     W: 87,
18629     /** Key constant @type Number */
18630     X: 88,
18631     /** Key constant @type Number */
18632     Y: 89,
18633     /** Key constant @type Number */
18634     Z: 90,
18635     /** Key constant @type Number */
18636     CONTEXT_MENU: 93,
18637     /** Key constant @type Number */
18638     NUM_ZERO: 96,
18639     /** Key constant @type Number */
18640     NUM_ONE: 97,
18641     /** Key constant @type Number */
18642     NUM_TWO: 98,
18643     /** Key constant @type Number */
18644     NUM_THREE: 99,
18645     /** Key constant @type Number */
18646     NUM_FOUR: 100,
18647     /** Key constant @type Number */
18648     NUM_FIVE: 101,
18649     /** Key constant @type Number */
18650     NUM_SIX: 102,
18651     /** Key constant @type Number */
18652     NUM_SEVEN: 103,
18653     /** Key constant @type Number */
18654     NUM_EIGHT: 104,
18655     /** Key constant @type Number */
18656     NUM_NINE: 105,
18657     /** Key constant @type Number */
18658     NUM_MULTIPLY: 106,
18659     /** Key constant @type Number */
18660     NUM_PLUS: 107,
18661     /** Key constant @type Number */
18662     NUM_MINUS: 109,
18663     /** Key constant @type Number */
18664     NUM_PERIOD: 110,
18665     /** Key constant @type Number */
18666     NUM_DIVISION: 111,
18667     /** Key constant @type Number */
18668     F1: 112,
18669     /** Key constant @type Number */
18670     F2: 113,
18671     /** Key constant @type Number */
18672     F3: 114,
18673     /** Key constant @type Number */
18674     F4: 115,
18675     /** Key constant @type Number */
18676     F5: 116,
18677     /** Key constant @type Number */
18678     F6: 117,
18679     /** Key constant @type Number */
18680     F7: 118,
18681     /** Key constant @type Number */
18682     F8: 119,
18683     /** Key constant @type Number */
18684     F9: 120,
18685     /** Key constant @type Number */
18686     F10: 121,
18687     /** Key constant @type Number */
18688     F11: 122,
18689     /** Key constant @type Number */
18690     F12: 123,
18691     /**
18692      * The mouse wheel delta scaling factor. This value depends on browser version and OS and
18693      * attempts to produce a similar scrolling experience across all platforms and browsers.
18694      *
18695      * To change this value:
18696      *
18697      *      Ext.EventObjectImpl.prototype.WHEEL_SCALE = 72;
18698      *
18699      * @type Number
18700      * @markdown
18701      */
18702     WHEEL_SCALE: (function () {
18703         var scale;
18704
18705         if (Ext.isGecko) {
18706             // Firefox uses 3 on all platforms
18707             scale = 3;
18708         } else if (Ext.isMac) {
18709             // Continuous scrolling devices have momentum and produce much more scroll than
18710             // discrete devices on the same OS and browser. To make things exciting, Safari
18711             // (and not Chrome) changed from small values to 120 (like IE).
18712
18713             if (Ext.isSafari && Ext.webKitVersion >= 532.0) {
18714                 // Safari changed the scrolling factor to match IE (for details see
18715                 // https://bugs.webkit.org/show_bug.cgi?id=24368). The WebKit version where this
18716                 // change was introduced was 532.0
18717                 //      Detailed discussion:
18718                 //      https://bugs.webkit.org/show_bug.cgi?id=29601
18719                 //      http://trac.webkit.org/browser/trunk/WebKit/chromium/src/mac/WebInputEventFactory.mm#L1063
18720                 scale = 120;
18721             } else {
18722                 // MS optical wheel mouse produces multiples of 12 which is close enough
18723                 // to help tame the speed of the continuous mice...
18724                 scale = 12;
18725             }
18726
18727             // Momentum scrolling produces very fast scrolling, so increase the scale factor
18728             // to help produce similar results cross platform. This could be even larger and
18729             // it would help those mice, but other mice would become almost unusable as a
18730             // result (since we cannot tell which device type is in use).
18731             scale *= 3;
18732         } else {
18733             // IE, Opera and other Windows browsers use 120.
18734             scale = 120;
18735         }
18736
18737         return scale;
18738     })(),
18739
18740     /**
18741      * Simple click regex
18742      * @private
18743      */
18744     clickRe: /(dbl)?click/,
18745     // safari keypress events for special keys return bad keycodes
18746     safariKeys: {
18747         3: 13, // enter
18748         63234: 37, // left
18749         63235: 39, // right
18750         63232: 38, // up
18751         63233: 40, // down
18752         63276: 33, // page up
18753         63277: 34, // page down
18754         63272: 46, // delete
18755         63273: 36, // home
18756         63275: 35 // end
18757     },
18758     // normalize button clicks, don't see any way to feature detect this.
18759     btnMap: Ext.isIE ? {
18760         1: 0,
18761         4: 1,
18762         2: 2
18763     } : {
18764         0: 0,
18765         1: 1,
18766         2: 2
18767     },
18768
18769     constructor: function(event, freezeEvent){
18770         if (event) {
18771             this.setEvent(event.browserEvent || event, freezeEvent);
18772         }
18773     },
18774
18775     setEvent: function(event, freezeEvent){
18776         var me = this, button, options;
18777
18778         if (event == me || (event && event.browserEvent)) { // already wrapped
18779             return event;
18780         }
18781         me.browserEvent = event;
18782         if (event) {
18783             // normalize buttons
18784             button = event.button ? me.btnMap[event.button] : (event.which ? event.which - 1 : -1);
18785             if (me.clickRe.test(event.type) && button == -1) {
18786                 button = 0;
18787             }
18788             options = {
18789                 type: event.type,
18790                 button: button,
18791                 shiftKey: event.shiftKey,
18792                 // mac metaKey behaves like ctrlKey
18793                 ctrlKey: event.ctrlKey || event.metaKey || false,
18794                 altKey: event.altKey,
18795                 // in getKey these will be normalized for the mac
18796                 keyCode: event.keyCode,
18797                 charCode: event.charCode,
18798                 // cache the targets for the delayed and or buffered events
18799                 target: Ext.EventManager.getTarget(event),
18800                 relatedTarget: Ext.EventManager.getRelatedTarget(event),
18801                 currentTarget: event.currentTarget,
18802                 xy: (freezeEvent ? me.getXY() : null)
18803             };
18804         } else {
18805             options = {
18806                 button: -1,
18807                 shiftKey: false,
18808                 ctrlKey: false,
18809                 altKey: false,
18810                 keyCode: 0,
18811                 charCode: 0,
18812                 target: null,
18813                 xy: [0, 0]
18814             };
18815         }
18816         Ext.apply(me, options);
18817         return me;
18818     },
18819
18820     /**
18821      * Stop the event (preventDefault and stopPropagation)
18822      */
18823     stopEvent: function(){
18824         this.stopPropagation();
18825         this.preventDefault();
18826     },
18827
18828     /**
18829      * Prevents the browsers default handling of the event.
18830      */
18831     preventDefault: function(){
18832         if (this.browserEvent) {
18833             Ext.EventManager.preventDefault(this.browserEvent);
18834         }
18835     },
18836
18837     /**
18838      * Cancels bubbling of the event.
18839      */
18840     stopPropagation: function(){
18841         var browserEvent = this.browserEvent;
18842
18843         if (browserEvent) {
18844             if (browserEvent.type == 'mousedown') {
18845                 Ext.EventManager.stoppedMouseDownEvent.fire(this);
18846             }
18847             Ext.EventManager.stopPropagation(browserEvent);
18848         }
18849     },
18850
18851     /**
18852      * Gets the character code for the event.
18853      * @return {Number}
18854      */
18855     getCharCode: function(){
18856         return this.charCode || this.keyCode;
18857     },
18858
18859     /**
18860      * Returns a normalized keyCode for the event.
18861      * @return {Number} The key code
18862      */
18863     getKey: function(){
18864         return this.normalizeKey(this.keyCode || this.charCode);
18865     },
18866
18867     /**
18868      * Normalize key codes across browsers
18869      * @private
18870      * @param {Number} key The key code
18871      * @return {Number} The normalized code
18872      */
18873     normalizeKey: function(key){
18874         // can't feature detect this
18875         return Ext.isWebKit ? (this.safariKeys[key] || key) : key;
18876     },
18877
18878     /**
18879      * Gets the x coordinate of the event.
18880      * @return {Number}
18881      * @deprecated 4.0 Replaced by {@link #getX}
18882      */
18883     getPageX: function(){
18884         return this.getX();
18885     },
18886
18887     /**
18888      * Gets the y coordinate of the event.
18889      * @return {Number}
18890      * @deprecated 4.0 Replaced by {@link #getY}
18891      */
18892     getPageY: function(){
18893         return this.getY();
18894     },
18895
18896     /**
18897      * Gets the x coordinate of the event.
18898      * @return {Number}
18899      */
18900     getX: function() {
18901         return this.getXY()[0];
18902     },
18903
18904     /**
18905      * Gets the y coordinate of the event.
18906      * @return {Number}
18907      */
18908     getY: function() {
18909         return this.getXY()[1];
18910     },
18911
18912     /**
18913      * Gets the page coordinates of the event.
18914      * @return {Number[]} The xy values like [x, y]
18915      */
18916     getXY: function() {
18917         if (!this.xy) {
18918             // same for XY
18919             this.xy = Ext.EventManager.getPageXY(this.browserEvent);
18920         }
18921         return this.xy;
18922     },
18923
18924     /**
18925      * Gets the target for the event.
18926      * @param {String} selector (optional) A simple selector to filter the target or look for an ancestor of the target
18927      * @param {Number/HTMLElement} maxDepth (optional) The max depth to search as a number or element (defaults to 10 || document.body)
18928      * @param {Boolean} returnEl (optional) True to return a Ext.Element object instead of DOM node
18929      * @return {HTMLElement}
18930      */
18931     getTarget : function(selector, maxDepth, returnEl){
18932         if (selector) {
18933             return Ext.fly(this.target).findParent(selector, maxDepth, returnEl);
18934         }
18935         return returnEl ? Ext.get(this.target) : this.target;
18936     },
18937
18938     /**
18939      * Gets the related target.
18940      * @param {String} selector (optional) A simple selector to filter the target or look for an ancestor of the target
18941      * @param {Number/HTMLElement} maxDepth (optional) The max depth to search as a number or element (defaults to 10 || document.body)
18942      * @param {Boolean} returnEl (optional) True to return a Ext.Element object instead of DOM node
18943      * @return {HTMLElement}
18944      */
18945     getRelatedTarget : function(selector, maxDepth, returnEl){
18946         if (selector) {
18947             return Ext.fly(this.relatedTarget).findParent(selector, maxDepth, returnEl);
18948         }
18949         return returnEl ? Ext.get(this.relatedTarget) : this.relatedTarget;
18950     },
18951
18952     /**
18953      * Correctly scales a given wheel delta.
18954      * @param {Number} delta The delta value.
18955      */
18956     correctWheelDelta : function (delta) {
18957         var scale = this.WHEEL_SCALE,
18958             ret = Math.round(delta / scale);
18959
18960         if (!ret && delta) {
18961             ret = (delta < 0) ? -1 : 1; // don't allow non-zero deltas to go to zero!
18962         }
18963
18964         return ret;
18965     },
18966
18967     /**
18968      * Returns the mouse wheel deltas for this event.
18969      * @return {Object} An object with "x" and "y" properties holding the mouse wheel deltas.
18970      */
18971     getWheelDeltas : function () {
18972         var me = this,
18973             event = me.browserEvent,
18974             dx = 0, dy = 0; // the deltas
18975
18976         if (Ext.isDefined(event.wheelDeltaX)) { // WebKit has both dimensions
18977             dx = event.wheelDeltaX;
18978             dy = event.wheelDeltaY;
18979         } else if (event.wheelDelta) { // old WebKit and IE
18980             dy = event.wheelDelta;
18981         } else if (event.detail) { // Gecko
18982             dy = -event.detail; // gecko is backwards
18983
18984             // Gecko sometimes returns really big values if the user changes settings to
18985             // scroll a whole page per scroll
18986             if (dy > 100) {
18987                 dy = 3;
18988             } else if (dy < -100) {
18989                 dy = -3;
18990             }
18991
18992             // Firefox 3.1 adds an axis field to the event to indicate direction of
18993             // scroll.  See https://developer.mozilla.org/en/Gecko-Specific_DOM_Events
18994             if (Ext.isDefined(event.axis) && event.axis === event.HORIZONTAL_AXIS) {
18995                 dx = dy;
18996                 dy = 0;
18997             }
18998         }
18999
19000         return {
19001             x: me.correctWheelDelta(dx),
19002             y: me.correctWheelDelta(dy)
19003         };
19004     },
19005
19006     /**
19007      * Normalizes mouse wheel y-delta across browsers. To get x-delta information, use
19008      * {@link #getWheelDeltas} instead.
19009      * @return {Number} The mouse wheel y-delta
19010      */
19011     getWheelDelta : function(){
19012         var deltas = this.getWheelDeltas();
19013
19014         return deltas.y;
19015     },
19016
19017     /**
19018      * 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.
19019      * Example usage:<pre><code>
19020 // Handle click on any child of an element
19021 Ext.getBody().on('click', function(e){
19022     if(e.within('some-el')){
19023         alert('Clicked on a child of some-el!');
19024     }
19025 });
19026
19027 // Handle click directly on an element, ignoring clicks on child nodes
19028 Ext.getBody().on('click', function(e,t){
19029     if((t.id == 'some-el') && !e.within(t, true)){
19030         alert('Clicked directly on some-el!');
19031     }
19032 });
19033 </code></pre>
19034      * @param {String/HTMLElement/Ext.Element} el The id, DOM element or Ext.Element to check
19035      * @param {Boolean} related (optional) true to test if the related target is within el instead of the target
19036      * @param {Boolean} allowEl (optional) true to also check if the passed element is the target or related target
19037      * @return {Boolean}
19038      */
19039     within : function(el, related, allowEl){
19040         if(el){
19041             var t = related ? this.getRelatedTarget() : this.getTarget(),
19042                 result;
19043
19044             if (t) {
19045                 result = Ext.fly(el).contains(t);
19046                 if (!result && allowEl) {
19047                     result = t == Ext.getDom(el);
19048                 }
19049                 return result;
19050             }
19051         }
19052         return false;
19053     },
19054
19055     /**
19056      * Checks if the key pressed was a "navigation" key
19057      * @return {Boolean} True if the press is a navigation keypress
19058      */
19059     isNavKeyPress : function(){
19060         var me = this,
19061             k = this.normalizeKey(me.keyCode);
19062
19063        return (k >= 33 && k <= 40) ||  // Page Up/Down, End, Home, Left, Up, Right, Down
19064        k == me.RETURN ||
19065        k == me.TAB ||
19066        k == me.ESC;
19067     },
19068
19069     /**
19070      * Checks if the key pressed was a "special" key
19071      * @return {Boolean} True if the press is a special keypress
19072      */
19073     isSpecialKey : function(){
19074         var k = this.normalizeKey(this.keyCode);
19075         return (this.type == 'keypress' && this.ctrlKey) ||
19076         this.isNavKeyPress() ||
19077         (k == this.BACKSPACE) || // Backspace
19078         (k >= 16 && k <= 20) || // Shift, Ctrl, Alt, Pause, Caps Lock
19079         (k >= 44 && k <= 46);   // Print Screen, Insert, Delete
19080     },
19081
19082     /**
19083      * Returns a point object that consists of the object coordinates.
19084      * @return {Ext.util.Point} point
19085      */
19086     getPoint : function(){
19087         var xy = this.getXY();
19088         return Ext.create('Ext.util.Point', xy[0], xy[1]);
19089     },
19090
19091    /**
19092     * Returns true if the control, meta, shift or alt key was pressed during this event.
19093     * @return {Boolean}
19094     */
19095     hasModifier : function(){
19096         return this.ctrlKey || this.altKey || this.shiftKey || this.metaKey;
19097     },
19098
19099     /**
19100      * Injects a DOM event using the data in this object and (optionally) a new target.
19101      * This is a low-level technique and not likely to be used by application code. The
19102      * currently supported event types are:
19103      * <p><b>HTMLEvents</b></p>
19104      * <ul>
19105      * <li>load</li>
19106      * <li>unload</li>
19107      * <li>select</li>
19108      * <li>change</li>
19109      * <li>submit</li>
19110      * <li>reset</li>
19111      * <li>resize</li>
19112      * <li>scroll</li>
19113      * </ul>
19114      * <p><b>MouseEvents</b></p>
19115      * <ul>
19116      * <li>click</li>
19117      * <li>dblclick</li>
19118      * <li>mousedown</li>
19119      * <li>mouseup</li>
19120      * <li>mouseover</li>
19121      * <li>mousemove</li>
19122      * <li>mouseout</li>
19123      * </ul>
19124      * <p><b>UIEvents</b></p>
19125      * <ul>
19126      * <li>focusin</li>
19127      * <li>focusout</li>
19128      * <li>activate</li>
19129      * <li>focus</li>
19130      * <li>blur</li>
19131      * </ul>
19132      * @param {Ext.Element/HTMLElement} target (optional) If specified, the target for the event. This
19133      * is likely to be used when relaying a DOM event. If not specified, {@link #getTarget}
19134      * is used to determine the target.
19135      */
19136     injectEvent: function () {
19137         var API,
19138             dispatchers = {}; // keyed by event type (e.g., 'mousedown')
19139
19140         // Good reference: http://developer.yahoo.com/yui/docs/UserAction.js.html
19141
19142         // IE9 has createEvent, but this code causes major problems with htmleditor (it
19143         // blocks all mouse events and maybe more). TODO
19144
19145         if (!Ext.isIE && document.createEvent) { // if (DOM compliant)
19146             API = {
19147                 createHtmlEvent: function (doc, type, bubbles, cancelable) {
19148                     var event = doc.createEvent('HTMLEvents');
19149
19150                     event.initEvent(type, bubbles, cancelable);
19151                     return event;
19152                 },
19153
19154                 createMouseEvent: function (doc, type, bubbles, cancelable, detail,
19155                                             clientX, clientY, ctrlKey, altKey, shiftKey, metaKey,
19156                                             button, relatedTarget) {
19157                     var event = doc.createEvent('MouseEvents'),
19158                         view = doc.defaultView || window;
19159
19160                     if (event.initMouseEvent) {
19161                         event.initMouseEvent(type, bubbles, cancelable, view, detail,
19162                                     clientX, clientY, clientX, clientY, ctrlKey, altKey,
19163                                     shiftKey, metaKey, button, relatedTarget);
19164                     } else { // old Safari
19165                         event = doc.createEvent('UIEvents');
19166                         event.initEvent(type, bubbles, cancelable);
19167                         event.view = view;
19168                         event.detail = detail;
19169                         event.screenX = clientX;
19170                         event.screenY = clientY;
19171                         event.clientX = clientX;
19172                         event.clientY = clientY;
19173                         event.ctrlKey = ctrlKey;
19174                         event.altKey = altKey;
19175                         event.metaKey = metaKey;
19176                         event.shiftKey = shiftKey;
19177                         event.button = button;
19178                         event.relatedTarget = relatedTarget;
19179                     }
19180
19181                     return event;
19182                 },
19183
19184                 createUIEvent: function (doc, type, bubbles, cancelable, detail) {
19185                     var event = doc.createEvent('UIEvents'),
19186                         view = doc.defaultView || window;
19187
19188                     event.initUIEvent(type, bubbles, cancelable, view, detail);
19189                     return event;
19190                 },
19191
19192                 fireEvent: function (target, type, event) {
19193                     target.dispatchEvent(event);
19194                 },
19195
19196                 fixTarget: function (target) {
19197                     // Safari3 doesn't have window.dispatchEvent()
19198                     if (target == window && !target.dispatchEvent) {
19199                         return document;
19200                     }
19201
19202                     return target;
19203                 }
19204             };
19205         } else if (document.createEventObject) { // else if (IE)
19206             var crazyIEButtons = { 0: 1, 1: 4, 2: 2 };
19207
19208             API = {
19209                 createHtmlEvent: function (doc, type, bubbles, cancelable) {
19210                     var event = doc.createEventObject();
19211                     event.bubbles = bubbles;
19212                     event.cancelable = cancelable;
19213                     return event;
19214                 },
19215
19216                 createMouseEvent: function (doc, type, bubbles, cancelable, detail,
19217                                             clientX, clientY, ctrlKey, altKey, shiftKey, metaKey,
19218                                             button, relatedTarget) {
19219                     var event = doc.createEventObject();
19220                     event.bubbles = bubbles;
19221                     event.cancelable = cancelable;
19222                     event.detail = detail;
19223                     event.screenX = clientX;
19224                     event.screenY = clientY;
19225                     event.clientX = clientX;
19226                     event.clientY = clientY;
19227                     event.ctrlKey = ctrlKey;
19228                     event.altKey = altKey;
19229                     event.shiftKey = shiftKey;
19230                     event.metaKey = metaKey;
19231                     event.button = crazyIEButtons[button] || button;
19232                     event.relatedTarget = relatedTarget; // cannot assign to/fromElement
19233                     return event;
19234                 },
19235
19236                 createUIEvent: function (doc, type, bubbles, cancelable, detail) {
19237                     var event = doc.createEventObject();
19238                     event.bubbles = bubbles;
19239                     event.cancelable = cancelable;
19240                     return event;
19241                 },
19242
19243                 fireEvent: function (target, type, event) {
19244                     target.fireEvent('on' + type, event);
19245                 },
19246
19247                 fixTarget: function (target) {
19248                     if (target == document) {
19249                         // IE6,IE7 thinks window==document and doesn't have window.fireEvent()
19250                         // IE6,IE7 cannot properly call document.fireEvent()
19251                         return document.documentElement;
19252                     }
19253
19254                     return target;
19255                 }
19256             };
19257         }
19258
19259         //----------------
19260         // HTMLEvents
19261
19262         Ext.Object.each({
19263                 load:   [false, false],
19264                 unload: [false, false],
19265                 select: [true, false],
19266                 change: [true, false],
19267                 submit: [true, true],
19268                 reset:  [true, false],
19269                 resize: [true, false],
19270                 scroll: [true, false]
19271             },
19272             function (name, value) {
19273                 var bubbles = value[0], cancelable = value[1];
19274                 dispatchers[name] = function (targetEl, srcEvent) {
19275                     var e = API.createHtmlEvent(name, bubbles, cancelable);
19276                     API.fireEvent(targetEl, name, e);
19277                 };
19278             });
19279
19280         //----------------
19281         // MouseEvents
19282
19283         function createMouseEventDispatcher (type, detail) {
19284             var cancelable = (type != 'mousemove');
19285             return function (targetEl, srcEvent) {
19286                 var xy = srcEvent.getXY(),
19287                     e = API.createMouseEvent(targetEl.ownerDocument, type, true, cancelable,
19288                                 detail, xy[0], xy[1], srcEvent.ctrlKey, srcEvent.altKey,
19289                                 srcEvent.shiftKey, srcEvent.metaKey, srcEvent.button,
19290                                 srcEvent.relatedTarget);
19291                 API.fireEvent(targetEl, type, e);
19292             };
19293         }
19294
19295         Ext.each(['click', 'dblclick', 'mousedown', 'mouseup', 'mouseover', 'mousemove', 'mouseout'],
19296             function (eventName) {
19297                 dispatchers[eventName] = createMouseEventDispatcher(eventName, 1);
19298             });
19299
19300         //----------------
19301         // UIEvents
19302
19303         Ext.Object.each({
19304                 focusin:  [true, false],
19305                 focusout: [true, false],
19306                 activate: [true, true],
19307                 focus:    [false, false],
19308                 blur:     [false, false]
19309             },
19310             function (name, value) {
19311                 var bubbles = value[0], cancelable = value[1];
19312                 dispatchers[name] = function (targetEl, srcEvent) {
19313                     var e = API.createUIEvent(targetEl.ownerDocument, name, bubbles, cancelable, 1);
19314                     API.fireEvent(targetEl, name, e);
19315                 };
19316             });
19317
19318         //---------
19319         if (!API) {
19320             // not even sure what ancient browsers fall into this category...
19321
19322             dispatchers = {}; // never mind all those we just built :P
19323
19324             API = {
19325                 fixTarget: function (t) {
19326                     return t;
19327                 }
19328             };
19329         }
19330
19331         function cannotInject (target, srcEvent) {
19332             // TODO log something
19333         }
19334
19335         return function (target) {
19336             var me = this,
19337                 dispatcher = dispatchers[me.type] || cannotInject,
19338                 t = target ? (target.dom || target) : me.getTarget();
19339
19340             t = API.fixTarget(t);
19341             dispatcher(t, me);
19342         };
19343     }() // call to produce method
19344
19345 }, function() {
19346
19347 Ext.EventObject = new Ext.EventObjectImpl();
19348
19349 });
19350
19351
19352 /**
19353  * @class Ext.Element
19354  */
19355 (function(){
19356     var doc = document,
19357         activeElement = null,
19358         isCSS1 = doc.compatMode == "CSS1Compat",
19359         ELEMENT = Ext.Element,
19360         fly = function(el){
19361             if (!_fly) {
19362                 _fly = new Ext.Element.Flyweight();
19363             }
19364             _fly.dom = el;
19365             return _fly;
19366         }, _fly;
19367
19368     // If the browser does not support document.activeElement we need some assistance.
19369     // This covers old Safari 3.2 (4.0 added activeElement along with just about all
19370     // other browsers). We need this support to handle issues with old Safari.
19371     if (!('activeElement' in doc) && doc.addEventListener) {
19372         doc.addEventListener('focus',
19373             function (ev) {
19374                 if (ev && ev.target) {
19375                     activeElement = (ev.target == doc) ? null : ev.target;
19376                 }
19377             }, true);
19378     }
19379
19380     /*
19381      * Helper function to create the function that will restore the selection.
19382      */
19383     function makeSelectionRestoreFn (activeEl, start, end) {
19384         return function () {
19385             activeEl.selectionStart = start;
19386             activeEl.selectionEnd = end;
19387         };
19388     }
19389
19390     Ext.apply(ELEMENT, {
19391         isAncestor : function(p, c) {
19392             var ret = false;
19393
19394             p = Ext.getDom(p);
19395             c = Ext.getDom(c);
19396             if (p && c) {
19397                 if (p.contains) {
19398                     return p.contains(c);
19399                 } else if (p.compareDocumentPosition) {
19400                     return !!(p.compareDocumentPosition(c) & 16);
19401                 } else {
19402                     while ((c = c.parentNode)) {
19403                         ret = c == p || ret;
19404                     }
19405                 }
19406             }
19407             return ret;
19408         },
19409
19410         /**
19411          * Returns the active element in the DOM. If the browser supports activeElement
19412          * on the document, this is returned. If not, the focus is tracked and the active
19413          * element is maintained internally.
19414          * @return {HTMLElement} The active (focused) element in the document.
19415          */
19416         getActiveElement: function () {
19417             return doc.activeElement || activeElement;
19418         },
19419
19420         /**
19421          * Creates a function to call to clean up problems with the work-around for the
19422          * WebKit RightMargin bug. The work-around is to add "display: 'inline-block'" to
19423          * the element before calling getComputedStyle and then to restore its original
19424          * display value. The problem with this is that it corrupts the selection of an
19425          * INPUT or TEXTAREA element (as in the "I-beam" goes away but ths focus remains).
19426          * To cleanup after this, we need to capture the selection of any such element and
19427          * then restore it after we have restored the display style.
19428          *
19429          * @param target {Element} The top-most element being adjusted.
19430          * @private
19431          */
19432         getRightMarginFixCleaner: function (target) {
19433             var supports = Ext.supports,
19434                 hasInputBug = supports.DisplayChangeInputSelectionBug,
19435                 hasTextAreaBug = supports.DisplayChangeTextAreaSelectionBug;
19436
19437             if (hasInputBug || hasTextAreaBug) {
19438                 var activeEl = doc.activeElement || activeElement, // save a call
19439                     tag = activeEl && activeEl.tagName,
19440                     start,
19441                     end;
19442
19443                 if ((hasTextAreaBug && tag == 'TEXTAREA') ||
19444                     (hasInputBug && tag == 'INPUT' && activeEl.type == 'text')) {
19445                     if (ELEMENT.isAncestor(target, activeEl)) {
19446                         start = activeEl.selectionStart;
19447                         end = activeEl.selectionEnd;
19448
19449                         if (Ext.isNumber(start) && Ext.isNumber(end)) { // to be safe...
19450                             // We don't create the raw closure here inline because that
19451                             // will be costly even if we don't want to return it (nested
19452                             // function decls and exprs are often instantiated on entry
19453                             // regardless of whether execution ever reaches them):
19454                             return makeSelectionRestoreFn(activeEl, start, end);
19455                         }
19456                     }
19457                 }
19458             }
19459
19460             return Ext.emptyFn; // avoid special cases, just return a nop
19461         },
19462
19463         getViewWidth : function(full) {
19464             return full ? ELEMENT.getDocumentWidth() : ELEMENT.getViewportWidth();
19465         },
19466
19467         getViewHeight : function(full) {
19468             return full ? ELEMENT.getDocumentHeight() : ELEMENT.getViewportHeight();
19469         },
19470
19471         getDocumentHeight: function() {
19472             return Math.max(!isCSS1 ? doc.body.scrollHeight : doc.documentElement.scrollHeight, ELEMENT.getViewportHeight());
19473         },
19474
19475         getDocumentWidth: function() {
19476             return Math.max(!isCSS1 ? doc.body.scrollWidth : doc.documentElement.scrollWidth, ELEMENT.getViewportWidth());
19477         },
19478
19479         getViewportHeight: function(){
19480             return Ext.isIE ?
19481                    (Ext.isStrict ? doc.documentElement.clientHeight : doc.body.clientHeight) :
19482                    self.innerHeight;
19483         },
19484
19485         getViewportWidth : function() {
19486             return (!Ext.isStrict && !Ext.isOpera) ? doc.body.clientWidth :
19487                    Ext.isIE ? doc.documentElement.clientWidth : self.innerWidth;
19488         },
19489
19490         getY : function(el) {
19491             return ELEMENT.getXY(el)[1];
19492         },
19493
19494         getX : function(el) {
19495             return ELEMENT.getXY(el)[0];
19496         },
19497
19498         getOffsetParent: function (el) {
19499             el = Ext.getDom(el);
19500             try {
19501                 // accessing offsetParent can throw "Unspecified Error" in IE6-8 (not 9)
19502                 return el.offsetParent;
19503             } catch (e) {
19504                 var body = document.body; // safe bet, unless...
19505                 return (el == body) ? null : body;
19506             }
19507         },
19508
19509         getXY : function(el) {
19510             var p,
19511                 pe,
19512                 b,
19513                 bt,
19514                 bl,
19515                 dbd,
19516                 x = 0,
19517                 y = 0,
19518                 scroll,
19519                 hasAbsolute,
19520                 bd = (doc.body || doc.documentElement),
19521                 ret;
19522
19523             el = Ext.getDom(el);
19524
19525             if(el != bd){
19526                 hasAbsolute = fly(el).isStyle("position", "absolute");
19527
19528                 if (el.getBoundingClientRect) {
19529                     try {
19530                         b = el.getBoundingClientRect();
19531                         scroll = fly(document).getScroll();
19532                         ret = [ Math.round(b.left + scroll.left), Math.round(b.top + scroll.top) ];
19533                     } catch (e) {
19534                         // IE6-8 can also throw from getBoundingClientRect...
19535                     }
19536                 }
19537
19538                 if (!ret) {
19539                     for (p = el; p; p = ELEMENT.getOffsetParent(p)) {
19540                         pe = fly(p);
19541                         x += p.offsetLeft;
19542                         y += p.offsetTop;
19543
19544                         hasAbsolute = hasAbsolute || pe.isStyle("position", "absolute");
19545
19546                         if (Ext.isGecko) {
19547                             y += bt = parseInt(pe.getStyle("borderTopWidth"), 10) || 0;
19548                             x += bl = parseInt(pe.getStyle("borderLeftWidth"), 10) || 0;
19549
19550                             if (p != el && !pe.isStyle('overflow','visible')) {
19551                                 x += bl;
19552                                 y += bt;
19553                             }
19554                         }
19555                     }
19556
19557                     if (Ext.isSafari && hasAbsolute) {
19558                         x -= bd.offsetLeft;
19559                         y -= bd.offsetTop;
19560                     }
19561
19562                     if (Ext.isGecko && !hasAbsolute) {
19563                         dbd = fly(bd);
19564                         x += parseInt(dbd.getStyle("borderLeftWidth"), 10) || 0;
19565                         y += parseInt(dbd.getStyle("borderTopWidth"), 10) || 0;
19566                     }
19567
19568                     p = el.parentNode;
19569                     while (p && p != bd) {
19570                         if (!Ext.isOpera || (p.tagName != 'TR' && !fly(p).isStyle("display", "inline"))) {
19571                             x -= p.scrollLeft;
19572                             y -= p.scrollTop;
19573                         }
19574                         p = p.parentNode;
19575                     }
19576                     ret = [x,y];
19577                 }
19578             }
19579             return ret || [0,0];
19580         },
19581
19582         setXY : function(el, xy) {
19583             (el = Ext.fly(el, '_setXY')).position();
19584
19585             var pts = el.translatePoints(xy),
19586                 style = el.dom.style,
19587                 pos;
19588
19589             for (pos in pts) {
19590                 if (!isNaN(pts[pos])) {
19591                     style[pos] = pts[pos] + "px";
19592                 }
19593             }
19594         },
19595
19596         setX : function(el, x) {
19597             ELEMENT.setXY(el, [x, false]);
19598         },
19599
19600         setY : function(el, y) {
19601             ELEMENT.setXY(el, [false, y]);
19602         },
19603
19604         /**
19605          * Serializes a DOM form into a url encoded string
19606          * @param {Object} form The form
19607          * @return {String} The url encoded form
19608          */
19609         serializeForm: function(form) {
19610             var fElements = form.elements || (document.forms[form] || Ext.getDom(form)).elements,
19611                 hasSubmit = false,
19612                 encoder = encodeURIComponent,
19613                 name,
19614                 data = '',
19615                 type,
19616                 hasValue;
19617
19618             Ext.each(fElements, function(element){
19619                 name = element.name;
19620                 type = element.type;
19621
19622                 if (!element.disabled && name) {
19623                     if (/select-(one|multiple)/i.test(type)) {
19624                         Ext.each(element.options, function(opt){
19625                             if (opt.selected) {
19626                                 hasValue = opt.hasAttribute ? opt.hasAttribute('value') : opt.getAttributeNode('value').specified;
19627                                 data += Ext.String.format("{0}={1}&", encoder(name), encoder(hasValue ? opt.value : opt.text));
19628                             }
19629                         });
19630                     } else if (!(/file|undefined|reset|button/i.test(type))) {
19631                         if (!(/radio|checkbox/i.test(type) && !element.checked) && !(type == 'submit' && hasSubmit)) {
19632                             data += encoder(name) + '=' + encoder(element.value) + '&';
19633                             hasSubmit = /submit/i.test(type);
19634                         }
19635                     }
19636                 }
19637             });
19638             return data.substr(0, data.length - 1);
19639         }
19640     });
19641 })();
19642
19643 /**
19644  * @class Ext.Element
19645  */
19646
19647 Ext.Element.addMethods((function(){
19648     var focusRe = /button|input|textarea|select|object/;
19649     return {
19650         /**
19651          * Monitors this Element for the mouse leaving. Calls the function after the specified delay only if
19652          * the mouse was not moved back into the Element within the delay. If the mouse <i>was</i> moved
19653          * back in, the function is not called.
19654          * @param {Number} delay The delay <b>in milliseconds</b> to wait for possible mouse re-entry before calling the handler function.
19655          * @param {Function} handler The function to call if the mouse remains outside of this Element for the specified time.
19656          * @param {Object} scope The scope (<code>this</code> reference) in which the handler function executes. Defaults to this Element.
19657          * @return {Object} The listeners object which was added to this element so that monitoring can be stopped. Example usage:<pre><code>
19658 // Hide the menu if the mouse moves out for 250ms or more
19659 this.mouseLeaveMonitor = this.menuEl.monitorMouseLeave(250, this.hideMenu, this);
19660
19661 ...
19662 // Remove mouseleave monitor on menu destroy
19663 this.menuEl.un(this.mouseLeaveMonitor);
19664     </code></pre>
19665          */
19666         monitorMouseLeave: function(delay, handler, scope) {
19667             var me = this,
19668                 timer,
19669                 listeners = {
19670                     mouseleave: function(e) {
19671                         timer = setTimeout(Ext.Function.bind(handler, scope||me, [e]), delay);
19672                     },
19673                     mouseenter: function() {
19674                         clearTimeout(timer);
19675                     },
19676                     freezeEvent: true
19677                 };
19678
19679             me.on(listeners);
19680             return listeners;
19681         },
19682
19683         /**
19684          * Stops the specified event(s) from bubbling and optionally prevents the default action
19685          * @param {String/String[]} eventName an event / array of events to stop from bubbling
19686          * @param {Boolean} preventDefault (optional) true to prevent the default action too
19687          * @return {Ext.Element} this
19688          */
19689         swallowEvent : function(eventName, preventDefault) {
19690             var me = this;
19691             function fn(e) {
19692                 e.stopPropagation();
19693                 if (preventDefault) {
19694                     e.preventDefault();
19695                 }
19696             }
19697
19698             if (Ext.isArray(eventName)) {
19699                 Ext.each(eventName, function(e) {
19700                      me.on(e, fn);
19701                 });
19702                 return me;
19703             }
19704             me.on(eventName, fn);
19705             return me;
19706         },
19707
19708         /**
19709          * Create an event handler on this element such that when the event fires and is handled by this element,
19710          * it will be relayed to another object (i.e., fired again as if it originated from that object instead).
19711          * @param {String} eventName The type of event to relay
19712          * @param {Object} object Any object that extends {@link Ext.util.Observable} that will provide the context
19713          * for firing the relayed event
19714          */
19715         relayEvent : function(eventName, observable) {
19716             this.on(eventName, function(e) {
19717                 observable.fireEvent(eventName, e);
19718             });
19719         },
19720
19721         /**
19722          * Removes Empty, or whitespace filled text nodes. Combines adjacent text nodes.
19723          * @param {Boolean} forceReclean (optional) By default the element
19724          * keeps track if it has been cleaned already so
19725          * you can call this over and over. However, if you update the element and
19726          * need to force a reclean, you can pass true.
19727          */
19728         clean : function(forceReclean) {
19729             var me  = this,
19730                 dom = me.dom,
19731                 n   = dom.firstChild,
19732                 nx,
19733                 ni  = -1;
19734     
19735             if (Ext.Element.data(dom, 'isCleaned') && forceReclean !== true) {
19736                 return me;
19737             }
19738
19739             while (n) {
19740                 nx = n.nextSibling;
19741                 if (n.nodeType == 3) {
19742                     // Remove empty/whitespace text nodes
19743                     if (!(/\S/.test(n.nodeValue))) {
19744                         dom.removeChild(n);
19745                     // Combine adjacent text nodes
19746                     } else if (nx && nx.nodeType == 3) {
19747                         n.appendData(Ext.String.trim(nx.data));
19748                         dom.removeChild(nx);
19749                         nx = n.nextSibling;
19750                         n.nodeIndex = ++ni;
19751                     }
19752                 } else {
19753                     // Recursively clean
19754                     Ext.fly(n).clean();
19755                     n.nodeIndex = ++ni;
19756                 }
19757                 n = nx;
19758             }
19759
19760             Ext.Element.data(dom, 'isCleaned', true);
19761             return me;
19762         },
19763
19764         /**
19765          * Direct access to the Ext.ElementLoader {@link Ext.ElementLoader#load} method. The method takes the same object
19766          * parameter as {@link Ext.ElementLoader#load}
19767          * @return {Ext.Element} this
19768          */
19769         load : function(options) {
19770             this.getLoader().load(options);
19771             return this;
19772         },
19773
19774         /**
19775         * Gets this element's {@link Ext.ElementLoader ElementLoader}
19776         * @return {Ext.ElementLoader} The loader
19777         */
19778         getLoader : function() {
19779             var dom = this.dom,
19780                 data = Ext.Element.data,
19781                 loader = data(dom, 'loader');
19782     
19783             if (!loader) {
19784                 loader = Ext.create('Ext.ElementLoader', {
19785                     target: this
19786                 });
19787                 data(dom, 'loader', loader);
19788             }
19789             return loader;
19790         },
19791
19792         /**
19793         * Update the innerHTML of this element, optionally searching for and processing scripts
19794         * @param {String} html The new HTML
19795         * @param {Boolean} [loadScripts=false] True to look for and process scripts
19796         * @param {Function} [callback] For async script loading you can be notified when the update completes
19797         * @return {Ext.Element} this
19798          */
19799         update : function(html, loadScripts, callback) {
19800             var me = this,
19801                 id,
19802                 dom,
19803                 interval;
19804
19805             if (!me.dom) {
19806                 return me;
19807             }
19808             html = html || '';
19809             dom = me.dom;
19810
19811             if (loadScripts !== true) {
19812                 dom.innerHTML = html;
19813                 Ext.callback(callback, me);
19814                 return me;
19815             }
19816
19817             id  = Ext.id();
19818             html += '<span id="' + id + '"></span>';
19819
19820             interval = setInterval(function(){
19821                 if (!document.getElementById(id)) {
19822                     return false;
19823                 }
19824                 clearInterval(interval);
19825                 var DOC    = document,
19826                     hd     = DOC.getElementsByTagName("head")[0],
19827                     re     = /(?:<script([^>]*)?>)((\n|\r|.)*?)(?:<\/script>)/ig,
19828                     srcRe  = /\ssrc=([\'\"])(.*?)\1/i,
19829                     typeRe = /\stype=([\'\"])(.*?)\1/i,
19830                     match,
19831                     attrs,
19832                     srcMatch,
19833                     typeMatch,
19834                     el,
19835                     s;
19836
19837                 while ((match = re.exec(html))) {
19838                     attrs = match[1];
19839                     srcMatch = attrs ? attrs.match(srcRe) : false;
19840                     if (srcMatch && srcMatch[2]) {
19841                        s = DOC.createElement("script");
19842                        s.src = srcMatch[2];
19843                        typeMatch = attrs.match(typeRe);
19844                        if (typeMatch && typeMatch[2]) {
19845                            s.type = typeMatch[2];
19846                        }
19847                        hd.appendChild(s);
19848                     } else if (match[2] && match[2].length > 0) {
19849                         if (window.execScript) {
19850                            window.execScript(match[2]);
19851                         } else {
19852                            window.eval(match[2]);
19853                         }
19854                     }
19855                 }
19856
19857                 el = DOC.getElementById(id);
19858                 if (el) {
19859                     Ext.removeNode(el);
19860                 }
19861                 Ext.callback(callback, me);
19862             }, 20);
19863             dom.innerHTML = html.replace(/(?:<script.*?>)((\n|\r|.)*?)(?:<\/script>)/ig, '');
19864             return me;
19865         },
19866
19867         // inherit docs, overridden so we can add removeAnchor
19868         removeAllListeners : function() {
19869             this.removeAnchor();
19870             Ext.EventManager.removeAll(this.dom);
19871             return this;
19872         },
19873     
19874         /**
19875          * Gets the parent node of the current element taking into account Ext.scopeResetCSS
19876          * @protected
19877          * @return {HTMLElement} The parent element
19878          */
19879         getScopeParent: function(){
19880             var parent = this.dom.parentNode;
19881             return Ext.scopeResetCSS ? parent.parentNode : parent;
19882         },
19883
19884         /**
19885          * Creates a proxy element of this element
19886          * @param {String/Object} config The class name of the proxy element or a DomHelper config object
19887          * @param {String/HTMLElement} [renderTo] The element or element id to render the proxy to (defaults to document.body)
19888          * @param {Boolean} [matchBox=false] True to align and size the proxy to this element now.
19889          * @return {Ext.Element} The new proxy element
19890          */
19891         createProxy : function(config, renderTo, matchBox) {
19892             config = (typeof config == 'object') ? config : {tag : "div", cls: config};
19893
19894             var me = this,
19895                 proxy = renderTo ? Ext.DomHelper.append(renderTo, config, true) :
19896                                    Ext.DomHelper.insertBefore(me.dom, config, true);
19897
19898             proxy.setVisibilityMode(Ext.Element.DISPLAY);
19899             proxy.hide();
19900             if (matchBox && me.setBox && me.getBox) { // check to make sure Element.position.js is loaded
19901                proxy.setBox(me.getBox());
19902             }
19903             return proxy;
19904         },
19905     
19906         /**
19907          * Checks whether this element can be focused.
19908          * @return {Boolean} True if the element is focusable
19909          */
19910         focusable: function(){
19911             var dom = this.dom,
19912                 nodeName = dom.nodeName.toLowerCase(),
19913                 canFocus = false,
19914                 hasTabIndex = !isNaN(dom.tabIndex);
19915             
19916             if (!dom.disabled) {
19917                 if (focusRe.test(nodeName)) {
19918                     canFocus = true;
19919                 } else {
19920                     canFocus = nodeName == 'a' ? dom.href || hasTabIndex : hasTabIndex;
19921                 }
19922             }
19923             return canFocus && this.isVisible(true);
19924         }    
19925     };
19926 })());
19927 Ext.Element.prototype.clearListeners = Ext.Element.prototype.removeAllListeners;
19928
19929 /**
19930  * @class Ext.Element
19931  */
19932 Ext.Element.addMethods({
19933     /**
19934      * Gets the x,y coordinates specified by the anchor position on the element.
19935      * @param {String} [anchor='c'] The specified anchor position.  See {@link #alignTo}
19936      * for details on supported anchor positions.
19937      * @param {Boolean} [local] True to get the local (element top/left-relative) anchor position instead
19938      * of page coordinates
19939      * @param {Object} [size] An object containing the size to use for calculating anchor position
19940      * {width: (target width), height: (target height)} (defaults to the element's current size)
19941      * @return {Number[]} [x, y] An array containing the element's x and y coordinates
19942      */
19943     getAnchorXY : function(anchor, local, s){
19944         //Passing a different size is useful for pre-calculating anchors,
19945         //especially for anchored animations that change the el size.
19946         anchor = (anchor || "tl").toLowerCase();
19947         s = s || {};
19948
19949         var me = this,
19950             vp = me.dom == document.body || me.dom == document,
19951             w = s.width || vp ? Ext.Element.getViewWidth() : me.getWidth(),
19952             h = s.height || vp ? Ext.Element.getViewHeight() : me.getHeight(),
19953             xy,
19954             r = Math.round,
19955             o = me.getXY(),
19956             scroll = me.getScroll(),
19957             extraX = vp ? scroll.left : !local ? o[0] : 0,
19958             extraY = vp ? scroll.top : !local ? o[1] : 0,
19959             hash = {
19960                 c  : [r(w * 0.5), r(h * 0.5)],
19961                 t  : [r(w * 0.5), 0],
19962                 l  : [0, r(h * 0.5)],
19963                 r  : [w, r(h * 0.5)],
19964                 b  : [r(w * 0.5), h],
19965                 tl : [0, 0],
19966                 bl : [0, h],
19967                 br : [w, h],
19968                 tr : [w, 0]
19969             };
19970
19971         xy = hash[anchor];
19972         return [xy[0] + extraX, xy[1] + extraY];
19973     },
19974
19975     /**
19976      * Anchors an element to another element and realigns it when the window is resized.
19977      * @param {String/HTMLElement/Ext.Element} element The element to align to.
19978      * @param {String} position The position to align to.
19979      * @param {Number[]} [offsets] Offset the positioning by [x, y]
19980      * @param {Boolean/Object} [animate] True for the default animation or a standard Element animation config object
19981      * @param {Boolean/Number} [monitorScroll] True to monitor body scroll and reposition. If this parameter
19982      * is a number, it is used as the buffer delay (defaults to 50ms).
19983      * @param {Function} [callback] The function to call after the animation finishes
19984      * @return {Ext.Element} this
19985      */
19986     anchorTo : function(el, alignment, offsets, animate, monitorScroll, callback){
19987         var me = this,
19988             dom = me.dom,
19989             scroll = !Ext.isEmpty(monitorScroll),
19990             action = function(){
19991                 Ext.fly(dom).alignTo(el, alignment, offsets, animate);
19992                 Ext.callback(callback, Ext.fly(dom));
19993             },
19994             anchor = this.getAnchor();
19995
19996         // previous listener anchor, remove it
19997         this.removeAnchor();
19998         Ext.apply(anchor, {
19999             fn: action,
20000             scroll: scroll
20001         });
20002
20003         Ext.EventManager.onWindowResize(action, null);
20004
20005         if(scroll){
20006             Ext.EventManager.on(window, 'scroll', action, null,
20007                 {buffer: !isNaN(monitorScroll) ? monitorScroll : 50});
20008         }
20009         action.call(me); // align immediately
20010         return me;
20011     },
20012
20013     /**
20014      * Remove any anchor to this element. See {@link #anchorTo}.
20015      * @return {Ext.Element} this
20016      */
20017     removeAnchor : function(){
20018         var me = this,
20019             anchor = this.getAnchor();
20020
20021         if(anchor && anchor.fn){
20022             Ext.EventManager.removeResizeListener(anchor.fn);
20023             if(anchor.scroll){
20024                 Ext.EventManager.un(window, 'scroll', anchor.fn);
20025             }
20026             delete anchor.fn;
20027         }
20028         return me;
20029     },
20030
20031     // private
20032     getAnchor : function(){
20033         var data = Ext.Element.data,
20034             dom = this.dom;
20035             if (!dom) {
20036                 return;
20037             }
20038             var anchor = data(dom, '_anchor');
20039
20040         if(!anchor){
20041             anchor = data(dom, '_anchor', {});
20042         }
20043         return anchor;
20044     },
20045
20046     getAlignVector: function(el, spec, offset) {
20047         var me = this,
20048             side = {t:"top", l:"left", r:"right", b: "bottom"},
20049             thisRegion = me.getRegion(),
20050             elRegion;
20051
20052         el = Ext.get(el);
20053         if(!el || !el.dom){
20054             Ext.Error.raise({
20055                 sourceClass: 'Ext.Element',
20056                 sourceMethod: 'getAlignVector',
20057                 msg: 'Attempted to align an element that doesn\'t exist'
20058             });
20059         }
20060
20061         elRegion = el.getRegion();
20062     },
20063
20064     /**
20065      * Gets the x,y coordinates to align this element with another element. See {@link #alignTo} for more info on the
20066      * supported position values.
20067      * @param {String/HTMLElement/Ext.Element} element The element to align to.
20068      * @param {String} [position="tl-bl?"] The position to align to (defaults to )
20069      * @param {Number[]} [offsets] Offset the positioning by [x, y]
20070      * @return {Number[]} [x, y]
20071      */
20072     getAlignToXY : function(el, p, o){
20073         el = Ext.get(el);
20074
20075         if(!el || !el.dom){
20076             Ext.Error.raise({
20077                 sourceClass: 'Ext.Element',
20078                 sourceMethod: 'getAlignToXY',
20079                 msg: 'Attempted to align an element that doesn\'t exist'
20080             });
20081         }
20082
20083         o = o || [0,0];
20084         p = (!p || p == "?" ? "tl-bl?" : (!(/-/).test(p) && p !== "" ? "tl-" + p : p || "tl-bl")).toLowerCase();
20085
20086         var me = this,
20087             d = me.dom,
20088             a1,
20089             a2,
20090             x,
20091             y,
20092             //constrain the aligned el to viewport if necessary
20093             w,
20094             h,
20095             r,
20096             dw = Ext.Element.getViewWidth() -10, // 10px of margin for ie
20097             dh = Ext.Element.getViewHeight()-10, // 10px of margin for ie
20098             p1y,
20099             p1x,
20100             p2y,
20101             p2x,
20102             swapY,
20103             swapX,
20104             doc = document,
20105             docElement = doc.documentElement,
20106             docBody = doc.body,
20107             scrollX = (docElement.scrollLeft || docBody.scrollLeft || 0)+5,
20108             scrollY = (docElement.scrollTop || docBody.scrollTop || 0)+5,
20109             c = false, //constrain to viewport
20110             p1 = "",
20111             p2 = "",
20112             m = p.match(/^([a-z]+)-([a-z]+)(\?)?$/);
20113
20114         if(!m){
20115             Ext.Error.raise({
20116                 sourceClass: 'Ext.Element',
20117                 sourceMethod: 'getAlignToXY',
20118                 el: el,
20119                 position: p,
20120                 offset: o,
20121                 msg: 'Attemmpted to align an element with an invalid position: "' + p + '"'
20122             });
20123         }
20124
20125         p1 = m[1];
20126         p2 = m[2];
20127         c = !!m[3];
20128
20129         //Subtract the aligned el's internal xy from the target's offset xy
20130         //plus custom offset to get the aligned el's new offset xy
20131         a1 = me.getAnchorXY(p1, true);
20132         a2 = el.getAnchorXY(p2, false);
20133
20134         x = a2[0] - a1[0] + o[0];
20135         y = a2[1] - a1[1] + o[1];
20136
20137         if(c){
20138            w = me.getWidth();
20139            h = me.getHeight();
20140            r = el.getRegion();
20141            //If we are at a viewport boundary and the aligned el is anchored on a target border that is
20142            //perpendicular to the vp border, allow the aligned el to slide on that border,
20143            //otherwise swap the aligned el to the opposite border of the target.
20144            p1y = p1.charAt(0);
20145            p1x = p1.charAt(p1.length-1);
20146            p2y = p2.charAt(0);
20147            p2x = p2.charAt(p2.length-1);
20148            swapY = ((p1y=="t" && p2y=="b") || (p1y=="b" && p2y=="t"));
20149            swapX = ((p1x=="r" && p2x=="l") || (p1x=="l" && p2x=="r"));
20150
20151
20152            if (x + w > dw + scrollX) {
20153                 x = swapX ? r.left-w : dw+scrollX-w;
20154            }
20155            if (x < scrollX) {
20156                x = swapX ? r.right : scrollX;
20157            }
20158            if (y + h > dh + scrollY) {
20159                 y = swapY ? r.top-h : dh+scrollY-h;
20160             }
20161            if (y < scrollY){
20162                y = swapY ? r.bottom : scrollY;
20163            }
20164         }
20165         return [x,y];
20166     },
20167
20168     /**
20169      * Aligns this element with another element relative to the specified anchor points. If the other element is the
20170      * document it aligns it to the viewport.
20171      * The position parameter is optional, and can be specified in any one of the following formats:
20172      * <ul>
20173      *   <li><b>Blank</b>: Defaults to aligning the element's top-left corner to the target's bottom-left corner ("tl-bl").</li>
20174      *   <li><b>One anchor (deprecated)</b>: The passed anchor position is used as the target element's anchor point.
20175      *       The element being aligned will position its top-left corner (tl) to that point.  <i>This method has been
20176      *       deprecated in favor of the newer two anchor syntax below</i>.</li>
20177      *   <li><b>Two anchors</b>: If two values from the table below are passed separated by a dash, the first value is used as the
20178      *       element's anchor point, and the second value is used as the target's anchor point.</li>
20179      * </ul>
20180      * In addition to the anchor points, the position parameter also supports the "?" character.  If "?" is passed at the end of
20181      * the position string, the element will attempt to align as specified, but the position will be adjusted to constrain to
20182      * the viewport if necessary.  Note that the element being aligned might be swapped to align to a different position than
20183      * that specified in order to enforce the viewport constraints.
20184      * Following are all of the supported anchor positions:
20185 <pre>
20186 Value  Description
20187 -----  -----------------------------
20188 tl     The top left corner (default)
20189 t      The center of the top edge
20190 tr     The top right corner
20191 l      The center of the left edge
20192 c      In the center of the element
20193 r      The center of the right edge
20194 bl     The bottom left corner
20195 b      The center of the bottom edge
20196 br     The bottom right corner
20197 </pre>
20198 Example Usage:
20199 <pre><code>
20200 // align el to other-el using the default positioning ("tl-bl", non-constrained)
20201 el.alignTo("other-el");
20202
20203 // align the top left corner of el with the top right corner of other-el (constrained to viewport)
20204 el.alignTo("other-el", "tr?");
20205
20206 // align the bottom right corner of el with the center left edge of other-el
20207 el.alignTo("other-el", "br-l?");
20208
20209 // align the center of el with the bottom left corner of other-el and
20210 // adjust the x position by -6 pixels (and the y position by 0)
20211 el.alignTo("other-el", "c-bl", [-6, 0]);
20212 </code></pre>
20213      * @param {String/HTMLElement/Ext.Element} element The element to align to.
20214      * @param {String} [position="tl-bl?"] The position to align to
20215      * @param {Number[]} [offsets] Offset the positioning by [x, y]
20216      * @param {Boolean/Object} [animate] true for the default animation or a standard Element animation config object
20217      * @return {Ext.Element} this
20218      */
20219     alignTo : function(element, position, offsets, animate){
20220         var me = this;
20221         return me.setXY(me.getAlignToXY(element, position, offsets),
20222                         me.anim && !!animate ? me.anim(animate) : false);
20223     },
20224
20225     // private ==>  used outside of core
20226     adjustForConstraints : function(xy, parent) {
20227         var vector = this.getConstrainVector(parent, xy);
20228         if (vector) {
20229             xy[0] += vector[0];
20230             xy[1] += vector[1];
20231         }
20232         return xy;
20233     },
20234
20235     /**
20236      * <p>Returns the <code>[X, Y]</code> vector by which this element must be translated to make a best attempt
20237      * to constrain within the passed constraint. Returns <code>false</code> is this element does not need to be moved.</p>
20238      * <p>Priority is given to constraining the top and left within the constraint.</p>
20239      * <p>The constraint may either be an existing element into which this element is to be constrained, or
20240      * an {@link Ext.util.Region Region} into which this element is to be constrained.</p>
20241      * @param constrainTo {Mixed} The Element or {@link Ext.util.Region Region} into which this element is to be constrained.
20242      * @param proposedPosition {Array} A proposed <code>[X, Y]</code> position to test for validity and to produce a vector for instead
20243      * of using this Element's current position;
20244      * @returns {Number[]/Boolean} <b>If</b> this element <i>needs</i> to be translated, an <code>[X, Y]</code>
20245      * vector by which this element must be translated. Otherwise, <code>false</code>.
20246      */
20247     getConstrainVector: function(constrainTo, proposedPosition) {
20248         if (!(constrainTo instanceof Ext.util.Region)) {
20249             constrainTo = Ext.get(constrainTo).getViewRegion();
20250         }
20251         var thisRegion = this.getRegion(),
20252             vector = [0, 0],
20253             shadowSize = this.shadow && this.shadow.offset,
20254             overflowed = false;
20255
20256         // Shift this region to occupy the proposed position
20257         if (proposedPosition) {
20258             thisRegion.translateBy(proposedPosition[0] - thisRegion.x, proposedPosition[1] - thisRegion.y);
20259         }
20260
20261         // Reduce the constrain region to allow for shadow
20262         // TODO: Rewrite the Shadow class. When that's done, get the extra for each side from the Shadow.
20263         if (shadowSize) {
20264             constrainTo.adjust(0, -shadowSize, -shadowSize, shadowSize);
20265         }
20266
20267         // Constrain the X coordinate by however much this Element overflows
20268         if (thisRegion.right > constrainTo.right) {
20269             overflowed = true;
20270             vector[0] = (constrainTo.right - thisRegion.right);    // overflowed the right
20271         }
20272         if (thisRegion.left + vector[0] < constrainTo.left) {
20273             overflowed = true;
20274             vector[0] = (constrainTo.left - thisRegion.left);      // overflowed the left
20275         }
20276
20277         // Constrain the Y coordinate by however much this Element overflows
20278         if (thisRegion.bottom > constrainTo.bottom) {
20279             overflowed = true;
20280             vector[1] = (constrainTo.bottom - thisRegion.bottom);  // overflowed the bottom
20281         }
20282         if (thisRegion.top + vector[1] < constrainTo.top) {
20283             overflowed = true;
20284             vector[1] = (constrainTo.top - thisRegion.top);        // overflowed the top
20285         }
20286         return overflowed ? vector : false;
20287     },
20288
20289     /**
20290     * Calculates the x, y to center this element on the screen
20291     * @return {Number[]} The x, y values [x, y]
20292     */
20293     getCenterXY : function(){
20294         return this.getAlignToXY(document, 'c-c');
20295     },
20296
20297     /**
20298     * Centers the Element in either the viewport, or another Element.
20299     * @param {String/HTMLElement/Ext.Element} centerIn (optional) The element in which to center the element.
20300     */
20301     center : function(centerIn){
20302         return this.alignTo(centerIn || document, 'c-c');
20303     }
20304 });
20305
20306 /**
20307  * @class Ext.Element
20308  */
20309 (function(){
20310
20311 var ELEMENT = Ext.Element,
20312     LEFT = "left",
20313     RIGHT = "right",
20314     TOP = "top",
20315     BOTTOM = "bottom",
20316     POSITION = "position",
20317     STATIC = "static",
20318     RELATIVE = "relative",
20319     AUTO = "auto",
20320     ZINDEX = "z-index";
20321
20322 Ext.override(Ext.Element, {
20323     /**
20324       * 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).
20325       * @return {Number} The X position of the element
20326       */
20327     getX : function(){
20328         return ELEMENT.getX(this.dom);
20329     },
20330
20331     /**
20332       * 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).
20333       * @return {Number} The Y position of the element
20334       */
20335     getY : function(){
20336         return ELEMENT.getY(this.dom);
20337     },
20338
20339     /**
20340       * 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).
20341       * @return {Number[]} The XY position of the element
20342       */
20343     getXY : function(){
20344         return ELEMENT.getXY(this.dom);
20345     },
20346
20347     /**
20348       * 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.
20349       * @param {String/HTMLElement/Ext.Element} element The element to get the offsets from.
20350       * @return {Number[]} The XY page offsets (e.g. [100, -200])
20351       */
20352     getOffsetsTo : function(el){
20353         var o = this.getXY(),
20354             e = Ext.fly(el, '_internal').getXY();
20355         return [o[0]-e[0],o[1]-e[1]];
20356     },
20357
20358     /**
20359      * 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).
20360      * @param {Number} The X position of the element
20361      * @param {Boolean/Object} animate (optional) True for the default animation, or a standard Element animation config object
20362      * @return {Ext.Element} this
20363      */
20364     setX : function(x, animate){
20365         return this.setXY([x, this.getY()], animate);
20366     },
20367
20368     /**
20369      * 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).
20370      * @param {Number} The Y position of the element
20371      * @param {Boolean/Object} animate (optional) True for the default animation, or a standard Element animation config object
20372      * @return {Ext.Element} this
20373      */
20374     setY : function(y, animate){
20375         return this.setXY([this.getX(), y], animate);
20376     },
20377
20378     /**
20379      * Sets the element's left position directly using CSS style (instead of {@link #setX}).
20380      * @param {String} left The left CSS property value
20381      * @return {Ext.Element} this
20382      */
20383     setLeft : function(left){
20384         this.setStyle(LEFT, this.addUnits(left));
20385         return this;
20386     },
20387
20388     /**
20389      * Sets the element's top position directly using CSS style (instead of {@link #setY}).
20390      * @param {String} top The top CSS property value
20391      * @return {Ext.Element} this
20392      */
20393     setTop : function(top){
20394         this.setStyle(TOP, this.addUnits(top));
20395         return this;
20396     },
20397
20398     /**
20399      * Sets the element's CSS right style.
20400      * @param {String} right The right CSS property value
20401      * @return {Ext.Element} this
20402      */
20403     setRight : function(right){
20404         this.setStyle(RIGHT, this.addUnits(right));
20405         return this;
20406     },
20407
20408     /**
20409      * Sets the element's CSS bottom style.
20410      * @param {String} bottom The bottom CSS property value
20411      * @return {Ext.Element} this
20412      */
20413     setBottom : function(bottom){
20414         this.setStyle(BOTTOM, this.addUnits(bottom));
20415         return this;
20416     },
20417
20418     /**
20419      * Sets the position of the element in page coordinates, regardless of how the element is positioned.
20420      * The element must be part of the DOM tree to have page coordinates (display:none or elements not appended return false).
20421      * @param {Number[]} pos Contains X & Y [x, y] values for new position (coordinates are page-based)
20422      * @param {Boolean/Object} animate (optional) True for the default animation, or a standard Element animation config object
20423      * @return {Ext.Element} this
20424      */
20425     setXY: function(pos, animate) {
20426         var me = this;
20427         if (!animate || !me.anim) {
20428             ELEMENT.setXY(me.dom, pos);
20429         }
20430         else {
20431             if (!Ext.isObject(animate)) {
20432                 animate = {};
20433             }
20434             me.animate(Ext.applyIf({ to: { x: pos[0], y: pos[1] } }, animate));
20435         }
20436         return me;
20437     },
20438
20439     /**
20440      * Sets the position of the element in page coordinates, regardless of how the element is positioned.
20441      * The element must be part of the DOM tree to have page coordinates (display:none or elements not appended return false).
20442      * @param {Number} x X value for new position (coordinates are page-based)
20443      * @param {Number} y Y value for new position (coordinates are page-based)
20444      * @param {Boolean/Object} animate (optional) True for the default animation, or a standard Element animation config object
20445      * @return {Ext.Element} this
20446      */
20447     setLocation : function(x, y, animate){
20448         return this.setXY([x, y], animate);
20449     },
20450
20451     /**
20452      * Sets the position of the element in page coordinates, regardless of how the element is positioned.
20453      * The element must be part of the DOM tree to have page coordinates (display:none or elements not appended return false).
20454      * @param {Number} x X value for new position (coordinates are page-based)
20455      * @param {Number} y Y value for new position (coordinates are page-based)
20456      * @param {Boolean/Object} animate (optional) True for the default animation, or a standard Element animation config object
20457      * @return {Ext.Element} this
20458      */
20459     moveTo : function(x, y, animate){
20460         return this.setXY([x, y], animate);
20461     },
20462
20463     /**
20464      * Gets the left X coordinate
20465      * @param {Boolean} local True to get the local css position instead of page coordinate
20466      * @return {Number}
20467      */
20468     getLeft : function(local){
20469         return !local ? this.getX() : parseInt(this.getStyle(LEFT), 10) || 0;
20470     },
20471
20472     /**
20473      * Gets the right X coordinate of the element (element X position + element width)
20474      * @param {Boolean} local True to get the local css position instead of page coordinate
20475      * @return {Number}
20476      */
20477     getRight : function(local){
20478         var me = this;
20479         return !local ? me.getX() + me.getWidth() : (me.getLeft(true) + me.getWidth()) || 0;
20480     },
20481
20482     /**
20483      * Gets the top Y coordinate
20484      * @param {Boolean} local True to get the local css position instead of page coordinate
20485      * @return {Number}
20486      */
20487     getTop : function(local) {
20488         return !local ? this.getY() : parseInt(this.getStyle(TOP), 10) || 0;
20489     },
20490
20491     /**
20492      * Gets the bottom Y coordinate of the element (element Y position + element height)
20493      * @param {Boolean} local True to get the local css position instead of page coordinate
20494      * @return {Number}
20495      */
20496     getBottom : function(local){
20497         var me = this;
20498         return !local ? me.getY() + me.getHeight() : (me.getTop(true) + me.getHeight()) || 0;
20499     },
20500
20501     /**
20502     * Initializes positioning on this element. If a desired position is not passed, it will make the
20503     * the element positioned relative IF it is not already positioned.
20504     * @param {String} pos (optional) Positioning to use "relative", "absolute" or "fixed"
20505     * @param {Number} zIndex (optional) The zIndex to apply
20506     * @param {Number} x (optional) Set the page X position
20507     * @param {Number} y (optional) Set the page Y position
20508     */
20509     position : function(pos, zIndex, x, y) {
20510         var me = this;
20511
20512         if (!pos && me.isStyle(POSITION, STATIC)){
20513             me.setStyle(POSITION, RELATIVE);
20514         } else if(pos) {
20515             me.setStyle(POSITION, pos);
20516         }
20517         if (zIndex){
20518             me.setStyle(ZINDEX, zIndex);
20519         }
20520         if (x || y) {
20521             me.setXY([x || false, y || false]);
20522         }
20523     },
20524
20525     /**
20526     * Clear positioning back to the default when the document was loaded
20527     * @param {String} value (optional) The value to use for the left,right,top,bottom, defaults to '' (empty string). You could use 'auto'.
20528     * @return {Ext.Element} this
20529      */
20530     clearPositioning : function(value){
20531         value = value || '';
20532         this.setStyle({
20533             left : value,
20534             right : value,
20535             top : value,
20536             bottom : value,
20537             "z-index" : "",
20538             position : STATIC
20539         });
20540         return this;
20541     },
20542
20543     /**
20544     * Gets an object with all CSS positioning properties. Useful along with setPostioning to get
20545     * snapshot before performing an update and then restoring the element.
20546     * @return {Object}
20547     */
20548     getPositioning : function(){
20549         var l = this.getStyle(LEFT);
20550         var t = this.getStyle(TOP);
20551         return {
20552             "position" : this.getStyle(POSITION),
20553             "left" : l,
20554             "right" : l ? "" : this.getStyle(RIGHT),
20555             "top" : t,
20556             "bottom" : t ? "" : this.getStyle(BOTTOM),
20557             "z-index" : this.getStyle(ZINDEX)
20558         };
20559     },
20560
20561     /**
20562     * Set positioning with an object returned by getPositioning().
20563     * @param {Object} posCfg
20564     * @return {Ext.Element} this
20565      */
20566     setPositioning : function(pc){
20567         var me = this,
20568             style = me.dom.style;
20569
20570         me.setStyle(pc);
20571
20572         if(pc.right == AUTO){
20573             style.right = "";
20574         }
20575         if(pc.bottom == AUTO){
20576             style.bottom = "";
20577         }
20578
20579         return me;
20580     },
20581
20582     /**
20583      * Translates the passed page coordinates into left/top css values for this element
20584      * @param {Number/Number[]} x The page x or an array containing [x, y]
20585      * @param {Number} y (optional) The page y, required if x is not an array
20586      * @return {Object} An object with left and top properties. e.g. {left: (value), top: (value)}
20587      */
20588     translatePoints: function(x, y) {
20589         if (Ext.isArray(x)) {
20590              y = x[1];
20591              x = x[0];
20592         }
20593         var me = this,
20594             relative = me.isStyle(POSITION, RELATIVE),
20595             o = me.getXY(),
20596             left = parseInt(me.getStyle(LEFT), 10),
20597             top = parseInt(me.getStyle(TOP), 10);
20598
20599         if (!Ext.isNumber(left)) {
20600             left = relative ? 0 : me.dom.offsetLeft;
20601         }
20602         if (!Ext.isNumber(top)) {
20603             top = relative ? 0 : me.dom.offsetTop;
20604         }
20605         left = (Ext.isNumber(x)) ? x - o[0] + left : undefined;
20606         top = (Ext.isNumber(y)) ? y - o[1] + top : undefined;
20607         return {
20608             left: left,
20609             top: top
20610         };
20611     },
20612
20613     /**
20614      * Sets the element's box. Use getBox() on another element to get a box obj. If animate is true then width, height, x and y will be animated concurrently.
20615      * @param {Object} box The box to fill {x, y, width, height}
20616      * @param {Boolean} adjust (optional) Whether to adjust for box-model issues automatically
20617      * @param {Boolean/Object} animate (optional) true for the default animation or a standard Element animation config object
20618      * @return {Ext.Element} this
20619      */
20620     setBox: function(box, adjust, animate) {
20621         var me = this,
20622             w = box.width,
20623             h = box.height;
20624         if ((adjust && !me.autoBoxAdjust) && !me.isBorderBox()) {
20625             w -= (me.getBorderWidth("lr") + me.getPadding("lr"));
20626             h -= (me.getBorderWidth("tb") + me.getPadding("tb"));
20627         }
20628         me.setBounds(box.x, box.y, w, h, animate);
20629         return me;
20630     },
20631
20632     /**
20633      * Return an object defining the area of this Element which can be passed to {@link #setBox} to
20634      * set another Element's size/location to match this element.
20635      * @param {Boolean} contentBox (optional) If true a box for the content of the element is returned.
20636      * @param {Boolean} local (optional) If true the element's left and top are returned instead of page x/y.
20637      * @return {Object} box An object in the format<pre><code>
20638 {
20639     x: &lt;Element's X position>,
20640     y: &lt;Element's Y position>,
20641     width: &lt;Element's width>,
20642     height: &lt;Element's height>,
20643     bottom: &lt;Element's lower bound>,
20644     right: &lt;Element's rightmost bound>
20645 }
20646 </code></pre>
20647      * The returned object may also be addressed as an Array where index 0 contains the X position
20648      * and index 1 contains the Y position. So the result may also be used for {@link #setXY}
20649      */
20650     getBox: function(contentBox, local) {
20651         var me = this,
20652             xy,
20653             left,
20654             top,
20655             getBorderWidth = me.getBorderWidth,
20656             getPadding = me.getPadding,
20657             l, r, t, b, w, h, bx;
20658         if (!local) {
20659             xy = me.getXY();
20660         } else {
20661             left = parseInt(me.getStyle("left"), 10) || 0;
20662             top = parseInt(me.getStyle("top"), 10) || 0;
20663             xy = [left, top];
20664         }
20665         w = me.getWidth();
20666         h = me.getHeight();
20667         if (!contentBox) {
20668             bx = {
20669                 x: xy[0],
20670                 y: xy[1],
20671                 0: xy[0],
20672                 1: xy[1],
20673                 width: w,
20674                 height: h
20675             };
20676         } else {
20677             l = getBorderWidth.call(me, "l") + getPadding.call(me, "l");
20678             r = getBorderWidth.call(me, "r") + getPadding.call(me, "r");
20679             t = getBorderWidth.call(me, "t") + getPadding.call(me, "t");
20680             b = getBorderWidth.call(me, "b") + getPadding.call(me, "b");
20681             bx = {
20682                 x: xy[0] + l,
20683                 y: xy[1] + t,
20684                 0: xy[0] + l,
20685                 1: xy[1] + t,
20686                 width: w - (l + r),
20687                 height: h - (t + b)
20688             };
20689         }
20690         bx.right = bx.x + bx.width;
20691         bx.bottom = bx.y + bx.height;
20692         return bx;
20693     },
20694
20695     /**
20696      * Move this element relative to its current position.
20697      * @param {String} direction Possible values are: "l" (or "left"), "r" (or "right"), "t" (or "top", or "up"), "b" (or "bottom", or "down").
20698      * @param {Number} distance How far to move the element in pixels
20699      * @param {Boolean/Object} animate (optional) true for the default animation or a standard Element animation config object
20700      */
20701     move: function(direction, distance, animate) {
20702         var me = this,
20703             xy = me.getXY(),
20704             x = xy[0],
20705             y = xy[1],
20706             left = [x - distance, y],
20707             right = [x + distance, y],
20708             top = [x, y - distance],
20709             bottom = [x, y + distance],
20710             hash = {
20711                 l: left,
20712                 left: left,
20713                 r: right,
20714                 right: right,
20715                 t: top,
20716                 top: top,
20717                 up: top,
20718                 b: bottom,
20719                 bottom: bottom,
20720                 down: bottom
20721             };
20722
20723         direction = direction.toLowerCase();
20724         me.moveTo(hash[direction][0], hash[direction][1], animate);
20725     },
20726
20727     /**
20728      * Quick set left and top adding default units
20729      * @param {String} left The left CSS property value
20730      * @param {String} top The top CSS property value
20731      * @return {Ext.Element} this
20732      */
20733     setLeftTop: function(left, top) {
20734         var me = this,
20735             style = me.dom.style;
20736         style.left = me.addUnits(left);
20737         style.top = me.addUnits(top);
20738         return me;
20739     },
20740
20741     /**
20742      * Returns the region of this element.
20743      * The element must be part of the DOM tree to have a region (display:none or elements not appended return false).
20744      * @return {Ext.util.Region} A Region containing "top, left, bottom, right" member data.
20745      */
20746     getRegion: function() {
20747         return this.getPageBox(true);
20748     },
20749
20750     /**
20751      * Returns the <b>content</b> region of this element. That is the region within the borders and padding.
20752      * @return {Ext.util.Region} A Region containing "top, left, bottom, right" member data.
20753      */
20754     getViewRegion: function() {
20755         var me = this,
20756             isBody = me.dom === document.body,
20757             scroll, pos, top, left, width, height;
20758
20759         // For the body we want to do some special logic
20760         if (isBody) {
20761             scroll = me.getScroll();
20762             left = scroll.left;
20763             top = scroll.top;
20764             width = Ext.Element.getViewportWidth();
20765             height = Ext.Element.getViewportHeight();
20766         }
20767         else {
20768             pos = me.getXY();
20769             left = pos[0] + me.getBorderWidth('l') + me.getPadding('l');
20770             top = pos[1] + me.getBorderWidth('t') + me.getPadding('t');
20771             width = me.getWidth(true);
20772             height = me.getHeight(true);
20773         }
20774
20775         return Ext.create('Ext.util.Region', top, left + width, top + height, left);
20776     },
20777
20778     /**
20779      * Return an object defining the area of this Element which can be passed to {@link #setBox} to
20780      * set another Element's size/location to match this element.
20781      * @param {Boolean} asRegion(optional) If true an Ext.util.Region will be returned
20782      * @return {Object} box An object in the format<pre><code>
20783 {
20784     x: &lt;Element's X position>,
20785     y: &lt;Element's Y position>,
20786     width: &lt;Element's width>,
20787     height: &lt;Element's height>,
20788     bottom: &lt;Element's lower bound>,
20789     right: &lt;Element's rightmost bound>
20790 }
20791 </code></pre>
20792      * The returned object may also be addressed as an Array where index 0 contains the X position
20793      * and index 1 contains the Y position. So the result may also be used for {@link #setXY}
20794      */
20795     getPageBox : function(getRegion) {
20796         var me = this,
20797             el = me.dom,
20798             isDoc = el === document.body,
20799             w = isDoc ? Ext.Element.getViewWidth()  : el.offsetWidth,
20800             h = isDoc ? Ext.Element.getViewHeight() : el.offsetHeight,
20801             xy = me.getXY(),
20802             t = xy[1],
20803             r = xy[0] + w,
20804             b = xy[1] + h,
20805             l = xy[0];
20806
20807         if (getRegion) {
20808             return Ext.create('Ext.util.Region', t, r, b, l);
20809         }
20810         else {
20811             return {
20812                 left: l,
20813                 top: t,
20814                 width: w,
20815                 height: h,
20816                 right: r,
20817                 bottom: b
20818             };
20819         }
20820     },
20821
20822     /**
20823      * Sets the element's position and size in one shot. If animation is true then width, height, x and y will be animated concurrently.
20824      * @param {Number} x X value for new position (coordinates are page-based)
20825      * @param {Number} y Y value for new position (coordinates are page-based)
20826      * @param {Number/String} width The new width. This may be one of:<div class="mdetail-params"><ul>
20827      * <li>A Number specifying the new width in this Element's {@link #defaultUnit}s (by default, pixels)</li>
20828      * <li>A String used to set the CSS width style. Animation may <b>not</b> be used.
20829      * </ul></div>
20830      * @param {Number/String} height The new height. This may be one of:<div class="mdetail-params"><ul>
20831      * <li>A Number specifying the new height in this Element's {@link #defaultUnit}s (by default, pixels)</li>
20832      * <li>A String used to set the CSS height style. Animation may <b>not</b> be used.</li>
20833      * </ul></div>
20834      * @param {Boolean/Object} animate (optional) true for the default animation or a standard Element animation config object
20835      * @return {Ext.Element} this
20836      */
20837     setBounds: function(x, y, width, height, animate) {
20838         var me = this;
20839         if (!animate || !me.anim) {
20840             me.setSize(width, height);
20841             me.setLocation(x, y);
20842         } else {
20843             if (!Ext.isObject(animate)) {
20844                 animate = {};
20845             }
20846             me.animate(Ext.applyIf({
20847                 to: {
20848                     x: x,
20849                     y: y,
20850                     width: me.adjustWidth(width),
20851                     height: me.adjustHeight(height)
20852                 }
20853             }, animate));
20854         }
20855         return me;
20856     },
20857
20858     /**
20859      * Sets the element's position and size the specified region. If animation is true then width, height, x and y will be animated concurrently.
20860      * @param {Ext.util.Region} region The region to fill
20861      * @param {Boolean/Object} animate (optional) true for the default animation or a standard Element animation config object
20862      * @return {Ext.Element} this
20863      */
20864     setRegion: function(region, animate) {
20865         return this.setBounds(region.left, region.top, region.right - region.left, region.bottom - region.top, animate);
20866     }
20867 });
20868 })();
20869
20870 /**
20871  * @class Ext.Element
20872  */
20873 Ext.override(Ext.Element, {
20874     /**
20875      * Returns true if this element is scrollable.
20876      * @return {Boolean}
20877      */
20878     isScrollable : function(){
20879         var dom = this.dom;
20880         return dom.scrollHeight > dom.clientHeight || dom.scrollWidth > dom.clientWidth;
20881     },
20882
20883     /**
20884      * Returns the current scroll position of the element.
20885      * @return {Object} An object containing the scroll position in the format {left: (scrollLeft), top: (scrollTop)}
20886      */
20887     getScroll : function() {
20888         var d = this.dom, 
20889             doc = document,
20890             body = doc.body,
20891             docElement = doc.documentElement,
20892             l,
20893             t,
20894             ret;
20895
20896         if (d == doc || d == body) {
20897             if (Ext.isIE && Ext.isStrict) {
20898                 l = docElement.scrollLeft; 
20899                 t = docElement.scrollTop;
20900             } else {
20901                 l = window.pageXOffset;
20902                 t = window.pageYOffset;
20903             }
20904             ret = {
20905                 left: l || (body ? body.scrollLeft : 0), 
20906                 top : t || (body ? body.scrollTop : 0)
20907             };
20908         } else {
20909             ret = {
20910                 left: d.scrollLeft, 
20911                 top : d.scrollTop
20912             };
20913         }
20914         
20915         return ret;
20916     },
20917     
20918     /**
20919      * 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().
20920      * @param {String} side Either "left" for scrollLeft values or "top" for scrollTop values.
20921      * @param {Number} value The new scroll value
20922      * @param {Boolean/Object} animate (optional) true for the default animation or a standard Element animation config object
20923      * @return {Ext.Element} this
20924      */
20925     scrollTo : function(side, value, animate) {
20926         //check if we're scrolling top or left
20927         var top = /top/i.test(side),
20928             me = this,
20929             dom = me.dom,
20930             obj = {},
20931             prop;
20932         if (!animate || !me.anim) {
20933             // just setting the value, so grab the direction
20934             prop = 'scroll' + (top ? 'Top' : 'Left');
20935             dom[prop] = value;
20936         }
20937         else {
20938             if (!Ext.isObject(animate)) {
20939                 animate = {};
20940             }
20941             obj['scroll' + (top ? 'Top' : 'Left')] = value;
20942             me.animate(Ext.applyIf({
20943                 to: obj
20944             }, animate));
20945         }
20946         return me;
20947     },
20948
20949     /**
20950      * Scrolls this element into view within the passed container.
20951      * @param {String/HTMLElement/Ext.Element} container (optional) The container element to scroll (defaults to document.body).  Should be a
20952      * string (id), dom node, or Ext.Element.
20953      * @param {Boolean} hscroll (optional) False to disable horizontal scroll (defaults to true)
20954      * @return {Ext.Element} this
20955      */
20956     scrollIntoView : function(container, hscroll) {
20957         container = Ext.getDom(container) || Ext.getBody().dom;
20958         var el = this.dom,
20959             offsets = this.getOffsetsTo(container),
20960             // el's box
20961             left = offsets[0] + container.scrollLeft,
20962             top = offsets[1] + container.scrollTop,
20963             bottom = top + el.offsetHeight,
20964             right = left + el.offsetWidth,
20965             // ct's box
20966             ctClientHeight = container.clientHeight,
20967             ctScrollTop = parseInt(container.scrollTop, 10),
20968             ctScrollLeft = parseInt(container.scrollLeft, 10),
20969             ctBottom = ctScrollTop + ctClientHeight,
20970             ctRight = ctScrollLeft + container.clientWidth;
20971
20972         if (el.offsetHeight > ctClientHeight || top < ctScrollTop) {
20973             container.scrollTop = top;
20974         } else if (bottom > ctBottom) {
20975             container.scrollTop = bottom - ctClientHeight;
20976         }
20977         // corrects IE, other browsers will ignore
20978         container.scrollTop = container.scrollTop;
20979
20980         if (hscroll !== false) {
20981             if (el.offsetWidth > container.clientWidth || left < ctScrollLeft) {
20982                 container.scrollLeft = left;
20983             }
20984             else if (right > ctRight) {
20985                 container.scrollLeft = right - container.clientWidth;
20986             }
20987             container.scrollLeft = container.scrollLeft;
20988         }
20989         return this;
20990     },
20991
20992     // private
20993     scrollChildIntoView : function(child, hscroll) {
20994         Ext.fly(child, '_scrollChildIntoView').scrollIntoView(this, hscroll);
20995     },
20996
20997     /**
20998      * Scrolls this element the specified direction. Does bounds checking to make sure the scroll is
20999      * within this element's scrollable range.
21000      * @param {String} direction Possible values are: "l" (or "left"), "r" (or "right"), "t" (or "top", or "up"), "b" (or "bottom", or "down").
21001      * @param {Number} distance How far to scroll the element in pixels
21002      * @param {Boolean/Object} animate (optional) true for the default animation or a standard Element animation config object
21003      * @return {Boolean} Returns true if a scroll was triggered or false if the element
21004      * was scrolled as far as it could go.
21005      */
21006      scroll : function(direction, distance, animate) {
21007         if (!this.isScrollable()) {
21008             return false;
21009         }
21010         var el = this.dom,
21011             l = el.scrollLeft, t = el.scrollTop,
21012             w = el.scrollWidth, h = el.scrollHeight,
21013             cw = el.clientWidth, ch = el.clientHeight,
21014             scrolled = false, v,
21015             hash = {
21016                 l: Math.min(l + distance, w-cw),
21017                 r: v = Math.max(l - distance, 0),
21018                 t: Math.max(t - distance, 0),
21019                 b: Math.min(t + distance, h-ch)
21020             };
21021             hash.d = hash.b;
21022             hash.u = hash.t;
21023
21024         direction = direction.substr(0, 1);
21025         if ((v = hash[direction]) > -1) {
21026             scrolled = true;
21027             this.scrollTo(direction == 'l' || direction == 'r' ? 'left' : 'top', v, this.anim(animate));
21028         }
21029         return scrolled;
21030     }
21031 });
21032 /**
21033  * @class Ext.Element
21034  */
21035 Ext.Element.addMethods(
21036     function() {
21037         var VISIBILITY      = "visibility",
21038             DISPLAY         = "display",
21039             HIDDEN          = "hidden",
21040             NONE            = "none",
21041             XMASKED         = Ext.baseCSSPrefix + "masked",
21042             XMASKEDRELATIVE = Ext.baseCSSPrefix + "masked-relative",
21043             data            = Ext.Element.data;
21044
21045         return {
21046             /**
21047              * Checks whether the element is currently visible using both visibility and display properties.
21048              * @param {Boolean} [deep=false] True to walk the dom and see if parent elements are hidden
21049              * @return {Boolean} True if the element is currently visible, else false
21050              */
21051             isVisible : function(deep) {
21052                 var vis = !this.isStyle(VISIBILITY, HIDDEN) && !this.isStyle(DISPLAY, NONE),
21053                     p   = this.dom.parentNode;
21054
21055                 if (deep !== true || !vis) {
21056                     return vis;
21057                 }
21058
21059                 while (p && !(/^body/i.test(p.tagName))) {
21060                     if (!Ext.fly(p, '_isVisible').isVisible()) {
21061                         return false;
21062                     }
21063                     p = p.parentNode;
21064                 }
21065                 return true;
21066             },
21067
21068             /**
21069              * Returns true if display is not "none"
21070              * @return {Boolean}
21071              */
21072             isDisplayed : function() {
21073                 return !this.isStyle(DISPLAY, NONE);
21074             },
21075
21076             /**
21077              * Convenience method for setVisibilityMode(Element.DISPLAY)
21078              * @param {String} display (optional) What to set display to when visible
21079              * @return {Ext.Element} this
21080              */
21081             enableDisplayMode : function(display) {
21082                 this.setVisibilityMode(Ext.Element.DISPLAY);
21083
21084                 if (!Ext.isEmpty(display)) {
21085                     data(this.dom, 'originalDisplay', display);
21086                 }
21087
21088                 return this;
21089             },
21090
21091             /**
21092              * Puts a mask over this element to disable user interaction. Requires core.css.
21093              * This method can only be applied to elements which accept child nodes.
21094              * @param {String} msg (optional) A message to display in the mask
21095              * @param {String} msgCls (optional) A css class to apply to the msg element
21096              * @return {Ext.Element} The mask element
21097              */
21098             mask : function(msg, msgCls) {
21099                 var me  = this,
21100                     dom = me.dom,
21101                     setExpression = dom.style.setExpression,
21102                     dh  = Ext.DomHelper,
21103                     EXTELMASKMSG = Ext.baseCSSPrefix + "mask-msg",
21104                     el,
21105                     mask;
21106
21107                 if (!(/^body/i.test(dom.tagName) && me.getStyle('position') == 'static')) {
21108                     me.addCls(XMASKEDRELATIVE);
21109                 }
21110                 el = data(dom, 'maskMsg');
21111                 if (el) {
21112                     el.remove();
21113                 }
21114                 el = data(dom, 'mask');
21115                 if (el) {
21116                     el.remove();
21117                 }
21118
21119                 mask = dh.append(dom, {cls : Ext.baseCSSPrefix + "mask"}, true);
21120                 data(dom, 'mask', mask);
21121
21122                 me.addCls(XMASKED);
21123                 mask.setDisplayed(true);
21124
21125                 if (typeof msg == 'string') {
21126                     var mm = dh.append(dom, {cls : EXTELMASKMSG, cn:{tag:'div'}}, true);
21127                     data(dom, 'maskMsg', mm);
21128                     mm.dom.className = msgCls ? EXTELMASKMSG + " " + msgCls : EXTELMASKMSG;
21129                     mm.dom.firstChild.innerHTML = msg;
21130                     mm.setDisplayed(true);
21131                     mm.center(me);
21132                 }
21133                 // NOTE: CSS expressions are resource intensive and to be used only as a last resort
21134                 // These expressions are removed as soon as they are no longer necessary - in the unmask method.
21135                 // In normal use cases an element will be masked for a limited period of time.
21136                 // Fix for https://sencha.jira.com/browse/EXTJSIV-19.
21137                 // IE6 strict mode and IE6-9 quirks mode takes off left+right padding when calculating width!
21138                 if (!Ext.supports.IncludePaddingInWidthCalculation && setExpression) {
21139                     mask.dom.style.setExpression('width', 'this.parentNode.offsetWidth + "px"');
21140                 }
21141
21142                 // Some versions and modes of IE subtract top+bottom padding when calculating height.
21143                 // Different versions from those which make the same error for width!
21144                 if (!Ext.supports.IncludePaddingInHeightCalculation && setExpression) {
21145                     mask.dom.style.setExpression('height', 'this.parentNode.offsetHeight + "px"');
21146                 }
21147                 // ie will not expand full height automatically
21148                 else if (Ext.isIE && !(Ext.isIE7 && Ext.isStrict) && me.getStyle('height') == 'auto') {
21149                     mask.setSize(undefined, me.getHeight());
21150                 }
21151                 return mask;
21152             },
21153
21154             /**
21155              * Removes a previously applied mask.
21156              */
21157             unmask : function() {
21158                 var me      = this,
21159                     dom     = me.dom,
21160                     mask    = data(dom, 'mask'),
21161                     maskMsg = data(dom, 'maskMsg');
21162
21163                 if (mask) {
21164                     // Remove resource-intensive CSS expressions as soon as they are not required.
21165                     if (mask.dom.style.clearExpression) {
21166                         mask.dom.style.clearExpression('width');
21167                         mask.dom.style.clearExpression('height');
21168                     }
21169                     if (maskMsg) {
21170                         maskMsg.remove();
21171                         data(dom, 'maskMsg', undefined);
21172                     }
21173
21174                     mask.remove();
21175                     data(dom, 'mask', undefined);
21176                     me.removeCls([XMASKED, XMASKEDRELATIVE]);
21177                 }
21178             },
21179             /**
21180              * Returns true if this element is masked. Also re-centers any displayed message within the mask.
21181              * @return {Boolean}
21182              */
21183             isMasked : function() {
21184                 var me = this,
21185                     mask = data(me.dom, 'mask'),
21186                     maskMsg = data(me.dom, 'maskMsg');
21187
21188                 if (mask && mask.isVisible()) {
21189                     if (maskMsg) {
21190                         maskMsg.center(me);
21191                     }
21192                     return true;
21193                 }
21194                 return false;
21195             },
21196
21197             /**
21198              * Creates an iframe shim for this element to keep selects and other windowed objects from
21199              * showing through.
21200              * @return {Ext.Element} The new shim element
21201              */
21202             createShim : function() {
21203                 var el = document.createElement('iframe'),
21204                     shim;
21205
21206                 el.frameBorder = '0';
21207                 el.className = Ext.baseCSSPrefix + 'shim';
21208                 el.src = Ext.SSL_SECURE_URL;
21209                 shim = Ext.get(this.dom.parentNode.insertBefore(el, this.dom));
21210                 shim.autoBoxAdjust = false;
21211                 return shim;
21212             }
21213         };
21214     }()
21215 );
21216 /**
21217  * @class Ext.Element
21218  */
21219 Ext.Element.addMethods({
21220     /**
21221      * Convenience method for constructing a KeyMap
21222      * @param {String/Number/Number[]/Object} key Either a string with the keys to listen for, the numeric key code, array of key codes or an object with the following options:
21223      * <code>{key: (number or array), shift: (true/false), ctrl: (true/false), alt: (true/false)}</code>
21224      * @param {Function} fn The function to call
21225      * @param {Object} scope (optional) The scope (<code>this</code> reference) in which the specified function is executed. Defaults to this Element.
21226      * @return {Ext.util.KeyMap} The KeyMap created
21227      */
21228     addKeyListener : function(key, fn, scope){
21229         var config;
21230         if(typeof key != 'object' || Ext.isArray(key)){
21231             config = {
21232                 key: key,
21233                 fn: fn,
21234                 scope: scope
21235             };
21236         }else{
21237             config = {
21238                 key : key.key,
21239                 shift : key.shift,
21240                 ctrl : key.ctrl,
21241                 alt : key.alt,
21242                 fn: fn,
21243                 scope: scope
21244             };
21245         }
21246         return Ext.create('Ext.util.KeyMap', this, config);
21247     },
21248
21249     /**
21250      * Creates a KeyMap for this element
21251      * @param {Object} config The KeyMap config. See {@link Ext.util.KeyMap} for more details
21252      * @return {Ext.util.KeyMap} The KeyMap created
21253      */
21254     addKeyMap : function(config){
21255         return Ext.create('Ext.util.KeyMap', this, config);
21256     }
21257 });
21258
21259 //Import the newly-added Ext.Element functions into CompositeElementLite. We call this here because
21260 //Element.keys.js is the last extra Ext.Element include in the ext-all.js build
21261 Ext.CompositeElementLite.importElementMethods();
21262
21263 /**
21264  * @class Ext.CompositeElementLite
21265  */
21266 Ext.apply(Ext.CompositeElementLite.prototype, {
21267     addElements : function(els, root){
21268         if(!els){
21269             return this;
21270         }
21271         if(typeof els == "string"){
21272             els = Ext.Element.selectorFunction(els, root);
21273         }
21274         var yels = this.elements;
21275         Ext.each(els, function(e) {
21276             yels.push(Ext.get(e));
21277         });
21278         return this;
21279     },
21280
21281     /**
21282      * Returns the first Element
21283      * @return {Ext.Element}
21284      */
21285     first : function(){
21286         return this.item(0);
21287     },
21288
21289     /**
21290      * Returns the last Element
21291      * @return {Ext.Element}
21292      */
21293     last : function(){
21294         return this.item(this.getCount()-1);
21295     },
21296
21297     /**
21298      * Returns true if this composite contains the passed element
21299      * @param el {String/HTMLElement/Ext.Element/Number} The id of an element, or an Ext.Element, or an HtmlElement to find within the composite collection.
21300      * @return Boolean
21301      */
21302     contains : function(el){
21303         return this.indexOf(el) != -1;
21304     },
21305
21306     /**
21307     * Removes the specified element(s).
21308     * @param {String/HTMLElement/Ext.Element/Number} el The id of an element, the Element itself, the index of the element in this composite
21309     * or an array of any of those.
21310     * @param {Boolean} removeDom (optional) True to also remove the element from the document
21311     * @return {Ext.CompositeElement} this
21312     */
21313     removeElement : function(keys, removeDom){
21314         var me = this,
21315             els = this.elements,
21316             el;
21317         Ext.each(keys, function(val){
21318             if ((el = (els[val] || els[val = me.indexOf(val)]))) {
21319                 if(removeDom){
21320                     if(el.dom){
21321                         el.remove();
21322                     }else{
21323                         Ext.removeNode(el);
21324                     }
21325                 }
21326                 Ext.Array.erase(els, val, 1);
21327             }
21328         });
21329         return this;
21330     }
21331 });
21332
21333 /**
21334  * @class Ext.CompositeElement
21335  * @extends Ext.CompositeElementLite
21336  * <p>This class encapsulates a <i>collection</i> of DOM elements, providing methods to filter
21337  * members, or to perform collective actions upon the whole set.</p>
21338  * <p>Although they are not listed, this class supports all of the methods of {@link Ext.Element} and
21339  * {@link Ext.fx.Anim}. The methods from these classes will be performed on all the elements in this collection.</p>
21340  * <p>All methods return <i>this</i> and can be chained.</p>
21341  * Usage:
21342 <pre><code>
21343 var els = Ext.select("#some-el div.some-class", true);
21344 // or select directly from an existing element
21345 var el = Ext.get('some-el');
21346 el.select('div.some-class', true);
21347
21348 els.setWidth(100); // all elements become 100 width
21349 els.hide(true); // all elements fade out and hide
21350 // or
21351 els.setWidth(100).hide(true);
21352 </code></pre>
21353  */
21354 Ext.CompositeElement = Ext.extend(Ext.CompositeElementLite, {
21355
21356     constructor : function(els, root){
21357         this.elements = [];
21358         this.add(els, root);
21359     },
21360
21361     // private
21362     getElement : function(el){
21363         // In this case just return it, since we already have a reference to it
21364         return el;
21365     },
21366
21367     // private
21368     transformElement : function(el){
21369         return Ext.get(el);
21370     }
21371 });
21372
21373 /**
21374  * Selects elements based on the passed CSS selector to enable {@link Ext.Element Element} methods
21375  * to be applied to many related elements in one statement through the returned {@link Ext.CompositeElement CompositeElement} or
21376  * {@link Ext.CompositeElementLite CompositeElementLite} object.
21377  * @param {String/HTMLElement[]} selector The CSS selector or an array of elements
21378  * @param {Boolean} [unique] true to create a unique Ext.Element for each element (defaults to a shared flyweight object)
21379  * @param {HTMLElement/String} [root] The root element of the query or id of the root
21380  * @return {Ext.CompositeElementLite/Ext.CompositeElement}
21381  * @member Ext.Element
21382  * @method select
21383  */
21384 Ext.Element.select = function(selector, unique, root){
21385     var els;
21386     if(typeof selector == "string"){
21387         els = Ext.Element.selectorFunction(selector, root);
21388     }else if(selector.length !== undefined){
21389         els = selector;
21390     }else{
21391         Ext.Error.raise({
21392             sourceClass: "Ext.Element",
21393             sourceMethod: "select",
21394             selector: selector,
21395             unique: unique,
21396             root: root,
21397             msg: "Invalid selector specified: " + selector
21398         });
21399     }
21400     return (unique === true) ? new Ext.CompositeElement(els) : new Ext.CompositeElementLite(els);
21401 };
21402
21403 /**
21404  * Shorthand of {@link Ext.Element#select}.
21405  * @member Ext
21406  * @method select
21407  * @alias Ext.Element#select
21408  */
21409 Ext.select = Ext.Element.select;
21410
21411
21412 /*
21413
21414 This file is part of Ext JS 4
21415
21416 Copyright (c) 2011 Sencha Inc
21417
21418 Contact:  http://www.sencha.com/contact
21419
21420 GNU General Public License Usage
21421 This file may be used under the terms of the GNU General Public License version 3.0 as published by the Free Software Foundation and appearing in the file LICENSE included in the packaging of this file.  Please review the following information to ensure the GNU General Public License version 3.0 requirements will be met: http://www.gnu.org/copyleft/gpl.html.
21422
21423 If you are unsure which license is appropriate for your use, please contact the sales department at http://www.sencha.com/contact.
21424
21425 */
21426 (function(){ var data = {
21427     "nameToAliasesMap":{
21428         "Ext.AbstractComponent":[""
21429         ],
21430         "Ext.AbstractManager":[""
21431         ],
21432         "Ext.AbstractPlugin":[""
21433         ],
21434         "Ext.Ajax":[""
21435         ],
21436         "Ext.ComponentLoader":[""
21437         ],
21438         "Ext.ComponentManager":[""
21439         ],
21440         "Ext.ComponentQuery":[""
21441         ],
21442         "Ext.ElementLoader":[""
21443         ],
21444         "Ext.ModelManager":[""
21445         ],
21446         "Ext.PluginManager":[""
21447         ],
21448         "Ext.Template":[""
21449         ],
21450         "Ext.XTemplate":[""
21451         ],
21452         "Ext.app.Application":[""
21453         ],
21454         "Ext.app.Controller":[""
21455         ],
21456         "Ext.app.EventBus":[""
21457         ],
21458         "Ext.chart.Callout":[""
21459         ],
21460         "Ext.chart.Chart":["widget.chart"
21461         ],
21462         "Ext.chart.Highlight":[""
21463         ],
21464         "Ext.chart.Label":[""
21465         ],
21466         "Ext.chart.Legend":[""
21467         ],
21468         "Ext.chart.LegendItem":[""
21469         ],
21470         "Ext.chart.Mask":[""
21471         ],
21472         "Ext.chart.MaskLayer":[""
21473         ],
21474         "Ext.chart.Navigation":[""
21475         ],
21476         "Ext.chart.Shape":[""
21477         ],
21478         "Ext.chart.Tip":[""
21479         ],
21480         "Ext.chart.TipSurface":[""
21481         ],
21482         "Ext.chart.axis.Abstract":[""
21483         ],
21484         "Ext.chart.axis.Axis":[""
21485         ],
21486         "Ext.chart.axis.Category":["axis.category"
21487         ],
21488         "Ext.chart.axis.Gauge":["axis.gauge"
21489         ],
21490         "Ext.chart.axis.Numeric":["axis.numeric"
21491         ],
21492         "Ext.chart.axis.Radial":["axis.radial"
21493         ],
21494         "Ext.chart.axis.Time":["axis.time"
21495         ],
21496         "Ext.chart.series.Area":["series.area"
21497         ],
21498         "Ext.chart.series.Bar":["series.bar"
21499         ],
21500         "Ext.chart.series.Cartesian":[""
21501         ],
21502         "Ext.chart.series.Column":["series.column"
21503         ],
21504         "Ext.chart.series.Gauge":["series.gauge"
21505         ],
21506         "Ext.chart.series.Line":["series.line"
21507         ],
21508         "Ext.chart.series.Pie":["series.pie"
21509         ],
21510         "Ext.chart.series.Radar":["series.radar"
21511         ],
21512         "Ext.chart.series.Scatter":["series.scatter"
21513         ],
21514         "Ext.chart.series.Series":[""
21515         ],
21516         "Ext.chart.theme.Base":[""
21517         ],
21518         "Ext.chart.theme.Theme":[""
21519         ],
21520         "Ext.container.AbstractContainer":[""
21521         ],
21522         "Ext.data.AbstractStore":[""
21523         ],
21524         "Ext.data.ArrayStore":["store.array"
21525         ],
21526         "Ext.data.Association":[""
21527         ],
21528         "Ext.data.Batch":[""
21529         ],
21530         "Ext.data.BelongsToAssociation":["association.belongsto"
21531         ],
21532         "Ext.data.BufferStore":["store.buffer"
21533         ],
21534         "Ext.data.Connection":[""
21535         ],
21536         "Ext.data.DirectStore":["store.direct"
21537         ],
21538         "Ext.data.Errors":[""
21539         ],
21540         "Ext.data.Field":["data.field"
21541         ],
21542         "Ext.data.HasManyAssociation":["association.hasmany"
21543         ],
21544         "Ext.data.IdGenerator":[""
21545         ],
21546         "Ext.data.JsonP":[""
21547         ],
21548         "Ext.data.JsonPStore":["store.jsonp"
21549         ],
21550         "Ext.data.JsonStore":["store.json"
21551         ],
21552         "Ext.data.Model":[""
21553         ],
21554         "Ext.data.NodeInterface":[""
21555         ],
21556         "Ext.data.NodeStore":["store.node"
21557         ],
21558         "Ext.data.Operation":[""
21559         ],
21560         "Ext.data.Request":[""
21561         ],
21562         "Ext.data.ResultSet":[""
21563         ],
21564         "Ext.data.SequentialIdGenerator":["idgen.sequential"
21565         ],
21566         "Ext.data.SortTypes":[""
21567         ],
21568         "Ext.data.Store":["store.store"
21569         ],
21570         "Ext.data.StoreManager":[""
21571         ],
21572         "Ext.data.Tree":["data.tree"
21573         ],
21574         "Ext.data.TreeStore":["store.tree"
21575         ],
21576         "Ext.data.Types":[""
21577         ],
21578         "Ext.data.UuidGenerator":[""
21579         ],
21580         "Ext.data.validations":[""
21581         ],
21582         "Ext.data.XmlStore":["store.xml"
21583         ],
21584         "Ext.data.proxy.Ajax":["proxy.ajax"
21585         ],
21586         "Ext.data.proxy.Client":[""
21587         ],
21588         "Ext.data.proxy.Direct":["proxy.direct"
21589         ],
21590         "Ext.data.proxy.JsonP":["proxy.jsonp",
21591             "proxy.scripttag"
21592         ],
21593         "Ext.data.proxy.LocalStorage":["proxy.localstorage"
21594         ],
21595         "Ext.data.proxy.Memory":["proxy.memory"
21596         ],
21597         "Ext.data.proxy.Proxy":["proxy.proxy"
21598         ],
21599         "Ext.data.proxy.Rest":["proxy.rest"
21600         ],
21601         "Ext.data.proxy.Server":["proxy.server"
21602         ],
21603         "Ext.data.proxy.SessionStorage":["proxy.sessionstorage"
21604         ],
21605         "Ext.data.proxy.WebStorage":[""
21606         ],
21607         "Ext.data.reader.Array":["reader.array"
21608         ],
21609         "Ext.data.reader.Json":["reader.json"
21610         ],
21611         "Ext.data.reader.Reader":[""
21612         ],
21613         "Ext.data.reader.Xml":["reader.xml"
21614         ],
21615         "Ext.data.writer.Json":["writer.json"
21616         ],
21617         "Ext.data.writer.Writer":["writer.base"
21618         ],
21619         "Ext.data.writer.Xml":["writer.xml"
21620         ],
21621         "Ext.direct.Event":["direct.event"
21622         ],
21623         "Ext.direct.ExceptionEvent":["direct.exception"
21624         ],
21625         "Ext.direct.JsonProvider":["direct.jsonprovider"
21626         ],
21627         "Ext.direct.Manager":[""
21628         ],
21629         "Ext.direct.PollingProvider":["direct.pollingprovider"
21630         ],
21631         "Ext.direct.Provider":["direct.provider"
21632         ],
21633         "Ext.direct.RemotingEvent":["direct.rpc"
21634         ],
21635         "Ext.direct.RemotingMethod":[""
21636         ],
21637         "Ext.direct.RemotingProvider":["direct.remotingprovider"
21638         ],
21639         "Ext.direct.Transaction":["direct.transaction"
21640         ],
21641         "Ext.draw.Color":[""
21642         ],
21643         "Ext.draw.Component":["widget.draw"
21644         ],
21645         "Ext.draw.CompositeSprite":[""
21646         ],
21647         "Ext.draw.Draw":[""
21648         ],
21649         "Ext.draw.Matrix":[""
21650         ],
21651         "Ext.draw.Sprite":[""
21652         ],
21653         "Ext.draw.SpriteDD":[""
21654         ],
21655         "Ext.draw.Surface":[""
21656         ],
21657         "Ext.draw.engine.Svg":[""
21658         ],
21659         "Ext.draw.engine.Vml":[""
21660         ],
21661         "Ext.fx.Anim":[""
21662         ],
21663         "Ext.fx.Animator":[""
21664         ],
21665         "Ext.fx.CubicBezier":[""
21666         ],
21667         "Ext.fx.Easing":[],
21668         "Ext.fx.Manager":[""
21669         ],
21670         "Ext.fx.PropertyHandler":[""
21671         ],
21672         "Ext.fx.Queue":[""
21673         ],
21674         "Ext.fx.target.Component":[""
21675         ],
21676         "Ext.fx.target.CompositeElement":[""
21677         ],
21678         "Ext.fx.target.CompositeElementCSS":[""
21679         ],
21680         "Ext.fx.target.CompositeSprite":[""
21681         ],
21682         "Ext.fx.target.Element":[""
21683         ],
21684         "Ext.fx.target.ElementCSS":[""
21685         ],
21686         "Ext.fx.target.Sprite":[""
21687         ],
21688         "Ext.fx.target.Target":[""
21689         ],
21690         "Ext.layout.Layout":[""
21691         ],
21692         "Ext.layout.component.AbstractDock":[""
21693         ],
21694         "Ext.layout.component.Auto":["layout.autocomponent"
21695         ],
21696         "Ext.layout.component.Component":[""
21697         ],
21698         "Ext.layout.component.Draw":["layout.draw"
21699         ],
21700         "Ext.layout.container.AbstractCard":[""
21701         ],
21702         "Ext.layout.container.AbstractContainer":[""
21703         ],
21704         "Ext.layout.container.AbstractFit":[""
21705         ],
21706         "Ext.layout.container.Auto":["layout.auto",
21707             "layout.autocontainer"
21708         ],
21709         "Ext.panel.AbstractPanel":[""
21710         ],
21711         "Ext.selection.DataViewModel":[""
21712         ],
21713         "Ext.selection.Model":[""
21714         ],
21715         "Ext.state.CookieProvider":[""
21716         ],
21717         "Ext.state.LocalStorageProvider":["state.localstorage"
21718         ],
21719         "Ext.state.Manager":[""
21720         ],
21721         "Ext.state.Provider":[""
21722         ],
21723         "Ext.state.Stateful":[""
21724         ],
21725         "Ext.util.AbstractMixedCollection":[""
21726         ],
21727         "Ext.util.Filter":[""
21728         ],
21729         "Ext.util.Grouper":[""
21730         ],
21731         "Ext.util.HashMap":[""
21732         ],
21733         "Ext.util.Inflector":[""
21734         ],
21735         "Ext.util.Memento":[""
21736         ],
21737         "Ext.util.MixedCollection":[""
21738         ],
21739         "Ext.util.Observable":[""
21740         ],
21741         "Ext.util.Offset":[""
21742         ],
21743         "Ext.util.Point":[""
21744         ],
21745         "Ext.util.Region":[""
21746         ],
21747         "Ext.util.Sortable":[""
21748         ],
21749         "Ext.util.Sorter":[""
21750         ],
21751         "Ext.view.AbstractView":[""
21752         ],
21753         "Ext.Action":[""
21754         ],
21755         "Ext.Component":["widget.component",
21756             "widget.box"
21757         ],
21758         "Ext.Editor":["widget.editor"
21759         ],
21760         "Ext.FocusManager":[""
21761         ],
21762         "Ext.Img":["widget.image",
21763             "widget.imagecomponent"
21764         ],
21765         "Ext.Layer":[""
21766         ],
21767         "Ext.LoadMask":["widget.loadmask"
21768         ],
21769         "Ext.ProgressBar":["widget.progressbar"
21770         ],
21771         "Ext.Shadow":[""
21772         ],
21773         "Ext.ShadowPool":[""
21774         ],
21775         "Ext.ZIndexManager":[""
21776         ],
21777         "Ext.button.Button":["widget.button"
21778         ],
21779         "Ext.button.Cycle":["widget.cycle"
21780         ],
21781         "Ext.button.Split":["widget.splitbutton"
21782         ],
21783         "Ext.container.ButtonGroup":["widget.buttongroup"
21784         ],
21785         "Ext.container.Container":["widget.container"
21786         ],
21787         "Ext.container.Viewport":["widget.viewport"
21788         ],
21789         "Ext.dd.DD":[""
21790         ],
21791         "Ext.dd.DDProxy":[""
21792         ],
21793         "Ext.dd.DDTarget":[""
21794         ],
21795         "Ext.dd.DragDrop":[""
21796         ],
21797         "Ext.dd.DragDropManager":[""
21798         ],
21799         "Ext.dd.DragSource":[""
21800         ],
21801         "Ext.dd.DragTracker":[""
21802         ],
21803         "Ext.dd.DragZone":[""
21804         ],
21805         "Ext.dd.DropTarget":[""
21806         ],
21807         "Ext.dd.DropZone":[""
21808         ],
21809         "Ext.dd.Registry":[""
21810         ],
21811         "Ext.dd.ScrollManager":[""
21812         ],
21813         "Ext.dd.StatusProxy":[""
21814         ],
21815         "Ext.flash.Component":["widget.flash"
21816         ],
21817         "Ext.form.Basic":[""
21818         ],
21819         "Ext.form.CheckboxGroup":["widget.checkboxgroup"
21820         ],
21821         "Ext.form.CheckboxManager":[""
21822         ],
21823         "Ext.form.FieldAncestor":[""
21824         ],
21825         "Ext.form.FieldContainer":["widget.fieldcontainer"
21826         ],
21827         "Ext.form.FieldSet":["widget.fieldset"
21828         ],
21829         "Ext.form.Label":["widget.label"
21830         ],
21831         "Ext.form.Labelable":[""
21832         ],
21833         "Ext.form.Panel":["widget.form"
21834         ],
21835         "Ext.form.RadioGroup":["widget.radiogroup"
21836         ],
21837         "Ext.form.RadioManager":[""
21838         ],
21839         "Ext.form.action.Action":[""
21840         ],
21841         "Ext.form.action.DirectLoad":["formaction.directload"
21842         ],
21843         "Ext.form.action.DirectSubmit":["formaction.directsubmit"
21844         ],
21845         "Ext.form.action.Load":["formaction.load"
21846         ],
21847         "Ext.form.action.StandardSubmit":["formaction.standardsubmit"
21848         ],
21849         "Ext.form.action.Submit":["formaction.submit"
21850         ],
21851         "Ext.form.field.Base":["widget.field"
21852         ],
21853         "Ext.form.field.Checkbox":["widget.checkboxfield",
21854             "widget.checkbox"
21855         ],
21856         "Ext.form.field.ComboBox":["widget.combobox",
21857             "widget.combo"
21858         ],
21859         "Ext.form.field.Date":["widget.datefield"
21860         ],
21861         "Ext.form.field.Display":["widget.displayfield"
21862         ],
21863         "Ext.form.field.Field":[""
21864         ],
21865         "Ext.form.field.File":["widget.filefield",
21866             "widget.fileuploadfield"
21867         ],
21868         "Ext.form.field.Hidden":["widget.hiddenfield",
21869             "widget.hidden"
21870         ],
21871         "Ext.form.field.HtmlEditor":["widget.htmleditor"
21872         ],
21873         "Ext.form.field.Number":["widget.numberfield"
21874         ],
21875         "Ext.form.field.Picker":["widget.pickerfield"
21876         ],
21877         "Ext.form.field.Radio":["widget.radiofield",
21878             "widget.radio"
21879         ],
21880         "Ext.form.field.Spinner":["widget.spinnerfield"
21881         ],
21882         "Ext.form.field.Text":["widget.textfield"
21883         ],
21884         "Ext.form.field.TextArea":["widget.textareafield",
21885             "widget.textarea"
21886         ],
21887         "Ext.form.field.Time":["widget.timefield"
21888         ],
21889         "Ext.form.field.Trigger":["widget.triggerfield",
21890             "widget.trigger"
21891         ],
21892         "Ext.form.field.VTypes":[""
21893         ],
21894         "Ext.grid.CellEditor":[""
21895         ],
21896         "Ext.grid.ColumnLayout":["layout.gridcolumn"
21897         ],
21898         "Ext.grid.Lockable":[""
21899         ],
21900         "Ext.grid.LockingView":[""
21901         ],
21902         "Ext.grid.PagingScroller":["widget.paginggridscroller"
21903         ],
21904         "Ext.grid.Panel":["widget.gridpanel",
21905             "widget.grid"
21906         ],
21907         "Ext.grid.RowEditor":[""
21908         ],
21909         "Ext.grid.RowNumberer":["widget.rownumberer"
21910         ],
21911         "Ext.grid.Scroller":["widget.gridscroller"
21912         ],
21913         "Ext.grid.View":["widget.gridview"
21914         ],
21915         "Ext.grid.ViewDropZone":[""
21916         ],
21917         "Ext.grid.column.Action":["widget.actioncolumn"
21918         ],
21919         "Ext.grid.column.Boolean":["widget.booleancolumn"
21920         ],
21921         "Ext.grid.column.Column":["widget.gridcolumn"
21922         ],
21923         "Ext.grid.column.Date":["widget.datecolumn"
21924         ],
21925         "Ext.grid.column.Number":["widget.numbercolumn"
21926         ],
21927         "Ext.grid.column.Template":["widget.templatecolumn"
21928         ],
21929         "Ext.grid.feature.AbstractSummary":["feature.abstractsummary"
21930         ],
21931         "Ext.grid.feature.Chunking":["feature.chunking"
21932         ],
21933         "Ext.grid.feature.Feature":["feature.feature"
21934         ],
21935         "Ext.grid.feature.Grouping":["feature.grouping"
21936         ],
21937         "Ext.grid.feature.GroupingSummary":["feature.groupingsummary"
21938         ],
21939         "Ext.grid.feature.RowBody":["feature.rowbody"
21940         ],
21941         "Ext.grid.feature.RowWrap":["feature.rowwrap"
21942         ],
21943         "Ext.grid.feature.Summary":["feature.summary"
21944         ],
21945         "Ext.grid.header.Container":["widget.headercontainer"
21946         ],
21947         "Ext.grid.header.DragZone":[""
21948         ],
21949         "Ext.grid.header.DropZone":[""
21950         ],
21951         "Ext.grid.plugin.CellEditing":["plugin.cellediting"
21952         ],
21953         "Ext.grid.plugin.DragDrop":["plugin.gridviewdragdrop"
21954         ],
21955         "Ext.grid.plugin.Editing":["editing.editing"
21956         ],
21957         "Ext.grid.plugin.HeaderReorderer":["plugin.gridheaderreorderer"
21958         ],
21959         "Ext.grid.plugin.HeaderResizer":["plugin.gridheaderresizer"
21960         ],
21961         "Ext.grid.plugin.RowEditing":["plugin.rowediting"
21962         ],
21963         "Ext.grid.property.Grid":["widget.propertygrid"
21964         ],
21965         "Ext.grid.property.HeaderContainer":[""
21966         ],
21967         "Ext.grid.property.Property":[""
21968         ],
21969         "Ext.grid.property.Store":[""
21970         ],
21971         "Ext.layout.component.Body":["layout.body"
21972         ],
21973         "Ext.layout.component.BoundList":["layout.boundlist"
21974         ],
21975         "Ext.layout.component.Button":["layout.button"
21976         ],
21977         "Ext.layout.component.Dock":["layout.dock"
21978         ],
21979         "Ext.layout.component.Editor":["layout.editor"
21980         ],
21981         "Ext.layout.component.FieldSet":["layout.fieldset"
21982         ],
21983         "Ext.layout.component.ProgressBar":["layout.progressbar"
21984         ],
21985         "Ext.layout.component.Tab":["layout.tab"
21986         ],
21987         "Ext.layout.component.Tip":["layout.tip"
21988         ],
21989         "Ext.layout.component.field.Field":["layout.field"
21990         ],
21991         "Ext.layout.component.field.File":["layout.filefield"
21992         ],
21993         "Ext.layout.component.field.HtmlEditor":["layout.htmleditor"
21994         ],
21995         "Ext.layout.component.field.Slider":["layout.sliderfield"
21996         ],
21997         "Ext.layout.component.field.Text":["layout.textfield"
21998         ],
21999         "Ext.layout.component.field.TextArea":["layout.textareafield"
22000         ],
22001         "Ext.layout.component.field.Trigger":["layout.triggerfield"
22002         ],
22003         "Ext.layout.container.Absolute":["layout.absolute"
22004         ],
22005         "Ext.layout.container.Accordion":["layout.accordion"
22006         ],
22007         "Ext.layout.container.Anchor":["layout.anchor"
22008         ],
22009         "Ext.layout.container.Border":["layout.border"
22010         ],
22011         "Ext.layout.container.Box":["layout.box"
22012         ],
22013         "Ext.layout.container.Card":["layout.card"
22014         ],
22015         "Ext.layout.container.CheckboxGroup":["layout.checkboxgroup"
22016         ],
22017         "Ext.layout.container.Column":["layout.column"
22018         ],
22019         "Ext.layout.container.Container":[""
22020         ],
22021         "Ext.layout.container.Fit":["layout.fit"
22022         ],
22023         "Ext.layout.container.HBox":["layout.hbox"
22024         ],
22025         "Ext.layout.container.Table":["layout.table"
22026         ],
22027         "Ext.layout.container.VBox":["layout.vbox"
22028         ],
22029         "Ext.layout.container.boxOverflow.Menu":[""
22030         ],
22031         "Ext.layout.container.boxOverflow.None":[""
22032         ],
22033         "Ext.layout.container.boxOverflow.Scroller":[""
22034         ],
22035         "Ext.menu.CheckItem":["widget.menucheckitem"
22036         ],
22037         "Ext.menu.ColorPicker":["widget.colormenu"
22038         ],
22039         "Ext.menu.DatePicker":["widget.datemenu"
22040         ],
22041         "Ext.menu.Item":["widget.menuitem"
22042         ],
22043         "Ext.menu.KeyNav":[""
22044         ],
22045         "Ext.menu.Manager":[""
22046         ],
22047         "Ext.menu.Menu":["widget.menu"
22048         ],
22049         "Ext.menu.Separator":["widget.menuseparator"
22050         ],
22051         "Ext.panel.DD":[""
22052         ],
22053         "Ext.panel.Header":["widget.header"
22054         ],
22055         "Ext.panel.Panel":["widget.panel"
22056         ],
22057         "Ext.panel.Proxy":[""
22058         ],
22059         "Ext.panel.Table":["widget.tablepanel"
22060         ],
22061         "Ext.panel.Tool":["widget.tool"
22062         ],
22063         "Ext.picker.Color":["widget.colorpicker"
22064         ],
22065         "Ext.picker.Date":["widget.datepicker"
22066         ],
22067         "Ext.picker.Month":["widget.monthpicker"
22068         ],
22069         "Ext.picker.Time":["widget.timepicker"
22070         ],
22071         "Ext.resizer.Handle":[""
22072         ],
22073         "Ext.resizer.Resizer":[""
22074         ],
22075         "Ext.resizer.ResizeTracker":[""
22076         ],
22077         "Ext.resizer.Splitter":["widget.splitter"
22078         ],
22079         "Ext.resizer.SplitterTracker":[""
22080         ],
22081         "Ext.selection.CellModel":["selection.cellmodel"
22082         ],
22083         "Ext.selection.CheckboxModel":["selection.checkboxmodel"
22084         ],
22085         "Ext.selection.RowModel":["selection.rowmodel"
22086         ],
22087         "Ext.selection.TreeModel":["selection.treemodel"
22088         ],
22089         "Ext.slider.Multi":["widget.multislider"
22090         ],
22091         "Ext.slider.Single":["widget.slider",
22092             "widget.sliderfield"
22093         ],
22094         "Ext.slider.Thumb":[""
22095         ],
22096         "Ext.slider.Tip":["widget.slidertip"
22097         ],
22098         "Ext.tab.Bar":["widget.tabbar"
22099         ],
22100         "Ext.tab.Panel":["widget.tabpanel"
22101         ],
22102         "Ext.tab.Tab":["widget.tab"
22103         ],
22104         "Ext.tip.QuickTip":[""
22105         ],
22106         "Ext.tip.QuickTipManager":[""
22107         ],
22108         "Ext.tip.Tip":[""
22109         ],
22110         "Ext.tip.ToolTip":["widget.tooltip"
22111         ],
22112         "Ext.toolbar.Fill":["widget.tbfill"
22113         ],
22114         "Ext.toolbar.Item":["widget.tbitem"
22115         ],
22116         "Ext.toolbar.Paging":["widget.pagingtoolbar"
22117         ],
22118         "Ext.toolbar.Separator":["widget.tbseparator"
22119         ],
22120         "Ext.toolbar.Spacer":["widget.tbspacer"
22121         ],
22122         "Ext.toolbar.TextItem":["widget.tbtext"
22123         ],
22124         "Ext.toolbar.Toolbar":["widget.toolbar"
22125         ],
22126         "Ext.tree.Column":["widget.treecolumn"
22127         ],
22128         "Ext.tree.Panel":["widget.treepanel"
22129         ],
22130         "Ext.tree.View":["widget.treeview"
22131         ],
22132         "Ext.tree.ViewDragZone":[""
22133         ],
22134         "Ext.tree.ViewDropZone":[""
22135         ],
22136         "Ext.tree.plugin.TreeViewDragDrop":["plugin.treeviewdragdrop"
22137         ],
22138         "Ext.util.Animate":[""
22139         ],
22140         "Ext.util.ClickRepeater":[""
22141         ],
22142         "Ext.util.ComponentDragger":[""
22143         ],
22144         "Ext.util.Cookies":[""
22145         ],
22146         "Ext.util.CSS":[""
22147         ],
22148         "Ext.util.Floating":[""
22149         ],
22150         "Ext.util.History":[""
22151         ],
22152         "Ext.util.KeyMap":[""
22153         ],
22154         "Ext.util.KeyNav":[""
22155         ],
22156         "Ext.util.TextMetrics":[""
22157         ],
22158         "Ext.view.BoundList":["widget.boundlist"
22159         ],
22160         "Ext.view.BoundListKeyNav":[""
22161         ],
22162         "Ext.view.DragZone":[""
22163         ],
22164         "Ext.view.DropZone":[""
22165         ],
22166         "Ext.view.Table":["widget.tableview"
22167         ],
22168         "Ext.view.TableChunker":[""
22169         ],
22170         "Ext.view.View":["widget.dataview"
22171         ],
22172         "Ext.window.MessageBox":["widget.messagebox"
22173         ],
22174         "Ext.window.Window":["widget.window"
22175         ]
22176     },
22177     "alternateToNameMap":{
22178         "Ext.ComponentMgr":"Ext.ComponentManager",
22179         "Ext.ModelMgr":"Ext.ModelManager",
22180         "Ext.PluginMgr":"Ext.PluginManager",
22181         "Ext.chart.Axis":"Ext.chart.axis.Axis",
22182         "Ext.chart.CategoryAxis":"Ext.chart.axis.Category",
22183         "Ext.chart.NumericAxis":"Ext.chart.axis.Numeric",
22184         "Ext.chart.TimeAxis":"Ext.chart.axis.Time",
22185         "Ext.chart.BarSeries":"Ext.chart.series.Bar",
22186         "Ext.chart.BarChart":"Ext.chart.series.Bar",
22187         "Ext.chart.StackedBarChart":"Ext.chart.series.Bar",
22188         "Ext.chart.CartesianSeries":"Ext.chart.series.Cartesian",
22189         "Ext.chart.CartesianChart":"Ext.chart.series.Cartesian",
22190         "Ext.chart.ColumnSeries":"Ext.chart.series.Column",
22191         "Ext.chart.ColumnChart":"Ext.chart.series.Column",
22192         "Ext.chart.StackedColumnChart":"Ext.chart.series.Column",
22193         "Ext.chart.LineSeries":"Ext.chart.series.Line",
22194         "Ext.chart.LineChart":"Ext.chart.series.Line",
22195         "Ext.chart.PieSeries":"Ext.chart.series.Pie",
22196         "Ext.chart.PieChart":"Ext.chart.series.Pie",
22197         "Ext.data.Record":"Ext.data.Model",
22198         "Ext.StoreMgr":"Ext.data.StoreManager",
22199         "Ext.data.StoreMgr":"Ext.data.StoreManager",
22200         "Ext.StoreManager":"Ext.data.StoreManager",
22201         "Ext.data.XmlStore":"Ext.data.XmlStore",
22202         "Ext.data.HttpProxy":"Ext.data.proxy.Ajax",
22203         "Ext.data.AjaxProxy":"Ext.data.proxy.Ajax",
22204         "Ext.data.ClientProxy":"Ext.data.proxy.Client",
22205         "Ext.data.DirectProxy":"Ext.data.proxy.Direct",
22206         "Ext.data.ScriptTagProxy":"Ext.data.proxy.JsonP",
22207         "Ext.data.LocalStorageProxy":"Ext.data.proxy.LocalStorage",
22208         "Ext.data.MemoryProxy":"Ext.data.proxy.Memory",
22209         "Ext.data.DataProxy":"Ext.data.proxy.Proxy",
22210         "Ext.data.Proxy":"Ext.data.proxy.Proxy",
22211         "Ext.data.RestProxy":"Ext.data.proxy.Rest",
22212         "Ext.data.ServerProxy":"Ext.data.proxy.Server",
22213         "Ext.data.SessionStorageProxy":"Ext.data.proxy.SessionStorage",
22214         "Ext.data.WebStorageProxy":"Ext.data.proxy.WebStorage",
22215         "Ext.data.ArrayReader":"Ext.data.reader.Array",
22216         "Ext.data.JsonReader":"Ext.data.reader.Json",
22217         "Ext.data.Reader":"Ext.data.reader.Reader",
22218         "Ext.data.DataReader":"Ext.data.reader.Reader",
22219         "Ext.data.XmlReader":"Ext.data.reader.Xml",
22220         "Ext.data.JsonWriter":"Ext.data.writer.Json",
22221         "Ext.data.DataWriter":"Ext.data.writer.Writer",
22222         "Ext.data.Writer":"Ext.data.writer.Writer",
22223         "Ext.data.XmlWriter":"Ext.data.writer.Xml",
22224         "Ext.Direct.Transaction":"Ext.direct.Transaction",
22225         "Ext.AbstractSelectionModel":"Ext.selection.Model",
22226         "Ext.view.AbstractView":"Ext.view.AbstractView",
22227         "Ext.FocusMgr":"Ext.FocusManager",
22228         "Ext.WindowGroup":"Ext.ZIndexManager",
22229         "Ext.Button":"Ext.button.Button",
22230         "Ext.CycleButton":"Ext.button.Cycle",
22231         "Ext.SplitButton":"Ext.button.Split",
22232         "Ext.ButtonGroup":"Ext.container.ButtonGroup",
22233         "Ext.Container":"Ext.container.Container",
22234         "Ext.Viewport":"Ext.container.Viewport",
22235         "Ext.dd.DragDropMgr":"Ext.dd.DragDropManager",
22236         "Ext.dd.DDM":"Ext.dd.DragDropManager",
22237         "Ext.FlashComponent":"Ext.flash.Component",
22238         "Ext.form.BasicForm":"Ext.form.Basic",
22239         "Ext.FormPanel":"Ext.form.Panel",
22240         "Ext.form.FormPanel":"Ext.form.Panel",
22241         "Ext.form.Action":"Ext.form.action.Action",
22242         "Ext.form.Action.DirectLoad":"Ext.form.action.DirectLoad",
22243         "Ext.form.Action.DirectSubmit":"Ext.form.action.DirectSubmit",
22244         "Ext.form.Action.Load":"Ext.form.action.Load",
22245         "Ext.form.Action.Submit":"Ext.form.action.Submit",
22246         "Ext.form.Field":"Ext.form.field.Base",
22247         "Ext.form.BaseField":"Ext.form.field.Base",
22248         "Ext.form.Checkbox":"Ext.form.field.Checkbox",
22249         "Ext.form.ComboBox":"Ext.form.field.ComboBox",
22250         "Ext.form.DateField":"Ext.form.field.Date",
22251         "Ext.form.Date":"Ext.form.field.Date",
22252         "Ext.form.DisplayField":"Ext.form.field.Display",
22253         "Ext.form.Display":"Ext.form.field.Display",
22254         "Ext.form.FileUploadField":"Ext.form.field.File",
22255         "Ext.ux.form.FileUploadField":"Ext.form.field.File",
22256         "Ext.form.File":"Ext.form.field.File",
22257         "Ext.form.Hidden":"Ext.form.field.Hidden",
22258         "Ext.form.HtmlEditor":"Ext.form.field.HtmlEditor",
22259         "Ext.form.NumberField":"Ext.form.field.Number",
22260         "Ext.form.Number":"Ext.form.field.Number",
22261         "Ext.form.Picker":"Ext.form.field.Picker",
22262         "Ext.form.Radio":"Ext.form.field.Radio",
22263         "Ext.form.Spinner":"Ext.form.field.Spinner",
22264         "Ext.form.TextField":"Ext.form.field.Text",
22265         "Ext.form.Text":"Ext.form.field.Text",
22266         "Ext.form.TextArea":"Ext.form.field.TextArea",
22267         "Ext.form.TimeField":"Ext.form.field.Time",
22268         "Ext.form.Time":"Ext.form.field.Time",
22269         "Ext.form.TriggerField":"Ext.form.field.Trigger",
22270         "Ext.form.TwinTriggerField":"Ext.form.field.Trigger",
22271         "Ext.form.Trigger":"Ext.form.field.Trigger",
22272         "Ext.list.ListView":"Ext.grid.Panel",
22273         "Ext.ListView":"Ext.grid.Panel",
22274         "Ext.grid.GridPanel":"Ext.grid.Panel",
22275         "Ext.grid.ActionColumn":"Ext.grid.column.Action",
22276         "Ext.grid.BooleanColumn":"Ext.grid.column.Boolean",
22277         "Ext.grid.Column":"Ext.grid.column.Column",
22278         "Ext.grid.DateColumn":"Ext.grid.column.Date",
22279         "Ext.grid.NumberColumn":"Ext.grid.column.Number",
22280         "Ext.grid.TemplateColumn":"Ext.grid.column.Template",
22281         "Ext.grid.PropertyGrid":"Ext.grid.property.Grid",
22282         "Ext.grid.PropertyColumnModel":"Ext.grid.property.HeaderContainer",
22283         "Ext.PropGridProperty":"Ext.grid.property.Property",
22284         "Ext.grid.PropertyStore":"Ext.grid.property.Store",
22285         "Ext.layout.AbsoluteLayout":"Ext.layout.container.Absolute",
22286         "Ext.layout.AccordionLayout":"Ext.layout.container.Accordion",
22287         "Ext.layout.AnchorLayout":"Ext.layout.container.Anchor",
22288         "Ext.layout.BorderLayout":"Ext.layout.container.Border",
22289         "Ext.layout.BoxLayout":"Ext.layout.container.Box",
22290         "Ext.layout.CardLayout":"Ext.layout.container.Card",
22291         "Ext.layout.ColumnLayout":"Ext.layout.container.Column",
22292         "Ext.layout.ContainerLayout":"Ext.layout.container.Container",
22293         "Ext.layout.FitLayout":"Ext.layout.container.Fit",
22294         "Ext.layout.HBoxLayout":"Ext.layout.container.HBox",
22295         "Ext.layout.TableLayout":"Ext.layout.container.Table",
22296         "Ext.layout.VBoxLayout":"Ext.layout.container.VBox",
22297         "Ext.layout.boxOverflow.Menu":"Ext.layout.container.boxOverflow.Menu",
22298         "Ext.layout.boxOverflow.None":"Ext.layout.container.boxOverflow.None",
22299         "Ext.layout.boxOverflow.Scroller":"Ext.layout.container.boxOverflow.Scroller",
22300         "Ext.menu.TextItem":"Ext.menu.Item",
22301         "Ext.menu.MenuMgr":"Ext.menu.Manager",
22302         "Ext.Panel":"Ext.panel.Panel",
22303         "Ext.dd.PanelProxy":"Ext.panel.Proxy",
22304         "Ext.ColorPalette":"Ext.picker.Color",
22305         "Ext.DatePicker":"Ext.picker.Date",
22306         "Ext.MonthPicker":"Ext.picker.Month",
22307         "Ext.Resizable":"Ext.resizer.Resizer",
22308         "Ext.slider.MultiSlider":"Ext.slider.Multi",
22309         "Ext.Slider":"Ext.slider.Single",
22310         "Ext.form.SliderField":"Ext.slider.Single",
22311         "Ext.slider.SingleSlider":"Ext.slider.Single",
22312         "Ext.slider.Slider":"Ext.slider.Single",
22313         "Ext.TabPanel":"Ext.tab.Panel",
22314         "Ext.QuickTip":"Ext.tip.QuickTip",
22315         "Ext.Tip":"Ext.tip.Tip",
22316         "Ext.ToolTip":"Ext.tip.ToolTip",
22317         "Ext.Toolbar.Fill":"Ext.toolbar.Fill",
22318         "Ext.Toolbar.Item":"Ext.toolbar.Item",
22319         "Ext.PagingToolbar":"Ext.toolbar.Paging",
22320         "Ext.Toolbar.Separator":"Ext.toolbar.Separator",
22321         "Ext.Toolbar.Spacer":"Ext.toolbar.Spacer",
22322         "Ext.Toolbar.TextItem":"Ext.toolbar.TextItem",
22323         "Ext.Toolbar":"Ext.toolbar.Toolbar",
22324         "Ext.tree.TreePanel":"Ext.tree.Panel",
22325         "Ext.TreePanel":"Ext.tree.Panel",
22326         "Ext.History":"Ext.util.History",
22327         "Ext.KeyMap":"Ext.util.KeyMap",
22328         "Ext.KeyNav":"Ext.util.KeyNav",
22329         "Ext.BoundList":"Ext.view.BoundList",
22330         "Ext.DataView":"Ext.view.View",
22331         "Ext.Window":"Ext.window.Window"
22332     }
22333 };var scripts = document.getElementsByTagName('script'),
22334     path = '',
22335     i, ln, src, match;
22336
22337 for (i = 0, ln = scripts.length; i < ln; i++) {
22338     src = scripts[i].src;
22339
22340     match = src.match(/ext(-debug)?\.js$/);
22341
22342     if (match) {
22343         path = src.substring(0, src.length - match[0].length);
22344         break;
22345     }
22346 }
22347
22348 var nameToAliasesMap = data.nameToAliasesMap,
22349     alternateToNameMap = data.alternateToNameMap,
22350     classManager = Ext.ClassManager,
22351     name, aliases;
22352
22353 for (name in nameToAliasesMap) {
22354     if (nameToAliasesMap.hasOwnProperty(name)) {
22355         aliases = nameToAliasesMap[name];
22356
22357         if (aliases.length > 0) {
22358             for (i = 0, ln = aliases.length; i < ln; i++) {
22359                 classManager.setAlias(name, aliases[i]);
22360             }
22361         }
22362         else {
22363             classManager.setAlias(name, null);
22364         }
22365     }
22366 }
22367
22368 Ext.Object.merge(classManager.maps.alternateToName, alternateToNameMap);
22369
22370 Ext.Loader.setConfig({
22371     enabled: true,
22372     disableCaching: true,
22373     paths: {
22374         'Ext': path + 'src'
22375     }
22376 });
22377 })();
22378
22379
22380
22381