Upgrade to ExtJS 4.0.0 - Released 04/26/2011
[extjs.git] / ext-debug.js
1 /*
2 Ext JS - JavaScript Library
3 Copyright (c) 2006-2011, Sencha Inc.
4 All rights reserved.
5 licensing@sencha.com
6 */
7 /**
8  * @class Ext
9  * @singleton
10  */
11 (function() {
12     var global = this,
13         objectPrototype = Object.prototype,
14         toString = Object.prototype.toString,
15         enumerables = true,
16         enumerablesTest = { toString: 1 },
17         i;
18
19     if (typeof Ext === 'undefined') {
20         global.Ext = {};
21     }
22
23     Ext.global = global;
24
25     for (i in enumerablesTest) {
26         enumerables = null;
27     }
28
29     if (enumerables) {
30         enumerables = ['hasOwnProperty', 'valueOf', 'isPrototypeOf', 'propertyIsEnumerable',
31                        'toLocaleString', 'toString', 'constructor'];
32     }
33
34     /**
35      * An array containing extra enumerables for old browsers
36      * @type Array
37      */
38     Ext.enumerables = enumerables;
39
40     /**
41      * Copies all the properties of config to the specified object.
42      * Note that if recursive merging and cloning without referencing the original objects / arrays is needed, use
43      * {@link Ext.Object#merge} instead.
44      * @param {Object} object The receiver of the properties
45      * @param {Object} config The source of the properties
46      * @param {Object} defaults A different object that will also be applied for default values
47      * @return {Object} returns obj
48      */
49     Ext.apply = function(object, config, defaults) {
50         if (defaults) {
51             Ext.apply(object, defaults);
52         }
53
54         if (object && config && typeof config === 'object') {
55             var i, j, k;
56
57             for (i in config) {
58                 object[i] = config[i];
59             }
60
61             if (enumerables) {
62                 for (j = enumerables.length; j--;) {
63                     k = enumerables[j];
64                     if (config.hasOwnProperty(k)) {
65                         object[k] = config[k];
66                     }
67                 }
68             }
69         }
70
71         return object;
72     };
73
74     Ext.buildSettings = Ext.apply({
75         baseCSSPrefix: 'x-',
76         scopeResetCSS: false
77     }, Ext.buildSettings || {});
78
79     Ext.apply(Ext, {
80         /**
81          * A reusable empty function
82          */
83         emptyFn: function() {},
84
85         baseCSSPrefix: Ext.buildSettings.baseCSSPrefix,
86
87         /**
88          * Copies all the properties of config to object if they don't already exist.
89          * @function
90          * @param {Object} object The receiver of the properties
91          * @param {Object} config The source of the properties
92          * @return {Object} returns obj
93          */
94         applyIf: function(object, config) {
95             var property;
96
97             if (object) {
98                 for (property in config) {
99                     if (object[property] === undefined) {
100                         object[property] = config[property];
101                     }
102                 }
103             }
104
105             return object;
106         },
107
108         /**
109          * Iterates either an array or an object. This method delegates to
110          * {@link Ext.Array#each Ext.Array.each} if the given value is iterable, and {@link Ext.Object#each Ext.Object.each} otherwise.
111          *
112          * @param {Object/Array} object The object or array to be iterated.
113          * @param {Function} fn The function to be called for each iteration. See and {@link Ext.Array#each Ext.Array.each} and
114          * {@link Ext.Object#each Ext.Object.each} for detailed lists of arguments passed to this function depending on the given object
115          * type that is being iterated.
116          * @param {Object} scope (Optional) The scope (`this` reference) in which the specified function is executed.
117          * Defaults to the object being iterated itself.
118          * @markdown
119          */
120         iterate: function(object, fn, scope) {
121             if (Ext.isEmpty(object)) {
122                 return;
123             }
124
125             if (scope === undefined) {
126                 scope = object;
127             }
128
129             if (Ext.isIterable(object)) {
130                 Ext.Array.each.call(Ext.Array, object, fn, scope);
131             }
132             else {
133                 Ext.Object.each.call(Ext.Object, object, fn, scope);
134             }
135         }
136     });
137
138     Ext.apply(Ext, {
139
140         /**
141          * This method deprecated. Use {@link Ext#define Ext.define} instead.
142          * @function
143          * @param {Function} superclass
144          * @param {Object} overrides
145          * @return {Function} The subclass constructor from the <tt>overrides</tt> parameter, or a generated one if not provided.
146          * @deprecated 4.0.0 Use {@link Ext#define Ext.define} instead
147          */
148         extend: function() {
149             // inline overrides
150             var objectConstructor = objectPrototype.constructor,
151                 inlineOverrides = function(o) {
152                 for (var m in o) {
153                     if (!o.hasOwnProperty(m)) {
154                         continue;
155                     }
156                     this[m] = o[m];
157                 }
158             };
159
160             return function(subclass, superclass, overrides) {
161                 // First we check if the user passed in just the superClass with overrides
162                 if (Ext.isObject(superclass)) {
163                     overrides = superclass;
164                     superclass = subclass;
165                     subclass = overrides.constructor !== objectConstructor ? overrides.constructor : function() {
166                         superclass.apply(this, arguments);
167                     };
168                 }
169
170                 if (!superclass) {
171                     Ext.Error.raise({
172                         sourceClass: 'Ext',
173                         sourceMethod: 'extend',
174                         msg: 'Attempting to extend from a class which has not been loaded on the page.'
175                     });
176                 }
177
178                 // We create a new temporary class
179                 var F = function() {},
180                     subclassProto, superclassProto = superclass.prototype;
181
182                 F.prototype = superclassProto;
183                 subclassProto = subclass.prototype = new F();
184                 subclassProto.constructor = subclass;
185                 subclass.superclass = superclassProto;
186
187                 if (superclassProto.constructor === objectConstructor) {
188                     superclassProto.constructor = superclass;
189                 }
190
191                 subclass.override = function(overrides) {
192                     Ext.override(subclass, overrides);
193                 };
194
195                 subclassProto.override = inlineOverrides;
196                 subclassProto.proto = subclassProto;
197
198                 subclass.override(overrides);
199                 subclass.extend = function(o) {
200                     return Ext.extend(subclass, o);
201                 };
202
203                 return subclass;
204             };
205         }(),
206
207         /**
208          * Proxy to {@link Ext.Base#override}. Please refer {@link Ext.Base#override} for further details.
209
210     Ext.define('My.cool.Class', {
211         sayHi: function() {
212             alert('Hi!');
213         }
214     }
215
216     Ext.override(My.cool.Class, {
217         sayHi: function() {
218             alert('About to say...');
219
220             this.callOverridden();
221         }
222     });
223
224     var cool = new My.cool.Class();
225     cool.sayHi(); // alerts 'About to say...'
226                   // alerts 'Hi!'
227
228          * Please note that `this.callOverridden()` only works if the class was previously
229          * created with {@link Ext#define)
230          *
231          * @param {Object} cls The class to override
232          * @param {Object} overrides The list of functions to add to origClass. This should be specified as an object literal
233          * containing one or more methods.
234          * @method override
235          * @markdown
236          */
237         override: function(cls, overrides) {
238             if (cls.prototype.$className) {
239                 return cls.override(overrides);
240             }
241             else {
242                 Ext.apply(cls.prototype, overrides);
243             }
244         }
245     });
246
247     // A full set of static methods to do type checking
248     Ext.apply(Ext, {
249
250         /**
251          * Returns the given value itself if it's not empty, as described in {@link Ext#isEmpty}; returns the default
252          * value (second argument) otherwise.
253          *
254          * @param {Mixed} value The value to test
255          * @param {Mixed} defaultValue The value to return if the original value is empty
256          * @param {Boolean} allowBlank (optional) true to allow zero length strings to qualify as non-empty (defaults to false)
257          * @return {Mixed} value, if non-empty, else defaultValue
258          */
259         valueFrom: function(value, defaultValue, allowBlank){
260             return Ext.isEmpty(value, allowBlank) ? defaultValue : value;
261         },
262
263         /**
264          * Returns the type of the given variable in string format. List of possible values are:
265          *
266          * - `undefined`: If the given value is `undefined`
267          * - `null`: If the given value is `null`
268          * - `string`: If the given value is a string
269          * - `number`: If the given value is a number
270          * - `boolean`: If the given value is a boolean value
271          * - `date`: If the given value is a `Date` object
272          * - `function`: If the given value is a function reference
273          * - `object`: If the given value is an object
274          * - `array`: If the given value is an array
275          * - `regexp`: If the given value is a regular expression
276          * - `element`: If the given value is a DOM Element
277          * - `textnode`: If the given value is a DOM text node and contains something other than whitespace
278          * - `whitespace`: If the given value is a DOM text node and contains only whitespace
279          *
280          * @param {Mixed} value
281          * @return {String}
282          * @markdown
283          */
284         typeOf: function(value) {
285             if (value === null) {
286                 return 'null';
287             }
288
289             var type = typeof value;
290
291             if (type === 'undefined' || type === 'string' || type === 'number' || type === 'boolean') {
292                 return type;
293             }
294
295             var typeToString = toString.call(value);
296
297             switch(typeToString) {
298                 case '[object Array]':
299                     return 'array';
300                 case '[object Date]':
301                     return 'date';
302                 case '[object Boolean]':
303                     return 'boolean';
304                 case '[object Number]':
305                     return 'number';
306                 case '[object RegExp]':
307                     return 'regexp';
308             }
309
310             if (type === 'function') {
311                 return 'function';
312             }
313
314             if (type === 'object') {
315                 if (value.nodeType !== undefined) {
316                     if (value.nodeType === 3) {
317                         return (/\S/).test(value.nodeValue) ? 'textnode' : 'whitespace';
318                     }
319                     else {
320                         return 'element';
321                     }
322                 }
323
324                 return 'object';
325             }
326
327             Ext.Error.raise({
328                 sourceClass: 'Ext',
329                 sourceMethod: 'typeOf',
330                 msg: 'Failed to determine the type of the specified value "' + value + '". This is most likely a bug.'
331             });
332         },
333
334         /**
335          * Returns true if the passed value is empty, false otherwise. The value is deemed to be empty if it is either:
336          *
337          * - `null`
338          * - `undefined`
339          * - a zero-length array
340          * - a zero-length string (Unless the `allowEmptyString` parameter is set to `true`)
341          *
342          * @param {Mixed} value The value to test
343          * @param {Boolean} allowEmptyString (optional) true to allow empty strings (defaults to false)
344          * @return {Boolean}
345          * @markdown
346          */
347         isEmpty: function(value, allowEmptyString) {
348             return (value === null) || (value === undefined) || (!allowEmptyString ? value === '' : false) || (Ext.isArray(value) && value.length === 0);
349         },
350
351         /**
352          * Returns true if the passed value is a JavaScript Array, false otherwise.
353          *
354          * @param {Mixed} target The target to test
355          * @return {Boolean}
356          */
357         isArray: ('isArray' in Array) ? Array.isArray : function(value) {
358             return toString.call(value) === '[object Array]';
359         },
360
361         /**
362          * Returns true if the passed value is a JavaScript Date object, false otherwise.
363          * @param {Object} object The object to test
364          * @return {Boolean}
365          */
366         isDate: function(value) {
367             return toString.call(value) === '[object Date]';
368         },
369
370         /**
371          * Returns true if the passed value is a JavaScript Object, false otherwise.
372          * @param {Mixed} value The value to test
373          * @return {Boolean}
374          */
375         isObject: (toString.call(null) === '[object Object]') ?
376         function(value) {
377             return value !== null && value !== undefined && toString.call(value) === '[object Object]' && value.nodeType === undefined;
378         } :
379         function(value) {
380             return toString.call(value) === '[object Object]';
381         },
382
383         /**
384          * Returns true if the passed value is a JavaScript 'primitive', a string, number or boolean.
385          * @param {Mixed} value The value to test
386          * @return {Boolean}
387          */
388         isPrimitive: function(value) {
389             var type = typeof value;
390
391             return type === 'string' || type === 'number' || type === 'boolean';
392         },
393
394         /**
395          * Returns true if the passed value is a JavaScript Function, false otherwise.
396          * @param {Mixed} value The value to test
397          * @return {Boolean}
398          */
399         isFunction:
400         // Safari 3.x and 4.x returns 'function' for typeof <NodeList>, hence we need to fall back to using
401         // Object.prorotype.toString (slower)
402         (typeof document !== 'undefined' && typeof document.getElementsByTagName('body') === 'function') ? function(value) {
403             return toString.call(value) === '[object Function]';
404         } : function(value) {
405             return typeof value === 'function';
406         },
407
408         /**
409          * Returns true if the passed value is a number. Returns false for non-finite numbers.
410          * @param {Mixed} value The value to test
411          * @return {Boolean}
412          */
413         isNumber: function(value) {
414             return typeof value === 'number' && isFinite(value);
415         },
416
417         /**
418          * Validates that a value is numeric.
419          * @param {Mixed} value Examples: 1, '1', '2.34'
420          * @return {Boolean} True if numeric, false otherwise
421          */
422         isNumeric: function(value) {
423             return !isNaN(parseFloat(value)) && isFinite(value);
424         },
425
426         /**
427          * Returns true if the passed value is a string.
428          * @param {Mixed} value The value to test
429          * @return {Boolean}
430          */
431         isString: function(value) {
432             return typeof value === 'string';
433         },
434
435         /**
436          * Returns true if the passed value is a boolean.
437          *
438          * @param {Mixed} value The value to test
439          * @return {Boolean}
440          */
441         isBoolean: function(value) {
442             return typeof value === 'boolean';
443         },
444
445         /**
446          * Returns true if the passed value is an HTMLElement
447          * @param {Mixed} value The value to test
448          * @return {Boolean}
449          */
450         isElement: function(value) {
451             return value ? value.nodeType !== undefined : false;
452         },
453
454         /**
455          * Returns true if the passed value is a TextNode
456          * @param {Mixed} value The value to test
457          * @return {Boolean}
458          */
459         isTextNode: function(value) {
460             return value ? value.nodeName === "#text" : false;
461         },
462
463         /**
464          * Returns true if the passed value is defined.
465          * @param {Mixed} value The value to test
466          * @return {Boolean}
467          */
468         isDefined: function(value) {
469             return typeof value !== 'undefined';
470         },
471
472         /**
473          * Returns true if the passed value is iterable, false otherwise
474          * @param {Mixed} value The value to test
475          * @return {Boolean}
476          */
477         isIterable: function(value) {
478             return (value && typeof value !== 'string') ? value.length !== undefined : false;
479         }
480     });
481
482     Ext.apply(Ext, {
483
484         /**
485          * Clone almost any type of variable including array, object, DOM nodes and Date without keeping the old reference
486          * @param {Mixed} item The variable to clone
487          * @return {Mixed} clone
488          */
489         clone: function(item) {
490             if (item === null || item === undefined) {
491                 return item;
492             }
493
494             // DOM nodes
495             // TODO proxy this to Ext.Element.clone to handle automatic id attribute changing
496             // recursively
497             if (item.nodeType && item.cloneNode) {
498                 return item.cloneNode(true);
499             }
500
501             var type = toString.call(item);
502
503             // Date
504             if (type === '[object Date]') {
505                 return new Date(item.getTime());
506             }
507
508             var i, j, k, clone, key;
509
510             // Array
511             if (type === '[object Array]') {
512                 i = item.length;
513
514                 clone = [];
515
516                 while (i--) {
517                     clone[i] = Ext.clone(item[i]);
518                 }
519             }
520             // Object
521             else if (type === '[object Object]' && item.constructor === Object) {
522                 clone = {};
523
524                 for (key in item) {
525                     clone[key] = Ext.clone(item[key]);
526                 }
527
528                 if (enumerables) {
529                     for (j = enumerables.length; j--;) {
530                         k = enumerables[j];
531                         clone[k] = item[k];
532                     }
533                 }
534             }
535
536             return clone || item;
537         },
538
539         /**
540          * @private
541          * Generate a unique reference of Ext in the global scope, useful for sandboxing
542          */
543         getUniqueGlobalNamespace: function() {
544             var uniqueGlobalNamespace = this.uniqueGlobalNamespace;
545
546             if (uniqueGlobalNamespace === undefined) {
547                 var i = 0;
548
549                 do {
550                     uniqueGlobalNamespace = 'ExtSandbox' + (++i);
551                 } while (Ext.global[uniqueGlobalNamespace] !== undefined);
552
553                 Ext.global[uniqueGlobalNamespace] = Ext;
554                 this.uniqueGlobalNamespace = uniqueGlobalNamespace;
555             }
556
557             return uniqueGlobalNamespace;
558         },
559
560         /**
561          * @private
562          */
563         functionFactory: function() {
564             var args = Array.prototype.slice.call(arguments);
565
566             if (args.length > 0) {
567                 args[args.length - 1] = 'var Ext=window.' + this.getUniqueGlobalNamespace() + ';' +
568                     args[args.length - 1];
569             }
570
571             return Function.prototype.constructor.apply(Function.prototype, args);
572         }
573     });
574
575     /**
576      * Old alias to {@link Ext#typeOf}
577      * @deprecated 4.0.0 Use {@link Ext#typeOf} instead
578      */
579     Ext.type = Ext.typeOf;
580
581 })();
582
583 /**
584  * @author Jacky Nguyen <jacky@sencha.com>
585  * @docauthor Jacky Nguyen <jacky@sencha.com>
586  * @class Ext.Version
587  *
588  * A utility class that wrap around a string version number and provide convenient
589  * method to perform comparison. See also: {@link Ext.Version#compare compare}. Example:
590
591     var version = new Ext.Version('1.0.2beta');
592     console.log("Version is " + version); // Version is 1.0.2beta
593
594     console.log(version.getMajor()); // 1
595     console.log(version.getMinor()); // 0
596     console.log(version.getPatch()); // 2
597     console.log(version.getBuild()); // 0
598     console.log(version.getRelease()); // beta
599
600     console.log(version.isGreaterThan('1.0.1')); // True
601     console.log(version.isGreaterThan('1.0.2alpha')); // True
602     console.log(version.isGreaterThan('1.0.2RC')); // False
603     console.log(version.isGreaterThan('1.0.2')); // False
604     console.log(version.isLessThan('1.0.2')); // True
605
606     console.log(version.match(1.0)); // True
607     console.log(version.match('1.0.2')); // True
608
609  * @markdown
610  */
611 (function() {
612
613 // Current core version
614 var version = '4.0.0', Version;
615     Ext.Version = Version = Ext.extend(Object, {
616
617         /**
618          * @constructor
619          * @param {String/Number} version The version number in the follow standard format: major[.minor[.patch[.build[release]]]]
620          * Examples: 1.0 or 1.2.3beta or 1.2.3.4RC
621          * @return {Ext.Version} this
622          * @param version
623          */
624         constructor: function(version) {
625             var parts, releaseStartIndex;
626
627             if (version instanceof Version) {
628                 return version;
629             }
630
631             this.version = this.shortVersion = String(version).toLowerCase().replace(/_/g, '.').replace(/[\-+]/g, '');
632
633             releaseStartIndex = this.version.search(/([^\d\.])/);
634
635             if (releaseStartIndex !== -1) {
636                 this.release = this.version.substr(releaseStartIndex, version.length);
637                 this.shortVersion = this.version.substr(0, releaseStartIndex);
638             }
639
640             this.shortVersion = this.shortVersion.replace(/[^\d]/g, '');
641
642             parts = this.version.split('.');
643
644             this.major = parseInt(parts.shift() || 0, 10);
645             this.minor = parseInt(parts.shift() || 0, 10);
646             this.patch = parseInt(parts.shift() || 0, 10);
647             this.build = parseInt(parts.shift() || 0, 10);
648
649             return this;
650         },
651
652         /**
653          * Override the native toString method
654          * @private
655          * @return {String} version
656          */
657         toString: function() {
658             return this.version;
659         },
660
661         /**
662          * Override the native valueOf method
663          * @private
664          * @return {String} version
665          */
666         valueOf: function() {
667             return this.version;
668         },
669
670         /**
671          * Returns the major component value
672          * @return {Number} major
673          */
674         getMajor: function() {
675             return this.major || 0;
676         },
677
678         /**
679          * Returns the minor component value
680          * @return {Number} minor
681          */
682         getMinor: function() {
683             return this.minor || 0;
684         },
685
686         /**
687          * Returns the patch component value
688          * @return {Number} patch
689          */
690         getPatch: function() {
691             return this.patch || 0;
692         },
693
694         /**
695          * Returns the build component value
696          * @return {Number} build
697          */
698         getBuild: function() {
699             return this.build || 0;
700         },
701
702         /**
703          * Returns the release component value
704          * @return {Number} release
705          */
706         getRelease: function() {
707             return this.release || '';
708         },
709
710         /**
711          * Returns whether this version if greater than the supplied argument
712          * @param {String/Number} target The version to compare with
713          * @return {Boolean} True if this version if greater than the target, false otherwise
714          */
715         isGreaterThan: function(target) {
716             return Version.compare(this.version, target) === 1;
717         },
718
719         /**
720          * Returns whether this version if smaller than the supplied argument
721          * @param {String/Number} target The version to compare with
722          * @return {Boolean} True if this version if smaller than the target, false otherwise
723          */
724         isLessThan: function(target) {
725             return Version.compare(this.version, target) === -1;
726         },
727
728         /**
729          * Returns whether this version equals to the supplied argument
730          * @param {String/Number} target The version to compare with
731          * @return {Boolean} True if this version equals to the target, false otherwise
732          */
733         equals: function(target) {
734             return Version.compare(this.version, target) === 0;
735         },
736
737         /**
738          * Returns whether this version matches the supplied argument. Example:
739          * <pre><code>
740          * var version = new Ext.Version('1.0.2beta');
741          * console.log(version.match(1)); // True
742          * console.log(version.match(1.0)); // True
743          * console.log(version.match('1.0.2')); // True
744          * console.log(version.match('1.0.2RC')); // False
745          * </code></pre>
746          * @param {String/Number} target The version to compare with
747          * @return {Boolean} True if this version matches the target, false otherwise
748          */
749         match: function(target) {
750             target = String(target);
751             return this.version.substr(0, target.length) === target;
752         },
753
754         /**
755          * Returns this format: [major, minor, patch, build, release]. Useful for comparison
756          * @return {Array}
757          */
758         toArray: function() {
759             return [this.getMajor(), this.getMinor(), this.getPatch(), this.getBuild(), this.getRelease()];
760         },
761
762         /**
763          * Returns shortVersion version without dots and release
764          * @return {String}
765          */
766         getShortVersion: function() {
767             return this.shortVersion;
768         }
769     });
770
771     Ext.apply(Version, {
772         // @private
773         releaseValueMap: {
774             'dev': -6,
775             'alpha': -5,
776             'a': -5,
777             'beta': -4,
778             'b': -4,
779             'rc': -3,
780             '#': -2,
781             'p': -1,
782             'pl': -1
783         },
784
785         /**
786          * Converts a version component to a comparable value
787          *
788          * @static
789          * @param {Mixed} value The value to convert
790          * @return {Mixed}
791          */
792         getComponentValue: function(value) {
793             return !value ? 0 : (isNaN(value) ? this.releaseValueMap[value] || value : parseInt(value, 10));
794         },
795
796         /**
797          * Compare 2 specified versions, starting from left to right. If a part contains special version strings,
798          * they are handled in the following order:
799          * 'dev' < 'alpha' = 'a' < 'beta' = 'b' < 'RC' = 'rc' < '#' < 'pl' = 'p' < 'anything else'
800          *
801          * @static
802          * @param {String} current The current version to compare to
803          * @param {String} target The target version to compare to
804          * @return {Number} Returns -1 if the current version is smaller than the target version, 1 if greater, and 0 if they're equivalent
805          */
806         compare: function(current, target) {
807             var currentValue, targetValue, i;
808
809             current = new Version(current).toArray();
810             target = new Version(target).toArray();
811
812             for (i = 0; i < Math.max(current.length, target.length); i++) {
813                 currentValue = this.getComponentValue(current[i]);
814                 targetValue = this.getComponentValue(target[i]);
815
816                 if (currentValue < targetValue) {
817                     return -1;
818                 } else if (currentValue > targetValue) {
819                     return 1;
820                 }
821             }
822
823             return 0;
824         }
825     });
826
827     Ext.apply(Ext, {
828         /**
829          * @private
830          */
831         versions: {},
832
833         /**
834          * @private
835          */
836         lastRegisteredVersion: null,
837
838         /**
839          * Set version number for the given package name.
840          *
841          * @param {String} packageName The package name, for example: 'core', 'touch', 'extjs'
842          * @param {String/Ext.Version} version The version, for example: '1.2.3alpha', '2.4.0-dev'
843          * @return {Ext}
844          */
845         setVersion: function(packageName, version) {
846             Ext.versions[packageName] = new Version(version);
847             Ext.lastRegisteredVersion = Ext.versions[packageName];
848
849             return this;
850         },
851
852         /**
853          * Get the version number of the supplied package name; will return the last registered version
854          * (last Ext.setVersion call) if there's no package name given.
855          *
856          * @param {String} packageName (Optional) The package name, for example: 'core', 'touch', 'extjs'
857          * @return {Ext.Version} The version
858          */
859         getVersion: function(packageName) {
860             if (packageName === undefined) {
861                 return Ext.lastRegisteredVersion;
862             }
863
864             return Ext.versions[packageName];
865         },
866
867         /**
868          * Create a closure for deprecated code.
869          *
870     // This means Ext.oldMethod is only supported in 4.0.0beta and older.
871     // If Ext.getVersion('extjs') returns a version that is later than '4.0.0beta', for example '4.0.0RC',
872     // the closure will not be invoked
873     Ext.deprecate('extjs', '4.0.0beta', function() {
874         Ext.oldMethod = Ext.newMethod;
875
876         ...
877     });
878
879          * @param {String} packageName The package name
880          * @param {String} since The last version before it's deprecated
881          * @param {Function} closure The callback function to be executed with the specified version is less than the current version
882          * @param {Object} scope The execution scope (<tt>this</tt>) if the closure
883          * @markdown
884          */
885         deprecate: function(packageName, since, closure, scope) {
886             if (Version.compare(Ext.getVersion(packageName), since) < 1) {
887                 closure.call(scope);
888             }
889         }
890     }); // End Versioning
891
892     Ext.setVersion('core', version);
893
894 })();
895
896 /**
897  * @class Ext.String
898  *
899  * A collection of useful static methods to deal with strings
900  * @singleton
901  */
902
903 Ext.String = {
904     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,
905     escapeRe: /('|\\)/g,
906     formatRe: /\{(\d+)\}/g,
907     escapeRegexRe: /([-.*+?^${}()|[\]\/\\])/g,
908
909     /**
910      * Convert certain characters (&, <, >, and ') to their HTML character equivalents for literal display in web pages.
911      * @param {String} value The string to encode
912      * @return {String} The encoded text
913      */
914     htmlEncode: (function() {
915         var entities = {
916             '&': '&amp;',
917             '>': '&gt;',
918             '<': '&lt;',
919             '"': '&quot;'
920         }, keys = [], p, regex;
921         
922         for (p in entities) {
923             keys.push(p);
924         }
925         
926         regex = new RegExp('(' + keys.join('|') + ')', 'g');
927         
928         return function(value) {
929             return (!value) ? value : String(value).replace(regex, function(match, capture) {
930                 return entities[capture];    
931             });
932         };
933     })(),
934
935     /**
936      * Convert certain characters (&, <, >, and ') from their HTML character equivalents.
937      * @param {String} value The string to decode
938      * @return {String} The decoded text
939      */
940     htmlDecode: (function() {
941         var entities = {
942             '&amp;': '&',
943             '&gt;': '>',
944             '&lt;': '<',
945             '&quot;': '"'
946         }, keys = [], p, regex;
947         
948         for (p in entities) {
949             keys.push(p);
950         }
951         
952         regex = new RegExp('(' + keys.join('|') + '|&#[0-9]{1,5};' + ')', 'g');
953         
954         return function(value) {
955             return (!value) ? value : String(value).replace(regex, function(match, capture) {
956                 if (capture in entities) {
957                     return entities[capture];
958                 } else {
959                     return String.fromCharCode(parseInt(capture.substr(2), 10));
960                 }
961             });
962         };
963     })(),
964
965     /**
966      * Appends content to the query string of a URL, handling logic for whether to place
967      * a question mark or ampersand.
968      * @param {String} url The URL to append to.
969      * @param {String} string The content to append to the URL.
970      * @return (String) The resulting URL
971      */
972     urlAppend : function(url, string) {
973         if (!Ext.isEmpty(string)) {
974             return url + (url.indexOf('?') === -1 ? '?' : '&') + string;
975         }
976
977         return url;
978     },
979
980     /**
981      * Trims whitespace from either end of a string, leaving spaces within the string intact.  Example:
982      * @example
983 var s = '  foo bar  ';
984 alert('-' + s + '-');         //alerts "- foo bar -"
985 alert('-' + Ext.String.trim(s) + '-');  //alerts "-foo bar-"
986
987      * @param {String} string The string to escape
988      * @return {String} The trimmed string
989      */
990     trim: function(string) {
991         return string.replace(Ext.String.trimRegex, "");
992     },
993
994     /**
995      * Capitalize the given string
996      * @param {String} string
997      * @return {String}
998      */
999     capitalize: function(string) {
1000         return string.charAt(0).toUpperCase() + string.substr(1);
1001     },
1002
1003     /**
1004      * Truncate a string and add an ellipsis ('...') to the end if it exceeds the specified length
1005      * @param {String} value The string to truncate
1006      * @param {Number} length The maximum length to allow before truncating
1007      * @param {Boolean} word True to try to find a common word break
1008      * @return {String} The converted text
1009      */
1010     ellipsis: function(value, len, word) {
1011         if (value && value.length > len) {
1012             if (word) {
1013                 var vs = value.substr(0, len - 2),
1014                 index = Math.max(vs.lastIndexOf(' '), vs.lastIndexOf('.'), vs.lastIndexOf('!'), vs.lastIndexOf('?'));
1015                 if (index !== -1 && index >= (len - 15)) {
1016                     return vs.substr(0, index) + "...";
1017                 }
1018             }
1019             return value.substr(0, len - 3) + "...";
1020         }
1021         return value;
1022     },
1023
1024     /**
1025      * Escapes the passed string for use in a regular expression
1026      * @param {String} string
1027      * @return {String}
1028      */
1029     escapeRegex: function(string) {
1030         return string.replace(Ext.String.escapeRegexRe, "\\$1");
1031     },
1032
1033     /**
1034      * Escapes the passed string for ' and \
1035      * @param {String} string The string to escape
1036      * @return {String} The escaped string
1037      */
1038     escape: function(string) {
1039         return string.replace(Ext.String.escapeRe, "\\$1");
1040     },
1041
1042     /**
1043      * Utility function that allows you to easily switch a string between two alternating values.  The passed value
1044      * is compared to the current string, and if they are equal, the other value that was passed in is returned.  If
1045      * they are already different, the first value passed in is returned.  Note that this method returns the new value
1046      * but does not change the current string.
1047      * <pre><code>
1048     // alternate sort directions
1049     sort = Ext.String.toggle(sort, 'ASC', 'DESC');
1050
1051     // instead of conditional logic:
1052     sort = (sort == 'ASC' ? 'DESC' : 'ASC');
1053        </code></pre>
1054      * @param {String} string The current string
1055      * @param {String} value The value to compare to the current string
1056      * @param {String} other The new value to use if the string already equals the first value passed in
1057      * @return {String} The new value
1058      */
1059     toggle: function(string, value, other) {
1060         return string === value ? other : value;
1061     },
1062
1063     /**
1064      * Pads the left side of a string with a specified character.  This is especially useful
1065      * for normalizing number and date strings.  Example usage:
1066      *
1067      * <pre><code>
1068 var s = Ext.String.leftPad('123', 5, '0');
1069 // s now contains the string: '00123'
1070        </code></pre>
1071      * @param {String} string The original string
1072      * @param {Number} size The total length of the output string
1073      * @param {String} character (optional) The character with which to pad the original string (defaults to empty string " ")
1074      * @return {String} The padded string
1075      */
1076     leftPad: function(string, size, character) {
1077         var result = String(string);
1078         character = character || " ";
1079         while (result.length < size) {
1080             result = character + result;
1081         }
1082         return result;
1083     },
1084
1085     /**
1086      * Allows you to define a tokenized string and pass an arbitrary number of arguments to replace the tokens.  Each
1087      * token must be unique, and must increment in the format {0}, {1}, etc.  Example usage:
1088      * <pre><code>
1089 var cls = 'my-class', text = 'Some text';
1090 var s = Ext.String.format('&lt;div class="{0}">{1}&lt;/div>', cls, text);
1091 // s now contains the string: '&lt;div class="my-class">Some text&lt;/div>'
1092        </code></pre>
1093      * @param {String} string The tokenized string to be formatted
1094      * @param {String} value1 The value to replace token {0}
1095      * @param {String} value2 Etc...
1096      * @return {String} The formatted string
1097      */
1098     format: function(format) {
1099         var args = Ext.Array.toArray(arguments, 1);
1100         return format.replace(Ext.String.formatRe, function(m, i) {
1101             return args[i];
1102         });
1103     }
1104 };
1105
1106 /**
1107  * @class Ext.Number
1108  *
1109  * A collection of useful static methods to deal with numbers
1110  * @singleton
1111  */
1112
1113 (function() {
1114
1115 var isToFixedBroken = (0.9).toFixed() !== '1';
1116
1117 Ext.Number = {
1118     /**
1119      * Checks whether or not the current number is within a desired range.  If the number is already within the
1120      * range it is returned, otherwise the min or max value is returned depending on which side of the range is
1121      * exceeded. Note that this method returns the constrained value but does not change the current number.
1122      * @param {Number} number The number to check
1123      * @param {Number} min The minimum number in the range
1124      * @param {Number} max The maximum number in the range
1125      * @return {Number} The constrained value if outside the range, otherwise the current value
1126      */
1127     constrain: function(number, min, max) {
1128         number = parseFloat(number);
1129
1130         if (!isNaN(min)) {
1131             number = Math.max(number, min);
1132         }
1133         if (!isNaN(max)) {
1134             number = Math.min(number, max);
1135         }
1136         return number;
1137     },
1138
1139     /**
1140      * Formats a number using fixed-point notation
1141      * @param {Number} value The number to format
1142      * @param {Number} precision The number of digits to show after the decimal point
1143      */
1144     toFixed: function(value, precision) {
1145         if (isToFixedBroken) {
1146             precision = precision || 0;
1147             var pow = Math.pow(10, precision);
1148             return (Math.round(value * pow) / pow).toFixed(precision);
1149         }
1150
1151         return value.toFixed(precision);
1152     },
1153
1154     /**
1155      * Validate that a value is numeric and convert it to a number if necessary. Returns the specified default value if
1156      * it is not.
1157
1158 Ext.Number.from('1.23', 1); // returns 1.23
1159 Ext.Number.from('abc', 1); // returns 1
1160
1161      * @param {Mixed} value
1162      * @param {Number} defaultValue The value to return if the original value is non-numeric
1163      * @return {Number} value, if numeric, defaultValue otherwise
1164      */
1165     from: function(value, defaultValue) {
1166         if (isFinite(value)) {
1167             value = parseFloat(value);
1168         }
1169
1170         return !isNaN(value) ? value : defaultValue;
1171     }
1172 };
1173
1174 })();
1175
1176 /**
1177  * This method is deprecated, please use {@link Ext.Number#from Ext.Number.from} instead
1178  *
1179  * @deprecated 4.0.0 Replaced by Ext.Number.from
1180  * @member Ext
1181  * @method num
1182  */
1183 Ext.num = function() {
1184     return Ext.Number.from.apply(this, arguments);
1185 };
1186 /**
1187  * @author Jacky Nguyen <jacky@sencha.com>
1188  * @docauthor Jacky Nguyen <jacky@sencha.com>
1189  * @class Ext.Array
1190  *
1191  * A set of useful static methods to deal with arrays; provide missing methods for older browsers.
1192
1193  * @singleton
1194  * @markdown
1195  */
1196 (function() {
1197
1198     var arrayPrototype = Array.prototype,
1199         slice = arrayPrototype.slice,
1200         supportsForEach = 'forEach' in arrayPrototype,
1201         supportsMap = 'map' in arrayPrototype,
1202         supportsIndexOf = 'indexOf' in arrayPrototype,
1203         supportsEvery = 'every' in arrayPrototype,
1204         supportsSome = 'some' in arrayPrototype,
1205         supportsFilter = 'filter' in arrayPrototype,
1206         supportsSort = function() {
1207             var a = [1,2,3,4,5].sort(function(){ return 0; });
1208             return a[0] === 1 && a[1] === 2 && a[2] === 3 && a[3] === 4 && a[4] === 5;
1209         }(),
1210         supportsSliceOnNodeList = true,
1211         ExtArray;
1212     try {
1213         // IE 6 - 8 will throw an error when using Array.prototype.slice on NodeList
1214         if (typeof document !== 'undefined') {
1215             slice.call(document.getElementsByTagName('body'));
1216         }
1217     } catch (e) {
1218         supportsSliceOnNodeList = false;
1219     }
1220
1221     ExtArray = Ext.Array = {
1222         /*
1223          * Iterates an array or an iterable value and invoke the given callback function for each item.
1224
1225     var countries = ['Vietnam', 'Singapore', 'United States', 'Russia'];
1226
1227     Ext.Array.each(countries, function(name, index, countriesItSelf) {
1228         console.log(name);
1229     });
1230
1231     var sum = function() {
1232         var sum = 0;
1233
1234         Ext.Array.each(arguments, function(value) {
1235             sum += value;
1236         });
1237
1238         return sum;
1239     };
1240
1241     sum(1, 2, 3); // returns 6
1242
1243          * The iteration can be stopped by returning false in the function callback.
1244
1245     Ext.Array.each(countries, function(name, index, countriesItSelf) {
1246         if (name === 'Singapore') {
1247             return false; // break here
1248         }
1249     });
1250
1251          * @param {Array/NodeList/Mixed} iterable The value to be iterated. If this
1252          * argument is not iterable, the callback function is called once.
1253          * @param {Function} fn The callback function. If it returns false, the iteration stops and this method returns
1254          * the current `index`. Arguments passed to this callback function are:
1255
1256 - `item`: {Mixed} The item at the current `index` in the passed `array`
1257 - `index`: {Number} The current `index` within the `array`
1258 - `allItems`: {Array/NodeList/Mixed} The `array` passed as the first argument to `Ext.Array.each`
1259
1260          * @param {Object} scope (Optional) The scope (`this` reference) in which the specified function is executed.
1261          * @param {Boolean} reverse (Optional) Reverse the iteration order (loop from the end to the beginning)
1262          * Defaults false
1263          * @return {Boolean} See description for the `fn` parameter.
1264          * @markdown
1265          */
1266         each: function(array, fn, scope, reverse) {
1267             array = ExtArray.from(array);
1268
1269             var i,
1270                 ln = array.length;
1271
1272             if (reverse !== true) {
1273                 for (i = 0; i < ln; i++) {
1274                     if (fn.call(scope || array[i], array[i], i, array) === false) {
1275                         return i;
1276                     }
1277                 }
1278             }
1279             else {
1280                 for (i = ln - 1; i > -1; i--) {
1281                     if (fn.call(scope || array[i], array[i], i, array) === false) {
1282                         return i;
1283                     }
1284                 }
1285             }
1286
1287             return true;
1288         },
1289
1290         /**
1291          * Iterates an array and invoke the given callback function for each item. Note that this will simply
1292          * delegate to the native Array.prototype.forEach method if supported.
1293          * It doesn't support stopping the iteration by returning false in the callback function like
1294          * {@link Ext.Array#each}. However, performance could be much better in modern browsers comparing with
1295          * {@link Ext.Array#each}
1296          *
1297          * @param {Array} array The array to iterate
1298          * @param {Function} fn The function callback, to be invoked these arguments:
1299          *
1300 - `item`: {Mixed} The item at the current `index` in the passed `array`
1301 - `index`: {Number} The current `index` within the `array`
1302 - `allItems`: {Array} The `array` itself which was passed as the first argument
1303
1304          * @param {Object} scope (Optional) The execution scope (`this`) in which the specified function is executed.
1305          * @markdown
1306          */
1307         forEach: function(array, fn, scope) {
1308             if (supportsForEach) {
1309                 return array.forEach(fn, scope);
1310             }
1311
1312             var i = 0,
1313                 ln = array.length;
1314
1315             for (; i < ln; i++) {
1316                 fn.call(scope, array[i], i, array);
1317             }
1318         },
1319
1320         /**
1321          * Get the index of the provided `item` in the given `array`, a supplement for the
1322          * missing arrayPrototype.indexOf in Internet Explorer.
1323          *
1324          * @param {Array} array The array to check
1325          * @param {Mixed} item The item to look for
1326          * @param {Number} from (Optional) The index at which to begin the search
1327          * @return {Number} The index of item in the array (or -1 if it is not found)
1328          * @markdown
1329          */
1330         indexOf: function(array, item, from) {
1331             if (supportsIndexOf) {
1332                 return array.indexOf(item, from);
1333             }
1334
1335             var i, length = array.length;
1336
1337             for (i = (from < 0) ? Math.max(0, length + from) : from || 0; i < length; i++) {
1338                 if (array[i] === item) {
1339                     return i;
1340                 }
1341             }
1342
1343             return -1;
1344         },
1345
1346         /**
1347          * Checks whether or not the given `array` contains the specified `item`
1348          *
1349          * @param {Array} array The array to check
1350          * @param {Mixed} item The item to look for
1351          * @return {Boolean} True if the array contains the item, false otherwise
1352          * @markdown
1353          */
1354         contains: function(array, item) {
1355             if (supportsIndexOf) {
1356                 return array.indexOf(item) !== -1;
1357             }
1358
1359             var i, ln;
1360
1361             for (i = 0, ln = array.length; i < ln; i++) {
1362                 if (array[i] === item) {
1363                     return true;
1364                 }
1365             }
1366
1367             return false;
1368         },
1369
1370         /**
1371          * Converts any iterable (numeric indices and a length property) into a true array.
1372
1373 function test() {
1374     var args = Ext.Array.toArray(arguments),
1375         fromSecondToLastArgs = Ext.Array.toArray(arguments, 1);
1376
1377     alert(args.join(' '));
1378     alert(fromSecondToLastArgs.join(' '));
1379 }
1380
1381 test('just', 'testing', 'here'); // alerts 'just testing here';
1382                                  // alerts 'testing here';
1383
1384 Ext.Array.toArray(document.getElementsByTagName('div')); // will convert the NodeList into an array
1385 Ext.Array.toArray('splitted'); // returns ['s', 'p', 'l', 'i', 't', 't', 'e', 'd']
1386 Ext.Array.toArray('splitted', 0, 3); // returns ['s', 'p', 'l', 'i']
1387
1388          * @param {Mixed} iterable the iterable object to be turned into a true Array.
1389          * @param {Number} start (Optional) a zero-based index that specifies the start of extraction. Defaults to 0
1390          * @param {Number} end (Optional) a zero-based index that specifies the end of extraction. Defaults to the last
1391          * index of the iterable value
1392          * @return {Array} array
1393          * @markdown
1394          */
1395         toArray: function(iterable, start, end){
1396             if (!iterable || !iterable.length) {
1397                 return [];
1398             }
1399
1400             if (typeof iterable === 'string') {
1401                 iterable = iterable.split('');
1402             }
1403
1404             if (supportsSliceOnNodeList) {
1405                 return slice.call(iterable, start || 0, end || iterable.length);
1406             }
1407
1408             var array = [],
1409                 i;
1410
1411             start = start || 0;
1412             end = end ? ((end < 0) ? iterable.length + end : end) : iterable.length;
1413
1414             for (i = start; i < end; i++) {
1415                 array.push(iterable[i]);
1416             }
1417
1418             return array;
1419         },
1420
1421         /**
1422          * Plucks the value of a property from each item in the Array. Example:
1423          *
1424     Ext.Array.pluck(Ext.query("p"), "className"); // [el1.className, el2.className, ..., elN.className]
1425
1426          * @param {Array|NodeList} array The Array of items to pluck the value from.
1427          * @param {String} propertyName The property name to pluck from each element.
1428          * @return {Array} The value from each item in the Array.
1429          */
1430         pluck: function(array, propertyName) {
1431             var ret = [],
1432                 i, ln, item;
1433
1434             for (i = 0, ln = array.length; i < ln; i++) {
1435                 item = array[i];
1436
1437                 ret.push(item[propertyName]);
1438             }
1439
1440             return ret;
1441         },
1442
1443         /**
1444          * Creates a new array with the results of calling a provided function on every element in this array.
1445          * @param {Array} array
1446          * @param {Function} fn Callback function for each item
1447          * @param {Object} scope Callback function scope
1448          * @return {Array} results
1449          */
1450         map: function(array, fn, scope) {
1451             if (supportsMap) {
1452                 return array.map(fn, scope);
1453             }
1454
1455             var results = [],
1456                 i = 0,
1457                 len = array.length;
1458
1459             for (; i < len; i++) {
1460                 results[i] = fn.call(scope, array[i], i, array);
1461             }
1462
1463             return results;
1464         },
1465
1466         /**
1467          * Executes the specified function for each array element until the function returns a falsy value.
1468          * If such an item is found, the function will return false immediately.
1469          * Otherwise, it will return true.
1470          *
1471          * @param {Array} array
1472          * @param {Function} fn Callback function for each item
1473          * @param {Object} scope Callback function scope
1474          * @return {Boolean} True if no false value is returned by the callback function.
1475          */
1476         every: function(array, fn, scope) {
1477             if (!fn) {
1478                 Ext.Error.raise('Ext.Array.every must have a callback function passed as second argument.');
1479             }
1480             if (supportsEvery) {
1481                 return array.every(fn, scope);
1482             }
1483
1484             var i = 0,
1485                 ln = array.length;
1486
1487             for (; i < ln; ++i) {
1488                 if (!fn.call(scope, array[i], i, array)) {
1489                     return false;
1490                 }
1491             }
1492
1493             return true;
1494         },
1495
1496         /**
1497          * Executes the specified function for each array element until the function returns a truthy value.
1498          * If such an item is found, the function will return true immediately. Otherwise, it will return false.
1499          *
1500          * @param {Array} array
1501          * @param {Function} fn Callback function for each item
1502          * @param {Object} scope Callback function scope
1503          * @return {Boolean} True if the callback function returns a truthy value.
1504          */
1505         some: function(array, fn, scope) {
1506             if (!fn) {
1507                 Ext.Error.raise('Ext.Array.some must have a callback function passed as second argument.');
1508             }
1509             if (supportsSome) {
1510                 return array.some(fn, scope);
1511             }
1512
1513             var i = 0,
1514                 ln = array.length;
1515
1516             for (; i < ln; ++i) {
1517                 if (fn.call(scope, array[i], i, array)) {
1518                     return true;
1519                 }
1520             }
1521
1522             return false;
1523         },
1524
1525         /**
1526          * Filter through an array and remove empty item as defined in {@link Ext#isEmpty Ext.isEmpty}
1527          *
1528          * @see Ext.Array.filter
1529          * @param {Array} array
1530          * @return {Array} results
1531          */
1532         clean: function(array) {
1533             var results = [],
1534                 i = 0,
1535                 ln = array.length,
1536                 item;
1537
1538             for (; i < ln; i++) {
1539                 item = array[i];
1540
1541                 if (!Ext.isEmpty(item)) {
1542                     results.push(item);
1543                 }
1544             }
1545
1546             return results;
1547         },
1548
1549         /**
1550          * Returns a new array with unique items
1551          *
1552          * @param {Array} array
1553          * @return {Array} results
1554          */
1555         unique: function(array) {
1556             var clone = [],
1557                 i = 0,
1558                 ln = array.length,
1559                 item;
1560
1561             for (; i < ln; i++) {
1562                 item = array[i];
1563
1564                 if (ExtArray.indexOf(clone, item) === -1) {
1565                     clone.push(item);
1566                 }
1567             }
1568
1569             return clone;
1570         },
1571
1572         /**
1573          * Creates a new array with all of the elements of this array for which
1574          * the provided filtering function returns true.
1575          * @param {Array} array
1576          * @param {Function} fn Callback function for each item
1577          * @param {Object} scope Callback function scope
1578          * @return {Array} results
1579          */
1580         filter: function(array, fn, scope) {
1581             if (supportsFilter) {
1582                 return array.filter(fn, scope);
1583             }
1584
1585             var results = [],
1586                 i = 0,
1587                 ln = array.length;
1588
1589             for (; i < ln; i++) {
1590                 if (fn.call(scope, array[i], i, array)) {
1591                     results.push(array[i]);
1592                 }
1593             }
1594
1595             return results;
1596         },
1597
1598         /**
1599          * Converts a value to an array if it's not already an array; returns:
1600          *
1601          * - An empty array if given value is `undefined` or `null`
1602          * - Itself if given value is already an array
1603          * - An array copy if given value is {@link Ext#isIterable iterable} (arguments, NodeList and alike)
1604          * - An array with one item which is the given value, otherwise
1605          *
1606          * @param {Array/Mixed} value The value to convert to an array if it's not already is an array
1607          * @param {Boolean} (Optional) newReference True to clone the given array and return a new reference if necessary,
1608          * defaults to false
1609          * @return {Array} array
1610          * @markdown
1611          */
1612         from: function(value, newReference) {
1613             if (value === undefined || value === null) {
1614                 return [];
1615             }
1616
1617             if (Ext.isArray(value)) {
1618                 return (newReference) ? slice.call(value) : value;
1619             }
1620
1621             if (value && value.length !== undefined && typeof value !== 'string') {
1622                 return Ext.toArray(value);
1623             }
1624
1625             return [value];
1626         },
1627
1628         /**
1629          * Removes the specified item from the array if it exists
1630          *
1631          * @param {Array} array The array
1632          * @param {Mixed} item The item to remove
1633          * @return {Array} The passed array itself
1634          */
1635         remove: function(array, item) {
1636             var index = ExtArray.indexOf(array, item);
1637
1638             if (index !== -1) {
1639                 array.splice(index, 1);
1640             }
1641
1642             return array;
1643         },
1644
1645         /**
1646          * Push an item into the array only if the array doesn't contain it yet
1647          *
1648          * @param {Array} array The array
1649          * @param {Mixed} item The item to include
1650          * @return {Array} The passed array itself
1651          */
1652         include: function(array, item) {
1653             if (!ExtArray.contains(array, item)) {
1654                 array.push(item);
1655             }
1656         },
1657
1658         /**
1659          * Clone a flat array without referencing the previous one. Note that this is different
1660          * from Ext.clone since it doesn't handle recursive cloning. It's simply a convenient, easy-to-remember method
1661          * for Array.prototype.slice.call(array)
1662          *
1663          * @param {Array} array The array
1664          * @return {Array} The clone array
1665          */
1666         clone: function(array) {
1667             return slice.call(array);
1668         },
1669
1670         /**
1671          * Merge multiple arrays into one with unique items. Alias to {@link Ext.Array#union}.
1672          *
1673          * @param {Array} array,...
1674          * @return {Array} merged
1675          */
1676         merge: function() {
1677             var args = slice.call(arguments),
1678                 array = [],
1679                 i, ln;
1680
1681             for (i = 0, ln = args.length; i < ln; i++) {
1682                 array = array.concat(args[i]);
1683             }
1684
1685             return ExtArray.unique(array);
1686         },
1687
1688         /**
1689          * Merge multiple arrays into one with unique items that exist in all of the arrays.
1690          *
1691          * @param {Array} array,...
1692          * @return {Array} intersect
1693          */
1694         intersect: function() {
1695             var intersect = [],
1696                 arrays = slice.call(arguments),
1697                 i, j, k, minArray, array, x, y, ln, arraysLn, arrayLn;
1698
1699             if (!arrays.length) {
1700                 return intersect;
1701             }
1702
1703             // Find the smallest array
1704             for (i = x = 0,ln = arrays.length; i < ln,array = arrays[i]; i++) {
1705                 if (!minArray || array.length < minArray.length) {
1706                     minArray = array;
1707                     x = i;
1708                 }
1709             }
1710
1711             minArray = Ext.Array.unique(minArray);
1712             arrays.splice(x, 1);
1713
1714             // Use the smallest unique'd array as the anchor loop. If the other array(s) do contain
1715             // an item in the small array, we're likely to find it before reaching the end
1716             // of the inner loop and can terminate the search early.
1717             for (i = 0,ln = minArray.length; i < ln,x = minArray[i]; i++) {
1718                 var count = 0;
1719
1720                 for (j = 0,arraysLn = arrays.length; j < arraysLn,array = arrays[j]; j++) {
1721                     for (k = 0,arrayLn = array.length; k < arrayLn,y = array[k]; k++) {
1722                         if (x === y) {
1723                             count++;
1724                             break;
1725                         }
1726                     }
1727                 }
1728
1729                 if (count === arraysLn) {
1730                     intersect.push(x);
1731                 }
1732             }
1733
1734             return intersect;
1735         },
1736
1737         /**
1738          * Perform a set difference A-B by subtracting all items in array B from array A.
1739          *
1740          * @param {Array} array A
1741          * @param {Array} array B
1742          * @return {Array} difference
1743          */
1744         difference: function(arrayA, arrayB) {
1745             var clone = slice.call(arrayA),
1746                 ln = clone.length,
1747                 i, j, lnB;
1748
1749             for (i = 0,lnB = arrayB.length; i < lnB; i++) {
1750                 for (j = 0; j < ln; j++) {
1751                     if (clone[j] === arrayB[i]) {
1752                         clone.splice(j, 1);
1753                         j--;
1754                         ln--;
1755                     }
1756                 }
1757             }
1758
1759             return clone;
1760         },
1761
1762         /**
1763          * Sorts the elements of an Array.
1764          * By default, this method sorts the elements alphabetically and ascending.
1765          *
1766          * @param {Array} array The array to sort.
1767          * @param {Function} sortFn (optional) The comparison function.
1768          * @return {Array} The sorted array.
1769          */
1770         sort: function(array, sortFn) {
1771             if (supportsSort) {
1772                 if (sortFn) {
1773                     return array.sort(sortFn);
1774                 } else {
1775                     return array.sort();
1776                 }
1777             }
1778
1779             var length = array.length,
1780                 i = 0,
1781                 comparison,
1782                 j, min, tmp;
1783
1784             for (; i < length; i++) {
1785                 min = i;
1786                 for (j = i + 1; j < length; j++) {
1787                     if (sortFn) {
1788                         comparison = sortFn(array[j], array[min]);
1789                         if (comparison < 0) {
1790                             min = j;
1791                         }
1792                     } else if (array[j] < array[min]) {
1793                         min = j;
1794                     }
1795                 }
1796                 if (min !== i) {
1797                     tmp = array[i];
1798                     array[i] = array[min];
1799                     array[min] = tmp;
1800                 }
1801             }
1802
1803             return array;
1804         },
1805
1806         /**
1807          * Recursively flattens into 1-d Array. Injects Arrays inline.
1808          * @param {Array} array The array to flatten
1809          * @return {Array} The new, flattened array.
1810          */
1811         flatten: function(array) {
1812             var worker = [];
1813
1814             function rFlatten(a) {
1815                 var i, ln, v;
1816
1817                 for (i = 0, ln = a.length; i < ln; i++) {
1818                     v = a[i];
1819
1820                     if (Ext.isArray(v)) {
1821                         rFlatten(v);
1822                     } else {
1823                         worker.push(v);
1824                     }
1825                 }
1826
1827                 return worker;
1828             }
1829
1830             return rFlatten(array);
1831         },
1832
1833         /**
1834          * Returns the minimum value in the Array.
1835          * @param {Array|NodeList} array The Array from which to select the minimum value.
1836          * @param {Function} comparisonFn (optional) a function to perform the comparision which determines minimization.
1837          *                   If omitted the "<" operator will be used. Note: gt = 1; eq = 0; lt = -1
1838          * @return {Mixed} minValue The minimum value
1839          */
1840         min: function(array, comparisonFn) {
1841             var min = array[0],
1842                 i, ln, item;
1843
1844             for (i = 0, ln = array.length; i < ln; i++) {
1845                 item = array[i];
1846
1847                 if (comparisonFn) {
1848                     if (comparisonFn(min, item) === 1) {
1849                         min = item;
1850                     }
1851                 }
1852                 else {
1853                     if (item < min) {
1854                         min = item;
1855                     }
1856                 }
1857             }
1858
1859             return min;
1860         },
1861
1862         /**
1863          * Returns the maximum value in the Array
1864          * @param {Array|NodeList} array The Array from which to select the maximum value.
1865          * @param {Function} comparisonFn (optional) a function to perform the comparision which determines maximization.
1866          *                   If omitted the ">" operator will be used. Note: gt = 1; eq = 0; lt = -1
1867          * @return {Mixed} maxValue The maximum value
1868          */
1869         max: function(array, comparisonFn) {
1870             var max = array[0],
1871                 i, ln, item;
1872
1873             for (i = 0, ln = array.length; i < ln; i++) {
1874                 item = array[i];
1875
1876                 if (comparisonFn) {
1877                     if (comparisonFn(max, item) === -1) {
1878                         max = item;
1879                     }
1880                 }
1881                 else {
1882                     if (item > max) {
1883                         max = item;
1884                     }
1885                 }
1886             }
1887
1888             return max;
1889         },
1890
1891         /**
1892          * Calculates the mean of all items in the array
1893          * @param {Array} array The Array to calculate the mean value of.
1894          * @return {Number} The mean.
1895          */
1896         mean: function(array) {
1897             return array.length > 0 ? ExtArray.sum(array) / array.length : undefined;
1898         },
1899
1900         /**
1901          * Calculates the sum of all items in the given array
1902          * @param {Array} array The Array to calculate the sum value of.
1903          * @return {Number} The sum.
1904          */
1905         sum: function(array) {
1906             var sum = 0,
1907                 i, ln, item;
1908
1909             for (i = 0,ln = array.length; i < ln; i++) {
1910                 item = array[i];
1911
1912                 sum += item;
1913             }
1914
1915             return sum;
1916         }
1917
1918     };
1919
1920     /**
1921      * Convenient alias to {@link Ext.Array#each}
1922      * @member Ext
1923      * @method each
1924      */
1925     Ext.each = Ext.Array.each;
1926
1927     /**
1928      * Alias to {@link Ext.Array#merge}.
1929      * @member Ext.Array
1930      * @method union
1931      */
1932     Ext.Array.union = Ext.Array.merge;
1933
1934     /**
1935      * Old alias to {@link Ext.Array#min}
1936      * @deprecated 4.0.0 Use {@link Ext.Array#min} instead
1937      * @member Ext
1938      * @method min
1939      */
1940     Ext.min = Ext.Array.min;
1941
1942     /**
1943      * Old alias to {@link Ext.Array#max}
1944      * @deprecated 4.0.0 Use {@link Ext.Array#max} instead
1945      * @member Ext
1946      * @method max
1947      */
1948     Ext.max = Ext.Array.max;
1949
1950     /**
1951      * Old alias to {@link Ext.Array#sum}
1952      * @deprecated 4.0.0 Use {@link Ext.Array#sum} instead
1953      * @member Ext
1954      * @method sum
1955      */
1956     Ext.sum = Ext.Array.sum;
1957
1958     /**
1959      * Old alias to {@link Ext.Array#mean}
1960      * @deprecated 4.0.0 Use {@link Ext.Array#mean} instead
1961      * @member Ext
1962      * @method mean
1963      */
1964     Ext.mean = Ext.Array.mean;
1965
1966     /**
1967      * Old alias to {@link Ext.Array#flatten}
1968      * @deprecated 4.0.0 Use {@link Ext.Array#flatten} instead
1969      * @member Ext
1970      * @method flatten
1971      */
1972     Ext.flatten = Ext.Array.flatten;
1973
1974     /**
1975      * Old alias to {@link Ext.Array#clean Ext.Array.clean}
1976      * @deprecated 4.0.0 Use {@link Ext.Array.clean} instead
1977      * @member Ext
1978      * @method clean
1979      */
1980     Ext.clean = Ext.Array.clean;
1981
1982     /**
1983      * Old alias to {@link Ext.Array#unique Ext.Array.unique}
1984      * @deprecated 4.0.0 Use {@link Ext.Array.unique} instead
1985      * @member Ext
1986      * @method unique
1987      */
1988     Ext.unique = Ext.Array.unique;
1989
1990     /**
1991      * Old alias to {@link Ext.Array#pluck Ext.Array.pluck}
1992      * @deprecated 4.0.0 Use {@link Ext.Array#pluck Ext.Array.pluck} instead
1993      * @member Ext
1994      * @method pluck
1995      */
1996     Ext.pluck = Ext.Array.pluck;
1997
1998     /**
1999      * Convenient alias to {@link Ext.Array#toArray Ext.Array.toArray}
2000      * @param {Iterable} the iterable object to be turned into a true Array.
2001      * @member Ext
2002      * @method toArray
2003      * @return {Array} array
2004      */
2005     Ext.toArray = function() {
2006         return ExtArray.toArray.apply(ExtArray, arguments);
2007     }
2008 })();
2009
2010 /**
2011  * @class Ext.Function
2012  *
2013  * A collection of useful static methods to deal with function callbacks
2014  * @singleton
2015  */
2016
2017 Ext.Function = {
2018
2019     /**
2020      * A very commonly used method throughout the framework. It acts as a wrapper around another method
2021      * which originally accepts 2 arguments for <code>name</code> and <code>value</code>.
2022      * The wrapped function then allows "flexible" value setting of either:
2023      *
2024      * <ul>
2025      *      <li><code>name</code> and <code>value</code> as 2 arguments</li>
2026      *      <li>one single object argument with multiple key - value pairs</li>
2027      * </ul>
2028      *
2029      * For example:
2030      * <pre><code>
2031 var setValue = Ext.Function.flexSetter(function(name, value) {
2032     this[name] = value;
2033 });
2034
2035 // Afterwards
2036 // Setting a single name - value
2037 setValue('name1', 'value1');
2038
2039 // Settings multiple name - value pairs
2040 setValue({
2041     name1: 'value1',
2042     name2: 'value2',
2043     name3: 'value3'
2044 });
2045      * </code></pre>
2046      * @param {Function} setter
2047      * @returns {Function} flexSetter
2048      */
2049     flexSetter: function(fn) {
2050         return function(a, b) {
2051             var k, i;
2052
2053             if (a === null) {
2054                 return this;
2055             }
2056
2057             if (typeof a !== 'string') {
2058                 for (k in a) {
2059                     if (a.hasOwnProperty(k)) {
2060                         fn.call(this, k, a[k]);
2061                     }
2062                 }
2063
2064                 if (Ext.enumerables) {
2065                     for (i = Ext.enumerables.length; i--;) {
2066                         k = Ext.enumerables[i];
2067                         if (a.hasOwnProperty(k)) {
2068                             fn.call(this, k, a[k]);
2069                         }
2070                     }
2071                 }
2072             } else {
2073                 fn.call(this, a, b);
2074             }
2075
2076             return this;
2077         };
2078     },
2079
2080    /**
2081      * Create a new function from the provided <code>fn</code>, change <code>this</code> to the provided scope, optionally
2082      * overrides arguments for the call. (Defaults to the arguments passed by the caller)
2083      *
2084      * @param {Function} fn The function to delegate.
2085      * @param {Object} scope (optional) The scope (<code><b>this</b></code> reference) in which the function is executed.
2086      * <b>If omitted, defaults to the browser window.</b>
2087      * @param {Array} args (optional) Overrides arguments for the call. (Defaults to the arguments passed by the caller)
2088      * @param {Boolean/Number} appendArgs (optional) if True args are appended to call args instead of overriding,
2089      * if a number the args are inserted at the specified position
2090      * @return {Function} The new function
2091      */
2092     bind: function(fn, scope, args, appendArgs) {
2093         var method = fn,
2094             applyArgs;
2095
2096         return function() {
2097             var callArgs = args || arguments;
2098
2099             if (appendArgs === true) {
2100                 callArgs = Array.prototype.slice.call(arguments, 0);
2101                 callArgs = callArgs.concat(args);
2102             }
2103             else if (Ext.isNumber(appendArgs)) {
2104                 callArgs = Array.prototype.slice.call(arguments, 0); // copy arguments first
2105                 applyArgs = [appendArgs, 0].concat(args); // create method call params
2106                 Array.prototype.splice.apply(callArgs, applyArgs); // splice them in
2107             }
2108
2109             return method.apply(scope || window, callArgs);
2110         };
2111     },
2112
2113     /**
2114      * Create a new function from the provided <code>fn</code>, the arguments of which are pre-set to `args`.
2115      * New arguments passed to the newly created callback when it's invoked are appended after the pre-set ones.
2116      * This is especially useful when creating callbacks.
2117      * For example:
2118      *
2119     var originalFunction = function(){
2120         alert(Ext.Array.from(arguments).join(' '));
2121     };
2122
2123     var callback = Ext.Function.pass(originalFunction, ['Hello', 'World']);
2124
2125     callback(); // alerts 'Hello World'
2126     callback('by Me'); // alerts 'Hello World by Me'
2127
2128      * @param {Function} fn The original function
2129      * @param {Array} args The arguments to pass to new callback
2130      * @param {Object} scope (optional) The scope (<code><b>this</b></code> reference) in which the function is executed.
2131      * @return {Function} The new callback function
2132      */
2133     pass: function(fn, args, scope) {
2134         if (args) {
2135             args = Ext.Array.from(args);
2136         }
2137
2138         return function() {
2139             return fn.apply(scope, args.concat(Ext.Array.toArray(arguments)));
2140         };
2141     },
2142
2143     /**
2144      * Create an alias to the provided method property with name <code>methodName</code> of <code>object</code>.
2145      * Note that the execution scope will still be bound to the provided <code>object</code> itself.
2146      *
2147      * @param {Object/Function} object
2148      * @param {String} methodName
2149      * @return {Function} aliasFn
2150      */
2151     alias: function(object, methodName) {
2152         return function() {
2153             return object[methodName].apply(object, arguments);
2154         };
2155     },
2156
2157     /**
2158      * Creates an interceptor function. The passed function is called before the original one. If it returns false,
2159      * the original one is not called. The resulting function returns the results of the original function.
2160      * The passed function is called with the parameters of the original function. Example usage:
2161      * <pre><code>
2162 var sayHi = function(name){
2163     alert('Hi, ' + name);
2164 }
2165
2166 sayHi('Fred'); // alerts "Hi, Fred"
2167
2168 // create a new function that validates input without
2169 // directly modifying the original function:
2170 var sayHiToFriend = Ext.Function.createInterceptor(sayHi, function(name){
2171     return name == 'Brian';
2172 });
2173
2174 sayHiToFriend('Fred');  // no alert
2175 sayHiToFriend('Brian'); // alerts "Hi, Brian"
2176      </code></pre>
2177      * @param {Function} origFn The original function.
2178      * @param {Function} newFn The function to call before the original
2179      * @param {Object} scope (optional) The scope (<code><b>this</b></code> reference) in which the passed function is executed.
2180      * <b>If omitted, defaults to the scope in which the original function is called or the browser window.</b>
2181      * @param {Mixed} returnValue (optional) The value to return if the passed function return false (defaults to null).
2182      * @return {Function} The new function
2183      */
2184     createInterceptor: function(origFn, newFn, scope, returnValue) {
2185         var method = origFn;
2186         if (!Ext.isFunction(newFn)) {
2187             return origFn;
2188         }
2189         else {
2190             return function() {
2191                 var me = this,
2192                     args = arguments;
2193                 newFn.target = me;
2194                 newFn.method = origFn;
2195                 return (newFn.apply(scope || me || window, args) !== false) ? origFn.apply(me || window, args) : returnValue || null;
2196             };
2197         }
2198     },
2199
2200     /**
2201     * Creates a delegate (callback) which, when called, executes after a specific delay.
2202     * @param {Function} fn The function which will be called on a delay when the returned function is called.
2203     * Optionally, a replacement (or additional) argument list may be specified.
2204     * @param {Number} delay The number of milliseconds to defer execution by whenever called.
2205     * @param {Object} scope (optional) The scope (<code>this</code> reference) used by the function at execution time.
2206     * @param {Array} args (optional) Override arguments for the call. (Defaults to the arguments passed by the caller)
2207     * @param {Boolean/Number} appendArgs (optional) if True args are appended to call args instead of overriding,
2208     * if a number the args are inserted at the specified position.
2209     * @return {Function} A function which, when called, executes the original function after the specified delay.
2210     */
2211     createDelayed: function(fn, delay, scope, args, appendArgs) {
2212         if (scope || args) {
2213             fn = Ext.Function.bind(fn, scope, args, appendArgs);
2214         }
2215         return function() {
2216             var me = this;
2217             setTimeout(function() {
2218                 fn.apply(me, arguments);
2219             }, delay);
2220         };
2221     },
2222
2223     /**
2224      * Calls this function after the number of millseconds specified, optionally in a specific scope. Example usage:
2225      * <pre><code>
2226 var sayHi = function(name){
2227     alert('Hi, ' + name);
2228 }
2229
2230 // executes immediately:
2231 sayHi('Fred');
2232
2233 // executes after 2 seconds:
2234 Ext.Function.defer(sayHi, 2000, this, ['Fred']);
2235
2236 // this syntax is sometimes useful for deferring
2237 // execution of an anonymous function:
2238 Ext.Function.defer(function(){
2239     alert('Anonymous');
2240 }, 100);
2241      </code></pre>
2242      * @param {Function} fn The function to defer.
2243      * @param {Number} millis The number of milliseconds for the setTimeout call (if less than or equal to 0 the function is executed immediately)
2244      * @param {Object} scope (optional) The scope (<code><b>this</b></code> reference) in which the function is executed.
2245      * <b>If omitted, defaults to the browser window.</b>
2246      * @param {Array} args (optional) Overrides arguments for the call. (Defaults to the arguments passed by the caller)
2247      * @param {Boolean/Number} appendArgs (optional) if True args are appended to call args instead of overriding,
2248      * if a number the args are inserted at the specified position
2249      * @return {Number} The timeout id that can be used with clearTimeout
2250      */
2251     defer: function(fn, millis, obj, args, appendArgs) {
2252         fn = Ext.Function.bind(fn, obj, args, appendArgs);
2253         if (millis > 0) {
2254             return setTimeout(fn, millis);
2255         }
2256         fn();
2257         return 0;
2258     },
2259
2260     /**
2261      * Create a combined function call sequence of the original function + the passed function.
2262      * The resulting function returns the results of the original function.
2263      * The passed function is called with the parameters of the original function. Example usage:
2264      *
2265      * <pre><code>
2266 var sayHi = function(name){
2267     alert('Hi, ' + name);
2268 }
2269
2270 sayHi('Fred'); // alerts "Hi, Fred"
2271
2272 var sayGoodbye = Ext.Function.createSequence(sayHi, function(name){
2273     alert('Bye, ' + name);
2274 });
2275
2276 sayGoodbye('Fred'); // both alerts show
2277      * </code></pre>
2278      *
2279      * @param {Function} origFn The original function.
2280      * @param {Function} newFn The function to sequence
2281      * @param {Object} scope (optional) The scope (this reference) in which the passed function is executed.
2282      * If omitted, defaults to the scope in which the original function is called or the browser window.
2283      * @return {Function} The new function
2284      */
2285     createSequence: function(origFn, newFn, scope) {
2286         if (!Ext.isFunction(newFn)) {
2287             return origFn;
2288         }
2289         else {
2290             return function() {
2291                 var retval = origFn.apply(this || window, arguments);
2292                 newFn.apply(scope || this || window, arguments);
2293                 return retval;
2294             };
2295         }
2296     },
2297
2298     /**
2299      * <p>Creates a delegate function, optionally with a bound scope which, when called, buffers
2300      * the execution of the passed function for the configured number of milliseconds.
2301      * If called again within that period, the impending invocation will be canceled, and the
2302      * timeout period will begin again.</p>
2303      *
2304      * @param {Function} fn The function to invoke on a buffered timer.
2305      * @param {Number} buffer The number of milliseconds by which to buffer the invocation of the
2306      * function.
2307      * @param {Object} scope (optional) The scope (<code><b>this</b></code> reference) in which
2308      * the passed function is executed. If omitted, defaults to the scope specified by the caller.
2309      * @param {Array} args (optional) Override arguments for the call. Defaults to the arguments
2310      * passed by the caller.
2311      * @return {Function} A function which invokes the passed function after buffering for the specified time.
2312      */
2313     createBuffered: function(fn, buffer, scope, args) {
2314         return function(){
2315             var timerId;
2316             return function() {
2317                 var me = this;
2318                 if (timerId) {
2319                     clearInterval(timerId);
2320                     timerId = null;
2321                 }
2322                 timerId = setTimeout(function(){
2323                     fn.apply(scope || me, args || arguments);
2324                 }, buffer);
2325             };
2326         }();
2327     },
2328
2329     /**
2330      * <p>Creates a throttled version of the passed function which, when called repeatedly and
2331      * rapidly, invokes the passed function only after a certain interval has elapsed since the
2332      * previous invocation.</p>
2333      *
2334      * <p>This is useful for wrapping functions which may be called repeatedly, such as
2335      * a handler of a mouse move event when the processing is expensive.</p>
2336      *
2337      * @param fn {Function} The function to execute at a regular time interval.
2338      * @param interval {Number} The interval <b>in milliseconds</b> on which the passed function is executed.
2339      * @param scope (optional) The scope (<code><b>this</b></code> reference) in which
2340      * the passed function is executed. If omitted, defaults to the scope specified by the caller.
2341      * @returns {Function} A function which invokes the passed function at the specified interval.
2342      */
2343     createThrottled: function(fn, interval, scope) {
2344         var lastCallTime, elapsed, lastArgs, timer, execute = function() {
2345             fn.apply(scope || this, lastArgs);
2346             lastCallTime = new Date().getTime();
2347         };
2348
2349         return function() {
2350             elapsed = new Date().getTime() - lastCallTime;
2351             lastArgs = arguments;
2352
2353             clearTimeout(timer);
2354             if (!lastCallTime || (elapsed >= interval)) {
2355                 execute();
2356             } else {
2357                 timer = setTimeout(execute, interval - elapsed);
2358             }
2359         };
2360     }
2361 };
2362
2363 /**
2364  * Shorthand for {@link Ext.Function#defer}
2365  * @member Ext
2366  * @method defer
2367  */
2368 Ext.defer = Ext.Function.alias(Ext.Function, 'defer');
2369
2370 /**
2371  * Shorthand for {@link Ext.Function#pass}
2372  * @member Ext
2373  * @method pass
2374  */
2375 Ext.pass = Ext.Function.alias(Ext.Function, 'pass');
2376
2377 /**
2378  * Shorthand for {@link Ext.Function#bind}
2379  * @member Ext
2380  * @method bind
2381  */
2382 Ext.bind = Ext.Function.alias(Ext.Function, 'bind');
2383
2384 /**
2385  * @author Jacky Nguyen <jacky@sencha.com>
2386  * @docauthor Jacky Nguyen <jacky@sencha.com>
2387  * @class Ext.Object
2388  *
2389  * A collection of useful static methods to deal with objects
2390  *
2391  * @singleton
2392  */
2393
2394 (function() {
2395
2396 var ExtObject = Ext.Object = {
2397
2398     /**
2399      * Convert a `name` - `value` pair to an array of objects with support for nested structures; useful to construct
2400      * query strings. For example:
2401
2402     var objects = Ext.Object.toQueryObjects('hobbies', ['reading', 'cooking', 'swimming']);
2403
2404     // objects then equals:
2405     [
2406         { name: 'hobbies', value: 'reading' },
2407         { name: 'hobbies', value: 'cooking' },
2408         { name: 'hobbies', value: 'swimming' },
2409     ];
2410
2411     var objects = Ext.Object.toQueryObjects('dateOfBirth', {
2412         day: 3,
2413         month: 8,
2414         year: 1987,
2415         extra: {
2416             hour: 4
2417             minute: 30
2418         }
2419     }, true); // Recursive
2420
2421     // objects then equals:
2422     [
2423         { name: 'dateOfBirth[day]', value: 3 },
2424         { name: 'dateOfBirth[month]', value: 8 },
2425         { name: 'dateOfBirth[year]', value: 1987 },
2426         { name: 'dateOfBirth[extra][hour]', value: 4 },
2427         { name: 'dateOfBirth[extra][minute]', value: 30 },
2428     ];
2429
2430      * @param {String} name
2431      * @param {Mixed} value
2432      * @param {Boolean} recursive
2433      * @markdown
2434      */
2435     toQueryObjects: function(name, value, recursive) {
2436         var self = ExtObject.toQueryObjects,
2437             objects = [],
2438             i, ln;
2439
2440         if (Ext.isArray(value)) {
2441             for (i = 0, ln = value.length; i < ln; i++) {
2442                 if (recursive) {
2443                     objects = objects.concat(self(name + '[' + i + ']', value[i], true));
2444                 }
2445                 else {
2446                     objects.push({
2447                         name: name,
2448                         value: value[i]
2449                     });
2450                 }
2451             }
2452         }
2453         else if (Ext.isObject(value)) {
2454             for (i in value) {
2455                 if (value.hasOwnProperty(i)) {
2456                     if (recursive) {
2457                         objects = objects.concat(self(name + '[' + i + ']', value[i], true));
2458                     }
2459                     else {
2460                         objects.push({
2461                             name: name,
2462                             value: value[i]
2463                         });
2464                     }
2465                 }
2466             }
2467         }
2468         else {
2469             objects.push({
2470                 name: name,
2471                 value: value
2472             });
2473         }
2474
2475         return objects;
2476     },
2477
2478     /**
2479      * Takes an object and converts it to an encoded query string
2480
2481 - Non-recursive:
2482
2483     Ext.Object.toQueryString({foo: 1, bar: 2}); // returns "foo=1&bar=2"
2484     Ext.Object.toQueryString({foo: null, bar: 2}); // returns "foo=&bar=2"
2485     Ext.Object.toQueryString({'some price': '$300'}); // returns "some%20price=%24300"
2486     Ext.Object.toQueryString({date: new Date(2011, 0, 1)}); // returns "date=%222011-01-01T00%3A00%3A00%22"
2487     Ext.Object.toQueryString({colors: ['red', 'green', 'blue']}); // returns "colors=red&colors=green&colors=blue"
2488
2489 - Recursive:
2490
2491     Ext.Object.toQueryString({
2492         username: 'Jacky',
2493         dateOfBirth: {
2494             day: 1,
2495             month: 2,
2496             year: 1911
2497         },
2498         hobbies: ['coding', 'eating', 'sleeping', ['nested', 'stuff']]
2499     }, true); // returns the following string (broken down and url-decoded for ease of reading purpose):
2500               // username=Jacky
2501               //    &dateOfBirth[day]=1&dateOfBirth[month]=2&dateOfBirth[year]=1911
2502               //    &hobbies[0]=coding&hobbies[1]=eating&hobbies[2]=sleeping&hobbies[3][0]=nested&hobbies[3][1]=stuff
2503
2504      *
2505      * @param {Object} object The object to encode
2506      * @param {Boolean} recursive (optional) Whether or not to interpret the object in recursive format.
2507      * (PHP / Ruby on Rails servers and similar). Defaults to false
2508      * @return {String} queryString
2509      * @markdown
2510      */
2511     toQueryString: function(object, recursive) {
2512         var paramObjects = [],
2513             params = [],
2514             i, j, ln, paramObject, value;
2515
2516         for (i in object) {
2517             if (object.hasOwnProperty(i)) {
2518                 paramObjects = paramObjects.concat(ExtObject.toQueryObjects(i, object[i], recursive));
2519             }
2520         }
2521
2522         for (j = 0, ln = paramObjects.length; j < ln; j++) {
2523             paramObject = paramObjects[j];
2524             value = paramObject.value;
2525
2526             if (Ext.isEmpty(value)) {
2527                 value = '';
2528             }
2529             else if (Ext.isDate(value)) {
2530                 value = Ext.Date.toString(value);
2531             }
2532
2533             params.push(encodeURIComponent(paramObject.name) + '=' + encodeURIComponent(String(value)));
2534         }
2535
2536         return params.join('&');
2537     },
2538
2539     /**
2540      * Converts a query string back into an object.
2541      *
2542 - Non-recursive:
2543
2544     Ext.Object.fromQueryString(foo=1&bar=2); // returns {foo: 1, bar: 2}
2545     Ext.Object.fromQueryString(foo=&bar=2); // returns {foo: null, bar: 2}
2546     Ext.Object.fromQueryString(some%20price=%24300); // returns {'some price': '$300'}
2547     Ext.Object.fromQueryString(colors=red&colors=green&colors=blue); // returns {colors: ['red', 'green', 'blue']}
2548
2549 - Recursive:
2550
2551     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);
2552
2553     // returns
2554     {
2555         username: 'Jacky',
2556         dateOfBirth: {
2557             day: '1',
2558             month: '2',
2559             year: '1911'
2560         },
2561         hobbies: ['coding', 'eating', 'sleeping', ['nested', 'stuff']]
2562     }
2563
2564      * @param {String} queryString The query string to decode
2565      * @param {Boolean} recursive (Optional) Whether or not to recursively decode the string. This format is supported by
2566      * PHP / Ruby on Rails servers and similar. Defaults to false
2567      * @return {Object}
2568      */
2569     fromQueryString: function(queryString, recursive) {
2570         var parts = queryString.replace(/^\?/, '').split('&'),
2571             object = {},
2572             temp, components, name, value, i, ln,
2573             part, j, subLn, matchedKeys, matchedName,
2574             keys, key, nextKey;
2575
2576         for (i = 0, ln = parts.length; i < ln; i++) {
2577             part = parts[i];
2578
2579             if (part.length > 0) {
2580                 components = part.split('=');
2581                 name = decodeURIComponent(components[0]);
2582                 value = (components[1] !== undefined) ? decodeURIComponent(components[1]) : '';
2583
2584                 if (!recursive) {
2585                     if (object.hasOwnProperty(name)) {
2586                         if (!Ext.isArray(object[name])) {
2587                             object[name] = [object[name]];
2588                         }
2589
2590                         object[name].push(value);
2591                     }
2592                     else {
2593                         object[name] = value;
2594                     }
2595                 }
2596                 else {
2597                     matchedKeys = name.match(/(\[):?([^\]]*)\]/g);
2598                     matchedName = name.match(/^([^\[]+)/);
2599
2600                     if (!matchedName) {
2601                         Ext.Error.raise({
2602                             sourceClass: "Ext.Object",
2603                             sourceMethod: "fromQueryString",
2604                             queryString: queryString,
2605                             recursive: recursive,
2606                             msg: 'Malformed query string given, failed parsing name from "' + part + '"'
2607                         });
2608                     }
2609
2610                     name = matchedName[0];
2611                     keys = [];
2612
2613                     if (matchedKeys === null) {
2614                         object[name] = value;
2615                         continue;
2616                     }
2617
2618                     for (j = 0, subLn = matchedKeys.length; j < subLn; j++) {
2619                         key = matchedKeys[j];
2620                         key = (key.length === 2) ? '' : key.substring(1, key.length - 1);
2621                         keys.push(key);
2622                     }
2623
2624                     keys.unshift(name);
2625
2626                     temp = object;
2627
2628                     for (j = 0, subLn = keys.length; j < subLn; j++) {
2629                         key = keys[j];
2630
2631                         if (j === subLn - 1) {
2632                             if (Ext.isArray(temp) && key === '') {
2633                                 temp.push(value);
2634                             }
2635                             else {
2636                                 temp[key] = value;
2637                             }
2638                         }
2639                         else {
2640                             if (temp[key] === undefined || typeof temp[key] === 'string') {
2641                                 nextKey = keys[j+1];
2642
2643                                 temp[key] = (Ext.isNumeric(nextKey) || nextKey === '') ? [] : {};
2644                             }
2645
2646                             temp = temp[key];
2647                         }
2648                     }
2649                 }
2650             }
2651         }
2652
2653         return object;
2654     },
2655
2656     /**
2657      * Iterate through an object and invoke the given callback function for each iteration. The iteration can be stop
2658      * by returning `false` in the callback function. For example:
2659
2660     var person = {
2661         name: 'Jacky'
2662         hairColor: 'black'
2663         loves: ['food', 'sleeping', 'wife']
2664     };
2665
2666     Ext.Object.each(person, function(key, value, myself) {
2667         console.log(key + ":" + value);
2668
2669         if (key === 'hairColor') {
2670             return false; // stop the iteration
2671         }
2672     });
2673
2674      * @param {Object} object The object to iterate
2675      * @param {Function} fn The callback function. Passed arguments for each iteration are:
2676
2677 - {String} `key`
2678 - {Mixed} `value`
2679 - {Object} `object` The object itself
2680
2681      * @param {Object} scope (Optional) The execution scope (`this`) of the callback function
2682      * @markdown
2683      */
2684     each: function(object, fn, scope) {
2685         for (var property in object) {
2686             if (object.hasOwnProperty(property)) {
2687                 if (fn.call(scope || object, property, object[property], object) === false) {
2688                     return;
2689                 }
2690             }
2691         }
2692     },
2693
2694     /**
2695      * Merges any number of objects recursively without referencing them or their children.
2696
2697     var extjs = {
2698         companyName: 'Ext JS',
2699         products: ['Ext JS', 'Ext GWT', 'Ext Designer'],
2700         isSuperCool: true
2701         office: {
2702             size: 2000,
2703             location: 'Palo Alto',
2704             isFun: true
2705         }
2706     };
2707
2708     var newStuff = {
2709         companyName: 'Sencha Inc.',
2710         products: ['Ext JS', 'Ext GWT', 'Ext Designer', 'Sencha Touch', 'Sencha Animator'],
2711         office: {
2712             size: 40000,
2713             location: 'Redwood City'
2714         }
2715     };
2716
2717     var sencha = Ext.Object.merge(extjs, newStuff);
2718
2719     // extjs and sencha then equals to
2720     {
2721         companyName: 'Sencha Inc.',
2722         products: ['Ext JS', 'Ext GWT', 'Ext Designer', 'Sencha Touch', 'Sencha Animator'],
2723         isSuperCool: true
2724         office: {
2725             size: 30000,
2726             location: 'Redwood City'
2727             isFun: true
2728         }
2729     }
2730
2731      * @param {Object} object,...
2732      * @return {Object} merged The object that is created as a result of merging all the objects passed in.
2733      * @markdown
2734      */
2735     merge: function(source, key, value) {
2736         if (typeof key === 'string') {
2737             if (value && value.constructor === Object) {
2738                 if (source[key] && source[key].constructor === Object) {
2739                     ExtObject.merge(source[key], value);
2740                 }
2741                 else {
2742                     source[key] = Ext.clone(value);
2743                 }
2744             }
2745             else {
2746                 source[key] = value;
2747             }
2748
2749             return source;
2750         }
2751
2752         var i = 1,
2753             ln = arguments.length,
2754             object, property;
2755
2756         for (; i < ln; i++) {
2757             object = arguments[i];
2758
2759             for (property in object) {
2760                 if (object.hasOwnProperty(property)) {
2761                     ExtObject.merge(source, property, object[property]);
2762                 }
2763             }
2764         }
2765
2766         return source;
2767     },
2768
2769     /**
2770      * Returns the first matching key corresponding to the given value.
2771      * If no matching value is found, null is returned.
2772
2773     var person = {
2774         name: 'Jacky',
2775         loves: 'food'
2776     };
2777
2778     alert(Ext.Object.getKey(sencha, 'loves')); // alerts 'food'
2779
2780      * @param {Object} object
2781      * @param {Object} value The value to find
2782      * @markdown
2783      */
2784     getKey: function(object, value) {
2785         for (var property in object) {
2786             if (object.hasOwnProperty(property) && object[property] === value) {
2787                 return property;
2788             }
2789         }
2790
2791         return null;
2792     },
2793
2794     /**
2795      * Gets all values of the given object as an array.
2796
2797     var values = Ext.Object.getValues({
2798         name: 'Jacky',
2799         loves: 'food'
2800     }); // ['Jacky', 'food']
2801
2802      * @param {Object} object
2803      * @return {Array} An array of values from the object
2804      * @markdown
2805      */
2806     getValues: function(object) {
2807         var values = [],
2808             property;
2809
2810         for (property in object) {
2811             if (object.hasOwnProperty(property)) {
2812                 values.push(object[property]);
2813             }
2814         }
2815
2816         return values;
2817     },
2818
2819     /**
2820      * Gets all keys of the given object as an array.
2821
2822     var values = Ext.Object.getKeys({
2823         name: 'Jacky',
2824         loves: 'food'
2825     }); // ['name', 'loves']
2826
2827      * @param {Object} object
2828      * @return {Array} An array of keys from the object
2829      */
2830     getKeys: ('keys' in Object.prototype) ? Object.keys : function(object) {
2831         var keys = [],
2832             property;
2833
2834         for (property in object) {
2835             if (object.hasOwnProperty(property)) {
2836                 keys.push(property);
2837             }
2838         }
2839
2840         return keys;
2841     },
2842
2843     /**
2844      * Gets the total number of this object's own properties
2845
2846     var size = Ext.Object.getSize({
2847         name: 'Jacky',
2848         loves: 'food'
2849     }); // size equals 2
2850
2851      * @param {Object} object
2852      * @return {Number} size
2853      * @markdown
2854      */
2855     getSize: function(object) {
2856         var size = 0,
2857             property;
2858
2859         for (property in object) {
2860             if (object.hasOwnProperty(property)) {
2861                 size++;
2862             }
2863         }
2864
2865         return size;
2866     }
2867 };
2868
2869
2870 /**
2871  * A convenient alias method for {@link Ext.Object#merge}
2872  *
2873  * @member Ext
2874  * @method merge
2875  */
2876 Ext.merge = Ext.Object.merge;
2877
2878 /**
2879  * A convenient alias method for {@link Ext.Object#toQueryString}
2880  *
2881  * @member Ext
2882  * @method urlEncode
2883  * @deprecated 4.0.0 Use {@link Ext.Object#toQueryString Ext.Object.toQueryString} instead
2884  */
2885 Ext.urlEncode = function() {
2886     var args = Ext.Array.from(arguments),
2887         prefix = '';
2888
2889     // Support for the old `pre` argument
2890     if ((typeof args[1] === 'string')) {
2891         prefix = args[1] + '&';
2892         args[1] = false;
2893     }
2894
2895     return prefix + Ext.Object.toQueryString.apply(Ext.Object, args);
2896 };
2897
2898 /**
2899  * A convenient alias method for {@link Ext.Object#fromQueryString}
2900  *
2901  * @member Ext
2902  * @method urlDecode
2903  * @deprecated 4.0.0 Use {@link Ext.Object#fromQueryString Ext.Object.fromQueryString} instead
2904  */
2905 Ext.urlDecode = function() {
2906     return Ext.Object.fromQueryString.apply(Ext.Object, arguments);
2907 };
2908
2909 })();
2910
2911 /**
2912  * @class Ext.Date
2913  * A set of useful static methods to deal with date
2914  * Note that if Ext.Date is required and loaded, it will copy all methods / properties to
2915  * this object for convenience
2916  *
2917  * The date parsing and formatting syntax contains a subset of
2918  * <a href="http://www.php.net/date">PHP's date() function</a>, and the formats that are
2919  * supported will provide results equivalent to their PHP versions.
2920  *
2921  * The following is a list of all currently supported formats:
2922  * <pre class="">
2923 Format  Description                                                               Example returned values
2924 ------  -----------------------------------------------------------------------   -----------------------
2925   d     Day of the month, 2 digits with leading zeros                             01 to 31
2926   D     A short textual representation of the day of the week                     Mon to Sun
2927   j     Day of the month without leading zeros                                    1 to 31
2928   l     A full textual representation of the day of the week                      Sunday to Saturday
2929   N     ISO-8601 numeric representation of the day of the week                    1 (for Monday) through 7 (for Sunday)
2930   S     English ordinal suffix for the day of the month, 2 characters             st, nd, rd or th. Works well with j
2931   w     Numeric representation of the day of the week                             0 (for Sunday) to 6 (for Saturday)
2932   z     The day of the year (starting from 0)                                     0 to 364 (365 in leap years)
2933   W     ISO-8601 week number of year, weeks starting on Monday                    01 to 53
2934   F     A full textual representation of a month, such as January or March        January to December
2935   m     Numeric representation of a month, with leading zeros                     01 to 12
2936   M     A short textual representation of a month                                 Jan to Dec
2937   n     Numeric representation of a month, without leading zeros                  1 to 12
2938   t     Number of days in the given month                                         28 to 31
2939   L     Whether it&#39;s a leap year                                                  1 if it is a leap year, 0 otherwise.
2940   o     ISO-8601 year number (identical to (Y), but if the ISO week number (W)    Examples: 1998 or 2004
2941         belongs to the previous or next year, that year is used instead)
2942   Y     A full numeric representation of a year, 4 digits                         Examples: 1999 or 2003
2943   y     A two digit representation of a year                                      Examples: 99 or 03
2944   a     Lowercase Ante meridiem and Post meridiem                                 am or pm
2945   A     Uppercase Ante meridiem and Post meridiem                                 AM or PM
2946   g     12-hour format of an hour without leading zeros                           1 to 12
2947   G     24-hour format of an hour without leading zeros                           0 to 23
2948   h     12-hour format of an hour with leading zeros                              01 to 12
2949   H     24-hour format of an hour with leading zeros                              00 to 23
2950   i     Minutes, with leading zeros                                               00 to 59
2951   s     Seconds, with leading zeros                                               00 to 59
2952   u     Decimal fraction of a second                                              Examples:
2953         (minimum 1 digit, arbitrary number of digits allowed)                     001 (i.e. 0.001s) or
2954                                                                                   100 (i.e. 0.100s) or
2955                                                                                   999 (i.e. 0.999s) or
2956                                                                                   999876543210 (i.e. 0.999876543210s)
2957   O     Difference to Greenwich time (GMT) in hours and minutes                   Example: +1030
2958   P     Difference to Greenwich time (GMT) with colon between hours and minutes   Example: -08:00
2959   T     Timezone abbreviation of the machine running the code                     Examples: EST, MDT, PDT ...
2960   Z     Timezone offset in seconds (negative if west of UTC, positive if east)    -43200 to 50400
2961   c     ISO 8601 date
2962         Notes:                                                                    Examples:
2963         1) If unspecified, the month / day defaults to the current month / day,   1991 or
2964            the time defaults to midnight, while the timezone defaults to the      1992-10 or
2965            browser's timezone. If a time is specified, it must include both hours 1993-09-20 or
2966            and minutes. The "T" delimiter, seconds, milliseconds and timezone     1994-08-19T16:20+01:00 or
2967            are optional.                                                          1995-07-18T17:21:28-02:00 or
2968         2) The decimal fraction of a second, if specified, must contain at        1996-06-17T18:22:29.98765+03:00 or
2969            least 1 digit (there is no limit to the maximum number                 1997-05-16T19:23:30,12345-0400 or
2970            of digits allowed), and may be delimited by either a '.' or a ','      1998-04-15T20:24:31.2468Z or
2971         Refer to the examples on the right for the various levels of              1999-03-14T20:24:32Z or
2972         date-time granularity which are supported, or see                         2000-02-13T21:25:33
2973         http://www.w3.org/TR/NOTE-datetime for more info.                         2001-01-12 22:26:34
2974   U     Seconds since the Unix Epoch (January 1 1970 00:00:00 GMT)                1193432466 or -2138434463
2975   MS    Microsoft AJAX serialized dates                                           \/Date(1238606590509)\/ (i.e. UTC milliseconds since epoch) or
2976                                                                                   \/Date(1238606590509+0800)\/
2977 </pre>
2978  *
2979  * Example usage (note that you must escape format specifiers with '\\' to render them as character literals):
2980  * <pre><code>
2981 // Sample date:
2982 // 'Wed Jan 10 2007 15:05:01 GMT-0600 (Central Standard Time)'
2983
2984 var dt = new Date('1/10/2007 03:05:01 PM GMT-0600');
2985 console.log(Ext.Date.format(dt, 'Y-m-d'));                          // 2007-01-10
2986 console.log(Ext.Date.format(dt, 'F j, Y, g:i a'));                  // January 10, 2007, 3:05 pm
2987 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
2988 </code></pre>
2989  *
2990  * Here are some standard date/time patterns that you might find helpful.  They
2991  * are not part of the source of Ext.Date, but to use them you can simply copy this
2992  * block of code into any script that is included after Ext.Date and they will also become
2993  * globally available on the Date object.  Feel free to add or remove patterns as needed in your code.
2994  * <pre><code>
2995 Ext.Date.patterns = {
2996     ISO8601Long:"Y-m-d H:i:s",
2997     ISO8601Short:"Y-m-d",
2998     ShortDate: "n/j/Y",
2999     LongDate: "l, F d, Y",
3000     FullDateTime: "l, F d, Y g:i:s A",
3001     MonthDay: "F d",
3002     ShortTime: "g:i A",
3003     LongTime: "g:i:s A",
3004     SortableDateTime: "Y-m-d\\TH:i:s",
3005     UniversalSortableDateTime: "Y-m-d H:i:sO",
3006     YearMonth: "F, Y"
3007 };
3008 </code></pre>
3009  *
3010  * Example usage:
3011  * <pre><code>
3012 var dt = new Date();
3013 console.log(Ext.Date.format(dt, Ext.Date.patterns.ShortDate));
3014 </code></pre>
3015  * <p>Developer-written, custom formats may be used by supplying both a formatting and a parsing function
3016  * which perform to specialized requirements. The functions are stored in {@link #parseFunctions} and {@link #formatFunctions}.</p>
3017  * @singleton
3018  */
3019
3020 /*
3021  * Most of the date-formatting functions below are the excellent work of Baron Schwartz.
3022  * (see http://www.xaprb.com/blog/2005/12/12/javascript-closures-for-runtime-efficiency/)
3023  * They generate precompiled functions from format patterns instead of parsing and
3024  * processing each pattern every time a date is formatted. These functions are available
3025  * on every Date object.
3026  */
3027
3028 (function() {
3029
3030 // create private copy of Ext's Ext.util.Format.format() method
3031 // - to remove unnecessary dependency
3032 // - to resolve namespace conflict with MS-Ajax's implementation
3033 function xf(format) {
3034     var args = Array.prototype.slice.call(arguments, 1);
3035     return format.replace(/\{(\d+)\}/g, function(m, i) {
3036         return args[i];
3037     });
3038 }
3039
3040 Ext.Date = {
3041     /**
3042      * Returns the current timestamp
3043      * @return {Date} The current timestamp
3044      */
3045     now: Date.now || function() {
3046         return +new Date();
3047     },
3048
3049     /**
3050      * @private
3051      * Private for now
3052      */
3053     toString: function(date) {
3054         var pad = Ext.String.leftPad;
3055
3056         return date.getFullYear() + "-"
3057             + pad(date.getMonth() + 1, 2, '0') + "-"
3058             + pad(date.getDate(), 2, '0') + "T"
3059             + pad(date.getHours(), 2, '0') + ":"
3060             + pad(date.getMinutes(), 2, '0') + ":"
3061             + pad(date.getSeconds(), 2, '0');
3062     },
3063
3064     /**
3065      * Returns the number of milliseconds between two dates
3066      * @param {Date} dateA The first date
3067      * @param {Date} dateB (optional) The second date, defaults to now
3068      * @return {Number} The difference in milliseconds
3069      */
3070     getElapsed: function(dateA, dateB) {
3071         return Math.abs(dateA - (dateB || new Date()));
3072     },
3073
3074     /**
3075      * Global flag which determines if strict date parsing should be used.
3076      * Strict date parsing will not roll-over invalid dates, which is the
3077      * default behaviour of javascript Date objects.
3078      * (see {@link #parse} for more information)
3079      * Defaults to <tt>false</tt>.
3080      * @static
3081      * @type Boolean
3082     */
3083     useStrict: false,
3084
3085     // private
3086     formatCodeToRegex: function(character, currentGroup) {
3087         // Note: currentGroup - position in regex result array (see notes for Ext.Date.parseCodes below)
3088         var p = utilDate.parseCodes[character];
3089
3090         if (p) {
3091           p = typeof p == 'function'? p() : p;
3092           utilDate.parseCodes[character] = p; // reassign function result to prevent repeated execution
3093         }
3094
3095         return p ? Ext.applyIf({
3096           c: p.c ? xf(p.c, currentGroup || "{0}") : p.c
3097         }, p) : {
3098             g: 0,
3099             c: null,
3100             s: Ext.String.escapeRegex(character) // treat unrecognised characters as literals
3101         };
3102     },
3103
3104     /**
3105      * <p>An object hash in which each property is a date parsing function. The property name is the
3106      * format string which that function parses.</p>
3107      * <p>This object is automatically populated with date parsing functions as
3108      * date formats are requested for Ext standard formatting strings.</p>
3109      * <p>Custom parsing functions may be inserted into this object, keyed by a name which from then on
3110      * may be used as a format string to {@link #parse}.<p>
3111      * <p>Example:</p><pre><code>
3112 Ext.Date.parseFunctions['x-date-format'] = myDateParser;
3113 </code></pre>
3114      * <p>A parsing function should return a Date object, and is passed the following parameters:<div class="mdetail-params"><ul>
3115      * <li><code>date</code> : String<div class="sub-desc">The date string to parse.</div></li>
3116      * <li><code>strict</code> : Boolean<div class="sub-desc">True to validate date strings while parsing
3117      * (i.e. prevent javascript Date "rollover") (The default must be false).
3118      * Invalid date strings should return null when parsed.</div></li>
3119      * </ul></div></p>
3120      * <p>To enable Dates to also be <i>formatted</i> according to that format, a corresponding
3121      * formatting function must be placed into the {@link #formatFunctions} property.
3122      * @property parseFunctions
3123      * @static
3124      * @type Object
3125      */
3126     parseFunctions: {
3127         "MS": function(input, strict) {
3128             // note: the timezone offset is ignored since the MS Ajax server sends
3129             // a UTC milliseconds-since-Unix-epoch value (negative values are allowed)
3130             var re = new RegExp('\\/Date\\(([-+])?(\\d+)(?:[+-]\\d{4})?\\)\\/');
3131             var r = (input || '').match(re);
3132             return r? new Date(((r[1] || '') + r[2]) * 1) : null;
3133         }
3134     },
3135     parseRegexes: [],
3136
3137     /**
3138      * <p>An object hash in which each property is a date formatting function. The property name is the
3139      * format string which corresponds to the produced formatted date string.</p>
3140      * <p>This object is automatically populated with date formatting functions as
3141      * date formats are requested for Ext standard formatting strings.</p>
3142      * <p>Custom formatting functions may be inserted into this object, keyed by a name which from then on
3143      * may be used as a format string to {@link #format}. Example:</p><pre><code>
3144 Ext.Date.formatFunctions['x-date-format'] = myDateFormatter;
3145 </code></pre>
3146      * <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>
3147      * <li><code>date</code> : Date<div class="sub-desc">The Date to format.</div></li>
3148      * </ul></div></p>
3149      * <p>To enable date strings to also be <i>parsed</i> according to that format, a corresponding
3150      * parsing function must be placed into the {@link #parseFunctions} property.
3151      * @property formatFunctions
3152      * @static
3153      * @type Object
3154      */
3155     formatFunctions: {
3156         "MS": function() {
3157             // UTC milliseconds since Unix epoch (MS-AJAX serialized date format (MRSF))
3158             return '\\/Date(' + this.getTime() + ')\\/';
3159         }
3160     },
3161
3162     y2kYear : 50,
3163
3164     /**
3165      * Date interval constant
3166      * @static
3167      * @type String
3168      */
3169     MILLI : "ms",
3170
3171     /**
3172      * Date interval constant
3173      * @static
3174      * @type String
3175      */
3176     SECOND : "s",
3177
3178     /**
3179      * Date interval constant
3180      * @static
3181      * @type String
3182      */
3183     MINUTE : "mi",
3184
3185     /** Date interval constant
3186      * @static
3187      * @type String
3188      */
3189     HOUR : "h",
3190
3191     /**
3192      * Date interval constant
3193      * @static
3194      * @type String
3195      */
3196     DAY : "d",
3197
3198     /**
3199      * Date interval constant
3200      * @static
3201      * @type String
3202      */
3203     MONTH : "mo",
3204
3205     /**
3206      * Date interval constant
3207      * @static
3208      * @type String
3209      */
3210     YEAR : "y",
3211
3212     /**
3213      * <p>An object hash containing default date values used during date parsing.</p>
3214      * <p>The following properties are available:<div class="mdetail-params"><ul>
3215      * <li><code>y</code> : Number<div class="sub-desc">The default year value. (defaults to undefined)</div></li>
3216      * <li><code>m</code> : Number<div class="sub-desc">The default 1-based month value. (defaults to undefined)</div></li>
3217      * <li><code>d</code> : Number<div class="sub-desc">The default day value. (defaults to undefined)</div></li>
3218      * <li><code>h</code> : Number<div class="sub-desc">The default hour value. (defaults to undefined)</div></li>
3219      * <li><code>i</code> : Number<div class="sub-desc">The default minute value. (defaults to undefined)</div></li>
3220      * <li><code>s</code> : Number<div class="sub-desc">The default second value. (defaults to undefined)</div></li>
3221      * <li><code>ms</code> : Number<div class="sub-desc">The default millisecond value. (defaults to undefined)</div></li>
3222      * </ul></div></p>
3223      * <p>Override these properties to customize the default date values used by the {@link #parse} method.</p>
3224      * <p><b>Note: In countries which experience Daylight Saving Time (i.e. DST), the <tt>h</tt>, <tt>i</tt>, <tt>s</tt>
3225      * and <tt>ms</tt> properties may coincide with the exact time in which DST takes effect.
3226      * It is the responsiblity of the developer to account for this.</b></p>
3227      * Example Usage:
3228      * <pre><code>
3229 // set default day value to the first day of the month
3230 Ext.Date.defaults.d = 1;
3231
3232 // parse a February date string containing only year and month values.
3233 // setting the default day value to 1 prevents weird date rollover issues
3234 // when attempting to parse the following date string on, for example, March 31st 2009.
3235 Ext.Date.parse('2009-02', 'Y-m'); // returns a Date object representing February 1st 2009
3236 </code></pre>
3237      * @property defaults
3238      * @static
3239      * @type Object
3240      */
3241     defaults: {},
3242
3243     /**
3244      * An array of textual day names.
3245      * Override these values for international dates.
3246      * Example:
3247      * <pre><code>
3248 Ext.Date.dayNames = [
3249     'SundayInYourLang',
3250     'MondayInYourLang',
3251     ...
3252 ];
3253 </code></pre>
3254      * @type Array
3255      * @static
3256      */
3257     dayNames : [
3258         "Sunday",
3259         "Monday",
3260         "Tuesday",
3261         "Wednesday",
3262         "Thursday",
3263         "Friday",
3264         "Saturday"
3265     ],
3266
3267     /**
3268      * An array of textual month names.
3269      * Override these values for international dates.
3270      * Example:
3271      * <pre><code>
3272 Ext.Date.monthNames = [
3273     'JanInYourLang',
3274     'FebInYourLang',
3275     ...
3276 ];
3277 </code></pre>
3278      * @type Array
3279      * @static
3280      */
3281     monthNames : [
3282         "January",
3283         "February",
3284         "March",
3285         "April",
3286         "May",
3287         "June",
3288         "July",
3289         "August",
3290         "September",
3291         "October",
3292         "November",
3293         "December"
3294     ],
3295
3296     /**
3297      * An object hash of zero-based javascript month numbers (with short month names as keys. note: keys are case-sensitive).
3298      * Override these values for international dates.
3299      * Example:
3300      * <pre><code>
3301 Ext.Date.monthNumbers = {
3302     'ShortJanNameInYourLang':0,
3303     'ShortFebNameInYourLang':1,
3304     ...
3305 };
3306 </code></pre>
3307      * @type Object
3308      * @static
3309      */
3310     monthNumbers : {
3311         Jan:0,
3312         Feb:1,
3313         Mar:2,
3314         Apr:3,
3315         May:4,
3316         Jun:5,
3317         Jul:6,
3318         Aug:7,
3319         Sep:8,
3320         Oct:9,
3321         Nov:10,
3322         Dec:11
3323     },
3324     /**
3325      * <p>The date format string that the {@link #dateRenderer} and {@link #date} functions use.
3326      * see {@link #Date} for details.</p>
3327      * <p>This defaults to <code>m/d/Y</code>, but may be overridden in a locale file.</p>
3328      * @property defaultFormat
3329      * @static
3330      * @type String
3331      */
3332     defaultFormat : "m/d/Y",
3333     /**
3334      * Get the short month name for the given month number.
3335      * Override this function for international dates.
3336      * @param {Number} month A zero-based javascript month number.
3337      * @return {String} The short month name.
3338      * @static
3339      */
3340     getShortMonthName : function(month) {
3341         return utilDate.monthNames[month].substring(0, 3);
3342     },
3343
3344     /**
3345      * Get the short day name for the given day number.
3346      * Override this function for international dates.
3347      * @param {Number} day A zero-based javascript day number.
3348      * @return {String} The short day name.
3349      * @static
3350      */
3351     getShortDayName : function(day) {
3352         return utilDate.dayNames[day].substring(0, 3);
3353     },
3354
3355     /**
3356      * Get the zero-based javascript month number for the given short/full month name.
3357      * Override this function for international dates.
3358      * @param {String} name The short/full month name.
3359      * @return {Number} The zero-based javascript month number.
3360      * @static
3361      */
3362     getMonthNumber : function(name) {
3363         // handle camel casing for english month names (since the keys for the Ext.Date.monthNumbers hash are case sensitive)
3364         return utilDate.monthNumbers[name.substring(0, 1).toUpperCase() + name.substring(1, 3).toLowerCase()];
3365     },
3366
3367     /**
3368      * Checks if the specified format contains hour information
3369      * @param {String} format The format to check
3370      * @return {Boolean} True if the format contains hour information
3371      * @static
3372      */
3373     formatContainsHourInfo : (function(){
3374         var stripEscapeRe = /(\\.)/g,
3375             hourInfoRe = /([gGhHisucUOPZ]|MS)/;
3376         return function(format){
3377             return hourInfoRe.test(format.replace(stripEscapeRe, ''));
3378         };
3379     })(),
3380
3381     /**
3382      * Checks if the specified format contains information about
3383      * anything other than the time.
3384      * @param {String} format The format to check
3385      * @return {Boolean} True if the format contains information about
3386      * date/day information.
3387      * @static
3388      */
3389     formatContainsDateInfo : (function(){
3390         var stripEscapeRe = /(\\.)/g,
3391             dateInfoRe = /([djzmnYycU]|MS)/;
3392
3393         return function(format){
3394             return dateInfoRe.test(format.replace(stripEscapeRe, ''));
3395         };
3396     })(),
3397
3398     /**
3399      * The base format-code to formatting-function hashmap used by the {@link #format} method.
3400      * Formatting functions are strings (or functions which return strings) which
3401      * will return the appropriate value when evaluated in the context of the Date object
3402      * from which the {@link #format} method is called.
3403      * Add to / override these mappings for custom date formatting.
3404      * Note: Ext.Date.format() treats characters as literals if an appropriate mapping cannot be found.
3405      * Example:
3406      * <pre><code>
3407 Ext.Date.formatCodes.x = "Ext.util.Format.leftPad(this.getDate(), 2, '0')";
3408 console.log(Ext.Date.format(new Date(), 'X'); // returns the current day of the month
3409 </code></pre>
3410      * @type Object
3411      * @static
3412      */
3413     formatCodes : {
3414         d: "Ext.String.leftPad(this.getDate(), 2, '0')",
3415         D: "Ext.Date.getShortDayName(this.getDay())", // get localised short day name
3416         j: "this.getDate()",
3417         l: "Ext.Date.dayNames[this.getDay()]",
3418         N: "(this.getDay() ? this.getDay() : 7)",
3419         S: "Ext.Date.getSuffix(this)",
3420         w: "this.getDay()",
3421         z: "Ext.Date.getDayOfYear(this)",
3422         W: "Ext.String.leftPad(Ext.Date.getWeekOfYear(this), 2, '0')",
3423         F: "Ext.Date.monthNames[this.getMonth()]",
3424         m: "Ext.String.leftPad(this.getMonth() + 1, 2, '0')",
3425         M: "Ext.Date.getShortMonthName(this.getMonth())", // get localised short month name
3426         n: "(this.getMonth() + 1)",
3427         t: "Ext.Date.getDaysInMonth(this)",
3428         L: "(Ext.Date.isLeapYear(this) ? 1 : 0)",
3429         o: "(this.getFullYear() + (Ext.Date.getWeekOfYear(this) == 1 && this.getMonth() > 0 ? +1 : (Ext.Date.getWeekOfYear(this) >= 52 && this.getMonth() < 11 ? -1 : 0)))",
3430         Y: "Ext.String.leftPad(this.getFullYear(), 4, '0')",
3431         y: "('' + this.getFullYear()).substring(2, 4)",
3432         a: "(this.getHours() < 12 ? 'am' : 'pm')",
3433         A: "(this.getHours() < 12 ? 'AM' : 'PM')",
3434         g: "((this.getHours() % 12) ? this.getHours() % 12 : 12)",
3435         G: "this.getHours()",
3436         h: "Ext.String.leftPad((this.getHours() % 12) ? this.getHours() % 12 : 12, 2, '0')",
3437         H: "Ext.String.leftPad(this.getHours(), 2, '0')",
3438         i: "Ext.String.leftPad(this.getMinutes(), 2, '0')",
3439         s: "Ext.String.leftPad(this.getSeconds(), 2, '0')",
3440         u: "Ext.String.leftPad(this.getMilliseconds(), 3, '0')",
3441         O: "Ext.Date.getGMTOffset(this)",
3442         P: "Ext.Date.getGMTOffset(this, true)",
3443         T: "Ext.Date.getTimezone(this)",
3444         Z: "(this.getTimezoneOffset() * -60)",
3445
3446         c: function() { // ISO-8601 -- GMT format
3447             for (var c = "Y-m-dTH:i:sP", code = [], i = 0, l = c.length; i < l; ++i) {
3448                 var e = c.charAt(i);
3449                 code.push(e == "T" ? "'T'" : utilDate.getFormatCode(e)); // treat T as a character literal
3450             }
3451             return code.join(" + ");
3452         },
3453         /*
3454         c: function() { // ISO-8601 -- UTC format
3455             return [
3456               "this.getUTCFullYear()", "'-'",
3457               "Ext.util.Format.leftPad(this.getUTCMonth() + 1, 2, '0')", "'-'",
3458               "Ext.util.Format.leftPad(this.getUTCDate(), 2, '0')",
3459               "'T'",
3460               "Ext.util.Format.leftPad(this.getUTCHours(), 2, '0')", "':'",
3461               "Ext.util.Format.leftPad(this.getUTCMinutes(), 2, '0')", "':'",
3462               "Ext.util.Format.leftPad(this.getUTCSeconds(), 2, '0')",
3463               "'Z'"
3464             ].join(" + ");
3465         },
3466         */
3467
3468         U: "Math.round(this.getTime() / 1000)"
3469     },
3470
3471     /**
3472      * Checks if the passed Date parameters will cause a javascript Date "rollover".
3473      * @param {Number} year 4-digit year
3474      * @param {Number} month 1-based month-of-year
3475      * @param {Number} day Day of month
3476      * @param {Number} hour (optional) Hour
3477      * @param {Number} minute (optional) Minute
3478      * @param {Number} second (optional) Second
3479      * @param {Number} millisecond (optional) Millisecond
3480      * @return {Boolean} true if the passed parameters do not cause a Date "rollover", false otherwise.
3481      * @static
3482      */
3483     isValid : function(y, m, d, h, i, s, ms) {
3484         // setup defaults
3485         h = h || 0;
3486         i = i || 0;
3487         s = s || 0;
3488         ms = ms || 0;
3489
3490         // Special handling for year < 100
3491         var dt = utilDate.add(new Date(y < 100 ? 100 : y, m - 1, d, h, i, s, ms), utilDate.YEAR, y < 100 ? y - 100 : 0);
3492
3493         return y == dt.getFullYear() &&
3494             m == dt.getMonth() + 1 &&
3495             d == dt.getDate() &&
3496             h == dt.getHours() &&
3497             i == dt.getMinutes() &&
3498             s == dt.getSeconds() &&
3499             ms == dt.getMilliseconds();
3500     },
3501
3502     /**
3503      * Parses the passed string using the specified date format.
3504      * Note that this function expects normal calendar dates, meaning that months are 1-based (i.e. 1 = January).
3505      * The {@link #defaults} hash will be used for any date value (i.e. year, month, day, hour, minute, second or millisecond)
3506      * which cannot be found in the passed string. If a corresponding default date value has not been specified in the {@link #defaults} hash,
3507      * the current date's year, month, day or DST-adjusted zero-hour time value will be used instead.
3508      * Keep in mind that the input date string must precisely match the specified format string
3509      * in order for the parse operation to be successful (failed parse operations return a null value).
3510      * <p>Example:</p><pre><code>
3511 //dt = Fri May 25 2007 (current date)
3512 var dt = new Date();
3513
3514 //dt = Thu May 25 2006 (today&#39;s month/day in 2006)
3515 dt = Ext.Date.parse("2006", "Y");
3516
3517 //dt = Sun Jan 15 2006 (all date parts specified)
3518 dt = Ext.Date.parse("2006-01-15", "Y-m-d");
3519
3520 //dt = Sun Jan 15 2006 15:20:01
3521 dt = Ext.Date.parse("2006-01-15 3:20:01 PM", "Y-m-d g:i:s A");
3522
3523 // attempt to parse Sun Feb 29 2006 03:20:01 in strict mode
3524 dt = Ext.Date.parse("2006-02-29 03:20:01", "Y-m-d H:i:s", true); // returns null
3525 </code></pre>
3526      * @param {String} input The raw date string.
3527      * @param {String} format The expected date string format.
3528      * @param {Boolean} strict (optional) True to validate date strings while parsing (i.e. prevents javascript Date "rollover")
3529                         (defaults to false). Invalid date strings will return null when parsed.
3530      * @return {Date} The parsed Date.
3531      * @static
3532      */
3533     parse : function(input, format, strict) {
3534         var p = utilDate.parseFunctions;
3535         if (p[format] == null) {
3536             utilDate.createParser(format);
3537         }
3538         return p[format](input, Ext.isDefined(strict) ? strict : utilDate.useStrict);
3539     },
3540
3541     // Backwards compat
3542     parseDate: function(input, format, strict){
3543         return utilDate.parse(input, format, strict);
3544     },
3545
3546
3547     // private
3548     getFormatCode : function(character) {
3549         var f = utilDate.formatCodes[character];
3550
3551         if (f) {
3552           f = typeof f == 'function'? f() : f;
3553           utilDate.formatCodes[character] = f; // reassign function result to prevent repeated execution
3554         }
3555
3556         // note: unknown characters are treated as literals
3557         return f || ("'" + Ext.String.escape(character) + "'");
3558     },
3559
3560     // private
3561     createFormat : function(format) {
3562         var code = [],
3563             special = false,
3564             ch = '';
3565
3566         for (var i = 0; i < format.length; ++i) {
3567             ch = format.charAt(i);
3568             if (!special && ch == "\\") {
3569                 special = true;
3570             } else if (special) {
3571                 special = false;
3572                 code.push("'" + Ext.String.escape(ch) + "'");
3573             } else {
3574                 code.push(utilDate.getFormatCode(ch));
3575             }
3576         }
3577         utilDate.formatFunctions[format] = Ext.functionFactory("return " + code.join('+'));
3578     },
3579
3580     // private
3581     createParser : (function() {
3582         var code = [
3583             "var dt, y, m, d, h, i, s, ms, o, z, zz, u, v,",
3584                 "def = Ext.Date.defaults,",
3585                 "results = String(input).match(Ext.Date.parseRegexes[{0}]);", // either null, or an array of matched strings
3586
3587             "if(results){",
3588                 "{1}",
3589
3590                 "if(u != null){", // i.e. unix time is defined
3591                     "v = new Date(u * 1000);", // give top priority to UNIX time
3592                 "}else{",
3593                     // create Date object representing midnight of the current day;
3594                     // this will provide us with our date defaults
3595                     // (note: clearTime() handles Daylight Saving Time automatically)
3596                     "dt = Ext.Date.clearTime(new Date);",
3597
3598                     // date calculations (note: these calculations create a dependency on Ext.Number.from())
3599                     "y = Ext.Number.from(y, Ext.Number.from(def.y, dt.getFullYear()));",
3600                     "m = Ext.Number.from(m, Ext.Number.from(def.m - 1, dt.getMonth()));",
3601                     "d = Ext.Number.from(d, Ext.Number.from(def.d, dt.getDate()));",
3602
3603                     // time calculations (note: these calculations create a dependency on Ext.Number.from())
3604                     "h  = Ext.Number.from(h, Ext.Number.from(def.h, dt.getHours()));",
3605                     "i  = Ext.Number.from(i, Ext.Number.from(def.i, dt.getMinutes()));",
3606                     "s  = Ext.Number.from(s, Ext.Number.from(def.s, dt.getSeconds()));",
3607                     "ms = Ext.Number.from(ms, Ext.Number.from(def.ms, dt.getMilliseconds()));",
3608
3609                     "if(z >= 0 && y >= 0){",
3610                         // both the year and zero-based day of year are defined and >= 0.
3611                         // these 2 values alone provide sufficient info to create a full date object
3612
3613                         // create Date object representing January 1st for the given year
3614                         // handle years < 100 appropriately
3615                         "v = Ext.Date.add(new Date(y < 100 ? 100 : y, 0, 1, h, i, s, ms), Ext.Date.YEAR, y < 100 ? y - 100 : 0);",
3616
3617                         // then add day of year, checking for Date "rollover" if necessary
3618                         "v = !strict? v : (strict === true && (z <= 364 || (Ext.Date.isLeapYear(v) && z <= 365))? Ext.Date.add(v, Ext.Date.DAY, z) : null);",
3619                     "}else if(strict === true && !Ext.Date.isValid(y, m + 1, d, h, i, s, ms)){", // check for Date "rollover"
3620                         "v = null;", // invalid date, so return null
3621                     "}else{",
3622                         // plain old Date object
3623                         // handle years < 100 properly
3624                         "v = Ext.Date.add(new Date(y < 100 ? 100 : y, m, d, h, i, s, ms), Ext.Date.YEAR, y < 100 ? y - 100 : 0);",
3625                     "}",
3626                 "}",
3627             "}",
3628
3629             "if(v){",
3630                 // favour UTC offset over GMT offset
3631                 "if(zz != null){",
3632                     // reset to UTC, then add offset
3633                     "v = Ext.Date.add(v, Ext.Date.SECOND, -v.getTimezoneOffset() * 60 - zz);",
3634                 "}else if(o){",
3635                     // reset to GMT, then add offset
3636                     "v = Ext.Date.add(v, Ext.Date.MINUTE, -v.getTimezoneOffset() + (sn == '+'? -1 : 1) * (hr * 60 + mn));",
3637                 "}",
3638             "}",
3639
3640             "return v;"
3641         ].join('\n');
3642
3643         return function(format) {
3644             var regexNum = utilDate.parseRegexes.length,
3645                 currentGroup = 1,
3646                 calc = [],
3647                 regex = [],
3648                 special = false,
3649                 ch = "";
3650
3651             for (var i = 0; i < format.length; ++i) {
3652                 ch = format.charAt(i);
3653                 if (!special && ch == "\\") {
3654                     special = true;
3655                 } else if (special) {
3656                     special = false;
3657                     regex.push(Ext.String.escape(ch));
3658                 } else {
3659                     var obj = utilDate.formatCodeToRegex(ch, currentGroup);
3660                     currentGroup += obj.g;
3661                     regex.push(obj.s);
3662                     if (obj.g && obj.c) {
3663                         calc.push(obj.c);
3664                     }
3665                 }
3666             }
3667
3668             utilDate.parseRegexes[regexNum] = new RegExp("^" + regex.join('') + "$", 'i');
3669             utilDate.parseFunctions[format] = Ext.functionFactory("input", "strict", xf(code, regexNum, calc.join('')));
3670         };
3671     })(),
3672
3673     // private
3674     parseCodes : {
3675         /*
3676          * Notes:
3677          * g = {Number} calculation group (0 or 1. only group 1 contributes to date calculations.)
3678          * c = {String} calculation method (required for group 1. null for group 0. {0} = currentGroup - position in regex result array)
3679          * s = {String} regex pattern. all matches are stored in results[], and are accessible by the calculation mapped to 'c'
3680          */
3681         d: {
3682             g:1,
3683             c:"d = parseInt(results[{0}], 10);\n",
3684             s:"(\\d{2})" // day of month with leading zeroes (01 - 31)
3685         },
3686         j: {
3687             g:1,
3688             c:"d = parseInt(results[{0}], 10);\n",
3689             s:"(\\d{1,2})" // day of month without leading zeroes (1 - 31)
3690         },
3691         D: function() {
3692             for (var a = [], i = 0; i < 7; a.push(utilDate.getShortDayName(i)), ++i); // get localised short day names
3693             return {
3694                 g:0,
3695                 c:null,
3696                 s:"(?:" + a.join("|") +")"
3697             };
3698         },
3699         l: function() {
3700             return {
3701                 g:0,
3702                 c:null,
3703                 s:"(?:" + utilDate.dayNames.join("|") + ")"
3704             };
3705         },
3706         N: {
3707             g:0,
3708             c:null,
3709             s:"[1-7]" // ISO-8601 day number (1 (monday) - 7 (sunday))
3710         },
3711         S: {
3712             g:0,
3713             c:null,
3714             s:"(?:st|nd|rd|th)"
3715         },
3716         w: {
3717             g:0,
3718             c:null,
3719             s:"[0-6]" // javascript day number (0 (sunday) - 6 (saturday))
3720         },
3721         z: {
3722             g:1,
3723             c:"z = parseInt(results[{0}], 10);\n",
3724             s:"(\\d{1,3})" // day of the year (0 - 364 (365 in leap years))
3725         },
3726         W: {
3727             g:0,
3728             c:null,
3729             s:"(?:\\d{2})" // ISO-8601 week number (with leading zero)
3730         },
3731         F: function() {
3732             return {
3733                 g:1,
3734                 c:"m = parseInt(Ext.Date.getMonthNumber(results[{0}]), 10);\n", // get localised month number
3735                 s:"(" + utilDate.monthNames.join("|") + ")"
3736             };
3737         },
3738         M: function() {
3739             for (var a = [], i = 0; i < 12; a.push(utilDate.getShortMonthName(i)), ++i); // get localised short month names
3740             return Ext.applyIf({
3741                 s:"(" + a.join("|") + ")"
3742             }, utilDate.formatCodeToRegex("F"));
3743         },
3744         m: {
3745             g:1,
3746             c:"m = parseInt(results[{0}], 10) - 1;\n",
3747             s:"(\\d{2})" // month number with leading zeros (01 - 12)
3748         },
3749         n: {
3750             g:1,
3751             c:"m = parseInt(results[{0}], 10) - 1;\n",
3752             s:"(\\d{1,2})" // month number without leading zeros (1 - 12)
3753         },
3754         t: {
3755             g:0,
3756             c:null,
3757             s:"(?:\\d{2})" // no. of days in the month (28 - 31)
3758         },
3759         L: {
3760             g:0,
3761             c:null,
3762             s:"(?:1|0)"
3763         },
3764         o: function() {
3765             return utilDate.formatCodeToRegex("Y");
3766         },
3767         Y: {
3768             g:1,
3769             c:"y = parseInt(results[{0}], 10);\n",
3770             s:"(\\d{4})" // 4-digit year
3771         },
3772         y: {
3773             g:1,
3774             c:"var ty = parseInt(results[{0}], 10);\n"
3775                 + "y = ty > Ext.Date.y2kYear ? 1900 + ty : 2000 + ty;\n", // 2-digit year
3776             s:"(\\d{1,2})"
3777         },
3778         /**
3779          * In the am/pm parsing routines, we allow both upper and lower case
3780          * even though it doesn't exactly match the spec. It gives much more flexibility
3781          * in being able to specify case insensitive regexes.
3782          */
3783         a: {
3784             g:1,
3785             c:"if (/(am)/i.test(results[{0}])) {\n"
3786                 + "if (!h || h == 12) { h = 0; }\n"
3787                 + "} else { if (!h || h < 12) { h = (h || 0) + 12; }}",
3788             s:"(am|pm|AM|PM)"
3789         },
3790         A: {
3791             g:1,
3792             c:"if (/(am)/i.test(results[{0}])) {\n"
3793                 + "if (!h || h == 12) { h = 0; }\n"
3794                 + "} else { if (!h || h < 12) { h = (h || 0) + 12; }}",
3795             s:"(AM|PM|am|pm)"
3796         },
3797         g: function() {
3798             return utilDate.formatCodeToRegex("G");
3799         },
3800         G: {
3801             g:1,
3802             c:"h = parseInt(results[{0}], 10);\n",
3803             s:"(\\d{1,2})" // 24-hr format of an hour without leading zeroes (0 - 23)
3804         },
3805         h: function() {
3806             return utilDate.formatCodeToRegex("H");
3807         },
3808         H: {
3809             g:1,
3810             c:"h = parseInt(results[{0}], 10);\n",
3811             s:"(\\d{2})" //  24-hr format of an hour with leading zeroes (00 - 23)
3812         },
3813         i: {
3814             g:1,
3815             c:"i = parseInt(results[{0}], 10);\n",
3816             s:"(\\d{2})" // minutes with leading zeros (00 - 59)
3817         },
3818         s: {
3819             g:1,
3820             c:"s = parseInt(results[{0}], 10);\n",
3821             s:"(\\d{2})" // seconds with leading zeros (00 - 59)
3822         },
3823         u: {
3824             g:1,
3825             c:"ms = results[{0}]; ms = parseInt(ms, 10)/Math.pow(10, ms.length - 3);\n",
3826             s:"(\\d+)" // decimal fraction of a second (minimum = 1 digit, maximum = unlimited)
3827         },
3828         O: {
3829             g:1,
3830             c:[
3831                 "o = results[{0}];",
3832                 "var sn = o.substring(0,1),", // get + / - sign
3833                     "hr = o.substring(1,3)*1 + Math.floor(o.substring(3,5) / 60),", // get hours (performs minutes-to-hour conversion also, just in case)
3834                     "mn = o.substring(3,5) % 60;", // get minutes
3835                 "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
3836             ].join("\n"),
3837             s: "([+\-]\\d{4})" // GMT offset in hrs and mins
3838         },
3839         P: {
3840             g:1,
3841             c:[
3842                 "o = results[{0}];",
3843                 "var sn = o.substring(0,1),", // get + / - sign
3844                     "hr = o.substring(1,3)*1 + Math.floor(o.substring(4,6) / 60),", // get hours (performs minutes-to-hour conversion also, just in case)
3845                     "mn = o.substring(4,6) % 60;", // get minutes
3846                 "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
3847             ].join("\n"),
3848             s: "([+\-]\\d{2}:\\d{2})" // GMT offset in hrs and mins (with colon separator)
3849         },
3850         T: {
3851             g:0,
3852             c:null,
3853             s:"[A-Z]{1,4}" // timezone abbrev. may be between 1 - 4 chars
3854         },
3855         Z: {
3856             g:1,
3857             c:"zz = results[{0}] * 1;\n" // -43200 <= UTC offset <= 50400
3858                   + "zz = (-43200 <= zz && zz <= 50400)? zz : null;\n",
3859             s:"([+\-]?\\d{1,5})" // leading '+' sign is optional for UTC offset
3860         },
3861         c: function() {
3862             var calc = [],
3863                 arr = [
3864                     utilDate.formatCodeToRegex("Y", 1), // year
3865                     utilDate.formatCodeToRegex("m", 2), // month
3866                     utilDate.formatCodeToRegex("d", 3), // day
3867                     utilDate.formatCodeToRegex("h", 4), // hour
3868                     utilDate.formatCodeToRegex("i", 5), // minute
3869                     utilDate.formatCodeToRegex("s", 6), // second
3870                     {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)
3871                     {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
3872                         "if(results[8]) {", // timezone specified
3873                             "if(results[8] == 'Z'){",
3874                                 "zz = 0;", // UTC
3875                             "}else if (results[8].indexOf(':') > -1){",
3876                                 utilDate.formatCodeToRegex("P", 8).c, // timezone offset with colon separator
3877                             "}else{",
3878                                 utilDate.formatCodeToRegex("O", 8).c, // timezone offset without colon separator
3879                             "}",
3880                         "}"
3881                     ].join('\n')}
3882                 ];
3883
3884             for (var i = 0, l = arr.length; i < l; ++i) {
3885                 calc.push(arr[i].c);
3886             }
3887
3888             return {
3889                 g:1,
3890                 c:calc.join(""),
3891                 s:[
3892                     arr[0].s, // year (required)
3893                     "(?:", "-", arr[1].s, // month (optional)
3894                         "(?:", "-", arr[2].s, // day (optional)
3895                             "(?:",
3896                                 "(?:T| )?", // time delimiter -- either a "T" or a single blank space
3897                                 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
3898                                 "(?::", arr[5].s, ")?", // seconds (optional)
3899                                 "(?:(?:\\.|,)(\\d+))?", // decimal fraction of a second (e.g. ",12345" or ".98765") (optional)
3900                                 "(Z|(?:[-+]\\d{2}(?::)?\\d{2}))?", // "Z" (UTC) or "-0530" (UTC offset without colon delimiter) or "+08:00" (UTC offset with colon delimiter) (optional)
3901                             ")?",
3902                         ")?",
3903                     ")?"
3904                 ].join("")
3905             };
3906         },
3907         U: {
3908             g:1,
3909             c:"u = parseInt(results[{0}], 10);\n",
3910             s:"(-?\\d+)" // leading minus sign indicates seconds before UNIX epoch
3911         }
3912     },
3913
3914     //Old Ext.Date prototype methods.
3915     // private
3916     dateFormat: function(date, format) {
3917         return utilDate.format(date, format);
3918     },
3919
3920     /**
3921      * Formats a date given the supplied format string.
3922      * @param {Date} date The date to format
3923      * @param {String} format The format string
3924      * @return {String} The formatted date
3925      */
3926     format: function(date, format) {
3927         if (utilDate.formatFunctions[format] == null) {
3928             utilDate.createFormat(format);
3929         }
3930         var result = utilDate.formatFunctions[format].call(date);
3931         return result + '';
3932     },
3933
3934     /**
3935      * Get the timezone abbreviation of the current date (equivalent to the format specifier 'T').
3936      *
3937      * Note: The date string returned by the javascript Date object's toString() method varies
3938      * between browsers (e.g. FF vs IE) and system region settings (e.g. IE in Asia vs IE in America).
3939      * For a given date string e.g. "Thu Oct 25 2007 22:55:35 GMT+0800 (Malay Peninsula Standard Time)",
3940      * getTimezone() first tries to get the timezone abbreviation from between a pair of parentheses
3941      * (which may or may not be present), failing which it proceeds to get the timezone abbreviation
3942      * from the GMT offset portion of the date string.
3943      * @param {Date} date The date
3944      * @return {String} The abbreviated timezone name (e.g. 'CST', 'PDT', 'EDT', 'MPST' ...).
3945      */
3946     getTimezone : function(date) {
3947         // the following list shows the differences between date strings from different browsers on a WinXP SP2 machine from an Asian locale:
3948         //
3949         // Opera  : "Thu, 25 Oct 2007 22:53:45 GMT+0800" -- shortest (weirdest) date string of the lot
3950         // 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)
3951         // FF     : "Thu Oct 25 2007 22:55:35 GMT+0800 (Malay Peninsula Standard Time)" -- value in parentheses always gives the correct timezone
3952         // IE     : "Thu Oct 25 22:54:35 UTC+0800 2007" -- (Asian system setting) look for 3-4 letter timezone abbrev
3953         // IE     : "Thu Oct 25 17:06:37 PDT 2007" -- (American system setting) look for 3-4 letter timezone abbrev
3954         //
3955         // this crazy regex attempts to guess the correct timezone abbreviation despite these differences.
3956         // step 1: (?:\((.*)\) -- find timezone in parentheses
3957         // 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
3958         // step 3: remove all non uppercase characters found in step 1 and 2
3959         return date.toString().replace(/^.* (?:\((.*)\)|([A-Z]{1,4})(?:[\-+][0-9]{4})?(?: -?\d+)?)$/, "$1$2").replace(/[^A-Z]/g, "");
3960     },
3961
3962     /**
3963      * Get the offset from GMT of the current date (equivalent to the format specifier 'O').
3964      * @param {Date} date The date
3965      * @param {Boolean} colon (optional) true to separate the hours and minutes with a colon (defaults to false).
3966      * @return {String} The 4-character offset string prefixed with + or - (e.g. '-0600').
3967      */
3968     getGMTOffset : function(date, colon) {
3969         var offset = date.getTimezoneOffset();
3970         return (offset > 0 ? "-" : "+")
3971             + Ext.String.leftPad(Math.floor(Math.abs(offset) / 60), 2, "0")
3972             + (colon ? ":" : "")
3973             + Ext.String.leftPad(Math.abs(offset % 60), 2, "0");
3974     },
3975
3976     /**
3977      * Get the numeric day number of the year, adjusted for leap year.
3978      * @param {Date} date The date
3979      * @return {Number} 0 to 364 (365 in leap years).
3980      */
3981     getDayOfYear: function(date) {
3982         var num = 0,
3983             d = Ext.Date.clone(date),
3984             m = date.getMonth(),
3985             i;
3986
3987         for (i = 0, d.setDate(1), d.setMonth(0); i < m; d.setMonth(++i)) {
3988             num += utilDate.getDaysInMonth(d);
3989         }
3990         return num + date.getDate() - 1;
3991     },
3992
3993     /**
3994      * Get the numeric ISO-8601 week number of the year.
3995      * (equivalent to the format specifier 'W', but without a leading zero).
3996      * @param {Date} date The date
3997      * @return {Number} 1 to 53
3998      */
3999     getWeekOfYear : (function() {
4000         // adapted from http://www.merlyn.demon.co.uk/weekcalc.htm
4001         var ms1d = 864e5, // milliseconds in a day
4002             ms7d = 7 * ms1d; // milliseconds in a week
4003
4004         return function(date) { // return a closure so constants get calculated only once
4005             var DC3 = Date.UTC(date.getFullYear(), date.getMonth(), date.getDate() + 3) / ms1d, // an Absolute Day Number
4006                 AWN = Math.floor(DC3 / 7), // an Absolute Week Number
4007                 Wyr = new Date(AWN * ms7d).getUTCFullYear();
4008
4009             return AWN - Math.floor(Date.UTC(Wyr, 0, 7) / ms7d) + 1;
4010         };
4011     })(),
4012
4013     /**
4014      * Checks if the current date falls within a leap year.
4015      * @param {Date} date The date
4016      * @return {Boolean} True if the current date falls within a leap year, false otherwise.
4017      */
4018     isLeapYear : function(date) {
4019         var year = date.getFullYear();
4020         return !!((year & 3) == 0 && (year % 100 || (year % 400 == 0 && year)));
4021     },
4022
4023     /**
4024      * Get the first day of the current month, adjusted for leap year.  The returned value
4025      * is the numeric day index within the week (0-6) which can be used in conjunction with
4026      * the {@link #monthNames} array to retrieve the textual day name.
4027      * Example:
4028      * <pre><code>
4029 var dt = new Date('1/10/2007'),
4030     firstDay = Ext.Date.getFirstDayOfMonth(dt);
4031 console.log(Ext.Date.dayNames[firstDay]); //output: 'Monday'
4032      * </code></pre>
4033      * @param {Date} date The date
4034      * @return {Number} The day number (0-6).
4035      */
4036     getFirstDayOfMonth : function(date) {
4037         var day = (date.getDay() - (date.getDate() - 1)) % 7;
4038         return (day < 0) ? (day + 7) : day;
4039     },
4040
4041     /**
4042      * Get the last day of the current month, adjusted for leap year.  The returned value
4043      * is the numeric day index within the week (0-6) which can be used in conjunction with
4044      * the {@link #monthNames} array to retrieve the textual day name.
4045      * Example:
4046      * <pre><code>
4047 var dt = new Date('1/10/2007'),
4048     lastDay = Ext.Date.getLastDayOfMonth(dt);
4049 console.log(Ext.Date.dayNames[lastDay]); //output: 'Wednesday'
4050      * </code></pre>
4051      * @param {Date} date The date
4052      * @return {Number} The day number (0-6).
4053      */
4054     getLastDayOfMonth : function(date) {
4055         return utilDate.getLastDateOfMonth(date).getDay();
4056     },
4057
4058
4059     /**
4060      * Get the date of the first day of the month in which this date resides.
4061      * @param {Date} date The date
4062      * @return {Date}
4063      */
4064     getFirstDateOfMonth : function(date) {
4065         return new Date(date.getFullYear(), date.getMonth(), 1);
4066     },
4067
4068     /**
4069      * Get the date of the last day of the month in which this date resides.
4070      * @param {Date} date The date
4071      * @return {Date}
4072      */
4073     getLastDateOfMonth : function(date) {
4074         return new Date(date.getFullYear(), date.getMonth(), utilDate.getDaysInMonth(date));
4075     },
4076
4077     /**
4078      * Get the number of days in the current month, adjusted for leap year.
4079      * @param {Date} date The date
4080      * @return {Number} The number of days in the month.
4081      */
4082     getDaysInMonth: (function() {
4083         var daysInMonth = [31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31];
4084
4085         return function(date) { // return a closure for efficiency
4086             var m = date.getMonth();
4087
4088             return m == 1 && utilDate.isLeapYear(date) ? 29 : daysInMonth[m];
4089         };
4090     })(),
4091
4092     /**
4093      * Get the English ordinal suffix of the current day (equivalent to the format specifier 'S').
4094      * @param {Date} date The date
4095      * @return {String} 'st, 'nd', 'rd' or 'th'.
4096      */
4097     getSuffix : function(date) {
4098         switch (date.getDate()) {
4099             case 1:
4100             case 21:
4101             case 31:
4102                 return "st";
4103             case 2:
4104             case 22:
4105                 return "nd";
4106             case 3:
4107             case 23:
4108                 return "rd";
4109             default:
4110                 return "th";
4111         }
4112     },
4113
4114     /**
4115      * Creates and returns a new Date instance with the exact same date value as the called instance.
4116      * Dates are copied and passed by reference, so if a copied date variable is modified later, the original
4117      * variable will also be changed.  When the intention is to create a new variable that will not
4118      * modify the original instance, you should create a clone.
4119      *
4120      * Example of correctly cloning a date:
4121      * <pre><code>
4122 //wrong way:
4123 var orig = new Date('10/1/2006');
4124 var copy = orig;
4125 copy.setDate(5);
4126 console.log(orig);  //returns 'Thu Oct 05 2006'!
4127
4128 //correct way:
4129 var orig = new Date('10/1/2006'),
4130     copy = Ext.Date.clone(orig);
4131 copy.setDate(5);
4132 console.log(orig);  //returns 'Thu Oct 01 2006'
4133      * </code></pre>
4134      * @param {Date} date The date
4135      * @return {Date} The new Date instance.
4136      */
4137     clone : function(date) {
4138         return new Date(date.getTime());
4139     },
4140
4141     /**
4142      * Checks if the current date is affected by Daylight Saving Time (DST).
4143      * @param {Date} date The date
4144      * @return {Boolean} True if the current date is affected by DST.
4145      */
4146     isDST : function(date) {
4147         // adapted from http://sencha.com/forum/showthread.php?p=247172#post247172
4148         // courtesy of @geoffrey.mcgill
4149         return new Date(date.getFullYear(), 0, 1).getTimezoneOffset() != date.getTimezoneOffset();
4150     },
4151
4152     /**
4153      * Attempts to clear all time information from this Date by setting the time to midnight of the same day,
4154      * automatically adjusting for Daylight Saving Time (DST) where applicable.
4155      * (note: DST timezone information for the browser's host operating system is assumed to be up-to-date)
4156      * @param {Date} date The date
4157      * @param {Boolean} clone true to create a clone of this date, clear the time and return it (defaults to false).
4158      * @return {Date} this or the clone.
4159      */
4160     clearTime : function(date, clone) {
4161         if (clone) {
4162             return Ext.Date.clearTime(Ext.Date.clone(date));
4163         }
4164
4165         // get current date before clearing time
4166         var d = date.getDate();
4167
4168         // clear time
4169         date.setHours(0);
4170         date.setMinutes(0);
4171         date.setSeconds(0);
4172         date.setMilliseconds(0);
4173
4174         if (date.getDate() != d) { // account for DST (i.e. day of month changed when setting hour = 0)
4175             // note: DST adjustments are assumed to occur in multiples of 1 hour (this is almost always the case)
4176             // refer to http://www.timeanddate.com/time/aboutdst.html for the (rare) exceptions to this rule
4177
4178             // increment hour until cloned date == current date
4179             for (var hr = 1, c = utilDate.add(date, Ext.Date.HOUR, hr); c.getDate() != d; hr++, c = utilDate.add(date, Ext.Date.HOUR, hr));
4180
4181             date.setDate(d);
4182             date.setHours(c.getHours());
4183         }
4184
4185         return date;
4186     },
4187
4188     /**
4189      * Provides a convenient method for performing basic date arithmetic. This method
4190      * does not modify the Date instance being called - it creates and returns
4191      * a new Date instance containing the resulting date value.
4192      *
4193      * Examples:
4194      * <pre><code>
4195 // Basic usage:
4196 var dt = Ext.Date.add(new Date('10/29/2006'), Ext.Date.DAY, 5);
4197 console.log(dt); //returns 'Fri Nov 03 2006 00:00:00'
4198
4199 // Negative values will be subtracted:
4200 var dt2 = Ext.Date.add(new Date('10/1/2006'), Ext.Date.DAY, -5);
4201 console.log(dt2); //returns 'Tue Sep 26 2006 00:00:00'
4202
4203      * </code></pre>
4204      *
4205      * @param {Date} date The date to modify
4206      * @param {String} interval A valid date interval enum value.
4207      * @param {Number} value The amount to add to the current date.
4208      * @return {Date} The new Date instance.
4209      */
4210     add : function(date, interval, value) {
4211         var d = Ext.Date.clone(date),
4212             Date = Ext.Date;
4213         if (!interval || value === 0) return d;
4214
4215         switch(interval.toLowerCase()) {
4216             case Ext.Date.MILLI:
4217                 d.setMilliseconds(d.getMilliseconds() + value);
4218                 break;
4219             case Ext.Date.SECOND:
4220                 d.setSeconds(d.getSeconds() + value);
4221                 break;
4222             case Ext.Date.MINUTE:
4223                 d.setMinutes(d.getMinutes() + value);
4224                 break;
4225             case Ext.Date.HOUR:
4226                 d.setHours(d.getHours() + value);
4227                 break;
4228             case Ext.Date.DAY:
4229                 d.setDate(d.getDate() + value);
4230                 break;
4231             case Ext.Date.MONTH:
4232                 var day = date.getDate();
4233                 if (day > 28) {
4234                     day = Math.min(day, Ext.Date.getLastDateOfMonth(Ext.Date.add(Ext.Date.getFirstDateOfMonth(date), 'mo', value)).getDate());
4235                 }
4236                 d.setDate(day);
4237                 d.setMonth(date.getMonth() + value);
4238                 break;
4239             case Ext.Date.YEAR:
4240                 d.setFullYear(date.getFullYear() + value);
4241                 break;
4242         }
4243         return d;
4244     },
4245
4246     /**
4247      * Checks if a date falls on or between the given start and end dates.
4248      * @param {Date} date The date to check
4249      * @param {Date} start Start date
4250      * @param {Date} end End date
4251      * @return {Boolean} true if this date falls on or between the given start and end dates.
4252      */
4253     between : function(date, start, end) {
4254         var t = date.getTime();
4255         return start.getTime() <= t && t <= end.getTime();
4256     },
4257
4258     //Maintains compatibility with old static and prototype window.Date methods.
4259     compat: function() {
4260         var nativeDate = window.Date,
4261             p, u,
4262             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'],
4263             proto = ['dateFormat', 'format', 'getTimezone', 'getGMTOffset', 'getDayOfYear', 'getWeekOfYear', 'isLeapYear', 'getFirstDayOfMonth', 'getLastDayOfMonth', 'getDaysInMonth', 'getSuffix', 'clone', 'isDST', 'clearTime', 'add', 'between'];
4264
4265         //Append statics
4266         Ext.Array.forEach(statics, function(s) {
4267             nativeDate[s] = utilDate[s];
4268         });
4269
4270         //Append to prototype
4271         Ext.Array.forEach(proto, function(s) {
4272             nativeDate.prototype[s] = function() {
4273                 var args = Array.prototype.slice.call(arguments);
4274                 args.unshift(this);
4275                 return utilDate[s].apply(utilDate, args);
4276             };
4277         });
4278     }
4279 };
4280
4281 var utilDate = Ext.Date;
4282
4283 })();
4284
4285 /**
4286  * @author Jacky Nguyen <jacky@sencha.com>
4287  * @docauthor Jacky Nguyen <jacky@sencha.com>
4288  * @class Ext.Base
4289  *
4290  * The root of all classes created with {@link Ext#define}
4291  * All prototype and static members of this class are inherited by any other class
4292  *
4293  */
4294 (function(flexSetter) {
4295
4296 var Base = Ext.Base = function() {};
4297     Base.prototype = {
4298         $className: 'Ext.Base',
4299
4300         $class: Base,
4301
4302         /**
4303          * Get the reference to the current class from which this object was instantiated. Unlike {@link Ext.Base#statics},
4304          * `this.self` is scope-dependent and it's meant to be used for dynamic inheritance. See {@link Ext.Base#statics}
4305          * for a detailed comparison
4306
4307     Ext.define('My.Cat', {
4308         statics: {
4309             speciesName: 'Cat' // My.Cat.speciesName = 'Cat'
4310         },
4311
4312         constructor: function() {
4313             alert(this.self.speciesName); / dependent on 'this'
4314
4315             return this;
4316         },
4317
4318         clone: function() {
4319             return new this.self();
4320         }
4321     });
4322
4323
4324     Ext.define('My.SnowLeopard', {
4325         extend: 'My.Cat',
4326         statics: {
4327             speciesName: 'Snow Leopard'         // My.SnowLeopard.speciesName = 'Snow Leopard'
4328         }
4329     });
4330
4331     var cat = new My.Cat();                     // alerts 'Cat'
4332     var snowLeopard = new My.SnowLeopard();     // alerts 'Snow Leopard'
4333
4334     var clone = snowLeopard.clone();
4335     alert(Ext.getClassName(clone));             // alerts 'My.SnowLeopard'
4336
4337          * @type Class
4338          * @protected
4339          * @markdown
4340          */
4341         self: Base,
4342
4343         /**
4344          * Default constructor, simply returns `this`
4345          *
4346          * @constructor
4347          * @protected
4348          * @return {Object} this
4349          */
4350         constructor: function() {
4351             return this;
4352         },
4353
4354         /**
4355          * Initialize configuration for this class. a typical example:
4356
4357     Ext.define('My.awesome.Class', {
4358         // The default config
4359         config: {
4360             name: 'Awesome',
4361             isAwesome: true
4362         },
4363
4364         constructor: function(config) {
4365             this.initConfig(config);
4366
4367             return this;
4368         }
4369     });
4370
4371     var awesome = new My.awesome.Class({
4372         name: 'Super Awesome'
4373     });
4374
4375     alert(awesome.getName()); // 'Super Awesome'
4376
4377          * @protected
4378          * @param {Object} config
4379          * @return {Object} mixins The mixin prototypes as key - value pairs
4380          * @markdown
4381          */
4382         initConfig: function(config) {
4383             if (!this.$configInited) {
4384                 this.config = Ext.Object.merge({}, this.config || {}, config || {});
4385
4386                 this.applyConfig(this.config);
4387
4388                 this.$configInited = true;
4389             }
4390
4391             return this;
4392         },
4393
4394         /**
4395          * @private
4396          */
4397         setConfig: function(config) {
4398             this.applyConfig(config || {});
4399
4400             return this;
4401         },
4402
4403         /**
4404          * @private
4405          */
4406         applyConfig: flexSetter(function(name, value) {
4407             var setter = 'set' + Ext.String.capitalize(name);
4408
4409             if (typeof this[setter] === 'function') {
4410                 this[setter].call(this, value);
4411             }
4412
4413             return this;
4414         }),
4415
4416         /**
4417          * Call the parent's overridden method. For example:
4418
4419     Ext.define('My.own.A', {
4420         constructor: function(test) {
4421             alert(test);
4422         }
4423     });
4424
4425     Ext.define('My.own.B', {
4426         extend: 'My.own.A',
4427
4428         constructor: function(test) {
4429             alert(test);
4430
4431             this.callParent([test + 1]);
4432         }
4433     });
4434
4435     Ext.define('My.own.C', {
4436         extend: 'My.own.B',
4437
4438         constructor: function() {
4439             alert("Going to call parent's overriden constructor...");
4440
4441             this.callParent(arguments);
4442         }
4443     });
4444
4445     var a = new My.own.A(1); // alerts '1'
4446     var b = new My.own.B(1); // alerts '1', then alerts '2'
4447     var c = new My.own.C(2); // alerts "Going to call parent's overriden constructor..."
4448                              // alerts '2', then alerts '3'
4449
4450          * @protected
4451          * @param {Array/Arguments} args The arguments, either an array or the `arguments` object
4452          * from the current method, for example: `this.callParent(arguments)`
4453          * @return {Mixed} Returns the result from the superclass' method
4454          * @markdown
4455          */
4456         callParent: function(args) {
4457             var method = this.callParent.caller,
4458                 parentClass, methodName;
4459
4460             if (!method.$owner) {
4461                 if (!method.caller) {
4462                     Ext.Error.raise({
4463                         sourceClass: Ext.getClassName(this),
4464                         sourceMethod: "callParent",
4465                         msg: "Attempting to call a protected method from the public scope, which is not allowed"
4466                     });
4467                 }
4468
4469                 method = method.caller;
4470             }
4471
4472             parentClass = method.$owner.superclass;
4473             methodName = method.$name;
4474
4475             if (!(methodName in parentClass)) {
4476                 Ext.Error.raise({
4477                     sourceClass: Ext.getClassName(this),
4478                     sourceMethod: methodName,
4479                     msg: "this.callParent() was called but there's no such method (" + methodName +
4480                          ") found in the parent class (" + (Ext.getClassName(parentClass) || 'Object') + ")"
4481                  });
4482             }
4483
4484             return parentClass[methodName].apply(this, args || []);
4485         },
4486
4487
4488         /**
4489          * Get the reference to the class from which this object was instantiated. Note that unlike {@link Ext.Base#self},
4490          * `this.statics()` is scope-independent and it always returns the class from which it was called, regardless of what
4491          * `this` points to during run-time
4492
4493     Ext.define('My.Cat', {
4494         statics: {
4495             totalCreated: 0,
4496             speciesName: 'Cat' // My.Cat.speciesName = 'Cat'
4497         },
4498
4499         constructor: function() {
4500             var statics = this.statics();
4501
4502             alert(statics.speciesName);     // always equals to 'Cat' no matter what 'this' refers to
4503                                             // equivalent to: My.Cat.speciesName
4504
4505             alert(this.self.speciesName);   // dependent on 'this'
4506
4507             statics.totalCreated++;
4508
4509             return this;
4510         },
4511
4512         clone: function() {
4513             var cloned = new this.self;                      // dependent on 'this'
4514
4515             cloned.groupName = this.statics().speciesName;   // equivalent to: My.Cat.speciesName
4516
4517             return cloned;
4518         }
4519     });
4520
4521
4522     Ext.define('My.SnowLeopard', {
4523         extend: 'My.Cat',
4524
4525         statics: {
4526             speciesName: 'Snow Leopard'     // My.SnowLeopard.speciesName = 'Snow Leopard'
4527         },
4528
4529         constructor: function() {
4530             this.callParent();
4531         }
4532     });
4533
4534     var cat = new My.Cat();                 // alerts 'Cat', then alerts 'Cat'
4535
4536     var snowLeopard = new My.SnowLeopard(); // alerts 'Cat', then alerts 'Snow Leopard'
4537
4538     var clone = snowLeopard.clone();
4539     alert(Ext.getClassName(clone));         // alerts 'My.SnowLeopard'
4540     alert(clone.groupName);                 // alerts 'Cat'
4541
4542     alert(My.Cat.totalCreated);             // alerts 3
4543
4544          * @protected
4545          * @return {Class}
4546          * @markdown
4547          */
4548         statics: function() {
4549             var method = this.statics.caller,
4550                 self = this.self;
4551
4552             if (!method) {
4553                 return self;
4554             }
4555
4556             return method.$owner;
4557         },
4558
4559         /**
4560          * Call the original method that was previously overridden with {@link Ext.Base#override}
4561
4562     Ext.define('My.Cat', {
4563         constructor: function() {
4564             alert("I'm a cat!");
4565
4566             return this;
4567         }
4568     });
4569
4570     My.Cat.override({
4571         constructor: function() {
4572             alert("I'm going to be a cat!");
4573
4574             var instance = this.callOverridden();
4575
4576             alert("Meeeeoooowwww");
4577
4578             return instance;
4579         }
4580     });
4581
4582     var kitty = new My.Cat(); // alerts "I'm going to be a cat!"
4583                               // alerts "I'm a cat!"
4584                               // alerts "Meeeeoooowwww"
4585
4586          * @param {Array/Arguments} args The arguments, either an array or the `arguments` object
4587          * @return {Mixed} Returns the result after calling the overridden method
4588          * @markdown
4589          */
4590         callOverridden: function(args) {
4591             var method = this.callOverridden.caller;
4592
4593             if (!method.$owner) {
4594                 Ext.Error.raise({
4595                     sourceClass: Ext.getClassName(this),
4596                     sourceMethod: "callOverridden",
4597                     msg: "Attempting to call a protected method from the public scope, which is not allowed"
4598                 });
4599             }
4600
4601             if (!method.$previous) {
4602                 Ext.Error.raise({
4603                     sourceClass: Ext.getClassName(this),
4604                     sourceMethod: "callOverridden",
4605                     msg: "this.callOverridden was called in '" + method.$name +
4606                          "' but this method has never been overridden"
4607                  });
4608             }
4609
4610             return method.$previous.apply(this, args || []);
4611         },
4612
4613         destroy: function() {}
4614     };
4615
4616     // These static properties will be copied to every newly created class with {@link Ext#define}
4617     Ext.apply(Ext.Base, {
4618         /**
4619          * Create a new instance of this Class.
4620 Ext.define('My.cool.Class', {
4621     ...
4622 });
4623
4624 My.cool.Class.create({
4625     someConfig: true
4626 });
4627          * @property create
4628          * @static
4629          * @type Function
4630          * @markdown
4631          */
4632         create: function() {
4633             return Ext.create.apply(Ext, [this].concat(Array.prototype.slice.call(arguments, 0)));
4634         },
4635
4636         /**
4637          * @private
4638          */
4639         own: flexSetter(function(name, value) {
4640             if (typeof value === 'function') {
4641                 this.ownMethod(name, value);
4642             }
4643             else {
4644                 this.prototype[name] = value;
4645             }
4646         }),
4647
4648         /**
4649          * @private
4650          */
4651         ownMethod: function(name, fn) {
4652             var originalFn;
4653
4654             if (fn.$owner !== undefined && fn !== Ext.emptyFn) {
4655                 originalFn = fn;
4656
4657                 fn = function() {
4658                     return originalFn.apply(this, arguments);
4659                 };
4660             }
4661
4662             var className;
4663             className = Ext.getClassName(this);
4664             if (className) {
4665                 fn.displayName = className + '#' + name;
4666             }
4667             fn.$owner = this;
4668             fn.$name = name;
4669
4670             this.prototype[name] = fn;
4671         },
4672
4673         /**
4674          * Add / override static properties of this class.
4675
4676     Ext.define('My.cool.Class', {
4677         ...
4678     });
4679
4680     My.cool.Class.addStatics({
4681         someProperty: 'someValue',      // My.cool.Class.someProperty = 'someValue'
4682         method1: function() { ... },    // My.cool.Class.method1 = function() { ... };
4683         method2: function() { ... }     // My.cool.Class.method2 = function() { ... };
4684     });
4685
4686          * @property addStatics
4687          * @static
4688          * @type Function
4689          * @param {Object} members
4690          * @markdown
4691          */
4692         addStatics: function(members) {
4693             for (var name in members) {
4694                 if (members.hasOwnProperty(name)) {
4695                     this[name] = members[name];
4696                 }
4697             }
4698
4699             return this;
4700         },
4701
4702         /**
4703          * Add methods / properties to the prototype of this class.
4704
4705     Ext.define('My.awesome.Cat', {
4706         constructor: function() {
4707             ...
4708         }
4709     });
4710
4711      My.awesome.Cat.implement({
4712          meow: function() {
4713             alert('Meowww...');
4714          }
4715      });
4716
4717      var kitty = new My.awesome.Cat;
4718      kitty.meow();
4719
4720          * @property implement
4721          * @static
4722          * @type Function
4723          * @param {Object} members
4724          * @markdown
4725          */
4726         implement: function(members) {
4727             var prototype = this.prototype,
4728                 name, i, member, previous;
4729             var className = Ext.getClassName(this);
4730             for (name in members) {
4731                 if (members.hasOwnProperty(name)) {
4732                     member = members[name];
4733
4734                     if (typeof member === 'function') {
4735                         member.$owner = this;
4736                         member.$name = name;
4737                         if (className) {
4738                             member.displayName = className + '#' + name;
4739                         }
4740                     }
4741
4742                     prototype[name] = member;
4743                 }
4744             }
4745
4746             if (Ext.enumerables) {
4747                 var enumerables = Ext.enumerables;
4748
4749                 for (i = enumerables.length; i--;) {
4750                     name = enumerables[i];
4751
4752                     if (members.hasOwnProperty(name)) {
4753                         member = members[name];
4754                         member.$owner = this;
4755                         member.$name = name;
4756                         prototype[name] = member;
4757                     }
4758                 }
4759             }
4760         },
4761
4762         /**
4763          * Borrow another class' members to the prototype of this class.
4764
4765 Ext.define('Bank', {
4766     money: '$$$',
4767     printMoney: function() {
4768         alert('$$$$$$$');
4769     }
4770 });
4771
4772 Ext.define('Thief', {
4773     ...
4774 });
4775
4776 Thief.borrow(Bank, ['money', 'printMoney']);
4777
4778 var steve = new Thief();
4779
4780 alert(steve.money); // alerts '$$$'
4781 steve.printMoney(); // alerts '$$$$$$$'
4782
4783          * @property borrow
4784          * @static
4785          * @type Function
4786          * @param {Ext.Base} fromClass The class to borrow members from
4787          * @param {Array/String} members The names of the members to borrow
4788          * @return {Ext.Base} this
4789          * @markdown
4790          */
4791         borrow: function(fromClass, members) {
4792             var fromPrototype = fromClass.prototype,
4793                 i, ln, member;
4794
4795             members = Ext.Array.from(members);
4796
4797             for (i = 0, ln = members.length; i < ln; i++) {
4798                 member = members[i];
4799
4800                 this.own(member, fromPrototype[member]);
4801             }
4802
4803             return this;
4804         },
4805
4806         /**
4807          * Override prototype members of this class. Overridden methods can be invoked via
4808          * {@link Ext.Base#callOverridden}
4809
4810     Ext.define('My.Cat', {
4811         constructor: function() {
4812             alert("I'm a cat!");
4813
4814             return this;
4815         }
4816     });
4817
4818     My.Cat.override({
4819         constructor: function() {
4820             alert("I'm going to be a cat!");
4821
4822             var instance = this.callOverridden();
4823
4824             alert("Meeeeoooowwww");
4825
4826             return instance;
4827         }
4828     });
4829
4830     var kitty = new My.Cat(); // alerts "I'm going to be a cat!"
4831                               // alerts "I'm a cat!"
4832                               // alerts "Meeeeoooowwww"
4833
4834          * @property override
4835          * @static
4836          * @type Function
4837          * @param {Object} members
4838          * @return {Ext.Base} this
4839          * @markdown
4840          */
4841         override: function(members) {
4842             var prototype = this.prototype,
4843                 name, i, member, previous;
4844
4845             for (name in members) {
4846                 if (members.hasOwnProperty(name)) {
4847                     member = members[name];
4848
4849                     if (typeof member === 'function') {
4850                         if (typeof prototype[name] === 'function') {
4851                             previous = prototype[name];
4852                             member.$previous = previous;
4853                         }
4854
4855                         this.ownMethod(name, member);
4856                     }
4857                     else {
4858                         prototype[name] = member;
4859                     }
4860                 }
4861             }
4862
4863             if (Ext.enumerables) {
4864                 var enumerables = Ext.enumerables;
4865
4866                 for (i = enumerables.length; i--;) {
4867                     name = enumerables[i];
4868
4869                     if (members.hasOwnProperty(name)) {
4870                         if (prototype[name] !== undefined) {
4871                             previous = prototype[name];
4872                             members[name].$previous = previous;
4873                         }
4874
4875                         this.ownMethod(name, members[name]);
4876                     }
4877                 }
4878             }
4879
4880             return this;
4881         },
4882
4883         /**
4884          * Used internally by the mixins pre-processor
4885          * @private
4886          */
4887         mixin: flexSetter(function(name, cls) {
4888             var mixin = cls.prototype,
4889                 my = this.prototype,
4890                 i, fn;
4891
4892             for (i in mixin) {
4893                 if (mixin.hasOwnProperty(i)) {
4894                     if (my[i] === undefined) {
4895                         if (typeof mixin[i] === 'function') {
4896                             fn = mixin[i];
4897
4898                             if (fn.$owner === undefined) {
4899                                 this.ownMethod(i, fn);
4900                             }
4901                             else {
4902                                 my[i] = fn;
4903                             }
4904                         }
4905                         else {
4906                             my[i] = mixin[i];
4907                         }
4908                     }
4909                     else if (i === 'config' && my.config && mixin.config) {
4910                         Ext.Object.merge(my.config, mixin.config);
4911                     }
4912                 }
4913             }
4914
4915             if (my.mixins === undefined) {
4916                 my.mixins = {};
4917             }
4918
4919             my.mixins[name] = mixin;
4920         }),
4921
4922         /**
4923          * Get the current class' name in string format.
4924
4925     Ext.define('My.cool.Class', {
4926         constructor: function() {
4927             alert(this.self.getName()); // alerts 'My.cool.Class'
4928         }
4929     });
4930
4931     My.cool.Class.getName(); // 'My.cool.Class'
4932
4933          * @return {String} className
4934          * @markdown
4935          */
4936         getName: function() {
4937             return Ext.getClassName(this);
4938         },
4939
4940         /**
4941          * Create aliases for existing prototype methods. Example:
4942
4943     Ext.define('My.cool.Class', {
4944         method1: function() { ... },
4945         method2: function() { ... }
4946     });
4947
4948     var test = new My.cool.Class();
4949
4950     My.cool.Class.createAlias({
4951         method3: 'method1',
4952         method4: 'method2'
4953     });
4954
4955     test.method3(); // test.method1()
4956
4957     My.cool.Class.createAlias('method5', 'method3');
4958
4959     test.method5(); // test.method3() -> test.method1()
4960
4961          * @property createAlias
4962          * @static
4963          * @type Function
4964          * @param {String/Object} alias The new method name, or an object to set multiple aliases. See
4965          * {@link Ext.Function#flexSetter flexSetter}
4966          * @param {String/Object} origin The original method name
4967          * @markdown
4968          */
4969         createAlias: flexSetter(function(alias, origin) {
4970             this.prototype[alias] = this.prototype[origin];
4971         })
4972     });
4973
4974 })(Ext.Function.flexSetter);
4975
4976 /**
4977  * @author Jacky Nguyen <jacky@sencha.com>
4978  * @docauthor Jacky Nguyen <jacky@sencha.com>
4979  * @class Ext.Class
4980  * 
4981  * Handles class creation throughout the whole framework. Note that most of the time {@link Ext#define Ext.define} should
4982  * be used instead, since it's a higher level wrapper that aliases to {@link Ext.ClassManager#create}
4983  * to enable namespacing and dynamic dependency resolution.
4984  * 
4985  * # Basic syntax: #
4986  * 
4987  *     Ext.define(className, properties);
4988  * 
4989  * in which `properties` is an object represent a collection of properties that apply to the class. See
4990  * {@link Ext.ClassManager#create} for more detailed instructions.
4991  * 
4992  *     Ext.define('Person', {
4993  *          name: 'Unknown',
4994  * 
4995  *          constructor: function(name) {
4996  *              if (name) {
4997  *                  this.name = name;
4998  *              }
4999  * 
5000  *              return this;
5001  *          },
5002  * 
5003  *          eat: function(foodType) {
5004  *              alert("I'm eating: " + foodType);
5005  * 
5006  *              return this;
5007  *          }
5008  *     });
5009  * 
5010  *     var aaron = new Person("Aaron");
5011  *     aaron.eat("Sandwich"); // alert("I'm eating: Sandwich");
5012  * 
5013  * Ext.Class has a powerful set of extensible {@link Ext.Class#registerPreprocessor pre-processors} which takes care of
5014  * everything related to class creation, including but not limited to inheritance, mixins, configuration, statics, etc.
5015  * 
5016  * # Inheritance: #
5017  * 
5018  *     Ext.define('Developer', {
5019  *          extend: 'Person',
5020  * 
5021  *          constructor: function(name, isGeek) {
5022  *              this.isGeek = isGeek;
5023  * 
5024  *              // Apply a method from the parent class' prototype
5025  *              this.callParent([name]);
5026  * 
5027  *              return this;
5028  * 
5029  *          },
5030  * 
5031  *          code: function(language) {
5032  *              alert("I'm coding in: " + language);
5033  * 
5034  *              this.eat("Bugs");
5035  * 
5036  *              return this;
5037  *          }
5038  *     });
5039  * 
5040  *     var jacky = new Developer("Jacky", true);
5041  *     jacky.code("JavaScript"); // alert("I'm coding in: JavaScript");
5042  *                               // alert("I'm eating: Bugs");
5043  * 
5044  * See {@link Ext.Base#callParent} for more details on calling superclass' methods
5045  * 
5046  * # Mixins: #
5047  * 
5048  *     Ext.define('CanPlayGuitar', {
5049  *          playGuitar: function() {
5050  *             alert("F#...G...D...A");
5051  *          }
5052  *     });
5053  * 
5054  *     Ext.define('CanComposeSongs', {
5055  *          composeSongs: function() { ... }
5056  *     });
5057  * 
5058  *     Ext.define('CanSing', {
5059  *          sing: function() {
5060  *              alert("I'm on the highway to hell...")
5061  *          }
5062  *     });
5063  * 
5064  *     Ext.define('Musician', {
5065  *          extend: 'Person',
5066  * 
5067  *          mixins: {
5068  *              canPlayGuitar: 'CanPlayGuitar',
5069  *              canComposeSongs: 'CanComposeSongs',
5070  *              canSing: 'CanSing'
5071  *          }
5072  *     })
5073  * 
5074  *     Ext.define('CoolPerson', {
5075  *          extend: 'Person',
5076  * 
5077  *          mixins: {
5078  *              canPlayGuitar: 'CanPlayGuitar',
5079  *              canSing: 'CanSing'
5080  *          },
5081  * 
5082  *          sing: function() {
5083  *              alert("Ahem....");
5084  * 
5085  *              this.mixins.canSing.sing.call(this);
5086  * 
5087  *              alert("[Playing guitar at the same time...]");
5088  * 
5089  *              this.playGuitar();
5090  *          }
5091  *     });
5092  * 
5093  *     var me = new CoolPerson("Jacky");
5094  * 
5095  *     me.sing(); // alert("Ahem...");
5096  *                // alert("I'm on the highway to hell...");
5097  *                // alert("[Playing guitar at the same time...]");
5098  *                // alert("F#...G...D...A");
5099  * 
5100  * # Config: #
5101  * 
5102  *     Ext.define('SmartPhone', {
5103  *          config: {
5104  *              hasTouchScreen: false,
5105  *              operatingSystem: 'Other',
5106  *              price: 500
5107  *          },
5108  * 
5109  *          isExpensive: false,
5110  * 
5111  *          constructor: function(config) {
5112  *              this.initConfig(config);
5113  * 
5114  *              return this;
5115  *          },
5116  * 
5117  *          applyPrice: function(price) {
5118  *              this.isExpensive = (price > 500);
5119  * 
5120  *              return price;
5121  *          },
5122  * 
5123  *          applyOperatingSystem: function(operatingSystem) {
5124  *              if (!(/^(iOS|Android|BlackBerry)$/i).test(operatingSystem)) {
5125  *                  return 'Other';
5126  *              }
5127  * 
5128  *              return operatingSystem;
5129  *          }
5130  *     });
5131  * 
5132  *     var iPhone = new SmartPhone({
5133  *          hasTouchScreen: true,
5134  *          operatingSystem: 'iOS'
5135  *     });
5136  * 
5137  *     iPhone.getPrice(); // 500;
5138  *     iPhone.getOperatingSystem(); // 'iOS'
5139  *     iPhone.getHasTouchScreen(); // true;
5140  *     iPhone.hasTouchScreen(); // true
5141  * 
5142  *     iPhone.isExpensive; // false;
5143  *     iPhone.setPrice(600);
5144  *     iPhone.getPrice(); // 600
5145  *     iPhone.isExpensive; // true;
5146  * 
5147  *     iPhone.setOperatingSystem('AlienOS');
5148  *     iPhone.getOperatingSystem(); // 'Other'
5149  * 
5150  * # Statics: #
5151  * 
5152  *     Ext.define('Computer', {
5153  *          statics: {
5154  *              factory: function(brand) {
5155  *                 // 'this' in static methods refer to the class itself
5156  *                  return new this(brand);
5157  *              }
5158  *          },
5159  * 
5160  *          constructor: function() { ... }
5161  *     });
5162  * 
5163  *     var dellComputer = Computer.factory('Dell');
5164  * 
5165  * Also see {@link Ext.Base#statics} and {@link Ext.Base#self} for more details on accessing
5166  * static properties within class methods
5167  *
5168  */
5169 (function() {
5170
5171     var Class,
5172         Base = Ext.Base,
5173         baseStaticProperties = [],
5174         baseStaticProperty;
5175
5176     for (baseStaticProperty in Base) {
5177         if (Base.hasOwnProperty(baseStaticProperty)) {
5178             baseStaticProperties.push(baseStaticProperty);
5179         }
5180     }
5181
5182     /**
5183      * @constructor
5184      * @param {Object} classData An object represent the properties of this class
5185      * @param {Function} createdFn Optional, the callback function to be executed when this class is fully created.
5186      * Note that the creation process can be asynchronous depending on the pre-processors used.
5187      * @return {Ext.Base} The newly created class
5188      */
5189     Ext.Class = Class = function(newClass, classData, onClassCreated) {
5190         if (typeof newClass !== 'function') {
5191             onClassCreated = classData;
5192             classData = newClass;
5193             newClass = function() {
5194                 return this.constructor.apply(this, arguments);
5195             };
5196         }
5197
5198         if (!classData) {
5199             classData = {};
5200         }
5201
5202         var preprocessorStack = classData.preprocessors || Class.getDefaultPreprocessors(),
5203             registeredPreprocessors = Class.getPreprocessors(),
5204             index = 0,
5205             preprocessors = [],
5206             preprocessor, preprocessors, staticPropertyName, process, i, j, ln;
5207
5208         for (i = 0, ln = baseStaticProperties.length; i < ln; i++) {
5209             staticPropertyName = baseStaticProperties[i];
5210             newClass[staticPropertyName] = Base[staticPropertyName];
5211         }
5212
5213         delete classData.preprocessors;
5214
5215         for (j = 0, ln = preprocessorStack.length; j < ln; j++) {
5216             preprocessor = preprocessorStack[j];
5217
5218             if (typeof preprocessor === 'string') {
5219                 preprocessor = registeredPreprocessors[preprocessor];
5220
5221                 if (!preprocessor.always) {
5222                     if (classData.hasOwnProperty(preprocessor.name)) {
5223                         preprocessors.push(preprocessor.fn);
5224                     }
5225                 }
5226                 else {
5227                     preprocessors.push(preprocessor.fn);
5228                 }
5229             }
5230             else {
5231                 preprocessors.push(preprocessor);
5232             }
5233         }
5234
5235         classData.onClassCreated = onClassCreated;
5236
5237         classData.onBeforeClassCreated = function(cls, data) {
5238             onClassCreated = data.onClassCreated;
5239
5240             delete data.onBeforeClassCreated;
5241             delete data.onClassCreated;
5242
5243             cls.implement(data);
5244
5245             if (onClassCreated) {
5246                 onClassCreated.call(cls, cls);
5247             }
5248         };
5249
5250         process = function(cls, data) {
5251             preprocessor = preprocessors[index++];
5252
5253             if (!preprocessor) {
5254                 data.onBeforeClassCreated.apply(this, arguments);
5255                 return;
5256             }
5257
5258             if (preprocessor.call(this, cls, data, process) !== false) {
5259                 process.apply(this, arguments);
5260             }
5261         };
5262
5263         process.call(Class, newClass, classData);
5264
5265         return newClass;
5266     };
5267
5268     Ext.apply(Class, {
5269
5270         /** @private */
5271         preprocessors: {},
5272
5273         /**
5274          * Register a new pre-processor to be used during the class creation process
5275          *
5276          * @member Ext.Class registerPreprocessor
5277          * @param {String} name The pre-processor's name
5278          * @param {Function} fn The callback function to be executed. Typical format:
5279
5280     function(cls, data, fn) {
5281         // Your code here
5282
5283         // Execute this when the processing is finished.
5284         // Asynchronous processing is perfectly ok
5285         if (fn) {
5286             fn.call(this, cls, data);
5287         }
5288     });
5289
5290          * Passed arguments for this function are:
5291          *
5292          * - `{Function} cls`: The created class
5293          * - `{Object} data`: The set of properties passed in {@link Ext.Class} constructor
5294          * - `{Function} fn`: The callback function that <b>must</b> to be executed when this pre-processor finishes,
5295          * regardless of whether the processing is synchronous or aynchronous
5296          *
5297          * @return {Ext.Class} this
5298          * @markdown
5299          */
5300         registerPreprocessor: function(name, fn, always) {
5301             this.preprocessors[name] = {
5302                 name: name,
5303                 always: always ||  false,
5304                 fn: fn
5305             };
5306
5307             return this;
5308         },
5309
5310         /**
5311          * Retrieve a pre-processor callback function by its name, which has been registered before
5312          *
5313          * @param {String} name
5314          * @return {Function} preprocessor
5315          */
5316         getPreprocessor: function(name) {
5317             return this.preprocessors[name];
5318         },
5319
5320         getPreprocessors: function() {
5321             return this.preprocessors;
5322         },
5323
5324         /**
5325          * Retrieve the array stack of default pre-processors
5326          *
5327          * @return {Function} defaultPreprocessors
5328          */
5329         getDefaultPreprocessors: function() {
5330             return this.defaultPreprocessors || [];
5331         },
5332
5333         /**
5334          * Set the default array stack of default pre-processors
5335          *
5336          * @param {Array} preprocessors
5337          * @return {Ext.Class} this
5338          */
5339         setDefaultPreprocessors: function(preprocessors) {
5340             this.defaultPreprocessors = Ext.Array.from(preprocessors);
5341
5342             return this;
5343         },
5344
5345         /**
5346          * Insert this pre-processor at a specific position in the stack, optionally relative to
5347          * any existing pre-processor. For example:
5348
5349     Ext.Class.registerPreprocessor('debug', function(cls, data, fn) {
5350         // Your code here
5351
5352         if (fn) {
5353             fn.call(this, cls, data);
5354         }
5355     }).insertDefaultPreprocessor('debug', 'last');
5356
5357          * @param {String} name The pre-processor name. Note that it needs to be registered with
5358          * {@link Ext#registerPreprocessor registerPreprocessor} before this
5359          * @param {String} offset The insertion position. Four possible values are:
5360          * 'first', 'last', or: 'before', 'after' (relative to the name provided in the third argument)
5361          * @param {String} relativeName
5362          * @return {Ext.Class} this
5363          * @markdown
5364          */
5365         setDefaultPreprocessorPosition: function(name, offset, relativeName) {
5366             var defaultPreprocessors = this.defaultPreprocessors,
5367                 index;
5368
5369             if (typeof offset === 'string') {
5370                 if (offset === 'first') {
5371                     defaultPreprocessors.unshift(name);
5372
5373                     return this;
5374                 }
5375                 else if (offset === 'last') {
5376                     defaultPreprocessors.push(name);
5377
5378                     return this;
5379                 }
5380
5381                 offset = (offset === 'after') ? 1 : -1;
5382             }
5383
5384             index = Ext.Array.indexOf(defaultPreprocessors, relativeName);
5385
5386             if (index !== -1) {
5387                 defaultPreprocessors.splice(Math.max(0, index + offset), 0, name);
5388             }
5389
5390             return this;
5391         }
5392     });
5393
5394     Class.registerPreprocessor('extend', function(cls, data) {
5395         var extend = data.extend,
5396             base = Ext.Base,
5397             basePrototype = base.prototype,
5398             prototype = function() {},
5399             parent, i, k, ln, staticName, parentStatics,
5400             parentPrototype, clsPrototype;
5401
5402         if (extend && extend !== Object) {
5403             parent = extend;
5404         }
5405         else {
5406             parent = base;
5407         }
5408
5409         parentPrototype = parent.prototype;
5410
5411         prototype.prototype = parentPrototype;
5412         clsPrototype = cls.prototype = new prototype();
5413
5414         if (!('$class' in parent)) {
5415             for (i in basePrototype) {
5416                 if (!parentPrototype[i]) {
5417                     parentPrototype[i] = basePrototype[i];
5418                 }
5419             }
5420         }
5421
5422         clsPrototype.self = cls;
5423
5424         cls.superclass = clsPrototype.superclass = parentPrototype;
5425
5426         delete data.extend;
5427
5428         // Statics inheritance
5429         parentStatics = parentPrototype.$inheritableStatics;
5430
5431         if (parentStatics) {
5432             for (k = 0, ln = parentStatics.length; k < ln; k++) {
5433                 staticName = parentStatics[k];
5434
5435                 if (!cls.hasOwnProperty(staticName)) {
5436                     cls[staticName] = parent[staticName];
5437                 }
5438             }
5439         }
5440
5441         // Merge the parent class' config object without referencing it
5442         if (parentPrototype.config) {
5443             clsPrototype.config = Ext.Object.merge({}, parentPrototype.config);
5444         }
5445         else {
5446             clsPrototype.config = {};
5447         }
5448
5449         if (clsPrototype.$onExtended) {
5450             clsPrototype.$onExtended.call(cls, cls, data);
5451         }
5452
5453         if (data.onClassExtended) {
5454             clsPrototype.$onExtended = data.onClassExtended;
5455             delete data.onClassExtended;
5456         }
5457
5458     }, true);
5459
5460     Class.registerPreprocessor('statics', function(cls, data) {
5461         var statics = data.statics,
5462             name;
5463
5464         for (name in statics) {
5465             if (statics.hasOwnProperty(name)) {
5466                 cls[name] = statics[name];
5467             }
5468         }
5469
5470         delete data.statics;
5471     });
5472
5473     Class.registerPreprocessor('inheritableStatics', function(cls, data) {
5474         var statics = data.inheritableStatics,
5475             inheritableStatics,
5476             prototype = cls.prototype,
5477             name;
5478
5479         inheritableStatics = prototype.$inheritableStatics;
5480
5481         if (!inheritableStatics) {
5482             inheritableStatics = prototype.$inheritableStatics = [];
5483         }
5484
5485         for (name in statics) {
5486             if (statics.hasOwnProperty(name)) {
5487                 cls[name] = statics[name];
5488                 inheritableStatics.push(name);
5489             }
5490         }
5491
5492         delete data.inheritableStatics;
5493     });
5494
5495     Class.registerPreprocessor('mixins', function(cls, data) {
5496         cls.mixin(data.mixins);
5497
5498         delete data.mixins;
5499     });
5500
5501     Class.registerPreprocessor('config', function(cls, data) {
5502         var prototype = cls.prototype;
5503
5504         Ext.Object.each(data.config, function(name) {
5505             var cName = name.charAt(0).toUpperCase() + name.substr(1),
5506                 pName = name,
5507                 apply = 'apply' + cName,
5508                 setter = 'set' + cName,
5509                 getter = 'get' + cName;
5510
5511             if (!(apply in prototype) && !data.hasOwnProperty(apply)) {
5512                 data[apply] = function(val) {
5513                     return val;
5514                 };
5515             }
5516
5517             if (!(setter in prototype) && !data.hasOwnProperty(setter)) {
5518                 data[setter] = function(val) {
5519                     var ret = this[apply].call(this, val, this[pName]);
5520
5521                     if (ret !== undefined) {
5522                         this[pName] = ret;
5523                     }
5524
5525                     return this;
5526                 };
5527             }
5528
5529             if (!(getter in prototype) && !data.hasOwnProperty(getter)) {
5530                 data[getter] = function() {
5531                     return this[pName];
5532                 };
5533             }
5534         });
5535
5536         Ext.Object.merge(prototype.config, data.config);
5537         delete data.config;
5538     });
5539
5540     Class.setDefaultPreprocessors(['extend', 'statics', 'inheritableStatics', 'mixins', 'config']);
5541
5542     // Backwards compatible
5543     Ext.extend = function(subclass, superclass, members) {
5544         if (arguments.length === 2 && Ext.isObject(superclass)) {
5545             members = superclass;
5546             superclass = subclass;
5547             subclass = null;
5548         }
5549
5550         var cls;
5551
5552         if (!superclass) {
5553             Ext.Error.raise("Attempting to extend from a class which has not been loaded on the page.");
5554         }
5555
5556         members.extend = superclass;
5557         members.preprocessors = ['extend', 'mixins', 'config', 'statics'];
5558
5559         if (subclass) {
5560             cls = new Class(subclass, members);
5561         }
5562         else {
5563             cls = new Class(members);
5564         }
5565
5566         cls.prototype.override = function(o) {
5567             for (var m in o) {
5568                 if (o.hasOwnProperty(m)) {
5569                     this[m] = o[m];
5570                 }
5571             }
5572         };
5573
5574         return cls;
5575     };
5576
5577 })();
5578
5579 /**
5580  * @author Jacky Nguyen <jacky@sencha.com>
5581  * @docauthor Jacky Nguyen <jacky@sencha.com>
5582  * @class Ext.ClassManager
5583
5584 Ext.ClassManager manages all classes and handles mapping from string class name to
5585 actual class objects throughout the whole framework. It is not generally accessed directly, rather through
5586 these convenient shorthands:
5587
5588 - {@link Ext#define Ext.define}
5589 - {@link Ext#create Ext.create}
5590 - {@link Ext#widget Ext.widget}
5591 - {@link Ext#getClass Ext.getClass}
5592 - {@link Ext#getClassName Ext.getClassName}
5593
5594  * @singleton
5595  * @markdown
5596  */
5597 (function(Class, alias) {
5598
5599     var slice = Array.prototype.slice;
5600
5601     var Manager = Ext.ClassManager = {
5602
5603         /**
5604          * @property classes
5605          * @type Object
5606          * All classes which were defined through the ClassManager. Keys are the
5607          * name of the classes and the values are references to the classes.
5608          * @private
5609          */
5610         classes: {},
5611
5612         /**
5613          * @private
5614          */
5615         existCache: {},
5616
5617         /**
5618          * @private
5619          */
5620         namespaceRewrites: [{
5621             from: 'Ext.',
5622             to: Ext
5623         }],
5624
5625         /**
5626          * @private
5627          */
5628         maps: {
5629             alternateToName: {},
5630             aliasToName: {},
5631             nameToAliases: {}
5632         },
5633
5634         /** @private */
5635         enableNamespaceParseCache: true,
5636
5637         /** @private */
5638         namespaceParseCache: {},
5639
5640         /** @private */
5641         instantiators: [],
5642
5643         /** @private */
5644         instantiationCounts: {},
5645
5646         /**
5647          * Checks if a class has already been created.
5648          *
5649          * @param {String} className
5650          * @return {Boolean} exist
5651          */
5652         isCreated: function(className) {
5653             var i, ln, part, root, parts;
5654
5655             if (typeof className !== 'string' || className.length < 1) {
5656                 Ext.Error.raise({
5657                     sourceClass: "Ext.ClassManager",
5658                     sourceMethod: "exist",
5659                     msg: "Invalid classname, must be a string and must not be empty"
5660                 });
5661             }
5662
5663             if (this.classes.hasOwnProperty(className) || this.existCache.hasOwnProperty(className)) {
5664                 return true;
5665             }
5666
5667             root = Ext.global;
5668             parts = this.parseNamespace(className);
5669
5670             for (i = 0, ln = parts.length; i < ln; i++) {
5671                 part = parts[i];
5672
5673                 if (typeof part !== 'string') {
5674                     root = part;
5675                 } else {
5676                     if (!root || !root[part]) {
5677                         return false;
5678                     }
5679
5680                     root = root[part];
5681                 }
5682             }
5683
5684             Ext.Loader.historyPush(className);
5685
5686             this.existCache[className] = true;
5687
5688             return true;
5689         },
5690
5691         /**
5692          * Supports namespace rewriting
5693          * @private
5694          */
5695         parseNamespace: function(namespace) {
5696             if (typeof namespace !== 'string') {
5697                 Ext.Error.raise({
5698                     sourceClass: "Ext.ClassManager",
5699                     sourceMethod: "parseNamespace",
5700                     msg: "Invalid namespace, must be a string"
5701                 });
5702             }
5703
5704             var cache = this.namespaceParseCache;
5705
5706             if (this.enableNamespaceParseCache) {
5707                 if (cache.hasOwnProperty(namespace)) {
5708                     return cache[namespace];
5709                 }
5710             }
5711
5712             var parts = [],
5713                 rewrites = this.namespaceRewrites,
5714                 rewrite, from, to, i, ln, root = Ext.global;
5715
5716             for (i = 0, ln = rewrites.length; i < ln; i++) {
5717                 rewrite = rewrites[i];
5718                 from = rewrite.from;
5719                 to = rewrite.to;
5720
5721                 if (namespace === from || namespace.substring(0, from.length) === from) {
5722                     namespace = namespace.substring(from.length);
5723
5724                     if (typeof to !== 'string') {
5725                         root = to;
5726                     } else {
5727                         parts = parts.concat(to.split('.'));
5728                     }
5729
5730                     break;
5731                 }
5732             }
5733
5734             parts.push(root);
5735
5736             parts = parts.concat(namespace.split('.'));
5737
5738             if (this.enableNamespaceParseCache) {
5739                 cache[namespace] = parts;
5740             }
5741
5742             return parts;
5743         },
5744
5745         /**
5746          * Creates a namespace and assign the `value` to the created object
5747
5748     Ext.ClassManager.setNamespace('MyCompany.pkg.Example', someObject);
5749
5750     alert(MyCompany.pkg.Example === someObject); // alerts true
5751
5752          * @param {String} name
5753          * @param {Mixed} value
5754          * @markdown
5755          */
5756         setNamespace: function(name, value) {
5757             var root = Ext.global,
5758                 parts = this.parseNamespace(name),
5759                 leaf = parts.pop(),
5760                 i, ln, part;
5761
5762             for (i = 0, ln = parts.length; i < ln; i++) {
5763                 part = parts[i];
5764
5765                 if (typeof part !== 'string') {
5766                     root = part;
5767                 } else {
5768                     if (!root[part]) {
5769                         root[part] = {};
5770                     }
5771
5772                     root = root[part];
5773                 }
5774             }
5775
5776             root[leaf] = value;
5777
5778             return root[leaf];
5779         },
5780
5781         /**
5782          * The new Ext.ns, supports namespace rewriting
5783          * @private
5784          */
5785         createNamespaces: function() {
5786             var root = Ext.global,
5787                 parts, part, i, j, ln, subLn;
5788
5789             for (i = 0, ln = arguments.length; i < ln; i++) {
5790                 parts = this.parseNamespace(arguments[i]);
5791
5792                 for (j = 0, subLn = parts.length; j < subLn; j++) {
5793                     part = parts[j];
5794
5795                     if (typeof part !== 'string') {
5796                         root = part;
5797                     } else {
5798                         if (!root[part]) {
5799                             root[part] = {};
5800                         }
5801
5802                         root = root[part];
5803                     }
5804                 }
5805             }
5806
5807             return root;
5808         },
5809
5810         /**
5811          * Sets a name reference to a class.
5812          *
5813          * @param {String} name
5814          * @param {Object} value
5815          * @return {Ext.ClassManager} this
5816          */
5817         set: function(name, value) {
5818             var targetName = this.getName(value);
5819
5820             this.classes[name] = this.setNamespace(name, value);
5821
5822             if (targetName && targetName !== name) {
5823                 this.maps.alternateToName[name] = targetName;
5824             }
5825
5826             return this;
5827         },
5828
5829         /**
5830          * Retrieve a class by its name.
5831          *
5832          * @param {String} name
5833          * @return {Class} class
5834          */
5835         get: function(name) {
5836             if (this.classes.hasOwnProperty(name)) {
5837                 return this.classes[name];
5838             }
5839
5840             var root = Ext.global,
5841                 parts = this.parseNamespace(name),
5842                 part, i, ln;
5843
5844             for (i = 0, ln = parts.length; i < ln; i++) {
5845                 part = parts[i];
5846
5847                 if (typeof part !== 'string') {
5848                     root = part;
5849                 } else {
5850                     if (!root || !root[part]) {
5851                         return null;
5852                     }
5853
5854                     root = root[part];
5855                 }
5856             }
5857
5858             return root;
5859         },
5860
5861         /**
5862          * Register the alias for a class.
5863          *
5864          * @param {Class/String} cls a reference to a class or a className
5865          * @param {String} alias Alias to use when referring to this class
5866          */
5867         setAlias: function(cls, alias) {
5868             var aliasToNameMap = this.maps.aliasToName,
5869                 nameToAliasesMap = this.maps.nameToAliases,
5870                 className;
5871
5872             if (typeof cls === 'string') {
5873                 className = cls;
5874             } else {
5875                 className = this.getName(cls);
5876             }
5877
5878             if (alias && aliasToNameMap[alias] !== className) {
5879                 if (aliasToNameMap.hasOwnProperty(alias) && Ext.isDefined(Ext.global.console)) {
5880                     Ext.global.console.log("[Ext.ClassManager] Overriding existing alias: '" + alias + "' " +
5881                         "of: '" + aliasToNameMap[alias] + "' with: '" + className + "'. Be sure it's intentional.");
5882                 }
5883
5884                 aliasToNameMap[alias] = className;
5885             }
5886
5887             if (!nameToAliasesMap[className]) {
5888                 nameToAliasesMap[className] = [];
5889             }
5890
5891             if (alias) {
5892                 Ext.Array.include(nameToAliasesMap[className], alias);
5893             }
5894
5895             return this;
5896         },
5897
5898         /**
5899          * Get a reference to the class by its alias.
5900          *
5901          * @param {String} alias
5902          * @return {Class} class
5903          */
5904         getByAlias: function(alias) {
5905             return this.get(this.getNameByAlias(alias));
5906         },
5907
5908         /**
5909          * Get the name of a class by its alias.
5910          *
5911          * @param {String} alias
5912          * @return {String} className
5913          */
5914         getNameByAlias: function(alias) {
5915             return this.maps.aliasToName[alias] || '';
5916         },
5917
5918         /**
5919          * Get the name of a class by its alternate name.
5920          *
5921          * @param {String} alternate
5922          * @return {String} className
5923          */
5924         getNameByAlternate: function(alternate) {
5925             return this.maps.alternateToName[alternate] || '';
5926         },
5927
5928         /**
5929          * Get the aliases of a class by the class name
5930          *
5931          * @param {String} name
5932          * @return {Array} aliases
5933          */
5934         getAliasesByName: function(name) {
5935             return this.maps.nameToAliases[name] || [];
5936         },
5937
5938         /**
5939          * Get the name of the class by its reference or its instance;
5940          * usually invoked by the shorthand {@link Ext#getClassName Ext.getClassName}
5941
5942     Ext.ClassManager.getName(Ext.Action); // returns "Ext.Action"
5943
5944          * @param {Class/Object} object
5945          * @return {String} className
5946          * @markdown
5947          */
5948         getName: function(object) {
5949             return object && object.$className || '';
5950         },
5951
5952         /**
5953          * Get the class of the provided object; returns null if it's not an instance
5954          * of any class created with Ext.define. This is usually invoked by the shorthand {@link Ext#getClass Ext.getClass}
5955          *
5956     var component = new Ext.Component();
5957
5958     Ext.ClassManager.getClass(component); // returns Ext.Component
5959              *
5960          * @param {Object} object
5961          * @return {Class} class
5962          * @markdown
5963          */
5964         getClass: function(object) {
5965             return object && object.self || null;
5966         },
5967
5968         /**
5969          * Defines a class. This is usually invoked via the alias {@link Ext#define Ext.define}
5970
5971     Ext.ClassManager.create('My.awesome.Class', {
5972         someProperty: 'something',
5973         someMethod: function() { ... }
5974         ...
5975
5976     }, function() {
5977         alert('Created!');
5978         alert(this === My.awesome.Class); // alerts true
5979
5980         var myInstance = new this();
5981     });
5982
5983          * @param {String} className The class name to create in string dot-namespaced format, for example:
5984          * 'My.very.awesome.Class', 'FeedViewer.plugin.CoolPager'
5985          * It is highly recommended to follow this simple convention:
5986
5987 - The root and the class name are 'CamelCased'
5988 - Everything else is lower-cased
5989
5990          * @param {Object} data The key - value pairs of properties to apply to this class. Property names can be of any valid
5991          * strings, except those in the reserved listed below:
5992
5993 - `mixins`
5994 - `statics`
5995 - `config`
5996 - `alias`
5997 - `self`
5998 - `singleton`
5999 - `alternateClassName`
6000          *
6001          * @param {Function} createdFn Optional callback to execute after the class is created, the execution scope of which
6002          * (`this`) will be the newly created class itself.
6003          * @return {Ext.Base}
6004          * @markdown
6005          */
6006         create: function(className, data, createdFn) {
6007             var manager = this;
6008
6009             if (typeof className !== 'string') {
6010                 Ext.Error.raise({
6011                     sourceClass: "Ext",
6012                     sourceMethod: "define",
6013                     msg: "Invalid class name '" + className + "' specified, must be a non-empty string"
6014                 });
6015             }
6016
6017             data.$className = className;
6018
6019             return new Class(data, function() {
6020                 var postprocessorStack = data.postprocessors || manager.defaultPostprocessors,
6021                     registeredPostprocessors = manager.postprocessors,
6022                     index = 0,
6023                     postprocessors = [],
6024                     postprocessor, postprocessors, process, i, ln;
6025
6026                 delete data.postprocessors;
6027
6028                 for (i = 0, ln = postprocessorStack.length; i < ln; i++) {
6029                     postprocessor = postprocessorStack[i];
6030
6031                     if (typeof postprocessor === 'string') {
6032                         postprocessor = registeredPostprocessors[postprocessor];
6033
6034                         if (!postprocessor.always) {
6035                             if (data[postprocessor.name] !== undefined) {
6036                                 postprocessors.push(postprocessor.fn);
6037                             }
6038                         }
6039                         else {
6040                             postprocessors.push(postprocessor.fn);
6041                         }
6042                     }
6043                     else {
6044                         postprocessors.push(postprocessor);
6045                     }
6046                 }
6047
6048                 process = function(clsName, cls, clsData) {
6049                     postprocessor = postprocessors[index++];
6050
6051                     if (!postprocessor) {
6052                         manager.set(className, cls);
6053
6054                         Ext.Loader.historyPush(className);
6055
6056                         if (createdFn) {
6057                             createdFn.call(cls, cls);
6058                         }
6059
6060                         return;
6061                     }
6062
6063                     if (postprocessor.call(this, clsName, cls, clsData, process) !== false) {
6064                         process.apply(this, arguments);
6065                     }
6066                 };
6067
6068                 process.call(manager, className, this, data);
6069             });
6070         },
6071
6072         /**
6073          * Instantiate a class by its alias; usually invoked by the convenient shorthand {@link Ext#createByAlias Ext.createByAlias}
6074          * If {@link Ext.Loader} is {@link Ext.Loader#setConfig enabled} and the class has not been defined yet, it will
6075          * attempt to load the class via synchronous loading.
6076
6077     var window = Ext.ClassManager.instantiateByAlias('widget.window', { width: 600, height: 800, ... });
6078
6079          * @param {String} alias
6080          * @param {Mixed} args,... Additional arguments after the alias will be passed to the
6081          * class constructor.
6082          * @return {Object} instance
6083          * @markdown
6084          */
6085         instantiateByAlias: function() {
6086             var alias = arguments[0],
6087                 args = slice.call(arguments),
6088                 className = this.getNameByAlias(alias);
6089
6090             if (!className) {
6091                 className = this.maps.aliasToName[alias];
6092
6093                 if (!className) {
6094                     Ext.Error.raise({
6095                         sourceClass: "Ext",
6096                         sourceMethod: "createByAlias",
6097                         msg: "Cannot create an instance of unrecognized alias: " + alias
6098                     });
6099                 }
6100
6101                 if (Ext.global.console) {
6102                     Ext.global.console.warn("[Ext.Loader] Synchronously loading '" + className + "'; consider adding " +
6103                          "Ext.require('" + alias + "') above Ext.onReady");
6104                 }
6105
6106                 Ext.syncRequire(className);
6107             }
6108
6109             args[0] = className;
6110
6111             return this.instantiate.apply(this, args);
6112         },
6113
6114         /**
6115          * Instantiate a class by either full name, alias or alternate name; usually invoked by the convenient
6116          * shorthand {@link Ext#create Ext.create}
6117          *
6118          * If {@link Ext.Loader} is {@link Ext.Loader#setConfig enabled} and the class has not been defined yet, it will
6119          * attempt to load the class via synchronous loading.
6120          *
6121          * For example, all these three lines return the same result:
6122
6123     // alias
6124     var window = Ext.ClassManager.instantiate('widget.window', { width: 600, height: 800, ... });
6125
6126     // alternate name
6127     var window = Ext.ClassManager.instantiate('Ext.Window', { width: 600, height: 800, ... });
6128
6129     // full class name
6130     var window = Ext.ClassManager.instantiate('Ext.window.Window', { width: 600, height: 800, ... });
6131
6132          * @param {String} name
6133          * @param {Mixed} args,... Additional arguments after the name will be passed to the class' constructor.
6134          * @return {Object} instance
6135          * @markdown
6136          */
6137         instantiate: function() {
6138             var name = arguments[0],
6139                 args = slice.call(arguments, 1),
6140                 alias = name,
6141                 possibleName, cls;
6142
6143             if (typeof name !== 'function') {
6144                 if ((typeof name !== 'string' || name.length < 1)) {
6145                     Ext.Error.raise({
6146                         sourceClass: "Ext",
6147                         sourceMethod: "create",
6148                         msg: "Invalid class name or alias '" + name + "' specified, must be a non-empty string"
6149                     });
6150                 }
6151
6152                 cls = this.get(name);
6153             }
6154             else {
6155                 cls = name;
6156             }
6157
6158             // No record of this class name, it's possibly an alias, so look it up
6159             if (!cls) {
6160                 possibleName = this.getNameByAlias(name);
6161
6162                 if (possibleName) {
6163                     name = possibleName;
6164
6165                     cls = this.get(name);
6166                 }
6167             }
6168
6169             // Still no record of this class name, it's possibly an alternate name, so look it up
6170             if (!cls) {
6171                 possibleName = this.getNameByAlternate(name);
6172
6173                 if (possibleName) {
6174                     name = possibleName;
6175
6176                     cls = this.get(name);
6177                 }
6178             }
6179
6180             // Still not existing at this point, try to load it via synchronous mode as the last resort
6181             if (!cls) {
6182                 if (Ext.global.console) {
6183                     Ext.global.console.warn("[Ext.Loader] Synchronously loading '" + name + "'; consider adding " +
6184                          "Ext.require('" + ((possibleName) ? alias : name) + "') above Ext.onReady");
6185                 }
6186
6187                 Ext.syncRequire(name);
6188
6189                 cls = this.get(name);
6190             }
6191
6192             if (!cls) {
6193                 Ext.Error.raise({
6194                     sourceClass: "Ext",
6195                     sourceMethod: "create",
6196                     msg: "Cannot create an instance of unrecognized class name / alias: " + alias
6197                 });
6198             }
6199
6200             if (typeof cls !== 'function') {
6201                 Ext.Error.raise({
6202                     sourceClass: "Ext",
6203                     sourceMethod: "create",
6204                     msg: "'" + name + "' is a singleton and cannot be instantiated"
6205                 });
6206             }
6207
6208             if (!this.instantiationCounts[name]) {
6209                 this.instantiationCounts[name] = 0;
6210             }
6211
6212             this.instantiationCounts[name]++;
6213
6214             return this.getInstantiator(args.length)(cls, args);
6215         },
6216
6217         /**
6218          * @private
6219          * @param name
6220          * @param args
6221          */
6222         dynInstantiate: function(name, args) {
6223             args = Ext.Array.from(args, true);
6224             args.unshift(name);
6225
6226             return this.instantiate.apply(this, args);
6227         },
6228
6229         /**
6230          * @private
6231          * @param length
6232          */
6233         getInstantiator: function(length) {
6234             if (!this.instantiators[length]) {
6235                 var i = length,
6236                     args = [];
6237
6238                 for (i = 0; i < length; i++) {
6239                     args.push('a['+i+']');
6240                 }
6241
6242                 this.instantiators[length] = new Function('c', 'a', 'return new c('+args.join(',')+')');
6243             }
6244
6245             return this.instantiators[length];
6246         },
6247
6248         /**
6249          * @private
6250          */
6251         postprocessors: {},
6252
6253         /**
6254          * @private
6255          */
6256         defaultPostprocessors: [],
6257
6258         /**
6259          * Register a post-processor function.
6260          *
6261          * @param {String} name
6262          * @param {Function} postprocessor
6263          */
6264         registerPostprocessor: function(name, fn, always) {
6265             this.postprocessors[name] = {
6266                 name: name,
6267                 always: always ||  false,
6268                 fn: fn
6269             };
6270
6271             return this;
6272         },
6273
6274         /**
6275          * Set the default post processors array stack which are applied to every class.
6276          *
6277          * @param {String/Array} The name of a registered post processor or an array of registered names.
6278          * @return {Ext.ClassManager} this
6279          */
6280         setDefaultPostprocessors: function(postprocessors) {
6281             this.defaultPostprocessors = Ext.Array.from(postprocessors);
6282
6283             return this;
6284         },
6285
6286         /**
6287          * Insert this post-processor at a specific position in the stack, optionally relative to
6288          * any existing post-processor
6289          *
6290          * @param {String} name The post-processor name. Note that it needs to be registered with
6291          * {@link Ext.ClassManager#registerPostprocessor} before this
6292          * @param {String} offset The insertion position. Four possible values are:
6293          * 'first', 'last', or: 'before', 'after' (relative to the name provided in the third argument)
6294          * @param {String} relativeName
6295          * @return {Ext.ClassManager} this
6296          */
6297         setDefaultPostprocessorPosition: function(name, offset, relativeName) {
6298             var defaultPostprocessors = this.defaultPostprocessors,
6299                 index;
6300
6301             if (typeof offset === 'string') {
6302                 if (offset === 'first') {
6303                     defaultPostprocessors.unshift(name);
6304
6305                     return this;
6306                 }
6307                 else if (offset === 'last') {
6308                     defaultPostprocessors.push(name);
6309
6310                     return this;
6311                 }
6312
6313                 offset = (offset === 'after') ? 1 : -1;
6314             }
6315
6316             index = Ext.Array.indexOf(defaultPostprocessors, relativeName);
6317
6318             if (index !== -1) {
6319                 defaultPostprocessors.splice(Math.max(0, index + offset), 0, name);
6320             }
6321
6322             return this;
6323         },
6324
6325         /**
6326          * Converts a string expression to an array of matching class names. An expression can either refers to class aliases
6327          * or class names. Expressions support wildcards:
6328
6329      // returns ['Ext.window.Window']
6330     var window = Ext.ClassManager.getNamesByExpression('widget.window');
6331
6332     // returns ['widget.panel', 'widget.window', ...]
6333     var allWidgets = Ext.ClassManager.getNamesByExpression('widget.*');
6334
6335     // returns ['Ext.data.Store', 'Ext.data.ArrayProxy', ...]
6336     var allData = Ext.ClassManager.getNamesByExpression('Ext.data.*');
6337
6338          * @param {String} expression
6339          * @return {Array} classNames
6340          * @markdown
6341          */
6342         getNamesByExpression: function(expression) {
6343             var nameToAliasesMap = this.maps.nameToAliases,
6344                 names = [],
6345                 name, alias, aliases, possibleName, regex, i, ln;
6346
6347             if (typeof expression !== 'string' || expression.length < 1) {
6348                 Ext.Error.raise({
6349                     sourceClass: "Ext.ClassManager",
6350                     sourceMethod: "getNamesByExpression",
6351                     msg: "Expression " + expression + " is invalid, must be a non-empty string"
6352                 });
6353             }
6354
6355             if (expression.indexOf('*') !== -1) {
6356                 expression = expression.replace(/\*/g, '(.*?)');
6357                 regex = new RegExp('^' + expression + '$');
6358
6359                 for (name in nameToAliasesMap) {
6360                     if (nameToAliasesMap.hasOwnProperty(name)) {
6361                         aliases = nameToAliasesMap[name];
6362
6363                         if (name.search(regex) !== -1) {
6364                             names.push(name);
6365                         }
6366                         else {
6367                             for (i = 0, ln = aliases.length; i < ln; i++) {
6368                                 alias = aliases[i];
6369
6370                                 if (alias.search(regex) !== -1) {
6371                                     names.push(name);
6372                                     break;
6373                                 }
6374                             }
6375                         }
6376                     }
6377                 }
6378
6379             } else {
6380                 possibleName = this.getNameByAlias(expression);
6381
6382                 if (possibleName) {
6383                     names.push(possibleName);
6384                 } else {
6385                     possibleName = this.getNameByAlternate(expression);
6386
6387                     if (possibleName) {
6388                         names.push(possibleName);
6389                     } else {
6390                         names.push(expression);
6391                     }
6392                 }
6393             }
6394
6395             return names;
6396         }
6397     };
6398
6399     Manager.registerPostprocessor('alias', function(name, cls, data) {
6400         var aliases = data.alias,
6401             widgetPrefix = 'widget.',
6402             i, ln, alias;
6403
6404         if (!(aliases instanceof Array)) {
6405             aliases = [aliases];
6406         }
6407
6408         for (i = 0, ln = aliases.length; i < ln; i++) {
6409             alias = aliases[i];
6410
6411             if (typeof alias !== 'string') {
6412                 Ext.Error.raise({
6413                     sourceClass: "Ext",
6414                     sourceMethod: "define",
6415                     msg: "Invalid alias of: '" + alias + "' for class: '" + name + "'; must be a valid string"
6416                 });
6417             }
6418
6419             this.setAlias(cls, alias);
6420         }
6421
6422         // This is ugly, will change to make use of parseNamespace for alias later on
6423         for (i = 0, ln = aliases.length; i < ln; i++) {
6424             alias = aliases[i];
6425
6426             if (alias.substring(0, widgetPrefix.length) === widgetPrefix) {
6427                 // Only the first alias with 'widget.' prefix will be used for xtype
6428                 cls.xtype = cls.$xtype = alias.substring(widgetPrefix.length);
6429                 break;
6430             }
6431         }
6432     });
6433
6434     Manager.registerPostprocessor('singleton', function(name, cls, data, fn) {
6435         fn.call(this, name, new cls(), data);
6436         return false;
6437     });
6438
6439     Manager.registerPostprocessor('alternateClassName', function(name, cls, data) {
6440         var alternates = data.alternateClassName,
6441             i, ln, alternate;
6442
6443         if (!(alternates instanceof Array)) {
6444             alternates = [alternates];
6445         }
6446
6447         for (i = 0, ln = alternates.length; i < ln; i++) {
6448             alternate = alternates[i];
6449
6450             if (typeof alternate !== 'string') {
6451                 Ext.Error.raise({
6452                     sourceClass: "Ext",
6453                     sourceMethod: "define",
6454                     msg: "Invalid alternate of: '" + alternate + "' for class: '" + name + "'; must be a valid string"
6455                 });
6456             }
6457
6458             this.set(alternate, cls);
6459         }
6460     });
6461
6462     Manager.setDefaultPostprocessors(['alias', 'singleton', 'alternateClassName']);
6463
6464     Ext.apply(Ext, {
6465         /**
6466          * Convenient shorthand, see {@link Ext.ClassManager#instantiate}
6467          * @member Ext
6468          * @method create
6469          */
6470         create: alias(Manager, 'instantiate'),
6471
6472         /**
6473          * @private
6474          * API to be stablized
6475          *
6476          * @param {Mixed} item
6477          * @param {String} namespace
6478          */
6479         factory: function(item, namespace) {
6480             if (item instanceof Array) {
6481                 var i, ln;
6482
6483                 for (i = 0, ln = item.length; i < ln; i++) {
6484                     item[i] = Ext.factory(item[i], namespace);
6485                 }
6486
6487                 return item;
6488             }
6489
6490             var isString = (typeof item === 'string');
6491
6492             if (isString || (item instanceof Object && item.constructor === Object)) {
6493                 var name, config = {};
6494
6495                 if (isString) {
6496                     name = item;
6497                 }
6498                 else {
6499                     name = item.className;
6500                     config = item;
6501                     delete config.className;
6502                 }
6503
6504                 if (namespace !== undefined && name.indexOf(namespace) === -1) {
6505                     name = namespace + '.' + Ext.String.capitalize(name);
6506                 }
6507
6508                 return Ext.create(name, config);
6509             }
6510
6511             if (typeof item === 'function') {
6512                 return Ext.create(item);
6513             }
6514
6515             return item;
6516         },
6517
6518         /**
6519          * Convenient shorthand to create a widget by its xtype, also see {@link Ext.ClassManager#instantiateByAlias}
6520
6521     var button = Ext.widget('button'); // Equivalent to Ext.create('widget.button')
6522     var panel = Ext.widget('panel'); // Equivalent to Ext.create('widget.panel')
6523
6524          * @member Ext
6525          * @method widget
6526          * @markdown
6527          */
6528         widget: function(name) {
6529             var args = slice.call(arguments);
6530             args[0] = 'widget.' + name;
6531
6532             return Manager.instantiateByAlias.apply(Manager, args);
6533         },
6534
6535         /**
6536          * Convenient shorthand, see {@link Ext.ClassManager#instantiateByAlias}
6537          * @member Ext
6538          * @method createByAlias
6539          */
6540         createByAlias: alias(Manager, 'instantiateByAlias'),
6541
6542         /**
6543          * Convenient shorthand for {@link Ext.ClassManager#create}, see detailed {@link Ext.Class explanation}
6544          * @member Ext
6545          * @method define
6546          */
6547         define: alias(Manager, 'create'),
6548
6549         /**
6550          * Convenient shorthand, see {@link Ext.ClassManager#getName}
6551          * @member Ext
6552          * @method getClassName
6553          */
6554         getClassName: alias(Manager, 'getName'),
6555
6556         /**
6557          *
6558          * @param {Mixed} object
6559          */
6560         getDisplayName: function(object) {
6561             if (object.displayName) {
6562                 return object.displayName;
6563             }
6564
6565             if (object.$name && object.$class) {
6566                 return Ext.getClassName(object.$class) + '#' + object.$name;
6567             }
6568
6569             if (object.$className) {
6570                 return object.$className;
6571             }
6572
6573             return 'Anonymous';
6574         },
6575
6576         /**
6577          * Convenient shorthand, see {@link Ext.ClassManager#getClass}
6578          * @member Ext
6579          * @method getClassName
6580          */
6581         getClass: alias(Manager, 'getClass'),
6582
6583         /**
6584          * Creates namespaces to be used for scoping variables and classes so that they are not global.
6585          * Specifying the last node of a namespace implicitly creates all other nodes. Usage:
6586
6587     Ext.namespace('Company', 'Company.data');
6588
6589      // equivalent and preferable to the above syntax
6590     Ext.namespace('Company.data');
6591
6592     Company.Widget = function() { ... };
6593
6594     Company.data.CustomStore = function(config) { ... };
6595
6596          * @param {String} namespace1
6597          * @param {String} namespace2
6598          * @param {String} etc
6599          * @return {Object} The namespace object. (If multiple arguments are passed, this will be the last namespace created)
6600          * @function
6601          * @member Ext
6602          * @method namespace
6603          * @markdown
6604          */
6605         namespace: alias(Manager, 'createNamespaces')
6606     });
6607
6608     Ext.createWidget = Ext.widget;
6609
6610     /**
6611      * Convenient alias for {@link Ext#namespace Ext.namespace}
6612      * @member Ext
6613      * @method ns
6614      */
6615     Ext.ns = Ext.namespace;
6616
6617     Class.registerPreprocessor('className', function(cls, data) {
6618         if (data.$className) {
6619             cls.$className = data.$className;
6620             cls.displayName = cls.$className;
6621         }
6622     }, true);
6623
6624     Class.setDefaultPreprocessorPosition('className', 'first');
6625
6626 })(Ext.Class, Ext.Function.alias);
6627
6628 /**
6629  * @author Jacky Nguyen <jacky@sencha.com>
6630  * @docauthor Jacky Nguyen <jacky@sencha.com>
6631  * @class Ext.Loader
6632  *
6633
6634 Ext.Loader is the heart of the new dynamic dependency loading capability in Ext JS 4+. It is most commonly used
6635 via the {@link Ext#require} shorthand. Ext.Loader supports both asynchronous and synchronous loading
6636 approaches, and leverage their advantages for the best development flow. We'll discuss about the pros and cons of each approach:
6637
6638 # Asynchronous Loading #
6639
6640 - Advantages:
6641         + Cross-domain
6642         + No web server needed: you can run the application via the file system protocol (i.e: `file://path/to/your/index
6643  .html`)
6644         + Best possible debugging experience: error messages come with the exact file name and line number
6645
6646 - Disadvantages:
6647         + Dependencies need to be specified before-hand
6648
6649 ### Method 1: Explicitly include what you need: ###
6650
6651     // Syntax
6652     Ext.require({String/Array} expressions);
6653
6654     // Example: Single alias
6655     Ext.require('widget.window');
6656
6657     // Example: Single class name
6658     Ext.require('Ext.window.Window');
6659
6660     // Example: Multiple aliases / class names mix
6661     Ext.require(['widget.window', 'layout.border', 'Ext.data.Connection']);
6662
6663     // Wildcards
6664     Ext.require(['widget.*', 'layout.*', 'Ext.data.*']);
6665
6666 ### Method 2: Explicitly exclude what you don't need: ###
6667
6668     // Syntax: Note that it must be in this chaining format.
6669     Ext.exclude({String/Array} expressions)
6670        .require({String/Array} expressions);
6671
6672     // Include everything except Ext.data.*
6673     Ext.exclude('Ext.data.*').require('*'); 
6674
6675     // Include all widgets except widget.checkbox*,
6676     // which will match widget.checkbox, widget.checkboxfield, widget.checkboxgroup, etc.
6677     Ext.exclude('widget.checkbox*').require('widget.*');
6678
6679 # Synchronous Loading on Demand #
6680
6681 - *Advantages:*
6682         + There's no need to specify dependencies before-hand, which is always the convenience of including ext-all.js
6683  before
6684
6685 - *Disadvantages:*
6686         + Not as good debugging experience since file name won't be shown (except in Firebug at the moment)
6687         + Must be from the same domain due to XHR restriction
6688         + Need a web server, same reason as above
6689
6690 There's one simple rule to follow: Instantiate everything with Ext.create instead of the `new` keyword
6691
6692     Ext.create('widget.window', { ... }); // Instead of new Ext.window.Window({...});
6693
6694     Ext.create('Ext.window.Window', {}); // Same as above, using full class name instead of alias
6695
6696     Ext.widget('window', {}); // Same as above, all you need is the traditional `xtype`
6697
6698 Behind the scene, {@link Ext.ClassManager} will automatically check whether the given class name / alias has already
6699  existed on the page. If it's not, Ext.Loader will immediately switch itself to synchronous mode and automatic load the given
6700  class and all its dependencies.
6701
6702 # Hybrid Loading - The Best of Both Worlds #
6703
6704 It has all the advantages combined from asynchronous and synchronous loading. The development flow is simple:
6705
6706 ### Step 1: Start writing your application using synchronous approach. Ext.Loader will automatically fetch all
6707  dependencies on demand as they're needed during run-time. For example: ###
6708
6709     Ext.onReady(function(){
6710         var window = Ext.createWidget('window', {
6711             width: 500,
6712             height: 300,
6713             layout: {
6714                 type: 'border',
6715                 padding: 5
6716             },
6717             title: 'Hello Dialog',
6718             items: [{
6719                 title: 'Navigation',
6720                 collapsible: true,
6721                 region: 'west',
6722                 width: 200,
6723                 html: 'Hello',
6724                 split: true
6725             }, {
6726                 title: 'TabPanel',
6727                 region: 'center'
6728             }]
6729         });
6730
6731         window.show();
6732     })
6733
6734 ### Step 2: Along the way, when you need better debugging ability, watch the console for warnings like these: ###
6735
6736     [Ext.Loader] Synchronously loading 'Ext.window.Window'; consider adding Ext.require('Ext.window.Window') before your application's code
6737     ClassManager.js:432
6738     [Ext.Loader] Synchronously loading 'Ext.layout.container.Border'; consider adding Ext.require('Ext.layout.container.Border') before your application's code
6739
6740 Simply copy and paste the suggested code above `Ext.onReady`, i.e:
6741
6742     Ext.require('Ext.window.Window');
6743     Ext.require('Ext.layout.container.Border');
6744
6745     Ext.onReady(...);
6746
6747 Everything should now load via asynchronous mode.
6748
6749 # Deployment #
6750
6751 It's important to note that dynamic loading should only be used during development on your local machines.
6752 During production, all dependencies should be combined into one single JavaScript file. Ext.Loader makes
6753 the whole process of transitioning from / to between development / maintenance and production as easy as
6754 possible. Internally {@link Ext.Loader#history Ext.Loader.history} maintains the list of all dependencies your application
6755 needs in the exact loading sequence. It's as simple as concatenating all files in this array into one,
6756 then include it on top of your application.
6757
6758 This process will be automated with Sencha Command, to be released and documented towards Ext JS 4 Final.
6759
6760  * @singleton
6761  * @markdown
6762  */
6763
6764 (function(Manager, Class, flexSetter, alias) {
6765
6766     var
6767         dependencyProperties = ['extend', 'mixins', 'requires'],
6768         Loader;
6769
6770     Loader = Ext.Loader = {
6771         /**
6772          * @private
6773          */
6774         documentHead: typeof document !== 'undefined' && (document.head || document.getElementsByTagName('head')[0]),
6775
6776         /**
6777          * Flag indicating whether there are still files being loaded
6778          * @private
6779          */
6780         isLoading: false,
6781
6782         /**
6783          * Maintain the queue for all dependencies. Each item in the array is an object of the format:
6784          * {
6785          *      requires: [...], // The required classes for this queue item
6786          *      callback: function() { ... } // The function to execute when all classes specified in requires exist
6787          * }
6788          * @private
6789          */
6790         queue: [],
6791
6792         /**
6793          * Maintain the list of files that have already been handled so that they never get double-loaded
6794          * @private
6795          */
6796         isFileLoaded: {},
6797
6798         /**
6799          * Maintain the list of listeners to execute when all required scripts are fully loaded
6800          * @private
6801          */
6802         readyListeners: [],
6803
6804         /**
6805          * Contains optional dependencies to be loaded last
6806          * @private
6807          */
6808         optionalRequires: [],
6809
6810         /**
6811          * Map of fully qualified class names to an array of dependent classes.
6812          * @private
6813          */
6814         requiresMap: {},
6815
6816         /**
6817          * @private
6818          */
6819         numPendingFiles: 0,
6820
6821         /**
6822          * @private
6823          */
6824         numLoadedFiles: 0,
6825
6826         /** @private */
6827         hasFileLoadError: false,
6828
6829         /**
6830          * @private
6831          */
6832         classNameToFilePathMap: {},
6833
6834         /**
6835          * An array of class names to keep track of the dependency loading order.
6836          * This is not guaranteed to be the same everytime due to the asynchronous
6837          * nature of the Loader.
6838          *
6839          * @property history
6840          * @type Array
6841          */
6842         history: [],
6843
6844         /**
6845          * Configuration
6846          * @private
6847          */
6848         config: {
6849             /**
6850              * Whether or not to enable the dynamic dependency loading feature
6851              * Defaults to false
6852              * @cfg {Boolean} enabled
6853              */
6854             enabled: false,
6855
6856             /**
6857              * @cfg {Boolean} disableCaching
6858              * Appends current timestamp to script files to prevent caching
6859              * Defaults to true
6860              */
6861             disableCaching: true,
6862
6863             /**
6864              * @cfg {String} disableCachingParam
6865              * The get parameter name for the cache buster's timestamp.
6866              * Defaults to '_dc'
6867              */
6868             disableCachingParam: '_dc',
6869
6870             /**
6871              * @cfg {Object} paths
6872              * The mapping from namespaces to file paths
6873     {
6874         'Ext': '.', // This is set by default, Ext.layout.container.Container will be
6875                     // loaded from ./layout/Container.js
6876
6877         'My': './src/my_own_folder' // My.layout.Container will be loaded from
6878                                     // ./src/my_own_folder/layout/Container.js
6879     }
6880              * Note that all relative paths are relative to the current HTML document.
6881              * If not being specified, for example, <code>Other.awesome.Class</code>
6882              * will simply be loaded from <code>./Other/awesome/Class.js</code>
6883              */
6884             paths: {
6885                 'Ext': '.'
6886             }
6887         },
6888
6889         /**
6890          * Set the configuration for the loader. This should be called right after ext-core.js
6891          * (or ext-core-debug.js) is included in the page, i.e:
6892
6893     <script type="text/javascript" src="ext-core-debug.js"></script>
6894     <script type="text/javascript">
6895       Ext.Loader.setConfig({
6896           enabled: true,
6897           paths: {
6898               'My': 'my_own_path'
6899           }
6900       });
6901     <script>
6902     <script type="text/javascript">
6903       Ext.require(...);
6904
6905       Ext.onReady(function() {
6906           // application code here
6907       });
6908     </script>
6909
6910          * Refer to {@link Ext.Loader#configs} for the list of possible properties
6911          *
6912          * @param {Object} config The config object to override the default values in {@link Ext.Loader#config}
6913          * @return {Ext.Loader} this
6914          * @markdown
6915          */
6916         setConfig: function(name, value) {
6917             if (Ext.isObject(name) && arguments.length === 1) {
6918                 Ext.Object.merge(this.config, name);
6919             }
6920             else {
6921                 this.config[name] = (Ext.isObject(value)) ? Ext.Object.merge(this.config[name], value) : value;
6922             }
6923
6924             return this;
6925         },
6926
6927         /**
6928          * Get the config value corresponding to the specified name. If no name is given, will return the config object
6929          * @param {String} name The config property name
6930          * @return {Object/Mixed}
6931          */
6932         getConfig: function(name) {
6933             if (name) {
6934                 return this.config[name];
6935             }
6936
6937             return this.config;
6938         },
6939
6940         /**
6941          * Sets the path of a namespace.
6942          * For Example:
6943
6944     Ext.Loader.setPath('Ext', '.');
6945
6946          * @param {String/Object} name See {@link Ext.Function#flexSetter flexSetter}
6947          * @param {String} path See {@link Ext.Function#flexSetter flexSetter}
6948          * @return {Ext.Loader} this
6949          * @markdown
6950          */
6951         setPath: flexSetter(function(name, path) {
6952             this.config.paths[name] = path;
6953
6954             return this;
6955         }),
6956
6957         /**
6958          * Translates a className to a file path by adding the
6959          * the proper prefix and converting the .'s to /'s. For example:
6960
6961     Ext.Loader.setPath('My', '/path/to/My');
6962
6963     alert(Ext.Loader.getPath('My.awesome.Class')); // alerts '/path/to/My/awesome/Class.js'
6964
6965          * Note that the deeper namespace levels, if explicitly set, are always resolved first. For example:
6966
6967     Ext.Loader.setPath({
6968         'My': '/path/to/lib',
6969         'My.awesome': '/other/path/for/awesome/stuff',
6970         'My.awesome.more': '/more/awesome/path'
6971     });
6972
6973     alert(Ext.Loader.getPath('My.awesome.Class')); // alerts '/other/path/for/awesome/stuff/Class.js'
6974
6975     alert(Ext.Loader.getPath('My.awesome.more.Class')); // alerts '/more/awesome/path/Class.js'
6976
6977     alert(Ext.Loader.getPath('My.cool.Class')); // alerts '/path/to/lib/cool/Class.js'
6978
6979     alert(Ext.Loader.getPath('Unknown.strange.Stuff')); // alerts 'Unknown/strange/Stuff.js'
6980
6981          * @param {String} className
6982          * @return {String} path
6983          * @markdown
6984          */
6985         getPath: function(className) {
6986             var path = '',
6987                 paths = this.config.paths,
6988                 prefix = this.getPrefix(className);
6989
6990             if (prefix.length > 0) {
6991                 if (prefix === className) {
6992                     return paths[prefix];
6993                 }
6994
6995                 path = paths[prefix];
6996                 className = className.substring(prefix.length + 1);
6997             }
6998
6999             if (path.length > 0) {
7000                 path += '/';
7001             }
7002
7003             return path.replace(/\/\.\//g, '/') + className.replace(/\./g, "/") + '.js';
7004         },
7005
7006         /**
7007          * @private
7008          * @param {String} className
7009          */
7010         getPrefix: function(className) {
7011             var paths = this.config.paths,
7012                 prefix, deepestPrefix = '';
7013
7014             if (paths.hasOwnProperty(className)) {
7015                 return className;
7016             }
7017
7018             for (prefix in paths) {
7019                 if (paths.hasOwnProperty(prefix) && prefix + '.' === className.substring(0, prefix.length + 1)) {
7020                     if (prefix.length > deepestPrefix.length) {
7021                         deepestPrefix = prefix;
7022                     }
7023                 }
7024             }
7025
7026             return deepestPrefix;
7027         },
7028
7029         /**
7030          * Refresh all items in the queue. If all dependencies for an item exist during looping,
7031          * it will execute the callback and call refreshQueue again. Triggers onReady when the queue is
7032          * empty
7033          * @private
7034          */
7035         refreshQueue: function() {
7036             var ln = this.queue.length,
7037                 i, item, j, requires;
7038
7039             if (ln === 0) {
7040                 this.triggerReady();
7041                 return;
7042             }
7043
7044             for (i = 0; i < ln; i++) {
7045                 item = this.queue[i];
7046
7047                 if (item) {
7048                     requires = item.requires;
7049
7050                     // Don't bother checking when the number of files loaded
7051                     // is still less than the array length
7052                     if (requires.length > this.numLoadedFiles) {
7053                         continue;
7054                     }
7055
7056                     j = 0;
7057
7058                     do {
7059                         if (Manager.isCreated(requires[j])) {
7060                             // Take out from the queue
7061                             requires.splice(j, 1);
7062                         }
7063                         else {
7064                             j++;
7065                         }
7066                     } while (j < requires.length);
7067
7068                     if (item.requires.length === 0) {
7069                         this.queue.splice(i, 1);
7070                         item.callback.call(item.scope);
7071                         this.refreshQueue();
7072                         break;
7073                     }
7074                 }
7075             }
7076
7077             return this;
7078         },
7079
7080         /**
7081          * Inject a script element to document's head, call onLoad and onError accordingly
7082          * @private
7083          */
7084         injectScriptElement: function(url, onLoad, onError, scope) {
7085             var script = document.createElement('script'),
7086                 me = this,
7087                 onLoadFn = function() {
7088                     me.cleanupScriptElement(script);
7089                     onLoad.call(scope);
7090                 },
7091                 onErrorFn = function() {
7092                     me.cleanupScriptElement(script);
7093                     onError.call(scope);
7094                 };
7095
7096             script.type = 'text/javascript';
7097             script.src = url;
7098             script.onload = onLoadFn;
7099             script.onerror = onErrorFn;
7100             script.onreadystatechange = function() {
7101                 if (this.readyState === 'loaded' || this.readyState === 'complete') {
7102                     onLoadFn();
7103                 }
7104             };
7105
7106             this.documentHead.appendChild(script);
7107
7108             return script;
7109         },
7110
7111         /**
7112          * @private
7113          */
7114         cleanupScriptElement: function(script) {
7115             script.onload = null;
7116             script.onreadystatechange = null;
7117             script.onerror = null;
7118
7119             return this;
7120         },
7121
7122         /**
7123          * Load a script file, supports both asynchronous and synchronous approaches
7124          *
7125          * @param {String} url
7126          * @param {Function} onLoad
7127          * @param {Scope} scope
7128          * @param {Boolean} synchronous
7129          * @private
7130          */
7131         loadScriptFile: function(url, onLoad, onError, scope, synchronous) {
7132             var me = this,
7133                 noCacheUrl = url + (this.getConfig('disableCaching') ? ('?' + this.getConfig('disableCachingParam') + '=' + Ext.Date.now()) : ''),
7134                 fileName = url.split('/').pop(),
7135                 isCrossOriginRestricted = false,
7136                 xhr, status, onScriptError;
7137
7138             scope = scope || this;
7139
7140             this.isLoading = true;
7141
7142             if (!synchronous) {
7143                 onScriptError = function() {
7144                     onError.call(scope, "Failed loading '" + url + "', please verify that the file exists", synchronous);
7145                 };
7146
7147                 if (!Ext.isReady && Ext.onDocumentReady) {
7148                     Ext.onDocumentReady(function() {
7149                         me.injectScriptElement(noCacheUrl, onLoad, onScriptError, scope);
7150                     });
7151                 }
7152                 else {
7153                     this.injectScriptElement(noCacheUrl, onLoad, onScriptError, scope);
7154                 }
7155             }
7156             else {
7157                 if (typeof XMLHttpRequest !== 'undefined') {
7158                     xhr = new XMLHttpRequest();
7159                 } else {
7160                     xhr = new ActiveXObject('Microsoft.XMLHTTP');
7161                 }
7162
7163                 try {
7164                     xhr.open('GET', noCacheUrl, false);
7165                     xhr.send(null);
7166                 } catch (e) {
7167                     isCrossOriginRestricted = true;
7168                 }
7169
7170                 status = (xhr.status === 1223) ? 204 : xhr.status;
7171
7172                 if (!isCrossOriginRestricted) {
7173                     isCrossOriginRestricted = (status === 0);
7174                 }
7175
7176                 if (isCrossOriginRestricted
7177                 ) {
7178                     onError.call(this, "Failed loading synchronously via XHR: '" + url + "'; It's likely that the file is either " +
7179                                        "being loaded from a different domain or from the local file system whereby cross origin " +
7180                                        "requests are not allowed due to security reasons. Use asynchronous loading with " +
7181                                        "Ext.require instead.", synchronous);
7182                 }
7183                 else if (status >= 200 && status < 300
7184                 ) {
7185                     // Firebug friendly, file names are still shown even though they're eval'ed code
7186                     new Function(xhr.responseText + "\n//@ sourceURL=" + fileName)();
7187
7188                     onLoad.call(scope);
7189                 }
7190                 else {
7191                     onError.call(this, "Failed loading synchronously via XHR: '" + url + "'; please " +
7192                                        "verify that the file exists. " +
7193                                        "XHR status code: " + status, synchronous);
7194                 }
7195
7196                 // Prevent potential IE memory leak
7197                 xhr = null;
7198             }
7199         },
7200
7201         /**
7202          * Explicitly exclude files from being loaded. Useful when used in conjunction with a broad include expression.
7203          * Can be chained with more `require` and `exclude` methods, eg:
7204
7205     Ext.exclude('Ext.data.*').require('*');
7206
7207     Ext.exclude('widget.button*').require('widget.*');
7208
7209          * @param {Array} excludes
7210          * @return {Object} object contains `require` method for chaining
7211          * @markdown
7212          */
7213         exclude: function(excludes) {
7214             var me = this;
7215
7216             return {
7217                 require: function(expressions, fn, scope) {
7218                     return me.require(expressions, fn, scope, excludes);
7219                 },
7220
7221                 syncRequire: function(expressions, fn, scope) {
7222                     return me.syncRequire(expressions, fn, scope, excludes);
7223                 }
7224             };
7225         },
7226
7227         /**
7228          * Synchronously loads all classes by the given names and all their direct dependencies; optionally executes the given callback function when finishes, within the optional scope. This method is aliased by {@link Ext#syncRequire} for convenience
7229          * @param {String/Array} expressions Can either be a string or an array of string
7230          * @param {Function} fn (Optional) The callback function
7231          * @param {Object} scope (Optional) The execution scope (`this`) of the callback function
7232          * @param {String/Array} excludes (Optional) Classes to be excluded, useful when being used with expressions
7233          * @markdown
7234          */
7235         syncRequire: function() {
7236             this.syncModeEnabled = true;
7237             this.require.apply(this, arguments);
7238             this.refreshQueue();
7239             this.syncModeEnabled = false;
7240         },
7241
7242         /**
7243          * Loads all classes by the given names and all their direct dependencies; optionally executes the given callback function when
7244          * finishes, within the optional scope. This method is aliased by {@link Ext#require Ext.require} for convenience
7245          * @param {String/Array} expressions Can either be a string or an array of string
7246          * @param {Function} fn (Optional) The callback function
7247          * @param {Object} scope (Optional) The execution scope (`this`) of the callback function
7248          * @param {String/Array} excludes (Optional) Classes to be excluded, useful when being used with expressions
7249          * @markdown
7250          */
7251         require: function(expressions, fn, scope, excludes) {
7252             var filePath, expression, exclude, className, excluded = {},
7253                 excludedClassNames = [],
7254                 possibleClassNames = [],
7255                 possibleClassName, classNames = [],
7256                 i, j, ln, subLn;
7257
7258             expressions = Ext.Array.from(expressions);
7259             excludes = Ext.Array.from(excludes);
7260
7261             fn = fn || Ext.emptyFn;
7262
7263             scope = scope || Ext.global;
7264
7265             for (i = 0, ln = excludes.length; i < ln; i++) {
7266                 exclude = excludes[i];
7267
7268                 if (typeof exclude === 'string' && exclude.length > 0) {
7269                     excludedClassNames = Manager.getNamesByExpression(exclude);
7270
7271                     for (j = 0, subLn = excludedClassNames.length; j < subLn; j++) {
7272                         excluded[excludedClassNames[j]] = true;
7273                     }
7274                 }
7275             }
7276
7277             for (i = 0, ln = expressions.length; i < ln; i++) {
7278                 expression = expressions[i];
7279
7280                 if (typeof expression === 'string' && expression.length > 0) {
7281                     possibleClassNames = Manager.getNamesByExpression(expression);
7282
7283                     for (j = 0, subLn = possibleClassNames.length; j < subLn; j++) {
7284                         possibleClassName = possibleClassNames[j];
7285
7286                         if (!excluded.hasOwnProperty(possibleClassName) && !Manager.isCreated(possibleClassName)) {
7287                             Ext.Array.include(classNames, possibleClassName);
7288                         }
7289                     }
7290                 }
7291             }
7292
7293             // If the dynamic dependency feature is not being used, throw an error
7294             // if the dependencies are not defined
7295             if (!this.config.enabled) {
7296                 if (classNames.length > 0) {
7297                     Ext.Error.raise({
7298                         sourceClass: "Ext.Loader",
7299                         sourceMethod: "require",
7300                         msg: "Ext.Loader is not enabled, so dependencies cannot be resolved dynamically. " +
7301                              "Missing required class" + ((classNames.length > 1) ? "es" : "") + ": " + classNames.join(', ')
7302                     });
7303                 }
7304             }
7305
7306             if (classNames.length === 0) {
7307                 fn.call(scope);
7308                 return this;
7309             }
7310
7311             this.queue.push({
7312                 requires: classNames,
7313                 callback: fn,
7314                 scope: scope
7315             });
7316
7317             classNames = classNames.slice();
7318
7319             for (i = 0, ln = classNames.length; i < ln; i++) {
7320                 className = classNames[i];
7321
7322                 if (!this.isFileLoaded.hasOwnProperty(className)) {
7323                     this.isFileLoaded[className] = false;
7324
7325                     filePath = this.getPath(className);
7326
7327                     this.classNameToFilePathMap[className] = filePath;
7328
7329                     this.numPendingFiles++;
7330
7331                     this.loadScriptFile(
7332                         filePath,
7333                         Ext.Function.pass(this.onFileLoaded, [className, filePath], this),
7334                         Ext.Function.pass(this.onFileLoadError, [className, filePath]),
7335                         this,
7336                         this.syncModeEnabled
7337                     );
7338                 }
7339             }
7340
7341             return this;
7342         },
7343
7344         /**
7345          * @private
7346          * @param {String} className
7347          * @param {String} filePath
7348          */
7349         onFileLoaded: function(className, filePath) {
7350             this.numLoadedFiles++;
7351
7352             this.isFileLoaded[className] = true;
7353
7354             this.numPendingFiles--;
7355
7356             if (this.numPendingFiles === 0) {
7357                 this.refreshQueue();
7358             }
7359
7360             if (this.numPendingFiles <= 1) {
7361                 window.status = "Finished loading all dependencies, onReady fired!";
7362             }
7363             else {
7364                 window.status = "Loading dependencies, " + this.numPendingFiles + " files left...";
7365             }
7366
7367             if (!this.syncModeEnabled && this.numPendingFiles === 0 && this.isLoading && !this.hasFileLoadError) {
7368                 var queue = this.queue,
7369                     requires,
7370                     i, ln, j, subLn, missingClasses = [], missingPaths = [];
7371
7372                 for (i = 0, ln = queue.length; i < ln; i++) {
7373                     requires = queue[i].requires;
7374
7375                     for (j = 0, subLn = requires.length; j < ln; j++) {
7376                         if (this.isFileLoaded[requires[j]]) {
7377                             missingClasses.push(requires[j]);
7378                         }
7379                     }
7380                 }
7381
7382                 if (missingClasses.length < 1) {
7383                     return;
7384                 }
7385
7386                 missingClasses = Ext.Array.filter(missingClasses, function(item) {
7387                     return !this.requiresMap.hasOwnProperty(item);
7388                 }, this);
7389
7390                 for (i = 0,ln = missingClasses.length; i < ln; i++) {
7391                     missingPaths.push(this.classNameToFilePathMap[missingClasses[i]]);
7392                 }
7393
7394                 Ext.Error.raise({
7395                     sourceClass: "Ext.Loader",
7396                     sourceMethod: "onFileLoaded",
7397                     msg: "The following classes are not declared even if their files have been " +
7398                             "loaded: '" + missingClasses.join("', '") + "'. Please check the source code of their " +
7399                             "corresponding files for possible typos: '" + missingPaths.join("', '") + "'"
7400                 });
7401             }
7402         },
7403
7404         /**
7405          * @private
7406          */
7407         onFileLoadError: function(className, filePath, errorMessage, isSynchronous) {
7408             this.numPendingFiles--;
7409             this.hasFileLoadError = true;
7410
7411             Ext.Error.raise({
7412                 sourceClass: "Ext.Loader",
7413                 classToLoad: className,
7414                 loadPath: filePath,
7415                 loadingType: isSynchronous ? 'synchronous' : 'async',
7416                 msg: errorMessage
7417             });
7418         },
7419
7420         /**
7421          * @private
7422          */
7423         addOptionalRequires: function(requires) {
7424             var optionalRequires = this.optionalRequires,
7425                 i, ln, require;
7426
7427             requires = Ext.Array.from(requires);
7428
7429             for (i = 0, ln = requires.length; i < ln; i++) {
7430                 require = requires[i];
7431
7432                 Ext.Array.include(optionalRequires, require);
7433             }
7434
7435             return this;
7436         },
7437
7438         /**
7439          * @private
7440          */
7441         triggerReady: function(force) {
7442             var readyListeners = this.readyListeners,
7443                 optionalRequires, listener;
7444
7445             if (this.isLoading || force) {
7446                 this.isLoading = false;
7447
7448                 if (this.optionalRequires.length) {
7449                     // Clone then empty the array to eliminate potential recursive loop issue
7450                     optionalRequires = Ext.Array.clone(this.optionalRequires);
7451
7452                     // Empty the original array
7453                     this.optionalRequires.length = 0;
7454
7455                     this.require(optionalRequires, Ext.Function.pass(this.triggerReady, [true], this), this);
7456                     return this;
7457                 }
7458
7459                 while (readyListeners.length) {
7460                     listener = readyListeners.shift();
7461                     listener.fn.call(listener.scope);
7462
7463                     if (this.isLoading) {
7464                         return this;
7465                     }
7466                 }
7467             }
7468
7469             return this;
7470         },
7471
7472         /**
7473          * Add a new listener to be executed when all required scripts are fully loaded
7474          *
7475          * @param {Function} fn The function callback to be executed
7476          * @param {Object} scope The execution scope (<code>this</code>) of the callback function
7477          * @param {Boolean} withDomReady Whether or not to wait for document dom ready as well
7478          */
7479         onReady: function(fn, scope, withDomReady, options) {
7480             var oldFn;
7481
7482             if (withDomReady !== false && Ext.onDocumentReady) {
7483                 oldFn = fn;
7484
7485                 fn = function() {
7486                     Ext.onDocumentReady(oldFn, scope, options);
7487                 };
7488             }
7489
7490             if (!this.isLoading) {
7491                 fn.call(scope);
7492             }
7493             else {
7494                 this.readyListeners.push({
7495                     fn: fn,
7496                     scope: scope
7497                 });
7498             }
7499         },
7500
7501         /**
7502          * @private
7503          * @param {String} className
7504          */
7505         historyPush: function(className) {
7506             if (className && this.isFileLoaded.hasOwnProperty(className)) {
7507                 Ext.Array.include(this.history, className);
7508             }
7509
7510             return this;
7511         }
7512     };
7513
7514     /**
7515      * Convenient alias of {@link Ext.Loader#require}. Please see the introduction documentation of
7516      * {@link Ext.Loader} for examples.
7517      * @member Ext
7518      * @method require
7519      */
7520     Ext.require = alias(Loader, 'require');
7521
7522     /**
7523      * Synchronous version of {@link Ext#require}, convenient alias of {@link Ext.Loader#syncRequire}.
7524      *
7525      * @member Ext
7526      * @method syncRequire
7527      */
7528     Ext.syncRequire = alias(Loader, 'syncRequire');
7529
7530     /**
7531      * Convenient shortcut to {@link Ext.Loader#exclude}
7532      * @member Ext
7533      * @method exclude
7534      */
7535     Ext.exclude = alias(Loader, 'exclude');
7536
7537     /**
7538      * @member Ext
7539      * @method onReady
7540      */
7541     Ext.onReady = function(fn, scope, options) {
7542         Loader.onReady(fn, scope, true, options);
7543     };
7544
7545     Class.registerPreprocessor('loader', function(cls, data, continueFn) {
7546         var me = this,
7547             dependencies = [],
7548             className = Manager.getName(cls),
7549             i, j, ln, subLn, value, propertyName, propertyValue;
7550
7551         /*
7552         Basically loop through the dependencyProperties, look for string class names and push
7553         them into a stack, regardless of whether the property's value is a string, array or object. For example:
7554         {
7555               extend: 'Ext.MyClass',
7556               requires: ['Ext.some.OtherClass'],
7557               mixins: {
7558                   observable: 'Ext.util.Observable';
7559               }
7560         }
7561         which will later be transformed into:
7562         {
7563               extend: Ext.MyClass,
7564               requires: [Ext.some.OtherClass],
7565               mixins: {
7566                   observable: Ext.util.Observable;
7567               }
7568         }
7569         */
7570
7571         for (i = 0, ln = dependencyProperties.length; i < ln; i++) {
7572             propertyName = dependencyProperties[i];
7573
7574             if (data.hasOwnProperty(propertyName)) {
7575                 propertyValue = data[propertyName];
7576
7577                 if (typeof propertyValue === 'string') {
7578                     dependencies.push(propertyValue);
7579                 }
7580                 else if (propertyValue instanceof Array) {
7581                     for (j = 0, subLn = propertyValue.length; j < subLn; j++) {
7582                         value = propertyValue[j];
7583
7584                         if (typeof value === 'string') {
7585                             dependencies.push(value);
7586                         }
7587                     }
7588                 }
7589                 else {
7590                     for (j in propertyValue) {
7591                         if (propertyValue.hasOwnProperty(j)) {
7592                             value = propertyValue[j];
7593
7594                             if (typeof value === 'string') {
7595                                 dependencies.push(value);
7596                             }
7597                         }
7598                     }
7599                 }
7600             }
7601         }
7602
7603         if (dependencies.length === 0) {
7604 //            Loader.historyPush(className);
7605             return;
7606         }
7607
7608         var deadlockPath = [],
7609             requiresMap = Loader.requiresMap,
7610             detectDeadlock;
7611
7612         /*
7613         Automatically detect deadlocks before-hand,
7614         will throw an error with detailed path for ease of debugging. Examples of deadlock cases:
7615
7616         - A extends B, then B extends A
7617         - A requires B, B requires C, then C requires A
7618
7619         The detectDeadlock function will recursively transverse till the leaf, hence it can detect deadlocks
7620         no matter how deep the path is.
7621         */
7622
7623         if (className) {
7624             requiresMap[className] = dependencies;
7625
7626             detectDeadlock = function(cls) {
7627                 deadlockPath.push(cls);
7628
7629                 if (requiresMap[cls]) {
7630                     if (Ext.Array.contains(requiresMap[cls], className)) {
7631                         Ext.Error.raise({
7632                             sourceClass: "Ext.Loader",
7633                             msg: "Deadlock detected while loading dependencies! '" + className + "' and '" +
7634                                 deadlockPath[1] + "' " + "mutually require each other. Path: " +
7635                                 deadlockPath.join(' -> ') + " -> " + deadlockPath[0]
7636                         });
7637                     }
7638
7639                     for (i = 0, ln = requiresMap[cls].length; i < ln; i++) {
7640                         detectDeadlock(requiresMap[cls][i]);
7641                     }
7642                 }
7643             };
7644
7645             detectDeadlock(className);
7646         }
7647
7648
7649         Loader.require(dependencies, function() {
7650             for (i = 0, ln = dependencyProperties.length; i < ln; i++) {
7651                 propertyName = dependencyProperties[i];
7652
7653                 if (data.hasOwnProperty(propertyName)) {
7654                     propertyValue = data[propertyName];
7655
7656                     if (typeof propertyValue === 'string') {
7657                         data[propertyName] = Manager.get(propertyValue);
7658                     }
7659                     else if (propertyValue instanceof Array) {
7660                         for (j = 0, subLn = propertyValue.length; j < subLn; j++) {
7661                             value = propertyValue[j];
7662
7663                             if (typeof value === 'string') {
7664                                 data[propertyName][j] = Manager.get(value);
7665                             }
7666                         }
7667                     }
7668                     else {
7669                         for (var k in propertyValue) {
7670                             if (propertyValue.hasOwnProperty(k)) {
7671                                 value = propertyValue[k];
7672
7673                                 if (typeof value === 'string') {
7674                                     data[propertyName][k] = Manager.get(value);
7675                                 }
7676                             }
7677                         }
7678                     }
7679                 }
7680             }
7681
7682             continueFn.call(me, cls, data);
7683         });
7684
7685         return false;
7686     }, true);
7687
7688     Class.setDefaultPreprocessorPosition('loader', 'after', 'className');
7689
7690     Manager.registerPostprocessor('uses', function(name, cls, data) {
7691         var uses = Ext.Array.from(data.uses),
7692             items = [],
7693             i, ln, item;
7694
7695         for (i = 0, ln = uses.length; i < ln; i++) {
7696             item = uses[i];
7697
7698             if (typeof item === 'string') {
7699                 items.push(item);
7700             }
7701         }
7702
7703         Loader.addOptionalRequires(items);
7704     });
7705
7706     Manager.setDefaultPostprocessorPosition('uses', 'last');
7707
7708 })(Ext.ClassManager, Ext.Class, Ext.Function.flexSetter, Ext.Function.alias);
7709
7710 /**
7711  * @class Ext.Error
7712  * @private
7713  * @extends Error
7714
7715 A wrapper class for the native JavaScript Error object that adds a few useful capabilities for handling
7716 errors in an Ext application. When you use Ext.Error to {@link #raise} an error from within any class that
7717 uses the Ext 4 class system, the Error class can automatically add the source class and method from which
7718 the error was raised. It also includes logic to automatically log the eroor to the console, if available, 
7719 with additional metadata about the error. In all cases, the error will always be thrown at the end so that
7720 execution will halt.
7721
7722 Ext.Error also offers a global error {@link #handle handling} method that can be overridden in order to 
7723 handle application-wide errors in a single spot. You can optionally {@link #ignore} errors altogether,
7724 although in a real application it's usually a better idea to override the handling function and perform
7725 logging or some other method of reporting the errors in a way that is meaningful to the application.
7726
7727 At its simplest you can simply raise an error as a simple string from within any code:
7728
7729 #Example usage:#
7730
7731     Ext.Error.raise('Something bad happened!');
7732     
7733 If raised from plain JavaScript code, the error will be logged to the console (if available) and the message
7734 displayed. In most cases however you'll be raising errors from within a class, and it may often be useful to add
7735 additional metadata about the error being raised.  The {@link #raise} method can also take a config object.
7736 In this form the `msg` attribute becomes the error description, and any other data added to the config gets
7737 added to the error object and, if the console is available, logged to the console for inspection.
7738
7739 #Example usage:#
7740  
7741     Ext.define('Ext.Foo', {
7742         doSomething: function(option){
7743             if (someCondition === false) {
7744                 Ext.Error.raise({
7745                     msg: 'You cannot do that!',
7746                     option: option,   // whatever was passed into the method
7747                     'error code': 100 // other arbitrary info
7748                 });
7749             }
7750         }
7751     });
7752
7753 If a console is available (that supports the `console.dir` function) you'll see console output like:
7754
7755     An error was raised with the following data:
7756     option:         Object { foo: "bar"}
7757         foo:        "bar"
7758     error code:     100
7759     msg:            "You cannot do that!"
7760     sourceClass:   "Ext.Foo"
7761     sourceMethod:  "doSomething"
7762     
7763     uncaught exception: You cannot do that!
7764
7765 As you can see, the error will report exactly where it was raised and will include as much information as the 
7766 raising code can usefully provide.
7767
7768 If you want to handle all application errors globally you can simply override the static {@link handle} method
7769 and provide whatever handling logic you need. If the method returns true then the error is considered handled
7770 and will not be thrown to the browser. If anything but true is returned then the error will be thrown normally.
7771
7772 #Example usage:#
7773
7774     Ext.Error.handle = function(err) {
7775         if (err.someProperty == 'NotReallyAnError') {
7776             // maybe log something to the application here if applicable
7777             return true;
7778         }
7779         // any non-true return value (including none) will cause the error to be thrown
7780     }
7781
7782  * Create a new Error object
7783  * @param {Object} config The config object
7784  * @markdown
7785  * @author Brian Moeskau <brian@sencha.com>
7786  * @docauthor Brian Moeskau <brian@sencha.com>
7787  */
7788 Ext.Error = Ext.extend(Error, {
7789     statics: {
7790         /**
7791          * @property ignore
7792 Static flag that can be used to globally disable error reporting to the browser if set to true
7793 (defaults to false). Note that if you ignore Ext errors it's likely that some other code may fail
7794 and throw a native JavaScript error thereafter, so use with caution. In most cases it will probably
7795 be preferable to supply a custom error {@link #handle handling} function instead.
7796
7797 #Example usage:#
7798
7799     Ext.Error.ignore = true;
7800
7801          * @markdown
7802          * @static
7803          */
7804         ignore: false,
7805
7806         /**
7807 Raise an error that can include additional data and supports automatic console logging if available. 
7808 You can pass a string error message or an object with the `msg` attribute which will be used as the 
7809 error message. The object can contain any other name-value attributes (or objects) to be logged 
7810 along with the error.
7811
7812 Note that after displaying the error message a JavaScript error will ultimately be thrown so that 
7813 execution will halt.
7814
7815 #Example usage:#
7816
7817     Ext.Error.raise('A simple string error message');
7818
7819     // or...
7820
7821     Ext.define('Ext.Foo', {
7822         doSomething: function(option){
7823             if (someCondition === false) {
7824                 Ext.Error.raise({
7825                     msg: 'You cannot do that!',
7826                     option: option,   // whatever was passed into the method
7827                     'error code': 100 // other arbitrary info
7828                 });
7829             }
7830         }
7831     });
7832          * @param {String/Object} err The error message string, or an object containing the 
7833          * attribute "msg" that will be used as the error message. Any other data included in
7834          * the object will also be logged to the browser console, if available.
7835          * @static
7836          * @markdown
7837          */
7838         raise: function(err){
7839             err = err || {};
7840             if (Ext.isString(err)) {
7841                 err = { msg: err };
7842             }
7843
7844             var method = this.raise.caller;
7845
7846             if (method) {
7847                 if (method.$name) {
7848                     err.sourceMethod = method.$name;
7849                 }
7850                 if (method.$owner) {
7851                     err.sourceClass = method.$owner.$className;
7852                 }
7853             }
7854
7855             if (Ext.Error.handle(err) !== true) {
7856                 var global = Ext.global,
7857                     con = global.console,
7858                     msg = Ext.Error.prototype.toString.call(err),
7859                     noConsoleMsg = 'An uncaught error was raised: "' + msg + 
7860                         '". Use Firebug or Webkit console for additional details.';
7861
7862                 if (con) {
7863                     if (con.dir) {
7864                         con.warn('An uncaught error was raised with the following data:');
7865                         con.dir(err);
7866                     }
7867                     else {
7868                         con.warn(noConsoleMsg);
7869                     }
7870                     if (con.error) {
7871                         con.error(msg);
7872                     }
7873                 }
7874                 else if (global.alert){
7875                     global.alert(noConsoleMsg);
7876                 }
7877                 
7878                 throw new Ext.Error(err);
7879             }
7880         },
7881
7882         /**
7883 Globally handle any Ext errors that may be raised, optionally providing custom logic to
7884 handle different errors individually. Return true from the function to bypass throwing the
7885 error to the browser, otherwise the error will be thrown and execution will halt.
7886
7887 #Example usage:#
7888
7889     Ext.Error.handle = function(err) {
7890         if (err.someProperty == 'NotReallyAnError') {
7891             // maybe log something to the application here if applicable
7892             return true;
7893         }
7894         // any non-true return value (including none) will cause the error to be thrown
7895     }
7896
7897          * @param {Ext.Error} err The Ext.Error object being raised. It will contain any attributes
7898          * that were originally raised with it, plus properties about the method and class from which
7899          * the error originated (if raised from a class that uses the Ext 4 class system).
7900          * @static
7901          * @markdown
7902          */
7903         handle: function(){
7904             return Ext.Error.ignore;
7905         }
7906     },
7907
7908     /**
7909      * @constructor
7910      * @param {String/Object} config The error message string, or an object containing the 
7911      * attribute "msg" that will be used as the error message. Any other data included in
7912      * the object will be applied to the error instance and logged to the browser console, if available.
7913      */
7914     constructor: function(config){
7915         if (Ext.isString(config)) {
7916             config = { msg: config };
7917         }
7918         Ext.apply(this, config);
7919     },
7920
7921     /**
7922 Provides a custom string representation of the error object. This is an override of the base JavaScript 
7923 `Object.toString` method, which is useful so that when logged to the browser console, an error object will 
7924 be displayed with a useful message instead of `[object Object]`, the default `toString` result.
7925
7926 The default implementation will include the error message along with the raising class and method, if available,
7927 but this can be overridden with a custom implementation either at the prototype level (for all errors) or on
7928 a particular error instance, if you want to provide a custom description that will show up in the console.
7929      * @markdown
7930      * @return {String} The error message. If raised from within the Ext 4 class system, the error message
7931      * will also include the raising class and method names, if available.
7932      */
7933     toString: function(){
7934         var me = this,
7935             className = me.className ? me.className  : '',
7936             methodName = me.methodName ? '.' + me.methodName + '(): ' : '',
7937             msg = me.msg || '(No description provided)';
7938
7939         return className + methodName + msg;
7940     }
7941 });
7942
7943
7944 /*
7945 Ext JS - JavaScript Library
7946 Copyright (c) 2006-2011, Sencha Inc.
7947 All rights reserved.
7948 licensing@sencha.com
7949 */
7950 /**
7951  * @class Ext.JSON
7952  * Modified version of Douglas Crockford"s json.js that doesn"t
7953  * mess with the Object prototype
7954  * http://www.json.org/js.html
7955  * @singleton
7956  */
7957 Ext.JSON = new(function() {
7958     var useHasOwn = !! {}.hasOwnProperty,
7959     isNative = function() {
7960         var useNative = null;
7961
7962         return function() {
7963             if (useNative === null) {
7964                 useNative = Ext.USE_NATIVE_JSON && window.JSON && JSON.toString() == '[object JSON]';
7965             }
7966
7967             return useNative;
7968         };
7969     }(),
7970     pad = function(n) {
7971         return n < 10 ? "0" + n : n;
7972     },
7973     doDecode = function(json) {
7974         return eval("(" + json + ')');
7975     },
7976     doEncode = function(o) {
7977         if (!Ext.isDefined(o) || o === null) {
7978             return "null";
7979         } else if (Ext.isArray(o)) {
7980             return encodeArray(o);
7981         } else if (Ext.isDate(o)) {
7982             return Ext.JSON.encodeDate(o);
7983         } else if (Ext.isString(o)) {
7984             return encodeString(o);
7985         } else if (typeof o == "number") {
7986             //don't use isNumber here, since finite checks happen inside isNumber
7987             return isFinite(o) ? String(o) : "null";
7988         } else if (Ext.isBoolean(o)) {
7989             return String(o);
7990         } else if (Ext.isObject(o)) {
7991             return encodeObject(o);
7992         } else if (typeof o === "function") {
7993             return "null";
7994         }
7995         return 'undefined';
7996     },
7997     m = {
7998         "\b": '\\b',
7999         "\t": '\\t',
8000         "\n": '\\n',
8001         "\f": '\\f',
8002         "\r": '\\r',
8003         '"': '\\"',
8004         "\\": '\\\\',
8005         '\x0b': '\\u000b' //ie doesn't handle \v
8006     },
8007     charToReplace = /[\\\"\x00-\x1f\x7f-\uffff]/g,
8008     encodeString = function(s) {
8009         return '"' + s.replace(charToReplace, function(a) {
8010             var c = m[a];
8011             return typeof c === 'string' ? c : '\\u' + ('0000' + a.charCodeAt(0).toString(16)).slice(-4);
8012         }) + '"';
8013     },
8014     encodeArray = function(o) {
8015         var a = ["[", ""],
8016         // Note empty string in case there are no serializable members.
8017         len = o.length,
8018         i;
8019         for (i = 0; i < len; i += 1) {
8020             a.push(doEncode(o[i]), ',');
8021         }
8022         // Overwrite trailing comma (or empty string)
8023         a[a.length - 1] = ']';
8024         return a.join("");
8025     },
8026     encodeObject = function(o) {
8027         var a = ["{", ""],
8028         // Note empty string in case there are no serializable members.
8029         i;
8030         for (i in o) {
8031             if (!useHasOwn || o.hasOwnProperty(i)) {
8032                 a.push(doEncode(i), ":", doEncode(o[i]), ',');
8033             }
8034         }
8035         // Overwrite trailing comma (or empty string)
8036         a[a.length - 1] = '}';
8037         return a.join("");
8038     };
8039
8040     /**
8041      * <p>Encodes a Date. This returns the actual string which is inserted into the JSON string as the literal expression.
8042      * <b>The returned value includes enclosing double quotation marks.</b></p>
8043      * <p>The default return format is "yyyy-mm-ddThh:mm:ss".</p>
8044      * <p>To override this:</p><pre><code>
8045      Ext.JSON.encodeDate = function(d) {
8046      return d.format('"Y-m-d"');
8047      };
8048      </code></pre>
8049      * @param {Date} d The Date to encode
8050      * @return {String} The string literal to use in a JSON string.
8051      */
8052     this.encodeDate = function(o) {
8053         return '"' + o.getFullYear() + "-" 
8054         + pad(o.getMonth() + 1) + "-"
8055         + pad(o.getDate()) + "T"
8056         + pad(o.getHours()) + ":"
8057         + pad(o.getMinutes()) + ":"
8058         + pad(o.getSeconds()) + '"';
8059     };
8060
8061     /**
8062      * Encodes an Object, Array or other value
8063      * @param {Mixed} o The variable to encode
8064      * @return {String} The JSON string
8065      */
8066     this.encode = function() {
8067         var ec;
8068         return function(o) {
8069             if (!ec) {
8070                 // setup encoding function on first access
8071                 ec = isNative() ? JSON.stringify : doEncode;
8072             }
8073             return ec(o);
8074         };
8075     }();
8076
8077
8078     /**
8079      * Decodes (parses) a JSON string to an object. If the JSON is invalid, this function throws a SyntaxError unless the safe option is set.
8080      * @param {String} json The JSON string
8081      * @param {Boolean} safe (optional) Whether to return null or throw an exception if the JSON is invalid.
8082      * @return {Object} The resulting object
8083      */
8084     this.decode = function() {
8085         var dc;
8086         return function(json, safe) {
8087             if (!dc) {
8088                 // setup decoding function on first access
8089                 dc = isNative() ? JSON.parse : doDecode;
8090             }
8091             try {
8092                 return dc(json);
8093             } catch (e) {
8094                 if (safe === true) {
8095                     return null;
8096                 }
8097                 Ext.Error.raise({
8098                     sourceClass: "Ext.JSON",
8099                     sourceMethod: "decode",
8100                     msg: "You're trying to decode and invalid JSON String: " + json
8101                 });
8102             }
8103         };
8104     }();
8105
8106 })();
8107 /**
8108  * Shorthand for {@link Ext.JSON#encode}
8109  * @param {Mixed} o The variable to encode
8110  * @return {String} The JSON string
8111  * @member Ext
8112  * @method encode
8113  */
8114 Ext.encode = Ext.JSON.encode;
8115 /**
8116  * Shorthand for {@link Ext.JSON#decode}
8117  * @param {String} json The JSON string
8118  * @param {Boolean} safe (optional) Whether to return null or throw an exception if the JSON is invalid.
8119  * @return {Object} The resulting object
8120  * @member Ext
8121  * @method decode
8122  */
8123 Ext.decode = Ext.JSON.decode;
8124
8125
8126 /**
8127  * @class Ext
8128
8129  The Ext namespace (global object) encapsulates all classes, singletons, and utility methods provided by Sencha's libraries.</p>
8130  Most user interface Components are at a lower level of nesting in the namespace, but many common utility functions are provided
8131  as direct properties of the Ext namespace.
8132
8133  Also many frequently used methods from other classes are provided as shortcuts within the Ext namespace.
8134  For example {@link Ext#getCmp Ext.getCmp} aliases {@link Ext.ComponentManager#get Ext.ComponentManager.get}.
8135
8136  Many applications are initiated with {@link Ext#onReady Ext.onReady} which is called once the DOM is ready.
8137  This ensures all scripts have been loaded, preventing dependency issues. For example
8138
8139      Ext.onReady(function(){
8140          new Ext.Component({
8141              renderTo: document.body,
8142              html: 'DOM ready!'
8143          });
8144      });
8145
8146 For more information about how to use the Ext classes, see
8147
8148 * <a href="http://www.sencha.com/learn/">The Learning Center</a>
8149 * <a href="http://www.sencha.com/learn/Ext_FAQ">The FAQ</a>
8150 * <a href="http://www.sencha.com/forum/">The forums</a>
8151
8152  * @singleton
8153  * @markdown
8154  */
8155 Ext.apply(Ext, {
8156     userAgent: navigator.userAgent.toLowerCase(),
8157     cache: {},
8158     idSeed: 1000,
8159     BLANK_IMAGE_URL : 'data:image/gif;base64,R0lGODlhAQABAID/AMDAwAAAACH5BAEAAAAALAAAAAABAAEAAAICRAEAOw==',
8160     isStrict: document.compatMode == "CSS1Compat",
8161     windowId: 'ext-window',
8162     documentId: 'ext-document',
8163
8164     /**
8165      * True when the document is fully initialized and ready for action
8166      * @type Boolean
8167      */
8168     isReady: false,
8169
8170     /**
8171      * True to automatically uncache orphaned Ext.core.Elements periodically (defaults to true)
8172      * @type Boolean
8173      */
8174     enableGarbageCollector: true,
8175
8176     /**
8177      * True to automatically purge event listeners during garbageCollection (defaults to true).
8178      * @type Boolean
8179      */
8180     enableListenerCollection: true,
8181
8182     /**
8183      * Generates unique ids. If the element already has an id, it is unchanged
8184      * @param {Mixed} el (optional) The element to generate an id for
8185      * @param {String} prefix (optional) Id prefix (defaults "ext-gen")
8186      * @return {String} The generated Id.
8187      */
8188     id: function(el, prefix) {
8189         el = Ext.getDom(el, true) || {};
8190         if (el === document) {
8191             el.id = this.documentId;
8192         }
8193         else if (el === window) {
8194             el.id = this.windowId;
8195         }
8196         if (!el.id) {
8197             el.id = (prefix || "ext-gen") + (++Ext.idSeed);
8198         }
8199         return el.id;
8200     },
8201
8202     /**
8203      * Returns the current document body as an {@link Ext.core.Element}.
8204      * @return Ext.core.Element The document body
8205      */
8206     getBody: function() {
8207         return Ext.get(document.body || false);
8208     },
8209
8210     /**
8211      * Returns the current document head as an {@link Ext.core.Element}.
8212      * @return Ext.core.Element The document head
8213      */
8214     getHead: function() {
8215         var head;
8216
8217         return function() {
8218             if (head == undefined) {
8219                 head = Ext.get(document.getElementsByTagName("head")[0]);
8220             }
8221
8222             return head;
8223         };
8224     }(),
8225
8226     /**
8227      * Returns the current HTML document object as an {@link Ext.core.Element}.
8228      * @return Ext.core.Element The document
8229      */
8230     getDoc: function() {
8231         return Ext.get(document);
8232     },
8233
8234     /**
8235      * This is shorthand reference to {@link Ext.ComponentManager#get}.
8236      * Looks up an existing {@link Ext.Component Component} by {@link Ext.Component#id id}
8237      * @param {String} id The component {@link Ext.Component#id id}
8238      * @return Ext.Component The Component, <tt>undefined</tt> if not found, or <tt>null</tt> if a
8239      * Class was found.
8240     */
8241     getCmp: function(id) {
8242         return Ext.ComponentManager.get(id);
8243     },
8244
8245     /**
8246      * Returns the current orientation of the mobile device
8247      * @return {String} Either 'portrait' or 'landscape'
8248      */
8249     getOrientation: function() {
8250         return window.innerHeight > window.innerWidth ? 'portrait' : 'landscape';
8251     },
8252
8253     /**
8254      * Attempts to destroy any objects passed to it by removing all event listeners, removing them from the
8255      * DOM (if applicable) and calling their destroy functions (if available).  This method is primarily
8256      * intended for arguments of type {@link Ext.core.Element} and {@link Ext.Component}, but any subclass of
8257      * {@link Ext.util.Observable} can be passed in.  Any number of elements and/or components can be
8258      * passed into this function in a single call as separate arguments.
8259      * @param {Mixed} arg1 An {@link Ext.core.Element}, {@link Ext.Component}, or an Array of either of these to destroy
8260      * @param {Mixed} arg2 (optional)
8261      * @param {Mixed} etc... (optional)
8262      */
8263     destroy: function() {
8264         var ln = arguments.length,
8265         i, arg;
8266
8267         for (i = 0; i < ln; i++) {
8268             arg = arguments[i];
8269             if (arg) {
8270                 if (Ext.isArray(arg)) {
8271                     this.destroy.apply(this, arg);
8272                 }
8273                 else if (Ext.isFunction(arg.destroy)) {
8274                     arg.destroy();
8275                 }
8276                 else if (arg.dom) {
8277                     arg.remove();
8278                 }
8279             }
8280         }
8281     },
8282
8283     /**
8284      * Execute a callback function in a particular scope. If no function is passed the call is ignored.
8285      * @param {Function} callback The callback to execute
8286      * @param {Object} scope (optional) The scope to execute in
8287      * @param {Array} args (optional) The arguments to pass to the function
8288      * @param {Number} delay (optional) Pass a number to delay the call by a number of milliseconds.
8289      */
8290     callback: function(callback, scope, args, delay){
8291         if(Ext.isFunction(callback)){
8292             args = args || [];
8293             scope = scope || window;
8294             if (delay) {
8295                 Ext.defer(callback, delay, scope, args);
8296             } else {
8297                 callback.apply(scope, args);
8298             }
8299         }
8300     },
8301
8302     /**
8303      * Convert certain characters (&, <, >, and ') to their HTML character equivalents for literal display in web pages.
8304      * @param {String} value The string to encode
8305      * @return {String} The encoded text
8306      */
8307     htmlEncode : function(value) {
8308         return Ext.String.htmlEncode(value);
8309     },
8310
8311     /**
8312      * Convert certain characters (&, <, >, and ') from their HTML character equivalents.
8313      * @param {String} value The string to decode
8314      * @return {String} The decoded text
8315      */
8316     htmlDecode : function(value) {
8317          return Ext.String.htmlDecode(value);
8318     },
8319
8320     /**
8321      * Appends content to the query string of a URL, handling logic for whether to place
8322      * a question mark or ampersand.
8323      * @param {String} url The URL to append to.
8324      * @param {String} s The content to append to the URL.
8325      * @return (String) The resulting URL
8326      */
8327     urlAppend : function(url, s) {
8328         if (!Ext.isEmpty(s)) {
8329             return url + (url.indexOf('?') === -1 ? '?' : '&') + s;
8330         }
8331         return url;
8332     }
8333 });
8334
8335
8336 Ext.ns = Ext.namespace;
8337
8338 // for old browsers
8339 window.undefined = window.undefined;
8340 /**
8341  * @class Ext
8342  * Ext core utilities and functions.
8343  * @singleton
8344  */
8345 (function(){
8346     var check = function(regex){
8347             return regex.test(Ext.userAgent);
8348         },
8349         docMode = document.documentMode,
8350         isOpera = check(/opera/),
8351         isOpera10_5 = isOpera && check(/version\/10\.5/),
8352         isChrome = check(/\bchrome\b/),
8353         isWebKit = check(/webkit/),
8354         isSafari = !isChrome && check(/safari/),
8355         isSafari2 = isSafari && check(/applewebkit\/4/), // unique to Safari 2
8356         isSafari3 = isSafari && check(/version\/3/),
8357         isSafari4 = isSafari && check(/version\/4/),
8358         isIE = !isOpera && check(/msie/),
8359         isIE7 = isIE && (check(/msie 7/) || docMode == 7),
8360         isIE8 = isIE && (check(/msie 8/) && docMode != 7 && docMode != 9 || docMode == 8),
8361         isIE9 = isIE && (check(/msie 9/) && docMode != 7 && docMode != 8 || docMode == 9),
8362         isIE6 = isIE && check(/msie 6/),
8363         isGecko = !isWebKit && check(/gecko/),
8364         isGecko3 = isGecko && check(/rv:1\.9/),
8365         isGecko4 = isGecko && check(/rv:2\.0/),
8366         isFF3_0 = isGecko3 && check(/rv:1\.9\.0/),
8367         isFF3_5 = isGecko3 && check(/rv:1\.9\.1/),
8368         isFF3_6 = isGecko3 && check(/rv:1\.9\.2/),
8369         isWindows = check(/windows|win32/),
8370         isMac = check(/macintosh|mac os x/),
8371         isLinux = check(/linux/),
8372         scrollWidth = null;
8373
8374     // remove css image flicker
8375     try {
8376         document.execCommand("BackgroundImageCache", false, true);
8377     } catch(e) {}
8378
8379     Ext.setVersion('extjs', '4.0.0');
8380     Ext.apply(Ext, {
8381         /**
8382          * URL to a blank file used by Ext when in secure mode for iframe src and onReady src to prevent
8383          * the IE insecure content warning (<tt>'about:blank'</tt>, except for IE in secure mode, which is <tt>'javascript:""'</tt>).
8384          * @type String
8385          */
8386         SSL_SECURE_URL : Ext.isSecure && isIE ? 'javascript:""' : 'about:blank',
8387
8388         /**
8389          * True if the {@link Ext.fx.Anim} Class is available
8390          * @type Boolean
8391          * @property enableFx
8392          */
8393
8394         /**
8395          * True to scope the reset CSS to be just applied to Ext components. Note that this wraps root containers
8396          * with an additional element. Also remember that when you turn on this option, you have to use ext-all-scoped {
8397          * unless you use the bootstrap.js to load your javascript, in which case it will be handled for you.
8398          * @type Boolean
8399          */
8400         scopeResetCSS : Ext.buildSettings.scopeResetCSS,
8401
8402         /**
8403          * EXPERIMENTAL - True to cascade listener removal to child elements when an element is removed.
8404          * Currently not optimized for performance.
8405          * @type Boolean
8406          */
8407         enableNestedListenerRemoval : false,
8408
8409         /**
8410          * Indicates whether to use native browser parsing for JSON methods.
8411          * This option is ignored if the browser does not support native JSON methods.
8412          * <b>Note: Native JSON methods will not work with objects that have functions.
8413          * Also, property names must be quoted, otherwise the data will not parse.</b> (Defaults to false)
8414          * @type Boolean
8415          */
8416         USE_NATIVE_JSON : false,
8417
8418         /**
8419          * Return the dom node for the passed String (id), dom node, or Ext.core.Element.
8420          * Optional 'strict' flag is needed for IE since it can return 'name' and
8421          * 'id' elements by using getElementById.
8422          * Here are some examples:
8423          * <pre><code>
8424 // gets dom node based on id
8425 var elDom = Ext.getDom('elId');
8426 // gets dom node based on the dom node
8427 var elDom1 = Ext.getDom(elDom);
8428
8429 // If we don&#39;t know if we are working with an
8430 // Ext.core.Element or a dom node use Ext.getDom
8431 function(el){
8432     var dom = Ext.getDom(el);
8433     // do something with the dom node
8434 }
8435          * </code></pre>
8436          * <b>Note</b>: the dom node to be found actually needs to exist (be rendered, etc)
8437          * when this method is called to be successful.
8438          * @param {Mixed} el
8439          * @return HTMLElement
8440          */
8441         getDom : function(el, strict) {
8442             if (!el || !document) {
8443                 return null;
8444             }
8445             if (el.dom) {
8446                 return el.dom;
8447             } else {
8448                 if (typeof el == 'string') {
8449                     var e = document.getElementById(el);
8450                     // IE returns elements with the 'name' and 'id' attribute.
8451                     // we do a strict check to return the element with only the id attribute
8452                     if (e && isIE && strict) {
8453                         if (el == e.getAttribute('id')) {
8454                             return e;
8455                         } else {
8456                             return null;
8457                         }
8458                     }
8459                     return e;
8460                 } else {
8461                     return el;
8462                 }
8463             }
8464         },
8465
8466         /**
8467          * Removes a DOM node from the document.
8468          * <p>Removes this element from the document, removes all DOM event listeners, and deletes the cache reference.
8469          * All DOM event listeners are removed from this element. If {@link Ext#enableNestedListenerRemoval Ext.enableNestedListenerRemoval} is
8470          * <code>true</code>, then DOM event listeners are also removed from all child nodes. The body node
8471          * will be ignored if passed in.</p>
8472          * @param {HTMLElement} node The node to remove
8473          */
8474         removeNode : isIE6 || isIE7 ? function() {
8475             var d;
8476             return function(n){
8477                 if(n && n.tagName != 'BODY'){
8478                     (Ext.enableNestedListenerRemoval) ? Ext.EventManager.purgeElement(n) : Ext.EventManager.removeAll(n);
8479                     d = d || document.createElement('div');
8480                     d.appendChild(n);
8481                     d.innerHTML = '';
8482                     delete Ext.cache[n.id];
8483                 }
8484             };
8485         }() : function(n) {
8486             if (n && n.parentNode && n.tagName != 'BODY') {
8487                 (Ext.enableNestedListenerRemoval) ? Ext.EventManager.purgeElement(n) : Ext.EventManager.removeAll(n);
8488                 n.parentNode.removeChild(n);
8489                 delete Ext.cache[n.id];
8490             }
8491         },
8492
8493         /**
8494          * True if the detected browser is Opera.
8495          * @type Boolean
8496          */
8497         isOpera : isOpera,
8498
8499         /**
8500          * True if the detected browser is Opera 10.5x.
8501          * @type Boolean
8502          */
8503         isOpera10_5 : isOpera10_5,
8504
8505         /**
8506          * True if the detected browser uses WebKit.
8507          * @type Boolean
8508          */
8509         isWebKit : isWebKit,
8510
8511         /**
8512          * True if the detected browser is Chrome.
8513          * @type Boolean
8514          */
8515         isChrome : isChrome,
8516
8517         /**
8518          * True if the detected browser is Safari.
8519          * @type Boolean
8520          */
8521         isSafari : isSafari,
8522
8523         /**
8524          * True if the detected browser is Safari 3.x.
8525          * @type Boolean
8526          */
8527         isSafari3 : isSafari3,
8528
8529         /**
8530          * True if the detected browser is Safari 4.x.
8531          * @type Boolean
8532          */
8533         isSafari4 : isSafari4,
8534
8535         /**
8536          * True if the detected browser is Safari 2.x.
8537          * @type Boolean
8538          */
8539         isSafari2 : isSafari2,
8540
8541         /**
8542          * True if the detected browser is Internet Explorer.
8543          * @type Boolean
8544          */
8545         isIE : isIE,
8546
8547         /**
8548          * True if the detected browser is Internet Explorer 6.x.
8549          * @type Boolean
8550          */
8551         isIE6 : isIE6,
8552
8553         /**
8554          * True if the detected browser is Internet Explorer 7.x.
8555          * @type Boolean
8556          */
8557         isIE7 : isIE7,
8558
8559         /**
8560          * True if the detected browser is Internet Explorer 8.x.
8561          * @type Boolean
8562          */
8563         isIE8 : isIE8,
8564
8565         /**
8566          * True if the detected browser is Internet Explorer 9.x.
8567          * @type Boolean
8568          */
8569         isIE9 : isIE9,
8570
8571         /**
8572          * True if the detected browser uses the Gecko layout engine (e.g. Mozilla, Firefox).
8573          * @type Boolean
8574          */
8575         isGecko : isGecko,
8576
8577         /**
8578          * True if the detected browser uses a Gecko 1.9+ layout engine (e.g. Firefox 3.x).
8579          * @type Boolean
8580          */
8581         isGecko3 : isGecko3,
8582
8583         /**
8584          * True if the detected browser uses a Gecko 2.0+ layout engine (e.g. Firefox 4.x).
8585          * @type Boolean
8586          */
8587         isGecko4 : isGecko4,
8588
8589         /**
8590          * True if the detected browser uses FireFox 3.0
8591          * @type Boolean
8592          */
8593
8594         isFF3_0 : isFF3_0,
8595         /**
8596          * True if the detected browser uses FireFox 3.5
8597          * @type Boolean
8598          */
8599
8600         isFF3_5 : isFF3_5,
8601         /**
8602          * True if the detected browser uses FireFox 3.6
8603          * @type Boolean
8604          */
8605         isFF3_6 : isFF3_6,
8606
8607         /**
8608          * True if the detected platform is Linux.
8609          * @type Boolean
8610          */
8611         isLinux : isLinux,
8612
8613         /**
8614          * True if the detected platform is Windows.
8615          * @type Boolean
8616          */
8617         isWindows : isWindows,
8618
8619         /**
8620          * True if the detected platform is Mac OS.
8621          * @type Boolean
8622          */
8623         isMac : isMac,
8624
8625         /**
8626          * URL to a 1x1 transparent gif image used by Ext to create inline icons with CSS background images.
8627          * In older versions of IE, this defaults to "http://sencha.com/s.gif" and you should change this to a URL on your server.
8628          * For other browsers it uses an inline data URL.
8629          * @type String
8630          */
8631         BLANK_IMAGE_URL : (isIE6 || isIE7) ? 'http:/' + '/www.sencha.com/s.gif' : 'data:image/gif;base64,R0lGODlhAQABAID/AMDAwAAAACH5BAEAAAAALAAAAAABAAEAAAICRAEAOw==',
8632
8633         /**
8634          * <p>Utility method for returning a default value if the passed value is empty.</p>
8635          * <p>The value is deemed to be empty if it is<div class="mdetail-params"><ul>
8636          * <li>null</li>
8637          * <li>undefined</li>
8638          * <li>an empty array</li>
8639          * <li>a zero length string (Unless the <tt>allowBlank</tt> parameter is <tt>true</tt>)</li>
8640          * </ul></div>
8641          * @param {Mixed} value The value to test
8642          * @param {Mixed} defaultValue The value to return if the original value is empty
8643          * @param {Boolean} allowBlank (optional) true to allow zero length strings to qualify as non-empty (defaults to false)
8644          * @return {Mixed} value, if non-empty, else defaultValue
8645          * @deprecated 4.0.0 Use {Ext#valueFrom} instead
8646          */
8647         value : function(v, defaultValue, allowBlank){
8648             return Ext.isEmpty(v, allowBlank) ? defaultValue : v;
8649         },
8650
8651         /**
8652          * Escapes the passed string for use in a regular expression
8653          * @param {String} str
8654          * @return {String}
8655          * @deprecated 4.0.0 Use {@link Ext.String#escapeRegex} instead
8656          */
8657         escapeRe : function(s) {
8658             return s.replace(/([-.*+?^${}()|[\]\/\\])/g, "\\$1");
8659         },
8660
8661         /**
8662          * Applies event listeners to elements by selectors when the document is ready.
8663          * The event name is specified with an <tt>&#64;</tt> suffix.
8664          * <pre><code>
8665 Ext.addBehaviors({
8666     // add a listener for click on all anchors in element with id foo
8667     '#foo a&#64;click' : function(e, t){
8668         // do something
8669     },
8670
8671     // add the same listener to multiple selectors (separated by comma BEFORE the &#64;)
8672     '#foo a, #bar span.some-class&#64;mouseover' : function(){
8673         // do something
8674     }
8675 });
8676          * </code></pre>
8677          * @param {Object} obj The list of behaviors to apply
8678          */
8679         addBehaviors : function(o){
8680             if(!Ext.isReady){
8681                 Ext.onReady(function(){
8682                     Ext.addBehaviors(o);
8683                 });
8684             } else {
8685                 var cache = {}, // simple cache for applying multiple behaviors to same selector does query multiple times
8686                     parts,
8687                     b,
8688                     s;
8689                 for (b in o) {
8690                     if ((parts = b.split('@'))[1]) { // for Object prototype breakers
8691                         s = parts[0];
8692                         if(!cache[s]){
8693                             cache[s] = Ext.select(s);
8694                         }
8695                         cache[s].on(parts[1], o[b]);
8696                     }
8697                 }
8698                 cache = null;
8699             }
8700         },
8701
8702         /**
8703          * Utility method for getting the width of the browser scrollbar. This can differ depending on
8704          * operating system settings, such as the theme or font size.
8705          * @param {Boolean} force (optional) true to force a recalculation of the value.
8706          * @return {Number} The width of the scrollbar.
8707          */
8708         getScrollBarWidth: function(force){
8709             if(!Ext.isReady){
8710                 return 0;
8711             }
8712
8713             if(force === true || scrollWidth === null){
8714                 // BrowserBug: IE9
8715                 // When IE9 positions an element offscreen via offsets, the offsetWidth is
8716                 // inaccurately reported. For IE9 only, we render on screen before removing.
8717                 var cssClass = Ext.isIE9 ? '' : Ext.baseCSSPrefix + 'hide-offsets';
8718                     // Append our div, do our calculation and then remove it
8719                 var div = Ext.getBody().createChild('<div class="' + cssClass + '" style="width:100px;height:50px;overflow:hidden;"><div style="height:200px;"></div></div>'),
8720                     child = div.child('div', true);
8721                 var w1 = child.offsetWidth;
8722                 div.setStyle('overflow', (Ext.isWebKit || Ext.isGecko) ? 'auto' : 'scroll');
8723                 var w2 = child.offsetWidth;
8724                 div.remove();
8725                 // Need to add 2 to ensure we leave enough space
8726                 scrollWidth = w1 - w2 + 2;
8727             }
8728             return scrollWidth;
8729         },
8730
8731         /**
8732          * Copies a set of named properties fom the source object to the destination object.
8733          * <p>example:<pre><code>
8734 ImageComponent = Ext.extend(Ext.Component, {
8735     initComponent: function() {
8736         this.autoEl = { tag: 'img' };
8737         MyComponent.superclass.initComponent.apply(this, arguments);
8738         this.initialBox = Ext.copyTo({}, this.initialConfig, 'x,y,width,height');
8739     }
8740 });
8741          * </code></pre>
8742          * Important note: To borrow class prototype methods, use {@link Ext.Base#borrow} instead.
8743          * @param {Object} dest The destination object.
8744          * @param {Object} source The source object.
8745          * @param {Array/String} names Either an Array of property names, or a comma-delimited list
8746          * of property names to copy.
8747          * @param {Boolean} usePrototypeKeys (Optional) Defaults to false. Pass true to copy keys off of the prototype as well as the instance.
8748          * @return {Object} The modified object.
8749         */
8750         copyTo : function(dest, source, names, usePrototypeKeys){
8751             if(typeof names == 'string'){
8752                 names = names.split(/[,;\s]/);
8753             }
8754             Ext.each(names, function(name){
8755                 if(usePrototypeKeys || source.hasOwnProperty(name)){
8756                     dest[name] = source[name];
8757                 }
8758             }, this);
8759             return dest;
8760         },
8761
8762         /**
8763          * Attempts to destroy and then remove a set of named properties of the passed object.
8764          * @param {Object} o The object (most likely a Component) who's properties you wish to destroy.
8765          * @param {Mixed} arg1 The name of the property to destroy and remove from the object.
8766          * @param {Mixed} etc... More property names to destroy and remove.
8767          */
8768         destroyMembers : function(o, arg1, arg2, etc){
8769             for (var i = 1, a = arguments, len = a.length; i < len; i++) {
8770                 Ext.destroy(o[a[i]]);
8771                 delete o[a[i]];
8772             }
8773         },
8774
8775         /**
8776          * Partitions the set into two sets: a true set and a false set.
8777          * Example:
8778          * Example2:
8779          * <pre><code>
8780 // Example 1:
8781 Ext.partition([true, false, true, true, false]); // [[true, true, true], [false, false]]
8782
8783 // Example 2:
8784 Ext.partition(
8785     Ext.query("p"),
8786     function(val){
8787         return val.className == "class1"
8788     }
8789 );
8790 // true are those paragraph elements with a className of "class1",
8791 // false set are those that do not have that className.
8792          * </code></pre>
8793          * @param {Array|NodeList} arr The array to partition
8794          * @param {Function} truth (optional) a function to determine truth.  If this is omitted the element
8795          *                   itself must be able to be evaluated for its truthfulness.
8796          * @return {Array} [true<Array>,false<Array>]
8797          * @deprecated 4.0.0 Will be removed in the next major version
8798          */
8799         partition : function(arr, truth){
8800             var ret = [[],[]];
8801             Ext.each(arr, function(v, i, a) {
8802                 ret[ (truth && truth(v, i, a)) || (!truth && v) ? 0 : 1].push(v);
8803             });
8804             return ret;
8805         },
8806
8807         /**
8808          * Invokes a method on each item in an Array.
8809          * <pre><code>
8810 // Example:
8811 Ext.invoke(Ext.query("p"), "getAttribute", "id");
8812 // [el1.getAttribute("id"), el2.getAttribute("id"), ..., elN.getAttribute("id")]
8813          * </code></pre>
8814          * @param {Array|NodeList} arr The Array of items to invoke the method on.
8815          * @param {String} methodName The method name to invoke.
8816          * @param {...*} args Arguments to send into the method invocation.
8817          * @return {Array} The results of invoking the method on each item in the array.
8818          * @deprecated 4.0.0 Will be removed in the next major version
8819          */
8820         invoke : function(arr, methodName){
8821             var ret = [],
8822                 args = Array.prototype.slice.call(arguments, 2);
8823             Ext.each(arr, function(v,i) {
8824                 if (v && typeof v[methodName] == 'function') {
8825                     ret.push(v[methodName].apply(v, args));
8826                 } else {
8827                     ret.push(undefined);
8828                 }
8829             });
8830             return ret;
8831         },
8832
8833         /**
8834          * <p>Zips N sets together.</p>
8835          * <pre><code>
8836 // Example 1:
8837 Ext.zip([1,2,3],[4,5,6]); // [[1,4],[2,5],[3,6]]
8838 // Example 2:
8839 Ext.zip(
8840     [ "+", "-", "+"],
8841     [  12,  10,  22],
8842     [  43,  15,  96],
8843     function(a, b, c){
8844         return "$" + a + "" + b + "." + c
8845     }
8846 ); // ["$+12.43", "$-10.15", "$+22.96"]
8847          * </code></pre>
8848          * @param {Arrays|NodeLists} arr This argument may be repeated. Array(s) to contribute values.
8849          * @param {Function} zipper (optional) The last item in the argument list. This will drive how the items are zipped together.
8850          * @return {Array} The zipped set.
8851          * @deprecated 4.0.0 Will be removed in the next major version
8852          */
8853         zip : function(){
8854             var parts = Ext.partition(arguments, function( val ){ return typeof val != 'function'; }),
8855                 arrs = parts[0],
8856                 fn = parts[1][0],
8857                 len = Ext.max(Ext.pluck(arrs, "length")),
8858                 ret = [];
8859
8860             for (var i = 0; i < len; i++) {
8861                 ret[i] = [];
8862                 if(fn){
8863                     ret[i] = fn.apply(fn, Ext.pluck(arrs, i));
8864                 }else{
8865                     for (var j = 0, aLen = arrs.length; j < aLen; j++){
8866                         ret[i].push( arrs[j][i] );
8867                     }
8868                 }
8869             }
8870             return ret;
8871         },
8872
8873         /**
8874          * Turns an array into a sentence, joined by a specified connector - e.g.:
8875          * Ext.toSentence(['Adama', 'Tigh', 'Roslin']); //'Adama, Tigh and Roslin'
8876          * Ext.toSentence(['Adama', 'Tigh', 'Roslin'], 'or'); //'Adama, Tigh or Roslin'
8877          * @param {Array} items The array to create a sentence from
8878          * @param {String} connector The string to use to connect the last two words. Usually 'and' or 'or' - defaults to 'and'.
8879          * @return {String} The sentence string
8880          * @deprecated 4.0.0 Will be removed in the next major version
8881          */
8882         toSentence: function(items, connector) {
8883             var length = items.length;
8884
8885             if (length <= 1) {
8886                 return items[0];
8887             } else {
8888                 var head = items.slice(0, length - 1),
8889                     tail = items[length - 1];
8890
8891                 return Ext.util.Format.format("{0} {1} {2}", head.join(", "), connector || 'and', tail);
8892             }
8893         },
8894
8895         /**
8896          * By default, Ext intelligently decides whether floating elements should be shimmed. If you are using flash,
8897          * you may want to set this to true.
8898          * @type Boolean
8899          */
8900         useShims: isIE6
8901     });
8902 })();
8903
8904 /**
8905  * TBD
8906  * @type Function
8907  * @param {Object} config
8908  */
8909 Ext.application = function(config) {
8910     Ext.require('Ext.app.Application');
8911
8912     Ext.onReady(function() {
8913         Ext.create('Ext.app.Application', config);
8914     });
8915 };
8916
8917 /**
8918  * @class Ext.util.Format
8919
8920 This class is a centralized place for formatting functions inside the library. It includes
8921 functions to format various different types of data, such as text, dates and numeric values.
8922
8923 __Localization__
8924 This class contains several options for localization. These can be set once the library has loaded,
8925 all calls to the functions from that point will use the locale settings that were specified.
8926 Options include:
8927 - thousandSeparator
8928 - decimalSeparator
8929 - currenyPrecision
8930 - currencySign
8931 - currencyAtEnd
8932 This class also uses the default date format defined here: {@link Ext.date#defaultFormat}.
8933
8934 __Using with renderers__
8935 There are two helper functions that return a new function that can be used in conjunction with 
8936 grid renderers:
8937
8938     columns: [{
8939         dataIndex: 'date',
8940         renderer: Ext.util.Format.dateRenderer('Y-m-d')
8941     }, {
8942         dataIndex: 'time',
8943         renderer: Ext.util.Format.numberRenderer('0.000')
8944     }]
8945     
8946 Functions that only take a single argument can also be passed directly:
8947     columns: [{
8948         dataIndex: 'cost',
8949         renderer: Ext.util.Format.usMoney
8950     }, {
8951         dataIndex: 'productCode',
8952         renderer: Ext.util.Format.uppercase
8953     }]
8954     
8955 __Using with XTemplates__
8956 XTemplates can also directly use Ext.util.Format functions:
8957
8958     new Ext.XTemplate([
8959         'Date: {startDate:date("Y-m-d")}',
8960         'Cost: {cost:usMoney}'
8961     ]);
8962
8963  * @markdown
8964  * @singleton
8965  */
8966 (function() {
8967     Ext.ns('Ext.util');
8968
8969     Ext.util.Format = {};
8970     var UtilFormat     = Ext.util.Format,
8971         stripTagsRE    = /<\/?[^>]+>/gi,
8972         stripScriptsRe = /(?:<script.*?>)((\n|\r|.)*?)(?:<\/script>)/ig,
8973         nl2brRe        = /\r?\n/g,
8974
8975         // A RegExp to remove from a number format string, all characters except digits and '.'
8976         formatCleanRe  = /[^\d\.]/g,
8977
8978         // A RegExp to remove from a number format string, all characters except digits and the local decimal separator.
8979         // Created on first use. The local decimal separator character must be initialized for this to be created.
8980         I18NFormatCleanRe;
8981
8982     Ext.apply(UtilFormat, {
8983         /**
8984          * @type String
8985          * @property thousandSeparator
8986          * <p>The character that the {@link #number} function uses as a thousand separator.</p>
8987          * <p>This defaults to <code>,</code>, but may be overridden in a locale file.</p>
8988          */
8989         thousandSeparator: ',',
8990
8991         /**
8992          * @type String
8993          * @property decimalSeparator
8994          * <p>The character that the {@link #number} function uses as a decimal point.</p>
8995          * <p>This defaults to <code>.</code>, but may be overridden in a locale file.</p>
8996          */
8997         decimalSeparator: '.',
8998
8999         /**
9000          * @type Number
9001          * @property currencyPrecision
9002          * <p>The number of decimal places that the {@link #currency} function displays.</p>
9003          * <p>This defaults to <code>2</code>, but may be overridden in a locale file.</p>
9004          */
9005         currencyPrecision: 2,
9006
9007         /**
9008          * @type String
9009          * @property currencySign
9010          * <p>The currency sign that the {@link #currency} function displays.</p>
9011          * <p>This defaults to <code>$</code>, but may be overridden in a locale file.</p>
9012          */
9013         currencySign: '$',
9014
9015         /**
9016          * @type Boolean
9017          * @property currencyAtEnd
9018          * <p>This may be set to <code>true</code> to make the {@link #currency} function
9019          * append the currency sign to the formatted value.</p>
9020          * <p>This defaults to <code>false</code>, but may be overridden in a locale file.</p>
9021          */
9022         currencyAtEnd: false,
9023
9024         /**
9025          * Checks a reference and converts it to empty string if it is undefined
9026          * @param {Mixed} value Reference to check
9027          * @return {Mixed} Empty string if converted, otherwise the original value
9028          */
9029         undef : function(value) {
9030             return value !== undefined ? value : "";
9031         },
9032
9033         /**
9034          * Checks a reference and converts it to the default value if it's empty
9035          * @param {Mixed} value Reference to check
9036          * @param {String} defaultValue The value to insert of it's undefined (defaults to "")
9037          * @return {String}
9038          */
9039         defaultValue : function(value, defaultValue) {
9040             return value !== undefined && value !== '' ? value : defaultValue;
9041         },
9042
9043         /**
9044          * Returns a substring from within an original string
9045          * @param {String} value The original text
9046          * @param {Number} start The start index of the substring
9047          * @param {Number} length The length of the substring
9048          * @return {String} The substring
9049          */
9050         substr : function(value, start, length) {
9051             return String(value).substr(start, length);
9052         },
9053
9054         /**
9055          * Converts a string to all lower case letters
9056          * @param {String} value The text to convert
9057          * @return {String} The converted text
9058          */
9059         lowercase : function(value) {
9060             return String(value).toLowerCase();
9061         },
9062
9063         /**
9064          * Converts a string to all upper case letters
9065          * @param {String} value The text to convert
9066          * @return {String} The converted text
9067          */
9068         uppercase : function(value) {
9069             return String(value).toUpperCase();
9070         },
9071
9072         /**
9073          * Format a number as US currency
9074          * @param {Number/String} value The numeric value to format
9075          * @return {String} The formatted currency string
9076          */
9077         usMoney : function(v) {
9078             return UtilFormat.currency(v, '$', 2);
9079         },
9080
9081         /**
9082          * Format a number as a currency
9083          * @param {Number/String} value The numeric value to format
9084          * @param {String} sign The currency sign to use (defaults to {@link #currencySign})
9085          * @param {Number} decimals The number of decimals to use for the currency (defaults to {@link #currencyPrecision})
9086          * @param {Boolean} end True if the currency sign should be at the end of the string (defaults to {@link #currencyAtEnd})
9087          * @return {String} The formatted currency string
9088          */
9089         currency: function(v, currencySign, decimals, end) {
9090             var negativeSign = '',
9091                 format = ",0",
9092                 i = 0;
9093             v = v - 0;
9094             if (v < 0) {
9095                 v = -v;
9096                 negativeSign = '-';
9097             }
9098             decimals = decimals || UtilFormat.currencyPrecision;
9099             format += format + (decimals > 0 ? '.' : '');
9100             for (; i < decimals; i++) {
9101                 format += '0';
9102             }
9103             v = UtilFormat.number(v, format); 
9104             if ((end || UtilFormat.currencyAtEnd) === true) {
9105                 return Ext.String.format("{0}{1}{2}", negativeSign, v, currencySign || UtilFormat.currencySign);
9106             } else {
9107                 return Ext.String.format("{0}{1}{2}", negativeSign, currencySign || UtilFormat.currencySign, v);
9108             }
9109         },
9110
9111         /**
9112          * Formats the passed date using the specified format pattern.
9113          * @param {String/Date} value The value to format. If a string is passed, it is converted to a Date by the Javascript
9114          * Date object's <a href="http://www.w3schools.com/jsref/jsref_parse.asp">parse()</a> method.
9115          * @param {String} format (Optional) Any valid date format string. Defaults to {@link Ext.Date#defaultFormat}.
9116          * @return {String} The formatted date string.
9117          */
9118         date: function(v, format) {
9119             if (!v) {
9120                 return "";
9121             }
9122             if (!Ext.isDate(v)) {
9123                 v = new Date(Date.parse(v));
9124             }
9125             return Ext.Date.dateFormat(v, format || Ext.Date.defaultFormat);
9126         },
9127
9128         /**
9129          * Returns a date rendering function that can be reused to apply a date format multiple times efficiently
9130          * @param {String} format Any valid date format string. Defaults to {@link Ext.Date#defaultFormat}.
9131          * @return {Function} The date formatting function
9132          */
9133         dateRenderer : function(format) {
9134             return function(v) {
9135                 return UtilFormat.date(v, format);
9136             };
9137         },
9138
9139         /**
9140          * Strips all HTML tags
9141          * @param {Mixed} value The text from which to strip tags
9142          * @return {String} The stripped text
9143          */
9144         stripTags : function(v) {
9145             return !v ? v : String(v).replace(stripTagsRE, "");
9146         },
9147
9148         /**
9149          * Strips all script tags
9150          * @param {Mixed} value The text from which to strip script tags
9151          * @return {String} The stripped text
9152          */
9153         stripScripts : function(v) {
9154             return !v ? v : String(v).replace(stripScriptsRe, "");
9155         },
9156
9157         /**
9158          * Simple format for a file size (xxx bytes, xxx KB, xxx MB)
9159          * @param {Number/String} size The numeric value to format
9160          * @return {String} The formatted file size
9161          */
9162         fileSize : function(size) {
9163             if (size < 1024) {
9164                 return size + " bytes";
9165             } else if (size < 1048576) {
9166                 return (Math.round(((size*10) / 1024))/10) + " KB";
9167             } else {
9168                 return (Math.round(((size*10) / 1048576))/10) + " MB";
9169             }
9170         },
9171
9172         /**
9173          * It does simple math for use in a template, for example:<pre><code>
9174          * var tpl = new Ext.Template('{value} * 10 = {value:math("* 10")}');
9175          * </code></pre>
9176          * @return {Function} A function that operates on the passed value.
9177          */
9178         math : function(){
9179             var fns = {};
9180
9181             return function(v, a){
9182                 if (!fns[a]) {
9183                     fns[a] = Ext.functionFactory('v', 'return v ' + a + ';');
9184                 }
9185                 return fns[a](v);
9186             };
9187         }(),
9188
9189         /**
9190          * Rounds the passed number to the required decimal precision.
9191          * @param {Number/String} value The numeric value to round.
9192          * @param {Number} precision The number of decimal places to which to round the first parameter's value.
9193          * @return {Number} The rounded value.
9194          */
9195         round : function(value, precision) {
9196             var result = Number(value);
9197             if (typeof precision == 'number') {
9198                 precision = Math.pow(10, precision);
9199                 result = Math.round(value * precision) / precision;
9200             }
9201             return result;
9202         },
9203
9204         /**
9205          * <p>Formats the passed number according to the passed format string.</p>
9206          * <p>The number of digits after the decimal separator character specifies the number of
9207          * decimal places in the resulting string. The <u>local-specific</u> decimal character is used in the result.</p>
9208          * <p>The <i>presence</i> of a thousand separator character in the format string specifies that
9209          * the <u>locale-specific</u> thousand separator (if any) is inserted separating thousand groups.</p>
9210          * <p>By default, "," is expected as the thousand separator, and "." is expected as the decimal separator.</p>
9211          * <p><b>New to Ext4</b></p>
9212          * <p>Locale-specific characters are always used in the formatted output when inserting
9213          * thousand and decimal separators.</p>
9214          * <p>The format string must specify separator characters according to US/UK conventions ("," as the
9215          * thousand separator, and "." as the decimal separator)</p>
9216          * <p>To allow specification of format strings according to local conventions for separator characters, add
9217          * the string <code>/i</code> to the end of the format string.</p>
9218          * <div style="margin-left:40px">examples (123456.789):
9219          * <div style="margin-left:10px">
9220          * 0 - (123456) show only digits, no precision<br>
9221          * 0.00 - (123456.78) show only digits, 2 precision<br>
9222          * 0.0000 - (123456.7890) show only digits, 4 precision<br>
9223          * 0,000 - (123,456) show comma and digits, no precision<br>
9224          * 0,000.00 - (123,456.78) show comma and digits, 2 precision<br>
9225          * 0,0.00 - (123,456.78) shortcut method, show comma and digits, 2 precision<br>
9226          * To allow specification of the formatting string using UK/US grouping characters (,) and decimal (.) for international numbers, add /i to the end.
9227          * For example: 0.000,00/i
9228          * </div></div>
9229          * @param {Number} v The number to format.
9230          * @param {String} format The way you would like to format this text.
9231          * @return {String} The formatted number.
9232          */
9233         number:
9234             function(v, formatString) {
9235             if (!formatString) {
9236                 return v;
9237             }
9238             v = Ext.Number.from(v, NaN);
9239             if (isNaN(v)) {
9240                 return '';
9241             }
9242             var comma = UtilFormat.thousandSeparator,
9243                 dec   = UtilFormat.decimalSeparator,
9244                 i18n  = false,
9245                 neg   = v < 0,
9246                 hasComma,
9247                 psplit;
9248
9249             v = Math.abs(v);
9250
9251             // The "/i" suffix allows caller to use a locale-specific formatting string.
9252             // Clean the format string by removing all but numerals and the decimal separator.
9253             // Then split the format string into pre and post decimal segments according to *what* the
9254             // decimal separator is. If they are specifying "/i", they are using the local convention in the format string.
9255             if (formatString.substr(formatString.length - 2) == '/i') {
9256                 if (!I18NFormatCleanRe) {
9257                     I18NFormatCleanRe = new RegExp('[^\\d\\' + UtilFormat.decimalSeparator + ']','g');
9258                 }
9259                 formatString = formatString.substr(0, formatString.length - 2);
9260                 i18n   = true;
9261                 hasComma = formatString.indexOf(comma) != -1;
9262                 psplit = formatString.replace(I18NFormatCleanRe, '').split(dec);
9263             } else {
9264                 hasComma = formatString.indexOf(',') != -1;
9265                 psplit = formatString.replace(formatCleanRe, '').split('.');
9266             }
9267
9268             if (1 < psplit.length) {
9269                 v = v.toFixed(psplit[1].length);
9270             } else if(2 < psplit.length) {
9271                 Ext.Error.raise({
9272                     sourceClass: "Ext.util.Format",
9273                     sourceMethod: "number",
9274                     value: v,
9275                     formatString: formatString,
9276                     msg: "Invalid number format, should have no more than 1 decimal"
9277                 });
9278             } else {
9279                 v = v.toFixed(0);
9280             }
9281
9282             var fnum = v.toString();
9283
9284             psplit = fnum.split('.');
9285
9286             if (hasComma) {
9287                 var cnum = psplit[0],
9288                     parr = [],
9289                     j    = cnum.length,
9290                     m    = Math.floor(j / 3),
9291                     n    = cnum.length % 3 || 3,
9292                     i;
9293
9294                 for (i = 0; i < j; i += n) {
9295                     if (i !== 0) {
9296                         n = 3;
9297                     }
9298
9299                     parr[parr.length] = cnum.substr(i, n);
9300                     m -= 1;
9301                 }
9302                 fnum = parr.join(comma);
9303                 if (psplit[1]) {
9304                     fnum += dec + psplit[1];
9305                 }
9306             } else {
9307                 if (psplit[1]) {
9308                     fnum = psplit[0] + dec + psplit[1];
9309                 }
9310             }
9311
9312             return (neg ? '-' : '') + formatString.replace(/[\d,?\.?]+/, fnum);
9313         },
9314
9315         /**
9316          * Returns a number rendering function that can be reused to apply a number format multiple times efficiently
9317          * @param {String} format Any valid number format string for {@link #number}
9318          * @return {Function} The number formatting function
9319          */
9320         numberRenderer : function(format) {
9321             return function(v) {
9322                 return UtilFormat.number(v, format);
9323             };
9324         },
9325
9326         /**
9327          * Selectively do a plural form of a word based on a numeric value. For example, in a template,
9328          * {commentCount:plural("Comment")}  would result in "1 Comment" if commentCount was 1 or would be "x Comments"
9329          * if the value is 0 or greater than 1.
9330          * @param {Number} value The value to compare against
9331          * @param {String} singular The singular form of the word
9332          * @param {String} plural (optional) The plural form of the word (defaults to the singular with an "s")
9333          */
9334         plural : function(v, s, p) {
9335             return v +' ' + (v == 1 ? s : (p ? p : s+'s'));
9336         },
9337
9338         /**
9339          * Converts newline characters to the HTML tag &lt;br/>
9340          * @param {String} The string value to format.
9341          * @return {String} The string with embedded &lt;br/> tags in place of newlines.
9342          */
9343         nl2br : function(v) {
9344             return Ext.isEmpty(v) ? '' : v.replace(nl2brRe, '<br/>');
9345         },
9346
9347         /**
9348          * Capitalize the given string. See {@link Ext.String#capitalize}.
9349          */
9350         capitalize: Ext.String.capitalize,
9351
9352         /**
9353          * Truncate a string and add an ellipsis ('...') to the end if it exceeds the specified length.
9354          * See {@link Ext.String#ellipsis}.
9355          */
9356         ellipsis: Ext.String.ellipsis,
9357
9358         /**
9359          * Formats to a string. See {@link Ext.String#format}
9360          */
9361         format: Ext.String.format,
9362
9363         /**
9364          * Convert certain characters (&, <, >, and ') from their HTML character equivalents.
9365          * See {@link Ext.string#htmlDecode}.
9366          */
9367         htmlDecode: Ext.String.htmlDecode,
9368
9369         /**
9370          * Convert certain characters (&, <, >, and ') to their HTML character equivalents for literal display in web pages.
9371          * See {@link Ext.String#htmlEncode}.
9372          */
9373         htmlEncode: Ext.String.htmlEncode,
9374
9375         /**
9376          * Adds left padding to a string. See {@link Ext.String#leftPad}
9377          */
9378         leftPad: Ext.String.leftPad,
9379
9380         /**
9381          * Trims any whitespace from either side of a string. See {@link Ext.String#trim}.
9382          */
9383         trim : Ext.String.trim,
9384
9385         /**
9386          * Parses a number or string representing margin sizes into an object. Supports CSS-style margin declarations
9387          * (e.g. 10, "10", "10 10", "10 10 10" and "10 10 10 10" are all valid options and would return the same result)
9388          * @param {Number|String} v The encoded margins
9389          * @return {Object} An object with margin sizes for top, right, bottom and left
9390          */
9391         parseBox : function(box) {
9392             if (Ext.isNumber(box)) {
9393                 box = box.toString();
9394             }
9395             var parts  = box.split(' '),
9396                 ln = parts.length;
9397
9398             if (ln == 1) {
9399                 parts[1] = parts[2] = parts[3] = parts[0];
9400             }
9401             else if (ln == 2) {
9402                 parts[2] = parts[0];
9403                 parts[3] = parts[1];
9404             }
9405             else if (ln == 3) {
9406                 parts[3] = parts[1];
9407             }
9408
9409             return {
9410                 top   :parseInt(parts[0], 10) || 0,
9411                 right :parseInt(parts[1], 10) || 0,
9412                 bottom:parseInt(parts[2], 10) || 0,
9413                 left  :parseInt(parts[3], 10) || 0
9414             };
9415         },
9416
9417         /**
9418          * Escapes the passed string for use in a regular expression
9419          * @param {String} str
9420          * @return {String}
9421          */
9422         escapeRegex : function(s) {
9423             return s.replace(/([\-.*+?\^${}()|\[\]\/\\])/g, "\\$1");
9424         }
9425     });
9426 })();
9427
9428 /**
9429  * @class Ext.util.TaskRunner
9430  * Provides the ability to execute one or more arbitrary tasks in a multithreaded
9431  * manner.  Generally, you can use the singleton {@link Ext.TaskManager} instead, but
9432  * if needed, you can create separate instances of TaskRunner.  Any number of
9433  * separate tasks can be started at any time and will run independently of each
9434  * other. Example usage:
9435  * <pre><code>
9436 // Start a simple clock task that updates a div once per second
9437 var updateClock = function(){
9438     Ext.fly('clock').update(new Date().format('g:i:s A'));
9439
9440 var task = {
9441     run: updateClock,
9442     interval: 1000 //1 second
9443 }
9444 var runner = new Ext.util.TaskRunner();
9445 runner.start(task);
9446
9447 // equivalent using TaskManager
9448 Ext.TaskManager.start({
9449     run: updateClock,
9450     interval: 1000
9451 });
9452
9453  * </code></pre>
9454  * <p>See the {@link #start} method for details about how to configure a task object.</p>
9455  * Also see {@link Ext.util.DelayedTask}. 
9456  * 
9457  * @constructor
9458  * @param {Number} interval (optional) The minimum precision in milliseconds supported by this TaskRunner instance
9459  * (defaults to 10)
9460  */
9461 Ext.ns('Ext.util');
9462
9463 Ext.util.TaskRunner = function(interval) {
9464     interval = interval || 10;
9465     var tasks = [],
9466     removeQueue = [],
9467     id = 0,
9468     running = false,
9469
9470     // private
9471     stopThread = function() {
9472         running = false;
9473         clearInterval(id);
9474         id = 0;
9475     },
9476
9477     // private
9478     startThread = function() {
9479         if (!running) {
9480             running = true;
9481             id = setInterval(runTasks, interval);
9482         }
9483     },
9484
9485     // private
9486     removeTask = function(t) {
9487         removeQueue.push(t);
9488         if (t.onStop) {
9489             t.onStop.apply(t.scope || t);
9490         }
9491     },
9492
9493     // private
9494     runTasks = function() {
9495         var rqLen = removeQueue.length,
9496             now = new Date().getTime(),
9497             i;
9498
9499         if (rqLen > 0) {
9500             for (i = 0; i < rqLen; i++) {
9501                 Ext.Array.remove(tasks, removeQueue[i]);
9502             }
9503             removeQueue = [];
9504             if (tasks.length < 1) {
9505                 stopThread();
9506                 return;
9507             }
9508         }
9509         i = 0;
9510         var t,
9511             itime,
9512             rt,
9513             len = tasks.length;
9514         for (; i < len; ++i) {
9515             t = tasks[i];
9516             itime = now - t.taskRunTime;
9517             if (t.interval <= itime) {
9518                 rt = t.run.apply(t.scope || t, t.args || [++t.taskRunCount]);
9519                 t.taskRunTime = now;
9520                 if (rt === false || t.taskRunCount === t.repeat) {
9521                     removeTask(t);
9522                     return;
9523                 }
9524             }
9525             if (t.duration && t.duration <= (now - t.taskStartTime)) {
9526                 removeTask(t);
9527             }
9528         }
9529     };
9530
9531     /**
9532      * Starts a new task.
9533      * @method start
9534      * @param {Object} task <p>A config object that supports the following properties:<ul>
9535      * <li><code>run</code> : Function<div class="sub-desc"><p>The function to execute each time the task is invoked. The
9536      * function will be called at each interval and passed the <code>args</code> argument if specified, and the
9537      * current invocation count if not.</p>
9538      * <p>If a particular scope (<code>this</code> reference) is required, be sure to specify it using the <code>scope</code> argument.</p>
9539      * <p>Return <code>false</code> from this function to terminate the task.</p></div></li>
9540      * <li><code>interval</code> : Number<div class="sub-desc">The frequency in milliseconds with which the task
9541      * should be invoked.</div></li>
9542      * <li><code>args</code> : Array<div class="sub-desc">(optional) An array of arguments to be passed to the function
9543      * specified by <code>run</code>. If not specified, the current invocation count is passed.</div></li>
9544      * <li><code>scope</code> : Object<div class="sub-desc">(optional) The scope (<tt>this</tt> reference) in which to execute the
9545      * <code>run</code> function. Defaults to the task config object.</div></li>
9546      * <li><code>duration</code> : Number<div class="sub-desc">(optional) The length of time in milliseconds to invoke
9547      * the task before stopping automatically (defaults to indefinite).</div></li>
9548      * <li><code>repeat</code> : Number<div class="sub-desc">(optional) The number of times to invoke the task before
9549      * stopping automatically (defaults to indefinite).</div></li>
9550      * </ul></p>
9551      * <p>Before each invocation, Ext injects the property <code>taskRunCount</code> into the task object so
9552      * that calculations based on the repeat count can be performed.</p>
9553      * @return {Object} The task
9554      */
9555     this.start = function(task) {
9556         tasks.push(task);
9557         task.taskStartTime = new Date().getTime();
9558         task.taskRunTime = 0;
9559         task.taskRunCount = 0;
9560         startThread();
9561         return task;
9562     };
9563
9564     /**
9565      * Stops an existing running task.
9566      * @method stop
9567      * @param {Object} task The task to stop
9568      * @return {Object} The task
9569      */
9570     this.stop = function(task) {
9571         removeTask(task);
9572         return task;
9573     };
9574
9575     /**
9576      * Stops all tasks that are currently running.
9577      * @method stopAll
9578      */
9579     this.stopAll = function() {
9580         stopThread();
9581         for (var i = 0, len = tasks.length; i < len; i++) {
9582             if (tasks[i].onStop) {
9583                 tasks[i].onStop();
9584             }
9585         }
9586         tasks = [];
9587         removeQueue = [];
9588     };
9589 };
9590
9591 /**
9592  * @class Ext.TaskManager
9593  * @extends Ext.util.TaskRunner
9594  * A static {@link Ext.util.TaskRunner} instance that can be used to start and stop arbitrary tasks.  See
9595  * {@link Ext.util.TaskRunner} for supported methods and task config properties.
9596  * <pre><code>
9597 // Start a simple clock task that updates a div once per second
9598 var task = {
9599     run: function(){
9600         Ext.fly('clock').update(new Date().format('g:i:s A'));
9601     },
9602     interval: 1000 //1 second
9603 }
9604 Ext.TaskManager.start(task);
9605 </code></pre>
9606  * <p>See the {@link #start} method for details about how to configure a task object.</p>
9607  * @singleton
9608  */
9609 Ext.TaskManager = Ext.create('Ext.util.TaskRunner');
9610 /**
9611  * @class Ext.is
9612  * 
9613  * Determines information about the current platform the application is running on.
9614  * 
9615  * @singleton
9616  */
9617 Ext.is = {
9618     init : function(navigator) {
9619         var platforms = this.platforms,
9620             ln = platforms.length,
9621             i, platform;
9622
9623         navigator = navigator || window.navigator;
9624
9625         for (i = 0; i < ln; i++) {
9626             platform = platforms[i];
9627             this[platform.identity] = platform.regex.test(navigator[platform.property]);
9628         }
9629
9630         /**
9631          * @property Desktop True if the browser is running on a desktop machine
9632          * @type {Boolean}
9633          */
9634         this.Desktop = this.Mac || this.Windows || (this.Linux && !this.Android);
9635         /**
9636          * @property Tablet True if the browser is running on a tablet (iPad)
9637          */
9638         this.Tablet = this.iPad;
9639         /**
9640          * @property Phone True if the browser is running on a phone.
9641          * @type {Boolean}
9642          */
9643         this.Phone = !this.Desktop && !this.Tablet;
9644         /**
9645          * @property iOS True if the browser is running on iOS
9646          * @type {Boolean}
9647          */
9648         this.iOS = this.iPhone || this.iPad || this.iPod;
9649         
9650         /**
9651          * @property Standalone Detects when application has been saved to homescreen.
9652          * @type {Boolean}
9653          */
9654         this.Standalone = !!window.navigator.standalone;
9655     },
9656     
9657     /**
9658      * @property iPhone True when the browser is running on a iPhone
9659      * @type {Boolean}
9660      */
9661     platforms: [{
9662         property: 'platform',
9663         regex: /iPhone/i,
9664         identity: 'iPhone'
9665     },
9666     
9667     /**
9668      * @property iPod True when the browser is running on a iPod
9669      * @type {Boolean}
9670      */
9671     {
9672         property: 'platform',
9673         regex: /iPod/i,
9674         identity: 'iPod'
9675     },
9676     
9677     /**
9678      * @property iPad True when the browser is running on a iPad
9679      * @type {Boolean}
9680      */
9681     {
9682         property: 'userAgent',
9683         regex: /iPad/i,
9684         identity: 'iPad'
9685     },
9686     
9687     /**
9688      * @property Blackberry True when the browser is running on a Blackberry
9689      * @type {Boolean}
9690      */
9691     {
9692         property: 'userAgent',
9693         regex: /Blackberry/i,
9694         identity: 'Blackberry'
9695     },
9696     
9697     /**
9698      * @property Android True when the browser is running on an Android device
9699      * @type {Boolean}
9700      */
9701     {
9702         property: 'userAgent',
9703         regex: /Android/i,
9704         identity: 'Android'
9705     },
9706     
9707     /**
9708      * @property Mac True when the browser is running on a Mac
9709      * @type {Boolean}
9710      */
9711     {
9712         property: 'platform',
9713         regex: /Mac/i,
9714         identity: 'Mac'
9715     },
9716     
9717     /**
9718      * @property Windows True when the browser is running on Windows
9719      * @type {Boolean}
9720      */
9721     {
9722         property: 'platform',
9723         regex: /Win/i,
9724         identity: 'Windows'
9725     },
9726     
9727     /**
9728      * @property Linux True when the browser is running on Linux
9729      * @type {Boolean}
9730      */
9731     {
9732         property: 'platform',
9733         regex: /Linux/i,
9734         identity: 'Linux'
9735     }]
9736 };
9737
9738 Ext.is.init();
9739
9740 /**
9741  * @class Ext.supports
9742  *
9743  * Determines information about features are supported in the current environment
9744  * 
9745  * @singleton
9746  */
9747 Ext.supports = {
9748     init : function() {
9749         var doc = document,
9750             div = doc.createElement('div'),
9751             tests = this.tests,
9752             ln = tests.length,
9753             i, test;
9754
9755         div.innerHTML = [
9756             '<div style="height:30px;width:50px;">',
9757                 '<div style="height:20px;width:20px;"></div>',
9758             '</div>',
9759             '<div style="width: 200px; height: 200px; position: relative; padding: 5px;">',
9760                 '<div style="position: absolute; top: 0; left: 0; width: 100%; height: 100%;"></div>',
9761             '</div>',
9762             '<div style="float:left; background-color:transparent;"></div>'
9763         ].join('');
9764
9765         doc.body.appendChild(div);
9766
9767         for (i = 0; i < ln; i++) {
9768             test = tests[i];
9769             this[test.identity] = test.fn.call(this, doc, div);
9770         }
9771
9772         doc.body.removeChild(div);
9773     },
9774
9775     /**
9776      * @property CSS3BoxShadow True if document environment supports the CSS3 box-shadow style.
9777      * @type {Boolean}
9778      */
9779     CSS3BoxShadow: Ext.isDefined(document.documentElement.style.boxShadow),
9780
9781     /**
9782      * @property ClassList True if document environment supports the HTML5 classList API.
9783      * @type {Boolean}
9784      */
9785     ClassList: !!document.documentElement.classList,
9786
9787     /**
9788      * @property OrientationChange True if the device supports orientation change
9789      * @type {Boolean}
9790      */
9791     OrientationChange: ((typeof window.orientation != 'undefined') && ('onorientationchange' in window)),
9792     
9793     /**
9794      * @property DeviceMotion True if the device supports device motion (acceleration and rotation rate)
9795      * @type {Boolean}
9796      */
9797     DeviceMotion: ('ondevicemotion' in window),
9798     
9799     /**
9800      * @property Touch True if the device supports touch
9801      * @type {Boolean}
9802      */
9803     // is.Desktop is needed due to the bug in Chrome 5.0.375, Safari 3.1.2
9804     // and Safari 4.0 (they all have 'ontouchstart' in the window object).
9805     Touch: ('ontouchstart' in window) && (!Ext.is.Desktop),
9806
9807     tests: [
9808         /**
9809          * @property Transitions True if the device supports CSS3 Transitions
9810          * @type {Boolean}
9811          */
9812         {
9813             identity: 'Transitions',
9814             fn: function(doc, div) {
9815                 var prefix = [
9816                         'webkit',
9817                         'Moz',
9818                         'o',
9819                         'ms',
9820                         'khtml'
9821                     ],
9822                     TE = 'TransitionEnd',
9823                     transitionEndName = [
9824                         prefix[0] + TE,
9825                         'transitionend', //Moz bucks the prefixing convention
9826                         prefix[2] + TE,
9827                         prefix[3] + TE,
9828                         prefix[4] + TE
9829                     ],
9830                     ln = prefix.length,
9831                     i = 0,
9832                     out = false;
9833                 div = Ext.get(div);
9834                 for (; i < ln; i++) {
9835                     if (div.getStyle(prefix[i] + "TransitionProperty")) {
9836                         Ext.supports.CSS3Prefix = prefix[i];
9837                         Ext.supports.CSS3TransitionEnd = transitionEndName[i];
9838                         out = true;
9839                         break;
9840                     }
9841                 }
9842                 return out;
9843             }
9844         },
9845         
9846         /**
9847          * @property RightMargin True if the device supports right margin.
9848          * See https://bugs.webkit.org/show_bug.cgi?id=13343 for why this is needed.
9849          * @type {Boolean}
9850          */
9851         {
9852             identity: 'RightMargin',
9853             fn: function(doc, div, view) {
9854                 view = doc.defaultView;
9855                 return !(view && view.getComputedStyle(div.firstChild.firstChild, null).marginRight != '0px');
9856             }
9857         },
9858         
9859         /**
9860          * @property TransparentColor True if the device supports transparent color
9861          * @type {Boolean}
9862          */
9863         {
9864             identity: 'TransparentColor',
9865             fn: function(doc, div, view) {
9866                 view = doc.defaultView;
9867                 return !(view && view.getComputedStyle(div.lastChild, null).backgroundColor != 'transparent');
9868             }
9869         },
9870
9871         /**
9872          * @property ComputedStyle True if the browser supports document.defaultView.getComputedStyle()
9873          * @type {Boolean}
9874          */
9875         {
9876             identity: 'ComputedStyle',
9877             fn: function(doc, div, view) {
9878                 view = doc.defaultView;
9879                 return view && view.getComputedStyle;
9880             }
9881         },
9882         
9883         /**
9884          * @property SVG True if the device supports SVG
9885          * @type {Boolean}
9886          */
9887         {
9888             identity: 'Svg',
9889             fn: function(doc) {
9890                 return !!doc.createElementNS && !!doc.createElementNS( "http:/" + "/www.w3.org/2000/svg", "svg").createSVGRect;
9891             }
9892         },
9893     
9894         /**
9895          * @property Canvas True if the device supports Canvas
9896          * @type {Boolean}
9897          */
9898         {
9899             identity: 'Canvas',
9900             fn: function(doc) {
9901                 return !!doc.createElement('canvas').getContext;
9902             }
9903         },
9904         
9905         /**
9906          * @property VML True if the device supports VML
9907          * @type {Boolean}
9908          */
9909         {
9910             identity: 'Vml',
9911             fn: function(doc) {
9912                 var d = doc.createElement("div");
9913                 d.innerHTML = "<!--[if vml]><br><br><![endif]-->";
9914                 return (d.childNodes.length == 2);
9915             }
9916         },
9917         
9918         /**
9919          * @property Float True if the device supports CSS float
9920          * @type {Boolean}
9921          */
9922         {
9923             identity: 'Float',
9924             fn: function(doc, div) {
9925                 return !!div.lastChild.style.cssFloat;
9926             }
9927         },
9928         
9929         /**
9930          * @property AudioTag True if the device supports the HTML5 audio tag
9931          * @type {Boolean}
9932          */
9933         {
9934             identity: 'AudioTag',
9935             fn: function(doc) {
9936                 return !!doc.createElement('audio').canPlayType;
9937             }
9938         },
9939         
9940         /**
9941          * @property History True if the device supports HTML5 history
9942          * @type {Boolean}
9943          */
9944         {
9945             identity: 'History',
9946             fn: function() {
9947                 return !!(window.history && history.pushState);
9948             }
9949         },
9950         
9951         /**
9952          * @property CSS3DTransform True if the device supports CSS3DTransform
9953          * @type {Boolean}
9954          */
9955         {
9956             identity: 'CSS3DTransform',
9957             fn: function() {
9958                 return (typeof WebKitCSSMatrix != 'undefined' && new WebKitCSSMatrix().hasOwnProperty('m41'));
9959             }
9960         },
9961
9962                 /**
9963          * @property CSS3LinearGradient True if the device supports CSS3 linear gradients
9964          * @type {Boolean}
9965          */
9966         {
9967             identity: 'CSS3LinearGradient',
9968             fn: function(doc, div) {
9969                 var property = 'background-image:',
9970                     webkit   = '-webkit-gradient(linear, left top, right bottom, from(black), to(white))',
9971                     w3c      = 'linear-gradient(left top, black, white)',
9972                     moz      = '-moz-' + w3c,
9973                     options  = [property + webkit, property + w3c, property + moz];
9974                 
9975                 div.style.cssText = options.join(';');
9976                 
9977                 return ("" + div.style.backgroundImage).indexOf('gradient') !== -1;
9978             }
9979         },
9980         
9981         /**
9982          * @property CSS3BorderRadius True if the device supports CSS3 border radius
9983          * @type {Boolean}
9984          */
9985         {
9986             identity: 'CSS3BorderRadius',
9987             fn: function(doc, div) {
9988                 var domPrefixes = ['borderRadius', 'BorderRadius', 'MozBorderRadius', 'WebkitBorderRadius', 'OBorderRadius', 'KhtmlBorderRadius'],
9989                     pass = false,
9990                     i;
9991                 for (i = 0; i < domPrefixes.length; i++) {
9992                     if (document.body.style[domPrefixes[i]] !== undefined) {
9993                         return true;
9994                     }
9995                 }
9996                 return pass;
9997             }
9998         },
9999         
10000         /**
10001          * @property GeoLocation True if the device supports GeoLocation
10002          * @type {Boolean}
10003          */
10004         {
10005             identity: 'GeoLocation',
10006             fn: function() {
10007                 return (typeof navigator != 'undefined' && typeof navigator.geolocation != 'undefined') || (typeof google != 'undefined' && typeof google.gears != 'undefined');
10008             }
10009         },
10010         /**
10011          * @property MouseEnterLeave True if the browser supports mouseenter and mouseleave events
10012          * @type {Boolean}
10013          */
10014         {
10015             identity: 'MouseEnterLeave',
10016             fn: function(doc, div){
10017                 return ('onmouseenter' in div && 'onmouseleave' in div);
10018             }
10019         },
10020         /**
10021          * @property MouseWheel True if the browser supports the mousewheel event
10022          * @type {Boolean}
10023          */
10024         {
10025             identity: 'MouseWheel',
10026             fn: function(doc, div) {
10027                 return ('onmousewheel' in div);
10028             }
10029         },
10030         /**
10031          * @property Opacity True if the browser supports normal css opacity
10032          * @type {Boolean}
10033          */
10034         {
10035             identity: 'Opacity',
10036             fn: function(doc, div){
10037                 // Not a strict equal comparison in case opacity can be converted to a number.
10038                 if (Ext.isIE6 || Ext.isIE7 || Ext.isIE8) {
10039                     return false;
10040                 }
10041                 div.firstChild.style.cssText = 'opacity:0.73';
10042                 return div.firstChild.style.opacity == '0.73';
10043             }
10044         },
10045         /**
10046          * @property Placeholder True if the browser supports the HTML5 placeholder attribute on inputs
10047          * @type {Boolean}
10048          */
10049         {
10050             identity: 'Placeholder',
10051             fn: function(doc) {
10052                 return 'placeholder' in doc.createElement('input');
10053             }
10054         },
10055         
10056         /**
10057          * @property Direct2DBug True if when asking for an element's dimension via offsetWidth or offsetHeight, 
10058          * getBoundingClientRect, etc. the browser returns the subpixel width rounded to the nearest pixel.
10059          * @type {Boolean}
10060          */
10061         {
10062             identity: 'Direct2DBug',
10063             fn: function() {
10064                 return Ext.isString(document.body.style.msTransformOrigin);
10065             }
10066         },
10067         /**
10068          * @property BoundingClientRect True if the browser supports the getBoundingClientRect method on elements
10069          * @type {Boolean}
10070          */
10071         {
10072             identity: 'BoundingClientRect',
10073             fn: function(doc, div) {
10074                 return Ext.isFunction(div.getBoundingClientRect);
10075             }
10076         },
10077         {
10078             identity: 'IncludePaddingInWidthCalculation',
10079             fn: function(doc, div){
10080                 var el = Ext.get(div.childNodes[1].firstChild);
10081                 return el.getWidth() == 210;
10082             }
10083         },
10084         {
10085             identity: 'IncludePaddingInHeightCalculation',
10086             fn: function(doc, div){
10087                 var el = Ext.get(div.childNodes[1].firstChild);
10088                 return el.getHeight() == 210;
10089             }
10090         },
10091         
10092         /**
10093          * @property ArraySort True if the Array sort native method isn't bugged.
10094          * @type {Boolean}
10095          */
10096         {
10097             identity: 'ArraySort',
10098             fn: function() {
10099                 var a = [1,2,3,4,5].sort(function(){ return 0; });
10100                 return a[0] === 1 && a[1] === 2 && a[2] === 3 && a[3] === 4 && a[4] === 5;
10101             }
10102         },
10103         /**
10104          * @property Range True if browser support document.createRange native method.
10105          * @type {Boolean}
10106          */
10107         {
10108             identity: 'Range',
10109             fn: function() {
10110                 return !!document.createRange;
10111             }
10112         },
10113         /**
10114          * @property CreateContextualFragment True if browser support CreateContextualFragment range native methods.
10115          * @type {Boolean}
10116          */
10117         {
10118             identity: 'CreateContextualFragment',
10119             fn: function() {
10120                 var range = Ext.supports.Range ? document.createRange() : false;
10121                 
10122                 return range && !!range.createContextualFragment;
10123             }
10124         }
10125         
10126     ]
10127 };
10128
10129
10130
10131 /*
10132 Ext JS - JavaScript Library
10133 Copyright (c) 2006-2011, Sencha Inc.
10134 All rights reserved.
10135 licensing@sencha.com
10136 */
10137 /**
10138  * @class Ext.core.DomHelper
10139  * <p>The DomHelper class provides a layer of abstraction from DOM and transparently supports creating
10140  * elements via DOM or using HTML fragments. It also has the ability to create HTML fragment templates
10141  * from your DOM building code.</p>
10142  *
10143  * <p><b><u>DomHelper element specification object</u></b></p>
10144  * <p>A specification object is used when creating elements. Attributes of this object
10145  * are assumed to be element attributes, except for 4 special attributes:
10146  * <div class="mdetail-params"><ul>
10147  * <li><b><tt>tag</tt></b> : <div class="sub-desc">The tag name of the element</div></li>
10148  * <li><b><tt>children</tt></b> : or <tt>cn</tt><div class="sub-desc">An array of the
10149  * same kind of element definition objects to be created and appended. These can be nested
10150  * as deep as you want.</div></li>
10151  * <li><b><tt>cls</tt></b> : <div class="sub-desc">The class attribute of the element.
10152  * This will end up being either the "class" attribute on a HTML fragment or className
10153  * for a DOM node, depending on whether DomHelper is using fragments or DOM.</div></li>
10154  * <li><b><tt>html</tt></b> : <div class="sub-desc">The innerHTML for the element</div></li>
10155  * </ul></div></p>
10156  *
10157  * <p><b><u>Insertion methods</u></b></p>
10158  * <p>Commonly used insertion methods:
10159  * <div class="mdetail-params"><ul>
10160  * <li><b><tt>{@link #append}</tt></b> : <div class="sub-desc"></div></li>
10161  * <li><b><tt>{@link #insertBefore}</tt></b> : <div class="sub-desc"></div></li>
10162  * <li><b><tt>{@link #insertAfter}</tt></b> : <div class="sub-desc"></div></li>
10163  * <li><b><tt>{@link #overwrite}</tt></b> : <div class="sub-desc"></div></li>
10164  * <li><b><tt>{@link #createTemplate}</tt></b> : <div class="sub-desc"></div></li>
10165  * <li><b><tt>{@link #insertHtml}</tt></b> : <div class="sub-desc"></div></li>
10166  * </ul></div></p>
10167  *
10168  * <p><b><u>Example</u></b></p>
10169  * <p>This is an example, where an unordered list with 3 children items is appended to an existing
10170  * element with id <tt>'my-div'</tt>:<br>
10171  <pre><code>
10172 var dh = Ext.core.DomHelper; // create shorthand alias
10173 // specification object
10174 var spec = {
10175     id: 'my-ul',
10176     tag: 'ul',
10177     cls: 'my-list',
10178     // append children after creating
10179     children: [     // may also specify 'cn' instead of 'children'
10180         {tag: 'li', id: 'item0', html: 'List Item 0'},
10181         {tag: 'li', id: 'item1', html: 'List Item 1'},
10182         {tag: 'li', id: 'item2', html: 'List Item 2'}
10183     ]
10184 };
10185 var list = dh.append(
10186     'my-div', // the context element 'my-div' can either be the id or the actual node
10187     spec      // the specification object
10188 );
10189  </code></pre></p>
10190  * <p>Element creation specification parameters in this class may also be passed as an Array of
10191  * specification objects. This can be used to insert multiple sibling nodes into an existing
10192  * container very efficiently. For example, to add more list items to the example above:<pre><code>
10193 dh.append('my-ul', [
10194     {tag: 'li', id: 'item3', html: 'List Item 3'},
10195     {tag: 'li', id: 'item4', html: 'List Item 4'}
10196 ]);
10197  * </code></pre></p>
10198  *
10199  * <p><b><u>Templating</u></b></p>
10200  * <p>The real power is in the built-in templating. Instead of creating or appending any elements,
10201  * <tt>{@link #createTemplate}</tt> returns a Template object which can be used over and over to
10202  * insert new elements. Revisiting the example above, we could utilize templating this time:
10203  * <pre><code>
10204 // create the node
10205 var list = dh.append('my-div', {tag: 'ul', cls: 'my-list'});
10206 // get template
10207 var tpl = dh.createTemplate({tag: 'li', id: 'item{0}', html: 'List Item {0}'});
10208
10209 for(var i = 0; i < 5, i++){
10210     tpl.append(list, [i]); // use template to append to the actual node
10211 }
10212  * </code></pre></p>
10213  * <p>An example using a template:<pre><code>
10214 var html = '<a id="{0}" href="{1}" class="nav">{2}</a>';
10215
10216 var tpl = new Ext.core.DomHelper.createTemplate(html);
10217 tpl.append('blog-roll', ['link1', 'http://www.edspencer.net/', "Ed&#39;s Site"]);
10218 tpl.append('blog-roll', ['link2', 'http://www.dustindiaz.com/', "Dustin&#39;s Site"]);
10219  * </code></pre></p>
10220  *
10221  * <p>The same example using named parameters:<pre><code>
10222 var html = '<a id="{id}" href="{url}" class="nav">{text}</a>';
10223
10224 var tpl = new Ext.core.DomHelper.createTemplate(html);
10225 tpl.append('blog-roll', {
10226     id: 'link1',
10227     url: 'http://www.edspencer.net/',
10228     text: "Ed&#39;s Site"
10229 });
10230 tpl.append('blog-roll', {
10231     id: 'link2',
10232     url: 'http://www.dustindiaz.com/',
10233     text: "Dustin&#39;s Site"
10234 });
10235  * </code></pre></p>
10236  *
10237  * <p><b><u>Compiling Templates</u></b></p>
10238  * <p>Templates are applied using regular expressions. The performance is great, but if
10239  * you are adding a bunch of DOM elements using the same template, you can increase
10240  * performance even further by {@link Ext.Template#compile "compiling"} the template.
10241  * The way "{@link Ext.Template#compile compile()}" works is the template is parsed and
10242  * broken up at the different variable points and a dynamic function is created and eval'ed.
10243  * The generated function performs string concatenation of these parts and the passed
10244  * variables instead of using regular expressions.
10245  * <pre><code>
10246 var html = '<a id="{id}" href="{url}" class="nav">{text}</a>';
10247
10248 var tpl = new Ext.core.DomHelper.createTemplate(html);
10249 tpl.compile();
10250
10251 //... use template like normal
10252  * </code></pre></p>
10253  *
10254  * <p><b><u>Performance Boost</u></b></p>
10255  * <p>DomHelper will transparently create HTML fragments when it can. Using HTML fragments instead
10256  * of DOM can significantly boost performance.</p>
10257  * <p>Element creation specification parameters may also be strings. If {@link #useDom} is <tt>false</tt>,
10258  * then the string is used as innerHTML. If {@link #useDom} is <tt>true</tt>, a string specification
10259  * results in the creation of a text node. Usage:</p>
10260  * <pre><code>
10261 Ext.core.DomHelper.useDom = true; // force it to use DOM; reduces performance
10262  * </code></pre>
10263  * @singleton
10264  */
10265 Ext.ns('Ext.core');
10266 Ext.core.DomHelper = function(){
10267     var tempTableEl = null,
10268         emptyTags = /^(?:br|frame|hr|img|input|link|meta|range|spacer|wbr|area|param|col)$/i,
10269         tableRe = /^table|tbody|tr|td$/i,
10270         confRe = /tag|children|cn|html$/i,
10271         tableElRe = /td|tr|tbody/i,
10272         endRe = /end/i,
10273         pub,
10274         // kill repeat to save bytes
10275         afterbegin = 'afterbegin',
10276         afterend = 'afterend',
10277         beforebegin = 'beforebegin',
10278         beforeend = 'beforeend',
10279         ts = '<table>',
10280         te = '</table>',
10281         tbs = ts+'<tbody>',
10282         tbe = '</tbody>'+te,
10283         trs = tbs + '<tr>',
10284         tre = '</tr>'+tbe;
10285
10286     // private
10287     function doInsert(el, o, returnElement, pos, sibling, append){
10288         el = Ext.getDom(el);
10289         var newNode;
10290         if (pub.useDom) {
10291             newNode = createDom(o, null);
10292             if (append) {
10293                 el.appendChild(newNode);
10294             } else {
10295                 (sibling == 'firstChild' ? el : el.parentNode).insertBefore(newNode, el[sibling] || el);
10296             }
10297         } else {
10298             newNode = Ext.core.DomHelper.insertHtml(pos, el, Ext.core.DomHelper.createHtml(o));
10299         }
10300         return returnElement ? Ext.get(newNode, true) : newNode;
10301     }
10302     
10303     function createDom(o, parentNode){
10304         var el,
10305             doc = document,
10306             useSet,
10307             attr,
10308             val,
10309             cn;
10310
10311         if (Ext.isArray(o)) {                       // Allow Arrays of siblings to be inserted
10312             el = doc.createDocumentFragment(); // in one shot using a DocumentFragment
10313             for (var i = 0, l = o.length; i < l; i++) {
10314                 createDom(o[i], el);
10315             }
10316         } else if (typeof o == 'string') {         // Allow a string as a child spec.
10317             el = doc.createTextNode(o);
10318         } else {
10319             el = doc.createElement( o.tag || 'div' );
10320             useSet = !!el.setAttribute; // In IE some elements don't have setAttribute
10321             for (attr in o) {
10322                 if(!confRe.test(attr)){
10323                     val = o[attr];
10324                     if(attr == 'cls'){
10325                         el.className = val;
10326                     }else{
10327                         if(useSet){
10328                             el.setAttribute(attr, val);
10329                         }else{
10330                             el[attr] = val;
10331                         }
10332                     }
10333                 }
10334             }
10335             Ext.core.DomHelper.applyStyles(el, o.style);
10336
10337             if ((cn = o.children || o.cn)) {
10338                 createDom(cn, el);
10339             } else if (o.html) {
10340                 el.innerHTML = o.html;
10341             }
10342         }
10343         if(parentNode){
10344            parentNode.appendChild(el);
10345         }
10346         return el;
10347     }
10348
10349     // build as innerHTML where available
10350     function createHtml(o){
10351         var b = '',
10352             attr,
10353             val,
10354             key,
10355             cn,
10356             i;
10357
10358         if(typeof o == "string"){
10359             b = o;
10360         } else if (Ext.isArray(o)) {
10361             for (i=0; i < o.length; i++) {
10362                 if(o[i]) {
10363                     b += createHtml(o[i]);
10364                 }
10365             }
10366         } else {
10367             b += '<' + (o.tag = o.tag || 'div');
10368             for (attr in o) {
10369                 val = o[attr];
10370                 if(!confRe.test(attr)){
10371                     if (typeof val == "object") {
10372                         b += ' ' + attr + '="';
10373                         for (key in val) {
10374                             b += key + ':' + val[key] + ';';
10375                         }
10376                         b += '"';
10377                     }else{
10378                         b += ' ' + ({cls : 'class', htmlFor : 'for'}[attr] || attr) + '="' + val + '"';
10379                     }
10380                 }
10381             }
10382             // Now either just close the tag or try to add children and close the tag.
10383             if (emptyTags.test(o.tag)) {
10384                 b += '/>';
10385             } else {
10386                 b += '>';
10387                 if ((cn = o.children || o.cn)) {
10388                     b += createHtml(cn);
10389                 } else if(o.html){
10390                     b += o.html;
10391                 }
10392                 b += '</' + o.tag + '>';
10393             }
10394         }
10395         return b;
10396     }
10397
10398     function ieTable(depth, s, h, e){
10399         tempTableEl.innerHTML = [s, h, e].join('');
10400         var i = -1,
10401             el = tempTableEl,
10402             ns;
10403         while(++i < depth){
10404             el = el.firstChild;
10405         }
10406 //      If the result is multiple siblings, then encapsulate them into one fragment.
10407         ns = el.nextSibling;
10408         if (ns){
10409             var df = document.createDocumentFragment();
10410             while(el){
10411                 ns = el.nextSibling;
10412                 df.appendChild(el);
10413                 el = ns;
10414             }
10415             el = df;
10416         }
10417         return el;
10418     }
10419
10420     /**
10421      * @ignore
10422      * Nasty code for IE's broken table implementation
10423      */
10424     function insertIntoTable(tag, where, el, html) {
10425         var node,
10426             before;
10427
10428         tempTableEl = tempTableEl || document.createElement('div');
10429
10430         if(tag == 'td' && (where == afterbegin || where == beforeend) ||
10431            !tableElRe.test(tag) && (where == beforebegin || where == afterend)) {
10432             return null;
10433         }
10434         before = where == beforebegin ? el :
10435                  where == afterend ? el.nextSibling :
10436                  where == afterbegin ? el.firstChild : null;
10437
10438         if (where == beforebegin || where == afterend) {
10439             el = el.parentNode;
10440         }
10441
10442         if (tag == 'td' || (tag == 'tr' && (where == beforeend || where == afterbegin))) {
10443             node = ieTable(4, trs, html, tre);
10444         } else if ((tag == 'tbody' && (where == beforeend || where == afterbegin)) ||
10445                    (tag == 'tr' && (where == beforebegin || where == afterend))) {
10446             node = ieTable(3, tbs, html, tbe);
10447         } else {
10448             node = ieTable(2, ts, html, te);
10449         }
10450         el.insertBefore(node, before);
10451         return node;
10452     }
10453     
10454     /**
10455      * @ignore
10456      * Fix for IE9 createContextualFragment missing method
10457      */   
10458     function createContextualFragment(html){
10459         var div = document.createElement("div"),
10460             fragment = document.createDocumentFragment(),
10461             i = 0,
10462             length, childNodes;
10463         
10464         div.innerHTML = html;
10465         childNodes = div.childNodes;
10466         length = childNodes.length;
10467
10468         for (; i < length; i++) {
10469             fragment.appendChild(childNodes[i].cloneNode(true));
10470         }
10471
10472         return fragment;
10473     }
10474     
10475     pub = {
10476         /**
10477          * Returns the markup for the passed Element(s) config.
10478          * @param {Object} o The DOM object spec (and children)
10479          * @return {String}
10480          */
10481         markup : function(o){
10482             return createHtml(o);
10483         },
10484
10485         /**
10486          * Applies a style specification to an element.
10487          * @param {String/HTMLElement} el The element to apply styles to
10488          * @param {String/Object/Function} styles A style specification string e.g. 'width:100px', or object in the form {width:'100px'}, or
10489          * a function which returns such a specification.
10490          */
10491         applyStyles : function(el, styles){
10492             if (styles) {
10493                 el = Ext.fly(el);
10494                 if (typeof styles == "function") {
10495                     styles = styles.call();
10496                 }
10497                 if (typeof styles == "string") {
10498                     styles = Ext.core.Element.parseStyles(styles);
10499                 }
10500                 if (typeof styles == "object") {
10501                     el.setStyle(styles);
10502                 }
10503             }
10504         },
10505
10506         /**
10507          * Inserts an HTML fragment into the DOM.
10508          * @param {String} where Where to insert the html in relation to el - beforeBegin, afterBegin, beforeEnd, afterEnd.
10509          * @param {HTMLElement/TextNode} el The context element
10510          * @param {String} html The HTML fragment
10511          * @return {HTMLElement} The new node
10512          */
10513         insertHtml : function(where, el, html){
10514             var hash = {},
10515                 hashVal,
10516                 range,
10517                 rangeEl,
10518                 setStart,
10519                 frag,
10520                 rs;
10521
10522             where = where.toLowerCase();
10523             // add these here because they are used in both branches of the condition.
10524             hash[beforebegin] = ['BeforeBegin', 'previousSibling'];
10525             hash[afterend] = ['AfterEnd', 'nextSibling'];
10526             
10527             // if IE and context element is an HTMLElement
10528             if (el.insertAdjacentHTML) {
10529                 if(tableRe.test(el.tagName) && (rs = insertIntoTable(el.tagName.toLowerCase(), where, el, html))){
10530                     return rs;
10531                 }
10532                 
10533                 // add these two to the hash.
10534                 hash[afterbegin] = ['AfterBegin', 'firstChild'];
10535                 hash[beforeend] = ['BeforeEnd', 'lastChild'];
10536                 if ((hashVal = hash[where])) {
10537                     el.insertAdjacentHTML(hashVal[0], html);
10538                     return el[hashVal[1]];
10539                 }
10540             // if (not IE and context element is an HTMLElement) or TextNode
10541             } else {
10542                 // we cannot insert anything inside a textnode so...
10543                 if (Ext.isTextNode(el)) {
10544                     where = where === 'afterbegin' ? 'beforebegin' : where; 
10545                     where = where === 'beforeend' ? 'afterend' : where;
10546                 }
10547                 range = Ext.supports.CreateContextualFragment ? el.ownerDocument.createRange() : undefined;
10548                 setStart = 'setStart' + (endRe.test(where) ? 'After' : 'Before');
10549                 if (hash[where]) {
10550                     if (range) {
10551                         range[setStart](el);
10552                         frag = range.createContextualFragment(html);
10553                     } else {
10554                         frag = createContextualFragment(html);
10555                     }
10556                     el.parentNode.insertBefore(frag, where == beforebegin ? el : el.nextSibling);
10557                     return el[(where == beforebegin ? 'previous' : 'next') + 'Sibling'];
10558                 } else {
10559                     rangeEl = (where == afterbegin ? 'first' : 'last') + 'Child';
10560                     if (el.firstChild) {
10561                         if (range) {
10562                             range[setStart](el[rangeEl]);
10563                             frag = range.createContextualFragment(html);
10564                         } else {
10565                             frag = createContextualFragment(html);
10566                         }
10567                         
10568                         if(where == afterbegin){
10569                             el.insertBefore(frag, el.firstChild);
10570                         }else{
10571                             el.appendChild(frag);
10572                         }
10573                     } else {
10574                         el.innerHTML = html;
10575                     }
10576                     return el[rangeEl];
10577                 }
10578             }
10579             Ext.Error.raise({
10580                 sourceClass: 'Ext.core.DomHelper',
10581                 sourceMethod: 'insertHtml',
10582                 htmlToInsert: html,
10583                 targetElement: el,
10584                 msg: 'Illegal insertion point reached: "' + where + '"'
10585             });
10586         },
10587
10588         /**
10589          * Creates new DOM element(s) and inserts them before el.
10590          * @param {Mixed} el The context element
10591          * @param {Object/String} o The DOM object spec (and children) or raw HTML blob
10592          * @param {Boolean} returnElement (optional) true to return a Ext.core.Element
10593          * @return {HTMLElement/Ext.core.Element} The new node
10594          */
10595         insertBefore : function(el, o, returnElement){
10596             return doInsert(el, o, returnElement, beforebegin);
10597         },
10598
10599         /**
10600          * Creates new DOM element(s) and inserts them after el.
10601          * @param {Mixed} el The context element
10602          * @param {Object} o The DOM object spec (and children)
10603          * @param {Boolean} returnElement (optional) true to return a Ext.core.Element
10604          * @return {HTMLElement/Ext.core.Element} The new node
10605          */
10606         insertAfter : function(el, o, returnElement){
10607             return doInsert(el, o, returnElement, afterend, 'nextSibling');
10608         },
10609
10610         /**
10611          * Creates new DOM element(s) and inserts them as the first child of el.
10612          * @param {Mixed} el The context element
10613          * @param {Object/String} o The DOM object spec (and children) or raw HTML blob
10614          * @param {Boolean} returnElement (optional) true to return a Ext.core.Element
10615          * @return {HTMLElement/Ext.core.Element} The new node
10616          */
10617         insertFirst : function(el, o, returnElement){
10618             return doInsert(el, o, returnElement, afterbegin, 'firstChild');
10619         },
10620
10621         /**
10622          * Creates new DOM element(s) and appends them to el.
10623          * @param {Mixed} el The context element
10624          * @param {Object/String} o The DOM object spec (and children) or raw HTML blob
10625          * @param {Boolean} returnElement (optional) true to return a Ext.core.Element
10626          * @return {HTMLElement/Ext.core.Element} The new node
10627          */
10628         append : function(el, o, returnElement){
10629             return doInsert(el, o, returnElement, beforeend, '', true);
10630         },
10631
10632         /**
10633          * Creates new DOM element(s) and overwrites the contents of el with them.
10634          * @param {Mixed} el The context element
10635          * @param {Object/String} o The DOM object spec (and children) or raw HTML blob
10636          * @param {Boolean} returnElement (optional) true to return a Ext.core.Element
10637          * @return {HTMLElement/Ext.core.Element} The new node
10638          */
10639         overwrite : function(el, o, returnElement){
10640             el = Ext.getDom(el);
10641             el.innerHTML = createHtml(o);
10642             return returnElement ? Ext.get(el.firstChild) : el.firstChild;
10643         },
10644
10645         createHtml : createHtml,
10646         
10647         /**
10648          * Creates new DOM element(s) without inserting them to the document.
10649          * @param {Object/String} o The DOM object spec (and children) or raw HTML blob
10650          * @return {HTMLElement} The new uninserted node
10651          */
10652         createDom: createDom,
10653         
10654         /** True to force the use of DOM instead of html fragments @type Boolean */
10655         useDom : false,
10656         
10657         /**
10658          * Creates a new Ext.Template from the DOM object spec.
10659          * @param {Object} o The DOM object spec (and children)
10660          * @return {Ext.Template} The new template
10661          */
10662         createTemplate : function(o){
10663             var html = Ext.core.DomHelper.createHtml(o);
10664             return Ext.create('Ext.Template', html);
10665         }
10666     };
10667     return pub;
10668 }();
10669
10670 /*
10671  * This is code is also distributed under MIT license for use
10672  * with jQuery and prototype JavaScript libraries.
10673  */
10674 /**
10675  * @class Ext.DomQuery
10676 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).
10677 <p>
10678 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>
10679
10680 <p>
10681 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.
10682 </p>
10683 <h4>Element Selectors:</h4>
10684 <ul class="list">
10685     <li> <b>*</b> any element</li>
10686     <li> <b>E</b> an element with the tag E</li>
10687     <li> <b>E F</b> All descendent elements of E that have the tag F</li>
10688     <li> <b>E > F</b> or <b>E/F</b> all direct children elements of E that have the tag F</li>
10689     <li> <b>E + F</b> all elements with the tag F that are immediately preceded by an element with the tag E</li>
10690     <li> <b>E ~ F</b> all elements with the tag F that are preceded by a sibling element with the tag E</li>
10691 </ul>
10692 <h4>Attribute Selectors:</h4>
10693 <p>The use of &#64; and quotes are optional. For example, div[&#64;foo='bar'] is also a valid attribute selector.</p>
10694 <ul class="list">
10695     <li> <b>E[foo]</b> has an attribute "foo"</li>
10696     <li> <b>E[foo=bar]</b> has an attribute "foo" that equals "bar"</li>
10697     <li> <b>E[foo^=bar]</b> has an attribute "foo" that starts with "bar"</li>
10698     <li> <b>E[foo$=bar]</b> has an attribute "foo" that ends with "bar"</li>
10699     <li> <b>E[foo*=bar]</b> has an attribute "foo" that contains the substring "bar"</li>
10700     <li> <b>E[foo%=2]</b> has an attribute "foo" that is evenly divisible by 2</li>
10701     <li> <b>E[foo!=bar]</b> attribute "foo" does not equal "bar"</li>
10702 </ul>
10703 <h4>Pseudo Classes:</h4>
10704 <ul class="list">
10705     <li> <b>E:first-child</b> E is the first child of its parent</li>
10706     <li> <b>E:last-child</b> E is the last child of its parent</li>
10707     <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>
10708     <li> <b>E:nth-child(odd)</b> E is an odd child of its parent</li>
10709     <li> <b>E:nth-child(even)</b> E is an even child of its parent</li>
10710     <li> <b>E:only-child</b> E is the only child of its parent</li>
10711     <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>
10712     <li> <b>E:first</b> the first E in the resultset</li>
10713     <li> <b>E:last</b> the last E in the resultset</li>
10714     <li> <b>E:nth(<i>n</i>)</b> the <i>n</i>th E in the resultset (1 based)</li>
10715     <li> <b>E:odd</b> shortcut for :nth-child(odd)</li>
10716     <li> <b>E:even</b> shortcut for :nth-child(even)</li>
10717     <li> <b>E:contains(foo)</b> E's innerHTML contains the substring "foo"</li>
10718     <li> <b>E:nodeValue(foo)</b> E contains a textNode with a nodeValue that equals "foo"</li>
10719     <li> <b>E:not(S)</b> an E element that does not match simple selector S</li>
10720     <li> <b>E:has(S)</b> an E element that has a descendent that matches simple selector S</li>
10721     <li> <b>E:next(S)</b> an E element whose next sibling matches simple selector S</li>
10722     <li> <b>E:prev(S)</b> an E element whose previous sibling matches simple selector S</li>
10723     <li> <b>E:any(S1|S2|S2)</b> an E element which matches any of the simple selectors S1, S2 or S3//\\</li>
10724 </ul>
10725 <h4>CSS Value Selectors:</h4>
10726 <ul class="list">
10727     <li> <b>E{display=none}</b> css value "display" that equals "none"</li>
10728     <li> <b>E{display^=none}</b> css value "display" that starts with "none"</li>
10729     <li> <b>E{display$=none}</b> css value "display" that ends with "none"</li>
10730     <li> <b>E{display*=none}</b> css value "display" that contains the substring "none"</li>
10731     <li> <b>E{display%=2}</b> css value "display" that is evenly divisible by 2</li>
10732     <li> <b>E{display!=none}</b> css value "display" that does not equal "none"</li>
10733 </ul>
10734  * @singleton
10735  */
10736 Ext.ns('Ext.core');
10737
10738 Ext.core.DomQuery = Ext.DomQuery = function(){
10739     var cache = {},
10740         simpleCache = {},
10741         valueCache = {},
10742         nonSpace = /\S/,
10743         trimRe = /^\s+|\s+$/g,
10744         tplRe = /\{(\d+)\}/g,
10745         modeRe = /^(\s?[\/>+~]\s?|\s|$)/,
10746         tagTokenRe = /^(#)?([\w-\*]+)/,
10747         nthRe = /(\d*)n\+?(\d*)/,
10748         nthRe2 = /\D/,
10749         // This is for IE MSXML which does not support expandos.
10750     // IE runs the same speed using setAttribute, however FF slows way down
10751     // and Safari completely fails so they need to continue to use expandos.
10752     isIE = window.ActiveXObject ? true : false,
10753     key = 30803;
10754
10755     // this eval is stop the compressor from
10756     // renaming the variable to something shorter
10757     eval("var batch = 30803;");
10758
10759     // Retrieve the child node from a particular
10760     // parent at the specified index.
10761     function child(parent, index){
10762         var i = 0,
10763             n = parent.firstChild;
10764         while(n){
10765             if(n.nodeType == 1){
10766                if(++i == index){
10767                    return n;
10768                }
10769             }
10770             n = n.nextSibling;
10771         }
10772         return null;
10773     }
10774
10775     // retrieve the next element node
10776     function next(n){
10777         while((n = n.nextSibling) && n.nodeType != 1);
10778         return n;
10779     }
10780
10781     // retrieve the previous element node
10782     function prev(n){
10783         while((n = n.previousSibling) && n.nodeType != 1);
10784         return n;
10785     }
10786
10787     // Mark each child node with a nodeIndex skipping and
10788     // removing empty text nodes.
10789     function children(parent){
10790         var n = parent.firstChild,
10791         nodeIndex = -1,
10792         nextNode;
10793         while(n){
10794             nextNode = n.nextSibling;
10795             // clean worthless empty nodes.
10796             if(n.nodeType == 3 && !nonSpace.test(n.nodeValue)){
10797             parent.removeChild(n);
10798             }else{
10799             // add an expando nodeIndex
10800             n.nodeIndex = ++nodeIndex;
10801             }
10802             n = nextNode;
10803         }
10804         return this;
10805     }
10806
10807
10808     // nodeSet - array of nodes
10809     // cls - CSS Class
10810     function byClassName(nodeSet, cls){
10811         if(!cls){
10812             return nodeSet;
10813         }
10814         var result = [], ri = -1;
10815         for(var i = 0, ci; ci = nodeSet[i]; i++){
10816             if((' '+ci.className+' ').indexOf(cls) != -1){
10817                 result[++ri] = ci;
10818             }
10819         }
10820         return result;
10821     };
10822
10823     function attrValue(n, attr){
10824         // if its an array, use the first node.
10825         if(!n.tagName && typeof n.length != "undefined"){
10826             n = n[0];
10827         }
10828         if(!n){
10829             return null;
10830         }
10831
10832         if(attr == "for"){
10833             return n.htmlFor;
10834         }
10835         if(attr == "class" || attr == "className"){
10836             return n.className;
10837         }
10838         return n.getAttribute(attr) || n[attr];
10839
10840     };
10841
10842
10843     // ns - nodes
10844     // mode - false, /, >, +, ~
10845     // tagName - defaults to "*"
10846     function getNodes(ns, mode, tagName){
10847         var result = [], ri = -1, cs;
10848         if(!ns){
10849             return result;
10850         }
10851         tagName = tagName || "*";
10852         // convert to array
10853         if(typeof ns.getElementsByTagName != "undefined"){
10854             ns = [ns];
10855         }
10856
10857         // no mode specified, grab all elements by tagName
10858         // at any depth
10859         if(!mode){
10860             for(var i = 0, ni; ni = ns[i]; i++){
10861                 cs = ni.getElementsByTagName(tagName);
10862                 for(var j = 0, ci; ci = cs[j]; j++){
10863                     result[++ri] = ci;
10864                 }
10865             }
10866         // Direct Child mode (/ or >)
10867         // E > F or E/F all direct children elements of E that have the tag
10868         } else if(mode == "/" || mode == ">"){
10869             var utag = tagName.toUpperCase();
10870             for(var i = 0, ni, cn; ni = ns[i]; i++){
10871                 cn = ni.childNodes;
10872                 for(var j = 0, cj; cj = cn[j]; j++){
10873                     if(cj.nodeName == utag || cj.nodeName == tagName  || tagName == '*'){
10874                         result[++ri] = cj;
10875                     }
10876                 }
10877             }
10878         // Immediately Preceding mode (+)
10879         // E + F all elements with the tag F that are immediately preceded by an element with the tag E
10880         }else if(mode == "+"){
10881             var utag = tagName.toUpperCase();
10882             for(var i = 0, n; n = ns[i]; i++){
10883                 while((n = n.nextSibling) && n.nodeType != 1);
10884                 if(n && (n.nodeName == utag || n.nodeName == tagName || tagName == '*')){
10885                     result[++ri] = n;
10886                 }
10887             }
10888         // Sibling mode (~)
10889         // E ~ F all elements with the tag F that are preceded by a sibling element with the tag E
10890         }else if(mode == "~"){
10891             var utag = tagName.toUpperCase();
10892             for(var i = 0, n; n = ns[i]; i++){
10893                 while((n = n.nextSibling)){
10894                     if (n.nodeName == utag || n.nodeName == tagName || tagName == '*'){
10895                         result[++ri] = n;
10896                     }
10897                 }
10898             }
10899         }
10900         return result;
10901     }
10902
10903     function concat(a, b){
10904         if(b.slice){
10905             return a.concat(b);
10906         }
10907         for(var i = 0, l = b.length; i < l; i++){
10908             a[a.length] = b[i];
10909         }
10910         return a;
10911     }
10912
10913     function byTag(cs, tagName){
10914         if(cs.tagName || cs == document){
10915             cs = [cs];
10916         }
10917         if(!tagName){
10918             return cs;
10919         }
10920         var result = [], ri = -1;
10921         tagName = tagName.toLowerCase();
10922         for(var i = 0, ci; ci = cs[i]; i++){
10923             if(ci.nodeType == 1 && ci.tagName.toLowerCase() == tagName){
10924                 result[++ri] = ci;
10925             }
10926         }
10927         return result;
10928     }
10929
10930     function byId(cs, id){
10931         if(cs.tagName || cs == document){
10932             cs = [cs];
10933         }
10934         if(!id){
10935             return cs;
10936         }
10937         var result = [], ri = -1;
10938         for(var i = 0, ci; ci = cs[i]; i++){
10939             if(ci && ci.id == id){
10940                 result[++ri] = ci;
10941                 return result;
10942             }
10943         }
10944         return result;
10945     }
10946
10947     // operators are =, !=, ^=, $=, *=, %=, |= and ~=
10948     // custom can be "{"
10949     function byAttribute(cs, attr, value, op, custom){
10950         var result = [],
10951             ri = -1,
10952             useGetStyle = custom == "{",
10953             fn = Ext.DomQuery.operators[op],
10954             a,
10955             xml,
10956             hasXml;
10957
10958         for(var i = 0, ci; ci = cs[i]; i++){
10959             // skip non-element nodes.
10960             if(ci.nodeType != 1){
10961                 continue;
10962             }
10963             // only need to do this for the first node
10964             if(!hasXml){
10965                 xml = Ext.DomQuery.isXml(ci);
10966                 hasXml = true;
10967             }
10968
10969             // we only need to change the property names if we're dealing with html nodes, not XML
10970             if(!xml){
10971                 if(useGetStyle){
10972                     a = Ext.DomQuery.getStyle(ci, attr);
10973                 } else if (attr == "class" || attr == "className"){
10974                     a = ci.className;
10975                 } else if (attr == "for"){
10976                     a = ci.htmlFor;
10977                 } else if (attr == "href"){
10978                     // getAttribute href bug
10979                     // http://www.glennjones.net/Post/809/getAttributehrefbug.htm
10980                     a = ci.getAttribute("href", 2);
10981                 } else{
10982                     a = ci.getAttribute(attr);
10983                 }
10984             }else{
10985                 a = ci.getAttribute(attr);
10986             }
10987             if((fn && fn(a, value)) || (!fn && a)){
10988                 result[++ri] = ci;
10989             }
10990         }
10991         return result;
10992     }
10993
10994     function byPseudo(cs, name, value){
10995         return Ext.DomQuery.pseudos[name](cs, value);
10996     }
10997
10998     function nodupIEXml(cs){
10999         var d = ++key,
11000             r;
11001         cs[0].setAttribute("_nodup", d);
11002         r = [cs[0]];
11003         for(var i = 1, len = cs.length; i < len; i++){
11004             var c = cs[i];
11005             if(!c.getAttribute("_nodup") != d){
11006                 c.setAttribute("_nodup", d);
11007                 r[r.length] = c;
11008             }
11009         }
11010         for(var i = 0, len = cs.length; i < len; i++){
11011             cs[i].removeAttribute("_nodup");
11012         }
11013         return r;
11014     }
11015
11016     function nodup(cs){
11017         if(!cs){
11018             return [];
11019         }
11020         var len = cs.length, c, i, r = cs, cj, ri = -1;
11021         if(!len || typeof cs.nodeType != "undefined" || len == 1){
11022             return cs;
11023         }
11024         if(isIE && typeof cs[0].selectSingleNode != "undefined"){
11025             return nodupIEXml(cs);
11026         }
11027         var d = ++key;
11028         cs[0]._nodup = d;
11029         for(i = 1; c = cs[i]; i++){
11030             if(c._nodup != d){
11031                 c._nodup = d;
11032             }else{
11033                 r = [];
11034                 for(var j = 0; j < i; j++){
11035                     r[++ri] = cs[j];
11036                 }
11037                 for(j = i+1; cj = cs[j]; j++){
11038                     if(cj._nodup != d){
11039                         cj._nodup = d;
11040                         r[++ri] = cj;
11041                     }
11042                 }
11043                 return r;
11044             }
11045         }
11046         return r;
11047     }
11048
11049     function quickDiffIEXml(c1, c2){
11050         var d = ++key,
11051             r = [];
11052         for(var i = 0, len = c1.length; i < len; i++){
11053             c1[i].setAttribute("_qdiff", d);
11054         }
11055         for(var i = 0, len = c2.length; i < len; i++){
11056             if(c2[i].getAttribute("_qdiff") != d){
11057                 r[r.length] = c2[i];
11058             }
11059         }
11060         for(var i = 0, len = c1.length; i < len; i++){
11061            c1[i].removeAttribute("_qdiff");
11062         }
11063         return r;
11064     }
11065
11066     function quickDiff(c1, c2){
11067         var len1 = c1.length,
11068             d = ++key,
11069             r = [];
11070         if(!len1){
11071             return c2;
11072         }
11073         if(isIE && typeof c1[0].selectSingleNode != "undefined"){
11074             return quickDiffIEXml(c1, c2);
11075         }
11076         for(var i = 0; i < len1; i++){
11077             c1[i]._qdiff = d;
11078         }
11079         for(var i = 0, len = c2.length; i < len; i++){
11080             if(c2[i]._qdiff != d){
11081                 r[r.length] = c2[i];
11082             }
11083         }
11084         return r;
11085     }
11086
11087     function quickId(ns, mode, root, id){
11088         if(ns == root){
11089            var d = root.ownerDocument || root;
11090            return d.getElementById(id);
11091         }
11092         ns = getNodes(ns, mode, "*");
11093         return byId(ns, id);
11094     }
11095
11096     return {
11097         getStyle : function(el, name){
11098             return Ext.fly(el).getStyle(name);
11099         },
11100         /**
11101          * Compiles a selector/xpath query into a reusable function. The returned function
11102          * takes one parameter "root" (optional), which is the context node from where the query should start.
11103          * @param {String} selector The selector/xpath query
11104          * @param {String} type (optional) Either "select" (the default) or "simple" for a simple selector match
11105          * @return {Function}
11106          */
11107         compile : function(path, type){
11108             type = type || "select";
11109
11110             // setup fn preamble
11111             var fn = ["var f = function(root){\n var mode; ++batch; var n = root || document;\n"],
11112                 mode,
11113                 lastPath,
11114                 matchers = Ext.DomQuery.matchers,
11115                 matchersLn = matchers.length,
11116                 modeMatch,
11117                 // accept leading mode switch
11118                 lmode = path.match(modeRe);
11119
11120             if(lmode && lmode[1]){
11121                 fn[fn.length] = 'mode="'+lmode[1].replace(trimRe, "")+'";';
11122                 path = path.replace(lmode[1], "");
11123             }
11124
11125             // strip leading slashes
11126             while(path.substr(0, 1)=="/"){
11127                 path = path.substr(1);
11128             }
11129
11130             while(path && lastPath != path){
11131                 lastPath = path;
11132                 var tokenMatch = path.match(tagTokenRe);
11133                 if(type == "select"){
11134                     if(tokenMatch){
11135                         // ID Selector
11136                         if(tokenMatch[1] == "#"){
11137                             fn[fn.length] = 'n = quickId(n, mode, root, "'+tokenMatch[2]+'");';
11138                         }else{
11139                             fn[fn.length] = 'n = getNodes(n, mode, "'+tokenMatch[2]+'");';
11140                         }
11141                         path = path.replace(tokenMatch[0], "");
11142                     }else if(path.substr(0, 1) != '@'){
11143                         fn[fn.length] = 'n = getNodes(n, mode, "*");';
11144                     }
11145                 // type of "simple"
11146                 }else{
11147                     if(tokenMatch){
11148                         if(tokenMatch[1] == "#"){
11149                             fn[fn.length] = 'n = byId(n, "'+tokenMatch[2]+'");';
11150                         }else{
11151                             fn[fn.length] = 'n = byTag(n, "'+tokenMatch[2]+'");';
11152                         }
11153                         path = path.replace(tokenMatch[0], "");
11154                     }
11155                 }
11156                 while(!(modeMatch = path.match(modeRe))){
11157                     var matched = false;
11158                     for(var j = 0; j < matchersLn; j++){
11159                         var t = matchers[j];
11160                         var m = path.match(t.re);
11161                         if(m){
11162                             fn[fn.length] = t.select.replace(tplRe, function(x, i){
11163                                 return m[i];
11164                             });
11165                             path = path.replace(m[0], "");
11166                             matched = true;
11167                             break;
11168                         }
11169                     }
11170                     // prevent infinite loop on bad selector
11171                     if(!matched){
11172                         Ext.Error.raise({
11173                             sourceClass: 'Ext.DomQuery',
11174                             sourceMethod: 'compile',
11175                             msg: 'Error parsing selector. Parsing failed at "' + path + '"'
11176                         });
11177                     }
11178                 }
11179                 if(modeMatch[1]){
11180                     fn[fn.length] = 'mode="'+modeMatch[1].replace(trimRe, "")+'";';
11181                     path = path.replace(modeMatch[1], "");
11182                 }
11183             }
11184             // close fn out
11185             fn[fn.length] = "return nodup(n);\n}";
11186
11187             // eval fn and return it
11188             eval(fn.join(""));
11189             return f;
11190         },
11191
11192         /**
11193          * Selects a group of elements.
11194          * @param {String} selector The selector/xpath query (can be a comma separated list of selectors)
11195          * @param {Node/String} root (optional) The start of the query (defaults to document).
11196          * @return {Array} An Array of DOM elements which match the selector. If there are
11197          * no matches, and empty Array is returned.
11198          */
11199         jsSelect: function(path, root, type){
11200             // set root to doc if not specified.
11201             root = root || document;
11202
11203             if(typeof root == "string"){
11204                 root = document.getElementById(root);
11205             }
11206             var paths = path.split(","),
11207                 results = [];
11208
11209             // loop over each selector
11210             for(var i = 0, len = paths.length; i < len; i++){
11211                 var subPath = paths[i].replace(trimRe, "");
11212                 // compile and place in cache
11213                 if(!cache[subPath]){
11214                     cache[subPath] = Ext.DomQuery.compile(subPath);
11215                     if(!cache[subPath]){
11216                         Ext.Error.raise({
11217                             sourceClass: 'Ext.DomQuery',
11218                             sourceMethod: 'jsSelect',
11219                             msg: subPath + ' is not a valid selector'
11220                         });
11221                     }
11222                 }
11223                 var result = cache[subPath](root);
11224                 if(result && result != document){
11225                     results = results.concat(result);
11226                 }
11227             }
11228
11229             // if there were multiple selectors, make sure dups
11230             // are eliminated
11231             if(paths.length > 1){
11232                 return nodup(results);
11233             }
11234             return results;
11235         },
11236
11237         isXml: function(el) {
11238             var docEl = (el ? el.ownerDocument || el : 0).documentElement;
11239             return docEl ? docEl.nodeName !== "HTML" : false;
11240         },
11241         
11242         select : document.querySelectorAll ? function(path, root, type) {
11243             root = root || document;
11244             if (!Ext.DomQuery.isXml(root)) {
11245             try {
11246                 var cs = root.querySelectorAll(path);
11247                 return Ext.Array.toArray(cs);
11248             }
11249             catch (ex) {}
11250             }
11251             return Ext.DomQuery.jsSelect.call(this, path, root, type);
11252         } : function(path, root, type) {
11253             return Ext.DomQuery.jsSelect.call(this, path, root, type);
11254         },
11255
11256         /**
11257          * Selects a single element.
11258          * @param {String} selector The selector/xpath query
11259          * @param {Node} root (optional) The start of the query (defaults to document).
11260          * @return {Element} The DOM element which matched the selector.
11261          */
11262         selectNode : function(path, root){
11263             return Ext.DomQuery.select(path, root)[0];
11264         },
11265
11266         /**
11267          * Selects the value of a node, optionally replacing null with the defaultValue.
11268          * @param {String} selector The selector/xpath query
11269          * @param {Node} root (optional) The start of the query (defaults to document).
11270          * @param {String} defaultValue
11271          * @return {String}
11272          */
11273         selectValue : function(path, root, defaultValue){
11274             path = path.replace(trimRe, "");
11275             if(!valueCache[path]){
11276                 valueCache[path] = Ext.DomQuery.compile(path, "select");
11277             }
11278             var n = valueCache[path](root), v;
11279             n = n[0] ? n[0] : n;
11280
11281             // overcome a limitation of maximum textnode size
11282             // Rumored to potentially crash IE6 but has not been confirmed.
11283             // http://reference.sitepoint.com/javascript/Node/normalize
11284             // https://developer.mozilla.org/En/DOM/Node.normalize
11285             if (typeof n.normalize == 'function') n.normalize();
11286
11287             v = (n && n.firstChild ? n.firstChild.nodeValue : null);
11288             return ((v === null||v === undefined||v==='') ? defaultValue : v);
11289         },
11290
11291         /**
11292          * Selects the value of a node, parsing integers and floats. Returns the defaultValue, or 0 if none is specified.
11293          * @param {String} selector The selector/xpath query
11294          * @param {Node} root (optional) The start of the query (defaults to document).
11295          * @param {Number} defaultValue
11296          * @return {Number}
11297          */
11298         selectNumber : function(path, root, defaultValue){
11299             var v = Ext.DomQuery.selectValue(path, root, defaultValue || 0);
11300             return parseFloat(v);
11301         },
11302
11303         /**
11304          * Returns true if the passed element(s) match the passed simple selector (e.g. div.some-class or span:first-child)
11305          * @param {String/HTMLElement/Array} el An element id, element or array of elements
11306          * @param {String} selector The simple selector to test
11307          * @return {Boolean}
11308          */
11309         is : function(el, ss){
11310             if(typeof el == "string"){
11311                 el = document.getElementById(el);
11312             }
11313             var isArray = Ext.isArray(el),
11314                 result = Ext.DomQuery.filter(isArray ? el : [el], ss);
11315             return isArray ? (result.length == el.length) : (result.length > 0);
11316         },
11317
11318         /**
11319          * Filters an array of elements to only include matches of a simple selector (e.g. div.some-class or span:first-child)
11320          * @param {Array} el An array of elements to filter
11321          * @param {String} selector The simple selector to test
11322          * @param {Boolean} nonMatches If true, it returns the elements that DON'T match
11323          * the selector instead of the ones that match
11324          * @return {Array} An Array of DOM elements which match the selector. If there are
11325          * no matches, and empty Array is returned.
11326          */
11327         filter : function(els, ss, nonMatches){
11328             ss = ss.replace(trimRe, "");
11329             if(!simpleCache[ss]){
11330                 simpleCache[ss] = Ext.DomQuery.compile(ss, "simple");
11331             }
11332             var result = simpleCache[ss](els);
11333             return nonMatches ? quickDiff(result, els) : result;
11334         },
11335
11336         /**
11337          * Collection of matching regular expressions and code snippets.
11338          * Each capture group within () will be replace the {} in the select
11339          * statement as specified by their index.
11340          */
11341         matchers : [{
11342                 re: /^\.([\w-]+)/,
11343                 select: 'n = byClassName(n, " {1} ");'
11344             }, {
11345                 re: /^\:([\w-]+)(?:\(((?:[^\s>\/]*|.*?))\))?/,
11346                 select: 'n = byPseudo(n, "{1}", "{2}");'
11347             },{
11348                 re: /^(?:([\[\{])(?:@)?([\w-]+)\s?(?:(=|.=)\s?['"]?(.*?)["']?)?[\]\}])/,
11349                 select: 'n = byAttribute(n, "{2}", "{4}", "{3}", "{1}");'
11350             }, {
11351                 re: /^#([\w-]+)/,
11352                 select: 'n = byId(n, "{1}");'
11353             },{
11354                 re: /^@([\w-]+)/,
11355                 select: 'return {firstChild:{nodeValue:attrValue(n, "{1}")}};'
11356             }
11357         ],
11358
11359         /**
11360          * Collection of operator comparison functions. The default operators are =, !=, ^=, $=, *=, %=, |= and ~=.
11361          * 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;.
11362          */
11363         operators : {
11364             "=" : function(a, v){
11365                 return a == v;
11366             },
11367             "!=" : function(a, v){
11368                 return a != v;
11369             },
11370             "^=" : function(a, v){
11371                 return a && a.substr(0, v.length) == v;
11372             },
11373             "$=" : function(a, v){
11374                 return a && a.substr(a.length-v.length) == v;
11375             },
11376             "*=" : function(a, v){
11377                 return a && a.indexOf(v) !== -1;
11378             },
11379             "%=" : function(a, v){
11380                 return (a % v) == 0;
11381             },
11382             "|=" : function(a, v){
11383                 return a && (a == v || a.substr(0, v.length+1) == v+'-');
11384             },
11385             "~=" : function(a, v){
11386                 return a && (' '+a+' ').indexOf(' '+v+' ') != -1;
11387             }
11388         },
11389
11390         /**
11391 Object hash of "pseudo class" filter functions which are used when filtering selections. 
11392 Each function is passed two parameters:
11393
11394 - **c** : Array
11395     An Array of DOM elements to filter.
11396     
11397 - **v** : String
11398     The argument (if any) supplied in the selector.
11399
11400 A filter function returns an Array of DOM elements which conform to the pseudo class.
11401 In addition to the provided pseudo classes listed above such as `first-child` and `nth-child`,
11402 developers may add additional, custom psuedo class filters to select elements according to application-specific requirements.
11403
11404 For example, to filter `a` elements to only return links to __external__ resources:
11405
11406     Ext.DomQuery.pseudos.external = function(c, v){
11407         var r = [], ri = -1;
11408         for(var i = 0, ci; ci = c[i]; i++){
11409             // Include in result set only if it's a link to an external resource
11410             if(ci.hostname != location.hostname){
11411                 r[++ri] = ci;
11412             }
11413         }
11414         return r;
11415     };
11416
11417 Then external links could be gathered with the following statement:
11418
11419     var externalLinks = Ext.select("a:external");
11420
11421         * @markdown
11422         */
11423         pseudos : {
11424             "first-child" : function(c){
11425                 var r = [], ri = -1, n;
11426                 for(var i = 0, ci; ci = n = c[i]; i++){
11427                     while((n = n.previousSibling) && n.nodeType != 1);
11428                     if(!n){
11429                         r[++ri] = ci;
11430                     }
11431                 }
11432                 return r;
11433             },
11434
11435             "last-child" : function(c){
11436                 var r = [], ri = -1, n;
11437                 for(var i = 0, ci; ci = n = c[i]; i++){
11438                     while((n = n.nextSibling) && n.nodeType != 1);
11439                     if(!n){
11440                         r[++ri] = ci;
11441                     }
11442                 }
11443                 return r;
11444             },
11445
11446             "nth-child" : function(c, a) {
11447                 var r = [], ri = -1,
11448                     m = nthRe.exec(a == "even" && "2n" || a == "odd" && "2n+1" || !nthRe2.test(a) && "n+" + a || a),
11449                     f = (m[1] || 1) - 0, l = m[2] - 0;
11450                 for(var i = 0, n; n = c[i]; i++){
11451                     var pn = n.parentNode;
11452                     if (batch != pn._batch) {
11453                         var j = 0;
11454                         for(var cn = pn.firstChild; cn; cn = cn.nextSibling){
11455                             if(cn.nodeType == 1){
11456                                cn.nodeIndex = ++j;
11457                             }
11458                         }
11459                         pn._batch = batch;
11460                     }
11461                     if (f == 1) {
11462                         if (l == 0 || n.nodeIndex == l){
11463                             r[++ri] = n;
11464                         }
11465                     } else if ((n.nodeIndex + l) % f == 0){
11466                         r[++ri] = n;
11467                     }
11468                 }
11469
11470                 return r;
11471             },
11472
11473             "only-child" : function(c){
11474                 var r = [], ri = -1;;
11475                 for(var i = 0, ci; ci = c[i]; i++){
11476                     if(!prev(ci) && !next(ci)){
11477                         r[++ri] = ci;
11478                     }
11479                 }
11480                 return r;
11481             },
11482
11483             "empty" : function(c){
11484                 var r = [], ri = -1;
11485                 for(var i = 0, ci; ci = c[i]; i++){
11486                     var cns = ci.childNodes, j = 0, cn, empty = true;
11487                     while(cn = cns[j]){
11488                         ++j;
11489                         if(cn.nodeType == 1 || cn.nodeType == 3){
11490                             empty = false;
11491                             break;
11492                         }
11493                     }
11494                     if(empty){
11495                         r[++ri] = ci;
11496                     }
11497                 }
11498                 return r;
11499             },
11500
11501             "contains" : function(c, v){
11502                 var r = [], ri = -1;
11503                 for(var i = 0, ci; ci = c[i]; i++){
11504                     if((ci.textContent||ci.innerText||'').indexOf(v) != -1){
11505                         r[++ri] = ci;
11506                     }
11507                 }
11508                 return r;
11509             },
11510
11511             "nodeValue" : function(c, v){
11512                 var r = [], ri = -1;
11513                 for(var i = 0, ci; ci = c[i]; i++){
11514                     if(ci.firstChild && ci.firstChild.nodeValue == v){
11515                         r[++ri] = ci;
11516                     }
11517                 }
11518                 return r;
11519             },
11520
11521             "checked" : function(c){
11522                 var r = [], ri = -1;
11523                 for(var i = 0, ci; ci = c[i]; i++){
11524                     if(ci.checked == true){
11525                         r[++ri] = ci;
11526                     }
11527                 }
11528                 return r;
11529             },
11530
11531             "not" : function(c, ss){
11532                 return Ext.DomQuery.filter(c, ss, true);
11533             },
11534
11535             "any" : function(c, selectors){
11536                 var ss = selectors.split('|'),
11537                     r = [], ri = -1, s;
11538                 for(var i = 0, ci; ci = c[i]; i++){
11539                     for(var j = 0; s = ss[j]; j++){
11540                         if(Ext.DomQuery.is(ci, s)){
11541                             r[++ri] = ci;
11542                             break;
11543                         }
11544                     }
11545                 }
11546                 return r;
11547             },
11548
11549             "odd" : function(c){
11550                 return this["nth-child"](c, "odd");
11551             },
11552
11553             "even" : function(c){
11554                 return this["nth-child"](c, "even");
11555             },
11556
11557             "nth" : function(c, a){
11558                 return c[a-1] || [];
11559             },
11560
11561             "first" : function(c){
11562                 return c[0] || [];
11563             },
11564
11565             "last" : function(c){
11566                 return c[c.length-1] || [];
11567             },
11568
11569             "has" : function(c, ss){
11570                 var s = Ext.DomQuery.select,
11571                     r = [], ri = -1;
11572                 for(var i = 0, ci; ci = c[i]; i++){
11573                     if(s(ss, ci).length > 0){
11574                         r[++ri] = ci;
11575                     }
11576                 }
11577                 return r;
11578             },
11579
11580             "next" : function(c, ss){
11581                 var is = Ext.DomQuery.is,
11582                     r = [], ri = -1;
11583                 for(var i = 0, ci; ci = c[i]; i++){
11584                     var n = next(ci);
11585                     if(n && is(n, ss)){
11586                         r[++ri] = ci;
11587                     }
11588                 }
11589                 return r;
11590             },
11591
11592             "prev" : function(c, ss){
11593                 var is = Ext.DomQuery.is,
11594                     r = [], ri = -1;
11595                 for(var i = 0, ci; ci = c[i]; i++){
11596                     var n = prev(ci);
11597                     if(n && is(n, ss)){
11598                         r[++ri] = ci;
11599                     }
11600                 }
11601                 return r;
11602             }
11603         }
11604     };
11605 }();
11606
11607 /**
11608  * Selects an array of DOM nodes by CSS/XPath selector. Shorthand of {@link Ext.DomQuery#select}
11609  * @param {String} path The selector/xpath query
11610  * @param {Node} root (optional) The start of the query (defaults to document).
11611  * @return {Array}
11612  * @member Ext
11613  * @method query
11614  */
11615 Ext.query = Ext.DomQuery.select;
11616
11617 /**
11618  * @class Ext.core.Element
11619  * <p>Encapsulates a DOM element, adding simple DOM manipulation facilities, normalizing for browser differences.</p>
11620  * <p>All instances of this class inherit the methods of {@link Ext.fx.Anim} making visual effects easily available to all DOM elements.</p>
11621  * <p>Note that the events documented in this class are not Ext events, they encapsulate browser events. To
11622  * access the underlying browser event, see {@link Ext.EventObject#browserEvent}. Some older
11623  * browsers may not support the full range of events. Which events are supported is beyond the control of ExtJs.</p>
11624  * Usage:<br>
11625 <pre><code>
11626 // by id
11627 var el = Ext.get("my-div");
11628
11629 // by DOM element reference
11630 var el = Ext.get(myDivElement);
11631 </code></pre>
11632  * <b>Animations</b><br />
11633  * <p>When an element is manipulated, by default there is no animation.</p>
11634  * <pre><code>
11635 var el = Ext.get("my-div");
11636
11637 // no animation
11638 el.setWidth(100);
11639  * </code></pre>
11640  * <p>Many of the functions for manipulating an element have an optional "animate" parameter.  This
11641  * parameter can be specified as boolean (<tt>true</tt>) for default animation effects.</p>
11642  * <pre><code>
11643 // default animation
11644 el.setWidth(100, true);
11645  * </code></pre>
11646  *
11647  * <p>To configure the effects, an object literal with animation options to use as the Element animation
11648  * configuration object can also be specified. Note that the supported Element animation configuration
11649  * options are a subset of the {@link Ext.fx.Anim} animation options specific to Fx effects.  The supported
11650  * Element animation configuration options are:</p>
11651 <pre>
11652 Option    Default   Description
11653 --------- --------  ---------------------------------------------
11654 {@link Ext.fx.Anim#duration duration}  .35       The duration of the animation in seconds
11655 {@link Ext.fx.Anim#easing easing}    easeOut   The easing method
11656 {@link Ext.fx.Anim#callback callback}  none      A function to execute when the anim completes
11657 {@link Ext.fx.Anim#scope scope}     this      The scope (this) of the callback function
11658 </pre>
11659  *
11660  * <pre><code>
11661 // Element animation options object
11662 var opt = {
11663     {@link Ext.fx.Anim#duration duration}: 1,
11664     {@link Ext.fx.Anim#easing easing}: 'elasticIn',
11665     {@link Ext.fx.Anim#callback callback}: this.foo,
11666     {@link Ext.fx.Anim#scope scope}: this
11667 };
11668 // animation with some options set
11669 el.setWidth(100, opt);
11670  * </code></pre>
11671  * <p>The Element animation object being used for the animation will be set on the options
11672  * object as "anim", which allows you to stop or manipulate the animation. Here is an example:</p>
11673  * <pre><code>
11674 // using the "anim" property to get the Anim object
11675 if(opt.anim.isAnimated()){
11676     opt.anim.stop();
11677 }
11678  * </code></pre>
11679  * <p>Also see the <tt>{@link #animate}</tt> method for another animation technique.</p>
11680  * <p><b> Composite (Collections of) Elements</b></p>
11681  * <p>For working with collections of Elements, see {@link Ext.CompositeElement}</p>
11682  * @constructor Create a new Element directly.
11683  * @param {String/HTMLElement} element
11684  * @param {Boolean} forceNew (optional) By default the constructor checks to see if there is already an instance of this element in the cache and if there is it returns the same instance. This will skip that check (useful for extending this class).
11685  */
11686  (function() {
11687     var DOC = document,
11688         EC = Ext.cache;
11689
11690     Ext.Element = Ext.core.Element = function(element, forceNew) {
11691         var dom = typeof element == "string" ? DOC.getElementById(element) : element,
11692         id;
11693
11694         if (!dom) {
11695             return null;
11696         }
11697
11698         id = dom.id;
11699
11700         if (!forceNew && id && EC[id]) {
11701             // element object already exists
11702             return EC[id].el;
11703         }
11704
11705         /**
11706      * The DOM element
11707      * @type HTMLElement
11708      */
11709         this.dom = dom;
11710
11711         /**
11712      * The DOM element ID
11713      * @type String
11714      */
11715         this.id = id || Ext.id(dom);
11716     };
11717
11718     var DH = Ext.core.DomHelper,
11719     El = Ext.core.Element;
11720
11721
11722     El.prototype = {
11723         /**
11724      * Sets the passed attributes as attributes of this element (a style attribute can be a string, object or function)
11725      * @param {Object} o The object with the attributes
11726      * @param {Boolean} useSet (optional) false to override the default setAttribute to use expandos.
11727      * @return {Ext.core.Element} this
11728      */
11729         set: function(o, useSet) {
11730             var el = this.dom,
11731                 attr,
11732                 val;
11733             useSet = (useSet !== false) && !!el.setAttribute;
11734
11735             for (attr in o) {
11736                 if (o.hasOwnProperty(attr)) {
11737                     val = o[attr];
11738                     if (attr == 'style') {
11739                         DH.applyStyles(el, val);
11740                     } else if (attr == 'cls') {
11741                         el.className = val;
11742                     } else if (useSet) {
11743                         el.setAttribute(attr, val);
11744                     } else {
11745                         el[attr] = val;
11746                     }
11747                 }
11748             }
11749             return this;
11750         },
11751
11752         //  Mouse events
11753         /**
11754      * @event click
11755      * Fires when a mouse click is detected within the element.
11756      * @param {Ext.EventObject} e The {@link Ext.EventObject} encapsulating the DOM event.
11757      * @param {HtmlElement} t The target of the event.
11758      * @param {Object} o The options configuration passed to the {@link #addListener} call.
11759      */
11760         /**
11761      * @event contextmenu
11762      * Fires when a right click is detected within the element.
11763      * @param {Ext.EventObject} e The {@link Ext.EventObject} encapsulating the DOM event.
11764      * @param {HtmlElement} t The target of the event.
11765      * @param {Object} o The options configuration passed to the {@link #addListener} call.
11766      */
11767         /**
11768      * @event dblclick
11769      * Fires when a mouse double click is detected within the element.
11770      * @param {Ext.EventObject} e The {@link Ext.EventObject} encapsulating the DOM event.
11771      * @param {HtmlElement} t The target of the event.
11772      * @param {Object} o The options configuration passed to the {@link #addListener} call.
11773      */
11774         /**
11775      * @event mousedown
11776      * Fires when a mousedown is detected within the element.
11777      * @param {Ext.EventObject} e The {@link Ext.EventObject} encapsulating the DOM event.
11778      * @param {HtmlElement} t The target of the event.
11779      * @param {Object} o The options configuration passed to the {@link #addListener} call.
11780      */
11781         /**
11782      * @event mouseup
11783      * Fires when a mouseup is detected within the element.
11784      * @param {Ext.EventObject} e The {@link Ext.EventObject} encapsulating the DOM event.
11785      * @param {HtmlElement} t The target of the event.
11786      * @param {Object} o The options configuration passed to the {@link #addListener} call.
11787      */
11788         /**
11789      * @event mouseover
11790      * Fires when a mouseover is detected within the element.
11791      * @param {Ext.EventObject} e The {@link Ext.EventObject} encapsulating the DOM event.
11792      * @param {HtmlElement} t The target of the event.
11793      * @param {Object} o The options configuration passed to the {@link #addListener} call.
11794      */
11795         /**
11796      * @event mousemove
11797      * Fires when a mousemove is detected with the element.
11798      * @param {Ext.EventObject} e The {@link Ext.EventObject} encapsulating the DOM event.
11799      * @param {HtmlElement} t The target of the event.
11800      * @param {Object} o The options configuration passed to the {@link #addListener} call.
11801      */
11802         /**
11803      * @event mouseout
11804      * Fires when a mouseout is detected with the element.
11805      * @param {Ext.EventObject} e The {@link Ext.EventObject} encapsulating the DOM event.
11806      * @param {HtmlElement} t The target of the event.
11807      * @param {Object} o The options configuration passed to the {@link #addListener} call.
11808      */
11809         /**
11810      * @event mouseenter
11811      * Fires when the mouse enters the element.
11812      * @param {Ext.EventObject} e The {@link Ext.EventObject} encapsulating the DOM event.
11813      * @param {HtmlElement} t The target of the event.
11814      * @param {Object} o The options configuration passed to the {@link #addListener} call.
11815      */
11816         /**
11817      * @event mouseleave
11818      * Fires when the mouse leaves the element.
11819      * @param {Ext.EventObject} e The {@link Ext.EventObject} encapsulating the DOM event.
11820      * @param {HtmlElement} t The target of the event.
11821      * @param {Object} o The options configuration passed to the {@link #addListener} call.
11822      */
11823
11824         //  Keyboard events
11825         /**
11826      * @event keypress
11827      * Fires when a keypress is detected within the element.
11828      * @param {Ext.EventObject} e The {@link Ext.EventObject} encapsulating the DOM event.
11829      * @param {HtmlElement} t The target of the event.
11830      * @param {Object} o The options configuration passed to the {@link #addListener} call.
11831      */
11832         /**
11833      * @event keydown
11834      * Fires when a keydown is detected within the element.
11835      * @param {Ext.EventObject} e The {@link Ext.EventObject} encapsulating the DOM event.
11836      * @param {HtmlElement} t The target of the event.
11837      * @param {Object} o The options configuration passed to the {@link #addListener} call.
11838      */
11839         /**
11840      * @event keyup
11841      * Fires when a keyup is detected within the element.
11842      * @param {Ext.EventObject} e The {@link Ext.EventObject} encapsulating the DOM event.
11843      * @param {HtmlElement} t The target of the event.
11844      * @param {Object} o The options configuration passed to the {@link #addListener} call.
11845      */
11846
11847
11848         //  HTML frame/object events
11849         /**
11850      * @event load
11851      * Fires when the user agent finishes loading all content within the element. Only supported by window, frames, objects and images.
11852      * @param {Ext.EventObject} e The {@link Ext.EventObject} encapsulating the DOM event.
11853      * @param {HtmlElement} t The target of the event.
11854      * @param {Object} o The options configuration passed to the {@link #addListener} call.
11855      */
11856         /**
11857      * @event unload
11858      * Fires when the user agent removes all content from a window or frame. For elements, it fires when the target element or any of its content has been removed.
11859      * @param {Ext.EventObject} e The {@link Ext.EventObject} encapsulating the DOM event.
11860      * @param {HtmlElement} t The target of the event.
11861      * @param {Object} o The options configuration passed to the {@link #addListener} call.
11862      */
11863         /**
11864      * @event abort
11865      * Fires when an object/image is stopped from loading before completely loaded.
11866      * @param {Ext.EventObject} e The {@link Ext.EventObject} encapsulating the DOM event.
11867      * @param {HtmlElement} t The target of the event.
11868      * @param {Object} o The options configuration passed to the {@link #addListener} call.
11869      */
11870         /**
11871      * @event error
11872      * Fires when an object/image/frame cannot be loaded properly.
11873      * @param {Ext.EventObject} e The {@link Ext.EventObject} encapsulating the DOM event.
11874      * @param {HtmlElement} t The target of the event.
11875      * @param {Object} o The options configuration passed to the {@link #addListener} call.
11876      */
11877         /**
11878      * @event resize
11879      * Fires when a document view is resized.
11880      * @param {Ext.EventObject} e The {@link Ext.EventObject} encapsulating the DOM event.
11881      * @param {HtmlElement} t The target of the event.
11882      * @param {Object} o The options configuration passed to the {@link #addListener} call.
11883      */
11884         /**
11885      * @event scroll
11886      * Fires when a document view is scrolled.
11887      * @param {Ext.EventObject} e The {@link Ext.EventObject} encapsulating the DOM event.
11888      * @param {HtmlElement} t The target of the event.
11889      * @param {Object} o The options configuration passed to the {@link #addListener} call.
11890      */
11891
11892         //  Form events
11893         /**
11894      * @event select
11895      * Fires when a user selects some text in a text field, including input and textarea.
11896      * @param {Ext.EventObject} e The {@link Ext.EventObject} encapsulating the DOM event.
11897      * @param {HtmlElement} t The target of the event.
11898      * @param {Object} o The options configuration passed to the {@link #addListener} call.
11899      */
11900         /**
11901      * @event change
11902      * Fires when a control loses the input focus and its value has been modified since gaining focus.
11903      * @param {Ext.EventObject} e The {@link Ext.EventObject} encapsulating the DOM event.
11904      * @param {HtmlElement} t The target of the event.
11905      * @param {Object} o The options configuration passed to the {@link #addListener} call.
11906      */
11907         /**
11908      * @event submit
11909      * Fires when a form is submitted.
11910      * @param {Ext.EventObject} e The {@link Ext.EventObject} encapsulating the DOM event.
11911      * @param {HtmlElement} t The target of the event.
11912      * @param {Object} o The options configuration passed to the {@link #addListener} call.
11913      */
11914         /**
11915      * @event reset
11916      * Fires when a form is reset.
11917      * @param {Ext.EventObject} e The {@link Ext.EventObject} encapsulating the DOM event.
11918      * @param {HtmlElement} t The target of the event.
11919      * @param {Object} o The options configuration passed to the {@link #addListener} call.
11920      */
11921         /**
11922      * @event focus
11923      * Fires when an element receives focus either via the pointing device or by tab navigation.
11924      * @param {Ext.EventObject} e The {@link Ext.EventObject} encapsulating the DOM event.
11925      * @param {HtmlElement} t The target of the event.
11926      * @param {Object} o The options configuration passed to the {@link #addListener} call.
11927      */
11928         /**
11929      * @event blur
11930      * Fires when an element loses focus either via the pointing device or by tabbing navigation.
11931      * @param {Ext.EventObject} e The {@link Ext.EventObject} encapsulating the DOM event.
11932      * @param {HtmlElement} t The target of the event.
11933      * @param {Object} o The options configuration passed to the {@link #addListener} call.
11934      */
11935
11936         //  User Interface events
11937         /**
11938      * @event DOMFocusIn
11939      * Where supported. Similar to HTML focus event, but can be applied to any focusable element.
11940      * @param {Ext.EventObject} e The {@link Ext.EventObject} encapsulating the DOM event.
11941      * @param {HtmlElement} t The target of the event.
11942      * @param {Object} o The options configuration passed to the {@link #addListener} call.
11943      */
11944         /**
11945      * @event DOMFocusOut
11946      * Where supported. Similar to HTML blur event, but can be applied to any focusable element.
11947      * @param {Ext.EventObject} e The {@link Ext.EventObject} encapsulating the DOM event.
11948      * @param {HtmlElement} t The target of the event.
11949      * @param {Object} o The options configuration passed to the {@link #addListener} call.
11950      */
11951         /**
11952      * @event DOMActivate
11953      * Where supported. Fires when an element is activated, for instance, through a mouse click or a keypress.
11954      * @param {Ext.EventObject} e The {@link Ext.EventObject} encapsulating the DOM event.
11955      * @param {HtmlElement} t The target of the event.
11956      * @param {Object} o The options configuration passed to the {@link #addListener} call.
11957      */
11958
11959         //  DOM Mutation events
11960         /**
11961      * @event DOMSubtreeModified
11962      * Where supported. Fires when the subtree is modified.
11963      * @param {Ext.EventObject} e The {@link Ext.EventObject} encapsulating the DOM event.
11964      * @param {HtmlElement} t The target of the event.
11965      * @param {Object} o The options configuration passed to the {@link #addListener} call.
11966      */
11967         /**
11968      * @event DOMNodeInserted
11969      * Where supported. Fires when a node has been added as a child of another node.
11970      * @param {Ext.EventObject} e The {@link Ext.EventObject} encapsulating the DOM event.
11971      * @param {HtmlElement} t The target of the event.
11972      * @param {Object} o The options configuration passed to the {@link #addListener} call.
11973      */
11974         /**
11975      * @event DOMNodeRemoved
11976      * Where supported. Fires when a descendant node of the element is removed.
11977      * @param {Ext.EventObject} e The {@link Ext.EventObject} encapsulating the DOM event.
11978      * @param {HtmlElement} t The target of the event.
11979      * @param {Object} o The options configuration passed to the {@link #addListener} call.
11980      */
11981         /**
11982      * @event DOMNodeRemovedFromDocument
11983      * Where supported. Fires when a node is being removed from a document.
11984      * @param {Ext.EventObject} e The {@link Ext.EventObject} encapsulating the DOM event.
11985      * @param {HtmlElement} t The target of the event.
11986      * @param {Object} o The options configuration passed to the {@link #addListener} call.
11987      */
11988         /**
11989      * @event DOMNodeInsertedIntoDocument
11990      * Where supported. Fires when a node is being inserted into a document.
11991      * @param {Ext.EventObject} e The {@link Ext.EventObject} encapsulating the DOM event.
11992      * @param {HtmlElement} t The target of the event.
11993      * @param {Object} o The options configuration passed to the {@link #addListener} call.
11994      */
11995         /**
11996      * @event DOMAttrModified
11997      * Where supported. Fires when an attribute has been modified.
11998      * @param {Ext.EventObject} e The {@link Ext.EventObject} encapsulating the DOM event.
11999      * @param {HtmlElement} t The target of the event.
12000      * @param {Object} o The options configuration passed to the {@link #addListener} call.
12001      */
12002         /**
12003      * @event DOMCharacterDataModified
12004      * Where supported. Fires when the character data has been modified.
12005      * @param {Ext.EventObject} e The {@link Ext.EventObject} encapsulating the DOM event.
12006      * @param {HtmlElement} t The target of the event.
12007      * @param {Object} o The options configuration passed to the {@link #addListener} call.
12008      */
12009
12010         /**
12011      * The default unit to append to CSS values where a unit isn't provided (defaults to px).
12012      * @type String
12013      */
12014         defaultUnit: "px",
12015
12016         /**
12017      * Returns true if this element matches the passed simple selector (e.g. div.some-class or span:first-child)
12018      * @param {String} selector The simple selector to test
12019      * @return {Boolean} True if this element matches the selector, else false
12020      */
12021         is: function(simpleSelector) {
12022             return Ext.DomQuery.is(this.dom, simpleSelector);
12023         },
12024
12025         /**
12026      * Tries to focus the element. Any exceptions are caught and ignored.
12027      * @param {Number} defer (optional) Milliseconds to defer the focus
12028      * @return {Ext.core.Element} this
12029      */
12030         focus: function(defer,
12031                         /* private */
12032                         dom) {
12033             var me = this;
12034             dom = dom || me.dom;
12035             try {
12036                 if (Number(defer)) {
12037                     Ext.defer(me.focus, defer, null, [null, dom]);
12038                 } else {
12039                     dom.focus();
12040                 }
12041             } catch(e) {}
12042             return me;
12043         },
12044
12045         /**
12046      * Tries to blur the element. Any exceptions are caught and ignored.
12047      * @return {Ext.core.Element} this
12048      */
12049         blur: function() {
12050             try {
12051                 this.dom.blur();
12052             } catch(e) {}
12053             return this;
12054         },
12055
12056         /**
12057      * Returns the value of the "value" attribute
12058      * @param {Boolean} asNumber true to parse the value as a number
12059      * @return {String/Number}
12060      */
12061         getValue: function(asNumber) {
12062             var val = this.dom.value;
12063             return asNumber ? parseInt(val, 10) : val;
12064         },
12065
12066         /**
12067      * Appends an event handler to this element.  The shorthand version {@link #on} is equivalent.
12068      * @param {String} eventName The name of event to handle.
12069      * @param {Function} fn The handler function the event invokes. This function is passed
12070      * the following parameters:<ul>
12071      * <li><b>evt</b> : EventObject<div class="sub-desc">The {@link Ext.EventObject EventObject} describing the event.</div></li>
12072      * <li><b>el</b> : HtmlElement<div class="sub-desc">The DOM element which was the target of the event.
12073      * Note that this may be filtered by using the <tt>delegate</tt> option.</div></li>
12074      * <li><b>o</b> : Object<div class="sub-desc">The options object from the addListener call.</div></li>
12075      * </ul>
12076      * @param {Object} scope (optional) The scope (<code><b>this</b></code> reference) in which the handler function is executed.
12077      * <b>If omitted, defaults to this Element.</b>.
12078      * @param {Object} options (optional) An object containing handler configuration properties.
12079      * This may contain any of the following properties:<ul>
12080      * <li><b>scope</b> Object : <div class="sub-desc">The scope (<code><b>this</b></code> reference) in which the handler function is executed.
12081      * <b>If omitted, defaults to this Element.</b></div></li>
12082      * <li><b>delegate</b> String: <div class="sub-desc">A simple selector to filter the target or look for a descendant of the target. See below for additional details.</div></li>
12083      * <li><b>stopEvent</b> Boolean: <div class="sub-desc">True to stop the event. That is stop propagation, and prevent the default action.</div></li>
12084      * <li><b>preventDefault</b> Boolean: <div class="sub-desc">True to prevent the default action</div></li>
12085      * <li><b>stopPropagation</b> Boolean: <div class="sub-desc">True to prevent event propagation</div></li>
12086      * <li><b>normalized</b> Boolean: <div class="sub-desc">False to pass a browser event to the handler function instead of an Ext.EventObject</div></li>
12087      * <li><b>target</b> Ext.core.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>
12088      * <li><b>delay</b> Number: <div class="sub-desc">The number of milliseconds to delay the invocation of the handler after the event fires.</div></li>
12089      * <li><b>single</b> Boolean: <div class="sub-desc">True to add a handler to handle just the next firing of the event, and then remove itself.</div></li>
12090      * <li><b>buffer</b> Number: <div class="sub-desc">Causes the handler to be scheduled to run in an {@link Ext.util.DelayedTask} delayed
12091      * by the specified number of milliseconds. If the event fires again within that time, the original
12092      * handler is <em>not</em> invoked, but the new handler is scheduled in its place.</div></li>
12093      * </ul><br>
12094      * <p>
12095      * <b>Combining Options</b><br>
12096      * In the following examples, the shorthand form {@link #on} is used rather than the more verbose
12097      * addListener.  The two are equivalent.  Using the options argument, it is possible to combine different
12098      * types of listeners:<br>
12099      * <br>
12100      * A delayed, one-time listener that auto stops the event and adds a custom argument (forumId) to the
12101      * options object. The options object is available as the third parameter in the handler function.<div style="margin: 5px 20px 20px;">
12102      * Code:<pre><code>
12103 el.on('click', this.onClick, this, {
12104     single: true,
12105     delay: 100,
12106     stopEvent : true,
12107     forumId: 4
12108 });</code></pre></p>
12109      * <p>
12110      * <b>Attaching multiple handlers in 1 call</b><br>
12111      * The method also allows for a single argument to be passed which is a config object containing properties
12112      * which specify multiple handlers.</p>
12113      * <p>
12114      * Code:<pre><code>
12115 el.on({
12116     'click' : {
12117         fn: this.onClick,
12118         scope: this,
12119         delay: 100
12120     },
12121     'mouseover' : {
12122         fn: this.onMouseOver,
12123         scope: this
12124     },
12125     'mouseout' : {
12126         fn: this.onMouseOut,
12127         scope: this
12128     }
12129 });</code></pre>
12130      * <p>
12131      * Or a shorthand syntax:<br>
12132      * Code:<pre><code></p>
12133 el.on({
12134     'click' : this.onClick,
12135     'mouseover' : this.onMouseOver,
12136     'mouseout' : this.onMouseOut,
12137     scope: this
12138 });
12139      * </code></pre></p>
12140      * <p><b>delegate</b></p>
12141      * <p>This is a configuration option that you can pass along when registering a handler for
12142      * an event to assist with event delegation. Event delegation is a technique that is used to
12143      * reduce memory consumption and prevent exposure to memory-leaks. By registering an event
12144      * for a container element as opposed to each element within a container. By setting this
12145      * configuration option to a simple selector, the target element will be filtered to look for
12146      * a descendant of the target.
12147      * For example:<pre><code>
12148 // using this markup:
12149 &lt;div id='elId'>
12150     &lt;p id='p1'>paragraph one&lt;/p>
12151     &lt;p id='p2' class='clickable'>paragraph two&lt;/p>
12152     &lt;p id='p3'>paragraph three&lt;/p>
12153 &lt;/div>
12154 // utilize event delegation to registering just one handler on the container element:
12155 el = Ext.get('elId');
12156 el.on(
12157     'click',
12158     function(e,t) {
12159         // handle click
12160         console.info(t.id); // 'p2'
12161     },
12162     this,
12163     {
12164         // filter the target element to be a descendant with the class 'clickable'
12165         delegate: '.clickable'
12166     }
12167 );
12168      * </code></pre></p>
12169      * @return {Ext.core.Element} this
12170      */
12171         addListener: function(eventName, fn, scope, options) {
12172             Ext.EventManager.on(this.dom, eventName, fn, scope || this, options);
12173             return this;
12174         },
12175
12176         /**
12177      * Removes an event handler from this element.  The shorthand version {@link #un} is equivalent.
12178      * <b>Note</b>: if a <i>scope</i> was explicitly specified when {@link #addListener adding} the
12179      * listener, the same scope must be specified here.
12180      * Example:
12181      * <pre><code>
12182 el.removeListener('click', this.handlerFn);
12183 // or
12184 el.un('click', this.handlerFn);
12185 </code></pre>
12186      * @param {String} eventName The name of the event from which to remove the handler.
12187      * @param {Function} fn The handler function to remove. <b>This must be a reference to the function passed into the {@link #addListener} call.</b>
12188      * @param {Object} scope If a scope (<b><code>this</code></b> reference) was specified when the listener was added,
12189      * then this must refer to the same object.
12190      * @return {Ext.core.Element} this
12191      */
12192         removeListener: function(eventName, fn, scope) {
12193             Ext.EventManager.un(this.dom, eventName, fn, scope || this);
12194             return this;
12195         },
12196
12197         /**
12198      * Removes all previous added listeners from this element
12199      * @return {Ext.core.Element} this
12200      */
12201         removeAllListeners: function() {
12202             Ext.EventManager.removeAll(this.dom);
12203             return this;
12204         },
12205
12206         /**
12207          * Recursively removes all previous added listeners from this element and its children
12208          * @return {Ext.core.Element} this
12209          */
12210         purgeAllListeners: function() {
12211             Ext.EventManager.purgeElement(this);
12212             return this;
12213         },
12214
12215         /**
12216          * @private Test if size has a unit, otherwise appends the passed unit string, or the default for this Element.
12217          * @param size {Mixed} The size to set
12218          * @param units {String} The units to append to a numeric size value
12219          */
12220         addUnits: function(size, units) {
12221
12222             // Most common case first: Size is set to a number
12223             if (Ext.isNumber(size)) {
12224                 return size + (units || this.defaultUnit || 'px');
12225             }
12226
12227             // Size set to a value which means "auto"
12228             if (size === "" || size == "auto" || size === undefined || size === null) {
12229                 return size || '';
12230             }
12231
12232             // Otherwise, warn if it's not a valid CSS measurement
12233             if (!unitPattern.test(size)) {
12234                 if (Ext.isDefined(Ext.global.console)) {
12235                     Ext.global.console.warn("Warning, size detected as NaN on Element.addUnits.");
12236                 }
12237                 return size || '';
12238             }
12239             return size;
12240         },
12241
12242         /**
12243          * Tests various css rules/browsers to determine if this element uses a border box
12244          * @return {Boolean}
12245          */
12246         isBorderBox: function() {
12247             return Ext.isBorderBox || noBoxAdjust[(this.dom.tagName || "").toLowerCase()];
12248         },
12249
12250         /**
12251          * <p>Removes this element's dom reference.  Note that event and cache removal is handled at {@link Ext#removeNode Ext.removeNode}</p>
12252          */
12253         remove: function() {
12254             var me = this,
12255             dom = me.dom;
12256
12257             if (dom) {
12258                 delete me.dom;
12259                 Ext.removeNode(dom);
12260             }
12261         },
12262
12263         /**
12264          * Sets up event handlers to call the passed functions when the mouse is moved into and out of the Element.
12265          * @param {Function} overFn The function to call when the mouse enters the Element.
12266          * @param {Function} outFn The function to call when the mouse leaves the Element.
12267          * @param {Object} scope (optional) The scope (<code>this</code> reference) in which the functions are executed. Defaults to the Element's DOM element.
12268          * @param {Object} options (optional) Options for the listener. See {@link Ext.util.Observable#addListener the <tt>options</tt> parameter}.
12269          * @return {Ext.core.Element} this
12270          */
12271         hover: function(overFn, outFn, scope, options) {
12272             var me = this;
12273             me.on('mouseenter', overFn, scope || me.dom, options);
12274             me.on('mouseleave', outFn, scope || me.dom, options);
12275             return me;
12276         },
12277
12278         /**
12279          * Returns true if this element is an ancestor of the passed element
12280          * @param {HTMLElement/String} el The element to check
12281          * @return {Boolean} True if this element is an ancestor of el, else false
12282          */
12283         contains: function(el) {
12284             return ! el ? false: Ext.core.Element.isAncestor(this.dom, el.dom ? el.dom: el);
12285         },
12286
12287         /**
12288          * Returns the value of a namespaced attribute from the element's underlying DOM node.
12289          * @param {String} namespace The namespace in which to look for the attribute
12290          * @param {String} name The attribute name
12291          * @return {String} The attribute value
12292          * @deprecated
12293          */
12294         getAttributeNS: function(ns, name) {
12295             return this.getAttribute(name, ns);
12296         },
12297
12298         /**
12299          * Returns the value of an attribute from the element's underlying DOM node.
12300          * @param {String} name The attribute name
12301          * @param {String} namespace (optional) The namespace in which to look for the attribute
12302          * @return {String} The attribute value
12303          */
12304         getAttribute: (Ext.isIE && !(Ext.isIE9 && document.documentMode === 9)) ?
12305         function(name, ns) {
12306             var d = this.dom,
12307             type;
12308             if(ns) {
12309                 type = typeof d[ns + ":" + name];
12310                 if (type != 'undefined' && type != 'unknown') {
12311                     return d[ns + ":" + name] || null;
12312                 }
12313                 return null;
12314             }
12315             if (name === "for") {
12316                 name = "htmlFor";
12317             }
12318             return d[name] || null;
12319         }: function(name, ns) {
12320             var d = this.dom;
12321             if (ns) {
12322                return d.getAttributeNS(ns, name) || d.getAttribute(ns + ":" + name);
12323             }
12324             return  d.getAttribute(name) || d[name] || null;
12325         },
12326
12327         /**
12328          * Update the innerHTML of this element
12329          * @param {String} html The new HTML
12330          * @return {Ext.core.Element} this
12331          */
12332         update: function(html) {
12333             if (this.dom) {
12334                 this.dom.innerHTML = html;
12335             }
12336             return this;
12337         }
12338     };
12339
12340     var ep = El.prototype;
12341
12342     El.addMethods = function(o) {
12343         Ext.apply(ep, o);
12344     };
12345
12346     /**
12347      * Appends an event handler (shorthand for {@link #addListener}).
12348      * @param {String} eventName The name of event to handle.
12349      * @param {Function} fn The handler function the event invokes.
12350      * @param {Object} scope (optional) The scope (<code>this</code> reference) in which the handler function is executed.
12351      * @param {Object} options (optional) An object containing standard {@link #addListener} options
12352      * @member Ext.core.Element
12353      * @method on
12354      */
12355     ep.on = ep.addListener;
12356
12357     /**
12358      * Removes an event handler from this element (see {@link #removeListener} for additional notes).
12359      * @param {String} eventName The name of the event from which to remove the handler.
12360      * @param {Function} fn The handler function to remove. <b>This must be a reference to the function passed into the {@link #addListener} call.</b>
12361      * @param {Object} scope If a scope (<b><code>this</code></b> reference) was specified when the listener was added,
12362      * then this must refer to the same object.
12363      * @return {Ext.core.Element} this
12364      * @member Ext.core.Element
12365      * @method un
12366      */
12367     ep.un = ep.removeListener;
12368
12369     /**
12370      * Removes all previous added listeners from this element
12371      * @return {Ext.core.Element} this
12372      * @member Ext.core.Element
12373      * @method clearListeners
12374      */
12375     ep.clearListeners = ep.removeAllListeners;
12376
12377     /**
12378      * Removes this element's dom reference.  Note that event and cache removal is handled at {@link Ext#removeNode Ext.removeNode}.
12379      * Alias to {@link #remove}.
12380      * @member Ext.core.Element
12381      * @method destroy
12382      */
12383     ep.destroy = ep.remove;
12384
12385     /**
12386      * true to automatically adjust width and height settings for box-model issues (default to true)
12387      */
12388     ep.autoBoxAdjust = true;
12389
12390     // private
12391     var unitPattern = /\d+(px|em|%|en|ex|pt|in|cm|mm|pc)$/i,
12392     docEl;
12393
12394     /**
12395      * Retrieves Ext.core.Element objects.
12396      * <p><b>This method does not retrieve {@link Ext.Component Component}s.</b> This method
12397      * retrieves Ext.core.Element objects which encapsulate DOM elements. To retrieve a Component by
12398      * its ID, use {@link Ext.ComponentManager#get}.</p>
12399      * <p>Uses simple caching to consistently return the same object. Automatically fixes if an
12400      * object was recreated with the same id via AJAX or DOM.</p>
12401      * @param {Mixed} el The id of the node, a DOM Node or an existing Element.
12402      * @return {Element} The Element object (or null if no matching element was found)
12403      * @static
12404      * @member Ext.core.Element
12405      * @method get
12406      */
12407     El.get = function(el) {
12408         var ex,
12409         elm,
12410         id;
12411         if (!el) {
12412             return null;
12413         }
12414         if (typeof el == "string") {
12415             // element id
12416             if (! (elm = DOC.getElementById(el))) {
12417                 return null;
12418             }
12419             if (EC[el] && EC[el].el) {
12420                 ex = EC[el].el;
12421                 ex.dom = elm;
12422             } else {
12423                 ex = El.addToCache(new El(elm));
12424             }
12425             return ex;
12426         } else if (el.tagName) {
12427             // dom element
12428             if (! (id = el.id)) {
12429                 id = Ext.id(el);
12430             }
12431             if (EC[id] && EC[id].el) {
12432                 ex = EC[id].el;
12433                 ex.dom = el;
12434             } else {
12435                 ex = El.addToCache(new El(el));
12436             }
12437             return ex;
12438         } else if (el instanceof El) {
12439             if (el != docEl) {
12440                 // refresh dom element in case no longer valid,
12441                 // catch case where it hasn't been appended
12442                 // If an el instance is passed, don't pass to getElementById without some kind of id
12443                 if (Ext.isIE && (el.id == undefined || el.id == '')) {
12444                     el.dom = el.dom;
12445                 } else {
12446                     el.dom = DOC.getElementById(el.id) || el.dom;
12447                 }
12448             }
12449             return el;
12450         } else if (el.isComposite) {
12451             return el;
12452         } else if (Ext.isArray(el)) {
12453             return El.select(el);
12454         } else if (el == DOC) {
12455             // create a bogus element object representing the document object
12456             if (!docEl) {
12457                 var f = function() {};
12458                 f.prototype = El.prototype;
12459                 docEl = new f();
12460                 docEl.dom = DOC;
12461             }
12462             return docEl;
12463         }
12464         return null;
12465     };
12466
12467     El.addToCache = function(el, id) {
12468         if (el) {
12469             id = id || el.id;
12470             EC[id] = {
12471                 el: el,
12472                 data: {},
12473                 events: {}
12474             };
12475         }
12476         return el;
12477     };
12478
12479     // private method for getting and setting element data
12480     El.data = function(el, key, value) {
12481         el = El.get(el);
12482         if (!el) {
12483             return null;
12484         }
12485         var c = EC[el.id].data;
12486         if (arguments.length == 2) {
12487             return c[key];
12488         } else {
12489             return (c[key] = value);
12490         }
12491     };
12492
12493     // private
12494     // Garbage collection - uncache elements/purge listeners on orphaned elements
12495     // so we don't hold a reference and cause the browser to retain them
12496     function garbageCollect() {
12497         if (!Ext.enableGarbageCollector) {
12498             clearInterval(El.collectorThreadId);
12499         } else {
12500             var eid,
12501             el,
12502             d,
12503             o;
12504
12505             for (eid in EC) {
12506                 if (!EC.hasOwnProperty(eid)) {
12507                     continue;
12508                 }
12509                 o = EC[eid];
12510                 if (o.skipGarbageCollection) {
12511                     continue;
12512                 }
12513                 el = o.el;
12514                 d = el.dom;
12515                 // -------------------------------------------------------
12516                 // Determining what is garbage:
12517                 // -------------------------------------------------------
12518                 // !d
12519                 // dom node is null, definitely garbage
12520                 // -------------------------------------------------------
12521                 // !d.parentNode
12522                 // no parentNode == direct orphan, definitely garbage
12523                 // -------------------------------------------------------
12524                 // !d.offsetParent && !document.getElementById(eid)
12525                 // display none elements have no offsetParent so we will
12526                 // also try to look it up by it's id. However, check
12527                 // offsetParent first so we don't do unneeded lookups.
12528                 // This enables collection of elements that are not orphans
12529                 // directly, but somewhere up the line they have an orphan
12530                 // parent.
12531                 // -------------------------------------------------------
12532                 if (!d || !d.parentNode || (!d.offsetParent && !DOC.getElementById(eid))) {
12533                     if (d && Ext.enableListenerCollection) {
12534                         Ext.EventManager.removeAll(d);
12535                     }
12536                     delete EC[eid];
12537                 }
12538             }
12539             // Cleanup IE Object leaks
12540             if (Ext.isIE) {
12541                 var t = {};
12542                 for (eid in EC) {
12543                     if (!EC.hasOwnProperty(eid)) {
12544                         continue;
12545                     }
12546                     t[eid] = EC[eid];
12547                 }
12548                 EC = Ext.cache = t;
12549             }
12550         }
12551     }
12552     El.collectorThreadId = setInterval(garbageCollect, 30000);
12553
12554     var flyFn = function() {};
12555     flyFn.prototype = El.prototype;
12556
12557     // dom is optional
12558     El.Flyweight = function(dom) {
12559         this.dom = dom;
12560     };
12561
12562     El.Flyweight.prototype = new flyFn();
12563     El.Flyweight.prototype.isFlyweight = true;
12564     El._flyweights = {};
12565
12566     /**
12567      * <p>Gets the globally shared flyweight Element, with the passed node as the active element. Do not store a reference to this element -
12568      * the dom node can be overwritten by other code. Shorthand of {@link Ext.core.Element#fly}</p>
12569      * <p>Use this to make one-time references to DOM elements which are not going to be accessed again either by
12570      * application code, or by Ext's classes. If accessing an element which will be processed regularly, then {@link Ext#get Ext.get}
12571      * will be more appropriate to take advantage of the caching provided by the Ext.core.Element class.</p>
12572      * @param {String/HTMLElement} el The dom node or id
12573      * @param {String} named (optional) Allows for creation of named reusable flyweights to prevent conflicts
12574      * (e.g. internally Ext uses "_global")
12575      * @return {Element} The shared Element object (or null if no matching element was found)
12576      * @member Ext.core.Element
12577      * @method fly
12578      */
12579     El.fly = function(el, named) {
12580         var ret = null;
12581         named = named || '_global';
12582         el = Ext.getDom(el);
12583         if (el) {
12584             (El._flyweights[named] = El._flyweights[named] || new El.Flyweight()).dom = el;
12585             ret = El._flyweights[named];
12586         }
12587         return ret;
12588     };
12589
12590     /**
12591      * Retrieves Ext.core.Element objects.
12592      * <p><b>This method does not retrieve {@link Ext.Component Component}s.</b> This method
12593      * retrieves Ext.core.Element objects which encapsulate DOM elements. To retrieve a Component by
12594      * its ID, use {@link Ext.ComponentManager#get}.</p>
12595      * <p>Uses simple caching to consistently return the same object. Automatically fixes if an
12596      * object was recreated with the same id via AJAX or DOM.</p>
12597      * Shorthand of {@link Ext.core.Element#get}
12598      * @param {Mixed} el The id of the node, a DOM Node or an existing Element.
12599      * @return {Element} The Element object (or null if no matching element was found)
12600      * @member Ext
12601      * @method get
12602      */
12603     Ext.get = El.get;
12604
12605     /**
12606      * <p>Gets the globally shared flyweight Element, with the passed node as the active element. Do not store a reference to this element -
12607      * the dom node can be overwritten by other code. Shorthand of {@link Ext.core.Element#fly}</p>
12608      * <p>Use this to make one-time references to DOM elements which are not going to be accessed again either by
12609      * application code, or by Ext's classes. If accessing an element which will be processed regularly, then {@link Ext#get Ext.get}
12610      * will be more appropriate to take advantage of the caching provided by the Ext.core.Element class.</p>
12611      * @param {String/HTMLElement} el The dom node or id
12612      * @param {String} named (optional) Allows for creation of named reusable flyweights to prevent conflicts
12613      * (e.g. internally Ext uses "_global")
12614      * @return {Element} The shared Element object (or null if no matching element was found)
12615      * @member Ext
12616      * @method fly
12617      */
12618     Ext.fly = El.fly;
12619
12620     // speedy lookup for elements never to box adjust
12621     var noBoxAdjust = Ext.isStrict ? {
12622         select: 1
12623     }: {
12624         input: 1,
12625         select: 1,
12626         textarea: 1
12627     };
12628     if (Ext.isIE || Ext.isGecko) {
12629         noBoxAdjust['button'] = 1;
12630     }
12631 })();
12632
12633 /**
12634  * @class Ext.core.Element
12635  */
12636 Ext.core.Element.addMethods({
12637     /**
12638      * 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)
12639      * @param {String} selector The simple selector to test
12640      * @param {Number/Mixed} maxDepth (optional) The max depth to search as a number or element (defaults to 50 || document.body)
12641      * @param {Boolean} returnEl (optional) True to return a Ext.core.Element object instead of DOM node
12642      * @return {HTMLElement} The matching DOM node (or null if no match was found)
12643      */
12644     findParent : function(simpleSelector, maxDepth, returnEl) {
12645         var p = this.dom,
12646             b = document.body,
12647             depth = 0,
12648             stopEl;
12649
12650         maxDepth = maxDepth || 50;
12651         if (isNaN(maxDepth)) {
12652             stopEl = Ext.getDom(maxDepth);
12653             maxDepth = Number.MAX_VALUE;
12654         }
12655         while (p && p.nodeType == 1 && depth < maxDepth && p != b && p != stopEl) {
12656             if (Ext.DomQuery.is(p, simpleSelector)) {
12657                 return returnEl ? Ext.get(p) : p;
12658             }
12659             depth++;
12660             p = p.parentNode;
12661         }
12662         return null;
12663     },
12664     
12665     /**
12666      * Looks at parent nodes for a match of the passed simple selector (e.g. div.some-class or span:first-child)
12667      * @param {String} selector The simple selector to test
12668      * @param {Number/Mixed} maxDepth (optional) The max depth to
12669             search as a number or element (defaults to 10 || document.body)
12670      * @param {Boolean} returnEl (optional) True to return a Ext.core.Element object instead of DOM node
12671      * @return {HTMLElement} The matching DOM node (or null if no match was found)
12672      */
12673     findParentNode : function(simpleSelector, maxDepth, returnEl) {
12674         var p = Ext.fly(this.dom.parentNode, '_internal');
12675         return p ? p.findParent(simpleSelector, maxDepth, returnEl) : null;
12676     },
12677
12678     /**
12679      * Walks up the dom looking for a parent node that matches the passed simple selector (e.g. div.some-class or span:first-child).
12680      * This is a shortcut for findParentNode() that always returns an Ext.core.Element.
12681      * @param {String} selector The simple selector to test
12682      * @param {Number/Mixed} maxDepth (optional) The max depth to
12683             search as a number or element (defaults to 10 || document.body)
12684      * @return {Ext.core.Element} The matching DOM node (or null if no match was found)
12685      */
12686     up : function(simpleSelector, maxDepth) {
12687         return this.findParentNode(simpleSelector, maxDepth, true);
12688     },
12689
12690     /**
12691      * Creates a {@link Ext.CompositeElement} for child nodes based on the passed CSS selector (the selector should not contain an id).
12692      * @param {String} selector The CSS selector
12693      * @return {CompositeElement/CompositeElement} The composite element
12694      */
12695     select : function(selector) {
12696         return Ext.core.Element.select(selector, false,  this.dom);
12697     },
12698
12699     /**
12700      * Selects child nodes based on the passed CSS selector (the selector should not contain an id).
12701      * @param {String} selector The CSS selector
12702      * @return {Array} An array of the matched nodes
12703      */
12704     query : function(selector) {
12705         return Ext.DomQuery.select(selector, this.dom);
12706     },
12707
12708     /**
12709      * Selects a single child at any depth below this element based on the passed CSS selector (the selector should not contain an id).
12710      * @param {String} selector The CSS selector
12711      * @param {Boolean} returnDom (optional) True to return the DOM node instead of Ext.core.Element (defaults to false)
12712      * @return {HTMLElement/Ext.core.Element} The child Ext.core.Element (or DOM node if returnDom = true)
12713      */
12714     down : function(selector, returnDom) {
12715         var n = Ext.DomQuery.selectNode(selector, this.dom);
12716         return returnDom ? n : Ext.get(n);
12717     },
12718
12719     /**
12720      * Selects a single *direct* child based on the passed CSS selector (the selector should not contain an id).
12721      * @param {String} selector The CSS selector
12722      * @param {Boolean} returnDom (optional) True to return the DOM node instead of Ext.core.Element (defaults to false)
12723      * @return {HTMLElement/Ext.core.Element} The child Ext.core.Element (or DOM node if returnDom = true)
12724      */
12725     child : function(selector, returnDom) {
12726         var node,
12727             me = this,
12728             id;
12729         id = Ext.get(me).id;
12730         // Escape . or :
12731         id = id.replace(/[\.:]/g, "\\$0");
12732         node = Ext.DomQuery.selectNode('#' + id + " > " + selector, me.dom);
12733         return returnDom ? node : Ext.get(node);
12734     },
12735
12736      /**
12737      * Gets the parent node for this element, optionally chaining up trying to match a selector
12738      * @param {String} selector (optional) Find a parent node that matches the passed simple selector
12739      * @param {Boolean} returnDom (optional) True to return a raw dom node instead of an Ext.core.Element
12740      * @return {Ext.core.Element/HTMLElement} The parent node or null
12741      */
12742     parent : function(selector, returnDom) {
12743         return this.matchNode('parentNode', 'parentNode', selector, returnDom);
12744     },
12745
12746      /**
12747      * Gets the next sibling, skipping text nodes
12748      * @param {String} selector (optional) Find the next sibling that matches the passed simple selector
12749      * @param {Boolean} returnDom (optional) True to return a raw dom node instead of an Ext.core.Element
12750      * @return {Ext.core.Element/HTMLElement} The next sibling or null
12751      */
12752     next : function(selector, returnDom) {
12753         return this.matchNode('nextSibling', 'nextSibling', selector, returnDom);
12754     },
12755
12756     /**
12757      * Gets the previous sibling, skipping text nodes
12758      * @param {String} selector (optional) Find the previous sibling that matches the passed simple selector
12759      * @param {Boolean} returnDom (optional) True to return a raw dom node instead of an Ext.core.Element
12760      * @return {Ext.core.Element/HTMLElement} The previous sibling or null
12761      */
12762     prev : function(selector, returnDom) {
12763         return this.matchNode('previousSibling', 'previousSibling', selector, returnDom);
12764     },
12765
12766
12767     /**
12768      * Gets the first child, skipping text nodes
12769      * @param {String} selector (optional) Find the next sibling that matches the passed simple selector
12770      * @param {Boolean} returnDom (optional) True to return a raw dom node instead of an Ext.core.Element
12771      * @return {Ext.core.Element/HTMLElement} The first child or null
12772      */
12773     first : function(selector, returnDom) {
12774         return this.matchNode('nextSibling', 'firstChild', selector, returnDom);
12775     },
12776
12777     /**
12778      * Gets the last child, skipping text nodes
12779      * @param {String} selector (optional) Find the previous sibling that matches the passed simple selector
12780      * @param {Boolean} returnDom (optional) True to return a raw dom node instead of an Ext.core.Element
12781      * @return {Ext.core.Element/HTMLElement} The last child or null
12782      */
12783     last : function(selector, returnDom) {
12784         return this.matchNode('previousSibling', 'lastChild', selector, returnDom);
12785     },
12786
12787     matchNode : function(dir, start, selector, returnDom) {
12788         if (!this.dom) {
12789             return null;
12790         }
12791         
12792         var n = this.dom[start];
12793         while (n) {
12794             if (n.nodeType == 1 && (!selector || Ext.DomQuery.is(n, selector))) {
12795                 return !returnDom ? Ext.get(n) : n;
12796             }
12797             n = n[dir];
12798         }
12799         return null;
12800     }
12801 });
12802
12803 /**
12804  * @class Ext.core.Element
12805  */
12806 Ext.core.Element.addMethods({
12807     /**
12808      * Appends the passed element(s) to this element
12809      * @param {String/HTMLElement/Array/Element/CompositeElement} el
12810      * @return {Ext.core.Element} this
12811      */
12812     appendChild : function(el) {
12813         return Ext.get(el).appendTo(this);
12814     },
12815
12816     /**
12817      * Appends this element to the passed element
12818      * @param {Mixed} el The new parent element
12819      * @return {Ext.core.Element} this
12820      */
12821     appendTo : function(el) {
12822         Ext.getDom(el).appendChild(this.dom);
12823         return this;
12824     },
12825
12826     /**
12827      * Inserts this element before the passed element in the DOM
12828      * @param {Mixed} el The element before which this element will be inserted
12829      * @return {Ext.core.Element} this
12830      */
12831     insertBefore : function(el) {
12832         el = Ext.getDom(el);
12833         el.parentNode.insertBefore(this.dom, el);
12834         return this;
12835     },
12836
12837     /**
12838      * Inserts this element after the passed element in the DOM
12839      * @param {Mixed} el The element to insert after
12840      * @return {Ext.core.Element} this
12841      */
12842     insertAfter : function(el) {
12843         el = Ext.getDom(el);
12844         el.parentNode.insertBefore(this.dom, el.nextSibling);
12845         return this;
12846     },
12847
12848     /**
12849      * Inserts (or creates) an element (or DomHelper config) as the first child of this element
12850      * @param {Mixed/Object} el The id or element to insert or a DomHelper config to create and insert
12851      * @return {Ext.core.Element} The new child
12852      */
12853     insertFirst : function(el, returnDom) {
12854         el = el || {};
12855         if (el.nodeType || el.dom || typeof el == 'string') { // element
12856             el = Ext.getDom(el);
12857             this.dom.insertBefore(el, this.dom.firstChild);
12858             return !returnDom ? Ext.get(el) : el;
12859         }
12860         else { // dh config
12861             return this.createChild(el, this.dom.firstChild, returnDom);
12862         }
12863     },
12864
12865     /**
12866      * Inserts (or creates) the passed element (or DomHelper config) as a sibling of this element
12867      * @param {Mixed/Object/Array} el The id, element to insert or a DomHelper config to create and insert *or* an array of any of those.
12868      * @param {String} where (optional) 'before' or 'after' defaults to before
12869      * @param {Boolean} returnDom (optional) True to return the .;ll;l,raw DOM element instead of Ext.core.Element
12870      * @return {Ext.core.Element} The inserted Element. If an array is passed, the last inserted element is returned.
12871      */
12872     insertSibling: function(el, where, returnDom){
12873         var me = this, rt,
12874         isAfter = (where || 'before').toLowerCase() == 'after',
12875         insertEl;
12876
12877         if(Ext.isArray(el)){
12878             insertEl = me;
12879             Ext.each(el, function(e) {
12880                 rt = Ext.fly(insertEl, '_internal').insertSibling(e, where, returnDom);
12881                 if(isAfter){
12882                     insertEl = rt;
12883                 }
12884             });
12885             return rt;
12886         }
12887
12888         el = el || {};
12889
12890         if(el.nodeType || el.dom){
12891             rt = me.dom.parentNode.insertBefore(Ext.getDom(el), isAfter ? me.dom.nextSibling : me.dom);
12892             if (!returnDom) {
12893                 rt = Ext.get(rt);
12894             }
12895         }else{
12896             if (isAfter && !me.dom.nextSibling) {
12897                 rt = Ext.core.DomHelper.append(me.dom.parentNode, el, !returnDom);
12898             } else {
12899                 rt = Ext.core.DomHelper[isAfter ? 'insertAfter' : 'insertBefore'](me.dom, el, !returnDom);
12900             }
12901         }
12902         return rt;
12903     },
12904
12905     /**
12906      * Replaces the passed element with this element
12907      * @param {Mixed} el The element to replace
12908      * @return {Ext.core.Element} this
12909      */
12910     replace : function(el) {
12911         el = Ext.get(el);
12912         this.insertBefore(el);
12913         el.remove();
12914         return this;
12915     },
12916     
12917     /**
12918      * Replaces this element with the passed element
12919      * @param {Mixed/Object} el The new element or a DomHelper config of an element to create
12920      * @return {Ext.core.Element} this
12921      */
12922     replaceWith: function(el){
12923         var me = this;
12924             
12925         if(el.nodeType || el.dom || typeof el == 'string'){
12926             el = Ext.get(el);
12927             me.dom.parentNode.insertBefore(el, me.dom);
12928         }else{
12929             el = Ext.core.DomHelper.insertBefore(me.dom, el);
12930         }
12931         
12932         delete Ext.cache[me.id];
12933         Ext.removeNode(me.dom);      
12934         me.id = Ext.id(me.dom = el);
12935         Ext.core.Element.addToCache(me.isFlyweight ? new Ext.core.Element(me.dom) : me);     
12936         return me;
12937     },
12938     
12939     /**
12940      * Creates the passed DomHelper config and appends it to this element or optionally inserts it before the passed child element.
12941      * @param {Object} config DomHelper element config object.  If no tag is specified (e.g., {tag:'input'}) then a div will be
12942      * automatically generated with the specified attributes.
12943      * @param {HTMLElement} insertBefore (optional) a child element of this element
12944      * @param {Boolean} returnDom (optional) true to return the dom node instead of creating an Element
12945      * @return {Ext.core.Element} The new child element
12946      */
12947     createChild : function(config, insertBefore, returnDom) {
12948         config = config || {tag:'div'};
12949         if (insertBefore) {
12950             return Ext.core.DomHelper.insertBefore(insertBefore, config, returnDom !== true);
12951         }
12952         else {
12953             return Ext.core.DomHelper[!this.dom.firstChild ? 'insertFirst' : 'append'](this.dom, config,  returnDom !== true);
12954         }
12955     },
12956
12957     /**
12958      * Creates and wraps this element with another element
12959      * @param {Object} config (optional) DomHelper element config object for the wrapper element or null for an empty div
12960      * @param {Boolean} returnDom (optional) True to return the raw DOM element instead of Ext.core.Element
12961      * @return {HTMLElement/Element} The newly created wrapper element
12962      */
12963     wrap : function(config, returnDom) {
12964         var newEl = Ext.core.DomHelper.insertBefore(this.dom, config || {tag: "div"}, !returnDom),
12965             d = newEl.dom || newEl;
12966
12967         d.appendChild(this.dom);
12968         return newEl;
12969     },
12970
12971     /**
12972      * Inserts an html fragment into this element
12973      * @param {String} where Where to insert the html in relation to this element - beforeBegin, afterBegin, beforeEnd, afterEnd.
12974      * @param {String} html The HTML fragment
12975      * @param {Boolean} returnEl (optional) True to return an Ext.core.Element (defaults to false)
12976      * @return {HTMLElement/Ext.core.Element} The inserted node (or nearest related if more than 1 inserted)
12977      */
12978     insertHtml : function(where, html, returnEl) {
12979         var el = Ext.core.DomHelper.insertHtml(where, this.dom, html);
12980         return returnEl ? Ext.get(el) : el;
12981     }
12982 });
12983
12984 /**
12985  * @class Ext.core.Element
12986  */
12987 (function(){
12988     Ext.core.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>';
12989     // local style camelizing for speed
12990     var supports = Ext.supports,
12991         view = document.defaultView,
12992         opacityRe = /alpha\(opacity=(.*)\)/i,
12993         trimRe = /^\s+|\s+$/g,
12994         spacesRe = /\s+/,
12995         wordsRe = /\w/g,
12996         adjustDirect2DTableRe = /table-row|table-.*-group/,
12997         INTERNAL = '_internal',
12998         PADDING = 'padding',
12999         MARGIN = 'margin',
13000         BORDER = 'border',
13001         LEFT = '-left',
13002         RIGHT = '-right',
13003         TOP = '-top',
13004         BOTTOM = '-bottom',
13005         WIDTH = '-width',
13006         MATH = Math,
13007         HIDDEN = 'hidden',
13008         ISCLIPPED = 'isClipped',
13009         OVERFLOW = 'overflow',
13010         OVERFLOWX = 'overflow-x',
13011         OVERFLOWY = 'overflow-y',
13012         ORIGINALCLIP = 'originalClip',
13013         // special markup used throughout Ext when box wrapping elements
13014         borders = {l: BORDER + LEFT + WIDTH, r: BORDER + RIGHT + WIDTH, t: BORDER + TOP + WIDTH, b: BORDER + BOTTOM + WIDTH},
13015         paddings = {l: PADDING + LEFT, r: PADDING + RIGHT, t: PADDING + TOP, b: PADDING + BOTTOM},
13016         margins = {l: MARGIN + LEFT, r: MARGIN + RIGHT, t: MARGIN + TOP, b: MARGIN + BOTTOM},
13017         data = Ext.core.Element.data;
13018
13019     Ext.override(Ext.core.Element, {
13020         
13021         /**
13022          * TODO: Look at this
13023          */
13024         // private  ==> used by Fx
13025         adjustWidth : function(width) {
13026             var me = this,
13027                 isNum = (typeof width == 'number');
13028                 
13029             if(isNum && me.autoBoxAdjust && !me.isBorderBox()){
13030                width -= (me.getBorderWidth("lr") + me.getPadding("lr"));
13031             }
13032             return (isNum && width < 0) ? 0 : width;
13033         },
13034
13035         // private   ==> used by Fx
13036         adjustHeight : function(height) {
13037             var me = this,
13038                 isNum = (typeof height == "number");
13039                 
13040             if(isNum && me.autoBoxAdjust && !me.isBorderBox()){
13041                height -= (me.getBorderWidth("tb") + me.getPadding("tb"));
13042             }
13043             return (isNum && height < 0) ? 0 : height;
13044         },
13045
13046
13047         /**
13048          * Adds one or more CSS classes to the element. Duplicate classes are automatically filtered out.
13049          * @param {String/Array} className The CSS classes to add separated by space, or an array of classes
13050          * @return {Ext.core.Element} this
13051          */
13052         addCls : function(className){
13053             var me = this,
13054                 cls = [],
13055                 space = ((me.dom.className.replace(trimRe, '') == '') ? "" : " "),
13056                 i, len, v;
13057             if (!Ext.isDefined(className)) {
13058                 return me;
13059             }
13060             // Separate case is for speed
13061             if (!Ext.isArray(className)) {
13062                 if (typeof className === 'string') {
13063                     className = className.replace(trimRe, '').split(spacesRe);
13064                     if (className.length === 1) {
13065                         className = className[0];
13066                         if (!me.hasCls(className)) {
13067                             me.dom.className += space + className;
13068                         }
13069                     } else {
13070                         this.addCls(className);
13071                     }
13072                 }
13073             } else {
13074                 for (i = 0, len = className.length; i < len; i++) {
13075                     v = className[i];
13076                     if (typeof v == 'string' && (' ' + me.dom.className + ' ').indexOf(' ' + v + ' ') == -1) {
13077                         cls.push(v);
13078                     }
13079                 }
13080                 if (cls.length) {
13081                     me.dom.className += space + cls.join(" ");
13082                 }
13083             }
13084             return me;
13085         },
13086
13087         /**
13088          * Removes one or more CSS classes from the element.
13089          * @param {String/Array} className The CSS classes to remove separated by space, or an array of classes
13090          * @return {Ext.core.Element} this
13091          */
13092         removeCls : function(className){
13093             var me = this,
13094                 i, idx, len, cls, elClasses;
13095             if (!Ext.isDefined(className)) {
13096                 return me;
13097             }
13098             if (!Ext.isArray(className)){
13099                 className = className.replace(trimRe, '').split(spacesRe);
13100             }
13101             if (me.dom && me.dom.className) {
13102                 elClasses = me.dom.className.replace(trimRe, '').split(spacesRe);
13103                 for (i = 0, len = className.length; i < len; i++) {
13104                     cls = className[i];
13105                     if (typeof cls == 'string') {
13106                         cls = cls.replace(trimRe, '');
13107                         idx = Ext.Array.indexOf(elClasses, cls);
13108                         if (idx != -1) {
13109                             elClasses.splice(idx, 1);
13110                         }
13111                     }
13112                 }
13113                 me.dom.className = elClasses.join(" ");
13114             }
13115             return me;
13116         },
13117
13118         /**
13119          * Adds one or more CSS classes to this element and removes the same class(es) from all siblings.
13120          * @param {String/Array} className The CSS class to add, or an array of classes
13121          * @return {Ext.core.Element} this
13122          */
13123         radioCls : function(className){
13124             var cn = this.dom.parentNode.childNodes,
13125                 v, i, len;
13126             className = Ext.isArray(className) ? className : [className];
13127             for (i = 0, len = cn.length; i < len; i++) {
13128                 v = cn[i];
13129                 if (v && v.nodeType == 1) {
13130                     Ext.fly(v, '_internal').removeCls(className);
13131                 }
13132             }
13133             return this.addCls(className);
13134         },
13135
13136         /**
13137          * Toggles the specified CSS class on this element (removes it if it already exists, otherwise adds it).
13138          * @param {String} className The CSS class to toggle
13139          * @return {Ext.core.Element} this
13140          */
13141         toggleCls : Ext.supports.ClassList ?
13142             function(className) {
13143                 this.dom.classList.toggle(Ext.String.trim(className));
13144                 return this;
13145             } :
13146             function(className) {
13147                 return this.hasCls(className) ? this.removeCls(className) : this.addCls(className);
13148             },
13149
13150         /**
13151          * Checks if the specified CSS class exists on this element's DOM node.
13152          * @param {String} className The CSS class to check for
13153          * @return {Boolean} True if the class exists, else false
13154          */
13155         hasCls : Ext.supports.ClassList ?
13156             function(className) {
13157                 if (!className) {
13158                     return false;
13159                 }
13160                 className = className.split(spacesRe);
13161                 var ln = className.length,
13162                     i = 0;
13163                 for (; i < ln; i++) {
13164                     if (className[i] && this.dom.classList.contains(className[i])) {
13165                         return true;
13166                     }
13167                 }
13168                 return false;
13169             } :
13170             function(className){
13171                 return className && (' ' + this.dom.className + ' ').indexOf(' ' + className + ' ') != -1;
13172             },
13173
13174         /**
13175          * Replaces a CSS class on the element with another.  If the old name does not exist, the new name will simply be added.
13176          * @param {String} oldClassName The CSS class to replace
13177          * @param {String} newClassName The replacement CSS class
13178          * @return {Ext.core.Element} this
13179          */
13180         replaceCls : function(oldClassName, newClassName){
13181             return this.removeCls(oldClassName).addCls(newClassName);
13182         },
13183
13184         isStyle : function(style, val) {
13185             return this.getStyle(style) == val;
13186         },
13187
13188         /**
13189          * Normalizes currentStyle and computedStyle.
13190          * @param {String} property The style property whose value is returned.
13191          * @return {String} The current value of the style property for this element.
13192          */
13193         getStyle : function(){
13194             return view && view.getComputedStyle ?
13195                 function(prop){
13196                     var el = this.dom,
13197                         v, cs, out, display;
13198
13199                     if(el == document){
13200                         return null;
13201                     }
13202                     prop = Ext.core.Element.normalize(prop);
13203                     out = (v = el.style[prop]) ? v :
13204                            (cs = view.getComputedStyle(el, "")) ? cs[prop] : null;
13205                            
13206                     // Ignore cases when the margin is correctly reported as 0, the bug only shows
13207                     // numbers larger.
13208                     if(prop == 'marginRight' && out != '0px' && !supports.RightMargin){
13209                         display = this.getStyle('display');
13210                         el.style.display = 'inline-block';
13211                         out = view.getComputedStyle(el, '').marginRight;
13212                         el.style.display = display;
13213                     }
13214                     
13215                     if(prop == 'backgroundColor' && out == 'rgba(0, 0, 0, 0)' && !supports.TransparentColor){
13216                         out = 'transparent';
13217                     }
13218                     return out;
13219                 } :
13220                 function(prop){
13221                     var el = this.dom,
13222                         m, cs;
13223
13224                     if (el == document) {
13225                         return null;
13226                     }
13227                     
13228                     if (prop == 'opacity') {
13229                         if (el.style.filter.match) {
13230                             m = el.style.filter.match(opacityRe);
13231                             if(m){
13232                                 var fv = parseFloat(m[1]);
13233                                 if(!isNaN(fv)){
13234                                     return fv ? fv / 100 : 0;
13235                                 }
13236                             }
13237                         }
13238                         return 1;
13239                     }
13240                     prop = Ext.core.Element.normalize(prop);
13241                     return el.style[prop] || ((cs = el.currentStyle) ? cs[prop] : null);
13242                 };
13243         }(),
13244
13245         /**
13246          * Return the CSS color for the specified CSS attribute. rgb, 3 digit (like #fff) and valid values
13247          * are convert to standard 6 digit hex color.
13248          * @param {String} attr The css attribute
13249          * @param {String} defaultValue The default value to use when a valid color isn't found
13250          * @param {String} prefix (optional) defaults to #. Use an empty string when working with
13251          * color anims.
13252          */
13253         getColor : function(attr, defaultValue, prefix){
13254             var v = this.getStyle(attr),
13255                 color = prefix || prefix === '' ? prefix : '#',
13256                 h;
13257
13258             if(!v || (/transparent|inherit/.test(v))) {
13259                 return defaultValue;
13260             }
13261             if(/^r/.test(v)){
13262                 Ext.each(v.slice(4, v.length -1).split(','), function(s){
13263                     h = parseInt(s, 10);
13264                     color += (h < 16 ? '0' : '') + h.toString(16);
13265                 });
13266             }else{
13267                 v = v.replace('#', '');
13268                 color += v.length == 3 ? v.replace(/^(\w)(\w)(\w)$/, '$1$1$2$2$3$3') : v;
13269             }
13270             return(color.length > 5 ? color.toLowerCase() : defaultValue);
13271         },
13272
13273         /**
13274          * Wrapper for setting style properties, also takes single object parameter of multiple styles.
13275          * @param {String/Object} property The style property to be set, or an object of multiple styles.
13276          * @param {String} value (optional) The value to apply to the given property, or null if an object was passed.
13277          * @return {Ext.core.Element} this
13278          */
13279         setStyle : function(prop, value){
13280             var me = this,
13281                 tmp, style;
13282
13283             if (!me.dom) {
13284                 return me;
13285             }
13286
13287             if (!Ext.isObject(prop)) {
13288                 tmp = {};
13289                 tmp[prop] = value;
13290                 prop = tmp;
13291             }
13292             for (style in prop) {
13293                 if (prop.hasOwnProperty(style)) {
13294                     value = Ext.value(prop[style], '');
13295                     if (style == 'opacity') {
13296                         me.setOpacity(value);
13297                     }
13298                     else {
13299                         me.dom.style[Ext.core.Element.normalize(style)] = value;
13300                     }
13301                 }
13302             }
13303             return me;
13304         },
13305
13306         /**
13307          * Set the opacity of the element
13308          * @param {Float} opacity The new opacity. 0 = transparent, .5 = 50% visibile, 1 = fully visible, etc
13309          * @param {Boolean/Object} animate (optional) a standard Element animation config object or <tt>true</tt> for
13310          * the default animation (<tt>{duration: .35, easing: 'easeIn'}</tt>)
13311          * @return {Ext.core.Element} this
13312          */
13313         setOpacity: function(opacity, animate) {
13314             var me = this,
13315                 dom = me.dom,
13316                 val,
13317                 style;
13318
13319             if (!me.dom) {
13320                 return me;
13321             }
13322
13323             style = me.dom.style;
13324
13325             if (!animate || !me.anim) {
13326                 if (!Ext.supports.Opacity) {
13327                     opacity = opacity < 1 ? 'alpha(opacity=' + opacity * 100 + ')': '';
13328                     val = style.filter.replace(opacityRe, '').replace(trimRe, '');
13329
13330                     style.zoom = 1;
13331                     style.filter = val + (val.length > 0 ? ' ': '') + opacity;
13332                 }
13333                 else {
13334                     style.opacity = opacity;
13335                 }
13336             }
13337             else {
13338                 if (!Ext.isObject(animate)) {
13339                     animate = {
13340                         duration: 350,
13341                         easing: 'ease-in'
13342                     };
13343                 }
13344                 me.animate(Ext.applyIf({
13345                     to: {
13346                         opacity: opacity
13347                     }
13348                 },
13349                 animate));
13350             }
13351             return me;
13352         },
13353
13354
13355         /**
13356          * Clears any opacity settings from this element. Required in some cases for IE.
13357          * @return {Ext.core.Element} this
13358          */
13359         clearOpacity : function(){
13360             var style = this.dom.style;
13361             if(!Ext.supports.Opacity){
13362                 if(!Ext.isEmpty(style.filter)){
13363                     style.filter = style.filter.replace(opacityRe, '').replace(trimRe, '');
13364                 }
13365             }else{
13366                 style.opacity = style['-moz-opacity'] = style['-khtml-opacity'] = '';
13367             }
13368             return this;
13369         },
13370         
13371         /**
13372          * @private
13373          * Returns 1 if the browser returns the subpixel dimension rounded to the lowest pixel.
13374          * @return {Number} 0 or 1 
13375          */
13376         adjustDirect2DDimension: function(dimension) {
13377             var me = this,
13378                 dom = me.dom,
13379                 display = me.getStyle('display'),
13380                 inlineDisplay = dom.style['display'],
13381                 inlinePosition = dom.style['position'],
13382                 originIndex = dimension === 'width' ? 0 : 1,
13383                 floating;
13384                 
13385             if (display === 'inline') {
13386                 dom.style['display'] = 'inline-block';
13387             }
13388
13389             dom.style['position'] = display.match(adjustDirect2DTableRe) ? 'absolute' : 'static';
13390
13391             // floating will contain digits that appears after the decimal point
13392             // if height or width are set to auto we fallback to msTransformOrigin calculation
13393             floating = (parseFloat(me.getStyle(dimension)) || parseFloat(dom.currentStyle.msTransformOrigin.split(' ')[originIndex]) * 2) % 1;
13394             
13395             dom.style['position'] = inlinePosition;
13396             
13397             if (display === 'inline') {
13398                 dom.style['display'] = inlineDisplay;
13399             }
13400
13401             return floating;
13402         },
13403         
13404         /**
13405          * Returns the offset height of the element
13406          * @param {Boolean} contentHeight (optional) true to get the height minus borders and padding
13407          * @return {Number} The element's height
13408          */
13409         getHeight: function(contentHeight, preciseHeight) {
13410             var me = this,
13411                 dom = me.dom,
13412                 hidden = Ext.isIE && me.isStyle('display', 'none'),
13413                 height, overflow, style, floating;
13414
13415             // IE Quirks mode acts more like a max-size measurement unless overflow is hidden during measurement.
13416             // We will put the overflow back to it's original value when we are done measuring.
13417             if (Ext.isIEQuirks) {
13418                 style = dom.style;
13419                 overflow = style.overflow;
13420                 me.setStyle({ overflow: 'hidden'});
13421             }
13422
13423             height = dom.offsetHeight;
13424
13425             height = MATH.max(height, hidden ? 0 : dom.clientHeight) || 0;
13426
13427             // IE9 Direct2D dimension rounding bug
13428             if (!hidden && Ext.supports.Direct2DBug) {
13429                 floating = me.adjustDirect2DDimension('height');
13430                 if (preciseHeight) {
13431                     height += floating;
13432                 }
13433                 else if (floating > 0 && floating < 0.5) {
13434                     height++;
13435                 }
13436             }
13437
13438             if (contentHeight) {
13439                 height -= (me.getBorderWidth("tb") + me.getPadding("tb"));
13440             }
13441
13442             if (Ext.isIEQuirks) {
13443                 me.setStyle({ overflow: overflow});
13444             }
13445
13446             if (height < 0) {
13447                 height = 0;
13448             }
13449             return height;
13450         },
13451                 
13452         /**
13453          * Returns the offset width of the element
13454          * @param {Boolean} contentWidth (optional) true to get the width minus borders and padding
13455          * @return {Number} The element's width
13456          */
13457         getWidth: function(contentWidth, preciseWidth) {
13458             var me = this,
13459                 dom = me.dom,
13460                 hidden = Ext.isIE && me.isStyle('display', 'none'),
13461                 rect, width, overflow, style, floating, parentPosition;
13462
13463             // IE Quirks mode acts more like a max-size measurement unless overflow is hidden during measurement.
13464             // We will put the overflow back to it's original value when we are done measuring.
13465             if (Ext.isIEQuirks) {
13466                 style = dom.style;
13467                 overflow = style.overflow;
13468                 me.setStyle({overflow: 'hidden'});
13469             }
13470             
13471             // Fix Opera 10.5x width calculation issues 
13472             if (Ext.isOpera10_5) {
13473                 if (dom.parentNode.currentStyle.position === 'relative') {
13474                     parentPosition = dom.parentNode.style.position;
13475                     dom.parentNode.style.position = 'static';
13476                     width = dom.offsetWidth;
13477                     dom.parentNode.style.position = parentPosition;
13478                 }
13479                 width = Math.max(width || 0, dom.offsetWidth);
13480             
13481             // Gecko will in some cases report an offsetWidth that is actually less than the width of the
13482             // text contents, because it measures fonts with sub-pixel precision but rounds the calculated
13483             // value down. Using getBoundingClientRect instead of offsetWidth allows us to get the precise
13484             // subpixel measurements so we can force them to always be rounded up. See
13485             // https://bugzilla.mozilla.org/show_bug.cgi?id=458617
13486             } else if (Ext.supports.BoundingClientRect) {
13487                 rect = dom.getBoundingClientRect();
13488                 width = rect.right - rect.left;
13489                 width = preciseWidth ? width : Math.ceil(width);
13490             } else {
13491                 width = dom.offsetWidth;
13492             }
13493
13494             width = MATH.max(width, hidden ? 0 : dom.clientWidth) || 0;
13495
13496             // IE9 Direct2D dimension rounding bug
13497             if (!hidden && Ext.supports.Direct2DBug) {
13498                 floating = me.adjustDirect2DDimension('width');
13499                 if (preciseWidth) {
13500                     width += floating;
13501                 }
13502                 else if (floating > 0 && floating < 0.5) {
13503                     width++;
13504                 }
13505             }
13506             
13507             if (contentWidth) {
13508                 width -= (me.getBorderWidth("lr") + me.getPadding("lr"));
13509             }
13510             
13511             if (Ext.isIEQuirks) {
13512                 me.setStyle({ overflow: overflow});
13513             }
13514
13515             if (width < 0) {
13516                 width = 0;
13517             }
13518             return width;
13519         },
13520
13521         /**
13522          * Set the width of this Element.
13523          * @param {Mixed} width The new width. This may be one of:<div class="mdetail-params"><ul>
13524          * <li>A Number specifying the new width in this Element's {@link #defaultUnit}s (by default, pixels).</li>
13525          * <li>A String used to set the CSS width style. Animation may <b>not</b> be used.
13526          * </ul></div>
13527          * @param {Boolean/Object} animate (optional) true for the default animation or a standard Element animation config object
13528          * @return {Ext.core.Element} this
13529          */
13530         setWidth : function(width, animate){
13531             var me = this;
13532             width = me.adjustWidth(width);
13533             if (!animate || !me.anim) {
13534                 me.dom.style.width = me.addUnits(width);
13535             }
13536             else {
13537                 if (!Ext.isObject(animate)) {
13538                     animate = {};
13539                 }
13540                 me.animate(Ext.applyIf({
13541                     to: {
13542                         width: width
13543                     }
13544                 }, animate));
13545             }
13546             return me;
13547         },
13548
13549         /**
13550          * Set the height of this Element.
13551          * <pre><code>
13552 // change the height to 200px and animate with default configuration
13553 Ext.fly('elementId').setHeight(200, true);
13554
13555 // change the height to 150px and animate with a custom configuration
13556 Ext.fly('elId').setHeight(150, {
13557     duration : .5, // animation will have a duration of .5 seconds
13558     // will change the content to "finished"
13559     callback: function(){ this.{@link #update}("finished"); }
13560 });
13561          * </code></pre>
13562          * @param {Mixed} height The new height. This may be one of:<div class="mdetail-params"><ul>
13563          * <li>A Number specifying the new height in this Element's {@link #defaultUnit}s (by default, pixels.)</li>
13564          * <li>A String used to set the CSS height style. Animation may <b>not</b> be used.</li>
13565          * </ul></div>
13566          * @param {Boolean/Object} animate (optional) true for the default animation or a standard Element animation config object
13567          * @return {Ext.core.Element} this
13568          */
13569          setHeight : function(height, animate){
13570             var me = this;
13571             height = me.adjustHeight(height);
13572             if (!animate || !me.anim) {
13573                 me.dom.style.height = me.addUnits(height);
13574             }
13575             else {
13576                 if (!Ext.isObject(animate)) {
13577                     animate = {};
13578                 }
13579                 me.animate(Ext.applyIf({
13580                     to: {
13581                         height: height
13582                     }
13583                 }, animate));
13584             }
13585             return me;
13586         },
13587
13588         /**
13589          * Gets the width of the border(s) for the specified side(s)
13590          * @param {String} side Can be t, l, r, b or any combination of those to add multiple values. For example,
13591          * passing <tt>'lr'</tt> would get the border <b><u>l</u></b>eft width + the border <b><u>r</u></b>ight width.
13592          * @return {Number} The width of the sides passed added together
13593          */
13594         getBorderWidth : function(side){
13595             return this.addStyles(side, borders);
13596         },
13597
13598         /**
13599          * Gets the width of the padding(s) for the specified side(s)
13600          * @param {String} side Can be t, l, r, b or any combination of those to add multiple values. For example,
13601          * passing <tt>'lr'</tt> would get the padding <b><u>l</u></b>eft + the padding <b><u>r</u></b>ight.
13602          * @return {Number} The padding of the sides passed added together
13603          */
13604         getPadding : function(side){
13605             return this.addStyles(side, paddings);
13606         },
13607
13608         /**
13609          *  Store the current overflow setting and clip overflow on the element - use <tt>{@link #unclip}</tt> to remove
13610          * @return {Ext.core.Element} this
13611          */
13612         clip : function(){
13613             var me = this,
13614                 dom = me.dom;
13615
13616             if(!data(dom, ISCLIPPED)){
13617                 data(dom, ISCLIPPED, true);
13618                 data(dom, ORIGINALCLIP, {
13619                     o: me.getStyle(OVERFLOW),
13620                     x: me.getStyle(OVERFLOWX),
13621                     y: me.getStyle(OVERFLOWY)
13622                 });
13623                 me.setStyle(OVERFLOW, HIDDEN);
13624                 me.setStyle(OVERFLOWX, HIDDEN);
13625                 me.setStyle(OVERFLOWY, HIDDEN);
13626             }
13627             return me;
13628         },
13629
13630         /**
13631          *  Return clipping (overflow) to original clipping before <tt>{@link #clip}</tt> was called
13632          * @return {Ext.core.Element} this
13633          */
13634         unclip : function(){
13635             var me = this,
13636                 dom = me.dom,
13637                 clip;
13638
13639             if(data(dom, ISCLIPPED)){
13640                 data(dom, ISCLIPPED, false);
13641                 clip = data(dom, ORIGINALCLIP);
13642                 if(o.o){
13643                     me.setStyle(OVERFLOW, o.o);
13644                 }
13645                 if(o.x){
13646                     me.setStyle(OVERFLOWX, o.x);
13647                 }
13648                 if(o.y){
13649                     me.setStyle(OVERFLOWY, o.y);
13650                 }
13651             }
13652             return me;
13653         },
13654
13655         // private
13656         addStyles : function(sides, styles){
13657             var totalSize = 0,
13658                 sidesArr = sides.match(wordsRe),
13659                 i = 0,
13660                 len = sidesArr.length,
13661                 side, size;
13662             for (; i < len; i++) {
13663                 side = sidesArr[i];
13664                 size = side && parseInt(this.getStyle(styles[side]), 10);
13665                 if (size) {
13666                     totalSize += MATH.abs(size);
13667                 }
13668             }
13669             return totalSize;
13670         },
13671
13672         margins : margins,
13673         
13674         /**
13675          * More flexible version of {@link #setStyle} for setting style properties.
13676          * @param {String/Object/Function} styles A style specification string, e.g. "width:100px", or object in the form {width:"100px"}, or
13677          * a function which returns such a specification.
13678          * @return {Ext.core.Element} this
13679          */
13680         applyStyles : function(style){
13681             Ext.core.DomHelper.applyStyles(this.dom, style);
13682             return this;
13683         },
13684
13685         /**
13686          * Returns an object with properties matching the styles requested.
13687          * For example, el.getStyles('color', 'font-size', 'width') might return
13688          * {'color': '#FFFFFF', 'font-size': '13px', 'width': '100px'}.
13689          * @param {String} style1 A style name
13690          * @param {String} style2 A style name
13691          * @param {String} etc.
13692          * @return {Object} The style object
13693          */
13694         getStyles : function(){
13695             var styles = {},
13696                 len = arguments.length,
13697                 i = 0, style;
13698                 
13699             for(; i < len; ++i) {
13700                 style = arguments[i];
13701                 styles[style] = this.getStyle(style);
13702             }
13703             return styles;
13704         },
13705
13706        /**
13707         * <p>Wraps the specified element with a special 9 element markup/CSS block that renders by default as
13708         * a gray container with a gradient background, rounded corners and a 4-way shadow.</p>
13709         * <p>This special markup is used throughout Ext when box wrapping elements ({@link Ext.button.Button},
13710         * {@link Ext.panel.Panel} when <tt>{@link Ext.panel.Panel#frame frame=true}</tt>, {@link Ext.window.Window}).  The markup
13711         * is of this form:</p>
13712         * <pre><code>
13713     Ext.core.Element.boxMarkup =
13714     &#39;&lt;div class="{0}-tl">&lt;div class="{0}-tr">&lt;div class="{0}-tc">&lt;/div>&lt;/div>&lt;/div>
13715      &lt;div class="{0}-ml">&lt;div class="{0}-mr">&lt;div class="{0}-mc">&lt;/div>&lt;/div>&lt;/div>
13716      &lt;div class="{0}-bl">&lt;div class="{0}-br">&lt;div class="{0}-bc">&lt;/div>&lt;/div>&lt;/div>&#39;;
13717         * </code></pre>
13718         * <p>Example usage:</p>
13719         * <pre><code>
13720     // Basic box wrap
13721     Ext.get("foo").boxWrap();
13722
13723     // You can also add a custom class and use CSS inheritance rules to customize the box look.
13724     // 'x-box-blue' is a built-in alternative -- look at the related CSS definitions as an example
13725     // for how to create a custom box wrap style.
13726     Ext.get("foo").boxWrap().addCls("x-box-blue");
13727         * </code></pre>
13728         * @param {String} class (optional) A base CSS class to apply to the containing wrapper element
13729         * (defaults to <tt>'x-box'</tt>). Note that there are a number of CSS rules that are dependent on
13730         * this name to make the overall effect work, so if you supply an alternate base class, make sure you
13731         * also supply all of the necessary rules.
13732         * @return {Ext.core.Element} The outermost wrapping element of the created box structure.
13733         */
13734         boxWrap : function(cls){
13735             cls = cls || Ext.baseCSSPrefix + 'box';
13736             var el = Ext.get(this.insertHtml("beforeBegin", "<div class='" + cls + "'>" + Ext.String.format(Ext.core.Element.boxMarkup, cls) + "</div>"));
13737             Ext.DomQuery.selectNode('.' + cls + '-mc', el.dom).appendChild(this.dom);
13738             return el;
13739         },
13740
13741         /**
13742          * Set the size of this Element. If animation is true, both width and height will be animated concurrently.
13743          * @param {Mixed} width The new width. This may be one of:<div class="mdetail-params"><ul>
13744          * <li>A Number specifying the new width in this Element's {@link #defaultUnit}s (by default, pixels).</li>
13745          * <li>A String used to set the CSS width style. Animation may <b>not</b> be used.
13746          * <li>A size object in the format <code>{width: widthValue, height: heightValue}</code>.</li>
13747          * </ul></div>
13748          * @param {Mixed} height The new height. This may be one of:<div class="mdetail-params"><ul>
13749          * <li>A Number specifying the new height in this Element's {@link #defaultUnit}s (by default, pixels).</li>
13750          * <li>A String used to set the CSS height style. Animation may <b>not</b> be used.</li>
13751          * </ul></div>
13752          * @param {Boolean/Object} animate (optional) true for the default animation or a standard Element animation config object
13753          * @return {Ext.core.Element} this
13754          */
13755         setSize : function(width, height, animate){
13756             var me = this;
13757             if (Ext.isObject(width)){ // in case of object from getSize()
13758                 height = width.height;
13759                 width = width.width;
13760             }
13761             width = me.adjustWidth(width);
13762             height = me.adjustHeight(height);
13763             if(!animate || !me.anim){
13764                 me.dom.style.width = me.addUnits(width);
13765                 me.dom.style.height = me.addUnits(height);
13766             }
13767             else {
13768                 if (!Ext.isObject(animate)) {
13769                     animate = {};
13770                 }
13771                 me.animate(Ext.applyIf({
13772                     to: {
13773                         width: width,
13774                         height: height
13775                     }
13776                 }, animate));
13777             }
13778             return me;
13779         },
13780
13781         /**
13782          * Returns either the offsetHeight or the height of this element based on CSS height adjusted by padding or borders
13783          * when needed to simulate offsetHeight when offsets aren't available. This may not work on display:none elements
13784          * if a height has not been set using CSS.
13785          * @return {Number}
13786          */
13787         getComputedHeight : function(){
13788             var me = this,
13789                 h = Math.max(me.dom.offsetHeight, me.dom.clientHeight);
13790             if(!h){
13791                 h = parseFloat(me.getStyle('height')) || 0;
13792                 if(!me.isBorderBox()){
13793                     h += me.getFrameWidth('tb');
13794                 }
13795             }
13796             return h;
13797         },
13798
13799         /**
13800          * Returns either the offsetWidth or the width of this element based on CSS width adjusted by padding or borders
13801          * when needed to simulate offsetWidth when offsets aren't available. This may not work on display:none elements
13802          * if a width has not been set using CSS.
13803          * @return {Number}
13804          */
13805         getComputedWidth : function(){
13806             var me = this,
13807                 w = Math.max(me.dom.offsetWidth, me.dom.clientWidth);
13808                 
13809             if(!w){
13810                 w = parseFloat(me.getStyle('width')) || 0;
13811                 if(!me.isBorderBox()){
13812                     w += me.getFrameWidth('lr');
13813                 }
13814             }
13815             return w;
13816         },
13817
13818         /**
13819          * Returns the sum width of the padding and borders for the passed "sides". See getBorderWidth()
13820          for more information about the sides.
13821          * @param {String} sides
13822          * @return {Number}
13823          */
13824         getFrameWidth : function(sides, onlyContentBox){
13825             return onlyContentBox && this.isBorderBox() ? 0 : (this.getPadding(sides) + this.getBorderWidth(sides));
13826         },
13827
13828         /**
13829          * Sets up event handlers to add and remove a css class when the mouse is over this element
13830          * @param {String} className
13831          * @return {Ext.core.Element} this
13832          */
13833         addClsOnOver : function(className){
13834             var dom = this.dom;
13835             this.hover(
13836                 function(){
13837                     Ext.fly(dom, INTERNAL).addCls(className);
13838                 },
13839                 function(){
13840                     Ext.fly(dom, INTERNAL).removeCls(className);
13841                 }
13842             );
13843             return this;
13844         },
13845
13846         /**
13847          * Sets up event handlers to add and remove a css class when this element has the focus
13848          * @param {String} className
13849          * @return {Ext.core.Element} this
13850          */
13851         addClsOnFocus : function(className){
13852             var me = this,
13853                 dom = me.dom;
13854             me.on("focus", function(){
13855                 Ext.fly(dom, INTERNAL).addCls(className);
13856             });
13857             me.on("blur", function(){
13858                 Ext.fly(dom, INTERNAL).removeCls(className);
13859             });
13860             return me;
13861         },
13862
13863         /**
13864          * 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)
13865          * @param {String} className
13866          * @return {Ext.core.Element} this
13867          */
13868         addClsOnClick : function(className){
13869             var dom = this.dom;
13870             this.on("mousedown", function(){
13871                 Ext.fly(dom, INTERNAL).addCls(className);
13872                 var d = Ext.getDoc(),
13873                     fn = function(){
13874                         Ext.fly(dom, INTERNAL).removeCls(className);
13875                         d.removeListener("mouseup", fn);
13876                     };
13877                 d.on("mouseup", fn);
13878             });
13879             return this;
13880         },
13881
13882         /**
13883          * <p>Returns the dimensions of the element available to lay content out in.<p>
13884          * <p>If the element (or any ancestor element) has CSS style <code>display : none</code>, the dimensions will be zero.</p>
13885          * example:<pre><code>
13886         var vpSize = Ext.getBody().getViewSize();
13887
13888         // all Windows created afterwards will have a default value of 90% height and 95% width
13889         Ext.Window.override({
13890             width: vpSize.width * 0.9,
13891             height: vpSize.height * 0.95
13892         });
13893         // To handle window resizing you would have to hook onto onWindowResize.
13894         * </code></pre>
13895         *
13896         * getViewSize utilizes clientHeight/clientWidth which excludes sizing of scrollbars.
13897         * To obtain the size including scrollbars, use getStyleSize
13898         *
13899         * Sizing of the document body is handled at the adapter level which handles special cases for IE and strict modes, etc.
13900         */
13901
13902         getViewSize : function(){
13903             var me = this,
13904                 dom = me.dom,
13905                 isDoc = (dom == Ext.getDoc().dom || dom == Ext.getBody().dom),
13906                 style, overflow, ret;
13907
13908             // If the body, use static methods
13909             if (isDoc) {
13910                 ret = {
13911                     width : Ext.core.Element.getViewWidth(),
13912                     height : Ext.core.Element.getViewHeight()
13913                 };
13914
13915             // Else use clientHeight/clientWidth
13916             }
13917             else {
13918                 // IE 6 & IE Quirks mode acts more like a max-size measurement unless overflow is hidden during measurement.
13919                 // We will put the overflow back to it's original value when we are done measuring.
13920                 if (Ext.isIE6 || Ext.isIEQuirks) {
13921                     style = dom.style;
13922                     overflow = style.overflow;
13923                     me.setStyle({ overflow: 'hidden'});
13924                 }
13925                 ret = {
13926                     width : dom.clientWidth,
13927                     height : dom.clientHeight
13928                 };
13929                 if (Ext.isIE6 || Ext.isIEQuirks) {
13930                     me.setStyle({ overflow: overflow });
13931                 }
13932             }
13933             return ret;
13934         },
13935
13936         /**
13937         * <p>Returns the dimensions of the element available to lay content out in.<p>
13938         *
13939         * getStyleSize utilizes prefers style sizing if present, otherwise it chooses the larger of offsetHeight/clientHeight and offsetWidth/clientWidth.
13940         * To obtain the size excluding scrollbars, use getViewSize
13941         *
13942         * Sizing of the document body is handled at the adapter level which handles special cases for IE and strict modes, etc.
13943         */
13944
13945         getStyleSize : function(){
13946             var me = this,
13947                 doc = document,
13948                 d = this.dom,
13949                 isDoc = (d == doc || d == doc.body),
13950                 s = d.style,
13951                 w, h;
13952
13953             // If the body, use static methods
13954             if (isDoc) {
13955                 return {
13956                     width : Ext.core.Element.getViewWidth(),
13957                     height : Ext.core.Element.getViewHeight()
13958                 };
13959             }
13960             // Use Styles if they are set
13961             if(s.width && s.width != 'auto'){
13962                 w = parseFloat(s.width);
13963                 if(me.isBorderBox()){
13964                    w -= me.getFrameWidth('lr');
13965                 }
13966             }
13967             // Use Styles if they are set
13968             if(s.height && s.height != 'auto'){
13969                 h = parseFloat(s.height);
13970                 if(me.isBorderBox()){
13971                    h -= me.getFrameWidth('tb');
13972                 }
13973             }
13974             // Use getWidth/getHeight if style not set.
13975             return {width: w || me.getWidth(true), height: h || me.getHeight(true)};
13976         },
13977
13978         /**
13979          * Returns the size of the element.
13980          * @param {Boolean} contentSize (optional) true to get the width/size minus borders and padding
13981          * @return {Object} An object containing the element's size {width: (element width), height: (element height)}
13982          */
13983         getSize : function(contentSize){
13984             return {width: this.getWidth(contentSize), height: this.getHeight(contentSize)};
13985         },
13986
13987         /**
13988          * Forces the browser to repaint this element
13989          * @return {Ext.core.Element} this
13990          */
13991         repaint : function(){
13992             var dom = this.dom;
13993             this.addCls(Ext.baseCSSPrefix + 'repaint');
13994             setTimeout(function(){
13995                 Ext.fly(dom).removeCls(Ext.baseCSSPrefix + 'repaint');
13996             }, 1);
13997             return this;
13998         },
13999
14000         /**
14001          * Disables text selection for this element (normalized across browsers)
14002          * @return {Ext.core.Element} this
14003          */
14004         unselectable : function(){
14005             var me = this;
14006             me.dom.unselectable = "on";
14007
14008             me.swallowEvent("selectstart", true);
14009             me.applyStyles("-moz-user-select:none;-khtml-user-select:none;");
14010             me.addCls(Ext.baseCSSPrefix + 'unselectable');
14011             
14012             return me;
14013         },
14014
14015         /**
14016          * Returns an object with properties top, left, right and bottom representing the margins of this element unless sides is passed,
14017          * then it returns the calculated width of the sides (see getPadding)
14018          * @param {String} sides (optional) Any combination of l, r, t, b to get the sum of those sides
14019          * @return {Object/Number}
14020          */
14021         getMargin : function(side){
14022             var me = this,
14023                 hash = {t:"top", l:"left", r:"right", b: "bottom"},
14024                 o = {},
14025                 key;
14026
14027             if (!side) {
14028                 for (key in me.margins){
14029                     o[hash[key]] = parseFloat(me.getStyle(me.margins[key])) || 0;
14030                 }
14031                 return o;
14032             } else {
14033                 return me.addStyles.call(me, side, me.margins);
14034             }
14035         }
14036     });
14037 })();
14038 /**
14039  * @class Ext.core.Element
14040  */
14041 /**
14042  * Visibility mode constant for use with {@link #setVisibilityMode}. Use visibility to hide element
14043  * @static
14044  * @type Number
14045  */
14046 Ext.core.Element.VISIBILITY = 1;
14047 /**
14048  * Visibility mode constant for use with {@link #setVisibilityMode}. Use display to hide element
14049  * @static
14050  * @type Number
14051  */
14052 Ext.core.Element.DISPLAY = 2;
14053
14054 /**
14055  * Visibility mode constant for use with {@link #setVisibilityMode}. Use offsets (x and y positioning offscreen)
14056  * to hide element.
14057  * @static
14058  * @type Number
14059  */
14060 Ext.core.Element.OFFSETS = 3;
14061
14062
14063 Ext.core.Element.ASCLASS = 4;
14064
14065 /**
14066  * Defaults to 'x-hide-nosize'
14067  * @static
14068  * @type String
14069  */
14070 Ext.core.Element.visibilityCls = Ext.baseCSSPrefix + 'hide-nosize';
14071
14072 Ext.core.Element.addMethods(function(){
14073     var El = Ext.core.Element,
14074         OPACITY = "opacity",
14075         VISIBILITY = "visibility",
14076         DISPLAY = "display",
14077         HIDDEN = "hidden",
14078         OFFSETS = "offsets",
14079         ASCLASS = "asclass",
14080         NONE = "none",
14081         NOSIZE = 'nosize',
14082         ORIGINALDISPLAY = 'originalDisplay',
14083         VISMODE = 'visibilityMode',
14084         ISVISIBLE = 'isVisible',
14085         data = El.data,
14086         getDisplay = function(dom){
14087             var d = data(dom, ORIGINALDISPLAY);
14088             if(d === undefined){
14089                 data(dom, ORIGINALDISPLAY, d = '');
14090             }
14091             return d;
14092         },
14093         getVisMode = function(dom){
14094             var m = data(dom, VISMODE);
14095             if(m === undefined){
14096                 data(dom, VISMODE, m = 1);
14097             }
14098             return m;
14099         };
14100
14101     return {
14102         /**
14103          * The element's default display mode  (defaults to "")
14104          * @type String
14105          */
14106         originalDisplay : "",
14107         visibilityMode : 1,
14108
14109         /**
14110          * Sets the element's visibility mode. When setVisible() is called it
14111          * will use this to determine whether to set the visibility or the display property.
14112          * @param {Number} visMode Ext.core.Element.VISIBILITY or Ext.core.Element.DISPLAY
14113          * @return {Ext.core.Element} this
14114          */
14115         setVisibilityMode : function(visMode){
14116             data(this.dom, VISMODE, visMode);
14117             return this;
14118         },
14119
14120         /**
14121          * Checks whether the element is currently visible using both visibility and display properties.
14122          * @return {Boolean} True if the element is currently visible, else false
14123          */
14124         isVisible : function() {
14125             var me = this,
14126                 dom = me.dom,
14127                 visible = data(dom, ISVISIBLE);
14128
14129             if(typeof visible == 'boolean'){ //return the cached value if registered
14130                 return visible;
14131             }
14132             //Determine the current state based on display states
14133             visible = !me.isStyle(VISIBILITY, HIDDEN) &&
14134                       !me.isStyle(DISPLAY, NONE) &&
14135                       !((getVisMode(dom) == El.ASCLASS) && me.hasCls(me.visibilityCls || El.visibilityCls));
14136
14137             data(dom, ISVISIBLE, visible);
14138             return visible;
14139         },
14140
14141         /**
14142          * Sets the visibility of the element (see details). If the visibilityMode is set to Element.DISPLAY, it will use
14143          * the display property to hide the element, otherwise it uses visibility. The default is to hide and show using the visibility property.
14144          * @param {Boolean} visible Whether the element is visible
14145          * @param {Boolean/Object} animate (optional) True for the default animation, or a standard Element animation config object
14146          * @return {Ext.core.Element} this
14147          */
14148         setVisible : function(visible, animate){
14149             var me = this, isDisplay, isVisibility, isOffsets, isNosize,
14150                 dom = me.dom,
14151                 visMode = getVisMode(dom);
14152
14153
14154             // hideMode string override
14155             if (typeof animate == 'string'){
14156                 switch (animate) {
14157                     case DISPLAY:
14158                         visMode = El.DISPLAY;
14159                         break;
14160                     case VISIBILITY:
14161                         visMode = El.VISIBILITY;
14162                         break;
14163                     case OFFSETS:
14164                         visMode = El.OFFSETS;
14165                         break;
14166                     case NOSIZE:
14167                     case ASCLASS:
14168                         visMode = El.ASCLASS;
14169                         break;
14170                 }
14171                 me.setVisibilityMode(visMode);
14172                 animate = false;
14173             }
14174
14175             if (!animate || !me.anim) {
14176                 if(visMode == El.ASCLASS ){
14177
14178                     me[visible?'removeCls':'addCls'](me.visibilityCls || El.visibilityCls);
14179
14180                 } else if (visMode == El.DISPLAY){
14181
14182                     return me.setDisplayed(visible);
14183
14184                 } else if (visMode == El.OFFSETS){
14185
14186                     if (!visible){
14187                         // Remember position for restoring, if we are not already hidden by offsets.
14188                         if (!me.hideModeStyles) {
14189                             me.hideModeStyles = {
14190                                 position: me.getStyle('position'),
14191                                 top: me.getStyle('top'),
14192                                 left: me.getStyle('left')
14193                             };
14194                         }
14195                         me.applyStyles({position: 'absolute', top: '-10000px', left: '-10000px'});
14196                     }
14197
14198                     // Only "restore" as position if we have actually been hidden using offsets.
14199                     // Calling setVisible(true) on a positioned element should not reposition it.
14200                     else if (me.hideModeStyles) {
14201                         me.applyStyles(me.hideModeStyles || {position: '', top: '', left: ''});
14202                         delete me.hideModeStyles;
14203                     }
14204
14205                 }else{
14206                     me.fixDisplay();
14207                     // Show by clearing visibility style. Explicitly setting to "visible" overrides parent visibility setting.
14208                     dom.style.visibility = visible ? '' : HIDDEN;
14209                 }
14210             }else{
14211                 // closure for composites
14212                 if(visible){
14213                     me.setOpacity(0.01);
14214                     me.setVisible(true);
14215                 }
14216                 if (!Ext.isObject(animate)) {
14217                     animate = {
14218                         duration: 350,
14219                         easing: 'ease-in'
14220                     };
14221                 }
14222                 me.animate(Ext.applyIf({
14223                     callback: function() {
14224                         visible || me.setVisible(false).setOpacity(1);
14225                     },
14226                     to: {
14227                         opacity: (visible) ? 1 : 0
14228                     }
14229                 }, animate));
14230             }
14231             data(dom, ISVISIBLE, visible);  //set logical visibility state
14232             return me;
14233         },
14234
14235
14236         /**
14237          * @private
14238          * Determine if the Element has a relevant height and width available based
14239          * upon current logical visibility state
14240          */
14241         hasMetrics  : function(){
14242             var dom = this.dom;
14243             return this.isVisible() || (getVisMode(dom) == El.OFFSETS) || (getVisMode(dom) == El.VISIBILITY);
14244         },
14245
14246         /**
14247          * Toggles the element's visibility or display, depending on visibility mode.
14248          * @param {Boolean/Object} animate (optional) True for the default animation, or a standard Element animation config object
14249          * @return {Ext.core.Element} this
14250          */
14251         toggle : function(animate){
14252             var me = this;
14253             me.setVisible(!me.isVisible(), me.anim(animate));
14254             return me;
14255         },
14256
14257         /**
14258          * Sets the CSS display property. Uses originalDisplay if the specified value is a boolean true.
14259          * @param {Mixed} value Boolean value to display the element using its default display, or a string to set the display directly.
14260          * @return {Ext.core.Element} this
14261          */
14262         setDisplayed : function(value) {
14263             if(typeof value == "boolean"){
14264                value = value ? getDisplay(this.dom) : NONE;
14265             }
14266             this.setStyle(DISPLAY, value);
14267             return this;
14268         },
14269
14270         // private
14271         fixDisplay : function(){
14272             var me = this;
14273             if (me.isStyle(DISPLAY, NONE)) {
14274                 me.setStyle(VISIBILITY, HIDDEN);
14275                 me.setStyle(DISPLAY, getDisplay(this.dom)); // first try reverting to default
14276                 if (me.isStyle(DISPLAY, NONE)) { // if that fails, default to block
14277                     me.setStyle(DISPLAY, "block");
14278                 }
14279             }
14280         },
14281
14282         /**
14283          * Hide this element - Uses display mode to determine whether to use "display" or "visibility". See {@link #setVisible}.
14284          * @param {Boolean/Object} animate (optional) true for the default animation or a standard Element animation config object
14285          * @return {Ext.core.Element} this
14286          */
14287         hide : function(animate){
14288             // hideMode override
14289             if (typeof animate == 'string'){
14290                 this.setVisible(false, animate);
14291                 return this;
14292             }
14293             this.setVisible(false, this.anim(animate));
14294             return this;
14295         },
14296
14297         /**
14298         * Show this element - Uses display mode to determine whether to use "display" or "visibility". See {@link #setVisible}.
14299         * @param {Boolean/Object} animate (optional) true for the default animation or a standard Element animation config object
14300          * @return {Ext.core.Element} this
14301          */
14302         show : function(animate){
14303             // hideMode override
14304             if (typeof animate == 'string'){
14305                 this.setVisible(true, animate);
14306                 return this;
14307             }
14308             this.setVisible(true, this.anim(animate));
14309             return this;
14310         }
14311     };
14312 }());
14313 /**
14314  * @class Ext.core.Element
14315  */
14316 Ext.applyIf(Ext.core.Element.prototype, {
14317     // @private override base Ext.util.Animate mixin for animate for backwards compatibility
14318     animate: function(config) {
14319         var me = this;
14320         if (!me.id) {
14321             me = Ext.get(me.dom);
14322         }
14323         if (Ext.fx.Manager.hasFxBlock(me.id)) {
14324             return me;
14325         }
14326         Ext.fx.Manager.queueFx(Ext.create('Ext.fx.Anim', me.anim(config)));
14327         return this;
14328     },
14329
14330     // @private override base Ext.util.Animate mixin for animate for backwards compatibility
14331     anim: function(config) {
14332         if (!Ext.isObject(config)) {
14333             return (config) ? {} : false;
14334         }
14335
14336         var me = this,
14337             duration = config.duration || Ext.fx.Anim.prototype.duration,
14338             easing = config.easing || 'ease',
14339             animConfig;
14340
14341         if (config.stopAnimation) {
14342             me.stopAnimation();
14343         }
14344
14345         Ext.applyIf(config, Ext.fx.Manager.getFxDefaults(me.id));
14346
14347         // Clear any 'paused' defaults.
14348         Ext.fx.Manager.setFxDefaults(me.id, {
14349             delay: 0
14350         });
14351
14352         animConfig = {
14353             target: me,
14354             remove: config.remove,
14355             alternate: config.alternate || false,
14356             duration: duration,
14357             easing: easing,
14358             callback: config.callback,
14359             listeners: config.listeners,
14360             iterations: config.iterations || 1,
14361             scope: config.scope,
14362             block: config.block,
14363             concurrent: config.concurrent,
14364             delay: config.delay || 0,
14365             paused: true,
14366             keyframes: config.keyframes,
14367             from: config.from || {},
14368             to: Ext.apply({}, config)
14369         };
14370         Ext.apply(animConfig.to, config.to);
14371
14372         // Anim API properties - backward compat
14373         delete animConfig.to.to;
14374         delete animConfig.to.from;
14375         delete animConfig.to.remove;
14376         delete animConfig.to.alternate;
14377         delete animConfig.to.keyframes;
14378         delete animConfig.to.iterations;
14379         delete animConfig.to.listeners;
14380         delete animConfig.to.target;
14381         delete animConfig.to.paused;
14382         delete animConfig.to.callback;
14383         delete animConfig.to.scope;
14384         delete animConfig.to.duration;
14385         delete animConfig.to.easing;
14386         delete animConfig.to.concurrent;
14387         delete animConfig.to.block;
14388         delete animConfig.to.stopAnimation;
14389         delete animConfig.to.delay;
14390         return animConfig;
14391     },
14392
14393     /**
14394      * Slides the element into view.  An anchor point can be optionally passed to set the point of
14395      * origin for the slide effect.  This function automatically handles wrapping the element with
14396      * a fixed-size container if needed.  See the Fx class overview for valid anchor point options.
14397      * Usage:
14398      *<pre><code>
14399 // default: slide the element in from the top
14400 el.slideIn();
14401
14402 // custom: slide the element in from the right with a 2-second duration
14403 el.slideIn('r', { duration: 2 });
14404
14405 // common config options shown with default values
14406 el.slideIn('t', {
14407     easing: 'easeOut',
14408     duration: 500
14409 });
14410 </code></pre>
14411      * @param {String} anchor (optional) One of the valid Fx anchor positions (defaults to top: 't')
14412      * @param {Object} options (optional) Object literal with any of the Fx config options
14413      * @return {Ext.core.Element} The Element
14414      */
14415     slideIn: function(anchor, obj, slideOut) { 
14416         var me = this,
14417             elStyle = me.dom.style,
14418             beforeAnim, wrapAnim;
14419
14420         anchor = anchor || "t";
14421         obj = obj || {};
14422
14423         beforeAnim = function() {
14424             var animScope = this,
14425                 listeners = obj.listeners,
14426                 box, position, restoreSize, wrap, anim;
14427
14428             if (!slideOut) {
14429                 me.fixDisplay();
14430             }
14431
14432             box = me.getBox();
14433             if ((anchor == 't' || anchor == 'b') && box.height == 0) {
14434                 box.height = me.dom.scrollHeight;
14435             }
14436             else if ((anchor == 'l' || anchor == 'r') && box.width == 0) {
14437                 box.width = me.dom.scrollWidth;
14438             }
14439             
14440             position = me.getPositioning();
14441             me.setSize(box.width, box.height);
14442
14443             wrap = me.wrap({
14444                 style: {
14445                     visibility: slideOut ? 'visible' : 'hidden'
14446                 }
14447             });
14448             wrap.setPositioning(position);
14449             if (wrap.isStyle('position', 'static')) {
14450                 wrap.position('relative');
14451             }
14452             me.clearPositioning('auto');
14453             wrap.clip();
14454
14455             // This element is temporarily positioned absolute within its wrapper.
14456             // Restore to its default, CSS-inherited visibility setting.
14457             // We cannot explicitly poke visibility:visible into its style because that overrides the visibility of the wrap.
14458             me.setStyle({
14459                 visibility: '',
14460                 position: 'absolute'
14461             });
14462             if (slideOut) {
14463                 wrap.setSize(box.width, box.height);
14464             }
14465
14466             switch (anchor) {
14467                 case 't':
14468                     anim = {
14469                         from: {
14470                             width: box.width + 'px',
14471                             height: '0px'
14472                         },
14473                         to: {
14474                             width: box.width + 'px',
14475                             height: box.height + 'px'
14476                         }
14477                     };
14478                     elStyle.bottom = '0px';
14479                     break;
14480                 case 'l':
14481                     anim = {
14482                         from: {
14483                             width: '0px',
14484                             height: box.height + 'px'
14485                         },
14486                         to: {
14487                             width: box.width + 'px',
14488                             height: box.height + 'px'
14489                         }
14490                     };
14491                     elStyle.right = '0px';
14492                     break;
14493                 case 'r':
14494                     anim = {
14495                         from: {
14496                             x: box.x + box.width,
14497                             width: '0px',
14498                             height: box.height + 'px'
14499                         },
14500                         to: {
14501                             x: box.x,
14502                             width: box.width + 'px',
14503                             height: box.height + 'px'
14504                         }
14505                     };
14506                     break;
14507                 case 'b':
14508                     anim = {
14509                         from: {
14510                             y: box.y + box.height,
14511                             width: box.width + 'px',
14512                             height: '0px'
14513                         },
14514                         to: {
14515                             y: box.y,
14516                             width: box.width + 'px',
14517                             height: box.height + 'px'
14518                         }
14519                     };
14520                     break;
14521                 case 'tl':
14522                     anim = {
14523                         from: {
14524                             x: box.x,
14525                             y: box.y,
14526                             width: '0px',
14527                             height: '0px'
14528                         },
14529                         to: {
14530                             width: box.width + 'px',
14531                             height: box.height + 'px'
14532                         }
14533                     };
14534                     elStyle.bottom = '0px';
14535                     elStyle.right = '0px';
14536                     break;
14537                 case 'bl':
14538                     anim = {
14539                         from: {
14540                             x: box.x + box.width,
14541                             width: '0px',
14542                             height: '0px'
14543                         },
14544                         to: {
14545                             x: box.x,
14546                             width: box.width + 'px',
14547                             height: box.height + 'px'
14548                         }
14549                     };
14550                     elStyle.right = '0px';
14551                     break;
14552                 case 'br':
14553                     anim = {
14554                         from: {
14555                             x: box.x + box.width,
14556                             y: box.y + box.height,
14557                             width: '0px',
14558                             height: '0px'
14559                         },
14560                         to: {
14561                             x: box.x,
14562                             y: box.y,
14563                             width: box.width + 'px',
14564                             height: box.height + 'px'
14565                         }
14566                     };
14567                     break;
14568                 case 'tr':
14569                     anim = {
14570                         from: {
14571                             y: box.y + box.height,
14572                             width: '0px',
14573                             height: '0px'
14574                         },
14575                         to: {
14576                             y: box.y,
14577                             width: box.width + 'px',
14578                             height: box.height + 'px'
14579                         }
14580                     };
14581                     elStyle.bottom = '0px';
14582                     break;
14583             }
14584
14585             wrap.show();
14586             wrapAnim = Ext.apply({}, obj);
14587             delete wrapAnim.listeners;
14588             wrapAnim = Ext.create('Ext.fx.Anim', Ext.applyIf(wrapAnim, {
14589                 target: wrap,
14590                 duration: 500,
14591                 easing: 'ease-out',
14592                 from: slideOut ? anim.to : anim.from,
14593                 to: slideOut ? anim.from : anim.to
14594             }));
14595
14596             // In the absence of a callback, this listener MUST be added first
14597             wrapAnim.on('afteranimate', function() {
14598                 if (slideOut) {
14599                     me.setPositioning(position);
14600                     if (obj.useDisplay) {
14601                         me.setDisplayed(false);
14602                     } else {
14603                         me.hide();   
14604                     }
14605                 }
14606                 else {
14607                     me.clearPositioning();
14608                     me.setPositioning(position);
14609                 }
14610                 if (wrap.dom) {
14611                     wrap.dom.parentNode.insertBefore(me.dom, wrap.dom); 
14612                     wrap.remove();
14613                 }
14614                 me.setSize(box.width, box.height);
14615                 animScope.end();
14616             });
14617             // Add configured listeners after
14618             if (listeners) {
14619                 wrapAnim.on(listeners);
14620             }
14621         };
14622
14623         me.animate({
14624             duration: obj.duration ? obj.duration * 2 : 1000,
14625             listeners: {
14626                 beforeanimate: {
14627                     fn: beforeAnim
14628                 },
14629                 afteranimate: {
14630                     fn: function() {
14631                         if (wrapAnim && wrapAnim.running) {
14632                             wrapAnim.end();
14633                         }
14634                     }
14635                 }
14636             }
14637         });
14638         return me;
14639     },
14640
14641     
14642     /**
14643      * Slides the element out of view.  An anchor point can be optionally passed to set the end point
14644      * for the slide effect.  When the effect is completed, the element will be hidden (visibility = 
14645      * 'hidden') but block elements will still take up space in the document.  The element must be removed
14646      * from the DOM using the 'remove' config option if desired.  This function automatically handles 
14647      * wrapping the element with a fixed-size container if needed.  See the Fx class overview for valid anchor point options.
14648      * Usage:
14649      *<pre><code>
14650 // default: slide the element out to the top
14651 el.slideOut();
14652
14653 // custom: slide the element out to the right with a 2-second duration
14654 el.slideOut('r', { duration: 2 });
14655
14656 // common config options shown with default values
14657 el.slideOut('t', {
14658     easing: 'easeOut',
14659     duration: 500,
14660     remove: false,
14661     useDisplay: false
14662 });
14663 </code></pre>
14664      * @param {String} anchor (optional) One of the valid Fx anchor positions (defaults to top: 't')
14665      * @param {Object} options (optional) Object literal with any of the Fx config options
14666      * @return {Ext.core.Element} The Element
14667      */
14668     slideOut: function(anchor, o) {
14669         return this.slideIn(anchor, o, true);
14670     },
14671
14672     /**
14673      * Fades the element out while slowly expanding it in all directions.  When the effect is completed, the 
14674      * element will be hidden (visibility = 'hidden') but block elements will still take up space in the document.
14675      * Usage:
14676      *<pre><code>
14677 // default
14678 el.puff();
14679
14680 // common config options shown with default values
14681 el.puff({
14682     easing: 'easeOut',
14683     duration: 500,
14684     useDisplay: false
14685 });
14686 </code></pre>
14687      * @param {Object} options (optional) Object literal with any of the Fx config options
14688      * @return {Ext.core.Element} The Element
14689      */
14690
14691     puff: function(obj) {
14692         var me = this,
14693             beforeAnim;
14694         obj = Ext.applyIf(obj || {}, {
14695             easing: 'ease-out',
14696             duration: 500,
14697             useDisplay: false
14698         });
14699
14700         beforeAnim = function() {
14701             me.clearOpacity();
14702             me.show();
14703
14704             var box = me.getBox(),
14705                 fontSize = me.getStyle('fontSize'),
14706                 position = me.getPositioning();
14707             this.to = {
14708                 width: box.width * 2,
14709                 height: box.height * 2,
14710                 x: box.x - (box.width / 2),
14711                 y: box.y - (box.height /2),
14712                 opacity: 0,
14713                 fontSize: '200%'
14714             };
14715             this.on('afteranimate',function() {
14716                 if (me.dom) {
14717                     if (obj.useDisplay) {
14718                         me.setDisplayed(false);
14719                     } else {
14720                         me.hide();
14721                     }
14722                     me.clearOpacity();  
14723                     me.setPositioning(position);
14724                     me.setStyle({fontSize: fontSize});
14725                 }
14726             });
14727         };
14728
14729         me.animate({
14730             duration: obj.duration,
14731             easing: obj.easing,
14732             listeners: {
14733                 beforeanimate: {
14734                     fn: beforeAnim
14735                 }
14736             }
14737         });
14738         return me;
14739     },
14740
14741     /**
14742      * Blinks the element as if it was clicked and then collapses on its center (similar to switching off a television).
14743      * When the effect is completed, the element will be hidden (visibility = 'hidden') but block elements will still 
14744      * take up space in the document. The element must be removed from the DOM using the 'remove' config option if desired.
14745      * Usage:
14746      *<pre><code>
14747 // default
14748 el.switchOff();
14749
14750 // all config options shown with default values
14751 el.switchOff({
14752     easing: 'easeIn',
14753     duration: .3,
14754     remove: false,
14755     useDisplay: false
14756 });
14757 </code></pre>
14758      * @param {Object} options (optional) Object literal with any of the Fx config options
14759      * @return {Ext.core.Element} The Element
14760      */
14761     switchOff: function(obj) {
14762         var me = this,
14763             beforeAnim;
14764         
14765         obj = Ext.applyIf(obj || {}, {
14766             easing: 'ease-in',
14767             duration: 500,
14768             remove: false,
14769             useDisplay: false
14770         });
14771
14772         beforeAnim = function() {
14773             var animScope = this,
14774                 size = me.getSize(),
14775                 xy = me.getXY(),
14776                 keyframe, position;
14777             me.clearOpacity();
14778             me.clip();
14779             position = me.getPositioning();
14780
14781             keyframe = Ext.create('Ext.fx.Animator', {
14782                 target: me,
14783                 duration: obj.duration,
14784                 easing: obj.easing,
14785                 keyframes: {
14786                     33: {
14787                         opacity: 0.3
14788                     },
14789                     66: {
14790                         height: 1,
14791                         y: xy[1] + size.height / 2
14792                     },
14793                     100: {
14794                         width: 1,
14795                         x: xy[0] + size.width / 2
14796                     }
14797                 }
14798             });
14799             keyframe.on('afteranimate', function() {
14800                 if (obj.useDisplay) {
14801                     me.setDisplayed(false);
14802                 } else {
14803                     me.hide();
14804                 }  
14805                 me.clearOpacity();
14806                 me.setPositioning(position);
14807                 me.setSize(size);
14808                 animScope.end();
14809             });
14810         };
14811         me.animate({
14812             duration: (obj.duration * 2),
14813             listeners: {
14814                 beforeanimate: {
14815                     fn: beforeAnim
14816                 }
14817             }
14818         });
14819         return me;
14820     },
14821
14822    /**
14823     * Shows a ripple of exploding, attenuating borders to draw attention to an Element.
14824     * Usage:
14825 <pre><code>
14826 // default: a single light blue ripple
14827 el.frame();
14828
14829 // custom: 3 red ripples lasting 3 seconds total
14830 el.frame("#ff0000", 3, { duration: 3 });
14831
14832 // common config options shown with default values
14833 el.frame("#C3DAF9", 1, {
14834     duration: 1 //duration of each individual ripple.
14835     // Note: Easing is not configurable and will be ignored if included
14836 });
14837 </code></pre>
14838     * @param {String} color (optional) The color of the border.  Should be a 6 char hex color without the leading # (defaults to light blue: 'C3DAF9').
14839     * @param {Number} count (optional) The number of ripples to display (defaults to 1)
14840     * @param {Object} options (optional) Object literal with any of the Fx config options
14841     * @return {Ext.core.Element} The Element
14842     */
14843     frame : function(color, count, obj){
14844         var me = this,
14845             beforeAnim;
14846
14847         color = color || '#C3DAF9';
14848         count = count || 1;
14849         obj = obj || {};
14850
14851         beforeAnim = function() {
14852             me.show();
14853             var animScope = this,
14854                 box = me.getBox(),
14855                 proxy = Ext.getBody().createChild({
14856                     style: {
14857                         position : 'absolute',
14858                         'pointer-events': 'none',
14859                         'z-index': 35000,
14860                         border : '0px solid ' + color
14861                     }
14862                 }),
14863                 proxyAnim;
14864             proxyAnim = Ext.create('Ext.fx.Anim', {
14865                 target: proxy,
14866                 duration: obj.duration || 1000,
14867                 iterations: count,
14868                 from: {
14869                     top: box.y,
14870                     left: box.x,
14871                     borderWidth: 0,
14872                     opacity: 1,
14873                     height: box.height,
14874                     width: box.width
14875                 },
14876                 to: {
14877                     top: box.y - 20,
14878                     left: box.x - 20,
14879                     borderWidth: 10,
14880                     opacity: 0,
14881                     height: box.height + 40,
14882                     width: box.width + 40
14883                 }
14884             });
14885             proxyAnim.on('afteranimate', function() {
14886                 proxy.remove();
14887                 animScope.end();
14888             });
14889         };
14890
14891         me.animate({
14892             duration: (obj.duration * 2) || 2000,
14893             listeners: {
14894                 beforeanimate: {
14895                     fn: beforeAnim
14896                 }
14897             }
14898         });
14899         return me;
14900     },
14901
14902     /**
14903      * Slides the element while fading it out of view.  An anchor point can be optionally passed to set the 
14904      * ending point of the effect.
14905      * Usage:
14906      *<pre><code>
14907 // default: slide the element downward while fading out
14908 el.ghost();
14909
14910 // custom: slide the element out to the right with a 2-second duration
14911 el.ghost('r', { duration: 2 });
14912
14913 // common config options shown with default values
14914 el.ghost('b', {
14915     easing: 'easeOut',
14916     duration: 500
14917 });
14918 </code></pre>
14919      * @param {String} anchor (optional) One of the valid Fx anchor positions (defaults to bottom: 'b')
14920      * @param {Object} options (optional) Object literal with any of the Fx config options
14921      * @return {Ext.core.Element} The Element
14922      */
14923     ghost: function(anchor, obj) {
14924         var me = this,
14925             beforeAnim;
14926
14927         anchor = anchor || "b";
14928         beforeAnim = function() {
14929             var width = me.getWidth(),
14930                 height = me.getHeight(),
14931                 xy = me.getXY(),
14932                 position = me.getPositioning(),
14933                 to = {
14934                     opacity: 0
14935                 };
14936             switch (anchor) {
14937                 case 't':
14938                     to.y = xy[1] - height;
14939                     break;
14940                 case 'l':
14941                     to.x = xy[0] - width;
14942                     break;
14943                 case 'r':
14944                     to.x = xy[0] + width;
14945                     break;
14946                 case 'b':
14947                     to.y = xy[1] + height;
14948                     break;
14949                 case 'tl':
14950                     to.x = xy[0] - width;
14951                     to.y = xy[1] - height;
14952                     break;
14953                 case 'bl':
14954                     to.x = xy[0] - width;
14955                     to.y = xy[1] + height;
14956                     break;
14957                 case 'br':
14958                     to.x = xy[0] + width;
14959                     to.y = xy[1] + height;
14960                     break;
14961                 case 'tr':
14962                     to.x = xy[0] + width;
14963                     to.y = xy[1] - height;
14964                     break;
14965             }
14966             this.to = to;
14967             this.on('afteranimate', function () {
14968                 if (me.dom) {
14969                     me.hide();
14970                     me.clearOpacity();
14971                     me.setPositioning(position);
14972                 }
14973             });
14974         };
14975
14976         me.animate(Ext.applyIf(obj || {}, {
14977             duration: 500,
14978             easing: 'ease-out',
14979             listeners: {
14980                 beforeanimate: {
14981                     fn: beforeAnim
14982                 }
14983             }
14984         }));
14985         return me;
14986     },
14987
14988     /**
14989      * Highlights the Element by setting a color (applies to the background-color by default, but can be
14990      * changed using the "attr" config option) and then fading back to the original color. If no original
14991      * color is available, you should provide the "endColor" config option which will be cleared after the animation.
14992      * Usage:
14993 <pre><code>
14994 // default: highlight background to yellow
14995 el.highlight();
14996
14997 // custom: highlight foreground text to blue for 2 seconds
14998 el.highlight("0000ff", { attr: 'color', duration: 2 });
14999
15000 // common config options shown with default values
15001 el.highlight("ffff9c", {
15002     attr: "backgroundColor", //can be any valid CSS property (attribute) that supports a color value
15003     endColor: (current color) or "ffffff",
15004     easing: 'easeIn',
15005     duration: 1000
15006 });
15007 </code></pre>
15008      * @param {String} color (optional) The highlight color. Should be a 6 char hex color without the leading # (defaults to yellow: 'ffff9c')
15009      * @param {Object} options (optional) Object literal with any of the Fx config options
15010      * @return {Ext.core.Element} The Element
15011      */ 
15012     highlight: function(color, o) {
15013         var me = this,
15014             dom = me.dom,
15015             from = {},
15016             restore, to, attr, lns, event, fn;
15017
15018         o = o || {};
15019         lns = o.listeners || {};
15020         attr = o.attr || 'backgroundColor';
15021         from[attr] = color || 'ffff9c';
15022         
15023         if (!o.to) {
15024             to = {};
15025             to[attr] = o.endColor || me.getColor(attr, 'ffffff', '');
15026         }
15027         else {
15028             to = o.to;
15029         }
15030         
15031         // Don't apply directly on lns, since we reference it in our own callbacks below
15032         o.listeners = Ext.apply(Ext.apply({}, lns), {
15033             beforeanimate: function() {
15034                 restore = dom.style[attr];
15035                 me.clearOpacity();
15036                 me.show();
15037                 
15038                 event = lns.beforeanimate;
15039                 if (event) {
15040                     fn = event.fn || event;
15041                     return fn.apply(event.scope || lns.scope || window, arguments);
15042                 }
15043             },
15044             afteranimate: function() {
15045                 if (dom) {
15046                     dom.style[attr] = restore;
15047                 }
15048                 
15049                 event = lns.afteranimate;
15050                 if (event) {
15051                     fn = event.fn || event;
15052                     fn.apply(event.scope || lns.scope || window, arguments);
15053                 }
15054             }
15055         });
15056
15057         me.animate(Ext.apply({}, o, {
15058             duration: 1000,
15059             easing: 'ease-in',
15060             from: from,
15061             to: to
15062         }));
15063         return me;
15064     },
15065
15066    /**
15067     * @deprecated 4.0
15068     * Creates a pause before any subsequent queued effects begin.  If there are
15069     * no effects queued after the pause it will have no effect.
15070     * Usage:
15071 <pre><code>
15072 el.pause(1);
15073 </code></pre>
15074     * @param {Number} seconds The length of time to pause (in seconds)
15075     * @return {Ext.Element} The Element
15076     */
15077     pause: function(ms) {
15078         var me = this;
15079         Ext.fx.Manager.setFxDefaults(me.id, {
15080             delay: ms
15081         });
15082         return me;
15083     },
15084
15085    /**
15086     * Fade an element in (from transparent to opaque).  The ending opacity can be specified
15087     * using the <tt>{@link #endOpacity}</tt> config option.
15088     * Usage:
15089 <pre><code>
15090 // default: fade in from opacity 0 to 100%
15091 el.fadeIn();
15092
15093 // custom: fade in from opacity 0 to 75% over 2 seconds
15094 el.fadeIn({ endOpacity: .75, duration: 2});
15095
15096 // common config options shown with default values
15097 el.fadeIn({
15098     endOpacity: 1, //can be any value between 0 and 1 (e.g. .5)
15099     easing: 'easeOut',
15100     duration: 500
15101 });
15102 </code></pre>
15103     * @param {Object} options (optional) Object literal with any of the Fx config options
15104     * @return {Ext.Element} The Element
15105     */
15106     fadeIn: function(o) {
15107         this.animate(Ext.apply({}, o, {
15108             opacity: 1
15109         }));
15110         return this;
15111     },
15112
15113    /**
15114     * Fade an element out (from opaque to transparent).  The ending opacity can be specified
15115     * using the <tt>{@link #endOpacity}</tt> config option.  Note that IE may require
15116     * <tt>{@link #useDisplay}:true</tt> in order to redisplay correctly.
15117     * Usage:
15118 <pre><code>
15119 // default: fade out from the element's current opacity to 0
15120 el.fadeOut();
15121
15122 // custom: fade out from the element's current opacity to 25% over 2 seconds
15123 el.fadeOut({ endOpacity: .25, duration: 2});
15124
15125 // common config options shown with default values
15126 el.fadeOut({
15127     endOpacity: 0, //can be any value between 0 and 1 (e.g. .5)
15128     easing: 'easeOut',
15129     duration: 500,
15130     remove: false,
15131     useDisplay: false
15132 });
15133 </code></pre>
15134     * @param {Object} options (optional) Object literal with any of the Fx config options
15135     * @return {Ext.Element} The Element
15136     */
15137     fadeOut: function(o) {
15138         this.animate(Ext.apply({}, o, {
15139             opacity: 0
15140         }));
15141         return this;
15142     },
15143
15144    /**
15145     * @deprecated 4.0
15146     * Animates the transition of an element's dimensions from a starting height/width
15147     * to an ending height/width.  This method is a convenience implementation of {@link shift}.
15148     * Usage:
15149 <pre><code>
15150 // change height and width to 100x100 pixels
15151 el.scale(100, 100);
15152
15153 // common config options shown with default values.  The height and width will default to
15154 // the element&#39;s existing values if passed as null.
15155 el.scale(
15156     [element&#39;s width],
15157     [element&#39;s height], {
15158         easing: 'easeOut',
15159         duration: .35
15160     }
15161 );
15162 </code></pre>
15163     * @param {Number} width  The new width (pass undefined to keep the original width)
15164     * @param {Number} height  The new height (pass undefined to keep the original height)
15165     * @param {Object} options (optional) Object literal with any of the Fx config options
15166     * @return {Ext.Element} The Element
15167     */
15168     scale: function(w, h, o) {
15169         this.animate(Ext.apply({}, o, {
15170             width: w,
15171             height: h
15172         }));
15173         return this;
15174     },
15175
15176    /**
15177     * @deprecated 4.0
15178     * Animates the transition of any combination of an element's dimensions, xy position and/or opacity.
15179     * Any of these properties not specified in the config object will not be changed.  This effect 
15180     * requires that at least one new dimension, position or opacity setting must be passed in on
15181     * the config object in order for the function to have any effect.
15182     * Usage:
15183 <pre><code>
15184 // slide the element horizontally to x position 200 while changing the height and opacity
15185 el.shift({ x: 200, height: 50, opacity: .8 });
15186
15187 // common config options shown with default values.
15188 el.shift({
15189     width: [element&#39;s width],
15190     height: [element&#39;s height],
15191     x: [element&#39;s x position],
15192     y: [element&#39;s y position],
15193     opacity: [element&#39;s opacity],
15194     easing: 'easeOut',
15195     duration: .35
15196 });
15197 </code></pre>
15198     * @param {Object} options  Object literal with any of the Fx config options
15199     * @return {Ext.Element} The Element
15200     */
15201     shift: function(config) {
15202         this.animate(config);
15203         return this;
15204     }
15205 });
15206
15207 /**
15208  * @class Ext.core.Element
15209  */
15210 Ext.applyIf(Ext.core.Element, {
15211     unitRe: /\d+(px|em|%|en|ex|pt|in|cm|mm|pc)$/i,
15212     camelRe: /(-[a-z])/gi,
15213     opacityRe: /alpha\(opacity=(.*)\)/i,
15214     cssRe: /([a-z0-9-]+)\s*:\s*([^;\s]+(?:\s*[^;\s]+)*);?/gi,
15215     propertyCache: {},
15216     defaultUnit : "px",
15217     borders: {l: 'border-left-width', r: 'border-right-width', t: 'border-top-width', b: 'border-bottom-width'},
15218     paddings: {l: 'padding-left', r: 'padding-right', t: 'padding-top', b: 'padding-bottom'},
15219     margins: {l: 'margin-left', r: 'margin-right', t: 'margin-top', b: 'margin-bottom'},
15220
15221     // Reference the prototype's version of the method. Signatures are identical.
15222     addUnits : Ext.core.Element.prototype.addUnits,
15223
15224     /**
15225      * Parses a number or string representing margin sizes into an object. Supports CSS-style margin declarations
15226      * (e.g. 10, "10", "10 10", "10 10 10" and "10 10 10 10" are all valid options and would return the same result)
15227      * @static
15228      * @param {Number|String} box The encoded margins
15229      * @return {Object} An object with margin sizes for top, right, bottom and left
15230      */
15231     parseBox : function(box) {
15232         if (Ext.isObject(box)) {
15233             return {
15234                 top: box.top || 0,
15235                 right: box.right || 0,
15236                 bottom: box.bottom || 0,
15237                 left: box.left || 0
15238             };
15239         } else {
15240             if (typeof box != 'string') {
15241                 box = box.toString();
15242             }
15243             var parts  = box.split(' '),
15244                 ln = parts.length;
15245     
15246             if (ln == 1) {
15247                 parts[1] = parts[2] = parts[3] = parts[0];
15248             }
15249             else if (ln == 2) {
15250                 parts[2] = parts[0];
15251                 parts[3] = parts[1];
15252             }
15253             else if (ln == 3) {
15254                 parts[3] = parts[1];
15255             }
15256     
15257             return {
15258                 top   :parseFloat(parts[0]) || 0,
15259                 right :parseFloat(parts[1]) || 0,
15260                 bottom:parseFloat(parts[2]) || 0,
15261                 left  :parseFloat(parts[3]) || 0
15262             };
15263         }
15264         
15265     },
15266     
15267     /**
15268      * Parses a number or string representing margin sizes into an object. Supports CSS-style margin declarations
15269      * (e.g. 10, "10", "10 10", "10 10 10" and "10 10 10 10" are all valid options and would return the same result)
15270      * @static
15271      * @param {Number|String} box The encoded margins
15272      * @param {String} units The type of units to add
15273      * @return {String} An string with unitized (px if units is not specified) metrics for top, right, bottom and left
15274      */
15275     unitizeBox : function(box, units) {
15276         var A = this.addUnits,
15277             B = this.parseBox(box);
15278             
15279         return A(B.top, units) + ' ' +
15280                A(B.right, units) + ' ' +
15281                A(B.bottom, units) + ' ' +
15282                A(B.left, units);
15283         
15284     },
15285
15286     // private
15287     camelReplaceFn : function(m, a) {
15288         return a.charAt(1).toUpperCase();
15289     },
15290
15291     /**
15292      * Normalizes CSS property keys from dash delimited to camel case JavaScript Syntax.
15293      * For example:
15294      * <ul>
15295      *  <li>border-width -> borderWidth</li>
15296      *  <li>padding-top -> paddingTop</li>
15297      * </ul>
15298      * @static
15299      * @param {String} prop The property to normalize
15300      * @return {String} The normalized string
15301      */
15302     normalize : function(prop) {
15303         if (prop == 'float') {
15304             prop = Ext.supports.Float ? 'cssFloat' : 'styleFloat';
15305         }
15306         return this.propertyCache[prop] || (this.propertyCache[prop] = prop.replace(this.camelRe, this.camelReplaceFn));
15307     },
15308
15309     /**
15310      * Retrieves the document height
15311      * @static
15312      * @return {Number} documentHeight
15313      */
15314     getDocumentHeight: function() {
15315         return Math.max(!Ext.isStrict ? document.body.scrollHeight : document.documentElement.scrollHeight, this.getViewportHeight());
15316     },
15317
15318     /**
15319      * Retrieves the document width
15320      * @static
15321      * @return {Number} documentWidth
15322      */
15323     getDocumentWidth: function() {
15324         return Math.max(!Ext.isStrict ? document.body.scrollWidth : document.documentElement.scrollWidth, this.getViewportWidth());
15325     },
15326
15327     /**
15328      * Retrieves the viewport height of the window.
15329      * @static
15330      * @return {Number} viewportHeight
15331      */
15332     getViewportHeight: function(){
15333         return window.innerHeight;
15334     },
15335
15336     /**
15337      * Retrieves the viewport width of the window.
15338      * @static
15339      * @return {Number} viewportWidth
15340      */
15341     getViewportWidth : function() {
15342         return window.innerWidth;
15343     },
15344
15345     /**
15346      * Retrieves the viewport size of the window.
15347      * @static
15348      * @return {Object} object containing width and height properties
15349      */
15350     getViewSize : function() {
15351         return {
15352             width: window.innerWidth,
15353             height: window.innerHeight
15354         };
15355     },
15356
15357     /**
15358      * Retrieves the current orientation of the window. This is calculated by
15359      * determing if the height is greater than the width.
15360      * @static
15361      * @return {String} Orientation of window: 'portrait' or 'landscape'
15362      */
15363     getOrientation : function() {
15364         if (Ext.supports.OrientationChange) {
15365             return (window.orientation == 0) ? 'portrait' : 'landscape';
15366         }
15367         
15368         return (window.innerHeight > window.innerWidth) ? 'portrait' : 'landscape';
15369     },
15370
15371     /** 
15372      * Returns the top Element that is located at the passed coordinates
15373      * @static
15374      * @param {Number} x The x coordinate
15375      * @param {Number} x The y coordinate
15376      * @return {String} The found Element
15377      */
15378     fromPoint: function(x, y) {
15379         return Ext.get(document.elementFromPoint(x, y));
15380     },
15381     
15382     /**
15383      * Converts a CSS string into an object with a property for each style.
15384      * <p>
15385      * The sample code below would return an object with 2 properties, one
15386      * for background-color and one for color.</p>
15387      * <pre><code>
15388 var css = 'background-color: red;color: blue; ';
15389 console.log(Ext.core.Element.parseStyles(css));
15390      * </code></pre>
15391      * @static
15392      * @param {String} styles A CSS string
15393      * @return {Object} styles
15394      */
15395     parseStyles: function(styles){
15396         var out = {},
15397             cssRe = this.cssRe,
15398             matches;
15399             
15400         if (styles) {
15401             // Since we're using the g flag on the regex, we need to set the lastIndex.
15402             // This automatically happens on some implementations, but not others, see:
15403             // http://stackoverflow.com/questions/2645273/javascript-regular-expression-literal-persists-between-function-calls
15404             // http://blog.stevenlevithan.com/archives/fixing-javascript-regexp
15405             cssRe.lastIndex = 0;
15406             while ((matches = cssRe.exec(styles))) {
15407                 out[matches[1]] = matches[2];
15408             }
15409         }
15410         return out;
15411     }
15412 });
15413
15414 /**
15415  * @class Ext.CompositeElementLite
15416  * <p>This class encapsulates a <i>collection</i> of DOM elements, providing methods to filter
15417  * members, or to perform collective actions upon the whole set.</p>
15418  * <p>Although they are not listed, this class supports all of the methods of {@link Ext.core.Element} and
15419  * {@link Ext.fx.Anim}. The methods from these classes will be performed on all the elements in this collection.</p>
15420  * Example:<pre><code>
15421 var els = Ext.select("#some-el div.some-class");
15422 // or select directly from an existing element
15423 var el = Ext.get('some-el');
15424 el.select('div.some-class');
15425
15426 els.setWidth(100); // all elements become 100 width
15427 els.hide(true); // all elements fade out and hide
15428 // or
15429 els.setWidth(100).hide(true);
15430 </code></pre>
15431  */
15432 Ext.CompositeElementLite = function(els, root){
15433     /**
15434      * <p>The Array of DOM elements which this CompositeElement encapsulates. Read-only.</p>
15435      * <p>This will not <i>usually</i> be accessed in developers' code, but developers wishing
15436      * to augment the capabilities of the CompositeElementLite class may use it when adding
15437      * methods to the class.</p>
15438      * <p>For example to add the <code>nextAll</code> method to the class to <b>add</b> all
15439      * following siblings of selected elements, the code would be</p><code><pre>
15440 Ext.override(Ext.CompositeElementLite, {
15441     nextAll: function() {
15442         var els = this.elements, i, l = els.length, n, r = [], ri = -1;
15443
15444 //      Loop through all elements in this Composite, accumulating
15445 //      an Array of all siblings.
15446         for (i = 0; i < l; i++) {
15447             for (n = els[i].nextSibling; n; n = n.nextSibling) {
15448                 r[++ri] = n;
15449             }
15450         }
15451
15452 //      Add all found siblings to this Composite
15453         return this.add(r);
15454     }
15455 });</pre></code>
15456      * @type Array
15457      * @property elements
15458      */
15459     this.elements = [];
15460     this.add(els, root);
15461     this.el = new Ext.core.Element.Flyweight();
15462 };
15463
15464 Ext.CompositeElementLite.prototype = {
15465     isComposite: true,
15466
15467     // private
15468     getElement : function(el){
15469         // Set the shared flyweight dom property to the current element
15470         var e = this.el;
15471         e.dom = el;
15472         e.id = el.id;
15473         return e;
15474     },
15475
15476     // private
15477     transformElement : function(el){
15478         return Ext.getDom(el);
15479     },
15480
15481     /**
15482      * Returns the number of elements in this Composite.
15483      * @return Number
15484      */
15485     getCount : function(){
15486         return this.elements.length;
15487     },
15488     /**
15489      * Adds elements to this Composite object.
15490      * @param {Mixed} els Either an Array of DOM elements to add, or another Composite object who's elements should be added.
15491      * @return {CompositeElement} This Composite object.
15492      */
15493     add : function(els, root){
15494         var me = this,
15495             elements = me.elements;
15496         if(!els){
15497             return this;
15498         }
15499         if(typeof els == "string"){
15500             els = Ext.core.Element.selectorFunction(els, root);
15501         }else if(els.isComposite){
15502             els = els.elements;
15503         }else if(!Ext.isIterable(els)){
15504             els = [els];
15505         }
15506
15507         for(var i = 0, len = els.length; i < len; ++i){
15508             elements.push(me.transformElement(els[i]));
15509         }
15510         return me;
15511     },
15512
15513     invoke : function(fn, args){
15514         var me = this,
15515             els = me.elements,
15516             len = els.length,
15517             e,
15518             i;
15519
15520         for(i = 0; i < len; i++) {
15521             e = els[i];
15522             if(e){
15523                 Ext.core.Element.prototype[fn].apply(me.getElement(e), args);
15524             }
15525         }
15526         return me;
15527     },
15528     /**
15529      * Returns a flyweight Element of the dom element object at the specified index
15530      * @param {Number} index
15531      * @return {Ext.core.Element}
15532      */
15533     item : function(index){
15534         var me = this,
15535             el = me.elements[index],
15536             out = null;
15537
15538         if(el){
15539             out = me.getElement(el);
15540         }
15541         return out;
15542     },
15543
15544     // fixes scope with flyweight
15545     addListener : function(eventName, handler, scope, opt){
15546         var els = this.elements,
15547             len = els.length,
15548             i, e;
15549
15550         for(i = 0; i<len; i++) {
15551             e = els[i];
15552             if(e) {
15553                 Ext.EventManager.on(e, eventName, handler, scope || e, opt);
15554             }
15555         }
15556         return this;
15557     },
15558     /**
15559      * <p>Calls the passed function for each element in this composite.</p>
15560      * @param {Function} fn The function to call. The function is passed the following parameters:<ul>
15561      * <li><b>el</b> : Element<div class="sub-desc">The current Element in the iteration.
15562      * <b>This is the flyweight (shared) Ext.core.Element instance, so if you require a
15563      * a reference to the dom node, use el.dom.</b></div></li>
15564      * <li><b>c</b> : Composite<div class="sub-desc">This Composite object.</div></li>
15565      * <li><b>idx</b> : Number<div class="sub-desc">The zero-based index in the iteration.</div></li>
15566      * </ul>
15567      * @param {Object} scope (optional) The scope (<i>this</i> reference) in which the function is executed. (defaults to the Element)
15568      * @return {CompositeElement} this
15569      */
15570     each : function(fn, scope){
15571         var me = this,
15572             els = me.elements,
15573             len = els.length,
15574             i, e;
15575
15576         for(i = 0; i<len; i++) {
15577             e = els[i];
15578             if(e){
15579                 e = this.getElement(e);
15580                 if(fn.call(scope || e, e, me, i) === false){
15581                     break;
15582                 }
15583             }
15584         }
15585         return me;
15586     },
15587
15588     /**
15589     * Clears this Composite and adds the elements passed.
15590     * @param {Mixed} els Either an array of DOM elements, or another Composite from which to fill this Composite.
15591     * @return {CompositeElement} this
15592     */
15593     fill : function(els){
15594         var me = this;
15595         me.elements = [];
15596         me.add(els);
15597         return me;
15598     },
15599
15600     /**
15601      * Filters this composite to only elements that match the passed selector.
15602      * @param {String/Function} selector A string CSS selector or a comparison function.
15603      * The comparison function will be called with the following arguments:<ul>
15604      * <li><code>el</code> : Ext.core.Element<div class="sub-desc">The current DOM element.</div></li>
15605      * <li><code>index</code> : Number<div class="sub-desc">The current index within the collection.</div></li>
15606      * </ul>
15607      * @return {CompositeElement} this
15608      */
15609     filter : function(selector){
15610         var els = [],
15611             me = this,
15612             fn = Ext.isFunction(selector) ? selector
15613                 : function(el){
15614                     return el.is(selector);
15615                 };
15616
15617         me.each(function(el, self, i) {
15618             if (fn(el, i) !== false) {
15619                 els[els.length] = me.transformElement(el);
15620             }
15621         });
15622         
15623         me.elements = els;
15624         return me;
15625     },
15626
15627     /**
15628      * Find the index of the passed element within the composite collection.
15629      * @param el {Mixed} The id of an element, or an Ext.core.Element, or an HtmlElement to find within the composite collection.
15630      * @return Number The index of the passed Ext.core.Element in the composite collection, or -1 if not found.
15631      */
15632     indexOf : function(el){
15633         return Ext.Array.indexOf(this.elements, this.transformElement(el));
15634     },
15635
15636     /**
15637     * Replaces the specified element with the passed element.
15638     * @param {Mixed} el The id of an element, the Element itself, the index of the element in this composite
15639     * to replace.
15640     * @param {Mixed} replacement The id of an element or the Element itself.
15641     * @param {Boolean} domReplace (Optional) True to remove and replace the element in the document too.
15642     * @return {CompositeElement} this
15643     */
15644     replaceElement : function(el, replacement, domReplace){
15645         var index = !isNaN(el) ? el : this.indexOf(el),
15646             d;
15647         if(index > -1){
15648             replacement = Ext.getDom(replacement);
15649             if(domReplace){
15650                 d = this.elements[index];
15651                 d.parentNode.insertBefore(replacement, d);
15652                 Ext.removeNode(d);
15653             }
15654             this.elements.splice(index, 1, replacement);
15655         }
15656         return this;
15657     },
15658
15659     /**
15660      * Removes all elements.
15661      */
15662     clear : function(){
15663         this.elements = [];
15664     }
15665 };
15666
15667 Ext.CompositeElementLite.prototype.on = Ext.CompositeElementLite.prototype.addListener;
15668
15669 /**
15670  * @private
15671  * Copies all of the functions from Ext.core.Element's prototype onto CompositeElementLite's prototype.
15672  * This is called twice - once immediately below, and once again after additional Ext.core.Element
15673  * are added in Ext JS
15674  */
15675 Ext.CompositeElementLite.importElementMethods = function() {
15676     var fnName,
15677         ElProto = Ext.core.Element.prototype,
15678         CelProto = Ext.CompositeElementLite.prototype;
15679
15680     for (fnName in ElProto) {
15681         if (typeof ElProto[fnName] == 'function'){
15682             (function(fnName) {
15683                 CelProto[fnName] = CelProto[fnName] || function() {
15684                     return this.invoke(fnName, arguments);
15685                 };
15686             }).call(CelProto, fnName);
15687
15688         }
15689     }
15690 };
15691
15692 Ext.CompositeElementLite.importElementMethods();
15693
15694 if(Ext.DomQuery){
15695     Ext.core.Element.selectorFunction = Ext.DomQuery.select;
15696 }
15697
15698 /**
15699  * Selects elements based on the passed CSS selector to enable {@link Ext.core.Element Element} methods
15700  * to be applied to many related elements in one statement through the returned {@link Ext.CompositeElement CompositeElement} or
15701  * {@link Ext.CompositeElementLite CompositeElementLite} object.
15702  * @param {String/Array} selector The CSS selector or an array of elements
15703  * @param {HTMLElement/String} root (optional) The root element of the query or id of the root
15704  * @return {CompositeElementLite/CompositeElement}
15705  * @member Ext.core.Element
15706  * @method select
15707  */
15708 Ext.core.Element.select = function(selector, root){
15709     var els;
15710     if(typeof selector == "string"){
15711         els = Ext.core.Element.selectorFunction(selector, root);
15712     }else if(selector.length !== undefined){
15713         els = selector;
15714     }else{
15715         Ext.Error.raise({
15716             sourceClass: "Ext.core.Element",
15717             sourceMethod: "select",
15718             selector: selector,
15719             root: root,
15720             msg: "Invalid selector specified: " + selector
15721         });
15722     }
15723     return new Ext.CompositeElementLite(els);
15724 };
15725 /**
15726  * Selects elements based on the passed CSS selector to enable {@link Ext.core.Element Element} methods
15727  * to be applied to many related elements in one statement through the returned {@link Ext.CompositeElement CompositeElement} or
15728  * {@link Ext.CompositeElementLite CompositeElementLite} object.
15729  * @param {String/Array} selector The CSS selector or an array of elements
15730  * @param {HTMLElement/String} root (optional) The root element of the query or id of the root
15731  * @return {CompositeElementLite/CompositeElement}
15732  * @member Ext
15733  * @method select
15734  */
15735 Ext.select = Ext.core.Element.select;
15736
15737 /**
15738  * @class Ext.util.DelayedTask
15739  * 
15740  * The DelayedTask class provides a convenient way to "buffer" the execution of a method,
15741  * performing setTimeout where a new timeout cancels the old timeout. When called, the
15742  * task will wait the specified time period before executing. If durng that time period,
15743  * the task is called again, the original call will be cancelled. This continues so that
15744  * the function is only called a single time for each iteration.
15745  * 
15746  * This method is especially useful for things like detecting whether a user has finished
15747  * typing in a text field. An example would be performing validation on a keypress. You can
15748  * use this class to buffer the keypress events for a certain number of milliseconds, and
15749  * perform only if they stop for that amount of time.  
15750  * 
15751  * ## Usage
15752  * 
15753  *     var task = new Ext.util.DelayedTask(function(){
15754  *         alert(Ext.getDom('myInputField').value.length);
15755  *     });
15756  *     
15757  *     // Wait 500ms before calling our function. If the user presses another key
15758  *     // during that 500ms, it will be cancelled and we'll wait another 500ms.
15759  *     Ext.get('myInputField').on('keypress', function(){
15760  *         task.{@link #delay}(500);
15761  *     });
15762  * 
15763  * Note that we are using a DelayedTask here to illustrate a point. The configuration
15764  * option `buffer` for {@link Ext.util.Observable#addListener addListener/on} will
15765  * also setup a delayed task for you to buffer events.
15766  * 
15767  * @constructor The parameters to this constructor serve as defaults and are not required.
15768  * @param {Function} fn (optional) The default function to call.
15769  * @param {Object} scope The default scope (The <code><b>this</b></code> reference) in which the
15770  * function is called. If not specified, <code>this</code> will refer to the browser window.
15771  * @param {Array} args (optional) The default Array of arguments.
15772  */
15773 Ext.util.DelayedTask = function(fn, scope, args) {
15774     var me = this,
15775         id,
15776         call = function() {
15777             clearInterval(id);
15778             id = null;
15779             fn.apply(scope, args || []);
15780         };
15781
15782     /**
15783      * Cancels any pending timeout and queues a new one
15784      * @param {Number} delay The milliseconds to delay
15785      * @param {Function} newFn (optional) Overrides function passed to constructor
15786      * @param {Object} newScope (optional) Overrides scope passed to constructor. Remember that if no scope
15787      * is specified, <code>this</code> will refer to the browser window.
15788      * @param {Array} newArgs (optional) Overrides args passed to constructor
15789      */
15790     this.delay = function(delay, newFn, newScope, newArgs) {
15791         me.cancel();
15792         fn = newFn || fn;
15793         scope = newScope || scope;
15794         args = newArgs || args;
15795         id = setInterval(call, delay);
15796     };
15797
15798     /**
15799      * Cancel the last queued timeout
15800      */
15801     this.cancel = function(){
15802         if (id) {
15803             clearInterval(id);
15804             id = null;
15805         }
15806     };
15807 };
15808 Ext.require('Ext.util.DelayedTask', function() {
15809
15810     Ext.util.Event = Ext.extend(Object, (function() {
15811         function createBuffered(handler, listener, o, scope) {
15812             listener.task = new Ext.util.DelayedTask();
15813             return function() {
15814                 listener.task.delay(o.buffer, handler, scope, Ext.Array.toArray(arguments));
15815             };
15816         }
15817
15818         function createDelayed(handler, listener, o, scope) {
15819             return function() {
15820                 var task = new Ext.util.DelayedTask();
15821                 if (!listener.tasks) {
15822                     listener.tasks = [];
15823                 }
15824                 listener.tasks.push(task);
15825                 task.delay(o.delay || 10, handler, scope, Ext.Array.toArray(arguments));
15826             };
15827         }
15828
15829         function createSingle(handler, listener, o, scope) {
15830             return function() {
15831                 listener.ev.removeListener(listener.fn, scope);
15832                 return handler.apply(scope, arguments);
15833             };
15834         }
15835
15836         return {
15837             isEvent: true,
15838
15839             constructor: function(observable, name) {
15840                 this.name = name;
15841                 this.observable = observable;
15842                 this.listeners = [];
15843             },
15844
15845             addListener: function(fn, scope, options) {
15846                 var me = this,
15847                     listener;
15848                     scope = scope || me.observable;
15849
15850                 if (!fn) {
15851                     Ext.Error.raise({
15852                         sourceClass: Ext.getClassName(this.observable),
15853                         sourceMethod: "addListener",
15854                         msg: "The specified callback function is undefined"
15855                     });
15856                 }
15857
15858                 if (!me.isListening(fn, scope)) {
15859                     listener = me.createListener(fn, scope, options);
15860                     if (me.firing) {
15861                         // if we are currently firing this event, don't disturb the listener loop
15862                         me.listeners = me.listeners.slice(0);
15863                     }
15864                     me.listeners.push(listener);
15865                 }
15866             },
15867
15868             createListener: function(fn, scope, o) {
15869                 o = o || {};
15870                 scope = scope || this.observable;
15871
15872                 var listener = {
15873                         fn: fn,
15874                         scope: scope,
15875                         o: o,
15876                         ev: this
15877                     },
15878                     handler = fn;
15879
15880                 // The order is important. The 'single' wrapper must be wrapped by the 'buffer' and 'delayed' wrapper
15881                 // because the event removal that the single listener does destroys the listener's DelayedTask(s)
15882                 if (o.single) {
15883                     handler = createSingle(handler, listener, o, scope);
15884                 }
15885                 if (o.delay) {
15886                     handler = createDelayed(handler, listener, o, scope);
15887                 }
15888                 if (o.buffer) {
15889                     handler = createBuffered(handler, listener, o, scope);
15890                 }
15891
15892                 listener.fireFn = handler;
15893                 return listener;
15894             },
15895
15896             findListener: function(fn, scope) {
15897                 var listeners = this.listeners,
15898                 i = listeners.length,
15899                 listener,
15900                 s;
15901
15902                 while (i--) {
15903                     listener = listeners[i];
15904                     if (listener) {
15905                         s = listener.scope;
15906                         if (listener.fn == fn && (s == scope || s == this.observable)) {
15907                             return i;
15908                         }
15909                     }
15910                 }
15911
15912                 return - 1;
15913             },
15914
15915             isListening: function(fn, scope) {
15916                 return this.findListener(fn, scope) !== -1;
15917             },
15918
15919             removeListener: function(fn, scope) {
15920                 var me = this,
15921                     index,
15922                     listener,
15923                     k;
15924                 index = me.findListener(fn, scope);
15925                 if (index != -1) {
15926                     listener = me.listeners[index];
15927
15928                     if (me.firing) {
15929                         me.listeners = me.listeners.slice(0);
15930                     }
15931
15932                     // cancel and remove a buffered handler that hasn't fired yet
15933                     if (listener.task) {
15934                         listener.task.cancel();
15935                         delete listener.task;
15936                     }
15937
15938                     // cancel and remove all delayed handlers that haven't fired yet
15939                     k = listener.tasks && listener.tasks.length;
15940                     if (k) {
15941                         while (k--) {
15942                             listener.tasks[k].cancel();
15943                         }
15944                         delete listener.tasks;
15945                     }
15946
15947                     // remove this listener from the listeners array
15948                     me.listeners.splice(index, 1);
15949                     return true;
15950                 }
15951
15952                 return false;
15953             },
15954
15955             // Iterate to stop any buffered/delayed events
15956             clearListeners: function() {
15957                 var listeners = this.listeners,
15958                     i = listeners.length;
15959
15960                 while (i--) {
15961                     this.removeListener(listeners[i].fn, listeners[i].scope);
15962                 }
15963             },
15964
15965             fire: function() {
15966                 var me = this,
15967                     listeners = me.listeners,
15968                     count = listeners.length,
15969                     i,
15970                     args,
15971                     listener;
15972
15973                 if (count > 0) {
15974                     me.firing = true;
15975                     for (i = 0; i < count; i++) {
15976                         listener = listeners[i];
15977                         args = arguments.length ? Array.prototype.slice.call(arguments, 0) : [];
15978                         if (listener.o) {
15979                             args.push(listener.o);
15980                         }
15981                         if (listener && listener.fireFn.apply(listener.scope || me.observable, args) === false) {
15982                             return (me.firing = false);
15983                         }
15984                     }
15985                 }
15986                 me.firing = false;
15987                 return true;
15988             }
15989         };
15990     })());
15991 });
15992
15993 /**
15994  * @class Ext.EventManager
15995  * Registers event handlers that want to receive a normalized EventObject instead of the standard browser event and provides
15996  * several useful events directly.
15997  * See {@link Ext.EventObject} for more details on normalized event objects.
15998  * @singleton
15999  */
16000 Ext.EventManager = {
16001
16002     // --------------------- onReady ---------------------
16003
16004     /**
16005      * Check if we have bound our global onReady listener
16006      * @private
16007      */
16008     hasBoundOnReady: false,
16009
16010     /**
16011      * Check if fireDocReady has been called
16012      * @private
16013      */
16014     hasFiredReady: false,
16015
16016     /**
16017      * Timer for the document ready event in old IE versions
16018      * @private
16019      */
16020     readyTimeout: null,
16021
16022     /**
16023      * Checks if we have bound an onreadystatechange event
16024      * @private
16025      */
16026     hasOnReadyStateChange: false,
16027
16028     /**
16029      * Holds references to any onReady functions
16030      * @private
16031      */
16032     readyEvent: new Ext.util.Event(),
16033
16034     /**
16035      * Check the ready state for old IE versions
16036      * @private
16037      * @return {Boolean} True if the document is ready
16038      */
16039     checkReadyState: function(){
16040         var me = Ext.EventManager;
16041
16042         if(window.attachEvent){
16043             // See here for reference: http://javascript.nwbox.com/IEContentLoaded/
16044             if (window != top) {
16045                 return false;
16046             }
16047             try{
16048                 document.documentElement.doScroll('left');
16049             }catch(e){
16050                 return false;
16051             }
16052             me.fireDocReady();
16053             return true;
16054         }
16055         if (document.readyState == 'complete') {
16056             me.fireDocReady();
16057             return true;
16058         }
16059         me.readyTimeout = setTimeout(arguments.callee, 2);
16060         return false;
16061     },
16062
16063     /**
16064      * Binds the appropriate browser event for checking if the DOM has loaded.
16065      * @private
16066      */
16067     bindReadyEvent: function(){
16068         var me = Ext.EventManager;
16069         if (me.hasBoundOnReady) {
16070             return;
16071         }
16072
16073         if (document.addEventListener) {
16074             document.addEventListener('DOMContentLoaded', me.fireDocReady, false);
16075             // fallback, load will ~always~ fire
16076             window.addEventListener('load', me.fireDocReady, false);
16077         } else {
16078             // check if the document is ready, this will also kick off the scroll checking timer
16079             if (!me.checkReadyState()) {
16080                 document.attachEvent('onreadystatechange', me.checkReadyState);
16081                 me.hasOnReadyStateChange = true;
16082             }
16083             // fallback, onload will ~always~ fire
16084             window.attachEvent('onload', me.fireDocReady, false);
16085         }
16086         me.hasBoundOnReady = true;
16087     },
16088
16089     /**
16090      * We know the document is loaded, so trigger any onReady events.
16091      * @private
16092      */
16093     fireDocReady: function(){
16094         var me = Ext.EventManager;
16095
16096         // only unbind these events once
16097         if (!me.hasFiredReady) {
16098             me.hasFiredReady = true;
16099
16100             if (document.addEventListener) {
16101                 document.removeEventListener('DOMContentLoaded', me.fireDocReady, false);
16102                 window.removeEventListener('load', me.fireDocReady, false);
16103             } else {
16104                 if (me.readyTimeout !== null) {
16105                     clearTimeout(me.readyTimeout);
16106                 }
16107                 if (me.hasOnReadyStateChange) {
16108                     document.detachEvent('onreadystatechange', me.checkReadyState);
16109                 }
16110                 window.detachEvent('onload', me.fireDocReady);
16111             }
16112             Ext.supports.init();
16113         }
16114         if (!Ext.isReady) {
16115             Ext.isReady = true;
16116             me.onWindowUnload();
16117             me.readyEvent.fire();
16118         }
16119     },
16120
16121     /**
16122      * Adds a listener to be notified when the document is ready (before onload and before images are loaded). Can be
16123      * accessed shorthanded as Ext.onReady().
16124      * @param {Function} fn The method the event invokes.
16125      * @param {Object} scope (optional) The scope (<code>this</code> reference) in which the handler function executes. Defaults to the browser window.
16126      * @param {boolean} options (optional) Options object as passed to {@link Ext.core.Element#addListener}.
16127      */
16128     onDocumentReady: function(fn, scope, options){
16129         options = options || {};
16130         var me = Ext.EventManager,
16131             readyEvent = me.readyEvent;
16132
16133         // force single to be true so our event is only ever fired once.
16134         options.single = true;
16135
16136         // Document already loaded, let's just fire it
16137         if (Ext.isReady) {
16138             readyEvent.addListener(fn, scope, options);
16139             readyEvent.fire();
16140         } else {
16141             options.delay = options.delay || 1;
16142             readyEvent.addListener(fn, scope, options);
16143             me.bindReadyEvent();
16144         }
16145     },
16146
16147
16148     // --------------------- event binding ---------------------
16149
16150     /**
16151      * Contains a list of all document mouse downs, so we can ensure they fire even when stopEvent is called.
16152      * @private
16153      */
16154     stoppedMouseDownEvent: new Ext.util.Event(),
16155
16156     /**
16157      * Options to parse for the 4th argument to addListener.
16158      * @private
16159      */
16160     propRe: /^(?:scope|delay|buffer|single|stopEvent|preventDefault|stopPropagation|normalized|args|delegate|freezeEvent)$/,
16161
16162     /**
16163      * Get the id of the element. If one has not been assigned, automatically assign it.
16164      * @param {Mixed} element The element to get the id for.
16165      * @return {String} id
16166      */
16167     getId : function(element) {
16168         var skipGarbageCollection = false,
16169             id;
16170     
16171         element = Ext.getDom(element);
16172     
16173         if (element === document || element === window) {
16174             id = element === document ? Ext.documentId : Ext.windowId;
16175         }
16176         else {
16177             id = Ext.id(element);
16178         }
16179         // skip garbage collection for special elements (window, document, iframes)
16180         if (element && (element.getElementById || element.navigator)) {
16181             skipGarbageCollection = true;
16182         }
16183     
16184         if (!Ext.cache[id]){
16185             Ext.core.Element.addToCache(new Ext.core.Element(element), id);
16186             if (skipGarbageCollection) {
16187                 Ext.cache[id].skipGarbageCollection = true;
16188             }
16189         }
16190         return id;
16191     },
16192
16193     /**
16194      * Convert a "config style" listener into a set of flat arguments so they can be passed to addListener
16195      * @private
16196      * @param {Object} element The element the event is for
16197      * @param {Object} event The event configuration
16198      * @param {Object} isRemove True if a removal should be performed, otherwise an add will be done.
16199      */
16200     prepareListenerConfig: function(element, config, isRemove){
16201         var me = this,
16202             propRe = me.propRe,
16203             key, value, args;
16204
16205         // loop over all the keys in the object
16206         for (key in config) {
16207             if (config.hasOwnProperty(key)) {
16208                 // if the key is something else then an event option
16209                 if (!propRe.test(key)) {
16210                     value = config[key];
16211                     // if the value is a function it must be something like click: function(){}, scope: this
16212                     // which means that there might be multiple event listeners with shared options
16213                     if (Ext.isFunction(value)) {
16214                         // shared options
16215                         args = [element, key, value, config.scope, config];
16216                     } else {
16217                         // if its not a function, it must be an object like click: {fn: function(){}, scope: this}
16218                         args = [element, key, value.fn, value.scope, value];
16219                     }
16220
16221                     if (isRemove === true) {
16222                         me.removeListener.apply(this, args);
16223                     } else {
16224                         me.addListener.apply(me, args);
16225                     }
16226                 }
16227             }
16228         }
16229     },
16230
16231     /**
16232      * Normalize cross browser event differences
16233      * @private
16234      * @param {Object} eventName The event name
16235      * @param {Object} fn The function to execute
16236      * @return {Object} The new event name/function
16237      */
16238     normalizeEvent: function(eventName, fn){
16239         if (/mouseenter|mouseleave/.test(eventName) && !Ext.supports.MouseEnterLeave) {
16240             if (fn) {
16241                 fn = Ext.Function.createInterceptor(fn, this.contains, this);
16242             }
16243             eventName = eventName == 'mouseenter' ? 'mouseover' : 'mouseout';
16244         } else if (eventName == 'mousewheel' && !Ext.supports.MouseWheel && !Ext.isOpera){
16245             eventName = 'DOMMouseScroll';
16246         }
16247         return {
16248             eventName: eventName,
16249             fn: fn
16250         };
16251     },
16252
16253     /**
16254      * Checks whether the event's relatedTarget is contained inside (or <b>is</b>) the element.
16255      * @private
16256      * @param {Object} event
16257      */
16258     contains: function(event){
16259         var parent = event.browserEvent.currentTarget,
16260             child = this.getRelatedTarget(event);
16261
16262         if (parent && parent.firstChild) {
16263             while (child) {
16264                 if (child === parent) {
16265                     return false;
16266                 }
16267                 child = child.parentNode;
16268                 if (child && (child.nodeType != 1)) {
16269                     child = null;
16270                 }
16271             }
16272         }
16273         return true;
16274     },
16275
16276     /**
16277     * Appends an event handler to an element.  The shorthand version {@link #on} is equivalent.  Typically you will
16278     * use {@link Ext.core.Element#addListener} directly on an Element in favor of calling this version.
16279     * @param {String/HTMLElement} el The html element or id to assign the event handler to.
16280     * @param {String} eventName The name of the event to listen for.
16281     * @param {Function} handler The handler function the event invokes. This function is passed
16282     * the following parameters:<ul>
16283     * <li>evt : EventObject<div class="sub-desc">The {@link Ext.EventObject EventObject} describing the event.</div></li>
16284     * <li>t : Element<div class="sub-desc">The {@link Ext.core.Element Element} which was the target of the event.
16285     * Note that this may be filtered by using the <tt>delegate</tt> option.</div></li>
16286     * <li>o : Object<div class="sub-desc">The options object from the addListener call.</div></li>
16287     * </ul>
16288     * @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>.
16289     * @param {Object} options (optional) An object containing handler configuration properties.
16290     * This may contain any of the following properties:<ul>
16291     * <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>
16292     * <li>delegate : String<div class="sub-desc">A simple selector to filter the target or look for a descendant of the target</div></li>
16293     * <li>stopEvent : Boolean<div class="sub-desc">True to stop the event. That is stop propagation, and prevent the default action.</div></li>
16294     * <li>preventDefault : Boolean<div class="sub-desc">True to prevent the default action</div></li>
16295     * <li>stopPropagation : Boolean<div class="sub-desc">True to prevent event propagation</div></li>
16296     * <li>normalized : Boolean<div class="sub-desc">False to pass a browser event to the handler function instead of an Ext.EventObject</div></li>
16297     * <li>delay : Number<div class="sub-desc">The number of milliseconds to delay the invocation of the handler after te event fires.</div></li>
16298     * <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>
16299     * <li>buffer : Number<div class="sub-desc">Causes the handler to be scheduled to run in an {@link Ext.util.DelayedTask} delayed
16300     * by the specified number of milliseconds. If the event fires again within that time, the original
16301     * handler is <em>not</em> invoked, but the new handler is scheduled in its place.</div></li>
16302     * <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>
16303     * </ul><br>
16304     * <p>See {@link Ext.core.Element#addListener} for examples of how to use these options.</p>
16305     */
16306     addListener: function(element, eventName, fn, scope, options){
16307         // Check if we've been passed a "config style" event.
16308         if (Ext.isObject(eventName)) {
16309             this.prepareListenerConfig(element, eventName);
16310             return;
16311         }
16312
16313         var dom = Ext.getDom(element),
16314             bind,
16315             wrap;
16316
16317         if (!dom){
16318             Ext.Error.raise({
16319                 sourceClass: 'Ext.EventManager',
16320                 sourceMethod: 'addListener',
16321                 targetElement: element,
16322                 eventName: eventName,
16323                 msg: 'Error adding "' + eventName + '\" listener for nonexistent element "' + element + '"'
16324             });
16325         }
16326         if (!fn) {
16327             Ext.Error.raise({
16328                 sourceClass: 'Ext.EventManager',
16329                 sourceMethod: 'addListener',
16330                 targetElement: element,
16331                 eventName: eventName,
16332                 msg: 'Error adding "' + eventName + '\" listener. The handler function is undefined.'
16333             });
16334         }
16335
16336         // create the wrapper function
16337         options = options || {};
16338
16339         bind = this.normalizeEvent(eventName, fn);
16340         wrap = this.createListenerWrap(dom, eventName, bind.fn, scope, options);
16341
16342
16343         if (dom.attachEvent) {
16344             dom.attachEvent('on' + bind.eventName, wrap);
16345         } else {
16346             dom.addEventListener(bind.eventName, wrap, options.capture || false);
16347         }
16348
16349         if (dom == document && eventName == 'mousedown') {
16350             this.stoppedMouseDownEvent.addListener(wrap);
16351         }
16352
16353         // add all required data into the event cache
16354         this.getEventListenerCache(dom, eventName).push({
16355             fn: fn,
16356             wrap: wrap,
16357             scope: scope
16358         });
16359     },
16360
16361     /**
16362     * Removes an event handler from an element.  The shorthand version {@link #un} is equivalent.  Typically
16363     * you will use {@link Ext.core.Element#removeListener} directly on an Element in favor of calling this version.
16364     * @param {String/HTMLElement} el The id or html element from which to remove the listener.
16365     * @param {String} eventName The name of the event.
16366     * @param {Function} fn The handler function to remove. <b>This must be a reference to the function passed into the {@link #addListener} call.</b>
16367     * @param {Object} scope If a scope (<b><code>this</code></b> reference) was specified when the listener was added,
16368     * then this must refer to the same object.
16369     */
16370     removeListener : function(element, eventName, fn, scope) {
16371         // handle our listener config object syntax
16372         if (Ext.isObject(eventName)) {
16373             this.prepareListenerConfig(element, eventName, true);
16374             return;
16375         }
16376
16377         var dom = Ext.getDom(element),
16378             cache = this.getEventListenerCache(dom, eventName),
16379             bindName = this.normalizeEvent(eventName).eventName,
16380             i = cache.length, j,
16381             listener, wrap, tasks;
16382
16383
16384         while (i--) {
16385             listener = cache[i];
16386
16387             if (listener && (!fn || listener.fn == fn) && (!scope || listener.scope === scope)) {
16388                 wrap = listener.wrap;
16389
16390                 // clear buffered calls
16391                 if (wrap.task) {
16392                     clearTimeout(wrap.task);
16393                     delete wrap.task;
16394                 }
16395
16396                 // clear delayed calls
16397                 j = wrap.tasks && wrap.tasks.length;
16398                 if (j) {
16399                     while (j--) {
16400                         clearTimeout(wrap.tasks[j]);
16401                     }
16402                     delete wrap.tasks;
16403                 }
16404
16405                 if (dom.detachEvent) {
16406                     dom.detachEvent('on' + bindName, wrap);
16407                 } else {
16408                     dom.removeEventListener(bindName, wrap, false);
16409                 }
16410
16411                 if (wrap && dom == document && eventName == 'mousedown') {
16412                     this.stoppedMouseDownEvent.removeListener(wrap);
16413                 }
16414
16415                 // remove listener from cache
16416                 cache.splice(i, 1);
16417             }
16418         }
16419     },
16420
16421     /**
16422     * Removes all event handers from an element.  Typically you will use {@link Ext.core.Element#removeAllListeners}
16423     * directly on an Element in favor of calling this version.
16424     * @param {String/HTMLElement} el The id or html element from which to remove all event handlers.
16425     */
16426     removeAll : function(element){
16427         var dom = Ext.getDom(element),
16428             cache, ev;
16429         if (!dom) {
16430             return;
16431         }
16432         cache = this.getElementEventCache(dom);
16433
16434         for (ev in cache) {
16435             if (cache.hasOwnProperty(ev)) {
16436                 this.removeListener(dom, ev);
16437             }
16438         }
16439         Ext.cache[dom.id].events = {};
16440     },
16441
16442     /**
16443      * Recursively removes all previous added listeners from an element and its children. Typically you will use {@link Ext.core.Element#purgeAllListeners}
16444      * directly on an Element in favor of calling this version.
16445      * @param {String/HTMLElement} el The id or html element from which to remove all event handlers.
16446      * @param {String} eventName (optional) The name of the event.
16447      */
16448     purgeElement : function(element, eventName) {
16449         var dom = Ext.getDom(element),
16450             i = 0, len;
16451
16452         if(eventName) {
16453             this.removeListener(dom, eventName);
16454         }
16455         else {
16456             this.removeAll(dom);
16457         }
16458
16459         if(dom && dom.childNodes) {
16460             for(len = element.childNodes.length; i < len; i++) {
16461                 this.purgeElement(element.childNodes[i], eventName);
16462             }
16463         }
16464     },
16465
16466     /**
16467      * Create the wrapper function for the event
16468      * @private
16469      * @param {HTMLElement} dom The dom element
16470      * @param {String} ename The event name
16471      * @param {Function} fn The function to execute
16472      * @param {Object} scope The scope to execute callback in
16473      * @param {Object} o The options
16474      */
16475     createListenerWrap : function(dom, ename, fn, scope, options) {
16476         options = !Ext.isObject(options) ? {} : options;
16477
16478         var f = ['if(!Ext) {return;}'],
16479             gen;
16480
16481         if(options.buffer || options.delay || options.freezeEvent) {
16482             f.push('e = new Ext.EventObjectImpl(e, ' + (options.freezeEvent ? 'true' : 'false' ) + ');');
16483         } else {
16484             f.push('e = Ext.EventObject.setEvent(e);');
16485         }
16486
16487         if (options.delegate) {
16488             f.push('var t = e.getTarget("' + options.delegate + '", this);');
16489             f.push('if(!t) {return;}');
16490         } else {
16491             f.push('var t = e.target;');
16492         }
16493
16494         if (options.target) {
16495             f.push('if(e.target !== options.target) {return;}');
16496         }
16497
16498         if(options.stopEvent) {
16499             f.push('e.stopEvent();');
16500         } else {
16501             if(options.preventDefault) {
16502                 f.push('e.preventDefault();');
16503             }
16504             if(options.stopPropagation) {
16505                 f.push('e.stopPropagation();');
16506             }
16507         }
16508
16509         if(options.normalized === false) {
16510             f.push('e = e.browserEvent;');
16511         }
16512
16513         if(options.buffer) {
16514             f.push('(wrap.task && clearTimeout(wrap.task));');
16515             f.push('wrap.task = setTimeout(function(){');
16516         }
16517
16518         if(options.delay) {
16519             f.push('wrap.tasks = wrap.tasks || [];');
16520             f.push('wrap.tasks.push(setTimeout(function(){');
16521         }
16522
16523         // finally call the actual handler fn
16524         f.push('fn.call(scope || dom, e, t, options);');
16525
16526         if(options.single) {
16527             f.push('Ext.EventManager.removeListener(dom, ename, fn, scope);');
16528         }
16529
16530         if(options.delay) {
16531             f.push('}, ' + options.delay + '));');
16532         }
16533
16534         if(options.buffer) {
16535             f.push('}, ' + options.buffer + ');');
16536         }
16537
16538         gen = Ext.functionFactory('e', 'options', 'fn', 'scope', 'ename', 'dom', 'wrap', 'args', f.join('\n'));
16539
16540         return function wrap(e, args) {
16541             gen.call(dom, e, options, fn, scope, ename, dom, wrap, args);
16542         };
16543     },
16544
16545     /**
16546      * Get the event cache for a particular element for a particular event
16547      * @private
16548      * @param {HTMLElement} element The element
16549      * @param {Object} eventName The event name
16550      * @return {Array} The events for the element
16551      */
16552     getEventListenerCache : function(element, eventName) {
16553         var eventCache = this.getElementEventCache(element);
16554         return eventCache[eventName] || (eventCache[eventName] = []);
16555     },
16556
16557     /**
16558      * Gets the event cache for the object
16559      * @private
16560      * @param {HTMLElement} element The element
16561      * @return {Object} The event cache for the object
16562      */
16563     getElementEventCache : function(element) {
16564         var elementCache = Ext.cache[this.getId(element)];
16565         return elementCache.events || (elementCache.events = {});
16566     },
16567
16568     // --------------------- utility methods ---------------------
16569     mouseLeaveRe: /(mouseout|mouseleave)/,
16570     mouseEnterRe: /(mouseover|mouseenter)/,
16571
16572     /**
16573      * Stop the event (preventDefault and stopPropagation)
16574      * @param {Event} The event to stop
16575      */
16576     stopEvent: function(event) {
16577         this.stopPropagation(event);
16578         this.preventDefault(event);
16579     },
16580
16581     /**
16582      * Cancels bubbling of the event.
16583      * @param {Event} The event to stop bubbling.
16584      */
16585     stopPropagation: function(event) {
16586         event = event.browserEvent || event;
16587         if (event.stopPropagation) {
16588             event.stopPropagation();
16589         } else {
16590             event.cancelBubble = true;
16591         }
16592     },
16593
16594     /**
16595      * Prevents the browsers default handling of the event.
16596      * @param {Event} The event to prevent the default
16597      */
16598     preventDefault: function(event) {
16599         event = event.browserEvent || event;
16600         if (event.preventDefault) {
16601             event.preventDefault();
16602         } else {
16603             event.returnValue = false;
16604             // Some keys events require setting the keyCode to -1 to be prevented
16605             try {
16606               // all ctrl + X and F1 -> F12
16607               if (event.ctrlKey || event.keyCode > 111 && event.keyCode < 124) {
16608                   event.keyCode = -1;
16609               }
16610             } catch (e) {
16611                 // see this outdated document http://support.microsoft.com/kb/934364/en-us for more info
16612             }
16613         }
16614     },
16615
16616     /**
16617      * Gets the related target from the event.
16618      * @param {Object} event The event
16619      * @return {HTMLElement} The related target.
16620      */
16621     getRelatedTarget: function(event) {
16622         event = event.browserEvent || event;
16623         var target = event.relatedTarget;
16624         if (!target) {
16625             if (this.mouseLeaveRe.test(event.type)) {
16626                 target = event.toElement;
16627             } else if (this.mouseEnterRe.test(event.type)) {
16628                 target = event.fromElement;
16629             }
16630         }
16631         return this.resolveTextNode(target);
16632     },
16633
16634     /**
16635      * Gets the x coordinate from the event
16636      * @param {Object} event The event
16637      * @return {Number} The x coordinate
16638      */
16639     getPageX: function(event) {
16640         return this.getXY(event)[0];
16641     },
16642
16643     /**
16644      * Gets the y coordinate from the event
16645      * @param {Object} event The event
16646      * @return {Number} The y coordinate
16647      */
16648     getPageY: function(event) {
16649         return this.getXY(event)[1];
16650     },
16651
16652     /**
16653      * Gets the x & ycoordinate from the event
16654      * @param {Object} event The event
16655      * @return {Array} The x/y coordinate
16656      */
16657     getPageXY: function(event) {
16658         event = event.browserEvent || event;
16659         var x = event.pageX,
16660             y = event.pageY,
16661             doc = document.documentElement,
16662             body = document.body;
16663
16664         // pageX/pageY not available (undefined, not null), use clientX/clientY instead
16665         if (!x && x !== 0) {
16666             x = event.clientX + (doc && doc.scrollLeft || body && body.scrollLeft || 0) - (doc && doc.clientLeft || body && body.clientLeft || 0);
16667             y = event.clientY + (doc && doc.scrollTop  || body && body.scrollTop  || 0) - (doc && doc.clientTop  || body && body.clientTop  || 0);
16668         }
16669         return [x, y];
16670     },
16671
16672     /**
16673      * Gets the target of the event.
16674      * @param {Object} event The event
16675      * @return {HTMLElement} target
16676      */
16677     getTarget: function(event) {
16678         event = event.browserEvent || event;
16679         return this.resolveTextNode(event.target || event.srcElement);
16680     },
16681
16682     /**
16683      * Resolve any text nodes accounting for browser differences.
16684      * @private
16685      * @param {HTMLElement} node The node
16686      * @return {HTMLElement} The resolved node
16687      */
16688     // 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.
16689     resolveTextNode: Ext.isGecko ?
16690         function(node) {
16691             if (!node) {
16692                 return;
16693             }
16694             // work around firefox bug, https://bugzilla.mozilla.org/show_bug.cgi?id=101197
16695             var s = HTMLElement.prototype.toString.call(node);
16696             if (s == '[xpconnect wrapped native prototype]' || s == '[object XULElement]') {
16697                 return;
16698             }
16699                 return node.nodeType == 3 ? node.parentNode: node;
16700             }: function(node) {
16701                 return node && node.nodeType == 3 ? node.parentNode: node;
16702             },
16703
16704     // --------------------- custom event binding ---------------------
16705
16706     // Keep track of the current width/height
16707     curWidth: 0,
16708     curHeight: 0,
16709
16710     /**
16711      * Adds a listener to be notified when the browser window is resized and provides resize event buffering (100 milliseconds),
16712      * passes new viewport width and height to handlers.
16713      * @param {Function} fn      The handler function the window resize event invokes.
16714      * @param {Object}   scope   The scope (<code>this</code> reference) in which the handler function executes. Defaults to the browser window.
16715      * @param {boolean}  options Options object as passed to {@link Ext.core.Element#addListener}
16716      */
16717     onWindowResize: function(fn, scope, options){
16718         var resize = this.resizeEvent;
16719         if(!resize){
16720             this.resizeEvent = resize = new Ext.util.Event();
16721             this.on(window, 'resize', this.fireResize, this, {buffer: 100});
16722         }
16723         resize.addListener(fn, scope, options);
16724     },
16725
16726     /**
16727      * Fire the resize event.
16728      * @private
16729      */
16730     fireResize: function(){
16731         var me = this,
16732             w = Ext.core.Element.getViewWidth(),
16733             h = Ext.core.Element.getViewHeight();
16734
16735          //whacky problem in IE where the resize event will sometimes fire even though the w/h are the same.
16736          if(me.curHeight != h || me.curWidth != w){
16737              me.curHeight = h;
16738              me.curWidth = w;
16739              me.resizeEvent.fire(w, h);
16740          }
16741     },
16742
16743     /**
16744      * Removes the passed window resize listener.
16745      * @param {Function} fn        The method the event invokes
16746      * @param {Object}   scope    The scope of handler
16747      */
16748     removeResizeListener: function(fn, scope){
16749         if (this.resizeEvent) {
16750             this.resizeEvent.removeListener(fn, scope);
16751         }
16752     },
16753
16754     onWindowUnload: function() {
16755         var unload = this.unloadEvent;
16756         if (!unload) {
16757             this.unloadEvent = unload = new Ext.util.Event();
16758             this.addListener(window, 'unload', this.fireUnload, this);
16759         }
16760     },
16761
16762     /**
16763      * Fires the unload event for items bound with onWindowUnload
16764      * @private
16765      */
16766     fireUnload: function() {
16767         // wrap in a try catch, could have some problems during unload
16768         try {
16769             this.removeUnloadListener();
16770             // Work around FF3 remembering the last scroll position when refreshing the grid and then losing grid view
16771             if (Ext.isGecko3) {
16772                 var gridviews = Ext.ComponentQuery.query('gridview'),
16773                     i = 0,
16774                     ln = gridviews.length;
16775                 for (; i < ln; i++) {
16776                     gridviews[i].scrollToTop();
16777                 }
16778             }
16779             // Purge all elements in the cache
16780             var el,
16781                 cache = Ext.cache;
16782             for (el in cache) {
16783                 if (cache.hasOwnProperty(el)) {
16784                     Ext.EventManager.removeAll(el);
16785                 }
16786             }
16787         } catch(e) {
16788         }
16789     },
16790
16791     /**
16792      * Removes the passed window unload listener.
16793      * @param {Function} fn        The method the event invokes
16794      * @param {Object}   scope    The scope of handler
16795      */
16796     removeUnloadListener: function(){
16797         if (this.unloadEvent) {
16798             this.removeListener(window, 'unload', this.fireUnload);
16799         }
16800     },
16801
16802     /**
16803      * note 1: IE fires ONLY the keydown event on specialkey autorepeat
16804      * note 2: Safari < 3.1, Gecko (Mac/Linux) & Opera fire only the keypress event on specialkey autorepeat
16805      * (research done by @Jan Wolter at http://unixpapa.com/js/key.html)
16806      * @private
16807      */
16808     useKeyDown: Ext.isWebKit ?
16809                    parseInt(navigator.userAgent.match(/AppleWebKit\/(\d+)/)[1], 10) >= 525 :
16810                    !((Ext.isGecko && !Ext.isWindows) || Ext.isOpera),
16811
16812     /**
16813      * Indicates which event to use for getting key presses.
16814      * @return {String} The appropriate event name.
16815      */
16816     getKeyEvent: function(){
16817         return this.useKeyDown ? 'keydown' : 'keypress';
16818     }
16819 };
16820
16821 /**
16822  * Alias for {@link Ext.Loader#onReady Ext.Loader.onReady} with withDomReady set to true
16823  * @member Ext
16824  * @method onReady
16825  */
16826 Ext.onReady = function(fn, scope, options) {
16827     Ext.Loader.onReady(fn, scope, true, options);
16828 };
16829
16830 /**
16831  * Alias for {@link Ext.EventManager#onDocumentReady Ext.EventManager.onDocumentReady}
16832  * @member Ext
16833  * @method onDocumentReady
16834  */
16835 Ext.onDocumentReady = Ext.EventManager.onDocumentReady;
16836
16837 /**
16838  * Alias for {@link Ext.EventManager#addListener Ext.EventManager.addListener}
16839  * @member Ext.EventManager
16840  * @method on
16841  */
16842 Ext.EventManager.on = Ext.EventManager.addListener;
16843
16844 /**
16845  * Alias for {@link Ext.EventManager#removeListener Ext.EventManager.removeListener}
16846  * @member Ext.EventManager
16847  * @method un
16848  */
16849 Ext.EventManager.un = Ext.EventManager.removeListener;
16850
16851 (function(){
16852     var initExtCss = function() {
16853         // find the body element
16854         var bd = document.body || document.getElementsByTagName('body')[0],
16855             baseCSSPrefix = Ext.baseCSSPrefix,
16856             cls = [],
16857             htmlCls = [],
16858             html;
16859
16860         if (!bd) {
16861             return false;
16862         }
16863
16864         html = bd.parentNode;
16865
16866         //Let's keep this human readable!
16867         if (Ext.isIE) {
16868             cls.push(baseCSSPrefix + 'ie');
16869         }
16870         if (Ext.isIE6) {
16871             cls.push(baseCSSPrefix + 'ie6');
16872         }
16873         if (Ext.isIE7) {
16874             cls.push(baseCSSPrefix + 'ie7');
16875         }
16876         if (Ext.isIE8) {
16877             cls.push(baseCSSPrefix + 'ie8');
16878         }
16879         if (Ext.isIE9) {
16880             cls.push(baseCSSPrefix + 'ie9');
16881         }
16882         if (Ext.isGecko) {
16883             cls.push(baseCSSPrefix + 'gecko');
16884         }
16885         if (Ext.isGecko3) {
16886             cls.push(baseCSSPrefix + 'gecko3');
16887         }
16888         if (Ext.isGecko4) {
16889             cls.push(baseCSSPrefix + 'gecko4');
16890         }
16891         if (Ext.isOpera) {
16892             cls.push(baseCSSPrefix + 'opera');
16893         }
16894         if (Ext.isWebKit) {
16895             cls.push(baseCSSPrefix + 'webkit');
16896         }
16897         if (Ext.isSafari) {
16898             cls.push(baseCSSPrefix + 'safari');
16899         }
16900         if (Ext.isSafari2) {
16901             cls.push(baseCSSPrefix + 'safari2');
16902         }
16903         if (Ext.isSafari3) {
16904             cls.push(baseCSSPrefix + 'safari3');
16905         }
16906         if (Ext.isSafari4) {
16907             cls.push(baseCSSPrefix + 'safari4');
16908         }
16909         if (Ext.isChrome) {
16910             cls.push(baseCSSPrefix + 'chrome');
16911         }
16912         if (Ext.isMac) {
16913             cls.push(baseCSSPrefix + 'mac');
16914         }
16915         if (Ext.isLinux) {
16916             cls.push(baseCSSPrefix + 'linux');
16917         }
16918         if (!Ext.supports.CSS3BorderRadius) {
16919             cls.push(baseCSSPrefix + 'nbr');
16920         }
16921         if (!Ext.supports.CSS3LinearGradient) {
16922             cls.push(baseCSSPrefix + 'nlg');
16923         }
16924         if (!Ext.scopeResetCSS) {
16925             cls.push(baseCSSPrefix + 'reset');
16926         }
16927
16928         // add to the parent to allow for selectors x-strict x-border-box, also set the isBorderBox property correctly
16929         if (html) {
16930             if (Ext.isStrict && (Ext.isIE6 || Ext.isIE7)) {
16931                 Ext.isBorderBox = false;
16932             }
16933             else {
16934                 Ext.isBorderBox = true;
16935             }
16936
16937             htmlCls.push(baseCSSPrefix + (Ext.isBorderBox ? 'border-box' : 'strict'));
16938             if (!Ext.isStrict) {
16939                 htmlCls.push(baseCSSPrefix + 'quirks');
16940                 if (Ext.isIE && !Ext.isStrict) {
16941                     Ext.isIEQuirks = true;
16942                 }
16943             }
16944             Ext.fly(html, '_internal').addCls(htmlCls);
16945         }
16946
16947         Ext.fly(bd, '_internal').addCls(cls);
16948         return true;
16949     };
16950
16951     Ext.onReady(initExtCss);
16952 })();
16953
16954 /**
16955  * @class Ext.EventObject
16956
16957 Just as {@link Ext.core.Element} wraps around a native DOM node, Ext.EventObject
16958 wraps the browser's native event-object normalizing cross-browser differences,
16959 such as which mouse button is clicked, keys pressed, mechanisms to stop
16960 event-propagation along with a method to prevent default actions from taking place.
16961
16962 For example:
16963
16964     function handleClick(e, t){ // e is not a standard event object, it is a Ext.EventObject
16965         e.preventDefault();
16966         var target = e.getTarget(); // same as t (the target HTMLElement)
16967         ...
16968     }
16969
16970     var myDiv = {@link Ext#get Ext.get}("myDiv");  // get reference to an {@link Ext.core.Element}
16971     myDiv.on(         // 'on' is shorthand for addListener
16972         "click",      // perform an action on click of myDiv
16973         handleClick   // reference to the action handler
16974     );
16975
16976     // other methods to do the same:
16977     Ext.EventManager.on("myDiv", 'click', handleClick);
16978     Ext.EventManager.addListener("myDiv", 'click', handleClick);
16979
16980  * @singleton
16981  * @markdown
16982  */
16983 Ext.define('Ext.EventObjectImpl', {
16984     uses: ['Ext.util.Point'],
16985
16986     /** Key constant @type Number */
16987     BACKSPACE: 8,
16988     /** Key constant @type Number */
16989     TAB: 9,
16990     /** Key constant @type Number */
16991     NUM_CENTER: 12,
16992     /** Key constant @type Number */
16993     ENTER: 13,
16994     /** Key constant @type Number */
16995     RETURN: 13,
16996     /** Key constant @type Number */
16997     SHIFT: 16,
16998     /** Key constant @type Number */
16999     CTRL: 17,
17000     /** Key constant @type Number */
17001     ALT: 18,
17002     /** Key constant @type Number */
17003     PAUSE: 19,
17004     /** Key constant @type Number */
17005     CAPS_LOCK: 20,
17006     /** Key constant @type Number */
17007     ESC: 27,
17008     /** Key constant @type Number */
17009     SPACE: 32,
17010     /** Key constant @type Number */
17011     PAGE_UP: 33,
17012     /** Key constant @type Number */
17013     PAGE_DOWN: 34,
17014     /** Key constant @type Number */
17015     END: 35,
17016     /** Key constant @type Number */
17017     HOME: 36,
17018     /** Key constant @type Number */
17019     LEFT: 37,
17020     /** Key constant @type Number */
17021     UP: 38,
17022     /** Key constant @type Number */
17023     RIGHT: 39,
17024     /** Key constant @type Number */
17025     DOWN: 40,
17026     /** Key constant @type Number */
17027     PRINT_SCREEN: 44,
17028     /** Key constant @type Number */
17029     INSERT: 45,
17030     /** Key constant @type Number */
17031     DELETE: 46,
17032     /** Key constant @type Number */
17033     ZERO: 48,
17034     /** Key constant @type Number */
17035     ONE: 49,
17036     /** Key constant @type Number */
17037     TWO: 50,
17038     /** Key constant @type Number */
17039     THREE: 51,
17040     /** Key constant @type Number */
17041     FOUR: 52,
17042     /** Key constant @type Number */
17043     FIVE: 53,
17044     /** Key constant @type Number */
17045     SIX: 54,
17046     /** Key constant @type Number */
17047     SEVEN: 55,
17048     /** Key constant @type Number */
17049     EIGHT: 56,
17050     /** Key constant @type Number */
17051     NINE: 57,
17052     /** Key constant @type Number */
17053     A: 65,
17054     /** Key constant @type Number */
17055     B: 66,
17056     /** Key constant @type Number */
17057     C: 67,
17058     /** Key constant @type Number */
17059     D: 68,
17060     /** Key constant @type Number */
17061     E: 69,
17062     /** Key constant @type Number */
17063     F: 70,
17064     /** Key constant @type Number */
17065     G: 71,
17066     /** Key constant @type Number */
17067     H: 72,
17068     /** Key constant @type Number */
17069     I: 73,
17070     /** Key constant @type Number */
17071     J: 74,
17072     /** Key constant @type Number */
17073     K: 75,
17074     /** Key constant @type Number */
17075     L: 76,
17076     /** Key constant @type Number */
17077     M: 77,
17078     /** Key constant @type Number */
17079     N: 78,
17080     /** Key constant @type Number */
17081     O: 79,
17082     /** Key constant @type Number */
17083     P: 80,
17084     /** Key constant @type Number */
17085     Q: 81,
17086     /** Key constant @type Number */
17087     R: 82,
17088     /** Key constant @type Number */
17089     S: 83,
17090     /** Key constant @type Number */
17091     T: 84,
17092     /** Key constant @type Number */
17093     U: 85,
17094     /** Key constant @type Number */
17095     V: 86,
17096     /** Key constant @type Number */
17097     W: 87,
17098     /** Key constant @type Number */
17099     X: 88,
17100     /** Key constant @type Number */
17101     Y: 89,
17102     /** Key constant @type Number */
17103     Z: 90,
17104     /** Key constant @type Number */
17105     CONTEXT_MENU: 93,
17106     /** Key constant @type Number */
17107     NUM_ZERO: 96,
17108     /** Key constant @type Number */
17109     NUM_ONE: 97,
17110     /** Key constant @type Number */
17111     NUM_TWO: 98,
17112     /** Key constant @type Number */
17113     NUM_THREE: 99,
17114     /** Key constant @type Number */
17115     NUM_FOUR: 100,
17116     /** Key constant @type Number */
17117     NUM_FIVE: 101,
17118     /** Key constant @type Number */
17119     NUM_SIX: 102,
17120     /** Key constant @type Number */
17121     NUM_SEVEN: 103,
17122     /** Key constant @type Number */
17123     NUM_EIGHT: 104,
17124     /** Key constant @type Number */
17125     NUM_NINE: 105,
17126     /** Key constant @type Number */
17127     NUM_MULTIPLY: 106,
17128     /** Key constant @type Number */
17129     NUM_PLUS: 107,
17130     /** Key constant @type Number */
17131     NUM_MINUS: 109,
17132     /** Key constant @type Number */
17133     NUM_PERIOD: 110,
17134     /** Key constant @type Number */
17135     NUM_DIVISION: 111,
17136     /** Key constant @type Number */
17137     F1: 112,
17138     /** Key constant @type Number */
17139     F2: 113,
17140     /** Key constant @type Number */
17141     F3: 114,
17142     /** Key constant @type Number */
17143     F4: 115,
17144     /** Key constant @type Number */
17145     F5: 116,
17146     /** Key constant @type Number */
17147     F6: 117,
17148     /** Key constant @type Number */
17149     F7: 118,
17150     /** Key constant @type Number */
17151     F8: 119,
17152     /** Key constant @type Number */
17153     F9: 120,
17154     /** Key constant @type Number */
17155     F10: 121,
17156     /** Key constant @type Number */
17157     F11: 122,
17158     /** Key constant @type Number */
17159     F12: 123,
17160
17161     /**
17162      * Simple click regex
17163      * @private
17164      */
17165     clickRe: /(dbl)?click/,
17166     // safari keypress events for special keys return bad keycodes
17167     safariKeys: {
17168         3: 13, // enter
17169         63234: 37, // left
17170         63235: 39, // right
17171         63232: 38, // up
17172         63233: 40, // down
17173         63276: 33, // page up
17174         63277: 34, // page down
17175         63272: 46, // delete
17176         63273: 36, // home
17177         63275: 35 // end
17178     },
17179     // normalize button clicks, don't see any way to feature detect this.
17180     btnMap: Ext.isIE ? {
17181         1: 0,
17182         4: 1,
17183         2: 2
17184     } : {
17185         0: 0,
17186         1: 1,
17187         2: 2
17188     },
17189
17190     constructor: function(event, freezeEvent){
17191         if (event) {
17192             this.setEvent(event.browserEvent || event, freezeEvent);
17193         }
17194     },
17195
17196     setEvent: function(event, freezeEvent){
17197         var me = this, button, options;
17198
17199         if (event == me || (event && event.browserEvent)) { // already wrapped
17200             return event;
17201         }
17202         me.browserEvent = event;
17203         if (event) {
17204             // normalize buttons
17205             button = event.button ? me.btnMap[event.button] : (event.which ? event.which - 1 : -1);
17206             if (me.clickRe.test(event.type) && button == -1) {
17207                 button = 0;
17208             }
17209             options = {
17210                 type: event.type,
17211                 button: button,
17212                 shiftKey: event.shiftKey,
17213                 // mac metaKey behaves like ctrlKey
17214                 ctrlKey: event.ctrlKey || event.metaKey || false,
17215                 altKey: event.altKey,
17216                 // in getKey these will be normalized for the mac
17217                 keyCode: event.keyCode,
17218                 charCode: event.charCode,
17219                 // cache the targets for the delayed and or buffered events
17220                 target: Ext.EventManager.getTarget(event),
17221                 relatedTarget: Ext.EventManager.getRelatedTarget(event),
17222                 currentTarget: event.currentTarget,
17223                 xy: (freezeEvent ? me.getXY() : null)
17224             };
17225         } else {
17226             options = {
17227                 button: -1,
17228                 shiftKey: false,
17229                 ctrlKey: false,
17230                 altKey: false,
17231                 keyCode: 0,
17232                 charCode: 0,
17233                 target: null,
17234                 xy: [0, 0]
17235             };
17236         }
17237         Ext.apply(me, options);
17238         return me;
17239     },
17240
17241     /**
17242      * Stop the event (preventDefault and stopPropagation)
17243      */
17244     stopEvent: function(){
17245         this.stopPropagation();
17246         this.preventDefault();
17247     },
17248
17249     /**
17250      * Prevents the browsers default handling of the event.
17251      */
17252     preventDefault: function(){
17253         if (this.browserEvent) {
17254             Ext.EventManager.preventDefault(this.browserEvent);
17255         }
17256     },
17257
17258     /**
17259      * Cancels bubbling of the event.
17260      */
17261     stopPropagation: function(){
17262         var browserEvent = this.browserEvent;
17263
17264         if (browserEvent) {
17265             if (browserEvent.type == 'mousedown') {
17266                 Ext.EventManager.stoppedMouseDownEvent.fire(this);
17267             }
17268             Ext.EventManager.stopPropagation(browserEvent);
17269         }
17270     },
17271
17272     /**
17273      * Gets the character code for the event.
17274      * @return {Number}
17275      */
17276     getCharCode: function(){
17277         return this.charCode || this.keyCode;
17278     },
17279
17280     /**
17281      * Returns a normalized keyCode for the event.
17282      * @return {Number} The key code
17283      */
17284     getKey: function(){
17285         return this.normalizeKey(this.keyCode || this.charCode);
17286     },
17287
17288     /**
17289      * Normalize key codes across browsers
17290      * @private
17291      * @param {Number} key The key code
17292      * @return {Number} The normalized code
17293      */
17294     normalizeKey: function(key){
17295         // can't feature detect this
17296         return Ext.isWebKit ? (this.safariKeys[key] || key) : key;
17297     },
17298
17299     /**
17300      * Gets the x coordinate of the event.
17301      * @return {Number}
17302      * @deprecated 4.0 Replaced by {@link #getX}
17303      */
17304     getPageX: function(){
17305         return this.getX();
17306     },
17307
17308     /**
17309      * Gets the y coordinate of the event.
17310      * @return {Number}
17311      * @deprecated 4.0 Replaced by {@link #getY}
17312      */
17313     getPageY: function(){
17314         return this.getY();
17315     },
17316     
17317     /**
17318      * Gets the x coordinate of the event.
17319      * @return {Number}
17320      */
17321     getX: function() {
17322         return this.getXY()[0];
17323     },    
17324     
17325     /**
17326      * Gets the y coordinate of the event.
17327      * @return {Number}
17328      */
17329     getY: function() {
17330         return this.getXY()[1];
17331     },
17332         
17333     /**
17334      * Gets the page coordinates of the event.
17335      * @return {Array} The xy values like [x, y]
17336      */
17337     getXY: function() {
17338         if (!this.xy) {
17339             // same for XY
17340             this.xy = Ext.EventManager.getPageXY(this.browserEvent);
17341         }
17342         return this.xy;
17343     },
17344
17345     /**
17346      * Gets the target for the event.
17347      * @param {String} selector (optional) A simple selector to filter the target or look for an ancestor of the target
17348      * @param {Number/Mixed} maxDepth (optional) The max depth to search as a number or element (defaults to 10 || document.body)
17349      * @param {Boolean} returnEl (optional) True to return a Ext.core.Element object instead of DOM node
17350      * @return {HTMLelement}
17351      */
17352     getTarget : function(selector, maxDepth, returnEl){
17353         if (selector) {
17354             return Ext.fly(this.target).findParent(selector, maxDepth, returnEl);
17355         }
17356         return returnEl ? Ext.get(this.target) : this.target;
17357     },
17358
17359     /**
17360      * Gets the related target.
17361      * @param {String} selector (optional) A simple selector to filter the target or look for an ancestor of the target
17362      * @param {Number/Mixed} maxDepth (optional) The max depth to search as a number or element (defaults to 10 || document.body)
17363      * @param {Boolean} returnEl (optional) True to return a Ext.core.Element object instead of DOM node
17364      * @return {HTMLElement}
17365      */
17366     getRelatedTarget : function(selector, maxDepth, returnEl){
17367         if (selector) {
17368             return Ext.fly(this.relatedTarget).findParent(selector, maxDepth, returnEl);
17369         }
17370         return returnEl ? Ext.get(this.relatedTarget) : this.relatedTarget;
17371     },
17372
17373     /**
17374      * Normalizes mouse wheel delta across browsers
17375      * @return {Number} The delta
17376      */
17377     getWheelDelta : function(){
17378         var event = this.browserEvent,
17379             delta = 0;
17380
17381         if (event.wheelDelta) { /* IE/Opera. */
17382             delta = event.wheelDelta / 120;
17383         } else if (event.detail){ /* Mozilla case. */
17384             delta = -event.detail / 3;
17385         }
17386         return delta;
17387     },
17388
17389     /**
17390     * 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.
17391     * Example usage:<pre><code>
17392 // Handle click on any child of an element
17393 Ext.getBody().on('click', function(e){
17394     if(e.within('some-el')){
17395         alert('Clicked on a child of some-el!');
17396     }
17397 });
17398
17399 // Handle click directly on an element, ignoring clicks on child nodes
17400 Ext.getBody().on('click', function(e,t){
17401     if((t.id == 'some-el') && !e.within(t, true)){
17402         alert('Clicked directly on some-el!');
17403     }
17404 });
17405 </code></pre>
17406      * @param {Mixed} el The id, DOM element or Ext.core.Element to check
17407      * @param {Boolean} related (optional) true to test if the related target is within el instead of the target
17408      * @param {Boolean} allowEl {optional} true to also check if the passed element is the target or related target
17409      * @return {Boolean}
17410      */
17411     within : function(el, related, allowEl){
17412         if(el){
17413             var t = related ? this.getRelatedTarget() : this.getTarget(),
17414                 result;
17415
17416             if (t) {
17417                 result = Ext.fly(el).contains(t);
17418                 if (!result && allowEl) {
17419                     result = t == Ext.getDom(el);
17420                 }
17421                 return result;
17422             }
17423         }
17424         return false;
17425     },
17426
17427     /**
17428      * Checks if the key pressed was a "navigation" key
17429      * @return {Boolean} True if the press is a navigation keypress
17430      */
17431     isNavKeyPress : function(){
17432         var me = this,
17433             k = this.normalizeKey(me.keyCode);
17434
17435        return (k >= 33 && k <= 40) ||  // Page Up/Down, End, Home, Left, Up, Right, Down
17436        k == me.RETURN ||
17437        k == me.TAB ||
17438        k == me.ESC;
17439     },
17440
17441     /**
17442      * Checks if the key pressed was a "special" key
17443      * @return {Boolean} True if the press is a special keypress
17444      */
17445     isSpecialKey : function(){
17446         var k = this.normalizeKey(this.keyCode);
17447         return (this.type == 'keypress' && this.ctrlKey) ||
17448         this.isNavKeyPress() ||
17449         (k == this.BACKSPACE) || // Backspace
17450         (k >= 16 && k <= 20) || // Shift, Ctrl, Alt, Pause, Caps Lock
17451         (k >= 44 && k <= 46);   // Print Screen, Insert, Delete
17452     },
17453
17454     /**
17455      * Returns a point object that consists of the object coordinates.
17456      * @return {Ext.util.Point} point
17457      */
17458     getPoint : function(){
17459         var xy = this.getXY();
17460         return Ext.create('Ext.util.Point', xy[0], xy[1]);
17461     },
17462
17463    /**
17464     * Returns true if the control, meta, shift or alt key was pressed during this event.
17465     * @return {Boolean}
17466     */
17467     hasModifier : function(){
17468         return this.ctrlKey || this.altKey || this.shiftKey || this.metaKey;
17469     },
17470
17471     /**
17472      * Injects a DOM event using the data in this object and (optionally) a new target.
17473      * This is a low-level technique and not likely to be used by application code. The
17474      * currently supported event types are:
17475      * <p><b>HTMLEvents</b></p>
17476      * <ul>
17477      * <li>load</li>
17478      * <li>unload</li>
17479      * <li>select</li>
17480      * <li>change</li>
17481      * <li>submit</li>
17482      * <li>reset</li>
17483      * <li>resize</li>
17484      * <li>scroll</li>
17485      * </ul>
17486      * <p><b>MouseEvents</b></p>
17487      * <ul>
17488      * <li>click</li>
17489      * <li>dblclick</li>
17490      * <li>mousedown</li>
17491      * <li>mouseup</li>
17492      * <li>mouseover</li>
17493      * <li>mousemove</li>
17494      * <li>mouseout</li>
17495      * </ul>
17496      * <p><b>UIEvents</b></p>
17497      * <ul>
17498      * <li>focusin</li>
17499      * <li>focusout</li>
17500      * <li>activate</li>
17501      * <li>focus</li>
17502      * <li>blur</li>
17503      * </ul>
17504      * @param {Element/HTMLElement} target If specified, the target for the event. This
17505      * is likely to be used when relaying a DOM event. If not specified, {@link #getTarget}
17506      * is used to determine the target.
17507      */
17508     injectEvent: function () {
17509         var API,
17510             dispatchers = {}; // keyed by event type (e.g., 'mousedown')
17511
17512         // Good reference: http://developer.yahoo.com/yui/docs/UserAction.js.html
17513
17514         // IE9 has createEvent, but this code causes major problems with htmleditor (it
17515         // blocks all mouse events and maybe more). TODO
17516
17517         if (!Ext.isIE && document.createEvent) { // if (DOM compliant)
17518             API = {
17519                 createHtmlEvent: function (doc, type, bubbles, cancelable) {
17520                     var event = doc.createEvent('HTMLEvents');
17521
17522                     event.initEvent(type, bubbles, cancelable);
17523                     return event;
17524                 },
17525
17526                 createMouseEvent: function (doc, type, bubbles, cancelable, detail,
17527                                             clientX, clientY, ctrlKey, altKey, shiftKey, metaKey,
17528                                             button, relatedTarget) {
17529                     var event = doc.createEvent('MouseEvents'),
17530                         view = doc.defaultView || window;
17531
17532                     if (event.initMouseEvent) {
17533                         event.initMouseEvent(type, bubbles, cancelable, view, detail,
17534                                     clientX, clientY, clientX, clientY, ctrlKey, altKey,
17535                                     shiftKey, metaKey, button, relatedTarget);
17536                     } else { // old Safari
17537                         event = doc.createEvent('UIEvents');
17538                         event.initEvent(type, bubbles, cancelable);
17539                         event.view = view;
17540                         event.detail = detail;
17541                         event.screenX = clientX;
17542                         event.screenY = clientY;
17543                         event.clientX = clientX;
17544                         event.clientY = clientY;
17545                         event.ctrlKey = ctrlKey;
17546                         event.altKey = altKey;
17547                         event.metaKey = metaKey;
17548                         event.shiftKey = shiftKey;
17549                         event.button = button;
17550                         event.relatedTarget = relatedTarget;
17551                     }
17552
17553                     return event;
17554                 },
17555
17556                 createUIEvent: function (doc, type, bubbles, cancelable, detail) {
17557                     var event = doc.createEvent('UIEvents'),
17558                         view = doc.defaultView || window;
17559
17560                     event.initUIEvent(type, bubbles, cancelable, view, detail);
17561                     return event;
17562                 },
17563
17564                 fireEvent: function (target, type, event) {
17565                     target.dispatchEvent(event);
17566                 },
17567
17568                 fixTarget: function (target) {
17569                     // Safari3 doesn't have window.dispatchEvent()
17570                     if (target == window && !target.dispatchEvent) {
17571                         return document;
17572                     }
17573
17574                     return target;
17575                 }
17576             }
17577         } else if (document.createEventObject) { // else if (IE)
17578             var crazyIEButtons = { 0: 1, 1: 4, 2: 2 };
17579
17580             API = {
17581                 createHtmlEvent: function (doc, type, bubbles, cancelable) {
17582                     var event = doc.createEventObject();
17583                     event.bubbles = bubbles;
17584                     event.cancelable = cancelable;
17585                     return event;
17586                 },
17587
17588                 createMouseEvent: function (doc, type, bubbles, cancelable, detail,
17589                                             clientX, clientY, ctrlKey, altKey, shiftKey, metaKey,
17590                                             button, relatedTarget) {
17591                     var event = doc.createEventObject();
17592                     event.bubbles = bubbles;
17593                     event.cancelable = cancelable;
17594                     event.detail = detail;
17595                     event.screenX = clientX;
17596                     event.screenY = clientY;
17597                     event.clientX = clientX;
17598                     event.clientY = clientY;
17599                     event.ctrlKey = ctrlKey;
17600                     event.altKey = altKey;
17601                     event.shiftKey = shiftKey;
17602                     event.metaKey = metaKey;
17603                     event.button = crazyIEButtons[button] || button;
17604                     event.relatedTarget = relatedTarget; // cannot assign to/fromElement
17605                     return event;
17606                 },
17607
17608                 createUIEvent: function (doc, type, bubbles, cancelable, detail) {
17609                     var event = doc.createEventObject();
17610                     event.bubbles = bubbles;
17611                     event.cancelable = cancelable;
17612                     return event;
17613                 },
17614
17615                 fireEvent: function (target, type, event) {
17616                     target.fireEvent('on' + type, event);
17617                 },
17618
17619                 fixTarget: function (target) {
17620                     if (target == document) {
17621                         // IE6,IE7 thinks window==document and doesn't have window.fireEvent()
17622                         // IE6,IE7 cannot properly call document.fireEvent()
17623                         return document.documentElement;
17624                     }
17625
17626                     return target;
17627                 }
17628             };
17629         }
17630
17631         //----------------
17632         // HTMLEvents
17633
17634         Ext.Object.each({
17635                 load:   [false, false],
17636                 unload: [false, false],
17637                 select: [true, false],
17638                 change: [true, false],
17639                 submit: [true, true],
17640                 reset:  [true, false],
17641                 resize: [true, false],
17642                 scroll: [true, false]
17643             },
17644             function (name, value) {
17645                 var bubbles = value[0], cancelable = value[1];
17646                 dispatchers[name] = function (targetEl, srcEvent) {
17647                     var e = API.createHtmlEvent(name, bubbles, cancelable);
17648                     API.fireEvent(targetEl, name, e);
17649                 };
17650             });
17651
17652         //----------------
17653         // MouseEvents
17654
17655         function createMouseEventDispatcher (type, detail) {
17656             var cancelable = (type != 'mousemove');
17657             return function (targetEl, srcEvent) {
17658                 var xy = srcEvent.getXY(),
17659                     e = API.createMouseEvent(targetEl.ownerDocument, type, true, cancelable,
17660                                 detail, xy[0], xy[1], srcEvent.ctrlKey, srcEvent.altKey,
17661                                 srcEvent.shiftKey, srcEvent.metaKey, srcEvent.button,
17662                                 srcEvent.relatedTarget);
17663                 API.fireEvent(targetEl, type, e);
17664             };
17665         }
17666
17667         Ext.each(['click', 'dblclick', 'mousedown', 'mouseup', 'mouseover', 'mousemove', 'mouseout'],
17668             function (eventName) {
17669                 dispatchers[eventName] = createMouseEventDispatcher(eventName, 1);
17670             });
17671
17672         //----------------
17673         // UIEvents
17674
17675         Ext.Object.each({
17676                 focusin:  [true, false],
17677                 focusout: [true, false],
17678                 activate: [true, true],
17679                 focus:    [false, false],
17680                 blur:     [false, false]
17681             },
17682             function (name, value) {
17683                 var bubbles = value[0], cancelable = value[1];
17684                 dispatchers[name] = function (targetEl, srcEvent) {
17685                     var e = API.createUIEvent(targetEl.ownerDocument, name, bubbles, cancelable, 1);
17686                     API.fireEvent(targetEl, name, e);
17687                 };
17688             });
17689
17690         //---------
17691         if (!API) {
17692             // not even sure what ancient browsers fall into this category...
17693
17694             dispatchers = {}; // never mind all those we just built :P
17695
17696             API = {
17697                 fixTarget: function (t) {
17698                     return t;
17699                 }
17700             };
17701         }
17702
17703         function cannotInject (target, srcEvent) {
17704             // TODO log something
17705         }
17706
17707         return function (target) {
17708             var me = this,
17709                 dispatcher = dispatchers[me.type] || cannotInject,
17710                 t = target ? (target.dom || target) : me.getTarget();
17711
17712             t = API.fixTarget(t);
17713             dispatcher(t, me);
17714         };
17715     }() // call to produce method
17716
17717 }, function() {
17718
17719 Ext.EventObject = new Ext.EventObjectImpl();
17720
17721 });
17722
17723
17724 /**
17725  * @class Ext.core.Element
17726  */
17727 (function(){
17728     var doc = document,
17729         isCSS1 = doc.compatMode == "CSS1Compat",
17730         ELEMENT = Ext.core.Element,
17731         fly = function(el){
17732             if (!_fly) {
17733                 _fly = new Ext.core.Element.Flyweight();
17734             }
17735             _fly.dom = el;
17736             return _fly;
17737         }, _fly;
17738
17739     Ext.apply(ELEMENT, {
17740         isAncestor : function(p, c) {
17741             var ret = false;
17742
17743             p = Ext.getDom(p);
17744             c = Ext.getDom(c);
17745             if (p && c) {
17746                 if (p.contains) {
17747                     return p.contains(c);
17748                 } else if (p.compareDocumentPosition) {
17749                     return !!(p.compareDocumentPosition(c) & 16);
17750                 } else {
17751                     while ((c = c.parentNode)) {
17752                         ret = c == p || ret;
17753                     }
17754                 }
17755             }
17756             return ret;
17757         },
17758
17759         getViewWidth : function(full) {
17760             return full ? ELEMENT.getDocumentWidth() : ELEMENT.getViewportWidth();
17761         },
17762
17763         getViewHeight : function(full) {
17764             return full ? ELEMENT.getDocumentHeight() : ELEMENT.getViewportHeight();
17765         },
17766
17767         getDocumentHeight: function() {
17768             return Math.max(!isCSS1 ? doc.body.scrollHeight : doc.documentElement.scrollHeight, ELEMENT.getViewportHeight());
17769         },
17770
17771         getDocumentWidth: function() {
17772             return Math.max(!isCSS1 ? doc.body.scrollWidth : doc.documentElement.scrollWidth, ELEMENT.getViewportWidth());
17773         },
17774
17775         getViewportHeight: function(){
17776             return Ext.isIE ?
17777                    (Ext.isStrict ? doc.documentElement.clientHeight : doc.body.clientHeight) :
17778                    self.innerHeight;
17779         },
17780
17781         getViewportWidth : function() {
17782             return (!Ext.isStrict && !Ext.isOpera) ? doc.body.clientWidth :
17783                    Ext.isIE ? doc.documentElement.clientWidth : self.innerWidth;
17784         },
17785
17786         getY : function(el) {
17787             return ELEMENT.getXY(el)[1];
17788         },
17789
17790         getX : function(el) {
17791             return ELEMENT.getXY(el)[0];
17792         },
17793
17794         getXY : function(el) {
17795             var p,
17796                 pe,
17797                 b,
17798                 bt,
17799                 bl,
17800                 dbd,
17801                 x = 0,
17802                 y = 0,
17803                 scroll,
17804                 hasAbsolute,
17805                 bd = (doc.body || doc.documentElement),
17806                 ret = [0,0];
17807
17808             el = Ext.getDom(el);
17809
17810             if(el != bd){
17811                 hasAbsolute = fly(el).isStyle("position", "absolute");
17812
17813                 if (el.getBoundingClientRect) {
17814                     b = el.getBoundingClientRect();
17815                     scroll = fly(document).getScroll();
17816                     ret = [Math.round(b.left + scroll.left), Math.round(b.top + scroll.top)];
17817                 } else {
17818                     p = el;
17819
17820                     while (p) {
17821                         pe = fly(p);
17822                         x += p.offsetLeft;
17823                         y += p.offsetTop;
17824
17825                         hasAbsolute = hasAbsolute || pe.isStyle("position", "absolute");
17826
17827                         if (Ext.isGecko) {
17828                             y += bt = parseInt(pe.getStyle("borderTopWidth"), 10) || 0;
17829                             x += bl = parseInt(pe.getStyle("borderLeftWidth"), 10) || 0;
17830
17831                             if (p != el && !pe.isStyle('overflow','visible')) {
17832                                 x += bl;
17833                                 y += bt;
17834                             }
17835                         }
17836                         p = p.offsetParent;
17837                     }
17838
17839                     if (Ext.isSafari && hasAbsolute) {
17840                         x -= bd.offsetLeft;
17841                         y -= bd.offsetTop;
17842                     }
17843
17844                     if (Ext.isGecko && !hasAbsolute) {
17845                         dbd = fly(bd);
17846                         x += parseInt(dbd.getStyle("borderLeftWidth"), 10) || 0;
17847                         y += parseInt(dbd.getStyle("borderTopWidth"), 10) || 0;
17848                     }
17849
17850                     p = el.parentNode;
17851                     while (p && p != bd) {
17852                         if (!Ext.isOpera || (p.tagName != 'TR' && !fly(p).isStyle("display", "inline"))) {
17853                             x -= p.scrollLeft;
17854                             y -= p.scrollTop;
17855                         }
17856                         p = p.parentNode;
17857                     }
17858                     ret = [x,y];
17859                 }
17860             }
17861             return ret;
17862         },
17863
17864         setXY : function(el, xy) {
17865             (el = Ext.fly(el, '_setXY')).position();
17866
17867             var pts = el.translatePoints(xy),
17868                 style = el.dom.style,
17869                 pos;
17870
17871             for (pos in pts) {
17872                 if (!isNaN(pts[pos])) {
17873                     style[pos] = pts[pos] + "px";
17874                 }
17875             }
17876         },
17877
17878         setX : function(el, x) {
17879             ELEMENT.setXY(el, [x, false]);
17880         },
17881
17882         setY : function(el, y) {
17883             ELEMENT.setXY(el, [false, y]);
17884         },
17885
17886         /**
17887          * Serializes a DOM form into a url encoded string
17888          * @param {Object} form The form
17889          * @return {String} The url encoded form
17890          */
17891         serializeForm: function(form) {
17892             var fElements = form.elements || (document.forms[form] || Ext.getDom(form)).elements,
17893                 hasSubmit = false,
17894                 encoder = encodeURIComponent,
17895                 name,
17896                 data = '',
17897                 type,
17898                 hasValue;
17899
17900             Ext.each(fElements, function(element){
17901                 name = element.name;
17902                 type = element.type;
17903
17904                 if (!element.disabled && name) {
17905                     if (/select-(one|multiple)/i.test(type)) {
17906                         Ext.each(element.options, function(opt){
17907                             if (opt.selected) {
17908                                 hasValue = opt.hasAttribute ? opt.hasAttribute('value') : opt.getAttributeNode('value').specified;
17909                                 data += String.format("{0}={1}&", encoder(name), encoder(hasValue ? opt.value : opt.text));
17910                             }
17911                         });
17912                     } else if (!(/file|undefined|reset|button/i.test(type))) {
17913                         if (!(/radio|checkbox/i.test(type) && !element.checked) && !(type == 'submit' && hasSubmit)) {
17914                             data += encoder(name) + '=' + encoder(element.value) + '&';
17915                             hasSubmit = /submit/i.test(type);
17916                         }
17917                     }
17918                 }
17919             });
17920             return data.substr(0, data.length - 1);
17921         }
17922     });
17923 })();
17924
17925 /**
17926  * @class Ext.core.Element
17927  */
17928
17929 Ext.core.Element.addMethods({
17930
17931     /**
17932      * Monitors this Element for the mouse leaving. Calls the function after the specified delay only if
17933      * the mouse was not moved back into the Element within the delay. If the mouse <i>was</i> moved
17934      * back in, the function is not called.
17935      * @param {Number} delay The delay <b>in milliseconds</b> to wait for possible mouse re-entry before calling the handler function.
17936      * @param {Function} handler The function to call if the mouse remains outside of this Element for the specified time.
17937      * @param {Object} scope The scope (<code>this</code> reference) in which the handler function executes. Defaults to this Element.
17938      * @return {Object} The listeners object which was added to this element so that monitoring can be stopped. Example usage:</pre><code>
17939 // Hide the menu if the mouse moves out for 250ms or more
17940 this.mouseLeaveMonitor = this.menuEl.monitorMouseLeave(250, this.hideMenu, this);
17941
17942 ...
17943 // Remove mouseleave monitor on menu destroy
17944 this.menuEl.un(this.mouseLeaveMonitor);
17945 </code></pre>
17946      */
17947     monitorMouseLeave: function(delay, handler, scope) {
17948         var me = this,
17949             timer,
17950             listeners = {
17951                 mouseleave: function(e) {
17952                     timer = setTimeout(Ext.Function.bind(handler, scope||me, [e]), delay);
17953                 },
17954                 mouseenter: function() {
17955                     clearTimeout(timer);
17956                 },
17957                 freezeEvent: true
17958             };
17959
17960         me.on(listeners);
17961         return listeners;
17962     },
17963
17964     /**
17965      * Stops the specified event(s) from bubbling and optionally prevents the default action
17966      * @param {String/Array} eventName an event / array of events to stop from bubbling
17967      * @param {Boolean} preventDefault (optional) true to prevent the default action too
17968      * @return {Ext.core.Element} this
17969      */
17970     swallowEvent : function(eventName, preventDefault) {
17971         var me = this;
17972         function fn(e) {
17973             e.stopPropagation();
17974             if (preventDefault) {
17975                 e.preventDefault();
17976             }
17977         }
17978         
17979         if (Ext.isArray(eventName)) {
17980             Ext.each(eventName, function(e) {
17981                  me.on(e, fn);
17982             });
17983             return me;
17984         }
17985         me.on(eventName, fn);
17986         return me;
17987     },
17988
17989     /**
17990      * Create an event handler on this element such that when the event fires and is handled by this element,
17991      * it will be relayed to another object (i.e., fired again as if it originated from that object instead).
17992      * @param {String} eventName The type of event to relay
17993      * @param {Object} object Any object that extends {@link Ext.util.Observable} that will provide the context
17994      * for firing the relayed event
17995      */
17996     relayEvent : function(eventName, observable) {
17997         this.on(eventName, function(e) {
17998             observable.fireEvent(eventName, e);
17999         });
18000     },
18001
18002     /**
18003      * Removes Empty, or whitespace filled text nodes. Combines adjacent text nodes.
18004      * @param {Boolean} forceReclean (optional) By default the element
18005      * keeps track if it has been cleaned already so
18006      * you can call this over and over. However, if you update the element and
18007      * need to force a reclean, you can pass true.
18008      */
18009     clean : function(forceReclean) {
18010         var me  = this,
18011             dom = me.dom,
18012             n   = dom.firstChild,
18013             nx,
18014             ni  = -1;
18015
18016         if (Ext.core.Element.data(dom, 'isCleaned') && forceReclean !== true) {
18017             return me;
18018         }
18019
18020         while (n) {
18021             nx = n.nextSibling;
18022             if (n.nodeType == 3) {
18023                 // Remove empty/whitespace text nodes
18024                 if (!(/\S/.test(n.nodeValue))) {
18025                     dom.removeChild(n);
18026                 // Combine adjacent text nodes
18027                 } else if (nx && nx.nodeType == 3) {
18028                     n.appendData(Ext.String.trim(nx.data));
18029                     dom.removeChild(nx);
18030                     nx = n.nextSibling;
18031                     n.nodeIndex = ++ni;
18032                 }
18033             } else {
18034                 // Recursively clean
18035                 Ext.fly(n).clean();
18036                 n.nodeIndex = ++ni;
18037             }
18038             n = nx;
18039         }
18040
18041         Ext.core.Element.data(dom, 'isCleaned', true);
18042         return me;
18043     },
18044
18045     /**
18046      * Direct access to the Ext.ElementLoader {@link Ext.ElementLoader#load} method. The method takes the same object
18047      * parameter as {@link Ext.ElementLoader#load}
18048      * @return {Ext.core.Element} this
18049      */
18050     load : function(options) {
18051         this.getLoader().load(options);
18052         return this;
18053     },
18054
18055     /**
18056     * Gets this element's {@link Ext.ElementLoader ElementLoader}
18057     * @return {Ext.ElementLoader} The loader
18058     */
18059     getLoader : function() {
18060         var dom = this.dom,
18061             data = Ext.core.Element.data,
18062             loader = data(dom, 'loader');
18063             
18064         if (!loader) {
18065             loader = Ext.create('Ext.ElementLoader', {
18066                 target: this
18067             });
18068             data(dom, 'loader', loader);
18069         }
18070         return loader;
18071     },
18072
18073     /**
18074     * Update the innerHTML of this element, optionally searching for and processing scripts
18075     * @param {String} html The new HTML
18076     * @param {Boolean} loadScripts (optional) True to look for and process scripts (defaults to false)
18077     * @param {Function} callback (optional) For async script loading you can be notified when the update completes
18078     * @return {Ext.core.Element} this
18079      */
18080     update : function(html, loadScripts, callback) {
18081         var me = this,
18082             id,
18083             dom,
18084             interval;
18085             
18086         if (!me.dom) {
18087             return me;
18088         }
18089         html = html || '';
18090         dom = me.dom;
18091
18092         if (loadScripts !== true) {
18093             dom.innerHTML = html;
18094             Ext.callback(callback, me);
18095             return me;
18096         }
18097
18098         id  = Ext.id();
18099         html += '<span id="' + id + '"></span>';
18100
18101         interval = setInterval(function(){
18102             if (!document.getElementById(id)) {
18103                 return false;    
18104             }
18105             clearInterval(interval);
18106             var DOC    = document,
18107                 hd     = DOC.getElementsByTagName("head")[0],
18108                 re     = /(?:<script([^>]*)?>)((\n|\r|.)*?)(?:<\/script>)/ig,
18109                 srcRe  = /\ssrc=([\'\"])(.*?)\1/i,
18110                 typeRe = /\stype=([\'\"])(.*?)\1/i,
18111                 match,
18112                 attrs,
18113                 srcMatch,
18114                 typeMatch,
18115                 el,
18116                 s;
18117
18118             while ((match = re.exec(html))) {
18119                 attrs = match[1];
18120                 srcMatch = attrs ? attrs.match(srcRe) : false;
18121                 if (srcMatch && srcMatch[2]) {
18122                    s = DOC.createElement("script");
18123                    s.src = srcMatch[2];
18124                    typeMatch = attrs.match(typeRe);
18125                    if (typeMatch && typeMatch[2]) {
18126                        s.type = typeMatch[2];
18127                    }
18128                    hd.appendChild(s);
18129                 } else if (match[2] && match[2].length > 0) {
18130                     if (window.execScript) {
18131                        window.execScript(match[2]);
18132                     } else {
18133                        window.eval(match[2]);
18134                     }
18135                 }
18136             }
18137             
18138             el = DOC.getElementById(id);
18139             if (el) {
18140                 Ext.removeNode(el);
18141             }
18142             Ext.callback(callback, me);
18143         }, 20);
18144         dom.innerHTML = html.replace(/(?:<script.*?>)((\n|\r|.)*?)(?:<\/script>)/ig, '');
18145         return me;
18146     },
18147
18148     // inherit docs, overridden so we can add removeAnchor
18149     removeAllListeners : function() {
18150         this.removeAnchor();
18151         Ext.EventManager.removeAll(this.dom);
18152         return this;
18153     },
18154
18155     /**
18156      * Creates a proxy element of this element
18157      * @param {String/Object} config The class name of the proxy element or a DomHelper config object
18158      * @param {String/HTMLElement} renderTo (optional) The element or element id to render the proxy to (defaults to document.body)
18159      * @param {Boolean} matchBox (optional) True to align and size the proxy to this element now (defaults to false)
18160      * @return {Ext.core.Element} The new proxy element
18161      */
18162     createProxy : function(config, renderTo, matchBox) {
18163         config = (typeof config == 'object') ? config : {tag : "div", cls: config};
18164
18165         var me = this,
18166             proxy = renderTo ? Ext.core.DomHelper.append(renderTo, config, true) :
18167                                Ext.core.DomHelper.insertBefore(me.dom, config, true);
18168
18169         proxy.setVisibilityMode(Ext.core.Element.DISPLAY);
18170         proxy.hide();
18171         if (matchBox && me.setBox && me.getBox) { // check to make sure Element.position.js is loaded
18172            proxy.setBox(me.getBox());
18173         }
18174         return proxy;
18175     }
18176 });
18177 Ext.core.Element.prototype.clearListeners = Ext.core.Element.prototype.removeAllListeners;
18178
18179 /**
18180  * @class Ext.core.Element
18181  */
18182 Ext.core.Element.addMethods({
18183     /**
18184      * Gets the x,y coordinates specified by the anchor position on the element.
18185      * @param {String} anchor (optional) The specified anchor position (defaults to "c").  See {@link #alignTo}
18186      * for details on supported anchor positions.
18187      * @param {Boolean} local (optional) True to get the local (element top/left-relative) anchor position instead
18188      * of page coordinates
18189      * @param {Object} size (optional) An object containing the size to use for calculating anchor position
18190      * {width: (target width), height: (target height)} (defaults to the element's current size)
18191      * @return {Array} [x, y] An array containing the element's x and y coordinates
18192      */
18193     getAnchorXY : function(anchor, local, s){
18194         //Passing a different size is useful for pre-calculating anchors,
18195         //especially for anchored animations that change the el size.
18196         anchor = (anchor || "tl").toLowerCase();
18197         s = s || {};
18198
18199         var me = this,
18200             vp = me.dom == document.body || me.dom == document,
18201             w = s.width || vp ? Ext.core.Element.getViewWidth() : me.getWidth(),
18202             h = s.height || vp ? Ext.core.Element.getViewHeight() : me.getHeight(),
18203             xy,
18204             r = Math.round,
18205             o = me.getXY(),
18206             scroll = me.getScroll(),
18207             extraX = vp ? scroll.left : !local ? o[0] : 0,
18208             extraY = vp ? scroll.top : !local ? o[1] : 0,
18209             hash = {
18210                 c  : [r(w * 0.5), r(h * 0.5)],
18211                 t  : [r(w * 0.5), 0],
18212                 l  : [0, r(h * 0.5)],
18213                 r  : [w, r(h * 0.5)],
18214                 b  : [r(w * 0.5), h],
18215                 tl : [0, 0],
18216                 bl : [0, h],
18217                 br : [w, h],
18218                 tr : [w, 0]
18219             };
18220
18221         xy = hash[anchor];
18222         return [xy[0] + extraX, xy[1] + extraY];
18223     },
18224
18225     /**
18226      * Anchors an element to another element and realigns it when the window is resized.
18227      * @param {Mixed} element The element to align to.
18228      * @param {String} position The position to align to.
18229      * @param {Array} offsets (optional) Offset the positioning by [x, y]
18230      * @param {Boolean/Object} animate (optional) True for the default animation or a standard Element animation config object
18231      * @param {Boolean/Number} monitorScroll (optional) True to monitor body scroll and reposition. If this parameter
18232      * is a number, it is used as the buffer delay (defaults to 50ms).
18233      * @param {Function} callback The function to call after the animation finishes
18234      * @return {Ext.core.Element} this
18235      */
18236     anchorTo : function(el, alignment, offsets, animate, monitorScroll, callback){
18237         var me = this,
18238             dom = me.dom,
18239             scroll = !Ext.isEmpty(monitorScroll),
18240             action = function(){
18241                 Ext.fly(dom).alignTo(el, alignment, offsets, animate);
18242                 Ext.callback(callback, Ext.fly(dom));
18243             },
18244             anchor = this.getAnchor();
18245
18246         // previous listener anchor, remove it
18247         this.removeAnchor();
18248         Ext.apply(anchor, {
18249             fn: action,
18250             scroll: scroll
18251         });
18252
18253         Ext.EventManager.onWindowResize(action, null);
18254
18255         if(scroll){
18256             Ext.EventManager.on(window, 'scroll', action, null,
18257                 {buffer: !isNaN(monitorScroll) ? monitorScroll : 50});
18258         }
18259         action.call(me); // align immediately
18260         return me;
18261     },
18262
18263     /**
18264      * Remove any anchor to this element. See {@link #anchorTo}.
18265      * @return {Ext.core.Element} this
18266      */
18267     removeAnchor : function(){
18268         var me = this,
18269             anchor = this.getAnchor();
18270
18271         if(anchor && anchor.fn){
18272             Ext.EventManager.removeResizeListener(anchor.fn);
18273             if(anchor.scroll){
18274                 Ext.EventManager.un(window, 'scroll', anchor.fn);
18275             }
18276             delete anchor.fn;
18277         }
18278         return me;
18279     },
18280
18281     // private
18282     getAnchor : function(){
18283         var data = Ext.core.Element.data,
18284             dom = this.dom;
18285             if (!dom) {
18286                 return;
18287             }
18288             var anchor = data(dom, '_anchor');
18289
18290         if(!anchor){
18291             anchor = data(dom, '_anchor', {});
18292         }
18293         return anchor;
18294     },
18295
18296     getAlignVector: function(el, spec, offset) {
18297         var me = this,
18298             side = {t:"top", l:"left", r:"right", b: "bottom"},
18299             thisRegion = me.getRegion(),
18300             elRegion;
18301
18302         el = Ext.get(el);
18303         if(!el || !el.dom){
18304             Ext.Error.raise({
18305                 sourceClass: 'Ext.core.Element',
18306                 sourceMethod: 'getAlignVector',
18307                 msg: 'Attempted to align an element that doesn\'t exist'
18308             });
18309         }
18310
18311         elRegion = el.getRegion();
18312     },
18313
18314     /**
18315      * Gets the x,y coordinates to align this element with another element. See {@link #alignTo} for more info on the
18316      * supported position values.
18317      * @param {Mixed} element The element to align to.
18318      * @param {String} position (optional, defaults to "tl-bl?") The position to align to.
18319      * @param {Array} offsets (optional) Offset the positioning by [x, y]
18320      * @return {Array} [x, y]
18321      */
18322     getAlignToXY : function(el, p, o){
18323         el = Ext.get(el);
18324
18325         if(!el || !el.dom){
18326             Ext.Error.raise({
18327                 sourceClass: 'Ext.core.Element',
18328                 sourceMethod: 'getAlignToXY',
18329                 msg: 'Attempted to align an element that doesn\'t exist'
18330             });
18331         }
18332
18333         o = o || [0,0];
18334         p = (!p || p == "?" ? "tl-bl?" : (!(/-/).test(p) && p !== "" ? "tl-" + p : p || "tl-bl")).toLowerCase();
18335
18336         var me = this,
18337             d = me.dom,
18338             a1,
18339             a2,
18340             x,
18341             y,
18342             //constrain the aligned el to viewport if necessary
18343             w,
18344             h,
18345             r,
18346             dw = Ext.core.Element.getViewWidth() -10, // 10px of margin for ie
18347             dh = Ext.core.Element.getViewHeight()-10, // 10px of margin for ie
18348             p1y,
18349             p1x,
18350             p2y,
18351             p2x,
18352             swapY,
18353             swapX,
18354             doc = document,
18355             docElement = doc.documentElement,
18356             docBody = doc.body,
18357             scrollX = (docElement.scrollLeft || docBody.scrollLeft || 0)+5,
18358             scrollY = (docElement.scrollTop || docBody.scrollTop || 0)+5,
18359             c = false, //constrain to viewport
18360             p1 = "",
18361             p2 = "",
18362             m = p.match(/^([a-z]+)-([a-z]+)(\?)?$/);
18363
18364         if(!m){
18365             Ext.Error.raise({
18366                 sourceClass: 'Ext.core.Element',
18367                 sourceMethod: 'getAlignToXY',
18368                 el: el,
18369                 position: p,
18370                 offset: o,
18371                 msg: 'Attemmpted to align an element with an invalid position: "' + p + '"'
18372             });
18373         }
18374
18375         p1 = m[1];
18376         p2 = m[2];
18377         c = !!m[3];
18378
18379         //Subtract the aligned el's internal xy from the target's offset xy
18380         //plus custom offset to get the aligned el's new offset xy
18381         a1 = me.getAnchorXY(p1, true);
18382         a2 = el.getAnchorXY(p2, false);
18383
18384         x = a2[0] - a1[0] + o[0];
18385         y = a2[1] - a1[1] + o[1];
18386
18387         if(c){
18388            w = me.getWidth();
18389            h = me.getHeight();
18390            r = el.getRegion();
18391            //If we are at a viewport boundary and the aligned el is anchored on a target border that is
18392            //perpendicular to the vp border, allow the aligned el to slide on that border,
18393            //otherwise swap the aligned el to the opposite border of the target.
18394            p1y = p1.charAt(0);
18395            p1x = p1.charAt(p1.length-1);
18396            p2y = p2.charAt(0);
18397            p2x = p2.charAt(p2.length-1);
18398            swapY = ((p1y=="t" && p2y=="b") || (p1y=="b" && p2y=="t"));
18399            swapX = ((p1x=="r" && p2x=="l") || (p1x=="l" && p2x=="r"));
18400
18401
18402            if (x + w > dw + scrollX) {
18403                 x = swapX ? r.left-w : dw+scrollX-w;
18404            }
18405            if (x < scrollX) {
18406                x = swapX ? r.right : scrollX;
18407            }
18408            if (y + h > dh + scrollY) {
18409                 y = swapY ? r.top-h : dh+scrollY-h;
18410             }
18411            if (y < scrollY){
18412                y = swapY ? r.bottom : scrollY;
18413            }
18414         }
18415         return [x,y];
18416     },
18417
18418     /**
18419      * Aligns this element with another element relative to the specified anchor points. If the other element is the
18420      * document it aligns it to the viewport.
18421      * The position parameter is optional, and can be specified in any one of the following formats:
18422      * <ul>
18423      *   <li><b>Blank</b>: Defaults to aligning the element's top-left corner to the target's bottom-left corner ("tl-bl").</li>
18424      *   <li><b>One anchor (deprecated)</b>: The passed anchor position is used as the target element's anchor point.
18425      *       The element being aligned will position its top-left corner (tl) to that point.  <i>This method has been
18426      *       deprecated in favor of the newer two anchor syntax below</i>.</li>
18427      *   <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
18428      *       element's anchor point, and the second value is used as the target's anchor point.</li>
18429      * </ul>
18430      * In addition to the anchor points, the position parameter also supports the "?" character.  If "?" is passed at the end of
18431      * the position string, the element will attempt to align as specified, but the position will be adjusted to constrain to
18432      * the viewport if necessary.  Note that the element being aligned might be swapped to align to a different position than
18433      * that specified in order to enforce the viewport constraints.
18434      * Following are all of the supported anchor positions:
18435 <pre>
18436 Value  Description
18437 -----  -----------------------------
18438 tl     The top left corner (default)
18439 t      The center of the top edge
18440 tr     The top right corner
18441 l      The center of the left edge
18442 c      In the center of the element
18443 r      The center of the right edge
18444 bl     The bottom left corner
18445 b      The center of the bottom edge
18446 br     The bottom right corner
18447 </pre>
18448 Example Usage:
18449 <pre><code>
18450 // align el to other-el using the default positioning ("tl-bl", non-constrained)
18451 el.alignTo("other-el");
18452
18453 // align the top left corner of el with the top right corner of other-el (constrained to viewport)
18454 el.alignTo("other-el", "tr?");
18455
18456 // align the bottom right corner of el with the center left edge of other-el
18457 el.alignTo("other-el", "br-l?");
18458
18459 // align the center of el with the bottom left corner of other-el and
18460 // adjust the x position by -6 pixels (and the y position by 0)
18461 el.alignTo("other-el", "c-bl", [-6, 0]);
18462 </code></pre>
18463      * @param {Mixed} element The element to align to.
18464      * @param {String} position (optional, defaults to "tl-bl?") The position to align to.
18465      * @param {Array} offsets (optional) Offset the positioning by [x, y]
18466      * @param {Boolean/Object} animate (optional) true for the default animation or a standard Element animation config object
18467      * @return {Ext.core.Element} this
18468      */
18469     alignTo : function(element, position, offsets, animate){
18470         var me = this;
18471         return me.setXY(me.getAlignToXY(element, position, offsets),
18472                         me.anim && !!animate ? me.anim(animate) : false);
18473     },
18474
18475     // private ==>  used outside of core
18476     adjustForConstraints : function(xy, parent) {
18477         var vector = this.getConstrainVector(parent, xy);
18478         if (vector) {
18479             xy[0] += vector[0];
18480             xy[1] += vector[1];
18481         }
18482         return xy;
18483     },
18484
18485     /**
18486      * <p>Returns the <code>[X, Y]</code> vector by which this element must be translated to make a best attempt
18487      * to constrain within the passed constraint. Returns <code>false</code> is this element does not need to be moved.</p>
18488      * <p>Priority is given to constraining the top and left within the constraint.</p>
18489      * <p>The constraint may either be an existing element into which this element is to be constrained, or
18490      * an {@link Ext.util.Region Region} into which this element is to be constrained.</p>
18491      * @param constrainTo {Mixed} The Element or {@link Ext.util.Region Region} into which this element is to be constrained.
18492      * @param proposedPosition {Array} A proposed <code>[X, Y]</code> position to test for validity and to produce a vector for instead
18493      * of using this Element's current position;
18494      * @returns {Array} <b>If</b> this element <i>needs</i> to be translated, an <code>[X, Y]</code>
18495      * vector by which this element must be translated. Otherwise, <code>false</code>.
18496      */
18497     getConstrainVector: function(constrainTo, proposedPosition) {
18498         if (!(constrainTo instanceof Ext.util.Region)) {
18499             constrainTo = Ext.get(constrainTo).getViewRegion();
18500         }
18501         var thisRegion = this.getRegion(),
18502             vector = [0, 0],
18503             shadowSize = this.shadow && this.shadow.offset,
18504             overflowed = false;
18505
18506         // Shift this region to occupy the proposed position
18507         if (proposedPosition) {
18508             thisRegion.translateBy(proposedPosition[0] - thisRegion.x, proposedPosition[1] - thisRegion.y);
18509         }
18510
18511         // Reduce the constrain region to allow for shadow
18512         // TODO: Rewrite the Shadow class. When that's done, get the extra for each side from the Shadow.
18513         if (shadowSize) {
18514             constrainTo.adjust(0, -shadowSize, -shadowSize, shadowSize);
18515         }
18516
18517         // Constrain the X coordinate by however much this Element overflows
18518         if (thisRegion.right > constrainTo.right) {
18519             overflowed = true;
18520             vector[0] = (constrainTo.right - thisRegion.right);    // overflowed the right
18521         }
18522         if (thisRegion.left + vector[0] < constrainTo.left) {
18523             overflowed = true;
18524             vector[0] = (constrainTo.left - thisRegion.left);      // overflowed the left
18525         }
18526
18527         // Constrain the Y coordinate by however much this Element overflows
18528         if (thisRegion.bottom > constrainTo.bottom) {
18529             overflowed = true;
18530             vector[1] = (constrainTo.bottom - thisRegion.bottom);  // overflowed the bottom
18531         }
18532         if (thisRegion.top + vector[1] < constrainTo.top) {
18533             overflowed = true;
18534             vector[1] = (constrainTo.top - thisRegion.top);        // overflowed the top
18535         }
18536         return overflowed ? vector : false;
18537     },
18538
18539     /**
18540     * Calculates the x, y to center this element on the screen
18541     * @return {Array} The x, y values [x, y]
18542     */
18543     getCenterXY : function(){
18544         return this.getAlignToXY(document, 'c-c');
18545     },
18546
18547     /**
18548     * Centers the Element in either the viewport, or another Element.
18549     * @param {Mixed} centerIn (optional) The element in which to center the element.
18550     */
18551     center : function(centerIn){
18552         return this.alignTo(centerIn || document, 'c-c');
18553     }
18554 });
18555
18556 /**
18557  * @class Ext.core.Element
18558  */
18559 (function(){
18560
18561 var ELEMENT = Ext.core.Element,
18562     LEFT = "left",
18563     RIGHT = "right",
18564     TOP = "top",
18565     BOTTOM = "bottom",
18566     POSITION = "position",
18567     STATIC = "static",
18568     RELATIVE = "relative",
18569     AUTO = "auto",
18570     ZINDEX = "z-index";
18571
18572 Ext.override(Ext.core.Element, {
18573     /**
18574       * 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).
18575       * @return {Number} The X position of the element
18576       */
18577     getX : function(){
18578         return ELEMENT.getX(this.dom);
18579     },
18580
18581     /**
18582       * 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).
18583       * @return {Number} The Y position of the element
18584       */
18585     getY : function(){
18586         return ELEMENT.getY(this.dom);
18587     },
18588
18589     /**
18590       * 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).
18591       * @return {Array} The XY position of the element
18592       */
18593     getXY : function(){
18594         return ELEMENT.getXY(this.dom);
18595     },
18596
18597     /**
18598       * 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.
18599       * @param {Mixed} element The element to get the offsets from.
18600       * @return {Array} The XY page offsets (e.g. [100, -200])
18601       */
18602     getOffsetsTo : function(el){
18603         var o = this.getXY(),
18604             e = Ext.fly(el, '_internal').getXY();
18605         return [o[0]-e[0],o[1]-e[1]];
18606     },
18607
18608     /**
18609      * 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).
18610      * @param {Number} The X position of the element
18611      * @param {Boolean/Object} animate (optional) True for the default animation, or a standard Element animation config object
18612      * @return {Ext.core.Element} this
18613      */
18614     setX : function(x, animate){
18615         return this.setXY([x, this.getY()], animate);
18616     },
18617
18618     /**
18619      * 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).
18620      * @param {Number} The Y position of the element
18621      * @param {Boolean/Object} animate (optional) True for the default animation, or a standard Element animation config object
18622      * @return {Ext.core.Element} this
18623      */
18624     setY : function(y, animate){
18625         return this.setXY([this.getX(), y], animate);
18626     },
18627
18628     /**
18629      * Sets the element's left position directly using CSS style (instead of {@link #setX}).
18630      * @param {String} left The left CSS property value
18631      * @return {Ext.core.Element} this
18632      */
18633     setLeft : function(left){
18634         this.setStyle(LEFT, this.addUnits(left));
18635         return this;
18636     },
18637
18638     /**
18639      * Sets the element's top position directly using CSS style (instead of {@link #setY}).
18640      * @param {String} top The top CSS property value
18641      * @return {Ext.core.Element} this
18642      */
18643     setTop : function(top){
18644         this.setStyle(TOP, this.addUnits(top));
18645         return this;
18646     },
18647
18648     /**
18649      * Sets the element's CSS right style.
18650      * @param {String} right The right CSS property value
18651      * @return {Ext.core.Element} this
18652      */
18653     setRight : function(right){
18654         this.setStyle(RIGHT, this.addUnits(right));
18655         return this;
18656     },
18657
18658     /**
18659      * Sets the element's CSS bottom style.
18660      * @param {String} bottom The bottom CSS property value
18661      * @return {Ext.core.Element} this
18662      */
18663     setBottom : function(bottom){
18664         this.setStyle(BOTTOM, this.addUnits(bottom));
18665         return this;
18666     },
18667
18668     /**
18669      * Sets the position of the element in page coordinates, regardless of how the element is positioned.
18670      * The element must be part of the DOM tree to have page coordinates (display:none or elements not appended return false).
18671      * @param {Array} pos Contains X & Y [x, y] values for new position (coordinates are page-based)
18672      * @param {Boolean/Object} animate (optional) True for the default animation, or a standard Element animation config object
18673      * @return {Ext.core.Element} this
18674      */
18675     setXY: function(pos, animate) {
18676         var me = this;
18677         if (!animate || !me.anim) {
18678             ELEMENT.setXY(me.dom, pos);
18679         }
18680         else {
18681             if (!Ext.isObject(animate)) {
18682                 animate = {};
18683             }
18684             me.animate(Ext.applyIf({ to: { x: pos[0], y: pos[1] } }, animate));
18685         }
18686         return me;
18687     },
18688
18689     /**
18690      * Sets the position of the element in page coordinates, regardless of how the element is positioned.
18691      * The element must be part of the DOM tree to have page coordinates (display:none or elements not appended return false).
18692      * @param {Number} x X value for new position (coordinates are page-based)
18693      * @param {Number} y Y value for new position (coordinates are page-based)
18694      * @param {Boolean/Object} animate (optional) True for the default animation, or a standard Element animation config object
18695      * @return {Ext.core.Element} this
18696      */
18697     setLocation : function(x, y, animate){
18698         return this.setXY([x, y], animate);
18699     },
18700
18701     /**
18702      * Sets the position of the element in page coordinates, regardless of how the element is positioned.
18703      * The element must be part of the DOM tree to have page coordinates (display:none or elements not appended return false).
18704      * @param {Number} x X value for new position (coordinates are page-based)
18705      * @param {Number} y Y value for new position (coordinates are page-based)
18706      * @param {Boolean/Object} animate (optional) True for the default animation, or a standard Element animation config object
18707      * @return {Ext.core.Element} this
18708      */
18709     moveTo : function(x, y, animate){
18710         return this.setXY([x, y], animate);
18711     },
18712
18713     /**
18714      * Gets the left X coordinate
18715      * @param {Boolean} local True to get the local css position instead of page coordinate
18716      * @return {Number}
18717      */
18718     getLeft : function(local){
18719         return !local ? this.getX() : parseInt(this.getStyle(LEFT), 10) || 0;
18720     },
18721
18722     /**
18723      * Gets the right X coordinate of the element (element X position + element width)
18724      * @param {Boolean} local True to get the local css position instead of page coordinate
18725      * @return {Number}
18726      */
18727     getRight : function(local){
18728         var me = this;
18729         return !local ? me.getX() + me.getWidth() : (me.getLeft(true) + me.getWidth()) || 0;
18730     },
18731
18732     /**
18733      * Gets the top Y coordinate
18734      * @param {Boolean} local True to get the local css position instead of page coordinate
18735      * @return {Number}
18736      */
18737     getTop : function(local) {
18738         return !local ? this.getY() : parseInt(this.getStyle(TOP), 10) || 0;
18739     },
18740
18741     /**
18742      * Gets the bottom Y coordinate of the element (element Y position + element height)
18743      * @param {Boolean} local True to get the local css position instead of page coordinate
18744      * @return {Number}
18745      */
18746     getBottom : function(local){
18747         var me = this;
18748         return !local ? me.getY() + me.getHeight() : (me.getTop(true) + me.getHeight()) || 0;
18749     },
18750
18751     /**
18752     * Initializes positioning on this element. If a desired position is not passed, it will make the
18753     * the element positioned relative IF it is not already positioned.
18754     * @param {String} pos (optional) Positioning to use "relative", "absolute" or "fixed"
18755     * @param {Number} zIndex (optional) The zIndex to apply
18756     * @param {Number} x (optional) Set the page X position
18757     * @param {Number} y (optional) Set the page Y position
18758     */
18759     position : function(pos, zIndex, x, y) {
18760         var me = this;
18761
18762         if (!pos && me.isStyle(POSITION, STATIC)){
18763             me.setStyle(POSITION, RELATIVE);
18764         } else if(pos) {
18765             me.setStyle(POSITION, pos);
18766         }
18767         if (zIndex){
18768             me.setStyle(ZINDEX, zIndex);
18769         }
18770         if (x || y) {
18771             me.setXY([x || false, y || false]);
18772         }
18773     },
18774
18775     /**
18776     * Clear positioning back to the default when the document was loaded
18777     * @param {String} value (optional) The value to use for the left,right,top,bottom, defaults to '' (empty string). You could use 'auto'.
18778     * @return {Ext.core.Element} this
18779      */
18780     clearPositioning : function(value){
18781         value = value || '';
18782         this.setStyle({
18783             left : value,
18784             right : value,
18785             top : value,
18786             bottom : value,
18787             "z-index" : "",
18788             position : STATIC
18789         });
18790         return this;
18791     },
18792
18793     /**
18794     * Gets an object with all CSS positioning properties. Useful along with setPostioning to get
18795     * snapshot before performing an update and then restoring the element.
18796     * @return {Object}
18797     */
18798     getPositioning : function(){
18799         var l = this.getStyle(LEFT);
18800         var t = this.getStyle(TOP);
18801         return {
18802             "position" : this.getStyle(POSITION),
18803             "left" : l,
18804             "right" : l ? "" : this.getStyle(RIGHT),
18805             "top" : t,
18806             "bottom" : t ? "" : this.getStyle(BOTTOM),
18807             "z-index" : this.getStyle(ZINDEX)
18808         };
18809     },
18810
18811     /**
18812     * Set positioning with an object returned by getPositioning().
18813     * @param {Object} posCfg
18814     * @return {Ext.core.Element} this
18815      */
18816     setPositioning : function(pc){
18817         var me = this,
18818             style = me.dom.style;
18819
18820         me.setStyle(pc);
18821
18822         if(pc.right == AUTO){
18823             style.right = "";
18824         }
18825         if(pc.bottom == AUTO){
18826             style.bottom = "";
18827         }
18828
18829         return me;
18830     },
18831
18832     /**
18833      * Translates the passed page coordinates into left/top css values for this element
18834      * @param {Number/Array} x The page x or an array containing [x, y]
18835      * @param {Number} y (optional) The page y, required if x is not an array
18836      * @return {Object} An object with left and top properties. e.g. {left: (value), top: (value)}
18837      */
18838     translatePoints: function(x, y) {
18839         if (Ext.isArray(x)) {
18840              y = x[1];
18841              x = x[0];
18842         }
18843         var me = this,
18844             relative = me.isStyle(POSITION, RELATIVE),
18845             o = me.getXY(),
18846             left = parseInt(me.getStyle(LEFT), 10),
18847             top = parseInt(me.getStyle(TOP), 10);
18848
18849         if (!Ext.isNumber(left)) {
18850             left = relative ? 0 : me.dom.offsetLeft;
18851         }
18852         if (!Ext.isNumber(top)) {
18853             top = relative ? 0 : me.dom.offsetTop;
18854         }
18855         left = (Ext.isNumber(x)) ? x - o[0] + left : undefined;
18856         top = (Ext.isNumber(y)) ? y - o[1] + top : undefined;
18857         return {
18858             left: left,
18859             top: top
18860         };
18861     },
18862
18863     /**
18864      * 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.
18865      * @param {Object} box The box to fill {x, y, width, height}
18866      * @param {Boolean} adjust (optional) Whether to adjust for box-model issues automatically
18867      * @param {Boolean/Object} animate (optional) true for the default animation or a standard Element animation config object
18868      * @return {Ext.core.Element} this
18869      */
18870     setBox: function(box, adjust, animate) {
18871         var me = this,
18872             w = box.width,
18873             h = box.height;
18874         if ((adjust && !me.autoBoxAdjust) && !me.isBorderBox()) {
18875             w -= (me.getBorderWidth("lr") + me.getPadding("lr"));
18876             h -= (me.getBorderWidth("tb") + me.getPadding("tb"));
18877         }
18878         me.setBounds(box.x, box.y, w, h, animate);
18879         return me;
18880     },
18881
18882     /**
18883      * Return an object defining the area of this Element which can be passed to {@link #setBox} to
18884      * set another Element's size/location to match this element.
18885      * @param {Boolean} contentBox (optional) If true a box for the content of the element is returned.
18886      * @param {Boolean} local (optional) If true the element's left and top are returned instead of page x/y.
18887      * @return {Object} box An object in the format<pre><code>
18888 {
18889     x: &lt;Element's X position>,
18890     y: &lt;Element's Y position>,
18891     width: &lt;Element's width>,
18892     height: &lt;Element's height>,
18893     bottom: &lt;Element's lower bound>,
18894     right: &lt;Element's rightmost bound>
18895 }
18896 </code></pre>
18897      * The returned object may also be addressed as an Array where index 0 contains the X position
18898      * and index 1 contains the Y position. So the result may also be used for {@link #setXY}
18899      */
18900     getBox: function(contentBox, local) {
18901         var me = this,
18902             xy,
18903             left,
18904             top,
18905             getBorderWidth = me.getBorderWidth,
18906             getPadding = me.getPadding,
18907             l, r, t, b, w, h, bx;
18908         if (!local) {
18909             xy = me.getXY();
18910         } else {
18911             left = parseInt(me.getStyle("left"), 10) || 0;
18912             top = parseInt(me.getStyle("top"), 10) || 0;
18913             xy = [left, top];
18914         }
18915         w = me.getWidth();
18916         h = me.getHeight();
18917         if (!contentBox) {
18918             bx = {
18919                 x: xy[0],
18920                 y: xy[1],
18921                 0: xy[0],
18922                 1: xy[1],
18923                 width: w,
18924                 height: h
18925             };
18926         } else {
18927             l = getBorderWidth.call(me, "l") + getPadding.call(me, "l");
18928             r = getBorderWidth.call(me, "r") + getPadding.call(me, "r");
18929             t = getBorderWidth.call(me, "t") + getPadding.call(me, "t");
18930             b = getBorderWidth.call(me, "b") + getPadding.call(me, "b");
18931             bx = {
18932                 x: xy[0] + l,
18933                 y: xy[1] + t,
18934                 0: xy[0] + l,
18935                 1: xy[1] + t,
18936                 width: w - (l + r),
18937                 height: h - (t + b)
18938             };
18939         }
18940         bx.right = bx.x + bx.width;
18941         bx.bottom = bx.y + bx.height;
18942         return bx;
18943     },
18944
18945     /**
18946      * Move this element relative to its current position.
18947      * @param {String} direction Possible values are: "l" (or "left"), "r" (or "right"), "t" (or "top", or "up"), "b" (or "bottom", or "down").
18948      * @param {Number} distance How far to move the element in pixels
18949      * @param {Boolean/Object} animate (optional) true for the default animation or a standard Element animation config object
18950      * @return {Ext.core.Element} this
18951      */
18952     move: function(direction, distance, animate) {
18953         var me = this,
18954             xy = me.getXY(),
18955             x = xy[0],
18956             y = xy[1],
18957             left = [x - distance, y],
18958             right = [x + distance, y],
18959             top = [x, y - distance],
18960             bottom = [x, y + distance],
18961             hash = {
18962                 l: left,
18963                 left: left,
18964                 r: right,
18965                 right: right,
18966                 t: top,
18967                 top: top,
18968                 up: top,
18969                 b: bottom,
18970                 bottom: bottom,
18971                 down: bottom
18972             };
18973
18974         direction = direction.toLowerCase();
18975         me.moveTo(hash[direction][0], hash[direction][1], animate);
18976     },
18977
18978     /**
18979      * Quick set left and top adding default units
18980      * @param {String} left The left CSS property value
18981      * @param {String} top The top CSS property value
18982      * @return {Ext.core.Element} this
18983      */
18984     setLeftTop: function(left, top) {
18985         var me = this,
18986             style = me.dom.style;
18987         style.left = me.addUnits(left);
18988         style.top = me.addUnits(top);
18989         return me;
18990     },
18991
18992     /**
18993      * Returns the region of this element.
18994      * The element must be part of the DOM tree to have a region (display:none or elements not appended return false).
18995      * @return {Region} A Ext.util.Region containing "top, left, bottom, right" member data.
18996      */
18997     getRegion: function() {
18998         return this.getPageBox(true);
18999     },
19000
19001     /**
19002      * Returns the <b>content</b> region of this element. That is the region within the borders and padding.
19003      * @return {Region} A Ext.util.Region containing "top, left, bottom, right" member data.
19004      */
19005     getViewRegion: function() {
19006         var me = this,
19007             isBody = me.dom === document.body,
19008             scroll, pos, top, left, width, height;
19009             
19010         // For the body we want to do some special logic
19011         if (isBody) {
19012             scroll = me.getScroll();
19013             left = scroll.left;
19014             top = scroll.top;
19015             width = Ext.core.Element.getViewportWidth();
19016             height = Ext.core.Element.getViewportHeight();
19017         }
19018         else {
19019             pos = me.getXY();
19020             left = pos[0] + me.getBorderWidth('l') + me.getPadding('l');
19021             top = pos[1] + me.getBorderWidth('t') + me.getPadding('t');
19022             width = me.getWidth(true);
19023             height = me.getHeight(true);
19024         }
19025
19026         return Ext.create('Ext.util.Region', top, left + width, top + height, left);
19027     },
19028
19029     /**
19030      * Return an object defining the area of this Element which can be passed to {@link #setBox} to
19031      * set another Element's size/location to match this element.
19032      * @param {Boolean} asRegion(optional) If true an Ext.util.Region will be returned
19033      * @return {Object} box An object in the format<pre><code>
19034 {
19035     x: &lt;Element's X position>,
19036     y: &lt;Element's Y position>,
19037     width: &lt;Element's width>,
19038     height: &lt;Element's height>,
19039     bottom: &lt;Element's lower bound>,
19040     right: &lt;Element's rightmost bound>
19041 }
19042 </code></pre>
19043      * The returned object may also be addressed as an Array where index 0 contains the X position
19044      * and index 1 contains the Y position. So the result may also be used for {@link #setXY}
19045      */
19046     getPageBox : function(getRegion) {
19047         var me = this,
19048             el = me.dom,
19049             isDoc = el === document.body,
19050             w = isDoc ? Ext.core.Element.getViewWidth()  : el.offsetWidth,
19051             h = isDoc ? Ext.core.Element.getViewHeight() : el.offsetHeight,
19052             xy = me.getXY(),
19053             t = xy[1],
19054             r = xy[0] + w,
19055             b = xy[1] + h,
19056             l = xy[0];
19057
19058         if (getRegion) {
19059             return Ext.create('Ext.util.Region', t, r, b, l);
19060         }
19061         else {
19062             return {
19063                 left: l,
19064                 top: t,
19065                 width: w,
19066                 height: h,
19067                 right: r,
19068                 bottom: b
19069             };
19070         }
19071     },
19072
19073     /**
19074      * Sets the element's position and size in one shot. If animation is true then width, height, x and y will be animated concurrently.
19075      * @param {Number} x X value for new position (coordinates are page-based)
19076      * @param {Number} y Y value for new position (coordinates are page-based)
19077      * @param {Mixed} width The new width. This may be one of:<div class="mdetail-params"><ul>
19078      * <li>A Number specifying the new width in this Element's {@link #defaultUnit}s (by default, pixels)</li>
19079      * <li>A String used to set the CSS width style. Animation may <b>not</b> be used.
19080      * </ul></div>
19081      * @param {Mixed} height The new height. This may be one of:<div class="mdetail-params"><ul>
19082      * <li>A Number specifying the new height in this Element's {@link #defaultUnit}s (by default, pixels)</li>
19083      * <li>A String used to set the CSS height style. Animation may <b>not</b> be used.</li>
19084      * </ul></div>
19085      * @param {Boolean/Object} animate (optional) true for the default animation or a standard Element animation config object
19086      * @return {Ext.core.Element} this
19087      */
19088     setBounds: function(x, y, width, height, animate) {
19089         var me = this;
19090         if (!animate || !me.anim) {
19091             me.setSize(width, height);
19092             me.setLocation(x, y);
19093         } else {
19094             if (!Ext.isObject(animate)) {
19095                 animate = {};
19096             }
19097             me.animate(Ext.applyIf({
19098                 to: {
19099                     x: x,
19100                     y: y,
19101                     width: me.adjustWidth(width),
19102                     height: me.adjustHeight(height)
19103                 }
19104             }, animate));
19105         }
19106         return me;
19107     },
19108
19109     /**
19110      * Sets the element's position and size the specified region. If animation is true then width, height, x and y will be animated concurrently.
19111      * @param {Ext.util.Region} region The region to fill
19112      * @param {Boolean/Object} animate (optional) true for the default animation or a standard Element animation config object
19113      * @return {Ext.core.Element} this
19114      */
19115     setRegion: function(region, animate) {
19116         return this.setBounds(region.left, region.top, region.right - region.left, region.bottom - region.top, animate);
19117     }
19118 });
19119 })();
19120
19121 /**
19122  * @class Ext.core.Element
19123  */
19124 Ext.override(Ext.core.Element, {
19125     /**
19126      * Returns true if this element is scrollable.
19127      * @return {Boolean}
19128      */
19129     isScrollable : function(){
19130         var dom = this.dom;
19131         return dom.scrollHeight > dom.clientHeight || dom.scrollWidth > dom.clientWidth;
19132     },
19133
19134     /**
19135      * Returns the current scroll position of the element.
19136      * @return {Object} An object containing the scroll position in the format {left: (scrollLeft), top: (scrollTop)}
19137      */
19138     getScroll : function() {
19139         var d = this.dom, 
19140             doc = document,
19141             body = doc.body,
19142             docElement = doc.documentElement,
19143             l,
19144             t,
19145             ret;
19146
19147         if (d == doc || d == body) {
19148             if (Ext.isIE && Ext.isStrict) {
19149                 l = docElement.scrollLeft; 
19150                 t = docElement.scrollTop;
19151             } else {
19152                 l = window.pageXOffset;
19153                 t = window.pageYOffset;
19154             }
19155             ret = {
19156                 left: l || (body ? body.scrollLeft : 0), 
19157                 top : t || (body ? body.scrollTop : 0)
19158             };
19159         } else {
19160             ret = {
19161                 left: d.scrollLeft, 
19162                 top : d.scrollTop
19163             };
19164         }
19165         
19166         return ret;
19167     },
19168     
19169     /**
19170      * 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().
19171      * @param {String} side Either "left" for scrollLeft values or "top" for scrollTop values.
19172      * @param {Number} value The new scroll value
19173      * @param {Boolean/Object} animate (optional) true for the default animation or a standard Element animation config object
19174      * @return {Element} this
19175      */
19176     scrollTo : function(side, value, animate) {
19177         //check if we're scrolling top or left
19178         var top = /top/i.test(side),
19179             me = this,
19180             dom = me.dom,
19181             obj = {},
19182             prop;
19183         if (!animate || !me.anim) {
19184             // just setting the value, so grab the direction
19185             prop = 'scroll' + (top ? 'Top' : 'Left');
19186             dom[prop] = value;
19187         }
19188         else {
19189             if (!Ext.isObject(animate)) {
19190                 animate = {};
19191             }
19192             obj['scroll' + (top ? 'Top' : 'Left')] = value;
19193             me.animate(Ext.applyIf({
19194                 to: obj
19195             }, animate));
19196         }
19197         return me;
19198     },
19199
19200     /**
19201      * Scrolls this element into view within the passed container.
19202      * @param {Mixed} container (optional) The container element to scroll (defaults to document.body).  Should be a
19203      * string (id), dom node, or Ext.core.Element.
19204      * @param {Boolean} hscroll (optional) False to disable horizontal scroll (defaults to true)
19205      * @return {Ext.core.Element} this
19206      */
19207     scrollIntoView : function(container, hscroll) {
19208         container = Ext.getDom(container) || Ext.getBody().dom;
19209         var el = this.dom,
19210             offsets = this.getOffsetsTo(container),
19211             // el's box
19212             left = offsets[0] + container.scrollLeft,
19213             top = offsets[1] + container.scrollTop,
19214             bottom = top + el.offsetHeight,
19215             right = left + el.offsetWidth,
19216             // ct's box
19217             ctClientHeight = container.clientHeight,
19218             ctScrollTop = parseInt(container.scrollTop, 10),
19219             ctScrollLeft = parseInt(container.scrollLeft, 10),
19220             ctBottom = ctScrollTop + ctClientHeight,
19221             ctRight = ctScrollLeft + container.clientWidth;
19222
19223         if (el.offsetHeight > ctClientHeight || top < ctScrollTop) {
19224             container.scrollTop = top;
19225         } else if (bottom > ctBottom) {
19226             container.scrollTop = bottom - ctClientHeight;
19227         }
19228         // corrects IE, other browsers will ignore
19229         container.scrollTop = container.scrollTop;
19230
19231         if (hscroll !== false) {
19232             if (el.offsetWidth > container.clientWidth || left < ctScrollLeft) {
19233                 container.scrollLeft = left;
19234             }
19235             else if (right > ctRight) {
19236                 container.scrollLeft = right - container.clientWidth;
19237             }
19238             container.scrollLeft = container.scrollLeft;
19239         }
19240         return this;
19241     },
19242
19243     // private
19244     scrollChildIntoView : function(child, hscroll) {
19245         Ext.fly(child, '_scrollChildIntoView').scrollIntoView(this, hscroll);
19246     },
19247
19248     /**
19249      * Scrolls this element the specified direction. Does bounds checking to make sure the scroll is
19250      * within this element's scrollable range.
19251      * @param {String} direction Possible values are: "l" (or "left"), "r" (or "right"), "t" (or "top", or "up"), "b" (or "bottom", or "down").
19252      * @param {Number} distance How far to scroll the element in pixels
19253      * @param {Boolean/Object} animate (optional) true for the default animation or a standard Element animation config object
19254      * @return {Boolean} Returns true if a scroll was triggered or false if the element
19255      * was scrolled as far as it could go.
19256      */
19257      scroll : function(direction, distance, animate) {
19258         if (!this.isScrollable()) {
19259             return false;
19260         }
19261         var el = this.dom,
19262             l = el.scrollLeft, t = el.scrollTop,
19263             w = el.scrollWidth, h = el.scrollHeight,
19264             cw = el.clientWidth, ch = el.clientHeight,
19265             scrolled = false, v,
19266             hash = {
19267                 l: Math.min(l + distance, w-cw),
19268                 r: v = Math.max(l - distance, 0),
19269                 t: Math.max(t - distance, 0),
19270                 b: Math.min(t + distance, h-ch)
19271             };
19272             hash.d = hash.b;
19273             hash.u = hash.t;
19274
19275         direction = direction.substr(0, 1);
19276         if ((v = hash[direction]) > -1) {
19277             scrolled = true;
19278             this.scrollTo(direction == 'l' || direction == 'r' ? 'left' : 'top', v, this.anim(animate));
19279         }
19280         return scrolled;
19281     }
19282 });
19283 /**
19284  * @class Ext.core.Element
19285  */
19286 Ext.core.Element.addMethods(
19287     function() {
19288         var VISIBILITY      = "visibility",
19289             DISPLAY         = "display",
19290             HIDDEN          = "hidden",
19291             NONE            = "none",
19292             XMASKED         = Ext.baseCSSPrefix + "masked",
19293             XMASKEDRELATIVE = Ext.baseCSSPrefix + "masked-relative",
19294             data            = Ext.core.Element.data;
19295
19296         return {
19297             /**
19298              * Checks whether the element is currently visible using both visibility and display properties.
19299              * @param {Boolean} deep (optional) True to walk the dom and see if parent elements are hidden (defaults to false)
19300              * @return {Boolean} True if the element is currently visible, else false
19301              */
19302             isVisible : function(deep) {
19303                 var vis = !this.isStyle(VISIBILITY, HIDDEN) && !this.isStyle(DISPLAY, NONE),
19304                     p   = this.dom.parentNode;
19305
19306                 if (deep !== true || !vis) {
19307                     return vis;
19308                 }
19309
19310                 while (p && !(/^body/i.test(p.tagName))) {
19311                     if (!Ext.fly(p, '_isVisible').isVisible()) {
19312                         return false;
19313                     }
19314                     p = p.parentNode;
19315                 }
19316                 return true;
19317             },
19318
19319             /**
19320              * Returns true if display is not "none"
19321              * @return {Boolean}
19322              */
19323             isDisplayed : function() {
19324                 return !this.isStyle(DISPLAY, NONE);
19325             },
19326
19327             /**
19328              * Convenience method for setVisibilityMode(Element.DISPLAY)
19329              * @param {String} display (optional) What to set display to when visible
19330              * @return {Ext.core.Element} this
19331              */
19332             enableDisplayMode : function(display) {
19333                 this.setVisibilityMode(Ext.core.Element.DISPLAY);
19334
19335                 if (!Ext.isEmpty(display)) {
19336                     data(this.dom, 'originalDisplay', display);
19337                 }
19338
19339                 return this;
19340             },
19341
19342             /**
19343              * Puts a mask over this element to disable user interaction. Requires core.css.
19344              * This method can only be applied to elements which accept child nodes.
19345              * @param {String} msg (optional) A message to display in the mask
19346              * @param {String} msgCls (optional) A css class to apply to the msg element
19347              * @return {Element} The mask element
19348              */
19349             mask : function(msg, msgCls) {
19350                 var me  = this,
19351                     dom = me.dom,
19352                     setExpression = dom.style.setExpression,
19353                     dh  = Ext.core.DomHelper,
19354                     EXTELMASKMSG = Ext.baseCSSPrefix + "mask-msg",
19355                     el,
19356                     mask;
19357
19358                 if (!(/^body/i.test(dom.tagName) && me.getStyle('position') == 'static')) {
19359                     me.addCls(XMASKEDRELATIVE);
19360                 }
19361                 el = data(dom, 'maskMsg');
19362                 if (el) {
19363                     el.remove();
19364                 }
19365                 el = data(dom, 'mask');
19366                 if (el) {
19367                     el.remove();
19368                 }
19369
19370                 mask = dh.append(dom, {cls : Ext.baseCSSPrefix + "mask"}, true);
19371                 data(dom, 'mask', mask);
19372
19373                 me.addCls(XMASKED);
19374                 mask.setDisplayed(true);
19375
19376                 if (typeof msg == 'string') {
19377                     var mm = dh.append(dom, {cls : EXTELMASKMSG, cn:{tag:'div'}}, true);
19378                     data(dom, 'maskMsg', mm);
19379                     mm.dom.className = msgCls ? EXTELMASKMSG + " " + msgCls : EXTELMASKMSG;
19380                     mm.dom.firstChild.innerHTML = msg;
19381                     mm.setDisplayed(true);
19382                     mm.center(me);
19383                 }
19384                 // NOTE: CSS expressions are resource intensive and to be used only as a last resort
19385                 // These expressions are removed as soon as they are no longer necessary - in the unmask method.
19386                 // In normal use cases an element will be masked for a limited period of time.
19387                 // Fix for https://sencha.jira.com/browse/EXTJSIV-19.
19388                 // IE6 strict mode and IE6-9 quirks mode takes off left+right padding when calculating width!
19389                 if (!Ext.supports.IncludePaddingInWidthCalculation && setExpression) {
19390                     mask.dom.style.setExpression('width', 'this.parentNode.offsetWidth + "px"');
19391                 }
19392
19393                 // Some versions and modes of IE subtract top+bottom padding when calculating height.
19394                 // Different versions from those which make the same error for width!
19395                 if (!Ext.supports.IncludePaddingInHeightCalculation && setExpression) {
19396                     mask.dom.style.setExpression('height', 'this.parentNode.offsetHeight + "px"');
19397                 }
19398                 // ie will not expand full height automatically
19399                 else if (Ext.isIE && !(Ext.isIE7 && Ext.isStrict) && me.getStyle('height') == 'auto') {
19400                     mask.setSize(undefined, me.getHeight());
19401                 }
19402                 return mask;
19403             },
19404
19405             /**
19406              * Removes a previously applied mask.
19407              */
19408             unmask : function() {
19409                 var me      = this,
19410                     dom     = me.dom,
19411                     mask    = data(dom, 'mask'),
19412                     maskMsg = data(dom, 'maskMsg');
19413
19414                 if (mask) {
19415                     // Remove resource-intensive CSS expressions as soon as they are not required.
19416                     if (mask.dom.style.clearExpression) {
19417                         mask.dom.style.clearExpression('width');
19418                         mask.dom.style.clearExpression('height');
19419                     }
19420                     if (maskMsg) {
19421                         maskMsg.remove();
19422                         data(dom, 'maskMsg', undefined);
19423                     }
19424
19425                     mask.remove();
19426                     data(dom, 'mask', undefined);
19427                     me.removeCls([XMASKED, XMASKEDRELATIVE]);
19428                 }
19429             },
19430             /**
19431              * Returns true if this element is masked. Also re-centers any displayed message within the mask.
19432              * @return {Boolean}
19433              */
19434             isMasked : function() {
19435                 var me = this,
19436                     mask = data(me.dom, 'mask'),
19437                     maskMsg = data(me.dom, 'maskMsg');
19438
19439                 if (mask && mask.isVisible()) {
19440                     if (maskMsg) {
19441                         maskMsg.center(me);
19442                     }
19443                     return true;
19444                 }
19445                 return false;
19446             },
19447
19448             /**
19449              * Creates an iframe shim for this element to keep selects and other windowed objects from
19450              * showing through.
19451              * @return {Ext.core.Element} The new shim element
19452              */
19453             createShim : function() {
19454                 var el = document.createElement('iframe'),
19455                     shim;
19456
19457                 el.frameBorder = '0';
19458                 el.className = Ext.baseCSSPrefix + 'shim';
19459                 el.src = Ext.SSL_SECURE_URL;
19460                 shim = Ext.get(this.dom.parentNode.insertBefore(el, this.dom));
19461                 shim.autoBoxAdjust = false;
19462                 return shim;
19463             }
19464         };
19465     }()
19466 );
19467 /**
19468  * @class Ext.core.Element
19469  */
19470 Ext.core.Element.addMethods({
19471     /**
19472      * Convenience method for constructing a KeyMap
19473      * @param {Number/Array/Object/String} key Either a string with the keys to listen for, the numeric key code, array of key codes or an object with the following options:
19474      * <code>{key: (number or array), shift: (true/false), ctrl: (true/false), alt: (true/false)}</code>
19475      * @param {Function} fn The function to call
19476      * @param {Object} scope (optional) The scope (<code>this</code> reference) in which the specified function is executed. Defaults to this Element.
19477      * @return {Ext.util.KeyMap} The KeyMap created
19478      */
19479     addKeyListener : function(key, fn, scope){
19480         var config;
19481         if(typeof key != 'object' || Ext.isArray(key)){
19482             config = {
19483                 key: key,
19484                 fn: fn,
19485                 scope: scope
19486             };
19487         }else{
19488             config = {
19489                 key : key.key,
19490                 shift : key.shift,
19491                 ctrl : key.ctrl,
19492                 alt : key.alt,
19493                 fn: fn,
19494                 scope: scope
19495             };
19496         }
19497         return Ext.create('Ext.util.KeyMap', this, config);
19498     },
19499
19500     /**
19501      * Creates a KeyMap for this element
19502      * @param {Object} config The KeyMap config. See {@link Ext.util.KeyMap} for more details
19503      * @return {Ext.util.KeyMap} The KeyMap created
19504      */
19505     addKeyMap : function(config){
19506         return Ext.create('Ext.util.KeyMap', this, config);
19507     }
19508 });
19509
19510 //Import the newly-added Ext.core.Element functions into CompositeElementLite. We call this here because
19511 //Element.keys.js is the last extra Ext.core.Element include in the ext-all.js build
19512 Ext.CompositeElementLite.importElementMethods();
19513
19514 /**
19515  * @class Ext.CompositeElementLite
19516  */
19517 Ext.apply(Ext.CompositeElementLite.prototype, {
19518     addElements : function(els, root){
19519         if(!els){
19520             return this;
19521         }
19522         if(typeof els == "string"){
19523             els = Ext.core.Element.selectorFunction(els, root);
19524         }
19525         var yels = this.elements;
19526         Ext.each(els, function(e) {
19527             yels.push(Ext.get(e));
19528         });
19529         return this;
19530     },
19531
19532     /**
19533      * Returns the first Element
19534      * @return {Ext.core.Element}
19535      */
19536     first : function(){
19537         return this.item(0);
19538     },
19539
19540     /**
19541      * Returns the last Element
19542      * @return {Ext.core.Element}
19543      */
19544     last : function(){
19545         return this.item(this.getCount()-1);
19546     },
19547
19548     /**
19549      * Returns true if this composite contains the passed element
19550      * @param el {Mixed} The id of an element, or an Ext.core.Element, or an HtmlElement to find within the composite collection.
19551      * @return Boolean
19552      */
19553     contains : function(el){
19554         return this.indexOf(el) != -1;
19555     },
19556
19557     /**
19558     * Removes the specified element(s).
19559     * @param {Mixed} el The id of an element, the Element itself, the index of the element in this composite
19560     * or an array of any of those.
19561     * @param {Boolean} removeDom (optional) True to also remove the element from the document
19562     * @return {CompositeElement} this
19563     */
19564     removeElement : function(keys, removeDom){
19565         var me = this,
19566             els = this.elements,
19567             el;
19568         Ext.each(keys, function(val){
19569             if ((el = (els[val] || els[val = me.indexOf(val)]))) {
19570                 if(removeDom){
19571                     if(el.dom){
19572                         el.remove();
19573                     }else{
19574                         Ext.removeNode(el);
19575                     }
19576                 }
19577                 els.splice(val, 1);
19578             }
19579         });
19580         return this;
19581     }
19582 });
19583
19584 /**
19585  * @class Ext.CompositeElement
19586  * @extends Ext.CompositeElementLite
19587  * <p>This class encapsulates a <i>collection</i> of DOM elements, providing methods to filter
19588  * members, or to perform collective actions upon the whole set.</p>
19589  * <p>Although they are not listed, this class supports all of the methods of {@link Ext.core.Element} and
19590  * {@link Ext.fx.Anim}. The methods from these classes will be performed on all the elements in this collection.</p>
19591  * <p>All methods return <i>this</i> and can be chained.</p>
19592  * Usage:
19593 <pre><code>
19594 var els = Ext.select("#some-el div.some-class", true);
19595 // or select directly from an existing element
19596 var el = Ext.get('some-el');
19597 el.select('div.some-class', true);
19598
19599 els.setWidth(100); // all elements become 100 width
19600 els.hide(true); // all elements fade out and hide
19601 // or
19602 els.setWidth(100).hide(true);
19603 </code></pre>
19604  */
19605 Ext.CompositeElement = Ext.extend(Ext.CompositeElementLite, {
19606     
19607     constructor : function(els, root){
19608         this.elements = [];
19609         this.add(els, root);
19610     },
19611     
19612     // private
19613     getElement : function(el){
19614         // In this case just return it, since we already have a reference to it
19615         return el;
19616     },
19617     
19618     // private
19619     transformElement : function(el){
19620         return Ext.get(el);
19621     }
19622
19623     /**
19624     * Adds elements to this composite.
19625     * @param {String/Array} els A string CSS selector, an array of elements or an element
19626     * @return {CompositeElement} this
19627     */
19628
19629     /**
19630      * Returns the Element object at the specified index
19631      * @param {Number} index
19632      * @return {Ext.core.Element}
19633      */
19634
19635     /**
19636      * Iterates each `element` in this `composite` calling the supplied function using {@link Ext#each Ext.each}.
19637      * @param {Function} fn 
19638
19639 The function to be called with each
19640 `element`. If the supplied function returns <tt>false</tt>,
19641 iteration stops. This function is called with the following arguments:
19642
19643 - `element` : __Ext.core.Element++
19644     The element at the current `index` in the `composite`
19645     
19646 - `composite` : __Object__ 
19647     This composite.
19648
19649 - `index` : __Number__ 
19650     The current index within the `composite`
19651
19652      * @param {Object} scope (optional) The scope (<code>this</code> reference) in which the specified function is executed.
19653      * Defaults to the <code>element</code> at the current <code>index</code>
19654      * within the composite.
19655      * @return {CompositeElement} this
19656      * @markdown
19657      */
19658 });
19659
19660 /**
19661  * Selects elements based on the passed CSS selector to enable {@link Ext.core.Element Element} methods
19662  * to be applied to many related elements in one statement through the returned {@link Ext.CompositeElement CompositeElement} or
19663  * {@link Ext.CompositeElementLite CompositeElementLite} object.
19664  * @param {String/Array} selector The CSS selector or an array of elements
19665  * @param {Boolean} unique (optional) true to create a unique Ext.core.Element for each element (defaults to a shared flyweight object)
19666  * @param {HTMLElement/String} root (optional) The root element of the query or id of the root
19667  * @return {CompositeElementLite/CompositeElement}
19668  * @member Ext.core.Element
19669  * @method select
19670  */
19671 Ext.core.Element.select = function(selector, unique, root){
19672     var els;
19673     if(typeof selector == "string"){
19674         els = Ext.core.Element.selectorFunction(selector, root);
19675     }else if(selector.length !== undefined){
19676         els = selector;
19677     }else{
19678         Ext.Error.raise({
19679             sourceClass: "Ext.core.Element",
19680             sourceMethod: "select",
19681             selector: selector,
19682             unique: unique,
19683             root: root,
19684             msg: "Invalid selector specified: " + selector
19685         });
19686     }
19687     return (unique === true) ? new Ext.CompositeElement(els) : new Ext.CompositeElementLite(els);
19688 };
19689
19690 /**
19691  * Selects elements based on the passed CSS selector to enable {@link Ext.core.Element Element} methods
19692  * to be applied to many related elements in one statement through the returned {@link Ext.CompositeElement CompositeElement} or
19693  * {@link Ext.CompositeElementLite CompositeElementLite} object.
19694  * @param {String/Array} selector The CSS selector or an array of elements
19695  * @param {Boolean} unique (optional) true to create a unique Ext.core.Element for each element (defaults to a shared flyweight object)
19696  * @param {HTMLElement/String} root (optional) The root element of the query or id of the root
19697  * @return {CompositeElementLite/CompositeElement}
19698  * @member Ext
19699  * @method select
19700  */
19701 Ext.select = Ext.core.Element.select;
19702
19703
19704 /*
19705 Ext JS - JavaScript Library
19706 Copyright (c) 2006-2011, Sencha Inc.
19707 All rights reserved.
19708 licensing@sencha.com
19709 */
19710 (function(){ var data = {
19711     "nameToAliasesMap":{
19712         "Ext.AbstractComponent":[""
19713         ],
19714         "Ext.AbstractManager":[""
19715         ],
19716         "Ext.AbstractPlugin":[""
19717         ],
19718         "Ext.Ajax":[""
19719         ],
19720         "Ext.ComponentLoader":[""
19721         ],
19722         "Ext.ComponentManager":[""
19723         ],
19724         "Ext.ComponentQuery":[""
19725         ],
19726         "Ext.ElementLoader":[""
19727         ],
19728         "Ext.LoadMask":[""
19729         ],
19730         "Ext.ModelManager":[""
19731         ],
19732         "Ext.PluginManager":[""
19733         ],
19734         "Ext.Template":[""
19735         ],
19736         "Ext.XTemplate":[""
19737         ],
19738         "Ext.app.Application":[""
19739         ],
19740         "Ext.app.Controller":[""
19741         ],
19742         "Ext.app.EventBus":[""
19743         ],
19744         "Ext.chart.Callout":[""
19745         ],
19746         "Ext.chart.Chart":["widget.chart"
19747         ],
19748         "Ext.chart.Highlight":[""
19749         ],
19750         "Ext.chart.Label":[""
19751         ],
19752         "Ext.chart.Legend":[""
19753         ],
19754         "Ext.chart.LegendItem":[""
19755         ],
19756         "Ext.chart.Mask":[""
19757         ],
19758         "Ext.chart.MaskLayer":[""
19759         ],
19760         "Ext.chart.Navigation":[""
19761         ],
19762         "Ext.chart.Shape":[""
19763         ],
19764         "Ext.chart.Tip":[""
19765         ],
19766         "Ext.chart.TipSurface":[""
19767         ],
19768         "Ext.chart.axis.Abstract":[""
19769         ],
19770         "Ext.chart.axis.Axis":[""
19771         ],
19772         "Ext.chart.axis.Category":["axis.category"
19773         ],
19774         "Ext.chart.axis.Gauge":["axis.gauge"
19775         ],
19776         "Ext.chart.axis.Numeric":["axis.numeric"
19777         ],
19778         "Ext.chart.axis.Radial":["axis.radial"
19779         ],
19780         "Ext.chart.axis.Time":["axis.time"
19781         ],
19782         "Ext.chart.series.Area":["series.area"
19783         ],
19784         "Ext.chart.series.Bar":["series.bar"
19785         ],
19786         "Ext.chart.series.Cartesian":[""
19787         ],
19788         "Ext.chart.series.Column":["series.column"
19789         ],
19790         "Ext.chart.series.Gauge":["series.gauge"
19791         ],
19792         "Ext.chart.series.Line":["series.line"
19793         ],
19794         "Ext.chart.series.Pie":["series.pie"
19795         ],
19796         "Ext.chart.series.Radar":["series.radar"
19797         ],
19798         "Ext.chart.series.Scatter":["series.scatter"
19799         ],
19800         "Ext.chart.series.Series":[""
19801         ],
19802         "Ext.chart.theme.Base":[""
19803         ],
19804         "Ext.chart.theme.Theme":[""
19805         ],
19806         "Ext.container.AbstractContainer":[""
19807         ],
19808         "Ext.data.AbstractStore":[""
19809         ],
19810         "Ext.data.ArrayStore":["store.array"
19811         ],
19812         "Ext.data.Association":[""
19813         ],
19814         "Ext.data.Batch":[""
19815         ],
19816         "Ext.data.BelongsToAssociation":["association.belongsto"
19817         ],
19818         "Ext.data.BufferStore":["store.buffer"
19819         ],
19820         "Ext.data.Connection":[""
19821         ],
19822         "Ext.data.DirectStore":["store.direct"
19823         ],
19824         "Ext.data.Errors":[""
19825         ],
19826         "Ext.data.Field":["data.field"
19827         ],
19828         "Ext.data.HasManyAssociation":["association.hasmany"
19829         ],
19830         "Ext.data.JsonP":[""
19831         ],
19832         "Ext.data.JsonPStore":["store.jsonp"
19833         ],
19834         "Ext.data.JsonStore":["store.json"
19835         ],
19836         "Ext.data.Model":[""
19837         ],
19838         "Ext.data.NodeInterface":[""
19839         ],
19840         "Ext.data.NodeStore":["store.node"
19841         ],
19842         "Ext.data.Operation":[""
19843         ],
19844         "Ext.data.Request":[""
19845         ],
19846         "Ext.data.ResultSet":[""
19847         ],
19848         "Ext.data.SortTypes":[""
19849         ],
19850         "Ext.data.Store":["store.store"
19851         ],
19852         "Ext.data.StoreManager":[""
19853         ],
19854         "Ext.data.Tree":["data.tree"
19855         ],
19856         "Ext.data.TreeStore":["store.tree"
19857         ],
19858         "Ext.data.Types":[""
19859         ],
19860         "Ext.data.validations":[""
19861         ],
19862         "Ext.data.XmlStore":["store.xml"
19863         ],
19864         "Ext.data.proxy.Ajax":["proxy.ajax"
19865         ],
19866         "Ext.data.proxy.Client":[""
19867         ],
19868         "Ext.data.proxy.Direct":["proxy.direct"
19869         ],
19870         "Ext.data.proxy.JsonP":["proxy.jsonp",
19871             "proxy.scripttag"
19872         ],
19873         "Ext.data.proxy.LocalStorage":["proxy.localstorage"
19874         ],
19875         "Ext.data.proxy.Memory":["proxy.memory"
19876         ],
19877         "Ext.data.proxy.Proxy":["proxy.proxy"
19878         ],
19879         "Ext.data.proxy.Rest":["proxy.rest"
19880         ],
19881         "Ext.data.proxy.Server":["proxy.server"
19882         ],
19883         "Ext.data.proxy.SessionStorage":["proxy.sessionstorage"
19884         ],
19885         "Ext.data.proxy.WebStorage":[""
19886         ],
19887         "Ext.data.reader.Array":["reader.array"
19888         ],
19889         "Ext.data.reader.Json":["reader.json"
19890         ],
19891         "Ext.data.reader.Reader":[""
19892         ],
19893         "Ext.data.reader.Xml":["reader.xml"
19894         ],
19895         "Ext.data.writer.Json":["writer.json"
19896         ],
19897         "Ext.data.writer.Writer":["writer.base"
19898         ],
19899         "Ext.data.writer.Xml":["writer.xml"
19900         ],
19901         "Ext.direct.Event":["direct.event"
19902         ],
19903         "Ext.direct.ExceptionEvent":["direct.exception"
19904         ],
19905         "Ext.direct.JsonProvider":["direct.jsonprovider"
19906         ],
19907         "Ext.direct.Manager":[""
19908         ],
19909         "Ext.direct.PollingProvider":["direct.pollingprovider"
19910         ],
19911         "Ext.direct.Provider":["direct.provider"
19912         ],
19913         "Ext.direct.RemotingEvent":["direct.rpc"
19914         ],
19915         "Ext.direct.RemotingMethod":[""
19916         ],
19917         "Ext.direct.RemotingProvider":["direct.remotingprovider"
19918         ],
19919         "Ext.direct.Transaction":["direct.transaction"
19920         ],
19921         "Ext.draw.Color":[""
19922         ],
19923         "Ext.draw.Component":["widget.draw"
19924         ],
19925         "Ext.draw.CompositeSprite":[""
19926         ],
19927         "Ext.draw.Draw":[""
19928         ],
19929         "Ext.draw.Matrix":[""
19930         ],
19931         "Ext.draw.Sprite":[""
19932         ],
19933         "Ext.draw.SpriteDD":[""
19934         ],
19935         "Ext.draw.Surface":[""
19936         ],
19937         "Ext.draw.engine.Svg":[""
19938         ],
19939         "Ext.draw.engine.Vml":[""
19940         ],
19941         "Ext.fx.Anim":[""
19942         ],
19943         "Ext.fx.Animator":[""
19944         ],
19945         "Ext.fx.CubicBezier":[""
19946         ],
19947         "Ext.fx.Easing":[],
19948         "Ext.fx.Manager":[""
19949         ],
19950         "Ext.fx.PropertyHandler":[""
19951         ],
19952         "Ext.fx.Queue":[""
19953         ],
19954         "Ext.fx.target.Component":[""
19955         ],
19956         "Ext.fx.target.CompositeElement":[""
19957         ],
19958         "Ext.fx.target.CompositeElementCSS":[""
19959         ],
19960         "Ext.fx.target.CompositeSprite":[""
19961         ],
19962         "Ext.fx.target.Element":[""
19963         ],
19964         "Ext.fx.target.ElementCSS":[""
19965         ],
19966         "Ext.fx.target.Sprite":[""
19967         ],
19968         "Ext.fx.target.Target":[""
19969         ],
19970         "Ext.layout.Layout":[""
19971         ],
19972         "Ext.layout.component.AbstractDock":[""
19973         ],
19974         "Ext.layout.component.Auto":["layout.autocomponent"
19975         ],
19976         "Ext.layout.component.Component":[""
19977         ],
19978         "Ext.layout.component.Draw":["layout.draw"
19979         ],
19980         "Ext.layout.container.AbstractCard":[""
19981         ],
19982         "Ext.layout.container.AbstractContainer":[""
19983         ],
19984         "Ext.layout.container.AbstractFit":[""
19985         ],
19986         "Ext.layout.container.Auto":["layout.auto",
19987             "layout.autocontainer"
19988         ],
19989         "Ext.panel.AbstractPanel":[""
19990         ],
19991         "Ext.selection.DataViewModel":[""
19992         ],
19993         "Ext.selection.Model":[""
19994         ],
19995         "Ext.state.CookieProvider":[""
19996         ],
19997         "Ext.state.LocalStorageProvider":["state.localstorage"
19998         ],
19999         "Ext.state.Manager":[""
20000         ],
20001         "Ext.state.Provider":[""
20002         ],
20003         "Ext.state.Stateful":[""
20004         ],
20005         "Ext.util.AbstractMixedCollection":[""
20006         ],
20007         "Ext.util.Filter":[""
20008         ],
20009         "Ext.util.Grouper":[""
20010         ],
20011         "Ext.util.HashMap":[""
20012         ],
20013         "Ext.util.Inflector":[""
20014         ],
20015         "Ext.util.MixedCollection":[""
20016         ],
20017         "Ext.util.Observable":[""
20018         ],
20019         "Ext.util.Offset":[""
20020         ],
20021         "Ext.util.Point":[""
20022         ],
20023         "Ext.util.Region":[""
20024         ],
20025         "Ext.util.Sortable":[""
20026         ],
20027         "Ext.util.Sorter":[""
20028         ],
20029         "Ext.view.AbstractView":[""
20030         ],
20031         "Ext.Action":[""
20032         ],
20033         "Ext.Component":["widget.component",
20034             "widget.box"
20035         ],
20036         "Ext.Editor":["widget.editor"
20037         ],
20038         "Ext.FocusManager":[""
20039         ],
20040         "Ext.Img":["widget.image",
20041             "widget.imagecomponent"
20042         ],
20043         "Ext.Layer":[""
20044         ],
20045         "Ext.ProgressBar":["widget.progressbar"
20046         ],
20047         "Ext.Shadow":[""
20048         ],
20049         "Ext.ShadowPool":[""
20050         ],
20051         "Ext.ZIndexManager":[""
20052         ],
20053         "Ext.button.Button":["widget.button"
20054         ],
20055         "Ext.button.Cycle":["widget.cycle"
20056         ],
20057         "Ext.button.Split":["widget.splitbutton"
20058         ],
20059         "Ext.container.ButtonGroup":["widget.buttongroup"
20060         ],
20061         "Ext.container.Container":["widget.container"
20062         ],
20063         "Ext.container.Viewport":["widget.viewport"
20064         ],
20065         "Ext.dd.DD":[""
20066         ],
20067         "Ext.dd.DDProxy":[""
20068         ],
20069         "Ext.dd.DDTarget":[""
20070         ],
20071         "Ext.dd.DragDrop":[""
20072         ],
20073         "Ext.dd.DragDropManager":[""
20074         ],
20075         "Ext.dd.DragSource":[""
20076         ],
20077         "Ext.dd.DragTracker":[""
20078         ],
20079         "Ext.dd.DragZone":[""
20080         ],
20081         "Ext.dd.DropTarget":[""
20082         ],
20083         "Ext.dd.DropZone":[""
20084         ],
20085         "Ext.dd.Registry":[""
20086         ],
20087         "Ext.dd.ScrollManager":[""
20088         ],
20089         "Ext.dd.StatusProxy":[""
20090         ],
20091         "Ext.flash.Component":["widget.flash"
20092         ],
20093         "Ext.form.Basic":[""
20094         ],
20095         "Ext.form.CheckboxGroup":["widget.checkboxgroup"
20096         ],
20097         "Ext.form.CheckboxManager":[""
20098         ],
20099         "Ext.form.FieldAncestor":[""
20100         ],
20101         "Ext.form.FieldContainer":["widget.fieldcontainer"
20102         ],
20103         "Ext.form.FieldSet":["widget.fieldset"
20104         ],
20105         "Ext.form.Label":["widget.label"
20106         ],
20107         "Ext.form.Labelable":[""
20108         ],
20109         "Ext.form.Panel":["widget.form"
20110         ],
20111         "Ext.form.RadioGroup":["widget.radiogroup"
20112         ],
20113         "Ext.form.RadioManager":[""
20114         ],
20115         "Ext.form.action.Action":[""
20116         ],
20117         "Ext.form.action.DirectLoad":["formaction.directload"
20118         ],
20119         "Ext.form.action.DirectSubmit":["formaction.directsubmit"
20120         ],
20121         "Ext.form.action.Load":["formaction.load"
20122         ],
20123         "Ext.form.action.StandardSubmit":["formaction.standardsubmit"
20124         ],
20125         "Ext.form.action.Submit":["formaction.submit"
20126         ],
20127         "Ext.form.field.Base":["widget.field"
20128         ],
20129         "Ext.form.field.Checkbox":["widget.checkboxfield",
20130             "widget.checkbox"
20131         ],
20132         "Ext.form.field.ComboBox":["widget.combobox",
20133             "widget.combo"
20134         ],
20135         "Ext.form.field.Date":["widget.datefield"
20136         ],
20137         "Ext.form.field.Display":["widget.displayfield"
20138         ],
20139         "Ext.form.field.Field":[""
20140         ],
20141         "Ext.form.field.File":["widget.filefield",
20142             "widget.fileuploadfield"
20143         ],
20144         "Ext.form.field.Hidden":["widget.hiddenfield",
20145             "widget.hidden"
20146         ],
20147         "Ext.form.field.HtmlEditor":["widget.htmleditor"
20148         ],
20149         "Ext.form.field.Number":["widget.numberfield"
20150         ],
20151         "Ext.form.field.Picker":["widget.pickerfield"
20152         ],
20153         "Ext.form.field.Radio":["widget.radiofield",
20154             "widget.radio"
20155         ],
20156         "Ext.form.field.Spinner":["widget.spinnerfield"
20157         ],
20158         "Ext.form.field.Text":["widget.textfield"
20159         ],
20160         "Ext.form.field.TextArea":["widget.textareafield",
20161             "widget.textarea"
20162         ],
20163         "Ext.form.field.Time":["widget.timefield"
20164         ],
20165         "Ext.form.field.Trigger":["widget.triggerfield",
20166             "widget.trigger"
20167         ],
20168         "Ext.form.field.VTypes":[""
20169         ],
20170         "Ext.grid.CellEditor":[""
20171         ],
20172         "Ext.grid.ColumnLayout":["layout.gridcolumn"
20173         ],
20174         "Ext.grid.Lockable":[""
20175         ],
20176         "Ext.grid.LockingView":[""
20177         ],
20178         "Ext.grid.PagingScroller":["widget.paginggridscroller"
20179         ],
20180         "Ext.grid.Panel":["widget.gridpanel",
20181             "widget.grid"
20182         ],
20183         "Ext.grid.RowEditor":[""
20184         ],
20185         "Ext.grid.RowNumberer":["widget.rownumberer"
20186         ],
20187         "Ext.grid.Scroller":["widget.gridscroller"
20188         ],
20189         "Ext.grid.View":["widget.gridview"
20190         ],
20191         "Ext.grid.ViewDropZone":[""
20192         ],
20193         "Ext.grid.column.Action":["widget.actioncolumn"
20194         ],
20195         "Ext.grid.column.Boolean":["widget.booleancolumn"
20196         ],
20197         "Ext.grid.column.Column":["widget.gridcolumn"
20198         ],
20199         "Ext.grid.column.Date":["widget.datecolumn"
20200         ],
20201         "Ext.grid.column.Number":["widget.numbercolumn"
20202         ],
20203         "Ext.grid.column.Template":["widget.templatecolumn"
20204         ],
20205         "Ext.grid.feature.AbstractSummary":["feature.abstractsummary"
20206         ],
20207         "Ext.grid.feature.Chunking":["feature.chunking"
20208         ],
20209         "Ext.grid.feature.Feature":["feature.feature"
20210         ],
20211         "Ext.grid.feature.Grouping":["feature.grouping"
20212         ],
20213         "Ext.grid.feature.GroupingSummary":["feature.groupingsummary"
20214         ],
20215         "Ext.grid.feature.RowBody":["feature.rowbody"
20216         ],
20217         "Ext.grid.feature.RowWrap":["feature.rowwrap"
20218         ],
20219         "Ext.grid.feature.Summary":["feature.summary"
20220         ],
20221         "Ext.grid.header.Container":["widget.headercontainer"
20222         ],
20223         "Ext.grid.header.DragZone":[""
20224         ],
20225         "Ext.grid.header.DropZone":[""
20226         ],
20227         "Ext.grid.plugin.CellEditing":["plugin.cellediting"
20228         ],
20229         "Ext.grid.plugin.DragDrop":["plugin.gridviewdragdrop"
20230         ],
20231         "Ext.grid.plugin.Editing":["editing.editing"
20232         ],
20233         "Ext.grid.plugin.HeaderReorderer":["plugin.gridheaderreorderer"
20234         ],
20235         "Ext.grid.plugin.HeaderResizer":["plugin.gridheaderresizer"
20236         ],
20237         "Ext.grid.plugin.RowEditing":["plugin.rowediting"
20238         ],
20239         "Ext.grid.property.Grid":[""
20240         ],
20241         "Ext.grid.property.HeaderContainer":[""
20242         ],
20243         "Ext.grid.property.Property":[""
20244         ],
20245         "Ext.grid.property.Store":[""
20246         ],
20247         "Ext.layout.component.Body":["layout.body"
20248         ],
20249         "Ext.layout.component.BoundList":["layout.boundlist"
20250         ],
20251         "Ext.layout.component.Button":["layout.button"
20252         ],
20253         "Ext.layout.component.Dock":["layout.dock"
20254         ],
20255         "Ext.layout.component.Editor":["layout.editor"
20256         ],
20257         "Ext.layout.component.FieldSet":["layout.fieldset"
20258         ],
20259         "Ext.layout.component.ProgressBar":["layout.progressbar"
20260         ],
20261         "Ext.layout.component.Tab":["layout.tab"
20262         ],
20263         "Ext.layout.component.Tip":["layout.tip"
20264         ],
20265         "Ext.layout.component.field.Field":["layout.field"
20266         ],
20267         "Ext.layout.component.field.File":["layout.filefield"
20268         ],
20269         "Ext.layout.component.field.HtmlEditor":["layout.htmleditor"
20270         ],
20271         "Ext.layout.component.field.Slider":["layout.sliderfield"
20272         ],
20273         "Ext.layout.component.field.Text":["layout.textfield"
20274         ],
20275         "Ext.layout.component.field.TextArea":["layout.textareafield"
20276         ],
20277         "Ext.layout.component.field.Trigger":["layout.triggerfield"
20278         ],
20279         "Ext.layout.container.Absolute":["layout.absolute"
20280         ],
20281         "Ext.layout.container.Accordion":["layout.accordion"
20282         ],
20283         "Ext.layout.container.Anchor":["layout.anchor"
20284         ],
20285         "Ext.layout.container.Border":["layout.border"
20286         ],
20287         "Ext.layout.container.Box":["layout.box"
20288         ],
20289         "Ext.layout.container.Card":["layout.card"
20290         ],
20291         "Ext.layout.container.CheckboxGroup":["layout.checkboxgroup"
20292         ],
20293         "Ext.layout.container.Column":["layout.column"
20294         ],
20295         "Ext.layout.container.Container":[""
20296         ],
20297         "Ext.layout.container.Fit":["layout.fit"
20298         ],
20299         "Ext.layout.container.HBox":["layout.hbox"
20300         ],
20301         "Ext.layout.container.Table":["layout.table"
20302         ],
20303         "Ext.layout.container.VBox":["layout.vbox"
20304         ],
20305         "Ext.layout.container.boxOverflow.Menu":[""
20306         ],
20307         "Ext.layout.container.boxOverflow.None":[""
20308         ],
20309         "Ext.layout.container.boxOverflow.Scroller":[""
20310         ],
20311         "Ext.menu.CheckItem":["widget.menucheckitem"
20312         ],
20313         "Ext.menu.ColorPicker":["widget.colormenu"
20314         ],
20315         "Ext.menu.DatePicker":["widget.datemenu"
20316         ],
20317         "Ext.menu.Item":["widget.menuitem"
20318         ],
20319         "Ext.menu.KeyNav":[""
20320         ],
20321         "Ext.menu.Manager":[""
20322         ],
20323         "Ext.menu.Menu":["widget.menu"
20324         ],
20325         "Ext.menu.Separator":["widget.menuseparator"
20326         ],
20327         "Ext.panel.DD":[""
20328         ],
20329         "Ext.panel.Header":["widget.header"
20330         ],
20331         "Ext.panel.Panel":["widget.panel"
20332         ],
20333         "Ext.panel.Proxy":[""
20334         ],
20335         "Ext.panel.Table":["widget.tablepanel"
20336         ],
20337         "Ext.panel.Tool":["widget.tool"
20338         ],
20339         "Ext.picker.Color":["widget.colorpicker"
20340         ],
20341         "Ext.picker.Date":["widget.datepicker"
20342         ],
20343         "Ext.picker.Month":["widget.monthpicker"
20344         ],
20345         "Ext.picker.Time":["widget.timepicker"
20346         ],
20347         "Ext.resizer.Handle":[""
20348         ],
20349         "Ext.resizer.Resizer":[""
20350         ],
20351         "Ext.resizer.ResizeTracker":[""
20352         ],
20353         "Ext.resizer.Splitter":["widget.splitter"
20354         ],
20355         "Ext.resizer.SplitterTracker":[""
20356         ],
20357         "Ext.selection.CellModel":["selection.cellmodel"
20358         ],
20359         "Ext.selection.CheckboxModel":[""
20360         ],
20361         "Ext.selection.RowModel":["selection.rowmodel"
20362         ],
20363         "Ext.selection.TreeModel":["selection.treemodel"
20364         ],
20365         "Ext.slider.Multi":["widget.multislider"
20366         ],
20367         "Ext.slider.Single":["widget.slider",
20368             "widget.sliderfield"
20369         ],
20370         "Ext.slider.Thumb":[""
20371         ],
20372         "Ext.slider.Tip":["widget.slidertip"
20373         ],
20374         "Ext.tab.Bar":["widget.tabbar"
20375         ],
20376         "Ext.tab.Panel":["widget.tabpanel"
20377         ],
20378         "Ext.tab.Tab":["widget.tab"
20379         ],
20380         "Ext.tip.QuickTip":[""
20381         ],
20382         "Ext.tip.QuickTipManager":[""
20383         ],
20384         "Ext.tip.Tip":[""
20385         ],
20386         "Ext.tip.ToolTip":["widget.tooltip"
20387         ],
20388         "Ext.toolbar.Fill":["widget.tbfill"
20389         ],
20390         "Ext.toolbar.Item":["widget.tbitem"
20391         ],
20392         "Ext.toolbar.Paging":["widget.pagingtoolbar"
20393         ],
20394         "Ext.toolbar.Separator":["widget.tbseparator"
20395         ],
20396         "Ext.toolbar.Spacer":["widget.tbspacer"
20397         ],
20398         "Ext.toolbar.TextItem":["widget.tbtext"
20399         ],
20400         "Ext.toolbar.Toolbar":["widget.toolbar"
20401         ],
20402         "Ext.tree.Column":["widget.treecolumn"
20403         ],
20404         "Ext.tree.Panel":["widget.treepanel"
20405         ],
20406         "Ext.tree.View":["widget.treeview"
20407         ],
20408         "Ext.tree.ViewDragZone":[""
20409         ],
20410         "Ext.tree.ViewDropZone":[""
20411         ],
20412         "Ext.tree.plugin.TreeViewDragDrop":["plugin.treeviewdragdrop"
20413         ],
20414         "Ext.util.Animate":[""
20415         ],
20416         "Ext.util.ClickRepeater":[""
20417         ],
20418         "Ext.util.ComponentDragger":[""
20419         ],
20420         "Ext.util.Cookies":[""
20421         ],
20422         "Ext.util.CSS":[""
20423         ],
20424         "Ext.util.Floating":[""
20425         ],
20426         "Ext.util.History":[""
20427         ],
20428         "Ext.util.KeyMap":[""
20429         ],
20430         "Ext.util.KeyNav":[""
20431         ],
20432         "Ext.util.TextMetrics":[""
20433         ],
20434         "Ext.view.BoundList":["widget.boundlist"
20435         ],
20436         "Ext.view.BoundListKeyNav":[""
20437         ],
20438         "Ext.view.DragZone":[""
20439         ],
20440         "Ext.view.DropZone":[""
20441         ],
20442         "Ext.view.Table":["widget.tableview"
20443         ],
20444         "Ext.view.TableChunker":[""
20445         ],
20446         "Ext.view.View":["widget.dataview"
20447         ],
20448         "Ext.window.MessageBox":["widget.messagebox"
20449         ],
20450         "Ext.window.Window":["widget.window"
20451         ]
20452     },
20453     "alternateToNameMap":{
20454         "Ext.ComponentMgr":"Ext.ComponentManager",
20455         "Ext.ModelMgr":"Ext.ModelManager",
20456         "Ext.PluginMgr":"Ext.PluginManager",
20457         "Ext.chart.Axis":"Ext.chart.axis.Axis",
20458         "Ext.chart.CategoryAxis":"Ext.chart.axis.Category",
20459         "Ext.chart.NumericAxis":"Ext.chart.axis.Numeric",
20460         "Ext.chart.TimeAxis":"Ext.chart.axis.Time",
20461         "Ext.data.Record":"Ext.data.Model",
20462         "Ext.data.XmlStore":"Ext.data.XmlStore",
20463         "Ext.data.ClientProxy":"Ext.data.proxy.Client",
20464         "Ext.data.DirectProxy":"Ext.data.proxy.Direct",
20465         "Ext.data.ScriptTagProxy":"Ext.data.proxy.JsonP",
20466         "Ext.data.LocalStorageProxy":"Ext.data.proxy.LocalStorage",
20467         "Ext.data.MemoryProxy":"Ext.data.proxy.Memory",
20468         "Ext.data.RestProxy":"Ext.data.proxy.Rest",
20469         "Ext.data.ServerProxy":"Ext.data.proxy.Server",
20470         "Ext.data.SessionStorageProxy":"Ext.data.proxy.SessionStorage",
20471         "Ext.data.WebStorageProxy":"Ext.data.proxy.WebStorage",
20472         "Ext.data.ArrayReader":"Ext.data.reader.Array",
20473         "Ext.data.JsonReader":"Ext.data.reader.Json",
20474         "Ext.data.XmlReader":"Ext.data.reader.Xml",
20475         "Ext.data.JsonWriter":"Ext.data.writer.Json",
20476         "Ext.data.XmlWriter":"Ext.data.writer.Xml",
20477         "Ext.Direct.Transaction":"Ext.direct.Transaction",
20478         "Ext.AbstractStoreSelectionModel":"Ext.selection.Model",
20479         "Ext.view.AbstractView":"Ext.view.AbstractView",
20480         "Ext.FocusMgr":"Ext.FocusManager",
20481         "Ext.WindowGroup":"Ext.ZIndexManager",
20482         "Ext.Button":"Ext.button.Button",
20483         "Ext.CycleButton":"Ext.button.Cycle",
20484         "Ext.SplitButton":"Ext.button.Split",
20485         "Ext.ButtonGroup":"Ext.container.ButtonGroup",
20486         "Ext.Container":"Ext.container.Container",
20487         "Ext.Viewport":"Ext.container.Viewport",
20488         "Ext.FlashComponent":"Ext.flash.Component",
20489         "Ext.form.BasicForm":"Ext.form.Basic",
20490         "Ext.form.Action":"Ext.form.action.Action",
20491         "Ext.form.Action.DirectLoad":"Ext.form.action.DirectLoad",
20492         "Ext.form.Action.DirectSubmit":"Ext.form.action.DirectSubmit",
20493         "Ext.form.Action.Load":"Ext.form.action.Load",
20494         "Ext.form.Action.Submit":"Ext.form.action.Submit",
20495         "Ext.form.Checkbox":"Ext.form.field.Checkbox",
20496         "Ext.form.ComboBox":"Ext.form.field.ComboBox",
20497         "Ext.form.Hidden":"Ext.form.field.Hidden",
20498         "Ext.form.HtmlEditor":"Ext.form.field.HtmlEditor",
20499         "Ext.form.Picker":"Ext.form.field.Picker",
20500         "Ext.form.Radio":"Ext.form.field.Radio",
20501         "Ext.form.Spinner":"Ext.form.field.Spinner",
20502         "Ext.form.TextArea":"Ext.form.field.TextArea",
20503         "Ext.grid.ActionColumn":"Ext.grid.column.Action",
20504         "Ext.grid.BooleanColumn":"Ext.grid.column.Boolean",
20505         "Ext.grid.Column":"Ext.grid.column.Column",
20506         "Ext.grid.DateColumn":"Ext.grid.column.Date",
20507         "Ext.grid.NumberColumn":"Ext.grid.column.Number",
20508         "Ext.grid.TemplateColumn":"Ext.grid.column.Template",
20509         "Ext.grid.PropertyGrid":"Ext.grid.property.Grid",
20510         "Ext.grid.PropertyColumnModel":"Ext.grid.property.HeaderContainer",
20511         "Ext.PropGridProperty":"Ext.grid.property.Property",
20512         "Ext.grid.PropertyStore":"Ext.grid.property.Store",
20513         "Ext.layout.AbsoluteLayout":"Ext.layout.container.Absolute",
20514         "Ext.layout.AccordionLayout":"Ext.layout.container.Accordion",
20515         "Ext.layout.AnchorLayout":"Ext.layout.container.Anchor",
20516         "Ext.layout.BorderLayout":"Ext.layout.container.Border",
20517         "Ext.layout.BoxLayout":"Ext.layout.container.Box",
20518         "Ext.layout.CardLayout":"Ext.layout.container.Card",
20519         "Ext.layout.ColumnLayout":"Ext.layout.container.Column",
20520         "Ext.layout.ContainerLayout":"Ext.layout.container.Container",
20521         "Ext.layout.FitLayout":"Ext.layout.container.Fit",
20522         "Ext.layout.HBoxLayout":"Ext.layout.container.HBox",
20523         "Ext.layout.TableLayout":"Ext.layout.container.Table",
20524         "Ext.layout.VBoxLayout":"Ext.layout.container.VBox",
20525         "Ext.layout.boxOverflow.Menu":"Ext.layout.container.boxOverflow.Menu",
20526         "Ext.layout.boxOverflow.None":"Ext.layout.container.boxOverflow.None",
20527         "Ext.layout.boxOverflow.Scroller":"Ext.layout.container.boxOverflow.Scroller",
20528         "Ext.menu.TextItem":"Ext.menu.Item",
20529         "Ext.menu.MenuMgr":"Ext.menu.Manager",
20530         "Ext.Panel":"Ext.panel.Panel",
20531         "Ext.dd.PanelProxy":"Ext.panel.Proxy",
20532         "Ext.ColorPalette":"Ext.picker.Color",
20533         "Ext.DatePicker":"Ext.picker.Date",
20534         "Ext.MonthPicker":"Ext.picker.Month",
20535         "Ext.Resizable":"Ext.resizer.Resizer",
20536         "Ext.slider.MultiSlider":"Ext.slider.Multi",
20537         "Ext.QuickTip":"Ext.tip.QuickTip",
20538         "Ext.Tip":"Ext.tip.Tip",
20539         "Ext.ToolTip":"Ext.tip.ToolTip",
20540         "Ext.Toolbar.Fill":"Ext.toolbar.Fill",
20541         "Ext.Toolbar.Item":"Ext.toolbar.Item",
20542         "Ext.PagingToolbar":"Ext.toolbar.Paging",
20543         "Ext.Toolbar.Separator":"Ext.toolbar.Separator",
20544         "Ext.Toolbar.Spacer":"Ext.toolbar.Spacer",
20545         "Ext.Toolbar.TextItem":"Ext.toolbar.TextItem",
20546         "Ext.Toolbar":"Ext.toolbar.Toolbar",
20547         "Ext.History":"Ext.util.History",
20548         "Ext.KeyMap":"Ext.util.KeyMap",
20549         "Ext.KeyNav":"Ext.util.KeyNav",
20550         "Ext.BoundList":"Ext.view.BoundList",
20551         "Ext.view.View":"Ext.view.View",
20552         "Ext.MessageBox":"Ext.window.MessageBox",
20553         "Ext.Window":"Ext.window.Window"
20554     }
20555 };var scripts = document.getElementsByTagName('script'),
20556     path = '',
20557     i, ln, src, match;
20558
20559 for (i = 0, ln = scripts.length; i < ln; i++) {
20560     src = scripts[i].src;
20561
20562     match = src.match(/ext(-debug)?\.js$/);
20563
20564     if (match) {
20565         path = src.substring(0, src.length - match[0].length);
20566         break;
20567     }
20568 }
20569
20570 var nameToAliasesMap = data.nameToAliasesMap,
20571     alternateToNameMap = data.alternateToNameMap,
20572     classManager = Ext.ClassManager,
20573     name, aliases;
20574
20575 for (name in nameToAliasesMap) {
20576     if (nameToAliasesMap.hasOwnProperty(name)) {
20577         aliases = nameToAliasesMap[name];
20578
20579         if (aliases.length > 0) {
20580             for (i = 0, ln = aliases.length; i < ln; i++) {
20581                 classManager.setAlias(name, aliases[i]);
20582             }
20583         }
20584         else {
20585             classManager.setAlias(name, null);
20586         }
20587     }
20588 }
20589
20590 Ext.Object.merge(classManager.maps.alternateToName, alternateToNameMap);
20591
20592 Ext.Loader.setConfig({
20593     enabled: true,
20594     disableCaching: true,
20595     paths: {
20596         'Ext': path + 'src'
20597     }
20598 });
20599 })();
20600
20601
20602
20603