Upgrade to ExtJS 4.0.1 - Released 05/18/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          * @method
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          * @method
357          */
358         isArray: ('isArray' in Array) ? Array.isArray : function(value) {
359             return toString.call(value) === '[object Array]';
360         },
361
362         /**
363          * Returns true if the passed value is a JavaScript Date object, false otherwise.
364          * @param {Object} object The object to test
365          * @return {Boolean}
366          */
367         isDate: function(value) {
368             return toString.call(value) === '[object Date]';
369         },
370
371         /**
372          * Returns true if the passed value is a JavaScript Object, false otherwise.
373          * @param {Mixed} value The value to test
374          * @return {Boolean}
375          * @method
376          */
377         isObject: (toString.call(null) === '[object Object]') ?
378         function(value) {
379             return value !== null && value !== undefined && toString.call(value) === '[object Object]' && value.nodeType === undefined;
380         } :
381         function(value) {
382             return toString.call(value) === '[object Object]';
383         },
384
385         /**
386          * Returns true if the passed value is a JavaScript 'primitive', a string, number or boolean.
387          * @param {Mixed} value The value to test
388          * @return {Boolean}
389          */
390         isPrimitive: function(value) {
391             var type = typeof value;
392
393             return type === 'string' || type === 'number' || type === 'boolean';
394         },
395
396         /**
397          * Returns true if the passed value is a JavaScript Function, false otherwise.
398          * @param {Mixed} value The value to test
399          * @return {Boolean}
400          * @method
401          */
402         isFunction:
403         // Safari 3.x and 4.x returns 'function' for typeof <NodeList>, hence we need to fall back to using
404         // Object.prorotype.toString (slower)
405         (typeof document !== 'undefined' && typeof document.getElementsByTagName('body') === 'function') ? function(value) {
406             return toString.call(value) === '[object Function]';
407         } : function(value) {
408             return typeof value === 'function';
409         },
410
411         /**
412          * Returns true if the passed value is a number. Returns false for non-finite numbers.
413          * @param {Mixed} value The value to test
414          * @return {Boolean}
415          */
416         isNumber: function(value) {
417             return typeof value === 'number' && isFinite(value);
418         },
419
420         /**
421          * Validates that a value is numeric.
422          * @param {Mixed} value Examples: 1, '1', '2.34'
423          * @return {Boolean} True if numeric, false otherwise
424          */
425         isNumeric: function(value) {
426             return !isNaN(parseFloat(value)) && isFinite(value);
427         },
428
429         /**
430          * Returns true if the passed value is a string.
431          * @param {Mixed} value The value to test
432          * @return {Boolean}
433          */
434         isString: function(value) {
435             return typeof value === 'string';
436         },
437
438         /**
439          * Returns true if the passed value is a boolean.
440          *
441          * @param {Mixed} value The value to test
442          * @return {Boolean}
443          */
444         isBoolean: function(value) {
445             return typeof value === 'boolean';
446         },
447
448         /**
449          * Returns true if the passed value is an HTMLElement
450          * @param {Mixed} value The value to test
451          * @return {Boolean}
452          */
453         isElement: function(value) {
454             return value ? value.nodeType === 1 : false;
455         },
456
457         /**
458          * Returns true if the passed value is a TextNode
459          * @param {Mixed} value The value to test
460          * @return {Boolean}
461          */
462         isTextNode: function(value) {
463             return value ? value.nodeName === "#text" : false;
464         },
465
466         /**
467          * Returns true if the passed value is defined.
468          * @param {Mixed} value The value to test
469          * @return {Boolean}
470          */
471         isDefined: function(value) {
472             return typeof value !== 'undefined';
473         },
474
475         /**
476          * Returns true if the passed value is iterable, false otherwise
477          * @param {Mixed} value The value to test
478          * @return {Boolean}
479          */
480         isIterable: function(value) {
481             return (value && typeof value !== 'string') ? value.length !== undefined : false;
482         }
483     });
484
485     Ext.apply(Ext, {
486
487         /**
488          * Clone almost any type of variable including array, object, DOM nodes and Date without keeping the old reference
489          * @param {Mixed} item The variable to clone
490          * @return {Mixed} clone
491          */
492         clone: function(item) {
493             if (item === null || item === undefined) {
494                 return item;
495             }
496
497             // DOM nodes
498             // TODO proxy this to Ext.Element.clone to handle automatic id attribute changing
499             // recursively
500             if (item.nodeType && item.cloneNode) {
501                 return item.cloneNode(true);
502             }
503
504             var type = toString.call(item);
505
506             // Date
507             if (type === '[object Date]') {
508                 return new Date(item.getTime());
509             }
510
511             var i, j, k, clone, key;
512
513             // Array
514             if (type === '[object Array]') {
515                 i = item.length;
516
517                 clone = [];
518
519                 while (i--) {
520                     clone[i] = Ext.clone(item[i]);
521                 }
522             }
523             // Object
524             else if (type === '[object Object]' && item.constructor === Object) {
525                 clone = {};
526
527                 for (key in item) {
528                     clone[key] = Ext.clone(item[key]);
529                 }
530
531                 if (enumerables) {
532                     for (j = enumerables.length; j--;) {
533                         k = enumerables[j];
534                         clone[k] = item[k];
535                     }
536                 }
537             }
538
539             return clone || item;
540         },
541
542         /**
543          * @private
544          * Generate a unique reference of Ext in the global scope, useful for sandboxing
545          */
546         getUniqueGlobalNamespace: function() {
547             var uniqueGlobalNamespace = this.uniqueGlobalNamespace;
548
549             if (uniqueGlobalNamespace === undefined) {
550                 var i = 0;
551
552                 do {
553                     uniqueGlobalNamespace = 'ExtSandbox' + (++i);
554                 } while (Ext.global[uniqueGlobalNamespace] !== undefined);
555
556                 Ext.global[uniqueGlobalNamespace] = Ext;
557                 this.uniqueGlobalNamespace = uniqueGlobalNamespace;
558             }
559
560             return uniqueGlobalNamespace;
561         },
562
563         /**
564          * @private
565          */
566         functionFactory: function() {
567             var args = Array.prototype.slice.call(arguments);
568
569             if (args.length > 0) {
570                 args[args.length - 1] = 'var Ext=window.' + this.getUniqueGlobalNamespace() + ';' +
571                     args[args.length - 1];
572             }
573
574             return Function.prototype.constructor.apply(Function.prototype, args);
575         }
576     });
577
578     /**
579      * Old alias to {@link Ext#typeOf}
580      * @deprecated 4.0.0 Use {@link Ext#typeOf} instead
581      * @method
582      */
583     Ext.type = Ext.typeOf;
584
585 })();
586
587 /**
588  * @author Jacky Nguyen <jacky@sencha.com>
589  * @docauthor Jacky Nguyen <jacky@sencha.com>
590  * @class Ext.Version
591  *
592  * A utility class that wrap around a string version number and provide convenient
593  * method to perform comparison. See also: {@link Ext.Version#compare compare}. Example:
594
595     var version = new Ext.Version('1.0.2beta');
596     console.log("Version is " + version); // Version is 1.0.2beta
597
598     console.log(version.getMajor()); // 1
599     console.log(version.getMinor()); // 0
600     console.log(version.getPatch()); // 2
601     console.log(version.getBuild()); // 0
602     console.log(version.getRelease()); // beta
603
604     console.log(version.isGreaterThan('1.0.1')); // True
605     console.log(version.isGreaterThan('1.0.2alpha')); // True
606     console.log(version.isGreaterThan('1.0.2RC')); // False
607     console.log(version.isGreaterThan('1.0.2')); // False
608     console.log(version.isLessThan('1.0.2')); // True
609
610     console.log(version.match(1.0)); // True
611     console.log(version.match('1.0.2')); // True
612
613  * @markdown
614  */
615 (function() {
616
617 // Current core version
618 var version = '4.0.1', Version;
619     Ext.Version = Version = Ext.extend(Object, {
620
621         /**
622          * @constructor
623          * @param {String/Number} version The version number in the follow standard format: major[.minor[.patch[.build[release]]]]
624          * Examples: 1.0 or 1.2.3beta or 1.2.3.4RC
625          * @return {Ext.Version} this
626          * @param version
627          */
628         constructor: function(version) {
629             var parts, releaseStartIndex;
630
631             if (version instanceof Version) {
632                 return version;
633             }
634
635             this.version = this.shortVersion = String(version).toLowerCase().replace(/_/g, '.').replace(/[\-+]/g, '');
636
637             releaseStartIndex = this.version.search(/([^\d\.])/);
638
639             if (releaseStartIndex !== -1) {
640                 this.release = this.version.substr(releaseStartIndex, version.length);
641                 this.shortVersion = this.version.substr(0, releaseStartIndex);
642             }
643
644             this.shortVersion = this.shortVersion.replace(/[^\d]/g, '');
645
646             parts = this.version.split('.');
647
648             this.major = parseInt(parts.shift() || 0, 10);
649             this.minor = parseInt(parts.shift() || 0, 10);
650             this.patch = parseInt(parts.shift() || 0, 10);
651             this.build = parseInt(parts.shift() || 0, 10);
652
653             return this;
654         },
655
656         /**
657          * Override the native toString method
658          * @private
659          * @return {String} version
660          */
661         toString: function() {
662             return this.version;
663         },
664
665         /**
666          * Override the native valueOf method
667          * @private
668          * @return {String} version
669          */
670         valueOf: function() {
671             return this.version;
672         },
673
674         /**
675          * Returns the major component value
676          * @return {Number} major
677          */
678         getMajor: function() {
679             return this.major || 0;
680         },
681
682         /**
683          * Returns the minor component value
684          * @return {Number} minor
685          */
686         getMinor: function() {
687             return this.minor || 0;
688         },
689
690         /**
691          * Returns the patch component value
692          * @return {Number} patch
693          */
694         getPatch: function() {
695             return this.patch || 0;
696         },
697
698         /**
699          * Returns the build component value
700          * @return {Number} build
701          */
702         getBuild: function() {
703             return this.build || 0;
704         },
705
706         /**
707          * Returns the release component value
708          * @return {Number} release
709          */
710         getRelease: function() {
711             return this.release || '';
712         },
713
714         /**
715          * Returns whether this version if greater than the supplied argument
716          * @param {String/Number} target The version to compare with
717          * @return {Boolean} True if this version if greater than the target, false otherwise
718          */
719         isGreaterThan: function(target) {
720             return Version.compare(this.version, target) === 1;
721         },
722
723         /**
724          * Returns whether this version if smaller than the supplied argument
725          * @param {String/Number} target The version to compare with
726          * @return {Boolean} True if this version if smaller than the target, false otherwise
727          */
728         isLessThan: function(target) {
729             return Version.compare(this.version, target) === -1;
730         },
731
732         /**
733          * Returns whether this version equals to the supplied argument
734          * @param {String/Number} target The version to compare with
735          * @return {Boolean} True if this version equals to the target, false otherwise
736          */
737         equals: function(target) {
738             return Version.compare(this.version, target) === 0;
739         },
740
741         /**
742          * Returns whether this version matches the supplied argument. Example:
743          * <pre><code>
744          * var version = new Ext.Version('1.0.2beta');
745          * console.log(version.match(1)); // True
746          * console.log(version.match(1.0)); // True
747          * console.log(version.match('1.0.2')); // True
748          * console.log(version.match('1.0.2RC')); // False
749          * </code></pre>
750          * @param {String/Number} target The version to compare with
751          * @return {Boolean} True if this version matches the target, false otherwise
752          */
753         match: function(target) {
754             target = String(target);
755             return this.version.substr(0, target.length) === target;
756         },
757
758         /**
759          * Returns this format: [major, minor, patch, build, release]. Useful for comparison
760          * @return {Array}
761          */
762         toArray: function() {
763             return [this.getMajor(), this.getMinor(), this.getPatch(), this.getBuild(), this.getRelease()];
764         },
765
766         /**
767          * Returns shortVersion version without dots and release
768          * @return {String}
769          */
770         getShortVersion: function() {
771             return this.shortVersion;
772         }
773     });
774
775     Ext.apply(Version, {
776         // @private
777         releaseValueMap: {
778             'dev': -6,
779             'alpha': -5,
780             'a': -5,
781             'beta': -4,
782             'b': -4,
783             'rc': -3,
784             '#': -2,
785             'p': -1,
786             'pl': -1
787         },
788
789         /**
790          * Converts a version component to a comparable value
791          *
792          * @static
793          * @param {Mixed} value The value to convert
794          * @return {Mixed}
795          */
796         getComponentValue: function(value) {
797             return !value ? 0 : (isNaN(value) ? this.releaseValueMap[value] || value : parseInt(value, 10));
798         },
799
800         /**
801          * Compare 2 specified versions, starting from left to right. If a part contains special version strings,
802          * they are handled in the following order:
803          * 'dev' < 'alpha' = 'a' < 'beta' = 'b' < 'RC' = 'rc' < '#' < 'pl' = 'p' < 'anything else'
804          *
805          * @static
806          * @param {String} current The current version to compare to
807          * @param {String} target The target version to compare to
808          * @return {Number} Returns -1 if the current version is smaller than the target version, 1 if greater, and 0 if they're equivalent
809          */
810         compare: function(current, target) {
811             var currentValue, targetValue, i;
812
813             current = new Version(current).toArray();
814             target = new Version(target).toArray();
815
816             for (i = 0; i < Math.max(current.length, target.length); i++) {
817                 currentValue = this.getComponentValue(current[i]);
818                 targetValue = this.getComponentValue(target[i]);
819
820                 if (currentValue < targetValue) {
821                     return -1;
822                 } else if (currentValue > targetValue) {
823                     return 1;
824                 }
825             }
826
827             return 0;
828         }
829     });
830
831     Ext.apply(Ext, {
832         /**
833          * @private
834          */
835         versions: {},
836
837         /**
838          * @private
839          */
840         lastRegisteredVersion: null,
841
842         /**
843          * Set version number for the given package name.
844          *
845          * @param {String} packageName The package name, for example: 'core', 'touch', 'extjs'
846          * @param {String/Ext.Version} version The version, for example: '1.2.3alpha', '2.4.0-dev'
847          * @return {Ext}
848          */
849         setVersion: function(packageName, version) {
850             Ext.versions[packageName] = new Version(version);
851             Ext.lastRegisteredVersion = Ext.versions[packageName];
852
853             return this;
854         },
855
856         /**
857          * Get the version number of the supplied package name; will return the last registered version
858          * (last Ext.setVersion call) if there's no package name given.
859          *
860          * @param {String} packageName (Optional) The package name, for example: 'core', 'touch', 'extjs'
861          * @return {Ext.Version} The version
862          */
863         getVersion: function(packageName) {
864             if (packageName === undefined) {
865                 return Ext.lastRegisteredVersion;
866             }
867
868             return Ext.versions[packageName];
869         },
870
871         /**
872          * Create a closure for deprecated code.
873          *
874     // This means Ext.oldMethod is only supported in 4.0.0beta and older.
875     // If Ext.getVersion('extjs') returns a version that is later than '4.0.0beta', for example '4.0.0RC',
876     // the closure will not be invoked
877     Ext.deprecate('extjs', '4.0.0beta', function() {
878         Ext.oldMethod = Ext.newMethod;
879
880         ...
881     });
882
883          * @param {String} packageName The package name
884          * @param {String} since The last version before it's deprecated
885          * @param {Function} closure The callback function to be executed with the specified version is less than the current version
886          * @param {Object} scope The execution scope (<tt>this</tt>) if the closure
887          * @markdown
888          */
889         deprecate: function(packageName, since, closure, scope) {
890             if (Version.compare(Ext.getVersion(packageName), since) < 1) {
891                 closure.call(scope);
892             }
893         }
894     }); // End Versioning
895
896     Ext.setVersion('core', version);
897
898 })();
899
900 /**
901  * @class Ext.String
902  *
903  * A collection of useful static methods to deal with strings
904  * @singleton
905  */
906
907 Ext.String = {
908     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,
909     escapeRe: /('|\\)/g,
910     formatRe: /\{(\d+)\}/g,
911     escapeRegexRe: /([-.*+?^${}()|[\]\/\\])/g,
912
913     /**
914      * Convert certain characters (&, <, >, and ') to their HTML character equivalents for literal display in web pages.
915      * @param {String} value The string to encode
916      * @return {String} The encoded text
917      * @method
918      */
919     htmlEncode: (function() {
920         var entities = {
921             '&': '&amp;',
922             '>': '&gt;',
923             '<': '&lt;',
924             '"': '&quot;'
925         }, keys = [], p, regex;
926         
927         for (p in entities) {
928             keys.push(p);
929         }
930         
931         regex = new RegExp('(' + keys.join('|') + ')', 'g');
932         
933         return function(value) {
934             return (!value) ? value : String(value).replace(regex, function(match, capture) {
935                 return entities[capture];    
936             });
937         };
938     })(),
939
940     /**
941      * Convert certain characters (&, <, >, and ') from their HTML character equivalents.
942      * @param {String} value The string to decode
943      * @return {String} The decoded text
944      * @method
945      */
946     htmlDecode: (function() {
947         var entities = {
948             '&amp;': '&',
949             '&gt;': '>',
950             '&lt;': '<',
951             '&quot;': '"'
952         }, keys = [], p, regex;
953         
954         for (p in entities) {
955             keys.push(p);
956         }
957         
958         regex = new RegExp('(' + keys.join('|') + '|&#[0-9]{1,5};' + ')', 'g');
959         
960         return function(value) {
961             return (!value) ? value : String(value).replace(regex, function(match, capture) {
962                 if (capture in entities) {
963                     return entities[capture];
964                 } else {
965                     return String.fromCharCode(parseInt(capture.substr(2), 10));
966                 }
967             });
968         };
969     })(),
970
971     /**
972      * Appends content to the query string of a URL, handling logic for whether to place
973      * a question mark or ampersand.
974      * @param {String} url The URL to append to.
975      * @param {String} string The content to append to the URL.
976      * @return (String) The resulting URL
977      */
978     urlAppend : function(url, string) {
979         if (!Ext.isEmpty(string)) {
980             return url + (url.indexOf('?') === -1 ? '?' : '&') + string;
981         }
982
983         return url;
984     },
985
986     /**
987      * Trims whitespace from either end of a string, leaving spaces within the string intact.  Example:
988      * @example
989 var s = '  foo bar  ';
990 alert('-' + s + '-');         //alerts "- foo bar -"
991 alert('-' + Ext.String.trim(s) + '-');  //alerts "-foo bar-"
992
993      * @param {String} string The string to escape
994      * @return {String} The trimmed string
995      */
996     trim: function(string) {
997         return string.replace(Ext.String.trimRegex, "");
998     },
999
1000     /**
1001      * Capitalize the given string
1002      * @param {String} string
1003      * @return {String}
1004      */
1005     capitalize: function(string) {
1006         return string.charAt(0).toUpperCase() + string.substr(1);
1007     },
1008
1009     /**
1010      * Truncate a string and add an ellipsis ('...') to the end if it exceeds the specified length
1011      * @param {String} value The string to truncate
1012      * @param {Number} length The maximum length to allow before truncating
1013      * @param {Boolean} word True to try to find a common word break
1014      * @return {String} The converted text
1015      */
1016     ellipsis: function(value, len, word) {
1017         if (value && value.length > len) {
1018             if (word) {
1019                 var vs = value.substr(0, len - 2),
1020                 index = Math.max(vs.lastIndexOf(' '), vs.lastIndexOf('.'), vs.lastIndexOf('!'), vs.lastIndexOf('?'));
1021                 if (index !== -1 && index >= (len - 15)) {
1022                     return vs.substr(0, index) + "...";
1023                 }
1024             }
1025             return value.substr(0, len - 3) + "...";
1026         }
1027         return value;
1028     },
1029
1030     /**
1031      * Escapes the passed string for use in a regular expression
1032      * @param {String} string
1033      * @return {String}
1034      */
1035     escapeRegex: function(string) {
1036         return string.replace(Ext.String.escapeRegexRe, "\\$1");
1037     },
1038
1039     /**
1040      * Escapes the passed string for ' and \
1041      * @param {String} string The string to escape
1042      * @return {String} The escaped string
1043      */
1044     escape: function(string) {
1045         return string.replace(Ext.String.escapeRe, "\\$1");
1046     },
1047
1048     /**
1049      * Utility function that allows you to easily switch a string between two alternating values.  The passed value
1050      * is compared to the current string, and if they are equal, the other value that was passed in is returned.  If
1051      * they are already different, the first value passed in is returned.  Note that this method returns the new value
1052      * but does not change the current string.
1053      * <pre><code>
1054     // alternate sort directions
1055     sort = Ext.String.toggle(sort, 'ASC', 'DESC');
1056
1057     // instead of conditional logic:
1058     sort = (sort == 'ASC' ? 'DESC' : 'ASC');
1059        </code></pre>
1060      * @param {String} string The current string
1061      * @param {String} value The value to compare to the current string
1062      * @param {String} other The new value to use if the string already equals the first value passed in
1063      * @return {String} The new value
1064      */
1065     toggle: function(string, value, other) {
1066         return string === value ? other : value;
1067     },
1068
1069     /**
1070      * Pads the left side of a string with a specified character.  This is especially useful
1071      * for normalizing number and date strings.  Example usage:
1072      *
1073      * <pre><code>
1074 var s = Ext.String.leftPad('123', 5, '0');
1075 // s now contains the string: '00123'
1076        </code></pre>
1077      * @param {String} string The original string
1078      * @param {Number} size The total length of the output string
1079      * @param {String} character (optional) The character with which to pad the original string (defaults to empty string " ")
1080      * @return {String} The padded string
1081      */
1082     leftPad: function(string, size, character) {
1083         var result = String(string);
1084         character = character || " ";
1085         while (result.length < size) {
1086             result = character + result;
1087         }
1088         return result;
1089     },
1090
1091     /**
1092      * Allows you to define a tokenized string and pass an arbitrary number of arguments to replace the tokens.  Each
1093      * token must be unique, and must increment in the format {0}, {1}, etc.  Example usage:
1094      * <pre><code>
1095 var cls = 'my-class', text = 'Some text';
1096 var s = Ext.String.format('&lt;div class="{0}">{1}&lt;/div>', cls, text);
1097 // s now contains the string: '&lt;div class="my-class">Some text&lt;/div>'
1098        </code></pre>
1099      * @param {String} string The tokenized string to be formatted
1100      * @param {String} value1 The value to replace token {0}
1101      * @param {String} value2 Etc...
1102      * @return {String} The formatted string
1103      */
1104     format: function(format) {
1105         var args = Ext.Array.toArray(arguments, 1);
1106         return format.replace(Ext.String.formatRe, function(m, i) {
1107             return args[i];
1108         });
1109     }
1110 };
1111
1112 /**
1113  * @class Ext.Number
1114  *
1115  * A collection of useful static methods to deal with numbers
1116  * @singleton
1117  */
1118
1119 (function() {
1120
1121 var isToFixedBroken = (0.9).toFixed() !== '1';
1122
1123 Ext.Number = {
1124     /**
1125      * Checks whether or not the current number is within a desired range.  If the number is already within the
1126      * range it is returned, otherwise the min or max value is returned depending on which side of the range is
1127      * exceeded. Note that this method returns the constrained value but does not change the current number.
1128      * @param {Number} number The number to check
1129      * @param {Number} min The minimum number in the range
1130      * @param {Number} max The maximum number in the range
1131      * @return {Number} The constrained value if outside the range, otherwise the current value
1132      */
1133     constrain: function(number, min, max) {
1134         number = parseFloat(number);
1135
1136         if (!isNaN(min)) {
1137             number = Math.max(number, min);
1138         }
1139         if (!isNaN(max)) {
1140             number = Math.min(number, max);
1141         }
1142         return number;
1143     },
1144
1145     /**
1146      * Formats a number using fixed-point notation
1147      * @param {Number} value The number to format
1148      * @param {Number} precision The number of digits to show after the decimal point
1149      */
1150     toFixed: function(value, precision) {
1151         if (isToFixedBroken) {
1152             precision = precision || 0;
1153             var pow = Math.pow(10, precision);
1154             return (Math.round(value * pow) / pow).toFixed(precision);
1155         }
1156
1157         return value.toFixed(precision);
1158     },
1159
1160     /**
1161      * Validate that a value is numeric and convert it to a number if necessary. Returns the specified default value if
1162      * it is not.
1163
1164 Ext.Number.from('1.23', 1); // returns 1.23
1165 Ext.Number.from('abc', 1); // returns 1
1166
1167      * @param {Mixed} value
1168      * @param {Number} defaultValue The value to return if the original value is non-numeric
1169      * @return {Number} value, if numeric, defaultValue otherwise
1170      */
1171     from: function(value, defaultValue) {
1172         if (isFinite(value)) {
1173             value = parseFloat(value);
1174         }
1175
1176         return !isNaN(value) ? value : defaultValue;
1177     }
1178 };
1179
1180 })();
1181
1182 /**
1183  * This method is deprecated, please use {@link Ext.Number#from Ext.Number.from} instead
1184  *
1185  * @deprecated 4.0.0 Replaced by Ext.Number.from
1186  * @member Ext
1187  * @method num
1188  */
1189 Ext.num = function() {
1190     return Ext.Number.from.apply(this, arguments);
1191 };
1192 /**
1193  * @author Jacky Nguyen <jacky@sencha.com>
1194  * @docauthor Jacky Nguyen <jacky@sencha.com>
1195  * @class Ext.Array
1196  *
1197  * A set of useful static methods to deal with arrays; provide missing methods for older browsers.
1198
1199  * @singleton
1200  * @markdown
1201  */
1202 (function() {
1203
1204     var arrayPrototype = Array.prototype,
1205         slice = arrayPrototype.slice,
1206         supportsForEach = 'forEach' in arrayPrototype,
1207         supportsMap = 'map' in arrayPrototype,
1208         supportsIndexOf = 'indexOf' in arrayPrototype,
1209         supportsEvery = 'every' in arrayPrototype,
1210         supportsSome = 'some' in arrayPrototype,
1211         supportsFilter = 'filter' in arrayPrototype,
1212         supportsSort = function() {
1213             var a = [1,2,3,4,5].sort(function(){ return 0; });
1214             return a[0] === 1 && a[1] === 2 && a[2] === 3 && a[3] === 4 && a[4] === 5;
1215         }(),
1216         supportsSliceOnNodeList = true,
1217         ExtArray;
1218     try {
1219         // IE 6 - 8 will throw an error when using Array.prototype.slice on NodeList
1220         if (typeof document !== 'undefined') {
1221             slice.call(document.getElementsByTagName('body'));
1222         }
1223     } catch (e) {
1224         supportsSliceOnNodeList = false;
1225     }
1226
1227     ExtArray = Ext.Array = {
1228         /**
1229          * Iterates an array or an iterable value and invoke the given callback function for each item.
1230
1231     var countries = ['Vietnam', 'Singapore', 'United States', 'Russia'];
1232
1233     Ext.Array.each(countries, function(name, index, countriesItSelf) {
1234         console.log(name);
1235     });
1236
1237     var sum = function() {
1238         var sum = 0;
1239
1240         Ext.Array.each(arguments, function(value) {
1241             sum += value;
1242         });
1243
1244         return sum;
1245     };
1246
1247     sum(1, 2, 3); // returns 6
1248
1249          * The iteration can be stopped by returning false in the function callback.
1250
1251     Ext.Array.each(countries, function(name, index, countriesItSelf) {
1252         if (name === 'Singapore') {
1253             return false; // break here
1254         }
1255     });
1256
1257          * @param {Array/NodeList/Mixed} iterable The value to be iterated. If this
1258          * argument is not iterable, the callback function is called once.
1259          * @param {Function} fn The callback function. If it returns false, the iteration stops and this method returns
1260          * the current `index`. Arguments passed to this callback function are:
1261
1262 - `item`: {Mixed} The item at the current `index` in the passed `array`
1263 - `index`: {Number} The current `index` within the `array`
1264 - `allItems`: {Array/NodeList/Mixed} The `array` passed as the first argument to `Ext.Array.each`
1265
1266          * @param {Object} scope (Optional) The scope (`this` reference) in which the specified function is executed.
1267          * @param {Boolean} reverse (Optional) Reverse the iteration order (loop from the end to the beginning)
1268          * Defaults false
1269          * @return {Boolean} See description for the `fn` parameter.
1270          * @markdown
1271          */
1272         each: function(array, fn, scope, reverse) {
1273             array = ExtArray.from(array);
1274
1275             var i,
1276                 ln = array.length;
1277
1278             if (reverse !== true) {
1279                 for (i = 0; i < ln; i++) {
1280                     if (fn.call(scope || array[i], array[i], i, array) === false) {
1281                         return i;
1282                     }
1283                 }
1284             }
1285             else {
1286                 for (i = ln - 1; i > -1; i--) {
1287                     if (fn.call(scope || array[i], array[i], i, array) === false) {
1288                         return i;
1289                     }
1290                 }
1291             }
1292
1293             return true;
1294         },
1295
1296         /**
1297          * Iterates an array and invoke the given callback function for each item. Note that this will simply
1298          * delegate to the native Array.prototype.forEach method if supported.
1299          * It doesn't support stopping the iteration by returning false in the callback function like
1300          * {@link Ext.Array#each}. However, performance could be much better in modern browsers comparing with
1301          * {@link Ext.Array#each}
1302          *
1303          * @param {Array} array The array to iterate
1304          * @param {Function} fn The function callback, to be invoked these arguments:
1305          *
1306 - `item`: {Mixed} The item at the current `index` in the passed `array`
1307 - `index`: {Number} The current `index` within the `array`
1308 - `allItems`: {Array} The `array` itself which was passed as the first argument
1309
1310          * @param {Object} scope (Optional) The execution scope (`this`) in which the specified function is executed.
1311          * @markdown
1312          */
1313         forEach: function(array, fn, scope) {
1314             if (supportsForEach) {
1315                 return array.forEach(fn, scope);
1316             }
1317
1318             var i = 0,
1319                 ln = array.length;
1320
1321             for (; i < ln; i++) {
1322                 fn.call(scope, array[i], i, array);
1323             }
1324         },
1325
1326         /**
1327          * Get the index of the provided `item` in the given `array`, a supplement for the
1328          * missing arrayPrototype.indexOf in Internet Explorer.
1329          *
1330          * @param {Array} array The array to check
1331          * @param {Mixed} item The item to look for
1332          * @param {Number} from (Optional) The index at which to begin the search
1333          * @return {Number} The index of item in the array (or -1 if it is not found)
1334          * @markdown
1335          */
1336         indexOf: function(array, item, from) {
1337             if (supportsIndexOf) {
1338                 return array.indexOf(item, from);
1339             }
1340
1341             var i, length = array.length;
1342
1343             for (i = (from < 0) ? Math.max(0, length + from) : from || 0; i < length; i++) {
1344                 if (array[i] === item) {
1345                     return i;
1346                 }
1347             }
1348
1349             return -1;
1350         },
1351
1352         /**
1353          * Checks whether or not the given `array` contains the specified `item`
1354          *
1355          * @param {Array} array The array to check
1356          * @param {Mixed} item The item to look for
1357          * @return {Boolean} True if the array contains the item, false otherwise
1358          * @markdown
1359          */
1360         contains: function(array, item) {
1361             if (supportsIndexOf) {
1362                 return array.indexOf(item) !== -1;
1363             }
1364
1365             var i, ln;
1366
1367             for (i = 0, ln = array.length; i < ln; i++) {
1368                 if (array[i] === item) {
1369                     return true;
1370                 }
1371             }
1372
1373             return false;
1374         },
1375
1376         /**
1377          * Converts any iterable (numeric indices and a length property) into a true array.
1378
1379 function test() {
1380     var args = Ext.Array.toArray(arguments),
1381         fromSecondToLastArgs = Ext.Array.toArray(arguments, 1);
1382
1383     alert(args.join(' '));
1384     alert(fromSecondToLastArgs.join(' '));
1385 }
1386
1387 test('just', 'testing', 'here'); // alerts 'just testing here';
1388                                  // alerts 'testing here';
1389
1390 Ext.Array.toArray(document.getElementsByTagName('div')); // will convert the NodeList into an array
1391 Ext.Array.toArray('splitted'); // returns ['s', 'p', 'l', 'i', 't', 't', 'e', 'd']
1392 Ext.Array.toArray('splitted', 0, 3); // returns ['s', 'p', 'l', 'i']
1393
1394          * @param {Mixed} iterable the iterable object to be turned into a true Array.
1395          * @param {Number} start (Optional) a zero-based index that specifies the start of extraction. Defaults to 0
1396          * @param {Number} end (Optional) a zero-based index that specifies the end of extraction. Defaults to the last
1397          * index of the iterable value
1398          * @return {Array} array
1399          * @markdown
1400          */
1401         toArray: function(iterable, start, end){
1402             if (!iterable || !iterable.length) {
1403                 return [];
1404             }
1405
1406             if (typeof iterable === 'string') {
1407                 iterable = iterable.split('');
1408             }
1409
1410             if (supportsSliceOnNodeList) {
1411                 return slice.call(iterable, start || 0, end || iterable.length);
1412             }
1413
1414             var array = [],
1415                 i;
1416
1417             start = start || 0;
1418             end = end ? ((end < 0) ? iterable.length + end : end) : iterable.length;
1419
1420             for (i = start; i < end; i++) {
1421                 array.push(iterable[i]);
1422             }
1423
1424             return array;
1425         },
1426
1427         /**
1428          * Plucks the value of a property from each item in the Array. Example:
1429          *
1430     Ext.Array.pluck(Ext.query("p"), "className"); // [el1.className, el2.className, ..., elN.className]
1431
1432          * @param {Array|NodeList} array The Array of items to pluck the value from.
1433          * @param {String} propertyName The property name to pluck from each element.
1434          * @return {Array} The value from each item in the Array.
1435          */
1436         pluck: function(array, propertyName) {
1437             var ret = [],
1438                 i, ln, item;
1439
1440             for (i = 0, ln = array.length; i < ln; i++) {
1441                 item = array[i];
1442
1443                 ret.push(item[propertyName]);
1444             }
1445
1446             return ret;
1447         },
1448
1449         /**
1450          * Creates a new array with the results of calling a provided function on every element in this array.
1451          * @param {Array} array
1452          * @param {Function} fn Callback function for each item
1453          * @param {Object} scope Callback function scope
1454          * @return {Array} results
1455          */
1456         map: function(array, fn, scope) {
1457             if (supportsMap) {
1458                 return array.map(fn, scope);
1459             }
1460
1461             var results = [],
1462                 i = 0,
1463                 len = array.length;
1464
1465             for (; i < len; i++) {
1466                 results[i] = fn.call(scope, array[i], i, array);
1467             }
1468
1469             return results;
1470         },
1471
1472         /**
1473          * Executes the specified function for each array element until the function returns a falsy value.
1474          * If such an item is found, the function will return false immediately.
1475          * Otherwise, it will return true.
1476          *
1477          * @param {Array} array
1478          * @param {Function} fn Callback function for each item
1479          * @param {Object} scope Callback function scope
1480          * @return {Boolean} True if no false value is returned by the callback function.
1481          */
1482         every: function(array, fn, scope) {
1483             if (!fn) {
1484                 Ext.Error.raise('Ext.Array.every must have a callback function passed as second argument.');
1485             }
1486             if (supportsEvery) {
1487                 return array.every(fn, scope);
1488             }
1489
1490             var i = 0,
1491                 ln = array.length;
1492
1493             for (; i < ln; ++i) {
1494                 if (!fn.call(scope, array[i], i, array)) {
1495                     return false;
1496                 }
1497             }
1498
1499             return true;
1500         },
1501
1502         /**
1503          * Executes the specified function for each array element until the function returns a truthy value.
1504          * If such an item is found, the function will return true immediately. Otherwise, it will return false.
1505          *
1506          * @param {Array} array
1507          * @param {Function} fn Callback function for each item
1508          * @param {Object} scope Callback function scope
1509          * @return {Boolean} True if the callback function returns a truthy value.
1510          */
1511         some: function(array, fn, scope) {
1512             if (!fn) {
1513                 Ext.Error.raise('Ext.Array.some must have a callback function passed as second argument.');
1514             }
1515             if (supportsSome) {
1516                 return array.some(fn, scope);
1517             }
1518
1519             var i = 0,
1520                 ln = array.length;
1521
1522             for (; i < ln; ++i) {
1523                 if (fn.call(scope, array[i], i, array)) {
1524                     return true;
1525                 }
1526             }
1527
1528             return false;
1529         },
1530
1531         /**
1532          * Filter through an array and remove empty item as defined in {@link Ext#isEmpty Ext.isEmpty}
1533          *
1534          * @see Ext.Array.filter
1535          * @param {Array} array
1536          * @return {Array} results
1537          */
1538         clean: function(array) {
1539             var results = [],
1540                 i = 0,
1541                 ln = array.length,
1542                 item;
1543
1544             for (; i < ln; i++) {
1545                 item = array[i];
1546
1547                 if (!Ext.isEmpty(item)) {
1548                     results.push(item);
1549                 }
1550             }
1551
1552             return results;
1553         },
1554
1555         /**
1556          * Returns a new array with unique items
1557          *
1558          * @param {Array} array
1559          * @return {Array} results
1560          */
1561         unique: function(array) {
1562             var clone = [],
1563                 i = 0,
1564                 ln = array.length,
1565                 item;
1566
1567             for (; i < ln; i++) {
1568                 item = array[i];
1569
1570                 if (ExtArray.indexOf(clone, item) === -1) {
1571                     clone.push(item);
1572                 }
1573             }
1574
1575             return clone;
1576         },
1577
1578         /**
1579          * Creates a new array with all of the elements of this array for which
1580          * the provided filtering function returns true.
1581          * @param {Array} array
1582          * @param {Function} fn Callback function for each item
1583          * @param {Object} scope Callback function scope
1584          * @return {Array} results
1585          */
1586         filter: function(array, fn, scope) {
1587             if (supportsFilter) {
1588                 return array.filter(fn, scope);
1589             }
1590
1591             var results = [],
1592                 i = 0,
1593                 ln = array.length;
1594
1595             for (; i < ln; i++) {
1596                 if (fn.call(scope, array[i], i, array)) {
1597                     results.push(array[i]);
1598                 }
1599             }
1600
1601             return results;
1602         },
1603
1604         /**
1605          * Converts a value to an array if it's not already an array; returns:
1606          *
1607          * - An empty array if given value is `undefined` or `null`
1608          * - Itself if given value is already an array
1609          * - An array copy if given value is {@link Ext#isIterable iterable} (arguments, NodeList and alike)
1610          * - An array with one item which is the given value, otherwise
1611          *
1612          * @param {Array/Mixed} value The value to convert to an array if it's not already is an array
1613          * @param {Boolean} (Optional) newReference True to clone the given array and return a new reference if necessary,
1614          * defaults to false
1615          * @return {Array} array
1616          * @markdown
1617          */
1618         from: function(value, newReference) {
1619             if (value === undefined || value === null) {
1620                 return [];
1621             }
1622
1623             if (Ext.isArray(value)) {
1624                 return (newReference) ? slice.call(value) : value;
1625             }
1626
1627             if (value && value.length !== undefined && typeof value !== 'string') {
1628                 return Ext.toArray(value);
1629             }
1630
1631             return [value];
1632         },
1633
1634         /**
1635          * Removes the specified item from the array if it exists
1636          *
1637          * @param {Array} array The array
1638          * @param {Mixed} item The item to remove
1639          * @return {Array} The passed array itself
1640          */
1641         remove: function(array, item) {
1642             var index = ExtArray.indexOf(array, item);
1643
1644             if (index !== -1) {
1645                 array.splice(index, 1);
1646             }
1647
1648             return array;
1649         },
1650
1651         /**
1652          * Push an item into the array only if the array doesn't contain it yet
1653          *
1654          * @param {Array} array The array
1655          * @param {Mixed} item The item to include
1656          * @return {Array} The passed array itself
1657          */
1658         include: function(array, item) {
1659             if (!ExtArray.contains(array, item)) {
1660                 array.push(item);
1661             }
1662         },
1663
1664         /**
1665          * Clone a flat array without referencing the previous one. Note that this is different
1666          * from Ext.clone since it doesn't handle recursive cloning. It's simply a convenient, easy-to-remember method
1667          * for Array.prototype.slice.call(array)
1668          *
1669          * @param {Array} array The array
1670          * @return {Array} The clone array
1671          */
1672         clone: function(array) {
1673             return slice.call(array);
1674         },
1675
1676         /**
1677          * Merge multiple arrays into one with unique items. Alias to {@link Ext.Array#union}.
1678          *
1679          * @param {Array} array,...
1680          * @return {Array} merged
1681          */
1682         merge: function() {
1683             var args = slice.call(arguments),
1684                 array = [],
1685                 i, ln;
1686
1687             for (i = 0, ln = args.length; i < ln; i++) {
1688                 array = array.concat(args[i]);
1689             }
1690
1691             return ExtArray.unique(array);
1692         },
1693
1694         /**
1695          * Merge multiple arrays into one with unique items that exist in all of the arrays.
1696          *
1697          * @param {Array} array,...
1698          * @return {Array} intersect
1699          */
1700         intersect: function() {
1701             var intersect = [],
1702                 arrays = slice.call(arguments),
1703                 i, j, k, minArray, array, x, y, ln, arraysLn, arrayLn;
1704
1705             if (!arrays.length) {
1706                 return intersect;
1707             }
1708
1709             // Find the smallest array
1710             for (i = x = 0,ln = arrays.length; i < ln,array = arrays[i]; i++) {
1711                 if (!minArray || array.length < minArray.length) {
1712                     minArray = array;
1713                     x = i;
1714                 }
1715             }
1716
1717             minArray = Ext.Array.unique(minArray);
1718             arrays.splice(x, 1);
1719
1720             // Use the smallest unique'd array as the anchor loop. If the other array(s) do contain
1721             // an item in the small array, we're likely to find it before reaching the end
1722             // of the inner loop and can terminate the search early.
1723             for (i = 0,ln = minArray.length; i < ln,x = minArray[i]; i++) {
1724                 var count = 0;
1725
1726                 for (j = 0,arraysLn = arrays.length; j < arraysLn,array = arrays[j]; j++) {
1727                     for (k = 0,arrayLn = array.length; k < arrayLn,y = array[k]; k++) {
1728                         if (x === y) {
1729                             count++;
1730                             break;
1731                         }
1732                     }
1733                 }
1734
1735                 if (count === arraysLn) {
1736                     intersect.push(x);
1737                 }
1738             }
1739
1740             return intersect;
1741         },
1742
1743         /**
1744          * Perform a set difference A-B by subtracting all items in array B from array A.
1745          *
1746          * @param {Array} array A
1747          * @param {Array} array B
1748          * @return {Array} difference
1749          */
1750         difference: function(arrayA, arrayB) {
1751             var clone = slice.call(arrayA),
1752                 ln = clone.length,
1753                 i, j, lnB;
1754
1755             for (i = 0,lnB = arrayB.length; i < lnB; i++) {
1756                 for (j = 0; j < ln; j++) {
1757                     if (clone[j] === arrayB[i]) {
1758                         clone.splice(j, 1);
1759                         j--;
1760                         ln--;
1761                     }
1762                 }
1763             }
1764
1765             return clone;
1766         },
1767
1768         /**
1769          * Sorts the elements of an Array.
1770          * By default, this method sorts the elements alphabetically and ascending.
1771          *
1772          * @param {Array} array The array to sort.
1773          * @param {Function} sortFn (optional) The comparison function.
1774          * @return {Array} The sorted array.
1775          */
1776         sort: function(array, sortFn) {
1777             if (supportsSort) {
1778                 if (sortFn) {
1779                     return array.sort(sortFn);
1780                 } else {
1781                     return array.sort();
1782                 }
1783             }
1784
1785             var length = array.length,
1786                 i = 0,
1787                 comparison,
1788                 j, min, tmp;
1789
1790             for (; i < length; i++) {
1791                 min = i;
1792                 for (j = i + 1; j < length; j++) {
1793                     if (sortFn) {
1794                         comparison = sortFn(array[j], array[min]);
1795                         if (comparison < 0) {
1796                             min = j;
1797                         }
1798                     } else if (array[j] < array[min]) {
1799                         min = j;
1800                     }
1801                 }
1802                 if (min !== i) {
1803                     tmp = array[i];
1804                     array[i] = array[min];
1805                     array[min] = tmp;
1806                 }
1807             }
1808
1809             return array;
1810         },
1811
1812         /**
1813          * Recursively flattens into 1-d Array. Injects Arrays inline.
1814          * @param {Array} array The array to flatten
1815          * @return {Array} The new, flattened array.
1816          */
1817         flatten: function(array) {
1818             var worker = [];
1819
1820             function rFlatten(a) {
1821                 var i, ln, v;
1822
1823                 for (i = 0, ln = a.length; i < ln; i++) {
1824                     v = a[i];
1825
1826                     if (Ext.isArray(v)) {
1827                         rFlatten(v);
1828                     } else {
1829                         worker.push(v);
1830                     }
1831                 }
1832
1833                 return worker;
1834             }
1835
1836             return rFlatten(array);
1837         },
1838
1839         /**
1840          * Returns the minimum value in the Array.
1841          * @param {Array|NodeList} array The Array from which to select the minimum value.
1842          * @param {Function} comparisonFn (optional) a function to perform the comparision which determines minimization.
1843          *                   If omitted the "<" operator will be used. Note: gt = 1; eq = 0; lt = -1
1844          * @return {Mixed} minValue The minimum value
1845          */
1846         min: function(array, comparisonFn) {
1847             var min = array[0],
1848                 i, ln, item;
1849
1850             for (i = 0, ln = array.length; i < ln; i++) {
1851                 item = array[i];
1852
1853                 if (comparisonFn) {
1854                     if (comparisonFn(min, item) === 1) {
1855                         min = item;
1856                     }
1857                 }
1858                 else {
1859                     if (item < min) {
1860                         min = item;
1861                     }
1862                 }
1863             }
1864
1865             return min;
1866         },
1867
1868         /**
1869          * Returns the maximum value in the Array
1870          * @param {Array|NodeList} array The Array from which to select the maximum value.
1871          * @param {Function} comparisonFn (optional) a function to perform the comparision which determines maximization.
1872          *                   If omitted the ">" operator will be used. Note: gt = 1; eq = 0; lt = -1
1873          * @return {Mixed} maxValue The maximum value
1874          */
1875         max: function(array, comparisonFn) {
1876             var max = array[0],
1877                 i, ln, item;
1878
1879             for (i = 0, ln = array.length; i < ln; i++) {
1880                 item = array[i];
1881
1882                 if (comparisonFn) {
1883                     if (comparisonFn(max, item) === -1) {
1884                         max = item;
1885                     }
1886                 }
1887                 else {
1888                     if (item > max) {
1889                         max = item;
1890                     }
1891                 }
1892             }
1893
1894             return max;
1895         },
1896
1897         /**
1898          * Calculates the mean of all items in the array
1899          * @param {Array} array The Array to calculate the mean value of.
1900          * @return {Number} The mean.
1901          */
1902         mean: function(array) {
1903             return array.length > 0 ? ExtArray.sum(array) / array.length : undefined;
1904         },
1905
1906         /**
1907          * Calculates the sum of all items in the given array
1908          * @param {Array} array The Array to calculate the sum value of.
1909          * @return {Number} The sum.
1910          */
1911         sum: function(array) {
1912             var sum = 0,
1913                 i, ln, item;
1914
1915             for (i = 0,ln = array.length; i < ln; i++) {
1916                 item = array[i];
1917
1918                 sum += item;
1919             }
1920
1921             return sum;
1922         }
1923
1924     };
1925
1926     /**
1927      * Convenient alias to {@link Ext.Array#each}
1928      * @member Ext
1929      * @method each
1930      */
1931     Ext.each = Ext.Array.each;
1932
1933     /**
1934      * Alias to {@link Ext.Array#merge}.
1935      * @member Ext.Array
1936      * @method union
1937      */
1938     Ext.Array.union = Ext.Array.merge;
1939
1940     /**
1941      * Old alias to {@link Ext.Array#min}
1942      * @deprecated 4.0.0 Use {@link Ext.Array#min} instead
1943      * @member Ext
1944      * @method min
1945      */
1946     Ext.min = Ext.Array.min;
1947
1948     /**
1949      * Old alias to {@link Ext.Array#max}
1950      * @deprecated 4.0.0 Use {@link Ext.Array#max} instead
1951      * @member Ext
1952      * @method max
1953      */
1954     Ext.max = Ext.Array.max;
1955
1956     /**
1957      * Old alias to {@link Ext.Array#sum}
1958      * @deprecated 4.0.0 Use {@link Ext.Array#sum} instead
1959      * @member Ext
1960      * @method sum
1961      */
1962     Ext.sum = Ext.Array.sum;
1963
1964     /**
1965      * Old alias to {@link Ext.Array#mean}
1966      * @deprecated 4.0.0 Use {@link Ext.Array#mean} instead
1967      * @member Ext
1968      * @method mean
1969      */
1970     Ext.mean = Ext.Array.mean;
1971
1972     /**
1973      * Old alias to {@link Ext.Array#flatten}
1974      * @deprecated 4.0.0 Use {@link Ext.Array#flatten} instead
1975      * @member Ext
1976      * @method flatten
1977      */
1978     Ext.flatten = Ext.Array.flatten;
1979
1980     /**
1981      * Old alias to {@link Ext.Array#clean Ext.Array.clean}
1982      * @deprecated 4.0.0 Use {@link Ext.Array.clean} instead
1983      * @member Ext
1984      * @method clean
1985      */
1986     Ext.clean = Ext.Array.clean;
1987
1988     /**
1989      * Old alias to {@link Ext.Array#unique Ext.Array.unique}
1990      * @deprecated 4.0.0 Use {@link Ext.Array.unique} instead
1991      * @member Ext
1992      * @method unique
1993      */
1994     Ext.unique = Ext.Array.unique;
1995
1996     /**
1997      * Old alias to {@link Ext.Array#pluck Ext.Array.pluck}
1998      * @deprecated 4.0.0 Use {@link Ext.Array#pluck Ext.Array.pluck} instead
1999      * @member Ext
2000      * @method pluck
2001      */
2002     Ext.pluck = Ext.Array.pluck;
2003
2004     /**
2005      * Convenient alias to {@link Ext.Array#toArray Ext.Array.toArray}
2006      * @param {Iterable} the iterable object to be turned into a true Array.
2007      * @member Ext
2008      * @method toArray
2009      * @return {Array} array
2010      */
2011     Ext.toArray = function() {
2012         return ExtArray.toArray.apply(ExtArray, arguments);
2013     }
2014 })();
2015
2016 /**
2017  * @class Ext.Function
2018  *
2019  * A collection of useful static methods to deal with function callbacks
2020  * @singleton
2021  */
2022
2023 Ext.Function = {
2024
2025     /**
2026      * A very commonly used method throughout the framework. It acts as a wrapper around another method
2027      * which originally accepts 2 arguments for <code>name</code> and <code>value</code>.
2028      * The wrapped function then allows "flexible" value setting of either:
2029      *
2030      * <ul>
2031      *      <li><code>name</code> and <code>value</code> as 2 arguments</li>
2032      *      <li>one single object argument with multiple key - value pairs</li>
2033      * </ul>
2034      *
2035      * For example:
2036      * <pre><code>
2037 var setValue = Ext.Function.flexSetter(function(name, value) {
2038     this[name] = value;
2039 });
2040
2041 // Afterwards
2042 // Setting a single name - value
2043 setValue('name1', 'value1');
2044
2045 // Settings multiple name - value pairs
2046 setValue({
2047     name1: 'value1',
2048     name2: 'value2',
2049     name3: 'value3'
2050 });
2051      * </code></pre>
2052      * @param {Function} setter
2053      * @returns {Function} flexSetter
2054      */
2055     flexSetter: function(fn) {
2056         return function(a, b) {
2057             var k, i;
2058
2059             if (a === null) {
2060                 return this;
2061             }
2062
2063             if (typeof a !== 'string') {
2064                 for (k in a) {
2065                     if (a.hasOwnProperty(k)) {
2066                         fn.call(this, k, a[k]);
2067                     }
2068                 }
2069
2070                 if (Ext.enumerables) {
2071                     for (i = Ext.enumerables.length; i--;) {
2072                         k = Ext.enumerables[i];
2073                         if (a.hasOwnProperty(k)) {
2074                             fn.call(this, k, a[k]);
2075                         }
2076                     }
2077                 }
2078             } else {
2079                 fn.call(this, a, b);
2080             }
2081
2082             return this;
2083         };
2084     },
2085
2086    /**
2087      * Create a new function from the provided <code>fn</code>, change <code>this</code> to the provided scope, optionally
2088      * overrides arguments for the call. (Defaults to the arguments passed by the caller)
2089      *
2090      * @param {Function} fn The function to delegate.
2091      * @param {Object} scope (optional) The scope (<code><b>this</b></code> reference) in which the function is executed.
2092      * <b>If omitted, defaults to the browser window.</b>
2093      * @param {Array} args (optional) Overrides arguments for the call. (Defaults to the arguments passed by the caller)
2094      * @param {Boolean/Number} appendArgs (optional) if True args are appended to call args instead of overriding,
2095      * if a number the args are inserted at the specified position
2096      * @return {Function} The new function
2097      */
2098     bind: function(fn, scope, args, appendArgs) {
2099         var method = fn,
2100             applyArgs;
2101
2102         return function() {
2103             var callArgs = args || arguments;
2104
2105             if (appendArgs === true) {
2106                 callArgs = Array.prototype.slice.call(arguments, 0);
2107                 callArgs = callArgs.concat(args);
2108             }
2109             else if (Ext.isNumber(appendArgs)) {
2110                 callArgs = Array.prototype.slice.call(arguments, 0); // copy arguments first
2111                 applyArgs = [appendArgs, 0].concat(args); // create method call params
2112                 Array.prototype.splice.apply(callArgs, applyArgs); // splice them in
2113             }
2114
2115             return method.apply(scope || window, callArgs);
2116         };
2117     },
2118
2119     /**
2120      * Create a new function from the provided <code>fn</code>, the arguments of which are pre-set to `args`.
2121      * New arguments passed to the newly created callback when it's invoked are appended after the pre-set ones.
2122      * This is especially useful when creating callbacks.
2123      * For example:
2124      *
2125     var originalFunction = function(){
2126         alert(Ext.Array.from(arguments).join(' '));
2127     };
2128
2129     var callback = Ext.Function.pass(originalFunction, ['Hello', 'World']);
2130
2131     callback(); // alerts 'Hello World'
2132     callback('by Me'); // alerts 'Hello World by Me'
2133
2134      * @param {Function} fn The original function
2135      * @param {Array} args The arguments to pass to new callback
2136      * @param {Object} scope (optional) The scope (<code><b>this</b></code> reference) in which the function is executed.
2137      * @return {Function} The new callback function
2138      */
2139     pass: function(fn, args, scope) {
2140         if (args) {
2141             args = Ext.Array.from(args);
2142         }
2143
2144         return function() {
2145             return fn.apply(scope, args.concat(Ext.Array.toArray(arguments)));
2146         };
2147     },
2148
2149     /**
2150      * Create an alias to the provided method property with name <code>methodName</code> of <code>object</code>.
2151      * Note that the execution scope will still be bound to the provided <code>object</code> itself.
2152      *
2153      * @param {Object/Function} object
2154      * @param {String} methodName
2155      * @return {Function} aliasFn
2156      */
2157     alias: function(object, methodName) {
2158         return function() {
2159             return object[methodName].apply(object, arguments);
2160         };
2161     },
2162
2163     /**
2164      * Creates an interceptor function. The passed function is called before the original one. If it returns false,
2165      * the original one is not called. The resulting function returns the results of the original function.
2166      * The passed function is called with the parameters of the original function. Example usage:
2167      * <pre><code>
2168 var sayHi = function(name){
2169     alert('Hi, ' + name);
2170 }
2171
2172 sayHi('Fred'); // alerts "Hi, Fred"
2173
2174 // create a new function that validates input without
2175 // directly modifying the original function:
2176 var sayHiToFriend = Ext.Function.createInterceptor(sayHi, function(name){
2177     return name == 'Brian';
2178 });
2179
2180 sayHiToFriend('Fred');  // no alert
2181 sayHiToFriend('Brian'); // alerts "Hi, Brian"
2182      </code></pre>
2183      * @param {Function} origFn The original function.
2184      * @param {Function} newFn The function to call before the original
2185      * @param {Object} scope (optional) The scope (<code><b>this</b></code> reference) in which the passed function is executed.
2186      * <b>If omitted, defaults to the scope in which the original function is called or the browser window.</b>
2187      * @param {Mixed} returnValue (optional) The value to return if the passed function return false (defaults to null).
2188      * @return {Function} The new function
2189      */
2190     createInterceptor: function(origFn, newFn, scope, returnValue) {
2191         var method = origFn;
2192         if (!Ext.isFunction(newFn)) {
2193             return origFn;
2194         }
2195         else {
2196             return function() {
2197                 var me = this,
2198                     args = arguments;
2199                 newFn.target = me;
2200                 newFn.method = origFn;
2201                 return (newFn.apply(scope || me || window, args) !== false) ? origFn.apply(me || window, args) : returnValue || null;
2202             };
2203         }
2204     },
2205
2206     /**
2207     * Creates a delegate (callback) which, when called, executes after a specific delay.
2208     * @param {Function} fn The function which will be called on a delay when the returned function is called.
2209     * Optionally, a replacement (or additional) argument list may be specified.
2210     * @param {Number} delay The number of milliseconds to defer execution by whenever called.
2211     * @param {Object} scope (optional) The scope (<code>this</code> reference) used by the function at execution time.
2212     * @param {Array} args (optional) Override arguments for the call. (Defaults to the arguments passed by the caller)
2213     * @param {Boolean/Number} appendArgs (optional) if True args are appended to call args instead of overriding,
2214     * if a number the args are inserted at the specified position.
2215     * @return {Function} A function which, when called, executes the original function after the specified delay.
2216     */
2217     createDelayed: function(fn, delay, scope, args, appendArgs) {
2218         if (scope || args) {
2219             fn = Ext.Function.bind(fn, scope, args, appendArgs);
2220         }
2221         return function() {
2222             var me = this;
2223             setTimeout(function() {
2224                 fn.apply(me, arguments);
2225             }, delay);
2226         };
2227     },
2228
2229     /**
2230      * Calls this function after the number of millseconds specified, optionally in a specific scope. Example usage:
2231      * <pre><code>
2232 var sayHi = function(name){
2233     alert('Hi, ' + name);
2234 }
2235
2236 // executes immediately:
2237 sayHi('Fred');
2238
2239 // executes after 2 seconds:
2240 Ext.Function.defer(sayHi, 2000, this, ['Fred']);
2241
2242 // this syntax is sometimes useful for deferring
2243 // execution of an anonymous function:
2244 Ext.Function.defer(function(){
2245     alert('Anonymous');
2246 }, 100);
2247      </code></pre>
2248      * @param {Function} fn The function to defer.
2249      * @param {Number} millis The number of milliseconds for the setTimeout call (if less than or equal to 0 the function is executed immediately)
2250      * @param {Object} scope (optional) The scope (<code><b>this</b></code> reference) in which the function is executed.
2251      * <b>If omitted, defaults to the browser window.</b>
2252      * @param {Array} args (optional) Overrides arguments for the call. (Defaults to the arguments passed by the caller)
2253      * @param {Boolean/Number} appendArgs (optional) if True args are appended to call args instead of overriding,
2254      * if a number the args are inserted at the specified position
2255      * @return {Number} The timeout id that can be used with clearTimeout
2256      */
2257     defer: function(fn, millis, obj, args, appendArgs) {
2258         fn = Ext.Function.bind(fn, obj, args, appendArgs);
2259         if (millis > 0) {
2260             return setTimeout(fn, millis);
2261         }
2262         fn();
2263         return 0;
2264     },
2265
2266     /**
2267      * Create a combined function call sequence of the original function + the passed function.
2268      * The resulting function returns the results of the original function.
2269      * The passed function is called with the parameters of the original function. Example usage:
2270      *
2271      * <pre><code>
2272 var sayHi = function(name){
2273     alert('Hi, ' + name);
2274 }
2275
2276 sayHi('Fred'); // alerts "Hi, Fred"
2277
2278 var sayGoodbye = Ext.Function.createSequence(sayHi, function(name){
2279     alert('Bye, ' + name);
2280 });
2281
2282 sayGoodbye('Fred'); // both alerts show
2283      * </code></pre>
2284      *
2285      * @param {Function} origFn The original function.
2286      * @param {Function} newFn The function to sequence
2287      * @param {Object} scope (optional) The scope (this reference) in which the passed function is executed.
2288      * If omitted, defaults to the scope in which the original function is called or the browser window.
2289      * @return {Function} The new function
2290      */
2291     createSequence: function(origFn, newFn, scope) {
2292         if (!Ext.isFunction(newFn)) {
2293             return origFn;
2294         }
2295         else {
2296             return function() {
2297                 var retval = origFn.apply(this || window, arguments);
2298                 newFn.apply(scope || this || window, arguments);
2299                 return retval;
2300             };
2301         }
2302     },
2303
2304     /**
2305      * <p>Creates a delegate function, optionally with a bound scope which, when called, buffers
2306      * the execution of the passed function for the configured number of milliseconds.
2307      * If called again within that period, the impending invocation will be canceled, and the
2308      * timeout period will begin again.</p>
2309      *
2310      * @param {Function} fn The function to invoke on a buffered timer.
2311      * @param {Number} buffer The number of milliseconds by which to buffer the invocation of the
2312      * function.
2313      * @param {Object} scope (optional) The scope (<code><b>this</b></code> reference) in which
2314      * the passed function is executed. If omitted, defaults to the scope specified by the caller.
2315      * @param {Array} args (optional) Override arguments for the call. Defaults to the arguments
2316      * passed by the caller.
2317      * @return {Function} A function which invokes the passed function after buffering for the specified time.
2318      */
2319     createBuffered: function(fn, buffer, scope, args) {
2320         return function(){
2321             var timerId;
2322             return function() {
2323                 var me = this;
2324                 if (timerId) {
2325                     clearInterval(timerId);
2326                     timerId = null;
2327                 }
2328                 timerId = setTimeout(function(){
2329                     fn.apply(scope || me, args || arguments);
2330                 }, buffer);
2331             };
2332         }();
2333     },
2334
2335     /**
2336      * <p>Creates a throttled version of the passed function which, when called repeatedly and
2337      * rapidly, invokes the passed function only after a certain interval has elapsed since the
2338      * previous invocation.</p>
2339      *
2340      * <p>This is useful for wrapping functions which may be called repeatedly, such as
2341      * a handler of a mouse move event when the processing is expensive.</p>
2342      *
2343      * @param fn {Function} The function to execute at a regular time interval.
2344      * @param interval {Number} The interval <b>in milliseconds</b> on which the passed function is executed.
2345      * @param scope (optional) The scope (<code><b>this</b></code> reference) in which
2346      * the passed function is executed. If omitted, defaults to the scope specified by the caller.
2347      * @returns {Function} A function which invokes the passed function at the specified interval.
2348      */
2349     createThrottled: function(fn, interval, scope) {
2350         var lastCallTime, elapsed, lastArgs, timer, execute = function() {
2351             fn.apply(scope || this, lastArgs);
2352             lastCallTime = new Date().getTime();
2353         };
2354
2355         return function() {
2356             elapsed = new Date().getTime() - lastCallTime;
2357             lastArgs = arguments;
2358
2359             clearTimeout(timer);
2360             if (!lastCallTime || (elapsed >= interval)) {
2361                 execute();
2362             } else {
2363                 timer = setTimeout(execute, interval - elapsed);
2364             }
2365         };
2366     }
2367 };
2368
2369 /**
2370  * Shorthand for {@link Ext.Function#defer}
2371  * @member Ext
2372  * @method defer
2373  */
2374 Ext.defer = Ext.Function.alias(Ext.Function, 'defer');
2375
2376 /**
2377  * Shorthand for {@link Ext.Function#pass}
2378  * @member Ext
2379  * @method pass
2380  */
2381 Ext.pass = Ext.Function.alias(Ext.Function, 'pass');
2382
2383 /**
2384  * Shorthand for {@link Ext.Function#bind}
2385  * @member Ext
2386  * @method bind
2387  */
2388 Ext.bind = Ext.Function.alias(Ext.Function, 'bind');
2389
2390 /**
2391  * @author Jacky Nguyen <jacky@sencha.com>
2392  * @docauthor Jacky Nguyen <jacky@sencha.com>
2393  * @class Ext.Object
2394  *
2395  * A collection of useful static methods to deal with objects
2396  *
2397  * @singleton
2398  */
2399
2400 (function() {
2401
2402 var ExtObject = Ext.Object = {
2403
2404     /**
2405      * Convert a `name` - `value` pair to an array of objects with support for nested structures; useful to construct
2406      * query strings. For example:
2407
2408     var objects = Ext.Object.toQueryObjects('hobbies', ['reading', 'cooking', 'swimming']);
2409
2410     // objects then equals:
2411     [
2412         { name: 'hobbies', value: 'reading' },
2413         { name: 'hobbies', value: 'cooking' },
2414         { name: 'hobbies', value: 'swimming' },
2415     ];
2416
2417     var objects = Ext.Object.toQueryObjects('dateOfBirth', {
2418         day: 3,
2419         month: 8,
2420         year: 1987,
2421         extra: {
2422             hour: 4
2423             minute: 30
2424         }
2425     }, true); // Recursive
2426
2427     // objects then equals:
2428     [
2429         { name: 'dateOfBirth[day]', value: 3 },
2430         { name: 'dateOfBirth[month]', value: 8 },
2431         { name: 'dateOfBirth[year]', value: 1987 },
2432         { name: 'dateOfBirth[extra][hour]', value: 4 },
2433         { name: 'dateOfBirth[extra][minute]', value: 30 },
2434     ];
2435
2436      * @param {String} name
2437      * @param {Mixed} value
2438      * @param {Boolean} recursive
2439      * @markdown
2440      */
2441     toQueryObjects: function(name, value, recursive) {
2442         var self = ExtObject.toQueryObjects,
2443             objects = [],
2444             i, ln;
2445
2446         if (Ext.isArray(value)) {
2447             for (i = 0, ln = value.length; i < ln; i++) {
2448                 if (recursive) {
2449                     objects = objects.concat(self(name + '[' + i + ']', value[i], true));
2450                 }
2451                 else {
2452                     objects.push({
2453                         name: name,
2454                         value: value[i]
2455                     });
2456                 }
2457             }
2458         }
2459         else if (Ext.isObject(value)) {
2460             for (i in value) {
2461                 if (value.hasOwnProperty(i)) {
2462                     if (recursive) {
2463                         objects = objects.concat(self(name + '[' + i + ']', value[i], true));
2464                     }
2465                     else {
2466                         objects.push({
2467                             name: name,
2468                             value: value[i]
2469                         });
2470                     }
2471                 }
2472             }
2473         }
2474         else {
2475             objects.push({
2476                 name: name,
2477                 value: value
2478             });
2479         }
2480
2481         return objects;
2482     },
2483
2484     /**
2485      * Takes an object and converts it to an encoded query string
2486
2487 - Non-recursive:
2488
2489     Ext.Object.toQueryString({foo: 1, bar: 2}); // returns "foo=1&bar=2"
2490     Ext.Object.toQueryString({foo: null, bar: 2}); // returns "foo=&bar=2"
2491     Ext.Object.toQueryString({'some price': '$300'}); // returns "some%20price=%24300"
2492     Ext.Object.toQueryString({date: new Date(2011, 0, 1)}); // returns "date=%222011-01-01T00%3A00%3A00%22"
2493     Ext.Object.toQueryString({colors: ['red', 'green', 'blue']}); // returns "colors=red&colors=green&colors=blue"
2494
2495 - Recursive:
2496
2497     Ext.Object.toQueryString({
2498         username: 'Jacky',
2499         dateOfBirth: {
2500             day: 1,
2501             month: 2,
2502             year: 1911
2503         },
2504         hobbies: ['coding', 'eating', 'sleeping', ['nested', 'stuff']]
2505     }, true); // returns the following string (broken down and url-decoded for ease of reading purpose):
2506               // username=Jacky
2507               //    &dateOfBirth[day]=1&dateOfBirth[month]=2&dateOfBirth[year]=1911
2508               //    &hobbies[0]=coding&hobbies[1]=eating&hobbies[2]=sleeping&hobbies[3][0]=nested&hobbies[3][1]=stuff
2509
2510      *
2511      * @param {Object} object The object to encode
2512      * @param {Boolean} recursive (optional) Whether or not to interpret the object in recursive format.
2513      * (PHP / Ruby on Rails servers and similar). Defaults to false
2514      * @return {String} queryString
2515      * @markdown
2516      */
2517     toQueryString: function(object, recursive) {
2518         var paramObjects = [],
2519             params = [],
2520             i, j, ln, paramObject, value;
2521
2522         for (i in object) {
2523             if (object.hasOwnProperty(i)) {
2524                 paramObjects = paramObjects.concat(ExtObject.toQueryObjects(i, object[i], recursive));
2525             }
2526         }
2527
2528         for (j = 0, ln = paramObjects.length; j < ln; j++) {
2529             paramObject = paramObjects[j];
2530             value = paramObject.value;
2531
2532             if (Ext.isEmpty(value)) {
2533                 value = '';
2534             }
2535             else if (Ext.isDate(value)) {
2536                 value = Ext.Date.toString(value);
2537             }
2538
2539             params.push(encodeURIComponent(paramObject.name) + '=' + encodeURIComponent(String(value)));
2540         }
2541
2542         return params.join('&');
2543     },
2544
2545     /**
2546      * Converts a query string back into an object.
2547      *
2548 - Non-recursive:
2549
2550     Ext.Object.fromQueryString(foo=1&bar=2); // returns {foo: 1, bar: 2}
2551     Ext.Object.fromQueryString(foo=&bar=2); // returns {foo: null, bar: 2}
2552     Ext.Object.fromQueryString(some%20price=%24300); // returns {'some price': '$300'}
2553     Ext.Object.fromQueryString(colors=red&colors=green&colors=blue); // returns {colors: ['red', 'green', 'blue']}
2554
2555 - Recursive:
2556
2557     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);
2558
2559     // returns
2560     {
2561         username: 'Jacky',
2562         dateOfBirth: {
2563             day: '1',
2564             month: '2',
2565             year: '1911'
2566         },
2567         hobbies: ['coding', 'eating', 'sleeping', ['nested', 'stuff']]
2568     }
2569
2570      * @param {String} queryString The query string to decode
2571      * @param {Boolean} recursive (Optional) Whether or not to recursively decode the string. This format is supported by
2572      * PHP / Ruby on Rails servers and similar. Defaults to false
2573      * @return {Object}
2574      */
2575     fromQueryString: function(queryString, recursive) {
2576         var parts = queryString.replace(/^\?/, '').split('&'),
2577             object = {},
2578             temp, components, name, value, i, ln,
2579             part, j, subLn, matchedKeys, matchedName,
2580             keys, key, nextKey;
2581
2582         for (i = 0, ln = parts.length; i < ln; i++) {
2583             part = parts[i];
2584
2585             if (part.length > 0) {
2586                 components = part.split('=');
2587                 name = decodeURIComponent(components[0]);
2588                 value = (components[1] !== undefined) ? decodeURIComponent(components[1]) : '';
2589
2590                 if (!recursive) {
2591                     if (object.hasOwnProperty(name)) {
2592                         if (!Ext.isArray(object[name])) {
2593                             object[name] = [object[name]];
2594                         }
2595
2596                         object[name].push(value);
2597                     }
2598                     else {
2599                         object[name] = value;
2600                     }
2601                 }
2602                 else {
2603                     matchedKeys = name.match(/(\[):?([^\]]*)\]/g);
2604                     matchedName = name.match(/^([^\[]+)/);
2605
2606                     if (!matchedName) {
2607                         Ext.Error.raise({
2608                             sourceClass: "Ext.Object",
2609                             sourceMethod: "fromQueryString",
2610                             queryString: queryString,
2611                             recursive: recursive,
2612                             msg: 'Malformed query string given, failed parsing name from "' + part + '"'
2613                         });
2614                     }
2615
2616                     name = matchedName[0];
2617                     keys = [];
2618
2619                     if (matchedKeys === null) {
2620                         object[name] = value;
2621                         continue;
2622                     }
2623
2624                     for (j = 0, subLn = matchedKeys.length; j < subLn; j++) {
2625                         key = matchedKeys[j];
2626                         key = (key.length === 2) ? '' : key.substring(1, key.length - 1);
2627                         keys.push(key);
2628                     }
2629
2630                     keys.unshift(name);
2631
2632                     temp = object;
2633
2634                     for (j = 0, subLn = keys.length; j < subLn; j++) {
2635                         key = keys[j];
2636
2637                         if (j === subLn - 1) {
2638                             if (Ext.isArray(temp) && key === '') {
2639                                 temp.push(value);
2640                             }
2641                             else {
2642                                 temp[key] = value;
2643                             }
2644                         }
2645                         else {
2646                             if (temp[key] === undefined || typeof temp[key] === 'string') {
2647                                 nextKey = keys[j+1];
2648
2649                                 temp[key] = (Ext.isNumeric(nextKey) || nextKey === '') ? [] : {};
2650                             }
2651
2652                             temp = temp[key];
2653                         }
2654                     }
2655                 }
2656             }
2657         }
2658
2659         return object;
2660     },
2661
2662     /**
2663      * Iterate through an object and invoke the given callback function for each iteration. The iteration can be stop
2664      * by returning `false` in the callback function. For example:
2665
2666     var person = {
2667         name: 'Jacky'
2668         hairColor: 'black'
2669         loves: ['food', 'sleeping', 'wife']
2670     };
2671
2672     Ext.Object.each(person, function(key, value, myself) {
2673         console.log(key + ":" + value);
2674
2675         if (key === 'hairColor') {
2676             return false; // stop the iteration
2677         }
2678     });
2679
2680      * @param {Object} object The object to iterate
2681      * @param {Function} fn The callback function. Passed arguments for each iteration are:
2682
2683 - {String} `key`
2684 - {Mixed} `value`
2685 - {Object} `object` The object itself
2686
2687      * @param {Object} scope (Optional) The execution scope (`this`) of the callback function
2688      * @markdown
2689      */
2690     each: function(object, fn, scope) {
2691         for (var property in object) {
2692             if (object.hasOwnProperty(property)) {
2693                 if (fn.call(scope || object, property, object[property], object) === false) {
2694                     return;
2695                 }
2696             }
2697         }
2698     },
2699
2700     /**
2701      * Merges any number of objects recursively without referencing them or their children.
2702
2703     var extjs = {
2704         companyName: 'Ext JS',
2705         products: ['Ext JS', 'Ext GWT', 'Ext Designer'],
2706         isSuperCool: true
2707         office: {
2708             size: 2000,
2709             location: 'Palo Alto',
2710             isFun: true
2711         }
2712     };
2713
2714     var newStuff = {
2715         companyName: 'Sencha Inc.',
2716         products: ['Ext JS', 'Ext GWT', 'Ext Designer', 'Sencha Touch', 'Sencha Animator'],
2717         office: {
2718             size: 40000,
2719             location: 'Redwood City'
2720         }
2721     };
2722
2723     var sencha = Ext.Object.merge(extjs, newStuff);
2724
2725     // extjs and sencha then equals to
2726     {
2727         companyName: 'Sencha Inc.',
2728         products: ['Ext JS', 'Ext GWT', 'Ext Designer', 'Sencha Touch', 'Sencha Animator'],
2729         isSuperCool: true
2730         office: {
2731             size: 30000,
2732             location: 'Redwood City'
2733             isFun: true
2734         }
2735     }
2736
2737      * @param {Object} object,...
2738      * @return {Object} merged The object that is created as a result of merging all the objects passed in.
2739      * @markdown
2740      */
2741     merge: function(source, key, value) {
2742         if (typeof key === 'string') {
2743             if (value && value.constructor === Object) {
2744                 if (source[key] && source[key].constructor === Object) {
2745                     ExtObject.merge(source[key], value);
2746                 }
2747                 else {
2748                     source[key] = Ext.clone(value);
2749                 }
2750             }
2751             else {
2752                 source[key] = value;
2753             }
2754
2755             return source;
2756         }
2757
2758         var i = 1,
2759             ln = arguments.length,
2760             object, property;
2761
2762         for (; i < ln; i++) {
2763             object = arguments[i];
2764
2765             for (property in object) {
2766                 if (object.hasOwnProperty(property)) {
2767                     ExtObject.merge(source, property, object[property]);
2768                 }
2769             }
2770         }
2771
2772         return source;
2773     },
2774
2775     /**
2776      * Returns the first matching key corresponding to the given value.
2777      * If no matching value is found, null is returned.
2778
2779     var person = {
2780         name: 'Jacky',
2781         loves: 'food'
2782     };
2783
2784     alert(Ext.Object.getKey(sencha, 'loves')); // alerts 'food'
2785
2786      * @param {Object} object
2787      * @param {Object} value The value to find
2788      * @markdown
2789      */
2790     getKey: function(object, value) {
2791         for (var property in object) {
2792             if (object.hasOwnProperty(property) && object[property] === value) {
2793                 return property;
2794             }
2795         }
2796
2797         return null;
2798     },
2799
2800     /**
2801      * Gets all values of the given object as an array.
2802
2803     var values = Ext.Object.getValues({
2804         name: 'Jacky',
2805         loves: 'food'
2806     }); // ['Jacky', 'food']
2807
2808      * @param {Object} object
2809      * @return {Array} An array of values from the object
2810      * @markdown
2811      */
2812     getValues: function(object) {
2813         var values = [],
2814             property;
2815
2816         for (property in object) {
2817             if (object.hasOwnProperty(property)) {
2818                 values.push(object[property]);
2819             }
2820         }
2821
2822         return values;
2823     },
2824
2825     /**
2826      * Gets all keys of the given object as an array.
2827
2828     var values = Ext.Object.getKeys({
2829         name: 'Jacky',
2830         loves: 'food'
2831     }); // ['name', 'loves']
2832
2833      * @param {Object} object
2834      * @return {Array} An array of keys from the object
2835      * @method
2836      */
2837     getKeys: ('keys' in Object.prototype) ? Object.keys : function(object) {
2838         var keys = [],
2839             property;
2840
2841         for (property in object) {
2842             if (object.hasOwnProperty(property)) {
2843                 keys.push(property);
2844             }
2845         }
2846
2847         return keys;
2848     },
2849
2850     /**
2851      * Gets the total number of this object's own properties
2852
2853     var size = Ext.Object.getSize({
2854         name: 'Jacky',
2855         loves: 'food'
2856     }); // size equals 2
2857
2858      * @param {Object} object
2859      * @return {Number} size
2860      * @markdown
2861      */
2862     getSize: function(object) {
2863         var size = 0,
2864             property;
2865
2866         for (property in object) {
2867             if (object.hasOwnProperty(property)) {
2868                 size++;
2869             }
2870         }
2871
2872         return size;
2873     }
2874 };
2875
2876
2877 /**
2878  * A convenient alias method for {@link Ext.Object#merge}
2879  *
2880  * @member Ext
2881  * @method merge
2882  */
2883 Ext.merge = Ext.Object.merge;
2884
2885 /**
2886  * A convenient alias method for {@link Ext.Object#toQueryString}
2887  *
2888  * @member Ext
2889  * @method urlEncode
2890  * @deprecated 4.0.0 Use {@link Ext.Object#toQueryString Ext.Object.toQueryString} instead
2891  */
2892 Ext.urlEncode = function() {
2893     var args = Ext.Array.from(arguments),
2894         prefix = '';
2895
2896     // Support for the old `pre` argument
2897     if ((typeof args[1] === 'string')) {
2898         prefix = args[1] + '&';
2899         args[1] = false;
2900     }
2901
2902     return prefix + Ext.Object.toQueryString.apply(Ext.Object, args);
2903 };
2904
2905 /**
2906  * A convenient alias method for {@link Ext.Object#fromQueryString}
2907  *
2908  * @member Ext
2909  * @method urlDecode
2910  * @deprecated 4.0.0 Use {@link Ext.Object#fromQueryString Ext.Object.fromQueryString} instead
2911  */
2912 Ext.urlDecode = function() {
2913     return Ext.Object.fromQueryString.apply(Ext.Object, arguments);
2914 };
2915
2916 })();
2917
2918 /**
2919  * @class Ext.Date
2920  * A set of useful static methods to deal with date
2921  * Note that if Ext.Date is required and loaded, it will copy all methods / properties to
2922  * this object for convenience
2923  *
2924  * The date parsing and formatting syntax contains a subset of
2925  * <a href="http://www.php.net/date">PHP's date() function</a>, and the formats that are
2926  * supported will provide results equivalent to their PHP versions.
2927  *
2928  * The following is a list of all currently supported formats:
2929  * <pre class="">
2930 Format  Description                                                               Example returned values
2931 ------  -----------------------------------------------------------------------   -----------------------
2932   d     Day of the month, 2 digits with leading zeros                             01 to 31
2933   D     A short textual representation of the day of the week                     Mon to Sun
2934   j     Day of the month without leading zeros                                    1 to 31
2935   l     A full textual representation of the day of the week                      Sunday to Saturday
2936   N     ISO-8601 numeric representation of the day of the week                    1 (for Monday) through 7 (for Sunday)
2937   S     English ordinal suffix for the day of the month, 2 characters             st, nd, rd or th. Works well with j
2938   w     Numeric representation of the day of the week                             0 (for Sunday) to 6 (for Saturday)
2939   z     The day of the year (starting from 0)                                     0 to 364 (365 in leap years)
2940   W     ISO-8601 week number of year, weeks starting on Monday                    01 to 53
2941   F     A full textual representation of a month, such as January or March        January to December
2942   m     Numeric representation of a month, with leading zeros                     01 to 12
2943   M     A short textual representation of a month                                 Jan to Dec
2944   n     Numeric representation of a month, without leading zeros                  1 to 12
2945   t     Number of days in the given month                                         28 to 31
2946   L     Whether it&#39;s a leap year                                                  1 if it is a leap year, 0 otherwise.
2947   o     ISO-8601 year number (identical to (Y), but if the ISO week number (W)    Examples: 1998 or 2004
2948         belongs to the previous or next year, that year is used instead)
2949   Y     A full numeric representation of a year, 4 digits                         Examples: 1999 or 2003
2950   y     A two digit representation of a year                                      Examples: 99 or 03
2951   a     Lowercase Ante meridiem and Post meridiem                                 am or pm
2952   A     Uppercase Ante meridiem and Post meridiem                                 AM or PM
2953   g     12-hour format of an hour without leading zeros                           1 to 12
2954   G     24-hour format of an hour without leading zeros                           0 to 23
2955   h     12-hour format of an hour with leading zeros                              01 to 12
2956   H     24-hour format of an hour with leading zeros                              00 to 23
2957   i     Minutes, with leading zeros                                               00 to 59
2958   s     Seconds, with leading zeros                                               00 to 59
2959   u     Decimal fraction of a second                                              Examples:
2960         (minimum 1 digit, arbitrary number of digits allowed)                     001 (i.e. 0.001s) or
2961                                                                                   100 (i.e. 0.100s) or
2962                                                                                   999 (i.e. 0.999s) or
2963                                                                                   999876543210 (i.e. 0.999876543210s)
2964   O     Difference to Greenwich time (GMT) in hours and minutes                   Example: +1030
2965   P     Difference to Greenwich time (GMT) with colon between hours and minutes   Example: -08:00
2966   T     Timezone abbreviation of the machine running the code                     Examples: EST, MDT, PDT ...
2967   Z     Timezone offset in seconds (negative if west of UTC, positive if east)    -43200 to 50400
2968   c     ISO 8601 date
2969         Notes:                                                                    Examples:
2970         1) If unspecified, the month / day defaults to the current month / day,   1991 or
2971            the time defaults to midnight, while the timezone defaults to the      1992-10 or
2972            browser's timezone. If a time is specified, it must include both hours 1993-09-20 or
2973            and minutes. The "T" delimiter, seconds, milliseconds and timezone     1994-08-19T16:20+01:00 or
2974            are optional.                                                          1995-07-18T17:21:28-02:00 or
2975         2) The decimal fraction of a second, if specified, must contain at        1996-06-17T18:22:29.98765+03:00 or
2976            least 1 digit (there is no limit to the maximum number                 1997-05-16T19:23:30,12345-0400 or
2977            of digits allowed), and may be delimited by either a '.' or a ','      1998-04-15T20:24:31.2468Z or
2978         Refer to the examples on the right for the various levels of              1999-03-14T20:24:32Z or
2979         date-time granularity which are supported, or see                         2000-02-13T21:25:33
2980         http://www.w3.org/TR/NOTE-datetime for more info.                         2001-01-12 22:26:34
2981   U     Seconds since the Unix Epoch (January 1 1970 00:00:00 GMT)                1193432466 or -2138434463
2982   MS    Microsoft AJAX serialized dates                                           \/Date(1238606590509)\/ (i.e. UTC milliseconds since epoch) or
2983                                                                                   \/Date(1238606590509+0800)\/
2984 </pre>
2985  *
2986  * Example usage (note that you must escape format specifiers with '\\' to render them as character literals):
2987  * <pre><code>
2988 // Sample date:
2989 // 'Wed Jan 10 2007 15:05:01 GMT-0600 (Central Standard Time)'
2990
2991 var dt = new Date('1/10/2007 03:05:01 PM GMT-0600');
2992 console.log(Ext.Date.format(dt, 'Y-m-d'));                          // 2007-01-10
2993 console.log(Ext.Date.format(dt, 'F j, Y, g:i a'));                  // January 10, 2007, 3:05 pm
2994 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
2995 </code></pre>
2996  *
2997  * Here are some standard date/time patterns that you might find helpful.  They
2998  * are not part of the source of Ext.Date, but to use them you can simply copy this
2999  * block of code into any script that is included after Ext.Date and they will also become
3000  * globally available on the Date object.  Feel free to add or remove patterns as needed in your code.
3001  * <pre><code>
3002 Ext.Date.patterns = {
3003     ISO8601Long:"Y-m-d H:i:s",
3004     ISO8601Short:"Y-m-d",
3005     ShortDate: "n/j/Y",
3006     LongDate: "l, F d, Y",
3007     FullDateTime: "l, F d, Y g:i:s A",
3008     MonthDay: "F d",
3009     ShortTime: "g:i A",
3010     LongTime: "g:i:s A",
3011     SortableDateTime: "Y-m-d\\TH:i:s",
3012     UniversalSortableDateTime: "Y-m-d H:i:sO",
3013     YearMonth: "F, Y"
3014 };
3015 </code></pre>
3016  *
3017  * Example usage:
3018  * <pre><code>
3019 var dt = new Date();
3020 console.log(Ext.Date.format(dt, Ext.Date.patterns.ShortDate));
3021 </code></pre>
3022  * <p>Developer-written, custom formats may be used by supplying both a formatting and a parsing function
3023  * which perform to specialized requirements. The functions are stored in {@link #parseFunctions} and {@link #formatFunctions}.</p>
3024  * @singleton
3025  */
3026
3027 /*
3028  * Most of the date-formatting functions below are the excellent work of Baron Schwartz.
3029  * (see http://www.xaprb.com/blog/2005/12/12/javascript-closures-for-runtime-efficiency/)
3030  * They generate precompiled functions from format patterns instead of parsing and
3031  * processing each pattern every time a date is formatted. These functions are available
3032  * on every Date object.
3033  */
3034
3035 (function() {
3036
3037 // create private copy of Ext's Ext.util.Format.format() method
3038 // - to remove unnecessary dependency
3039 // - to resolve namespace conflict with MS-Ajax's implementation
3040 function xf(format) {
3041     var args = Array.prototype.slice.call(arguments, 1);
3042     return format.replace(/\{(\d+)\}/g, function(m, i) {
3043         return args[i];
3044     });
3045 }
3046
3047 Ext.Date = {
3048     /**
3049      * Returns the current timestamp
3050      * @return {Date} The current timestamp
3051      * @method
3052      */
3053     now: Date.now || function() {
3054         return +new Date();
3055     },
3056
3057     /**
3058      * @private
3059      * Private for now
3060      */
3061     toString: function(date) {
3062         var pad = Ext.String.leftPad;
3063
3064         return date.getFullYear() + "-"
3065             + pad(date.getMonth() + 1, 2, '0') + "-"
3066             + pad(date.getDate(), 2, '0') + "T"
3067             + pad(date.getHours(), 2, '0') + ":"
3068             + pad(date.getMinutes(), 2, '0') + ":"
3069             + pad(date.getSeconds(), 2, '0');
3070     },
3071
3072     /**
3073      * Returns the number of milliseconds between two dates
3074      * @param {Date} dateA The first date
3075      * @param {Date} dateB (optional) The second date, defaults to now
3076      * @return {Number} The difference in milliseconds
3077      */
3078     getElapsed: function(dateA, dateB) {
3079         return Math.abs(dateA - (dateB || new Date()));
3080     },
3081
3082     /**
3083      * Global flag which determines if strict date parsing should be used.
3084      * Strict date parsing will not roll-over invalid dates, which is the
3085      * default behaviour of javascript Date objects.
3086      * (see {@link #parse} for more information)
3087      * Defaults to <tt>false</tt>.
3088      * @static
3089      * @type Boolean
3090     */
3091     useStrict: false,
3092
3093     // private
3094     formatCodeToRegex: function(character, currentGroup) {
3095         // Note: currentGroup - position in regex result array (see notes for Ext.Date.parseCodes below)
3096         var p = utilDate.parseCodes[character];
3097
3098         if (p) {
3099           p = typeof p == 'function'? p() : p;
3100           utilDate.parseCodes[character] = p; // reassign function result to prevent repeated execution
3101         }
3102
3103         return p ? Ext.applyIf({
3104           c: p.c ? xf(p.c, currentGroup || "{0}") : p.c
3105         }, p) : {
3106             g: 0,
3107             c: null,
3108             s: Ext.String.escapeRegex(character) // treat unrecognised characters as literals
3109         };
3110     },
3111
3112     /**
3113      * <p>An object hash in which each property is a date parsing function. The property name is the
3114      * format string which that function parses.</p>
3115      * <p>This object is automatically populated with date parsing functions as
3116      * date formats are requested for Ext standard formatting strings.</p>
3117      * <p>Custom parsing functions may be inserted into this object, keyed by a name which from then on
3118      * may be used as a format string to {@link #parse}.<p>
3119      * <p>Example:</p><pre><code>
3120 Ext.Date.parseFunctions['x-date-format'] = myDateParser;
3121 </code></pre>
3122      * <p>A parsing function should return a Date object, and is passed the following parameters:<div class="mdetail-params"><ul>
3123      * <li><code>date</code> : String<div class="sub-desc">The date string to parse.</div></li>
3124      * <li><code>strict</code> : Boolean<div class="sub-desc">True to validate date strings while parsing
3125      * (i.e. prevent javascript Date "rollover") (The default must be false).
3126      * Invalid date strings should return null when parsed.</div></li>
3127      * </ul></div></p>
3128      * <p>To enable Dates to also be <i>formatted</i> according to that format, a corresponding
3129      * formatting function must be placed into the {@link #formatFunctions} property.
3130      * @property parseFunctions
3131      * @static
3132      * @type Object
3133      */
3134     parseFunctions: {
3135         "MS": function(input, strict) {
3136             // note: the timezone offset is ignored since the MS Ajax server sends
3137             // a UTC milliseconds-since-Unix-epoch value (negative values are allowed)
3138             var re = new RegExp('\\/Date\\(([-+])?(\\d+)(?:[+-]\\d{4})?\\)\\/');
3139             var r = (input || '').match(re);
3140             return r? new Date(((r[1] || '') + r[2]) * 1) : null;
3141         }
3142     },
3143     parseRegexes: [],
3144
3145     /**
3146      * <p>An object hash in which each property is a date formatting function. The property name is the
3147      * format string which corresponds to the produced formatted date string.</p>
3148      * <p>This object is automatically populated with date formatting functions as
3149      * date formats are requested for Ext standard formatting strings.</p>
3150      * <p>Custom formatting functions may be inserted into this object, keyed by a name which from then on
3151      * may be used as a format string to {@link #format}. Example:</p><pre><code>
3152 Ext.Date.formatFunctions['x-date-format'] = myDateFormatter;
3153 </code></pre>
3154      * <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>
3155      * <li><code>date</code> : Date<div class="sub-desc">The Date to format.</div></li>
3156      * </ul></div></p>
3157      * <p>To enable date strings to also be <i>parsed</i> according to that format, a corresponding
3158      * parsing function must be placed into the {@link #parseFunctions} property.
3159      * @property formatFunctions
3160      * @static
3161      * @type Object
3162      */
3163     formatFunctions: {
3164         "MS": function() {
3165             // UTC milliseconds since Unix epoch (MS-AJAX serialized date format (MRSF))
3166             return '\\/Date(' + this.getTime() + ')\\/';
3167         }
3168     },
3169
3170     y2kYear : 50,
3171
3172     /**
3173      * Date interval constant
3174      * @static
3175      * @type String
3176      */
3177     MILLI : "ms",
3178
3179     /**
3180      * Date interval constant
3181      * @static
3182      * @type String
3183      */
3184     SECOND : "s",
3185
3186     /**
3187      * Date interval constant
3188      * @static
3189      * @type String
3190      */
3191     MINUTE : "mi",
3192
3193     /** Date interval constant
3194      * @static
3195      * @type String
3196      */
3197     HOUR : "h",
3198
3199     /**
3200      * Date interval constant
3201      * @static
3202      * @type String
3203      */
3204     DAY : "d",
3205
3206     /**
3207      * Date interval constant
3208      * @static
3209      * @type String
3210      */
3211     MONTH : "mo",
3212
3213     /**
3214      * Date interval constant
3215      * @static
3216      * @type String
3217      */
3218     YEAR : "y",
3219
3220     /**
3221      * <p>An object hash containing default date values used during date parsing.</p>
3222      * <p>The following properties are available:<div class="mdetail-params"><ul>
3223      * <li><code>y</code> : Number<div class="sub-desc">The default year value. (defaults to undefined)</div></li>
3224      * <li><code>m</code> : Number<div class="sub-desc">The default 1-based month value. (defaults to undefined)</div></li>
3225      * <li><code>d</code> : Number<div class="sub-desc">The default day value. (defaults to undefined)</div></li>
3226      * <li><code>h</code> : Number<div class="sub-desc">The default hour value. (defaults to undefined)</div></li>
3227      * <li><code>i</code> : Number<div class="sub-desc">The default minute value. (defaults to undefined)</div></li>
3228      * <li><code>s</code> : Number<div class="sub-desc">The default second value. (defaults to undefined)</div></li>
3229      * <li><code>ms</code> : Number<div class="sub-desc">The default millisecond value. (defaults to undefined)</div></li>
3230      * </ul></div></p>
3231      * <p>Override these properties to customize the default date values used by the {@link #parse} method.</p>
3232      * <p><b>Note: In countries which experience Daylight Saving Time (i.e. DST), the <tt>h</tt>, <tt>i</tt>, <tt>s</tt>
3233      * and <tt>ms</tt> properties may coincide with the exact time in which DST takes effect.
3234      * It is the responsiblity of the developer to account for this.</b></p>
3235      * Example Usage:
3236      * <pre><code>
3237 // set default day value to the first day of the month
3238 Ext.Date.defaults.d = 1;
3239
3240 // parse a February date string containing only year and month values.
3241 // setting the default day value to 1 prevents weird date rollover issues
3242 // when attempting to parse the following date string on, for example, March 31st 2009.
3243 Ext.Date.parse('2009-02', 'Y-m'); // returns a Date object representing February 1st 2009
3244 </code></pre>
3245      * @property defaults
3246      * @static
3247      * @type Object
3248      */
3249     defaults: {},
3250
3251     /**
3252      * An array of textual day names.
3253      * Override these values for international dates.
3254      * Example:
3255      * <pre><code>
3256 Ext.Date.dayNames = [
3257     'SundayInYourLang',
3258     'MondayInYourLang',
3259     ...
3260 ];
3261 </code></pre>
3262      * @type Array
3263      * @static
3264      */
3265     dayNames : [
3266         "Sunday",
3267         "Monday",
3268         "Tuesday",
3269         "Wednesday",
3270         "Thursday",
3271         "Friday",
3272         "Saturday"
3273     ],
3274
3275     /**
3276      * An array of textual month names.
3277      * Override these values for international dates.
3278      * Example:
3279      * <pre><code>
3280 Ext.Date.monthNames = [
3281     'JanInYourLang',
3282     'FebInYourLang',
3283     ...
3284 ];
3285 </code></pre>
3286      * @type Array
3287      * @static
3288      */
3289     monthNames : [
3290         "January",
3291         "February",
3292         "March",
3293         "April",
3294         "May",
3295         "June",
3296         "July",
3297         "August",
3298         "September",
3299         "October",
3300         "November",
3301         "December"
3302     ],
3303
3304     /**
3305      * An object hash of zero-based javascript month numbers (with short month names as keys. note: keys are case-sensitive).
3306      * Override these values for international dates.
3307      * Example:
3308      * <pre><code>
3309 Ext.Date.monthNumbers = {
3310     'ShortJanNameInYourLang':0,
3311     'ShortFebNameInYourLang':1,
3312     ...
3313 };
3314 </code></pre>
3315      * @type Object
3316      * @static
3317      */
3318     monthNumbers : {
3319         Jan:0,
3320         Feb:1,
3321         Mar:2,
3322         Apr:3,
3323         May:4,
3324         Jun:5,
3325         Jul:6,
3326         Aug:7,
3327         Sep:8,
3328         Oct:9,
3329         Nov:10,
3330         Dec:11
3331     },
3332     /**
3333      * <p>The date format string that the {@link #dateRenderer} and {@link #date} functions use.
3334      * see {@link #Date} for details.</p>
3335      * <p>This defaults to <code>m/d/Y</code>, but may be overridden in a locale file.</p>
3336      * @property defaultFormat
3337      * @static
3338      * @type String
3339      */
3340     defaultFormat : "m/d/Y",
3341     /**
3342      * Get the short month name for the given month number.
3343      * Override this function for international dates.
3344      * @param {Number} month A zero-based javascript month number.
3345      * @return {String} The short month name.
3346      * @static
3347      */
3348     getShortMonthName : function(month) {
3349         return utilDate.monthNames[month].substring(0, 3);
3350     },
3351
3352     /**
3353      * Get the short day name for the given day number.
3354      * Override this function for international dates.
3355      * @param {Number} day A zero-based javascript day number.
3356      * @return {String} The short day name.
3357      * @static
3358      */
3359     getShortDayName : function(day) {
3360         return utilDate.dayNames[day].substring(0, 3);
3361     },
3362
3363     /**
3364      * Get the zero-based javascript month number for the given short/full month name.
3365      * Override this function for international dates.
3366      * @param {String} name The short/full month name.
3367      * @return {Number} The zero-based javascript month number.
3368      * @static
3369      */
3370     getMonthNumber : function(name) {
3371         // handle camel casing for english month names (since the keys for the Ext.Date.monthNumbers hash are case sensitive)
3372         return utilDate.monthNumbers[name.substring(0, 1).toUpperCase() + name.substring(1, 3).toLowerCase()];
3373     },
3374
3375     /**
3376      * Checks if the specified format contains hour information
3377      * @param {String} format The format to check
3378      * @return {Boolean} True if the format contains hour information
3379      * @static
3380      * @method
3381      */
3382     formatContainsHourInfo : (function(){
3383         var stripEscapeRe = /(\\.)/g,
3384             hourInfoRe = /([gGhHisucUOPZ]|MS)/;
3385         return function(format){
3386             return hourInfoRe.test(format.replace(stripEscapeRe, ''));
3387         };
3388     })(),
3389
3390     /**
3391      * Checks if the specified format contains information about
3392      * anything other than the time.
3393      * @param {String} format The format to check
3394      * @return {Boolean} True if the format contains information about
3395      * date/day information.
3396      * @static
3397      * @method
3398      */
3399     formatContainsDateInfo : (function(){
3400         var stripEscapeRe = /(\\.)/g,
3401             dateInfoRe = /([djzmnYycU]|MS)/;
3402
3403         return function(format){
3404             return dateInfoRe.test(format.replace(stripEscapeRe, ''));
3405         };
3406     })(),
3407
3408     /**
3409      * The base format-code to formatting-function hashmap used by the {@link #format} method.
3410      * Formatting functions are strings (or functions which return strings) which
3411      * will return the appropriate value when evaluated in the context of the Date object
3412      * from which the {@link #format} method is called.
3413      * Add to / override these mappings for custom date formatting.
3414      * Note: Ext.Date.format() treats characters as literals if an appropriate mapping cannot be found.
3415      * Example:
3416      * <pre><code>
3417 Ext.Date.formatCodes.x = "Ext.util.Format.leftPad(this.getDate(), 2, '0')";
3418 console.log(Ext.Date.format(new Date(), 'X'); // returns the current day of the month
3419 </code></pre>
3420      * @type Object
3421      * @static
3422      */
3423     formatCodes : {
3424         d: "Ext.String.leftPad(this.getDate(), 2, '0')",
3425         D: "Ext.Date.getShortDayName(this.getDay())", // get localised short day name
3426         j: "this.getDate()",
3427         l: "Ext.Date.dayNames[this.getDay()]",
3428         N: "(this.getDay() ? this.getDay() : 7)",
3429         S: "Ext.Date.getSuffix(this)",
3430         w: "this.getDay()",
3431         z: "Ext.Date.getDayOfYear(this)",
3432         W: "Ext.String.leftPad(Ext.Date.getWeekOfYear(this), 2, '0')",
3433         F: "Ext.Date.monthNames[this.getMonth()]",
3434         m: "Ext.String.leftPad(this.getMonth() + 1, 2, '0')",
3435         M: "Ext.Date.getShortMonthName(this.getMonth())", // get localised short month name
3436         n: "(this.getMonth() + 1)",
3437         t: "Ext.Date.getDaysInMonth(this)",
3438         L: "(Ext.Date.isLeapYear(this) ? 1 : 0)",
3439         o: "(this.getFullYear() + (Ext.Date.getWeekOfYear(this) == 1 && this.getMonth() > 0 ? +1 : (Ext.Date.getWeekOfYear(this) >= 52 && this.getMonth() < 11 ? -1 : 0)))",
3440         Y: "Ext.String.leftPad(this.getFullYear(), 4, '0')",
3441         y: "('' + this.getFullYear()).substring(2, 4)",
3442         a: "(this.getHours() < 12 ? 'am' : 'pm')",
3443         A: "(this.getHours() < 12 ? 'AM' : 'PM')",
3444         g: "((this.getHours() % 12) ? this.getHours() % 12 : 12)",
3445         G: "this.getHours()",
3446         h: "Ext.String.leftPad((this.getHours() % 12) ? this.getHours() % 12 : 12, 2, '0')",
3447         H: "Ext.String.leftPad(this.getHours(), 2, '0')",
3448         i: "Ext.String.leftPad(this.getMinutes(), 2, '0')",
3449         s: "Ext.String.leftPad(this.getSeconds(), 2, '0')",
3450         u: "Ext.String.leftPad(this.getMilliseconds(), 3, '0')",
3451         O: "Ext.Date.getGMTOffset(this)",
3452         P: "Ext.Date.getGMTOffset(this, true)",
3453         T: "Ext.Date.getTimezone(this)",
3454         Z: "(this.getTimezoneOffset() * -60)",
3455
3456         c: function() { // ISO-8601 -- GMT format
3457             for (var c = "Y-m-dTH:i:sP", code = [], i = 0, l = c.length; i < l; ++i) {
3458                 var e = c.charAt(i);
3459                 code.push(e == "T" ? "'T'" : utilDate.getFormatCode(e)); // treat T as a character literal
3460             }
3461             return code.join(" + ");
3462         },
3463         /*
3464         c: function() { // ISO-8601 -- UTC format
3465             return [
3466               "this.getUTCFullYear()", "'-'",
3467               "Ext.util.Format.leftPad(this.getUTCMonth() + 1, 2, '0')", "'-'",
3468               "Ext.util.Format.leftPad(this.getUTCDate(), 2, '0')",
3469               "'T'",
3470               "Ext.util.Format.leftPad(this.getUTCHours(), 2, '0')", "':'",
3471               "Ext.util.Format.leftPad(this.getUTCMinutes(), 2, '0')", "':'",
3472               "Ext.util.Format.leftPad(this.getUTCSeconds(), 2, '0')",
3473               "'Z'"
3474             ].join(" + ");
3475         },
3476         */
3477
3478         U: "Math.round(this.getTime() / 1000)"
3479     },
3480
3481     /**
3482      * Checks if the passed Date parameters will cause a javascript Date "rollover".
3483      * @param {Number} year 4-digit year
3484      * @param {Number} month 1-based month-of-year
3485      * @param {Number} day Day of month
3486      * @param {Number} hour (optional) Hour
3487      * @param {Number} minute (optional) Minute
3488      * @param {Number} second (optional) Second
3489      * @param {Number} millisecond (optional) Millisecond
3490      * @return {Boolean} true if the passed parameters do not cause a Date "rollover", false otherwise.
3491      * @static
3492      */
3493     isValid : function(y, m, d, h, i, s, ms) {
3494         // setup defaults
3495         h = h || 0;
3496         i = i || 0;
3497         s = s || 0;
3498         ms = ms || 0;
3499
3500         // Special handling for year < 100
3501         var dt = utilDate.add(new Date(y < 100 ? 100 : y, m - 1, d, h, i, s, ms), utilDate.YEAR, y < 100 ? y - 100 : 0);
3502
3503         return y == dt.getFullYear() &&
3504             m == dt.getMonth() + 1 &&
3505             d == dt.getDate() &&
3506             h == dt.getHours() &&
3507             i == dt.getMinutes() &&
3508             s == dt.getSeconds() &&
3509             ms == dt.getMilliseconds();
3510     },
3511
3512     /**
3513      * Parses the passed string using the specified date format.
3514      * Note that this function expects normal calendar dates, meaning that months are 1-based (i.e. 1 = January).
3515      * The {@link #defaults} hash will be used for any date value (i.e. year, month, day, hour, minute, second or millisecond)
3516      * which cannot be found in the passed string. If a corresponding default date value has not been specified in the {@link #defaults} hash,
3517      * the current date's year, month, day or DST-adjusted zero-hour time value will be used instead.
3518      * Keep in mind that the input date string must precisely match the specified format string
3519      * in order for the parse operation to be successful (failed parse operations return a null value).
3520      * <p>Example:</p><pre><code>
3521 //dt = Fri May 25 2007 (current date)
3522 var dt = new Date();
3523
3524 //dt = Thu May 25 2006 (today&#39;s month/day in 2006)
3525 dt = Ext.Date.parse("2006", "Y");
3526
3527 //dt = Sun Jan 15 2006 (all date parts specified)
3528 dt = Ext.Date.parse("2006-01-15", "Y-m-d");
3529
3530 //dt = Sun Jan 15 2006 15:20:01
3531 dt = Ext.Date.parse("2006-01-15 3:20:01 PM", "Y-m-d g:i:s A");
3532
3533 // attempt to parse Sun Feb 29 2006 03:20:01 in strict mode
3534 dt = Ext.Date.parse("2006-02-29 03:20:01", "Y-m-d H:i:s", true); // returns null
3535 </code></pre>
3536      * @param {String} input The raw date string.
3537      * @param {String} format The expected date string format.
3538      * @param {Boolean} strict (optional) True to validate date strings while parsing (i.e. prevents javascript Date "rollover")
3539                         (defaults to false). Invalid date strings will return null when parsed.
3540      * @return {Date} The parsed Date.
3541      * @static
3542      */
3543     parse : function(input, format, strict) {
3544         var p = utilDate.parseFunctions;
3545         if (p[format] == null) {
3546             utilDate.createParser(format);
3547         }
3548         return p[format](input, Ext.isDefined(strict) ? strict : utilDate.useStrict);
3549     },
3550
3551     // Backwards compat
3552     parseDate: function(input, format, strict){
3553         return utilDate.parse(input, format, strict);
3554     },
3555
3556
3557     // private
3558     getFormatCode : function(character) {
3559         var f = utilDate.formatCodes[character];
3560
3561         if (f) {
3562           f = typeof f == 'function'? f() : f;
3563           utilDate.formatCodes[character] = f; // reassign function result to prevent repeated execution
3564         }
3565
3566         // note: unknown characters are treated as literals
3567         return f || ("'" + Ext.String.escape(character) + "'");
3568     },
3569
3570     // private
3571     createFormat : function(format) {
3572         var code = [],
3573             special = false,
3574             ch = '';
3575
3576         for (var i = 0; i < format.length; ++i) {
3577             ch = format.charAt(i);
3578             if (!special && ch == "\\") {
3579                 special = true;
3580             } else if (special) {
3581                 special = false;
3582                 code.push("'" + Ext.String.escape(ch) + "'");
3583             } else {
3584                 code.push(utilDate.getFormatCode(ch));
3585             }
3586         }
3587         utilDate.formatFunctions[format] = Ext.functionFactory("return " + code.join('+'));
3588     },
3589
3590     // private
3591     createParser : (function() {
3592         var code = [
3593             "var dt, y, m, d, h, i, s, ms, o, z, zz, u, v,",
3594                 "def = Ext.Date.defaults,",
3595                 "results = String(input).match(Ext.Date.parseRegexes[{0}]);", // either null, or an array of matched strings
3596
3597             "if(results){",
3598                 "{1}",
3599
3600                 "if(u != null){", // i.e. unix time is defined
3601                     "v = new Date(u * 1000);", // give top priority to UNIX time
3602                 "}else{",
3603                     // create Date object representing midnight of the current day;
3604                     // this will provide us with our date defaults
3605                     // (note: clearTime() handles Daylight Saving Time automatically)
3606                     "dt = Ext.Date.clearTime(new Date);",
3607
3608                     // date calculations (note: these calculations create a dependency on Ext.Number.from())
3609                     "y = Ext.Number.from(y, Ext.Number.from(def.y, dt.getFullYear()));",
3610                     "m = Ext.Number.from(m, Ext.Number.from(def.m - 1, dt.getMonth()));",
3611                     "d = Ext.Number.from(d, Ext.Number.from(def.d, dt.getDate()));",
3612
3613                     // time calculations (note: these calculations create a dependency on Ext.Number.from())
3614                     "h  = Ext.Number.from(h, Ext.Number.from(def.h, dt.getHours()));",
3615                     "i  = Ext.Number.from(i, Ext.Number.from(def.i, dt.getMinutes()));",
3616                     "s  = Ext.Number.from(s, Ext.Number.from(def.s, dt.getSeconds()));",
3617                     "ms = Ext.Number.from(ms, Ext.Number.from(def.ms, dt.getMilliseconds()));",
3618
3619                     "if(z >= 0 && y >= 0){",
3620                         // both the year and zero-based day of year are defined and >= 0.
3621                         // these 2 values alone provide sufficient info to create a full date object
3622
3623                         // create Date object representing January 1st for the given year
3624                         // handle years < 100 appropriately
3625                         "v = Ext.Date.add(new Date(y < 100 ? 100 : y, 0, 1, h, i, s, ms), Ext.Date.YEAR, y < 100 ? y - 100 : 0);",
3626
3627                         // then add day of year, checking for Date "rollover" if necessary
3628                         "v = !strict? v : (strict === true && (z <= 364 || (Ext.Date.isLeapYear(v) && z <= 365))? Ext.Date.add(v, Ext.Date.DAY, z) : null);",
3629                     "}else if(strict === true && !Ext.Date.isValid(y, m + 1, d, h, i, s, ms)){", // check for Date "rollover"
3630                         "v = null;", // invalid date, so return null
3631                     "}else{",
3632                         // plain old Date object
3633                         // handle years < 100 properly
3634                         "v = Ext.Date.add(new Date(y < 100 ? 100 : y, m, d, h, i, s, ms), Ext.Date.YEAR, y < 100 ? y - 100 : 0);",
3635                     "}",
3636                 "}",
3637             "}",
3638
3639             "if(v){",
3640                 // favour UTC offset over GMT offset
3641                 "if(zz != null){",
3642                     // reset to UTC, then add offset
3643                     "v = Ext.Date.add(v, Ext.Date.SECOND, -v.getTimezoneOffset() * 60 - zz);",
3644                 "}else if(o){",
3645                     // reset to GMT, then add offset
3646                     "v = Ext.Date.add(v, Ext.Date.MINUTE, -v.getTimezoneOffset() + (sn == '+'? -1 : 1) * (hr * 60 + mn));",
3647                 "}",
3648             "}",
3649
3650             "return v;"
3651         ].join('\n');
3652
3653         return function(format) {
3654             var regexNum = utilDate.parseRegexes.length,
3655                 currentGroup = 1,
3656                 calc = [],
3657                 regex = [],
3658                 special = false,
3659                 ch = "";
3660
3661             for (var i = 0; i < format.length; ++i) {
3662                 ch = format.charAt(i);
3663                 if (!special && ch == "\\") {
3664                     special = true;
3665                 } else if (special) {
3666                     special = false;
3667                     regex.push(Ext.String.escape(ch));
3668                 } else {
3669                     var obj = utilDate.formatCodeToRegex(ch, currentGroup);
3670                     currentGroup += obj.g;
3671                     regex.push(obj.s);
3672                     if (obj.g && obj.c) {
3673                         calc.push(obj.c);
3674                     }
3675                 }
3676             }
3677
3678             utilDate.parseRegexes[regexNum] = new RegExp("^" + regex.join('') + "$", 'i');
3679             utilDate.parseFunctions[format] = Ext.functionFactory("input", "strict", xf(code, regexNum, calc.join('')));
3680         };
3681     })(),
3682
3683     // private
3684     parseCodes : {
3685         /*
3686          * Notes:
3687          * g = {Number} calculation group (0 or 1. only group 1 contributes to date calculations.)
3688          * c = {String} calculation method (required for group 1. null for group 0. {0} = currentGroup - position in regex result array)
3689          * s = {String} regex pattern. all matches are stored in results[], and are accessible by the calculation mapped to 'c'
3690          */
3691         d: {
3692             g:1,
3693             c:"d = parseInt(results[{0}], 10);\n",
3694             s:"(\\d{2})" // day of month with leading zeroes (01 - 31)
3695         },
3696         j: {
3697             g:1,
3698             c:"d = parseInt(results[{0}], 10);\n",
3699             s:"(\\d{1,2})" // day of month without leading zeroes (1 - 31)
3700         },
3701         D: function() {
3702             for (var a = [], i = 0; i < 7; a.push(utilDate.getShortDayName(i)), ++i); // get localised short day names
3703             return {
3704                 g:0,
3705                 c:null,
3706                 s:"(?:" + a.join("|") +")"
3707             };
3708         },
3709         l: function() {
3710             return {
3711                 g:0,
3712                 c:null,
3713                 s:"(?:" + utilDate.dayNames.join("|") + ")"
3714             };
3715         },
3716         N: {
3717             g:0,
3718             c:null,
3719             s:"[1-7]" // ISO-8601 day number (1 (monday) - 7 (sunday))
3720         },
3721         S: {
3722             g:0,
3723             c:null,
3724             s:"(?:st|nd|rd|th)"
3725         },
3726         w: {
3727             g:0,
3728             c:null,
3729             s:"[0-6]" // javascript day number (0 (sunday) - 6 (saturday))
3730         },
3731         z: {
3732             g:1,
3733             c:"z = parseInt(results[{0}], 10);\n",
3734             s:"(\\d{1,3})" // day of the year (0 - 364 (365 in leap years))
3735         },
3736         W: {
3737             g:0,
3738             c:null,
3739             s:"(?:\\d{2})" // ISO-8601 week number (with leading zero)
3740         },
3741         F: function() {
3742             return {
3743                 g:1,
3744                 c:"m = parseInt(Ext.Date.getMonthNumber(results[{0}]), 10);\n", // get localised month number
3745                 s:"(" + utilDate.monthNames.join("|") + ")"
3746             };
3747         },
3748         M: function() {
3749             for (var a = [], i = 0; i < 12; a.push(utilDate.getShortMonthName(i)), ++i); // get localised short month names
3750             return Ext.applyIf({
3751                 s:"(" + a.join("|") + ")"
3752             }, utilDate.formatCodeToRegex("F"));
3753         },
3754         m: {
3755             g:1,
3756             c:"m = parseInt(results[{0}], 10) - 1;\n",
3757             s:"(\\d{2})" // month number with leading zeros (01 - 12)
3758         },
3759         n: {
3760             g:1,
3761             c:"m = parseInt(results[{0}], 10) - 1;\n",
3762             s:"(\\d{1,2})" // month number without leading zeros (1 - 12)
3763         },
3764         t: {
3765             g:0,
3766             c:null,
3767             s:"(?:\\d{2})" // no. of days in the month (28 - 31)
3768         },
3769         L: {
3770             g:0,
3771             c:null,
3772             s:"(?:1|0)"
3773         },
3774         o: function() {
3775             return utilDate.formatCodeToRegex("Y");
3776         },
3777         Y: {
3778             g:1,
3779             c:"y = parseInt(results[{0}], 10);\n",
3780             s:"(\\d{4})" // 4-digit year
3781         },
3782         y: {
3783             g:1,
3784             c:"var ty = parseInt(results[{0}], 10);\n"
3785                 + "y = ty > Ext.Date.y2kYear ? 1900 + ty : 2000 + ty;\n", // 2-digit year
3786             s:"(\\d{1,2})"
3787         },
3788         /*
3789          * In the am/pm parsing routines, we allow both upper and lower case
3790          * even though it doesn't exactly match the spec. It gives much more flexibility
3791          * in being able to specify case insensitive regexes.
3792          */
3793         a: {
3794             g:1,
3795             c:"if (/(am)/i.test(results[{0}])) {\n"
3796                 + "if (!h || h == 12) { h = 0; }\n"
3797                 + "} else { if (!h || h < 12) { h = (h || 0) + 12; }}",
3798             s:"(am|pm|AM|PM)"
3799         },
3800         A: {
3801             g:1,
3802             c:"if (/(am)/i.test(results[{0}])) {\n"
3803                 + "if (!h || h == 12) { h = 0; }\n"
3804                 + "} else { if (!h || h < 12) { h = (h || 0) + 12; }}",
3805             s:"(AM|PM|am|pm)"
3806         },
3807         g: function() {
3808             return utilDate.formatCodeToRegex("G");
3809         },
3810         G: {
3811             g:1,
3812             c:"h = parseInt(results[{0}], 10);\n",
3813             s:"(\\d{1,2})" // 24-hr format of an hour without leading zeroes (0 - 23)
3814         },
3815         h: function() {
3816             return utilDate.formatCodeToRegex("H");
3817         },
3818         H: {
3819             g:1,
3820             c:"h = parseInt(results[{0}], 10);\n",
3821             s:"(\\d{2})" //  24-hr format of an hour with leading zeroes (00 - 23)
3822         },
3823         i: {
3824             g:1,
3825             c:"i = parseInt(results[{0}], 10);\n",
3826             s:"(\\d{2})" // minutes with leading zeros (00 - 59)
3827         },
3828         s: {
3829             g:1,
3830             c:"s = parseInt(results[{0}], 10);\n",
3831             s:"(\\d{2})" // seconds with leading zeros (00 - 59)
3832         },
3833         u: {
3834             g:1,
3835             c:"ms = results[{0}]; ms = parseInt(ms, 10)/Math.pow(10, ms.length - 3);\n",
3836             s:"(\\d+)" // decimal fraction of a second (minimum = 1 digit, maximum = unlimited)
3837         },
3838         O: {
3839             g:1,
3840             c:[
3841                 "o = results[{0}];",
3842                 "var sn = o.substring(0,1),", // get + / - sign
3843                     "hr = o.substring(1,3)*1 + Math.floor(o.substring(3,5) / 60),", // get hours (performs minutes-to-hour conversion also, just in case)
3844                     "mn = o.substring(3,5) % 60;", // get minutes
3845                 "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
3846             ].join("\n"),
3847             s: "([+\-]\\d{4})" // GMT offset in hrs and mins
3848         },
3849         P: {
3850             g:1,
3851             c:[
3852                 "o = results[{0}];",
3853                 "var sn = o.substring(0,1),", // get + / - sign
3854                     "hr = o.substring(1,3)*1 + Math.floor(o.substring(4,6) / 60),", // get hours (performs minutes-to-hour conversion also, just in case)
3855                     "mn = o.substring(4,6) % 60;", // get minutes
3856                 "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
3857             ].join("\n"),
3858             s: "([+\-]\\d{2}:\\d{2})" // GMT offset in hrs and mins (with colon separator)
3859         },
3860         T: {
3861             g:0,
3862             c:null,
3863             s:"[A-Z]{1,4}" // timezone abbrev. may be between 1 - 4 chars
3864         },
3865         Z: {
3866             g:1,
3867             c:"zz = results[{0}] * 1;\n" // -43200 <= UTC offset <= 50400
3868                   + "zz = (-43200 <= zz && zz <= 50400)? zz : null;\n",
3869             s:"([+\-]?\\d{1,5})" // leading '+' sign is optional for UTC offset
3870         },
3871         c: function() {
3872             var calc = [],
3873                 arr = [
3874                     utilDate.formatCodeToRegex("Y", 1), // year
3875                     utilDate.formatCodeToRegex("m", 2), // month
3876                     utilDate.formatCodeToRegex("d", 3), // day
3877                     utilDate.formatCodeToRegex("h", 4), // hour
3878                     utilDate.formatCodeToRegex("i", 5), // minute
3879                     utilDate.formatCodeToRegex("s", 6), // second
3880                     {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)
3881                     {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
3882                         "if(results[8]) {", // timezone specified
3883                             "if(results[8] == 'Z'){",
3884                                 "zz = 0;", // UTC
3885                             "}else if (results[8].indexOf(':') > -1){",
3886                                 utilDate.formatCodeToRegex("P", 8).c, // timezone offset with colon separator
3887                             "}else{",
3888                                 utilDate.formatCodeToRegex("O", 8).c, // timezone offset without colon separator
3889                             "}",
3890                         "}"
3891                     ].join('\n')}
3892                 ];
3893
3894             for (var i = 0, l = arr.length; i < l; ++i) {
3895                 calc.push(arr[i].c);
3896             }
3897
3898             return {
3899                 g:1,
3900                 c:calc.join(""),
3901                 s:[
3902                     arr[0].s, // year (required)
3903                     "(?:", "-", arr[1].s, // month (optional)
3904                         "(?:", "-", arr[2].s, // day (optional)
3905                             "(?:",
3906                                 "(?:T| )?", // time delimiter -- either a "T" or a single blank space
3907                                 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
3908                                 "(?::", arr[5].s, ")?", // seconds (optional)
3909                                 "(?:(?:\\.|,)(\\d+))?", // decimal fraction of a second (e.g. ",12345" or ".98765") (optional)
3910                                 "(Z|(?:[-+]\\d{2}(?::)?\\d{2}))?", // "Z" (UTC) or "-0530" (UTC offset without colon delimiter) or "+08:00" (UTC offset with colon delimiter) (optional)
3911                             ")?",
3912                         ")?",
3913                     ")?"
3914                 ].join("")
3915             };
3916         },
3917         U: {
3918             g:1,
3919             c:"u = parseInt(results[{0}], 10);\n",
3920             s:"(-?\\d+)" // leading minus sign indicates seconds before UNIX epoch
3921         }
3922     },
3923
3924     //Old Ext.Date prototype methods.
3925     // private
3926     dateFormat: function(date, format) {
3927         return utilDate.format(date, format);
3928     },
3929
3930     /**
3931      * Formats a date given the supplied format string.
3932      * @param {Date} date The date to format
3933      * @param {String} format The format string
3934      * @return {String} The formatted date
3935      */
3936     format: function(date, format) {
3937         if (utilDate.formatFunctions[format] == null) {
3938             utilDate.createFormat(format);
3939         }
3940         var result = utilDate.formatFunctions[format].call(date);
3941         return result + '';
3942     },
3943
3944     /**
3945      * Get the timezone abbreviation of the current date (equivalent to the format specifier 'T').
3946      *
3947      * Note: The date string returned by the javascript Date object's toString() method varies
3948      * between browsers (e.g. FF vs IE) and system region settings (e.g. IE in Asia vs IE in America).
3949      * For a given date string e.g. "Thu Oct 25 2007 22:55:35 GMT+0800 (Malay Peninsula Standard Time)",
3950      * getTimezone() first tries to get the timezone abbreviation from between a pair of parentheses
3951      * (which may or may not be present), failing which it proceeds to get the timezone abbreviation
3952      * from the GMT offset portion of the date string.
3953      * @param {Date} date The date
3954      * @return {String} The abbreviated timezone name (e.g. 'CST', 'PDT', 'EDT', 'MPST' ...).
3955      */
3956     getTimezone : function(date) {
3957         // the following list shows the differences between date strings from different browsers on a WinXP SP2 machine from an Asian locale:
3958         //
3959         // Opera  : "Thu, 25 Oct 2007 22:53:45 GMT+0800" -- shortest (weirdest) date string of the lot
3960         // 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)
3961         // FF     : "Thu Oct 25 2007 22:55:35 GMT+0800 (Malay Peninsula Standard Time)" -- value in parentheses always gives the correct timezone
3962         // IE     : "Thu Oct 25 22:54:35 UTC+0800 2007" -- (Asian system setting) look for 3-4 letter timezone abbrev
3963         // IE     : "Thu Oct 25 17:06:37 PDT 2007" -- (American system setting) look for 3-4 letter timezone abbrev
3964         //
3965         // this crazy regex attempts to guess the correct timezone abbreviation despite these differences.
3966         // step 1: (?:\((.*)\) -- find timezone in parentheses
3967         // 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
3968         // step 3: remove all non uppercase characters found in step 1 and 2
3969         return date.toString().replace(/^.* (?:\((.*)\)|([A-Z]{1,4})(?:[\-+][0-9]{4})?(?: -?\d+)?)$/, "$1$2").replace(/[^A-Z]/g, "");
3970     },
3971
3972     /**
3973      * Get the offset from GMT of the current date (equivalent to the format specifier 'O').
3974      * @param {Date} date The date
3975      * @param {Boolean} colon (optional) true to separate the hours and minutes with a colon (defaults to false).
3976      * @return {String} The 4-character offset string prefixed with + or - (e.g. '-0600').
3977      */
3978     getGMTOffset : function(date, colon) {
3979         var offset = date.getTimezoneOffset();
3980         return (offset > 0 ? "-" : "+")
3981             + Ext.String.leftPad(Math.floor(Math.abs(offset) / 60), 2, "0")
3982             + (colon ? ":" : "")
3983             + Ext.String.leftPad(Math.abs(offset % 60), 2, "0");
3984     },
3985
3986     /**
3987      * Get the numeric day number of the year, adjusted for leap year.
3988      * @param {Date} date The date
3989      * @return {Number} 0 to 364 (365 in leap years).
3990      */
3991     getDayOfYear: function(date) {
3992         var num = 0,
3993             d = Ext.Date.clone(date),
3994             m = date.getMonth(),
3995             i;
3996
3997         for (i = 0, d.setDate(1), d.setMonth(0); i < m; d.setMonth(++i)) {
3998             num += utilDate.getDaysInMonth(d);
3999         }
4000         return num + date.getDate() - 1;
4001     },
4002
4003     /**
4004      * Get the numeric ISO-8601 week number of the year.
4005      * (equivalent to the format specifier 'W', but without a leading zero).
4006      * @param {Date} date The date
4007      * @return {Number} 1 to 53
4008      * @method
4009      */
4010     getWeekOfYear : (function() {
4011         // adapted from http://www.merlyn.demon.co.uk/weekcalc.htm
4012         var ms1d = 864e5, // milliseconds in a day
4013             ms7d = 7 * ms1d; // milliseconds in a week
4014
4015         return function(date) { // return a closure so constants get calculated only once
4016             var DC3 = Date.UTC(date.getFullYear(), date.getMonth(), date.getDate() + 3) / ms1d, // an Absolute Day Number
4017                 AWN = Math.floor(DC3 / 7), // an Absolute Week Number
4018                 Wyr = new Date(AWN * ms7d).getUTCFullYear();
4019
4020             return AWN - Math.floor(Date.UTC(Wyr, 0, 7) / ms7d) + 1;
4021         };
4022     })(),
4023
4024     /**
4025      * Checks if the current date falls within a leap year.
4026      * @param {Date} date The date
4027      * @return {Boolean} True if the current date falls within a leap year, false otherwise.
4028      */
4029     isLeapYear : function(date) {
4030         var year = date.getFullYear();
4031         return !!((year & 3) == 0 && (year % 100 || (year % 400 == 0 && year)));
4032     },
4033
4034     /**
4035      * Get the first day of the current month, adjusted for leap year.  The returned value
4036      * is the numeric day index within the week (0-6) which can be used in conjunction with
4037      * the {@link #monthNames} array to retrieve the textual day name.
4038      * Example:
4039      * <pre><code>
4040 var dt = new Date('1/10/2007'),
4041     firstDay = Ext.Date.getFirstDayOfMonth(dt);
4042 console.log(Ext.Date.dayNames[firstDay]); //output: 'Monday'
4043      * </code></pre>
4044      * @param {Date} date The date
4045      * @return {Number} The day number (0-6).
4046      */
4047     getFirstDayOfMonth : function(date) {
4048         var day = (date.getDay() - (date.getDate() - 1)) % 7;
4049         return (day < 0) ? (day + 7) : day;
4050     },
4051
4052     /**
4053      * Get the last day of the current month, adjusted for leap year.  The returned value
4054      * is the numeric day index within the week (0-6) which can be used in conjunction with
4055      * the {@link #monthNames} array to retrieve the textual day name.
4056      * Example:
4057      * <pre><code>
4058 var dt = new Date('1/10/2007'),
4059     lastDay = Ext.Date.getLastDayOfMonth(dt);
4060 console.log(Ext.Date.dayNames[lastDay]); //output: 'Wednesday'
4061      * </code></pre>
4062      * @param {Date} date The date
4063      * @return {Number} The day number (0-6).
4064      */
4065     getLastDayOfMonth : function(date) {
4066         return utilDate.getLastDateOfMonth(date).getDay();
4067     },
4068
4069
4070     /**
4071      * Get the date of the first day of the month in which this date resides.
4072      * @param {Date} date The date
4073      * @return {Date}
4074      */
4075     getFirstDateOfMonth : function(date) {
4076         return new Date(date.getFullYear(), date.getMonth(), 1);
4077     },
4078
4079     /**
4080      * Get the date of the last day of the month in which this date resides.
4081      * @param {Date} date The date
4082      * @return {Date}
4083      */
4084     getLastDateOfMonth : function(date) {
4085         return new Date(date.getFullYear(), date.getMonth(), utilDate.getDaysInMonth(date));
4086     },
4087
4088     /**
4089      * Get the number of days in the current month, adjusted for leap year.
4090      * @param {Date} date The date
4091      * @return {Number} The number of days in the month.
4092      * @method
4093      */
4094     getDaysInMonth: (function() {
4095         var daysInMonth = [31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31];
4096
4097         return function(date) { // return a closure for efficiency
4098             var m = date.getMonth();
4099
4100             return m == 1 && utilDate.isLeapYear(date) ? 29 : daysInMonth[m];
4101         };
4102     })(),
4103
4104     /**
4105      * Get the English ordinal suffix of the current day (equivalent to the format specifier 'S').
4106      * @param {Date} date The date
4107      * @return {String} 'st, 'nd', 'rd' or 'th'.
4108      */
4109     getSuffix : function(date) {
4110         switch (date.getDate()) {
4111             case 1:
4112             case 21:
4113             case 31:
4114                 return "st";
4115             case 2:
4116             case 22:
4117                 return "nd";
4118             case 3:
4119             case 23:
4120                 return "rd";
4121             default:
4122                 return "th";
4123         }
4124     },
4125
4126     /**
4127      * Creates and returns a new Date instance with the exact same date value as the called instance.
4128      * Dates are copied and passed by reference, so if a copied date variable is modified later, the original
4129      * variable will also be changed.  When the intention is to create a new variable that will not
4130      * modify the original instance, you should create a clone.
4131      *
4132      * Example of correctly cloning a date:
4133      * <pre><code>
4134 //wrong way:
4135 var orig = new Date('10/1/2006');
4136 var copy = orig;
4137 copy.setDate(5);
4138 console.log(orig);  //returns 'Thu Oct 05 2006'!
4139
4140 //correct way:
4141 var orig = new Date('10/1/2006'),
4142     copy = Ext.Date.clone(orig);
4143 copy.setDate(5);
4144 console.log(orig);  //returns 'Thu Oct 01 2006'
4145      * </code></pre>
4146      * @param {Date} date The date
4147      * @return {Date} The new Date instance.
4148      */
4149     clone : function(date) {
4150         return new Date(date.getTime());
4151     },
4152
4153     /**
4154      * Checks if the current date is affected by Daylight Saving Time (DST).
4155      * @param {Date} date The date
4156      * @return {Boolean} True if the current date is affected by DST.
4157      */
4158     isDST : function(date) {
4159         // adapted from http://sencha.com/forum/showthread.php?p=247172#post247172
4160         // courtesy of @geoffrey.mcgill
4161         return new Date(date.getFullYear(), 0, 1).getTimezoneOffset() != date.getTimezoneOffset();
4162     },
4163
4164     /**
4165      * Attempts to clear all time information from this Date by setting the time to midnight of the same day,
4166      * automatically adjusting for Daylight Saving Time (DST) where applicable.
4167      * (note: DST timezone information for the browser's host operating system is assumed to be up-to-date)
4168      * @param {Date} date The date
4169      * @param {Boolean} clone true to create a clone of this date, clear the time and return it (defaults to false).
4170      * @return {Date} this or the clone.
4171      */
4172     clearTime : function(date, clone) {
4173         if (clone) {
4174             return Ext.Date.clearTime(Ext.Date.clone(date));
4175         }
4176
4177         // get current date before clearing time
4178         var d = date.getDate();
4179
4180         // clear time
4181         date.setHours(0);
4182         date.setMinutes(0);
4183         date.setSeconds(0);
4184         date.setMilliseconds(0);
4185
4186         if (date.getDate() != d) { // account for DST (i.e. day of month changed when setting hour = 0)
4187             // note: DST adjustments are assumed to occur in multiples of 1 hour (this is almost always the case)
4188             // refer to http://www.timeanddate.com/time/aboutdst.html for the (rare) exceptions to this rule
4189
4190             // increment hour until cloned date == current date
4191             for (var hr = 1, c = utilDate.add(date, Ext.Date.HOUR, hr); c.getDate() != d; hr++, c = utilDate.add(date, Ext.Date.HOUR, hr));
4192
4193             date.setDate(d);
4194             date.setHours(c.getHours());
4195         }
4196
4197         return date;
4198     },
4199
4200     /**
4201      * Provides a convenient method for performing basic date arithmetic. This method
4202      * does not modify the Date instance being called - it creates and returns
4203      * a new Date instance containing the resulting date value.
4204      *
4205      * Examples:
4206      * <pre><code>
4207 // Basic usage:
4208 var dt = Ext.Date.add(new Date('10/29/2006'), Ext.Date.DAY, 5);
4209 console.log(dt); //returns 'Fri Nov 03 2006 00:00:00'
4210
4211 // Negative values will be subtracted:
4212 var dt2 = Ext.Date.add(new Date('10/1/2006'), Ext.Date.DAY, -5);
4213 console.log(dt2); //returns 'Tue Sep 26 2006 00:00:00'
4214
4215      * </code></pre>
4216      *
4217      * @param {Date} date The date to modify
4218      * @param {String} interval A valid date interval enum value.
4219      * @param {Number} value The amount to add to the current date.
4220      * @return {Date} The new Date instance.
4221      */
4222     add : function(date, interval, value) {
4223         var d = Ext.Date.clone(date),
4224             Date = Ext.Date;
4225         if (!interval || value === 0) return d;
4226
4227         switch(interval.toLowerCase()) {
4228             case Ext.Date.MILLI:
4229                 d.setMilliseconds(d.getMilliseconds() + value);
4230                 break;
4231             case Ext.Date.SECOND:
4232                 d.setSeconds(d.getSeconds() + value);
4233                 break;
4234             case Ext.Date.MINUTE:
4235                 d.setMinutes(d.getMinutes() + value);
4236                 break;
4237             case Ext.Date.HOUR:
4238                 d.setHours(d.getHours() + value);
4239                 break;
4240             case Ext.Date.DAY:
4241                 d.setDate(d.getDate() + value);
4242                 break;
4243             case Ext.Date.MONTH:
4244                 var day = date.getDate();
4245                 if (day > 28) {
4246                     day = Math.min(day, Ext.Date.getLastDateOfMonth(Ext.Date.add(Ext.Date.getFirstDateOfMonth(date), 'mo', value)).getDate());
4247                 }
4248                 d.setDate(day);
4249                 d.setMonth(date.getMonth() + value);
4250                 break;
4251             case Ext.Date.YEAR:
4252                 d.setFullYear(date.getFullYear() + value);
4253                 break;
4254         }
4255         return d;
4256     },
4257
4258     /**
4259      * Checks if a date falls on or between the given start and end dates.
4260      * @param {Date} date The date to check
4261      * @param {Date} start Start date
4262      * @param {Date} end End date
4263      * @return {Boolean} true if this date falls on or between the given start and end dates.
4264      */
4265     between : function(date, start, end) {
4266         var t = date.getTime();
4267         return start.getTime() <= t && t <= end.getTime();
4268     },
4269
4270     //Maintains compatibility with old static and prototype window.Date methods.
4271     compat: function() {
4272         var nativeDate = window.Date,
4273             p, u,
4274             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'],
4275             proto = ['dateFormat', 'format', 'getTimezone', 'getGMTOffset', 'getDayOfYear', 'getWeekOfYear', 'isLeapYear', 'getFirstDayOfMonth', 'getLastDayOfMonth', 'getDaysInMonth', 'getSuffix', 'clone', 'isDST', 'clearTime', 'add', 'between'];
4276
4277         //Append statics
4278         Ext.Array.forEach(statics, function(s) {
4279             nativeDate[s] = utilDate[s];
4280         });
4281
4282         //Append to prototype
4283         Ext.Array.forEach(proto, function(s) {
4284             nativeDate.prototype[s] = function() {
4285                 var args = Array.prototype.slice.call(arguments);
4286                 args.unshift(this);
4287                 return utilDate[s].apply(utilDate, args);
4288             };
4289         });
4290     }
4291 };
4292
4293 var utilDate = Ext.Date;
4294
4295 })();
4296
4297 /**
4298  * @author Jacky Nguyen <jacky@sencha.com>
4299  * @docauthor Jacky Nguyen <jacky@sencha.com>
4300  * @class Ext.Base
4301  *
4302  * The root of all classes created with {@link Ext#define}
4303  * All prototype and static members of this class are inherited by any other class
4304  *
4305  */
4306 (function(flexSetter) {
4307
4308 var Base = Ext.Base = function() {};
4309     Base.prototype = {
4310         $className: 'Ext.Base',
4311
4312         $class: Base,
4313
4314         /**
4315          * Get the reference to the current class from which this object was instantiated. Unlike {@link Ext.Base#statics},
4316          * `this.self` is scope-dependent and it's meant to be used for dynamic inheritance. See {@link Ext.Base#statics}
4317          * for a detailed comparison
4318          *
4319          *     Ext.define('My.Cat', {
4320          *         statics: {
4321          *             speciesName: 'Cat' // My.Cat.speciesName = 'Cat'
4322          *         },
4323          *
4324          *         constructor: function() {
4325          *             alert(this.self.speciesName); / dependent on 'this'
4326          *
4327          *             return this;
4328          *         },
4329          *
4330          *         clone: function() {
4331          *             return new this.self();
4332          *         }
4333          *     });
4334          *
4335          *
4336          *     Ext.define('My.SnowLeopard', {
4337          *         extend: 'My.Cat',
4338          *         statics: {
4339          *             speciesName: 'Snow Leopard'         // My.SnowLeopard.speciesName = 'Snow Leopard'
4340          *         }
4341          *     });
4342          *
4343          *     var cat = new My.Cat();                     // alerts 'Cat'
4344          *     var snowLeopard = new My.SnowLeopard();     // alerts 'Snow Leopard'
4345          *
4346          *     var clone = snowLeopard.clone();
4347          *     alert(Ext.getClassName(clone));             // alerts 'My.SnowLeopard'
4348          *
4349          * @type Class
4350          * @protected
4351          * @markdown
4352          */
4353         self: Base,
4354
4355         /**
4356          * Default constructor, simply returns `this`
4357          *
4358          * @constructor
4359          * @protected
4360          * @return {Object} this
4361          */
4362         constructor: function() {
4363             return this;
4364         },
4365
4366         /**
4367          * Initialize configuration for this class. a typical example:
4368          *
4369          *     Ext.define('My.awesome.Class', {
4370          *         // The default config
4371          *         config: {
4372          *             name: 'Awesome',
4373          *             isAwesome: true
4374          *         },
4375          *
4376          *         constructor: function(config) {
4377          *             this.initConfig(config);
4378          *
4379          *             return this;
4380          *         }
4381          *     });
4382          *
4383          *     var awesome = new My.awesome.Class({
4384          *         name: 'Super Awesome'
4385          *     });
4386          *
4387          *     alert(awesome.getName()); // 'Super Awesome'
4388          *
4389          * @protected
4390          * @param {Object} config
4391          * @return {Object} mixins The mixin prototypes as key - value pairs
4392          * @markdown
4393          */
4394         initConfig: function(config) {
4395             if (!this.$configInited) {
4396                 this.config = Ext.Object.merge({}, this.config || {}, config || {});
4397
4398                 this.applyConfig(this.config);
4399
4400                 this.$configInited = true;
4401             }
4402
4403             return this;
4404         },
4405
4406         /**
4407          * @private
4408          */
4409         setConfig: function(config) {
4410             this.applyConfig(config || {});
4411
4412             return this;
4413         },
4414
4415         /**
4416          * @private
4417          */
4418         applyConfig: flexSetter(function(name, value) {
4419             var setter = 'set' + Ext.String.capitalize(name);
4420
4421             if (typeof this[setter] === 'function') {
4422                 this[setter].call(this, value);
4423             }
4424
4425             return this;
4426         }),
4427
4428         /**
4429          * Call the parent's overridden method. For example:
4430          *
4431          *     Ext.define('My.own.A', {
4432          *         constructor: function(test) {
4433          *             alert(test);
4434          *         }
4435          *     });
4436          *
4437          *     Ext.define('My.own.B', {
4438          *         extend: 'My.own.A',
4439          *
4440          *         constructor: function(test) {
4441          *             alert(test);
4442          *
4443          *             this.callParent([test + 1]);
4444          *         }
4445          *     });
4446          *
4447          *     Ext.define('My.own.C', {
4448          *         extend: 'My.own.B',
4449          *
4450          *         constructor: function() {
4451          *             alert("Going to call parent's overriden constructor...");
4452          *
4453          *             this.callParent(arguments);
4454          *         }
4455          *     });
4456          *
4457          *     var a = new My.own.A(1); // alerts '1'
4458          *     var b = new My.own.B(1); // alerts '1', then alerts '2'
4459          *     var c = new My.own.C(2); // alerts "Going to call parent's overriden constructor..."
4460          *                              // alerts '2', then alerts '3'
4461          *
4462          * @protected
4463          * @param {Array/Arguments} args The arguments, either an array or the `arguments` object
4464          * from the current method, for example: `this.callParent(arguments)`
4465          * @return {Mixed} Returns the result from the superclass' method
4466          * @markdown
4467          */
4468         callParent: function(args) {
4469             var method = this.callParent.caller,
4470                 parentClass, methodName;
4471
4472             if (!method.$owner) {
4473                 if (!method.caller) {
4474                     Ext.Error.raise({
4475                         sourceClass: Ext.getClassName(this),
4476                         sourceMethod: "callParent",
4477                         msg: "Attempting to call a protected method from the public scope, which is not allowed"
4478                     });
4479                 }
4480
4481                 method = method.caller;
4482             }
4483
4484             parentClass = method.$owner.superclass;
4485             methodName = method.$name;
4486
4487             if (!(methodName in parentClass)) {
4488                 Ext.Error.raise({
4489                     sourceClass: Ext.getClassName(this),
4490                     sourceMethod: methodName,
4491                     msg: "this.callParent() was called but there's no such method (" + methodName +
4492                          ") found in the parent class (" + (Ext.getClassName(parentClass) || 'Object') + ")"
4493                  });
4494             }
4495
4496             return parentClass[methodName].apply(this, args || []);
4497         },
4498
4499
4500         /**
4501          * Get the reference to the class from which this object was instantiated. Note that unlike {@link Ext.Base#self},
4502          * `this.statics()` is scope-independent and it always returns the class from which it was called, regardless of what
4503          * `this` points to during run-time
4504          *
4505          *     Ext.define('My.Cat', {
4506          *         statics: {
4507          *             totalCreated: 0,
4508          *             speciesName: 'Cat' // My.Cat.speciesName = 'Cat'
4509          *         },
4510          *  
4511          *         constructor: function() {
4512          *             var statics = this.statics();
4513          *  
4514          *             alert(statics.speciesName);     // always equals to 'Cat' no matter what 'this' refers to
4515          *                                             // equivalent to: My.Cat.speciesName
4516          *  
4517          *             alert(this.self.speciesName);   // dependent on 'this'
4518          *  
4519          *             statics.totalCreated++;
4520          *  
4521          *             return this;
4522          *         },
4523          *  
4524          *         clone: function() {
4525          *             var cloned = new this.self;                      // dependent on 'this'
4526          *  
4527          *             cloned.groupName = this.statics().speciesName;   // equivalent to: My.Cat.speciesName
4528          *  
4529          *             return cloned;
4530          *         }
4531          *     });
4532          *
4533          *
4534          *     Ext.define('My.SnowLeopard', {
4535          *         extend: 'My.Cat',
4536          *  
4537          *         statics: {
4538          *             speciesName: 'Snow Leopard'     // My.SnowLeopard.speciesName = 'Snow Leopard'
4539          *         },
4540          *  
4541          *         constructor: function() {
4542          *             this.callParent();
4543          *         }
4544          *     });
4545          *
4546          *     var cat = new My.Cat();                 // alerts 'Cat', then alerts 'Cat'
4547          *
4548          *     var snowLeopard = new My.SnowLeopard(); // alerts 'Cat', then alerts 'Snow Leopard'
4549          *
4550          *     var clone = snowLeopard.clone();
4551          *     alert(Ext.getClassName(clone));         // alerts 'My.SnowLeopard'
4552          *     alert(clone.groupName);                 // alerts 'Cat'
4553          *
4554          *     alert(My.Cat.totalCreated);             // alerts 3
4555          *
4556          * @protected
4557          * @return {Class}
4558          * @markdown
4559          */
4560         statics: function() {
4561             var method = this.statics.caller,
4562                 self = this.self;
4563
4564             if (!method) {
4565                 return self;
4566             }
4567
4568             return method.$owner;
4569         },
4570
4571         /**
4572          * Call the original method that was previously overridden with {@link Ext.Base#override}
4573          *
4574          *     Ext.define('My.Cat', {
4575          *         constructor: function() {
4576          *             alert("I'm a cat!");
4577          *   
4578          *             return this;
4579          *         }
4580          *     });
4581          *
4582          *     My.Cat.override({
4583          *         constructor: function() {
4584          *             alert("I'm going to be a cat!");
4585          *   
4586          *             var instance = this.callOverridden();
4587          *   
4588          *             alert("Meeeeoooowwww");
4589          *   
4590          *             return instance;
4591          *         }
4592          *     });
4593          *
4594          *     var kitty = new My.Cat(); // alerts "I'm going to be a cat!"
4595          *                               // alerts "I'm a cat!"
4596          *                               // alerts "Meeeeoooowwww"
4597          *
4598          * @param {Array/Arguments} args The arguments, either an array or the `arguments` object
4599          * @return {Mixed} Returns the result after calling the overridden method
4600          * @markdown
4601          */
4602         callOverridden: function(args) {
4603             var method = this.callOverridden.caller;
4604
4605             if (!method.$owner) {
4606                 Ext.Error.raise({
4607                     sourceClass: Ext.getClassName(this),
4608                     sourceMethod: "callOverridden",
4609                     msg: "Attempting to call a protected method from the public scope, which is not allowed"
4610                 });
4611             }
4612
4613             if (!method.$previous) {
4614                 Ext.Error.raise({
4615                     sourceClass: Ext.getClassName(this),
4616                     sourceMethod: "callOverridden",
4617                     msg: "this.callOverridden was called in '" + method.$name +
4618                          "' but this method has never been overridden"
4619                  });
4620             }
4621
4622             return method.$previous.apply(this, args || []);
4623         },
4624
4625         destroy: function() {}
4626     };
4627
4628     // These static properties will be copied to every newly created class with {@link Ext#define}
4629     Ext.apply(Ext.Base, {
4630         /**
4631          * Create a new instance of this Class.
4632          *
4633          *     Ext.define('My.cool.Class', {
4634          *         ...
4635          *     });
4636          *      
4637          *     My.cool.Class.create({
4638          *         someConfig: true
4639          *     });
4640          *
4641          * @property create
4642          * @static
4643          * @type Function
4644          * @markdown
4645          */
4646         create: function() {
4647             return Ext.create.apply(Ext, [this].concat(Array.prototype.slice.call(arguments, 0)));
4648         },
4649
4650         /**
4651          * @private
4652          */
4653         own: flexSetter(function(name, value) {
4654             if (typeof value === 'function') {
4655                 this.ownMethod(name, value);
4656             }
4657             else {
4658                 this.prototype[name] = value;
4659             }
4660         }),
4661
4662         /**
4663          * @private
4664          */
4665         ownMethod: function(name, fn) {
4666             var originalFn;
4667
4668             if (fn.$owner !== undefined && fn !== Ext.emptyFn) {
4669                 originalFn = fn;
4670
4671                 fn = function() {
4672                     return originalFn.apply(this, arguments);
4673                 };
4674             }
4675
4676             var className;
4677             className = Ext.getClassName(this);
4678             if (className) {
4679                 fn.displayName = className + '#' + name;
4680             }
4681             fn.$owner = this;
4682             fn.$name = name;
4683
4684             this.prototype[name] = fn;
4685         },
4686
4687         /**
4688          * Add / override static properties of this class.
4689          *
4690          *     Ext.define('My.cool.Class', {
4691          *         ...
4692          *     });
4693          *
4694          *     My.cool.Class.addStatics({
4695          *         someProperty: 'someValue',      // My.cool.Class.someProperty = 'someValue'
4696          *         method1: function() { ... },    // My.cool.Class.method1 = function() { ... };
4697          *         method2: function() { ... }     // My.cool.Class.method2 = function() { ... };
4698          *     });
4699          *
4700          * @property addStatics
4701          * @static
4702          * @type Function
4703          * @param {Object} members
4704          * @markdown
4705          */
4706         addStatics: function(members) {
4707             for (var name in members) {
4708                 if (members.hasOwnProperty(name)) {
4709                     this[name] = members[name];
4710                 }
4711             }
4712
4713             return this;
4714         },
4715
4716         /**
4717          * Add methods / properties to the prototype of this class.
4718          *
4719          *     Ext.define('My.awesome.Cat', {
4720          *         constructor: function() {
4721          *             ...
4722          *         }
4723          *     });
4724          *
4725          *      My.awesome.Cat.implement({
4726          *          meow: function() {
4727          *             alert('Meowww...');
4728          *          }
4729          *      });
4730          *
4731          *      var kitty = new My.awesome.Cat;
4732          *      kitty.meow();
4733          *
4734          * @property implement
4735          * @static
4736          * @type Function
4737          * @param {Object} members
4738          * @markdown
4739          */
4740         implement: function(members) {
4741             var prototype = this.prototype,
4742                 name, i, member, previous;
4743             var className = Ext.getClassName(this);
4744             for (name in members) {
4745                 if (members.hasOwnProperty(name)) {
4746                     member = members[name];
4747
4748                     if (typeof member === 'function') {
4749                         member.$owner = this;
4750                         member.$name = name;
4751                         if (className) {
4752                             member.displayName = className + '#' + name;
4753                         }
4754                     }
4755
4756                     prototype[name] = member;
4757                 }
4758             }
4759
4760             if (Ext.enumerables) {
4761                 var enumerables = Ext.enumerables;
4762
4763                 for (i = enumerables.length; i--;) {
4764                     name = enumerables[i];
4765
4766                     if (members.hasOwnProperty(name)) {
4767                         member = members[name];
4768                         member.$owner = this;
4769                         member.$name = name;
4770                         prototype[name] = member;
4771                     }
4772                 }
4773             }
4774         },
4775
4776         /**
4777          * Borrow another class' members to the prototype of this class.
4778          *
4779          *     Ext.define('Bank', {
4780          *         money: '$$$',
4781          *         printMoney: function() {
4782          *             alert('$$$$$$$');
4783          *         }
4784          *     });
4785          *
4786          *     Ext.define('Thief', {
4787          *         ...
4788          *     });
4789          *
4790          *     Thief.borrow(Bank, ['money', 'printMoney']);
4791          *
4792          *     var steve = new Thief();
4793          *
4794          *     alert(steve.money); // alerts '$$$'
4795          *     steve.printMoney(); // alerts '$$$$$$$'
4796          *
4797          * @property borrow
4798          * @static
4799          * @type Function
4800          * @param {Ext.Base} fromClass The class to borrow members from
4801          * @param {Array/String} members The names of the members to borrow
4802          * @return {Ext.Base} this
4803          * @markdown
4804          */
4805         borrow: function(fromClass, members) {
4806             var fromPrototype = fromClass.prototype,
4807                 i, ln, member;
4808
4809             members = Ext.Array.from(members);
4810
4811             for (i = 0, ln = members.length; i < ln; i++) {
4812                 member = members[i];
4813
4814                 this.own(member, fromPrototype[member]);
4815             }
4816
4817             return this;
4818         },
4819
4820         /**
4821          * Override prototype members of this class. Overridden methods can be invoked via
4822          * {@link Ext.Base#callOverridden}
4823          *
4824          *     Ext.define('My.Cat', {
4825          *         constructor: function() {
4826          *             alert("I'm a cat!");
4827          *
4828          *             return this;
4829          *         }
4830          *     });
4831          *
4832          *     My.Cat.override({
4833          *         constructor: function() {
4834          *             alert("I'm going to be a cat!");
4835          *
4836          *             var instance = this.callOverridden();
4837          *
4838          *             alert("Meeeeoooowwww");
4839          *
4840          *             return instance;
4841          *         }
4842          *     });
4843          *
4844          *     var kitty = new My.Cat(); // alerts "I'm going to be a cat!"
4845          *                               // alerts "I'm a cat!"
4846          *                               // alerts "Meeeeoooowwww"
4847          *
4848          * @property override
4849          * @static
4850          * @type Function
4851          * @param {Object} members
4852          * @return {Ext.Base} this
4853          * @markdown
4854          */
4855         override: function(members) {
4856             var prototype = this.prototype,
4857                 name, i, member, previous;
4858
4859             for (name in members) {
4860                 if (members.hasOwnProperty(name)) {
4861                     member = members[name];
4862
4863                     if (typeof member === 'function') {
4864                         if (typeof prototype[name] === 'function') {
4865                             previous = prototype[name];
4866                             member.$previous = previous;
4867                         }
4868
4869                         this.ownMethod(name, member);
4870                     }
4871                     else {
4872                         prototype[name] = member;
4873                     }
4874                 }
4875             }
4876
4877             if (Ext.enumerables) {
4878                 var enumerables = Ext.enumerables;
4879
4880                 for (i = enumerables.length; i--;) {
4881                     name = enumerables[i];
4882
4883                     if (members.hasOwnProperty(name)) {
4884                         if (prototype[name] !== undefined) {
4885                             previous = prototype[name];
4886                             members[name].$previous = previous;
4887                         }
4888
4889                         this.ownMethod(name, members[name]);
4890                     }
4891                 }
4892             }
4893
4894             return this;
4895         },
4896
4897         /**
4898          * Used internally by the mixins pre-processor
4899          * @private
4900          */
4901         mixin: flexSetter(function(name, cls) {
4902             var mixin = cls.prototype,
4903                 my = this.prototype,
4904                 i, fn;
4905
4906             for (i in mixin) {
4907                 if (mixin.hasOwnProperty(i)) {
4908                     if (my[i] === undefined) {
4909                         if (typeof mixin[i] === 'function') {
4910                             fn = mixin[i];
4911
4912                             if (fn.$owner === undefined) {
4913                                 this.ownMethod(i, fn);
4914                             }
4915                             else {
4916                                 my[i] = fn;
4917                             }
4918                         }
4919                         else {
4920                             my[i] = mixin[i];
4921                         }
4922                     }
4923                     else if (i === 'config' && my.config && mixin.config) {
4924                         Ext.Object.merge(my.config, mixin.config);
4925                     }
4926                 }
4927             }
4928
4929             if (my.mixins === undefined) {
4930                 my.mixins = {};
4931             }
4932
4933             my.mixins[name] = mixin;
4934         }),
4935
4936         /**
4937          * Get the current class' name in string format.
4938          *
4939          *     Ext.define('My.cool.Class', {
4940          *         constructor: function() {
4941          *             alert(this.self.getName()); // alerts 'My.cool.Class'
4942          *         }
4943          *     });
4944          *
4945          *     My.cool.Class.getName(); // 'My.cool.Class'
4946          *
4947          * @return {String} className
4948          * @markdown
4949          */
4950         getName: function() {
4951             return Ext.getClassName(this);
4952         },
4953
4954         /**
4955          * Create aliases for existing prototype methods. Example:
4956          *
4957          *     Ext.define('My.cool.Class', {
4958          *         method1: function() { ... },
4959          *         method2: function() { ... }
4960          *     });
4961          *
4962          *     var test = new My.cool.Class();
4963          *
4964          *     My.cool.Class.createAlias({
4965          *         method3: 'method1',
4966          *         method4: 'method2'
4967          *     });
4968          *
4969          *     test.method3(); // test.method1()
4970          *
4971          *     My.cool.Class.createAlias('method5', 'method3');
4972          *
4973          *     test.method5(); // test.method3() -> test.method1()
4974          *
4975          * @property createAlias
4976          * @static
4977          * @type Function
4978          * @param {String/Object} alias The new method name, or an object to set multiple aliases. See
4979          * {@link Ext.Function#flexSetter flexSetter}
4980          * @param {String/Object} origin The original method name
4981          * @markdown
4982          */
4983         createAlias: flexSetter(function(alias, origin) {
4984             this.prototype[alias] = this.prototype[origin];
4985         })
4986     });
4987
4988 })(Ext.Function.flexSetter);
4989
4990 /**
4991  * @author Jacky Nguyen <jacky@sencha.com>
4992  * @docauthor Jacky Nguyen <jacky@sencha.com>
4993  * @class Ext.Class
4994  * 
4995  * Handles class creation throughout the whole framework. Note that most of the time {@link Ext#define Ext.define} should
4996  * be used instead, since it's a higher level wrapper that aliases to {@link Ext.ClassManager#create}
4997  * to enable namespacing and dynamic dependency resolution.
4998  * 
4999  * # Basic syntax: #
5000  * 
5001  *     Ext.define(className, properties);
5002  * 
5003  * in which `properties` is an object represent a collection of properties that apply to the class. See
5004  * {@link Ext.ClassManager#create} for more detailed instructions.
5005  * 
5006  *     Ext.define('Person', {
5007  *          name: 'Unknown',
5008  * 
5009  *          constructor: function(name) {
5010  *              if (name) {
5011  *                  this.name = name;
5012  *              }
5013  * 
5014  *              return this;
5015  *          },
5016  * 
5017  *          eat: function(foodType) {
5018  *              alert("I'm eating: " + foodType);
5019  * 
5020  *              return this;
5021  *          }
5022  *     });
5023  * 
5024  *     var aaron = new Person("Aaron");
5025  *     aaron.eat("Sandwich"); // alert("I'm eating: Sandwich");
5026  * 
5027  * Ext.Class has a powerful set of extensible {@link Ext.Class#registerPreprocessor pre-processors} which takes care of
5028  * everything related to class creation, including but not limited to inheritance, mixins, configuration, statics, etc.
5029  * 
5030  * # Inheritance: #
5031  * 
5032  *     Ext.define('Developer', {
5033  *          extend: 'Person',
5034  * 
5035  *          constructor: function(name, isGeek) {
5036  *              this.isGeek = isGeek;
5037  * 
5038  *              // Apply a method from the parent class' prototype
5039  *              this.callParent([name]);
5040  * 
5041  *              return this;
5042  * 
5043  *          },
5044  * 
5045  *          code: function(language) {
5046  *              alert("I'm coding in: " + language);
5047  * 
5048  *              this.eat("Bugs");
5049  * 
5050  *              return this;
5051  *          }
5052  *     });
5053  * 
5054  *     var jacky = new Developer("Jacky", true);
5055  *     jacky.code("JavaScript"); // alert("I'm coding in: JavaScript");
5056  *                               // alert("I'm eating: Bugs");
5057  * 
5058  * See {@link Ext.Base#callParent} for more details on calling superclass' methods
5059  * 
5060  * # Mixins: #
5061  * 
5062  *     Ext.define('CanPlayGuitar', {
5063  *          playGuitar: function() {
5064  *             alert("F#...G...D...A");
5065  *          }
5066  *     });
5067  * 
5068  *     Ext.define('CanComposeSongs', {
5069  *          composeSongs: function() { ... }
5070  *     });
5071  * 
5072  *     Ext.define('CanSing', {
5073  *          sing: function() {
5074  *              alert("I'm on the highway to hell...")
5075  *          }
5076  *     });
5077  * 
5078  *     Ext.define('Musician', {
5079  *          extend: 'Person',
5080  * 
5081  *          mixins: {
5082  *              canPlayGuitar: 'CanPlayGuitar',
5083  *              canComposeSongs: 'CanComposeSongs',
5084  *              canSing: 'CanSing'
5085  *          }
5086  *     })
5087  * 
5088  *     Ext.define('CoolPerson', {
5089  *          extend: 'Person',
5090  * 
5091  *          mixins: {
5092  *              canPlayGuitar: 'CanPlayGuitar',
5093  *              canSing: 'CanSing'
5094  *          },
5095  * 
5096  *          sing: function() {
5097  *              alert("Ahem....");
5098  * 
5099  *              this.mixins.canSing.sing.call(this);
5100  * 
5101  *              alert("[Playing guitar at the same time...]");
5102  * 
5103  *              this.playGuitar();
5104  *          }
5105  *     });
5106  * 
5107  *     var me = new CoolPerson("Jacky");
5108  * 
5109  *     me.sing(); // alert("Ahem...");
5110  *                // alert("I'm on the highway to hell...");
5111  *                // alert("[Playing guitar at the same time...]");
5112  *                // alert("F#...G...D...A");
5113  * 
5114  * # Config: #
5115  * 
5116  *     Ext.define('SmartPhone', {
5117  *          config: {
5118  *              hasTouchScreen: false,
5119  *              operatingSystem: 'Other',
5120  *              price: 500
5121  *          },
5122  * 
5123  *          isExpensive: false,
5124  * 
5125  *          constructor: function(config) {
5126  *              this.initConfig(config);
5127  * 
5128  *              return this;
5129  *          },
5130  * 
5131  *          applyPrice: function(price) {
5132  *              this.isExpensive = (price > 500);
5133  * 
5134  *              return price;
5135  *          },
5136  * 
5137  *          applyOperatingSystem: function(operatingSystem) {
5138  *              if (!(/^(iOS|Android|BlackBerry)$/i).test(operatingSystem)) {
5139  *                  return 'Other';
5140  *              }
5141  * 
5142  *              return operatingSystem;
5143  *          }
5144  *     });
5145  * 
5146  *     var iPhone = new SmartPhone({
5147  *          hasTouchScreen: true,
5148  *          operatingSystem: 'iOS'
5149  *     });
5150  * 
5151  *     iPhone.getPrice(); // 500;
5152  *     iPhone.getOperatingSystem(); // 'iOS'
5153  *     iPhone.getHasTouchScreen(); // true;
5154  *     iPhone.hasTouchScreen(); // true
5155  * 
5156  *     iPhone.isExpensive; // false;
5157  *     iPhone.setPrice(600);
5158  *     iPhone.getPrice(); // 600
5159  *     iPhone.isExpensive; // true;
5160  * 
5161  *     iPhone.setOperatingSystem('AlienOS');
5162  *     iPhone.getOperatingSystem(); // 'Other'
5163  * 
5164  * # Statics: #
5165  * 
5166  *     Ext.define('Computer', {
5167  *          statics: {
5168  *              factory: function(brand) {
5169  *                 // 'this' in static methods refer to the class itself
5170  *                  return new this(brand);
5171  *              }
5172  *          },
5173  * 
5174  *          constructor: function() { ... }
5175  *     });
5176  * 
5177  *     var dellComputer = Computer.factory('Dell');
5178  * 
5179  * Also see {@link Ext.Base#statics} and {@link Ext.Base#self} for more details on accessing
5180  * static properties within class methods
5181  *
5182  */
5183 (function() {
5184
5185     var Class,
5186         Base = Ext.Base,
5187         baseStaticProperties = [],
5188         baseStaticProperty;
5189
5190     for (baseStaticProperty in Base) {
5191         if (Base.hasOwnProperty(baseStaticProperty)) {
5192             baseStaticProperties.push(baseStaticProperty);
5193         }
5194     }
5195
5196     /**
5197      * @constructor
5198      * @param {Object} classData An object represent the properties of this class
5199      * @param {Function} createdFn Optional, the callback function to be executed when this class is fully created.
5200      * Note that the creation process can be asynchronous depending on the pre-processors used.
5201      * @return {Ext.Base} The newly created class
5202      */
5203     Ext.Class = Class = function(newClass, classData, onClassCreated) {
5204         if (typeof newClass !== 'function') {
5205             onClassCreated = classData;
5206             classData = newClass;
5207             newClass = function() {
5208                 return this.constructor.apply(this, arguments);
5209             };
5210         }
5211
5212         if (!classData) {
5213             classData = {};
5214         }
5215
5216         var preprocessorStack = classData.preprocessors || Class.getDefaultPreprocessors(),
5217             registeredPreprocessors = Class.getPreprocessors(),
5218             index = 0,
5219             preprocessors = [],
5220             preprocessor, preprocessors, staticPropertyName, process, i, j, ln;
5221
5222         for (i = 0, ln = baseStaticProperties.length; i < ln; i++) {
5223             staticPropertyName = baseStaticProperties[i];
5224             newClass[staticPropertyName] = Base[staticPropertyName];
5225         }
5226
5227         delete classData.preprocessors;
5228
5229         for (j = 0, ln = preprocessorStack.length; j < ln; j++) {
5230             preprocessor = preprocessorStack[j];
5231
5232             if (typeof preprocessor === 'string') {
5233                 preprocessor = registeredPreprocessors[preprocessor];
5234
5235                 if (!preprocessor.always) {
5236                     if (classData.hasOwnProperty(preprocessor.name)) {
5237                         preprocessors.push(preprocessor.fn);
5238                     }
5239                 }
5240                 else {
5241                     preprocessors.push(preprocessor.fn);
5242                 }
5243             }
5244             else {
5245                 preprocessors.push(preprocessor);
5246             }
5247         }
5248
5249         classData.onClassCreated = onClassCreated;
5250
5251         classData.onBeforeClassCreated = function(cls, data) {
5252             onClassCreated = data.onClassCreated;
5253
5254             delete data.onBeforeClassCreated;
5255             delete data.onClassCreated;
5256
5257             cls.implement(data);
5258
5259             if (onClassCreated) {
5260                 onClassCreated.call(cls, cls);
5261             }
5262         };
5263
5264         process = function(cls, data) {
5265             preprocessor = preprocessors[index++];
5266
5267             if (!preprocessor) {
5268                 data.onBeforeClassCreated.apply(this, arguments);
5269                 return;
5270             }
5271
5272             if (preprocessor.call(this, cls, data, process) !== false) {
5273                 process.apply(this, arguments);
5274             }
5275         };
5276
5277         process.call(Class, newClass, classData);
5278
5279         return newClass;
5280     };
5281
5282     Ext.apply(Class, {
5283
5284         /** @private */
5285         preprocessors: {},
5286
5287         /**
5288          * Register a new pre-processor to be used during the class creation process
5289          *
5290          * @member Ext.Class registerPreprocessor
5291          * @param {String} name The pre-processor's name
5292          * @param {Function} fn The callback function to be executed. Typical format:
5293
5294     function(cls, data, fn) {
5295         // Your code here
5296
5297         // Execute this when the processing is finished.
5298         // Asynchronous processing is perfectly ok
5299         if (fn) {
5300             fn.call(this, cls, data);
5301         }
5302     });
5303
5304          * Passed arguments for this function are:
5305          *
5306          * - `{Function} cls`: The created class
5307          * - `{Object} data`: The set of properties passed in {@link Ext.Class} constructor
5308          * - `{Function} fn`: The callback function that <b>must</b> to be executed when this pre-processor finishes,
5309          * regardless of whether the processing is synchronous or aynchronous
5310          *
5311          * @return {Ext.Class} this
5312          * @markdown
5313          */
5314         registerPreprocessor: function(name, fn, always) {
5315             this.preprocessors[name] = {
5316                 name: name,
5317                 always: always ||  false,
5318                 fn: fn
5319             };
5320
5321             return this;
5322         },
5323
5324         /**
5325          * Retrieve a pre-processor callback function by its name, which has been registered before
5326          *
5327          * @param {String} name
5328          * @return {Function} preprocessor
5329          */
5330         getPreprocessor: function(name) {
5331             return this.preprocessors[name];
5332         },
5333
5334         getPreprocessors: function() {
5335             return this.preprocessors;
5336         },
5337
5338         /**
5339          * Retrieve the array stack of default pre-processors
5340          *
5341          * @return {Function} defaultPreprocessors
5342          */
5343         getDefaultPreprocessors: function() {
5344             return this.defaultPreprocessors || [];
5345         },
5346
5347         /**
5348          * Set the default array stack of default pre-processors
5349          *
5350          * @param {Array} preprocessors
5351          * @return {Ext.Class} this
5352          */
5353         setDefaultPreprocessors: function(preprocessors) {
5354             this.defaultPreprocessors = Ext.Array.from(preprocessors);
5355
5356             return this;
5357         },
5358
5359         /**
5360          * Insert this pre-processor at a specific position in the stack, optionally relative to
5361          * any existing pre-processor. For example:
5362
5363     Ext.Class.registerPreprocessor('debug', function(cls, data, fn) {
5364         // Your code here
5365
5366         if (fn) {
5367             fn.call(this, cls, data);
5368         }
5369     }).insertDefaultPreprocessor('debug', 'last');
5370
5371          * @param {String} name The pre-processor name. Note that it needs to be registered with
5372          * {@link Ext#registerPreprocessor registerPreprocessor} before this
5373          * @param {String} offset The insertion position. Four possible values are:
5374          * 'first', 'last', or: 'before', 'after' (relative to the name provided in the third argument)
5375          * @param {String} relativeName
5376          * @return {Ext.Class} this
5377          * @markdown
5378          */
5379         setDefaultPreprocessorPosition: function(name, offset, relativeName) {
5380             var defaultPreprocessors = this.defaultPreprocessors,
5381                 index;
5382
5383             if (typeof offset === 'string') {
5384                 if (offset === 'first') {
5385                     defaultPreprocessors.unshift(name);
5386
5387                     return this;
5388                 }
5389                 else if (offset === 'last') {
5390                     defaultPreprocessors.push(name);
5391
5392                     return this;
5393                 }
5394
5395                 offset = (offset === 'after') ? 1 : -1;
5396             }
5397
5398             index = Ext.Array.indexOf(defaultPreprocessors, relativeName);
5399
5400             if (index !== -1) {
5401                 defaultPreprocessors.splice(Math.max(0, index + offset), 0, name);
5402             }
5403
5404             return this;
5405         }
5406     });
5407
5408     Class.registerPreprocessor('extend', function(cls, data) {
5409         var extend = data.extend,
5410             base = Ext.Base,
5411             basePrototype = base.prototype,
5412             prototype = function() {},
5413             parent, i, k, ln, staticName, parentStatics,
5414             parentPrototype, clsPrototype;
5415
5416         if (extend && extend !== Object) {
5417             parent = extend;
5418         }
5419         else {
5420             parent = base;
5421         }
5422
5423         parentPrototype = parent.prototype;
5424
5425         prototype.prototype = parentPrototype;
5426         clsPrototype = cls.prototype = new prototype();
5427
5428         if (!('$class' in parent)) {
5429             for (i in basePrototype) {
5430                 if (!parentPrototype[i]) {
5431                     parentPrototype[i] = basePrototype[i];
5432                 }
5433             }
5434         }
5435
5436         clsPrototype.self = cls;
5437
5438         cls.superclass = clsPrototype.superclass = parentPrototype;
5439
5440         delete data.extend;
5441
5442         // Statics inheritance
5443         parentStatics = parentPrototype.$inheritableStatics;
5444
5445         if (parentStatics) {
5446             for (k = 0, ln = parentStatics.length; k < ln; k++) {
5447                 staticName = parentStatics[k];
5448
5449                 if (!cls.hasOwnProperty(staticName)) {
5450                     cls[staticName] = parent[staticName];
5451                 }
5452             }
5453         }
5454
5455         // Merge the parent class' config object without referencing it
5456         if (parentPrototype.config) {
5457             clsPrototype.config = Ext.Object.merge({}, parentPrototype.config);
5458         }
5459         else {
5460             clsPrototype.config = {};
5461         }
5462
5463         if (clsPrototype.$onExtended) {
5464             clsPrototype.$onExtended.call(cls, cls, data);
5465         }
5466
5467         if (data.onClassExtended) {
5468             clsPrototype.$onExtended = data.onClassExtended;
5469             delete data.onClassExtended;
5470         }
5471
5472     }, true);
5473
5474     Class.registerPreprocessor('statics', function(cls, data) {
5475         var statics = data.statics,
5476             name;
5477
5478         for (name in statics) {
5479             if (statics.hasOwnProperty(name)) {
5480                 cls[name] = statics[name];
5481             }
5482         }
5483
5484         delete data.statics;
5485     });
5486
5487     Class.registerPreprocessor('inheritableStatics', function(cls, data) {
5488         var statics = data.inheritableStatics,
5489             inheritableStatics,
5490             prototype = cls.prototype,
5491             name;
5492
5493         inheritableStatics = prototype.$inheritableStatics;
5494
5495         if (!inheritableStatics) {
5496             inheritableStatics = prototype.$inheritableStatics = [];
5497         }
5498
5499         for (name in statics) {
5500             if (statics.hasOwnProperty(name)) {
5501                 cls[name] = statics[name];
5502                 inheritableStatics.push(name);
5503             }
5504         }
5505
5506         delete data.inheritableStatics;
5507     });
5508
5509     Class.registerPreprocessor('mixins', function(cls, data) {
5510         cls.mixin(data.mixins);
5511
5512         delete data.mixins;
5513     });
5514
5515     Class.registerPreprocessor('config', function(cls, data) {
5516         var prototype = cls.prototype;
5517
5518         Ext.Object.each(data.config, function(name) {
5519             var cName = name.charAt(0).toUpperCase() + name.substr(1),
5520                 pName = name,
5521                 apply = 'apply' + cName,
5522                 setter = 'set' + cName,
5523                 getter = 'get' + cName;
5524
5525             if (!(apply in prototype) && !data.hasOwnProperty(apply)) {
5526                 data[apply] = function(val) {
5527                     return val;
5528                 };
5529             }
5530
5531             if (!(setter in prototype) && !data.hasOwnProperty(setter)) {
5532                 data[setter] = function(val) {
5533                     var ret = this[apply].call(this, val, this[pName]);
5534
5535                     if (ret !== undefined) {
5536                         this[pName] = ret;
5537                     }
5538
5539                     return this;
5540                 };
5541             }
5542
5543             if (!(getter in prototype) && !data.hasOwnProperty(getter)) {
5544                 data[getter] = function() {
5545                     return this[pName];
5546                 };
5547             }
5548         });
5549
5550         Ext.Object.merge(prototype.config, data.config);
5551         delete data.config;
5552     });
5553
5554     Class.setDefaultPreprocessors(['extend', 'statics', 'inheritableStatics', 'mixins', 'config']);
5555
5556     // Backwards compatible
5557     Ext.extend = function(subclass, superclass, members) {
5558         if (arguments.length === 2 && Ext.isObject(superclass)) {
5559             members = superclass;
5560             superclass = subclass;
5561             subclass = null;
5562         }
5563
5564         var cls;
5565
5566         if (!superclass) {
5567             Ext.Error.raise("Attempting to extend from a class which has not been loaded on the page.");
5568         }
5569
5570         members.extend = superclass;
5571         members.preprocessors = ['extend', 'mixins', 'config', 'statics'];
5572
5573         if (subclass) {
5574             cls = new Class(subclass, members);
5575         }
5576         else {
5577             cls = new Class(members);
5578         }
5579
5580         cls.prototype.override = function(o) {
5581             for (var m in o) {
5582                 if (o.hasOwnProperty(m)) {
5583                     this[m] = o[m];
5584                 }
5585             }
5586         };
5587
5588         return cls;
5589     };
5590
5591 })();
5592
5593 /**
5594  * @author Jacky Nguyen <jacky@sencha.com>
5595  * @docauthor Jacky Nguyen <jacky@sencha.com>
5596  * @class Ext.ClassManager
5597
5598 Ext.ClassManager manages all classes and handles mapping from string class name to
5599 actual class objects throughout the whole framework. It is not generally accessed directly, rather through
5600 these convenient shorthands:
5601
5602 - {@link Ext#define Ext.define}
5603 - {@link Ext#create Ext.create}
5604 - {@link Ext#widget Ext.widget}
5605 - {@link Ext#getClass Ext.getClass}
5606 - {@link Ext#getClassName Ext.getClassName}
5607
5608  * @singleton
5609  * @markdown
5610  */
5611 (function(Class, alias) {
5612
5613     var slice = Array.prototype.slice;
5614
5615     var Manager = Ext.ClassManager = {
5616
5617         /**
5618          * @property classes
5619          * @type Object
5620          * All classes which were defined through the ClassManager. Keys are the
5621          * name of the classes and the values are references to the classes.
5622          * @private
5623          */
5624         classes: {},
5625
5626         /**
5627          * @private
5628          */
5629         existCache: {},
5630
5631         /**
5632          * @private
5633          */
5634         namespaceRewrites: [{
5635             from: 'Ext.',
5636             to: Ext
5637         }],
5638
5639         /**
5640          * @private
5641          */
5642         maps: {
5643             alternateToName: {},
5644             aliasToName: {},
5645             nameToAliases: {}
5646         },
5647
5648         /** @private */
5649         enableNamespaceParseCache: true,
5650
5651         /** @private */
5652         namespaceParseCache: {},
5653
5654         /** @private */
5655         instantiators: [],
5656
5657         /** @private */
5658         instantiationCounts: {},
5659
5660         /**
5661          * Checks if a class has already been created.
5662          *
5663          * @param {String} className
5664          * @return {Boolean} exist
5665          */
5666         isCreated: function(className) {
5667             var i, ln, part, root, parts;
5668
5669             if (typeof className !== 'string' || className.length < 1) {
5670                 Ext.Error.raise({
5671                     sourceClass: "Ext.ClassManager",
5672                     sourceMethod: "exist",
5673                     msg: "Invalid classname, must be a string and must not be empty"
5674                 });
5675             }
5676
5677             if (this.classes.hasOwnProperty(className) || this.existCache.hasOwnProperty(className)) {
5678                 return true;
5679             }
5680
5681             root = Ext.global;
5682             parts = this.parseNamespace(className);
5683
5684             for (i = 0, ln = parts.length; i < ln; i++) {
5685                 part = parts[i];
5686
5687                 if (typeof part !== 'string') {
5688                     root = part;
5689                 } else {
5690                     if (!root || !root[part]) {
5691                         return false;
5692                     }
5693
5694                     root = root[part];
5695                 }
5696             }
5697
5698             Ext.Loader.historyPush(className);
5699
5700             this.existCache[className] = true;
5701
5702             return true;
5703         },
5704
5705         /**
5706          * Supports namespace rewriting
5707          * @private
5708          */
5709         parseNamespace: function(namespace) {
5710             if (typeof namespace !== 'string') {
5711                 Ext.Error.raise({
5712                     sourceClass: "Ext.ClassManager",
5713                     sourceMethod: "parseNamespace",
5714                     msg: "Invalid namespace, must be a string"
5715                 });
5716             }
5717
5718             var cache = this.namespaceParseCache;
5719
5720             if (this.enableNamespaceParseCache) {
5721                 if (cache.hasOwnProperty(namespace)) {
5722                     return cache[namespace];
5723                 }
5724             }
5725
5726             var parts = [],
5727                 rewrites = this.namespaceRewrites,
5728                 rewrite, from, to, i, ln, root = Ext.global;
5729
5730             for (i = 0, ln = rewrites.length; i < ln; i++) {
5731                 rewrite = rewrites[i];
5732                 from = rewrite.from;
5733                 to = rewrite.to;
5734
5735                 if (namespace === from || namespace.substring(0, from.length) === from) {
5736                     namespace = namespace.substring(from.length);
5737
5738                     if (typeof to !== 'string') {
5739                         root = to;
5740                     } else {
5741                         parts = parts.concat(to.split('.'));
5742                     }
5743
5744                     break;
5745                 }
5746             }
5747
5748             parts.push(root);
5749
5750             parts = parts.concat(namespace.split('.'));
5751
5752             if (this.enableNamespaceParseCache) {
5753                 cache[namespace] = parts;
5754             }
5755
5756             return parts;
5757         },
5758
5759         /**
5760          * Creates a namespace and assign the `value` to the created object
5761
5762     Ext.ClassManager.setNamespace('MyCompany.pkg.Example', someObject);
5763
5764     alert(MyCompany.pkg.Example === someObject); // alerts true
5765
5766          * @param {String} name
5767          * @param {Mixed} value
5768          * @markdown
5769          */
5770         setNamespace: function(name, value) {
5771             var root = Ext.global,
5772                 parts = this.parseNamespace(name),
5773                 leaf = parts.pop(),
5774                 i, ln, part;
5775
5776             for (i = 0, ln = parts.length; i < ln; i++) {
5777                 part = parts[i];
5778
5779                 if (typeof part !== 'string') {
5780                     root = part;
5781                 } else {
5782                     if (!root[part]) {
5783                         root[part] = {};
5784                     }
5785
5786                     root = root[part];
5787                 }
5788             }
5789
5790             root[leaf] = value;
5791
5792             return root[leaf];
5793         },
5794
5795         /**
5796          * The new Ext.ns, supports namespace rewriting
5797          * @private
5798          */
5799         createNamespaces: function() {
5800             var root = Ext.global,
5801                 parts, part, i, j, ln, subLn;
5802
5803             for (i = 0, ln = arguments.length; i < ln; i++) {
5804                 parts = this.parseNamespace(arguments[i]);
5805
5806                 for (j = 0, subLn = parts.length; j < subLn; j++) {
5807                     part = parts[j];
5808
5809                     if (typeof part !== 'string') {
5810                         root = part;
5811                     } else {
5812                         if (!root[part]) {
5813                             root[part] = {};
5814                         }
5815
5816                         root = root[part];
5817                     }
5818                 }
5819             }
5820
5821             return root;
5822         },
5823
5824         /**
5825          * Sets a name reference to a class.
5826          *
5827          * @param {String} name
5828          * @param {Object} value
5829          * @return {Ext.ClassManager} this
5830          */
5831         set: function(name, value) {
5832             var targetName = this.getName(value);
5833
5834             this.classes[name] = this.setNamespace(name, value);
5835
5836             if (targetName && targetName !== name) {
5837                 this.maps.alternateToName[name] = targetName;
5838             }
5839
5840             return this;
5841         },
5842
5843         /**
5844          * Retrieve a class by its name.
5845          *
5846          * @param {String} name
5847          * @return {Class} class
5848          */
5849         get: function(name) {
5850             if (this.classes.hasOwnProperty(name)) {
5851                 return this.classes[name];
5852             }
5853
5854             var root = Ext.global,
5855                 parts = this.parseNamespace(name),
5856                 part, i, ln;
5857
5858             for (i = 0, ln = parts.length; i < ln; i++) {
5859                 part = parts[i];
5860
5861                 if (typeof part !== 'string') {
5862                     root = part;
5863                 } else {
5864                     if (!root || !root[part]) {
5865                         return null;
5866                     }
5867
5868                     root = root[part];
5869                 }
5870             }
5871
5872             return root;
5873         },
5874
5875         /**
5876          * Register the alias for a class.
5877          *
5878          * @param {Class/String} cls a reference to a class or a className
5879          * @param {String} alias Alias to use when referring to this class
5880          */
5881         setAlias: function(cls, alias) {
5882             var aliasToNameMap = this.maps.aliasToName,
5883                 nameToAliasesMap = this.maps.nameToAliases,
5884                 className;
5885
5886             if (typeof cls === 'string') {
5887                 className = cls;
5888             } else {
5889                 className = this.getName(cls);
5890             }
5891
5892             if (alias && aliasToNameMap[alias] !== className) {
5893                 if (aliasToNameMap.hasOwnProperty(alias) && Ext.isDefined(Ext.global.console)) {
5894                     Ext.global.console.log("[Ext.ClassManager] Overriding existing alias: '" + alias + "' " +
5895                         "of: '" + aliasToNameMap[alias] + "' with: '" + className + "'. Be sure it's intentional.");
5896                 }
5897
5898                 aliasToNameMap[alias] = className;
5899             }
5900
5901             if (!nameToAliasesMap[className]) {
5902                 nameToAliasesMap[className] = [];
5903             }
5904
5905             if (alias) {
5906                 Ext.Array.include(nameToAliasesMap[className], alias);
5907             }
5908
5909             return this;
5910         },
5911
5912         /**
5913          * Get a reference to the class by its alias.
5914          *
5915          * @param {String} alias
5916          * @return {Class} class
5917          */
5918         getByAlias: function(alias) {
5919             return this.get(this.getNameByAlias(alias));
5920         },
5921
5922         /**
5923          * Get the name of a class by its alias.
5924          *
5925          * @param {String} alias
5926          * @return {String} className
5927          */
5928         getNameByAlias: function(alias) {
5929             return this.maps.aliasToName[alias] || '';
5930         },
5931
5932         /**
5933          * Get the name of a class by its alternate name.
5934          *
5935          * @param {String} alternate
5936          * @return {String} className
5937          */
5938         getNameByAlternate: function(alternate) {
5939             return this.maps.alternateToName[alternate] || '';
5940         },
5941
5942         /**
5943          * Get the aliases of a class by the class name
5944          *
5945          * @param {String} name
5946          * @return {Array} aliases
5947          */
5948         getAliasesByName: function(name) {
5949             return this.maps.nameToAliases[name] || [];
5950         },
5951
5952         /**
5953          * Get the name of the class by its reference or its instance;
5954          * usually invoked by the shorthand {@link Ext#getClassName Ext.getClassName}
5955
5956     Ext.ClassManager.getName(Ext.Action); // returns "Ext.Action"
5957
5958          * @param {Class/Object} object
5959          * @return {String} className
5960          * @markdown
5961          */
5962         getName: function(object) {
5963             return object && object.$className || '';
5964         },
5965
5966         /**
5967          * Get the class of the provided object; returns null if it's not an instance
5968          * of any class created with Ext.define. This is usually invoked by the shorthand {@link Ext#getClass Ext.getClass}
5969          *
5970     var component = new Ext.Component();
5971
5972     Ext.ClassManager.getClass(component); // returns Ext.Component
5973              *
5974          * @param {Object} object
5975          * @return {Class} class
5976          * @markdown
5977          */
5978         getClass: function(object) {
5979             return object && object.self || null;
5980         },
5981
5982         /**
5983          * Defines a class. This is usually invoked via the alias {@link Ext#define Ext.define}
5984
5985     Ext.ClassManager.create('My.awesome.Class', {
5986         someProperty: 'something',
5987         someMethod: function() { ... }
5988         ...
5989
5990     }, function() {
5991         alert('Created!');
5992         alert(this === My.awesome.Class); // alerts true
5993
5994         var myInstance = new this();
5995     });
5996
5997          * @param {String} className The class name to create in string dot-namespaced format, for example:
5998          * 'My.very.awesome.Class', 'FeedViewer.plugin.CoolPager'
5999          * It is highly recommended to follow this simple convention:
6000
6001 - The root and the class name are 'CamelCased'
6002 - Everything else is lower-cased
6003
6004          * @param {Object} data The key - value pairs of properties to apply to this class. Property names can be of any valid
6005          * strings, except those in the reserved listed below:
6006
6007 - `mixins`
6008 - `statics`
6009 - `config`
6010 - `alias`
6011 - `self`
6012 - `singleton`
6013 - `alternateClassName`
6014          *
6015          * @param {Function} createdFn Optional callback to execute after the class is created, the execution scope of which
6016          * (`this`) will be the newly created class itself.
6017          * @return {Ext.Base}
6018          * @markdown
6019          */
6020         create: function(className, data, createdFn) {
6021             var manager = this;
6022
6023             if (typeof className !== 'string') {
6024                 Ext.Error.raise({
6025                     sourceClass: "Ext",
6026                     sourceMethod: "define",
6027                     msg: "Invalid class name '" + className + "' specified, must be a non-empty string"
6028                 });
6029             }
6030
6031             data.$className = className;
6032
6033             return new Class(data, function() {
6034                 var postprocessorStack = data.postprocessors || manager.defaultPostprocessors,
6035                     registeredPostprocessors = manager.postprocessors,
6036                     index = 0,
6037                     postprocessors = [],
6038                     postprocessor, postprocessors, process, i, ln;
6039
6040                 delete data.postprocessors;
6041
6042                 for (i = 0, ln = postprocessorStack.length; i < ln; i++) {
6043                     postprocessor = postprocessorStack[i];
6044
6045                     if (typeof postprocessor === 'string') {
6046                         postprocessor = registeredPostprocessors[postprocessor];
6047
6048                         if (!postprocessor.always) {
6049                             if (data[postprocessor.name] !== undefined) {
6050                                 postprocessors.push(postprocessor.fn);
6051                             }
6052                         }
6053                         else {
6054                             postprocessors.push(postprocessor.fn);
6055                         }
6056                     }
6057                     else {
6058                         postprocessors.push(postprocessor);
6059                     }
6060                 }
6061
6062                 process = function(clsName, cls, clsData) {
6063                     postprocessor = postprocessors[index++];
6064
6065                     if (!postprocessor) {
6066                         manager.set(className, cls);
6067
6068                         Ext.Loader.historyPush(className);
6069
6070                         if (createdFn) {
6071                             createdFn.call(cls, cls);
6072                         }
6073
6074                         return;
6075                     }
6076
6077                     if (postprocessor.call(this, clsName, cls, clsData, process) !== false) {
6078                         process.apply(this, arguments);
6079                     }
6080                 };
6081
6082                 process.call(manager, className, this, data);
6083             });
6084         },
6085
6086         /**
6087          * Instantiate a class by its alias; usually invoked by the convenient shorthand {@link Ext#createByAlias Ext.createByAlias}
6088          * If {@link Ext.Loader} is {@link Ext.Loader#setConfig enabled} and the class has not been defined yet, it will
6089          * attempt to load the class via synchronous loading.
6090
6091     var window = Ext.ClassManager.instantiateByAlias('widget.window', { width: 600, height: 800, ... });
6092
6093          * @param {String} alias
6094          * @param {Mixed} args,... Additional arguments after the alias will be passed to the
6095          * class constructor.
6096          * @return {Object} instance
6097          * @markdown
6098          */
6099         instantiateByAlias: function() {
6100             var alias = arguments[0],
6101                 args = slice.call(arguments),
6102                 className = this.getNameByAlias(alias);
6103
6104             if (!className) {
6105                 className = this.maps.aliasToName[alias];
6106
6107                 if (!className) {
6108                     Ext.Error.raise({
6109                         sourceClass: "Ext",
6110                         sourceMethod: "createByAlias",
6111                         msg: "Cannot create an instance of unrecognized alias: " + alias
6112                     });
6113                 }
6114
6115                 if (Ext.global.console) {
6116                     Ext.global.console.warn("[Ext.Loader] Synchronously loading '" + className + "'; consider adding " +
6117                          "Ext.require('" + alias + "') above Ext.onReady");
6118                 }
6119
6120                 Ext.syncRequire(className);
6121             }
6122
6123             args[0] = className;
6124
6125             return this.instantiate.apply(this, args);
6126         },
6127
6128         /**
6129          * Instantiate a class by either full name, alias or alternate name; usually invoked by the convenient
6130          * shorthand {@link Ext#create Ext.create}
6131          *
6132          * If {@link Ext.Loader} is {@link Ext.Loader#setConfig enabled} and the class has not been defined yet, it will
6133          * attempt to load the class via synchronous loading.
6134          *
6135          * For example, all these three lines return the same result:
6136
6137     // alias
6138     var window = Ext.ClassManager.instantiate('widget.window', { width: 600, height: 800, ... });
6139
6140     // alternate name
6141     var window = Ext.ClassManager.instantiate('Ext.Window', { width: 600, height: 800, ... });
6142
6143     // full class name
6144     var window = Ext.ClassManager.instantiate('Ext.window.Window', { width: 600, height: 800, ... });
6145
6146          * @param {String} name
6147          * @param {Mixed} args,... Additional arguments after the name will be passed to the class' constructor.
6148          * @return {Object} instance
6149          * @markdown
6150          */
6151         instantiate: function() {
6152             var name = arguments[0],
6153                 args = slice.call(arguments, 1),
6154                 alias = name,
6155                 possibleName, cls;
6156
6157             if (typeof name !== 'function') {
6158                 if ((typeof name !== 'string' || name.length < 1)) {
6159                     Ext.Error.raise({
6160                         sourceClass: "Ext",
6161                         sourceMethod: "create",
6162                         msg: "Invalid class name or alias '" + name + "' specified, must be a non-empty string"
6163                     });
6164                 }
6165
6166                 cls = this.get(name);
6167             }
6168             else {
6169                 cls = name;
6170             }
6171
6172             // No record of this class name, it's possibly an alias, so look it up
6173             if (!cls) {
6174                 possibleName = this.getNameByAlias(name);
6175
6176                 if (possibleName) {
6177                     name = possibleName;
6178
6179                     cls = this.get(name);
6180                 }
6181             }
6182
6183             // Still no record of this class name, it's possibly an alternate name, so look it up
6184             if (!cls) {
6185                 possibleName = this.getNameByAlternate(name);
6186
6187                 if (possibleName) {
6188                     name = possibleName;
6189
6190                     cls = this.get(name);
6191                 }
6192             }
6193
6194             // Still not existing at this point, try to load it via synchronous mode as the last resort
6195             if (!cls) {
6196                 if (Ext.global.console) {
6197                     Ext.global.console.warn("[Ext.Loader] Synchronously loading '" + name + "'; consider adding " +
6198                          "Ext.require('" + ((possibleName) ? alias : name) + "') above Ext.onReady");
6199                 }
6200
6201                 Ext.syncRequire(name);
6202
6203                 cls = this.get(name);
6204             }
6205
6206             if (!cls) {
6207                 Ext.Error.raise({
6208                     sourceClass: "Ext",
6209                     sourceMethod: "create",
6210                     msg: "Cannot create an instance of unrecognized class name / alias: " + alias
6211                 });
6212             }
6213
6214             if (typeof cls !== 'function') {
6215                 Ext.Error.raise({
6216                     sourceClass: "Ext",
6217                     sourceMethod: "create",
6218                     msg: "'" + name + "' is a singleton and cannot be instantiated"
6219                 });
6220             }
6221
6222             if (!this.instantiationCounts[name]) {
6223                 this.instantiationCounts[name] = 0;
6224             }
6225
6226             this.instantiationCounts[name]++;
6227
6228             return this.getInstantiator(args.length)(cls, args);
6229         },
6230
6231         /**
6232          * @private
6233          * @param name
6234          * @param args
6235          */
6236         dynInstantiate: function(name, args) {
6237             args = Ext.Array.from(args, true);
6238             args.unshift(name);
6239
6240             return this.instantiate.apply(this, args);
6241         },
6242
6243         /**
6244          * @private
6245          * @param length
6246          */
6247         getInstantiator: function(length) {
6248             if (!this.instantiators[length]) {
6249                 var i = length,
6250                     args = [];
6251
6252                 for (i = 0; i < length; i++) {
6253                     args.push('a['+i+']');
6254                 }
6255
6256                 this.instantiators[length] = new Function('c', 'a', 'return new c('+args.join(',')+')');
6257             }
6258
6259             return this.instantiators[length];
6260         },
6261
6262         /**
6263          * @private
6264          */
6265         postprocessors: {},
6266
6267         /**
6268          * @private
6269          */
6270         defaultPostprocessors: [],
6271
6272         /**
6273          * Register a post-processor function.
6274          *
6275          * @param {String} name
6276          * @param {Function} postprocessor
6277          */
6278         registerPostprocessor: function(name, fn, always) {
6279             this.postprocessors[name] = {
6280                 name: name,
6281                 always: always ||  false,
6282                 fn: fn
6283             };
6284
6285             return this;
6286         },
6287
6288         /**
6289          * Set the default post processors array stack which are applied to every class.
6290          *
6291          * @param {String/Array} The name of a registered post processor or an array of registered names.
6292          * @return {Ext.ClassManager} this
6293          */
6294         setDefaultPostprocessors: function(postprocessors) {
6295             this.defaultPostprocessors = Ext.Array.from(postprocessors);
6296
6297             return this;
6298         },
6299
6300         /**
6301          * Insert this post-processor at a specific position in the stack, optionally relative to
6302          * any existing post-processor
6303          *
6304          * @param {String} name The post-processor name. Note that it needs to be registered with
6305          * {@link Ext.ClassManager#registerPostprocessor} before this
6306          * @param {String} offset The insertion position. Four possible values are:
6307          * 'first', 'last', or: 'before', 'after' (relative to the name provided in the third argument)
6308          * @param {String} relativeName
6309          * @return {Ext.ClassManager} this
6310          */
6311         setDefaultPostprocessorPosition: function(name, offset, relativeName) {
6312             var defaultPostprocessors = this.defaultPostprocessors,
6313                 index;
6314
6315             if (typeof offset === 'string') {
6316                 if (offset === 'first') {
6317                     defaultPostprocessors.unshift(name);
6318
6319                     return this;
6320                 }
6321                 else if (offset === 'last') {
6322                     defaultPostprocessors.push(name);
6323
6324                     return this;
6325                 }
6326
6327                 offset = (offset === 'after') ? 1 : -1;
6328             }
6329
6330             index = Ext.Array.indexOf(defaultPostprocessors, relativeName);
6331
6332             if (index !== -1) {
6333                 defaultPostprocessors.splice(Math.max(0, index + offset), 0, name);
6334             }
6335
6336             return this;
6337         },
6338
6339         /**
6340          * Converts a string expression to an array of matching class names. An expression can either refers to class aliases
6341          * or class names. Expressions support wildcards:
6342
6343      // returns ['Ext.window.Window']
6344     var window = Ext.ClassManager.getNamesByExpression('widget.window');
6345
6346     // returns ['widget.panel', 'widget.window', ...]
6347     var allWidgets = Ext.ClassManager.getNamesByExpression('widget.*');
6348
6349     // returns ['Ext.data.Store', 'Ext.data.ArrayProxy', ...]
6350     var allData = Ext.ClassManager.getNamesByExpression('Ext.data.*');
6351
6352          * @param {String} expression
6353          * @return {Array} classNames
6354          * @markdown
6355          */
6356         getNamesByExpression: function(expression) {
6357             var nameToAliasesMap = this.maps.nameToAliases,
6358                 names = [],
6359                 name, alias, aliases, possibleName, regex, i, ln;
6360
6361             if (typeof expression !== 'string' || expression.length < 1) {
6362                 Ext.Error.raise({
6363                     sourceClass: "Ext.ClassManager",
6364                     sourceMethod: "getNamesByExpression",
6365                     msg: "Expression " + expression + " is invalid, must be a non-empty string"
6366                 });
6367             }
6368
6369             if (expression.indexOf('*') !== -1) {
6370                 expression = expression.replace(/\*/g, '(.*?)');
6371                 regex = new RegExp('^' + expression + '$');
6372
6373                 for (name in nameToAliasesMap) {
6374                     if (nameToAliasesMap.hasOwnProperty(name)) {
6375                         aliases = nameToAliasesMap[name];
6376
6377                         if (name.search(regex) !== -1) {
6378                             names.push(name);
6379                         }
6380                         else {
6381                             for (i = 0, ln = aliases.length; i < ln; i++) {
6382                                 alias = aliases[i];
6383
6384                                 if (alias.search(regex) !== -1) {
6385                                     names.push(name);
6386                                     break;
6387                                 }
6388                             }
6389                         }
6390                     }
6391                 }
6392
6393             } else {
6394                 possibleName = this.getNameByAlias(expression);
6395
6396                 if (possibleName) {
6397                     names.push(possibleName);
6398                 } else {
6399                     possibleName = this.getNameByAlternate(expression);
6400
6401                     if (possibleName) {
6402                         names.push(possibleName);
6403                     } else {
6404                         names.push(expression);
6405                     }
6406                 }
6407             }
6408
6409             return names;
6410         }
6411     };
6412
6413     Manager.registerPostprocessor('alias', function(name, cls, data) {
6414         var aliases = data.alias,
6415             widgetPrefix = 'widget.',
6416             i, ln, alias;
6417
6418         if (!(aliases instanceof Array)) {
6419             aliases = [aliases];
6420         }
6421
6422         for (i = 0, ln = aliases.length; i < ln; i++) {
6423             alias = aliases[i];
6424
6425             if (typeof alias !== 'string') {
6426                 Ext.Error.raise({
6427                     sourceClass: "Ext",
6428                     sourceMethod: "define",
6429                     msg: "Invalid alias of: '" + alias + "' for class: '" + name + "'; must be a valid string"
6430                 });
6431             }
6432
6433             this.setAlias(cls, alias);
6434         }
6435
6436         // This is ugly, will change to make use of parseNamespace for alias later on
6437         for (i = 0, ln = aliases.length; i < ln; i++) {
6438             alias = aliases[i];
6439
6440             if (alias.substring(0, widgetPrefix.length) === widgetPrefix) {
6441                 // Only the first alias with 'widget.' prefix will be used for xtype
6442                 cls.xtype = cls.$xtype = alias.substring(widgetPrefix.length);
6443                 break;
6444             }
6445         }
6446     });
6447
6448     Manager.registerPostprocessor('singleton', function(name, cls, data, fn) {
6449         fn.call(this, name, new cls(), data);
6450         return false;
6451     });
6452
6453     Manager.registerPostprocessor('alternateClassName', function(name, cls, data) {
6454         var alternates = data.alternateClassName,
6455             i, ln, alternate;
6456
6457         if (!(alternates instanceof Array)) {
6458             alternates = [alternates];
6459         }
6460
6461         for (i = 0, ln = alternates.length; i < ln; i++) {
6462             alternate = alternates[i];
6463
6464             if (typeof alternate !== 'string') {
6465                 Ext.Error.raise({
6466                     sourceClass: "Ext",
6467                     sourceMethod: "define",
6468                     msg: "Invalid alternate of: '" + alternate + "' for class: '" + name + "'; must be a valid string"
6469                 });
6470             }
6471
6472             this.set(alternate, cls);
6473         }
6474     });
6475
6476     Manager.setDefaultPostprocessors(['alias', 'singleton', 'alternateClassName']);
6477
6478     Ext.apply(Ext, {
6479         /**
6480          * Convenient shorthand, see {@link Ext.ClassManager#instantiate}
6481          * @member Ext
6482          * @method create
6483          */
6484         create: alias(Manager, 'instantiate'),
6485
6486         /**
6487          * @private
6488          * API to be stablized
6489          *
6490          * @param {Mixed} item
6491          * @param {String} namespace
6492          */
6493         factory: function(item, namespace) {
6494             if (item instanceof Array) {
6495                 var i, ln;
6496
6497                 for (i = 0, ln = item.length; i < ln; i++) {
6498                     item[i] = Ext.factory(item[i], namespace);
6499                 }
6500
6501                 return item;
6502             }
6503
6504             var isString = (typeof item === 'string');
6505
6506             if (isString || (item instanceof Object && item.constructor === Object)) {
6507                 var name, config = {};
6508
6509                 if (isString) {
6510                     name = item;
6511                 }
6512                 else {
6513                     name = item.className;
6514                     config = item;
6515                     delete config.className;
6516                 }
6517
6518                 if (namespace !== undefined && name.indexOf(namespace) === -1) {
6519                     name = namespace + '.' + Ext.String.capitalize(name);
6520                 }
6521
6522                 return Ext.create(name, config);
6523             }
6524
6525             if (typeof item === 'function') {
6526                 return Ext.create(item);
6527             }
6528
6529             return item;
6530         },
6531
6532         /**
6533          * Convenient shorthand to create a widget by its xtype, also see {@link Ext.ClassManager#instantiateByAlias}
6534
6535     var button = Ext.widget('button'); // Equivalent to Ext.create('widget.button')
6536     var panel = Ext.widget('panel'); // Equivalent to Ext.create('widget.panel')
6537
6538          * @member Ext
6539          * @method widget
6540          * @markdown
6541          */
6542         widget: function(name) {
6543             var args = slice.call(arguments);
6544             args[0] = 'widget.' + name;
6545
6546             return Manager.instantiateByAlias.apply(Manager, args);
6547         },
6548
6549         /**
6550          * Convenient shorthand, see {@link Ext.ClassManager#instantiateByAlias}
6551          * @member Ext
6552          * @method createByAlias
6553          */
6554         createByAlias: alias(Manager, 'instantiateByAlias'),
6555
6556         /**
6557          * Convenient shorthand for {@link Ext.ClassManager#create}, see detailed {@link Ext.Class explanation}
6558          * @member Ext
6559          * @method define
6560          */
6561         define: alias(Manager, 'create'),
6562
6563         /**
6564          * Convenient shorthand, see {@link Ext.ClassManager#getName}
6565          * @member Ext
6566          * @method getClassName
6567          */
6568         getClassName: alias(Manager, 'getName'),
6569
6570         /**
6571          *
6572          * @param {Mixed} object
6573          */
6574         getDisplayName: function(object) {
6575             if (object.displayName) {
6576                 return object.displayName;
6577             }
6578
6579             if (object.$name && object.$class) {
6580                 return Ext.getClassName(object.$class) + '#' + object.$name;
6581             }
6582
6583             if (object.$className) {
6584                 return object.$className;
6585             }
6586
6587             return 'Anonymous';
6588         },
6589
6590         /**
6591          * Convenient shorthand, see {@link Ext.ClassManager#getClass}
6592          * @member Ext
6593          * @method getClassName
6594          */
6595         getClass: alias(Manager, 'getClass'),
6596
6597         /**
6598          * Creates namespaces to be used for scoping variables and classes so that they are not global.
6599          * Specifying the last node of a namespace implicitly creates all other nodes. Usage:
6600
6601     Ext.namespace('Company', 'Company.data');
6602
6603      // equivalent and preferable to the above syntax
6604     Ext.namespace('Company.data');
6605
6606     Company.Widget = function() { ... };
6607
6608     Company.data.CustomStore = function(config) { ... };
6609
6610          * @param {String} namespace1
6611          * @param {String} namespace2
6612          * @param {String} etc
6613          * @return {Object} The namespace object. (If multiple arguments are passed, this will be the last namespace created)
6614          * @function
6615          * @member Ext
6616          * @method namespace
6617          * @markdown
6618          */
6619         namespace: alias(Manager, 'createNamespaces')
6620     });
6621
6622     Ext.createWidget = Ext.widget;
6623
6624     /**
6625      * Convenient alias for {@link Ext#namespace Ext.namespace}
6626      * @member Ext
6627      * @method ns
6628      */
6629     Ext.ns = Ext.namespace;
6630
6631     Class.registerPreprocessor('className', function(cls, data) {
6632         if (data.$className) {
6633             cls.$className = data.$className;
6634             cls.displayName = cls.$className;
6635         }
6636     }, true);
6637
6638     Class.setDefaultPreprocessorPosition('className', 'first');
6639
6640 })(Ext.Class, Ext.Function.alias);
6641
6642 /**
6643  * @author Jacky Nguyen <jacky@sencha.com>
6644  * @docauthor Jacky Nguyen <jacky@sencha.com>
6645  * @class Ext.Loader
6646  *
6647
6648 Ext.Loader is the heart of the new dynamic dependency loading capability in Ext JS 4+. It is most commonly used
6649 via the {@link Ext#require} shorthand. Ext.Loader supports both asynchronous and synchronous loading
6650 approaches, and leverage their advantages for the best development flow. We'll discuss about the pros and cons of each approach:
6651
6652 # Asynchronous Loading #
6653
6654 - Advantages:
6655         + Cross-domain
6656         + No web server needed: you can run the application via the file system protocol (i.e: `file://path/to/your/index
6657  .html`)
6658         + Best possible debugging experience: error messages come with the exact file name and line number
6659
6660 - Disadvantages:
6661         + Dependencies need to be specified before-hand
6662
6663 ### Method 1: Explicitly include what you need: ###
6664
6665     // Syntax
6666     Ext.require({String/Array} expressions);
6667
6668     // Example: Single alias
6669     Ext.require('widget.window');
6670
6671     // Example: Single class name
6672     Ext.require('Ext.window.Window');
6673
6674     // Example: Multiple aliases / class names mix
6675     Ext.require(['widget.window', 'layout.border', 'Ext.data.Connection']);
6676
6677     // Wildcards
6678     Ext.require(['widget.*', 'layout.*', 'Ext.data.*']);
6679
6680 ### Method 2: Explicitly exclude what you don't need: ###
6681
6682     // Syntax: Note that it must be in this chaining format.
6683     Ext.exclude({String/Array} expressions)
6684        .require({String/Array} expressions);
6685
6686     // Include everything except Ext.data.*
6687     Ext.exclude('Ext.data.*').require('*'); 
6688
6689     // Include all widgets except widget.checkbox*,
6690     // which will match widget.checkbox, widget.checkboxfield, widget.checkboxgroup, etc.
6691     Ext.exclude('widget.checkbox*').require('widget.*');
6692
6693 # Synchronous Loading on Demand #
6694
6695 - *Advantages:*
6696         + There's no need to specify dependencies before-hand, which is always the convenience of including ext-all.js
6697  before
6698
6699 - *Disadvantages:*
6700         + Not as good debugging experience since file name won't be shown (except in Firebug at the moment)
6701         + Must be from the same domain due to XHR restriction
6702         + Need a web server, same reason as above
6703
6704 There's one simple rule to follow: Instantiate everything with Ext.create instead of the `new` keyword
6705
6706     Ext.create('widget.window', { ... }); // Instead of new Ext.window.Window({...});
6707
6708     Ext.create('Ext.window.Window', {}); // Same as above, using full class name instead of alias
6709
6710     Ext.widget('window', {}); // Same as above, all you need is the traditional `xtype`
6711
6712 Behind the scene, {@link Ext.ClassManager} will automatically check whether the given class name / alias has already
6713  existed on the page. If it's not, Ext.Loader will immediately switch itself to synchronous mode and automatic load the given
6714  class and all its dependencies.
6715
6716 # Hybrid Loading - The Best of Both Worlds #
6717
6718 It has all the advantages combined from asynchronous and synchronous loading. The development flow is simple:
6719
6720 ### Step 1: Start writing your application using synchronous approach. Ext.Loader will automatically fetch all
6721  dependencies on demand as they're needed during run-time. For example: ###
6722
6723     Ext.onReady(function(){
6724         var window = Ext.createWidget('window', {
6725             width: 500,
6726             height: 300,
6727             layout: {
6728                 type: 'border',
6729                 padding: 5
6730             },
6731             title: 'Hello Dialog',
6732             items: [{
6733                 title: 'Navigation',
6734                 collapsible: true,
6735                 region: 'west',
6736                 width: 200,
6737                 html: 'Hello',
6738                 split: true
6739             }, {
6740                 title: 'TabPanel',
6741                 region: 'center'
6742             }]
6743         });
6744
6745         window.show();
6746     })
6747
6748 ### Step 2: Along the way, when you need better debugging ability, watch the console for warnings like these: ###
6749
6750     [Ext.Loader] Synchronously loading 'Ext.window.Window'; consider adding Ext.require('Ext.window.Window') before your application's code
6751     ClassManager.js:432
6752     [Ext.Loader] Synchronously loading 'Ext.layout.container.Border'; consider adding Ext.require('Ext.layout.container.Border') before your application's code
6753
6754 Simply copy and paste the suggested code above `Ext.onReady`, i.e:
6755
6756     Ext.require('Ext.window.Window');
6757     Ext.require('Ext.layout.container.Border');
6758
6759     Ext.onReady(...);
6760
6761 Everything should now load via asynchronous mode.
6762
6763 # Deployment #
6764
6765 It's important to note that dynamic loading should only be used during development on your local machines.
6766 During production, all dependencies should be combined into one single JavaScript file. Ext.Loader makes
6767 the whole process of transitioning from / to between development / maintenance and production as easy as
6768 possible. Internally {@link Ext.Loader#history Ext.Loader.history} maintains the list of all dependencies your application
6769 needs in the exact loading sequence. It's as simple as concatenating all files in this array into one,
6770 then include it on top of your application.
6771
6772 This process will be automated with Sencha Command, to be released and documented towards Ext JS 4 Final.
6773
6774  * @singleton
6775  * @markdown
6776  */
6777
6778 (function(Manager, Class, flexSetter, alias) {
6779
6780     var
6781         dependencyProperties = ['extend', 'mixins', 'requires'],
6782         Loader;
6783
6784     Loader = Ext.Loader = {
6785         /**
6786          * @private
6787          */
6788         documentHead: typeof document !== 'undefined' && (document.head || document.getElementsByTagName('head')[0]),
6789
6790         /**
6791          * Flag indicating whether there are still files being loaded
6792          * @private
6793          */
6794         isLoading: false,
6795
6796         /**
6797          * Maintain the queue for all dependencies. Each item in the array is an object of the format:
6798          * {
6799          *      requires: [...], // The required classes for this queue item
6800          *      callback: function() { ... } // The function to execute when all classes specified in requires exist
6801          * }
6802          * @private
6803          */
6804         queue: [],
6805
6806         /**
6807          * Maintain the list of files that have already been handled so that they never get double-loaded
6808          * @private
6809          */
6810         isFileLoaded: {},
6811
6812         /**
6813          * Maintain the list of listeners to execute when all required scripts are fully loaded
6814          * @private
6815          */
6816         readyListeners: [],
6817
6818         /**
6819          * Contains optional dependencies to be loaded last
6820          * @private
6821          */
6822         optionalRequires: [],
6823
6824         /**
6825          * Map of fully qualified class names to an array of dependent classes.
6826          * @private
6827          */
6828         requiresMap: {},
6829
6830         /**
6831          * @private
6832          */
6833         numPendingFiles: 0,
6834
6835         /**
6836          * @private
6837          */
6838         numLoadedFiles: 0,
6839
6840         /** @private */
6841         hasFileLoadError: false,
6842
6843         /**
6844          * @private
6845          */
6846         classNameToFilePathMap: {},
6847
6848         /**
6849          * An array of class names to keep track of the dependency loading order.
6850          * This is not guaranteed to be the same everytime due to the asynchronous
6851          * nature of the Loader.
6852          *
6853          * @property history
6854          * @type Array
6855          */
6856         history: [],
6857
6858         /**
6859          * Configuration
6860          * @private
6861          */
6862         config: {
6863             /**
6864              * Whether or not to enable the dynamic dependency loading feature
6865              * Defaults to false
6866              * @cfg {Boolean} enabled
6867              */
6868             enabled: false,
6869
6870             /**
6871              * @cfg {Boolean} disableCaching
6872              * Appends current timestamp to script files to prevent caching
6873              * Defaults to true
6874              */
6875             disableCaching: true,
6876
6877             /**
6878              * @cfg {String} disableCachingParam
6879              * The get parameter name for the cache buster's timestamp.
6880              * Defaults to '_dc'
6881              */
6882             disableCachingParam: '_dc',
6883
6884             /**
6885              * @cfg {Object} paths
6886              * The mapping from namespaces to file paths
6887     {
6888         'Ext': '.', // This is set by default, Ext.layout.container.Container will be
6889                     // loaded from ./layout/Container.js
6890
6891         'My': './src/my_own_folder' // My.layout.Container will be loaded from
6892                                     // ./src/my_own_folder/layout/Container.js
6893     }
6894              * Note that all relative paths are relative to the current HTML document.
6895              * If not being specified, for example, <code>Other.awesome.Class</code>
6896              * will simply be loaded from <code>./Other/awesome/Class.js</code>
6897              */
6898             paths: {
6899                 'Ext': '.'
6900             }
6901         },
6902
6903         /**
6904          * Set the configuration for the loader. This should be called right after ext-core.js
6905          * (or ext-core-debug.js) is included in the page, i.e:
6906
6907     <script type="text/javascript" src="ext-core-debug.js"></script>
6908     <script type="text/javascript">
6909       Ext.Loader.setConfig({
6910           enabled: true,
6911           paths: {
6912               'My': 'my_own_path'
6913           }
6914       });
6915     <script>
6916     <script type="text/javascript">
6917       Ext.require(...);
6918
6919       Ext.onReady(function() {
6920           // application code here
6921       });
6922     </script>
6923
6924          * Refer to {@link Ext.Loader#configs} for the list of possible properties
6925          *
6926          * @param {Object} config The config object to override the default values in {@link Ext.Loader#config}
6927          * @return {Ext.Loader} this
6928          * @markdown
6929          */
6930         setConfig: function(name, value) {
6931             if (Ext.isObject(name) && arguments.length === 1) {
6932                 Ext.Object.merge(this.config, name);
6933             }
6934             else {
6935                 this.config[name] = (Ext.isObject(value)) ? Ext.Object.merge(this.config[name], value) : value;
6936             }
6937
6938             return this;
6939         },
6940
6941         /**
6942          * Get the config value corresponding to the specified name. If no name is given, will return the config object
6943          * @param {String} name The config property name
6944          * @return {Object/Mixed}
6945          */
6946         getConfig: function(name) {
6947             if (name) {
6948                 return this.config[name];
6949             }
6950
6951             return this.config;
6952         },
6953
6954         /**
6955          * Sets the path of a namespace.
6956          * For Example:
6957
6958     Ext.Loader.setPath('Ext', '.');
6959
6960          * @param {String/Object} name See {@link Ext.Function#flexSetter flexSetter}
6961          * @param {String} path See {@link Ext.Function#flexSetter flexSetter}
6962          * @return {Ext.Loader} this
6963          * @method
6964          * @markdown
6965          */
6966         setPath: flexSetter(function(name, path) {
6967             this.config.paths[name] = path;
6968
6969             return this;
6970         }),
6971
6972         /**
6973          * Translates a className to a file path by adding the
6974          * the proper prefix and converting the .'s to /'s. For example:
6975
6976     Ext.Loader.setPath('My', '/path/to/My');
6977
6978     alert(Ext.Loader.getPath('My.awesome.Class')); // alerts '/path/to/My/awesome/Class.js'
6979
6980          * Note that the deeper namespace levels, if explicitly set, are always resolved first. For example:
6981
6982     Ext.Loader.setPath({
6983         'My': '/path/to/lib',
6984         'My.awesome': '/other/path/for/awesome/stuff',
6985         'My.awesome.more': '/more/awesome/path'
6986     });
6987
6988     alert(Ext.Loader.getPath('My.awesome.Class')); // alerts '/other/path/for/awesome/stuff/Class.js'
6989
6990     alert(Ext.Loader.getPath('My.awesome.more.Class')); // alerts '/more/awesome/path/Class.js'
6991
6992     alert(Ext.Loader.getPath('My.cool.Class')); // alerts '/path/to/lib/cool/Class.js'
6993
6994     alert(Ext.Loader.getPath('Unknown.strange.Stuff')); // alerts 'Unknown/strange/Stuff.js'
6995
6996          * @param {String} className
6997          * @return {String} path
6998          * @markdown
6999          */
7000         getPath: function(className) {
7001             var path = '',
7002                 paths = this.config.paths,
7003                 prefix = this.getPrefix(className);
7004
7005             if (prefix.length > 0) {
7006                 if (prefix === className) {
7007                     return paths[prefix];
7008                 }
7009
7010                 path = paths[prefix];
7011                 className = className.substring(prefix.length + 1);
7012             }
7013
7014             if (path.length > 0) {
7015                 path += '/';
7016             }
7017
7018             return path.replace(/\/\.\//g, '/') + className.replace(/\./g, "/") + '.js';
7019         },
7020
7021         /**
7022          * @private
7023          * @param {String} className
7024          */
7025         getPrefix: function(className) {
7026             var paths = this.config.paths,
7027                 prefix, deepestPrefix = '';
7028
7029             if (paths.hasOwnProperty(className)) {
7030                 return className;
7031             }
7032
7033             for (prefix in paths) {
7034                 if (paths.hasOwnProperty(prefix) && prefix + '.' === className.substring(0, prefix.length + 1)) {
7035                     if (prefix.length > deepestPrefix.length) {
7036                         deepestPrefix = prefix;
7037                     }
7038                 }
7039             }
7040
7041             return deepestPrefix;
7042         },
7043
7044         /**
7045          * Refresh all items in the queue. If all dependencies for an item exist during looping,
7046          * it will execute the callback and call refreshQueue again. Triggers onReady when the queue is
7047          * empty
7048          * @private
7049          */
7050         refreshQueue: function() {
7051             var ln = this.queue.length,
7052                 i, item, j, requires;
7053
7054             if (ln === 0) {
7055                 this.triggerReady();
7056                 return;
7057             }
7058
7059             for (i = 0; i < ln; i++) {
7060                 item = this.queue[i];
7061
7062                 if (item) {
7063                     requires = item.requires;
7064
7065                     // Don't bother checking when the number of files loaded
7066                     // is still less than the array length
7067                     if (requires.length > this.numLoadedFiles) {
7068                         continue;
7069                     }
7070
7071                     j = 0;
7072
7073                     do {
7074                         if (Manager.isCreated(requires[j])) {
7075                             // Take out from the queue
7076                             requires.splice(j, 1);
7077                         }
7078                         else {
7079                             j++;
7080                         }
7081                     } while (j < requires.length);
7082
7083                     if (item.requires.length === 0) {
7084                         this.queue.splice(i, 1);
7085                         item.callback.call(item.scope);
7086                         this.refreshQueue();
7087                         break;
7088                     }
7089                 }
7090             }
7091
7092             return this;
7093         },
7094
7095         /**
7096          * Inject a script element to document's head, call onLoad and onError accordingly
7097          * @private
7098          */
7099         injectScriptElement: function(url, onLoad, onError, scope) {
7100             var script = document.createElement('script'),
7101                 me = this,
7102                 onLoadFn = function() {
7103                     me.cleanupScriptElement(script);
7104                     onLoad.call(scope);
7105                 },
7106                 onErrorFn = function() {
7107                     me.cleanupScriptElement(script);
7108                     onError.call(scope);
7109                 };
7110
7111             script.type = 'text/javascript';
7112             script.src = url;
7113             script.onload = onLoadFn;
7114             script.onerror = onErrorFn;
7115             script.onreadystatechange = function() {
7116                 if (this.readyState === 'loaded' || this.readyState === 'complete') {
7117                     onLoadFn();
7118                 }
7119             };
7120
7121             this.documentHead.appendChild(script);
7122
7123             return script;
7124         },
7125
7126         /**
7127          * @private
7128          */
7129         cleanupScriptElement: function(script) {
7130             script.onload = null;
7131             script.onreadystatechange = null;
7132             script.onerror = null;
7133
7134             return this;
7135         },
7136
7137         /**
7138          * Load a script file, supports both asynchronous and synchronous approaches
7139          *
7140          * @param {String} url
7141          * @param {Function} onLoad
7142          * @param {Scope} scope
7143          * @param {Boolean} synchronous
7144          * @private
7145          */
7146         loadScriptFile: function(url, onLoad, onError, scope, synchronous) {
7147             var me = this,
7148                 noCacheUrl = url + (this.getConfig('disableCaching') ? ('?' + this.getConfig('disableCachingParam') + '=' + Ext.Date.now()) : ''),
7149                 fileName = url.split('/').pop(),
7150                 isCrossOriginRestricted = false,
7151                 xhr, status, onScriptError;
7152
7153             scope = scope || this;
7154
7155             this.isLoading = true;
7156
7157             if (!synchronous) {
7158                 onScriptError = function() {
7159                     onError.call(scope, "Failed loading '" + url + "', please verify that the file exists", synchronous);
7160                 };
7161
7162                 if (!Ext.isReady && Ext.onDocumentReady) {
7163                     Ext.onDocumentReady(function() {
7164                         me.injectScriptElement(noCacheUrl, onLoad, onScriptError, scope);
7165                     });
7166                 }
7167                 else {
7168                     this.injectScriptElement(noCacheUrl, onLoad, onScriptError, scope);
7169                 }
7170             }
7171             else {
7172                 if (typeof XMLHttpRequest !== 'undefined') {
7173                     xhr = new XMLHttpRequest();
7174                 } else {
7175                     xhr = new ActiveXObject('Microsoft.XMLHTTP');
7176                 }
7177
7178                 try {
7179                     xhr.open('GET', noCacheUrl, false);
7180                     xhr.send(null);
7181                 } catch (e) {
7182                     isCrossOriginRestricted = true;
7183                 }
7184
7185                 status = (xhr.status === 1223) ? 204 : xhr.status;
7186
7187                 if (!isCrossOriginRestricted) {
7188                     isCrossOriginRestricted = (status === 0);
7189                 }
7190
7191                 if (isCrossOriginRestricted
7192                 ) {
7193                     onError.call(this, "Failed loading synchronously via XHR: '" + url + "'; It's likely that the file is either " +
7194                                        "being loaded from a different domain or from the local file system whereby cross origin " +
7195                                        "requests are not allowed due to security reasons. Use asynchronous loading with " +
7196                                        "Ext.require instead.", synchronous);
7197                 }
7198                 else if (status >= 200 && status < 300
7199                 ) {
7200                     // Firebug friendly, file names are still shown even though they're eval'ed code
7201                     new Function(xhr.responseText + "\n//@ sourceURL=" + fileName)();
7202
7203                     onLoad.call(scope);
7204                 }
7205                 else {
7206                     onError.call(this, "Failed loading synchronously via XHR: '" + url + "'; please " +
7207                                        "verify that the file exists. " +
7208                                        "XHR status code: " + status, synchronous);
7209                 }
7210
7211                 // Prevent potential IE memory leak
7212                 xhr = null;
7213             }
7214         },
7215
7216         /**
7217          * Explicitly exclude files from being loaded. Useful when used in conjunction with a broad include expression.
7218          * Can be chained with more `require` and `exclude` methods, eg:
7219
7220     Ext.exclude('Ext.data.*').require('*');
7221
7222     Ext.exclude('widget.button*').require('widget.*');
7223
7224          * @param {Array} excludes
7225          * @return {Object} object contains `require` method for chaining
7226          * @markdown
7227          */
7228         exclude: function(excludes) {
7229             var me = this;
7230
7231             return {
7232                 require: function(expressions, fn, scope) {
7233                     return me.require(expressions, fn, scope, excludes);
7234                 },
7235
7236                 syncRequire: function(expressions, fn, scope) {
7237                     return me.syncRequire(expressions, fn, scope, excludes);
7238                 }
7239             };
7240         },
7241
7242         /**
7243          * 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
7244          * @param {String/Array} expressions Can either be a string or an array of string
7245          * @param {Function} fn (Optional) The callback function
7246          * @param {Object} scope (Optional) The execution scope (`this`) of the callback function
7247          * @param {String/Array} excludes (Optional) Classes to be excluded, useful when being used with expressions
7248          * @markdown
7249          */
7250         syncRequire: function() {
7251             this.syncModeEnabled = true;
7252             this.require.apply(this, arguments);
7253             this.refreshQueue();
7254             this.syncModeEnabled = false;
7255         },
7256
7257         /**
7258          * Loads all classes by the given names and all their direct dependencies; optionally executes the given callback function when
7259          * finishes, within the optional scope. This method is aliased by {@link Ext#require Ext.require} for convenience
7260          * @param {String/Array} expressions Can either be a string or an array of string
7261          * @param {Function} fn (Optional) The callback function
7262          * @param {Object} scope (Optional) The execution scope (`this`) of the callback function
7263          * @param {String/Array} excludes (Optional) Classes to be excluded, useful when being used with expressions
7264          * @markdown
7265          */
7266         require: function(expressions, fn, scope, excludes) {
7267             var filePath, expression, exclude, className, excluded = {},
7268                 excludedClassNames = [],
7269                 possibleClassNames = [],
7270                 possibleClassName, classNames = [],
7271                 i, j, ln, subLn;
7272
7273             expressions = Ext.Array.from(expressions);
7274             excludes = Ext.Array.from(excludes);
7275
7276             fn = fn || Ext.emptyFn;
7277
7278             scope = scope || Ext.global;
7279
7280             for (i = 0, ln = excludes.length; i < ln; i++) {
7281                 exclude = excludes[i];
7282
7283                 if (typeof exclude === 'string' && exclude.length > 0) {
7284                     excludedClassNames = Manager.getNamesByExpression(exclude);
7285
7286                     for (j = 0, subLn = excludedClassNames.length; j < subLn; j++) {
7287                         excluded[excludedClassNames[j]] = true;
7288                     }
7289                 }
7290             }
7291
7292             for (i = 0, ln = expressions.length; i < ln; i++) {
7293                 expression = expressions[i];
7294
7295                 if (typeof expression === 'string' && expression.length > 0) {
7296                     possibleClassNames = Manager.getNamesByExpression(expression);
7297
7298                     for (j = 0, subLn = possibleClassNames.length; j < subLn; j++) {
7299                         possibleClassName = possibleClassNames[j];
7300
7301                         if (!excluded.hasOwnProperty(possibleClassName) && !Manager.isCreated(possibleClassName)) {
7302                             Ext.Array.include(classNames, possibleClassName);
7303                         }
7304                     }
7305                 }
7306             }
7307
7308             // If the dynamic dependency feature is not being used, throw an error
7309             // if the dependencies are not defined
7310             if (!this.config.enabled) {
7311                 if (classNames.length > 0) {
7312                     Ext.Error.raise({
7313                         sourceClass: "Ext.Loader",
7314                         sourceMethod: "require",
7315                         msg: "Ext.Loader is not enabled, so dependencies cannot be resolved dynamically. " +
7316                              "Missing required class" + ((classNames.length > 1) ? "es" : "") + ": " + classNames.join(', ')
7317                     });
7318                 }
7319             }
7320
7321             if (classNames.length === 0) {
7322                 fn.call(scope);
7323                 return this;
7324             }
7325
7326             this.queue.push({
7327                 requires: classNames,
7328                 callback: fn,
7329                 scope: scope
7330             });
7331
7332             classNames = classNames.slice();
7333
7334             for (i = 0, ln = classNames.length; i < ln; i++) {
7335                 className = classNames[i];
7336
7337                 if (!this.isFileLoaded.hasOwnProperty(className)) {
7338                     this.isFileLoaded[className] = false;
7339
7340                     filePath = this.getPath(className);
7341
7342                     this.classNameToFilePathMap[className] = filePath;
7343
7344                     this.numPendingFiles++;
7345
7346                     this.loadScriptFile(
7347                         filePath,
7348                         Ext.Function.pass(this.onFileLoaded, [className, filePath], this),
7349                         Ext.Function.pass(this.onFileLoadError, [className, filePath]),
7350                         this,
7351                         this.syncModeEnabled
7352                     );
7353                 }
7354             }
7355
7356             return this;
7357         },
7358
7359         /**
7360          * @private
7361          * @param {String} className
7362          * @param {String} filePath
7363          */
7364         onFileLoaded: function(className, filePath) {
7365             this.numLoadedFiles++;
7366
7367             this.isFileLoaded[className] = true;
7368
7369             this.numPendingFiles--;
7370
7371             if (this.numPendingFiles === 0) {
7372                 this.refreshQueue();
7373             }
7374
7375             if (this.numPendingFiles <= 1) {
7376                 window.status = "Finished loading all dependencies, onReady fired!";
7377             }
7378             else {
7379                 window.status = "Loading dependencies, " + this.numPendingFiles + " files left...";
7380             }
7381
7382             if (!this.syncModeEnabled && this.numPendingFiles === 0 && this.isLoading && !this.hasFileLoadError) {
7383                 var queue = this.queue,
7384                     requires,
7385                     i, ln, j, subLn, missingClasses = [], missingPaths = [];
7386
7387                 for (i = 0, ln = queue.length; i < ln; i++) {
7388                     requires = queue[i].requires;
7389
7390                     for (j = 0, subLn = requires.length; j < ln; j++) {
7391                         if (this.isFileLoaded[requires[j]]) {
7392                             missingClasses.push(requires[j]);
7393                         }
7394                     }
7395                 }
7396
7397                 if (missingClasses.length < 1) {
7398                     return;
7399                 }
7400
7401                 missingClasses = Ext.Array.filter(missingClasses, function(item) {
7402                     return !this.requiresMap.hasOwnProperty(item);
7403                 }, this);
7404
7405                 for (i = 0,ln = missingClasses.length; i < ln; i++) {
7406                     missingPaths.push(this.classNameToFilePathMap[missingClasses[i]]);
7407                 }
7408
7409                 Ext.Error.raise({
7410                     sourceClass: "Ext.Loader",
7411                     sourceMethod: "onFileLoaded",
7412                     msg: "The following classes are not declared even if their files have been " +
7413                             "loaded: '" + missingClasses.join("', '") + "'. Please check the source code of their " +
7414                             "corresponding files for possible typos: '" + missingPaths.join("', '") + "'"
7415                 });
7416             }
7417         },
7418
7419         /**
7420          * @private
7421          */
7422         onFileLoadError: function(className, filePath, errorMessage, isSynchronous) {
7423             this.numPendingFiles--;
7424             this.hasFileLoadError = true;
7425
7426             Ext.Error.raise({
7427                 sourceClass: "Ext.Loader",
7428                 classToLoad: className,
7429                 loadPath: filePath,
7430                 loadingType: isSynchronous ? 'synchronous' : 'async',
7431                 msg: errorMessage
7432             });
7433         },
7434
7435         /**
7436          * @private
7437          */
7438         addOptionalRequires: function(requires) {
7439             var optionalRequires = this.optionalRequires,
7440                 i, ln, require;
7441
7442             requires = Ext.Array.from(requires);
7443
7444             for (i = 0, ln = requires.length; i < ln; i++) {
7445                 require = requires[i];
7446
7447                 Ext.Array.include(optionalRequires, require);
7448             }
7449
7450             return this;
7451         },
7452
7453         /**
7454          * @private
7455          */
7456         triggerReady: function(force) {
7457             var readyListeners = this.readyListeners,
7458                 optionalRequires, listener;
7459
7460             if (this.isLoading || force) {
7461                 this.isLoading = false;
7462
7463                 if (this.optionalRequires.length) {
7464                     // Clone then empty the array to eliminate potential recursive loop issue
7465                     optionalRequires = Ext.Array.clone(this.optionalRequires);
7466
7467                     // Empty the original array
7468                     this.optionalRequires.length = 0;
7469
7470                     this.require(optionalRequires, Ext.Function.pass(this.triggerReady, [true], this), this);
7471                     return this;
7472                 }
7473
7474                 while (readyListeners.length) {
7475                     listener = readyListeners.shift();
7476                     listener.fn.call(listener.scope);
7477
7478                     if (this.isLoading) {
7479                         return this;
7480                     }
7481                 }
7482             }
7483
7484             return this;
7485         },
7486
7487         /**
7488          * Add a new listener to be executed when all required scripts are fully loaded
7489          *
7490          * @param {Function} fn The function callback to be executed
7491          * @param {Object} scope The execution scope (<code>this</code>) of the callback function
7492          * @param {Boolean} withDomReady Whether or not to wait for document dom ready as well
7493          */
7494         onReady: function(fn, scope, withDomReady, options) {
7495             var oldFn;
7496
7497             if (withDomReady !== false && Ext.onDocumentReady) {
7498                 oldFn = fn;
7499
7500                 fn = function() {
7501                     Ext.onDocumentReady(oldFn, scope, options);
7502                 };
7503             }
7504
7505             if (!this.isLoading) {
7506                 fn.call(scope);
7507             }
7508             else {
7509                 this.readyListeners.push({
7510                     fn: fn,
7511                     scope: scope
7512                 });
7513             }
7514         },
7515
7516         /**
7517          * @private
7518          * @param {String} className
7519          */
7520         historyPush: function(className) {
7521             if (className && this.isFileLoaded.hasOwnProperty(className)) {
7522                 Ext.Array.include(this.history, className);
7523             }
7524
7525             return this;
7526         }
7527     };
7528
7529     /**
7530      * Convenient alias of {@link Ext.Loader#require}. Please see the introduction documentation of
7531      * {@link Ext.Loader} for examples.
7532      * @member Ext
7533      * @method require
7534      */
7535     Ext.require = alias(Loader, 'require');
7536
7537     /**
7538      * Synchronous version of {@link Ext#require}, convenient alias of {@link Ext.Loader#syncRequire}.
7539      *
7540      * @member Ext
7541      * @method syncRequire
7542      */
7543     Ext.syncRequire = alias(Loader, 'syncRequire');
7544
7545     /**
7546      * Convenient shortcut to {@link Ext.Loader#exclude}
7547      * @member Ext
7548      * @method exclude
7549      */
7550     Ext.exclude = alias(Loader, 'exclude');
7551
7552     /**
7553      * @member Ext
7554      * @method onReady
7555      */
7556     Ext.onReady = function(fn, scope, options) {
7557         Loader.onReady(fn, scope, true, options);
7558     };
7559
7560     Class.registerPreprocessor('loader', function(cls, data, continueFn) {
7561         var me = this,
7562             dependencies = [],
7563             className = Manager.getName(cls),
7564             i, j, ln, subLn, value, propertyName, propertyValue;
7565
7566         /*
7567         Basically loop through the dependencyProperties, look for string class names and push
7568         them into a stack, regardless of whether the property's value is a string, array or object. For example:
7569         {
7570               extend: 'Ext.MyClass',
7571               requires: ['Ext.some.OtherClass'],
7572               mixins: {
7573                   observable: 'Ext.util.Observable';
7574               }
7575         }
7576         which will later be transformed into:
7577         {
7578               extend: Ext.MyClass,
7579               requires: [Ext.some.OtherClass],
7580               mixins: {
7581                   observable: Ext.util.Observable;
7582               }
7583         }
7584         */
7585
7586         for (i = 0, ln = dependencyProperties.length; i < ln; i++) {
7587             propertyName = dependencyProperties[i];
7588
7589             if (data.hasOwnProperty(propertyName)) {
7590                 propertyValue = data[propertyName];
7591
7592                 if (typeof propertyValue === 'string') {
7593                     dependencies.push(propertyValue);
7594                 }
7595                 else if (propertyValue instanceof Array) {
7596                     for (j = 0, subLn = propertyValue.length; j < subLn; j++) {
7597                         value = propertyValue[j];
7598
7599                         if (typeof value === 'string') {
7600                             dependencies.push(value);
7601                         }
7602                     }
7603                 }
7604                 else {
7605                     for (j in propertyValue) {
7606                         if (propertyValue.hasOwnProperty(j)) {
7607                             value = propertyValue[j];
7608
7609                             if (typeof value === 'string') {
7610                                 dependencies.push(value);
7611                             }
7612                         }
7613                     }
7614                 }
7615             }
7616         }
7617
7618         if (dependencies.length === 0) {
7619 //            Loader.historyPush(className);
7620             return;
7621         }
7622
7623         var deadlockPath = [],
7624             requiresMap = Loader.requiresMap,
7625             detectDeadlock;
7626
7627         /*
7628         Automatically detect deadlocks before-hand,
7629         will throw an error with detailed path for ease of debugging. Examples of deadlock cases:
7630
7631         - A extends B, then B extends A
7632         - A requires B, B requires C, then C requires A
7633
7634         The detectDeadlock function will recursively transverse till the leaf, hence it can detect deadlocks
7635         no matter how deep the path is.
7636         */
7637
7638         if (className) {
7639             requiresMap[className] = dependencies;
7640
7641             detectDeadlock = function(cls) {
7642                 deadlockPath.push(cls);
7643
7644                 if (requiresMap[cls]) {
7645                     if (Ext.Array.contains(requiresMap[cls], className)) {
7646                         Ext.Error.raise({
7647                             sourceClass: "Ext.Loader",
7648                             msg: "Deadlock detected while loading dependencies! '" + className + "' and '" +
7649                                 deadlockPath[1] + "' " + "mutually require each other. Path: " +
7650                                 deadlockPath.join(' -> ') + " -> " + deadlockPath[0]
7651                         });
7652                     }
7653
7654                     for (i = 0, ln = requiresMap[cls].length; i < ln; i++) {
7655                         detectDeadlock(requiresMap[cls][i]);
7656                     }
7657                 }
7658             };
7659
7660             detectDeadlock(className);
7661         }
7662
7663
7664         Loader.require(dependencies, function() {
7665             for (i = 0, ln = dependencyProperties.length; i < ln; i++) {
7666                 propertyName = dependencyProperties[i];
7667
7668                 if (data.hasOwnProperty(propertyName)) {
7669                     propertyValue = data[propertyName];
7670
7671                     if (typeof propertyValue === 'string') {
7672                         data[propertyName] = Manager.get(propertyValue);
7673                     }
7674                     else if (propertyValue instanceof Array) {
7675                         for (j = 0, subLn = propertyValue.length; j < subLn; j++) {
7676                             value = propertyValue[j];
7677
7678                             if (typeof value === 'string') {
7679                                 data[propertyName][j] = Manager.get(value);
7680                             }
7681                         }
7682                     }
7683                     else {
7684                         for (var k in propertyValue) {
7685                             if (propertyValue.hasOwnProperty(k)) {
7686                                 value = propertyValue[k];
7687
7688                                 if (typeof value === 'string') {
7689                                     data[propertyName][k] = Manager.get(value);
7690                                 }
7691                             }
7692                         }
7693                     }
7694                 }
7695             }
7696
7697             continueFn.call(me, cls, data);
7698         });
7699
7700         return false;
7701     }, true);
7702
7703     Class.setDefaultPreprocessorPosition('loader', 'after', 'className');
7704
7705     Manager.registerPostprocessor('uses', function(name, cls, data) {
7706         var uses = Ext.Array.from(data.uses),
7707             items = [],
7708             i, ln, item;
7709
7710         for (i = 0, ln = uses.length; i < ln; i++) {
7711             item = uses[i];
7712
7713             if (typeof item === 'string') {
7714                 items.push(item);
7715             }
7716         }
7717
7718         Loader.addOptionalRequires(items);
7719     });
7720
7721     Manager.setDefaultPostprocessorPosition('uses', 'last');
7722
7723 })(Ext.ClassManager, Ext.Class, Ext.Function.flexSetter, Ext.Function.alias);
7724
7725 /**
7726  * @class Ext.Error
7727  * @private
7728  * @extends Error
7729
7730 A wrapper class for the native JavaScript Error object that adds a few useful capabilities for handling
7731 errors in an Ext application. When you use Ext.Error to {@link #raise} an error from within any class that
7732 uses the Ext 4 class system, the Error class can automatically add the source class and method from which
7733 the error was raised. It also includes logic to automatically log the eroor to the console, if available,
7734 with additional metadata about the error. In all cases, the error will always be thrown at the end so that
7735 execution will halt.
7736
7737 Ext.Error also offers a global error {@link #handle handling} method that can be overridden in order to
7738 handle application-wide errors in a single spot. You can optionally {@link #ignore} errors altogether,
7739 although in a real application it's usually a better idea to override the handling function and perform
7740 logging or some other method of reporting the errors in a way that is meaningful to the application.
7741
7742 At its simplest you can simply raise an error as a simple string from within any code:
7743
7744 #Example usage:#
7745
7746     Ext.Error.raise('Something bad happened!');
7747
7748 If raised from plain JavaScript code, the error will be logged to the console (if available) and the message
7749 displayed. In most cases however you'll be raising errors from within a class, and it may often be useful to add
7750 additional metadata about the error being raised.  The {@link #raise} method can also take a config object.
7751 In this form the `msg` attribute becomes the error description, and any other data added to the config gets
7752 added to the error object and, if the console is available, logged to the console for inspection.
7753
7754 #Example usage:#
7755
7756     Ext.define('Ext.Foo', {
7757         doSomething: function(option){
7758             if (someCondition === false) {
7759                 Ext.Error.raise({
7760                     msg: 'You cannot do that!',
7761                     option: option,   // whatever was passed into the method
7762                     'error code': 100 // other arbitrary info
7763                 });
7764             }
7765         }
7766     });
7767
7768 If a console is available (that supports the `console.dir` function) you'll see console output like:
7769
7770     An error was raised with the following data:
7771     option:         Object { foo: "bar"}
7772         foo:        "bar"
7773     error code:     100
7774     msg:            "You cannot do that!"
7775     sourceClass:   "Ext.Foo"
7776     sourceMethod:  "doSomething"
7777
7778     uncaught exception: You cannot do that!
7779
7780 As you can see, the error will report exactly where it was raised and will include as much information as the
7781 raising code can usefully provide.
7782
7783 If you want to handle all application errors globally you can simply override the static {@link handle} method
7784 and provide whatever handling logic you need. If the method returns true then the error is considered handled
7785 and will not be thrown to the browser. If anything but true is returned then the error will be thrown normally.
7786
7787 #Example usage:#
7788
7789     Ext.Error.handle = function(err) {
7790         if (err.someProperty == 'NotReallyAnError') {
7791             // maybe log something to the application here if applicable
7792             return true;
7793         }
7794         // any non-true return value (including none) will cause the error to be thrown
7795     }
7796
7797  * Create a new Error object
7798  * @param {Object} config The config object
7799  * @markdown
7800  * @author Brian Moeskau <brian@sencha.com>
7801  * @docauthor Brian Moeskau <brian@sencha.com>
7802  */
7803 Ext.Error = Ext.extend(Error, {
7804     statics: {
7805         /**
7806          * @property ignore
7807 Static flag that can be used to globally disable error reporting to the browser if set to true
7808 (defaults to false). Note that if you ignore Ext errors it's likely that some other code may fail
7809 and throw a native JavaScript error thereafter, so use with caution. In most cases it will probably
7810 be preferable to supply a custom error {@link #handle handling} function instead.
7811
7812 #Example usage:#
7813
7814     Ext.Error.ignore = true;
7815
7816          * @markdown
7817          * @static
7818          */
7819         ignore: false,
7820
7821         /**
7822          * @property notify
7823 Static flag that can be used to globally control error notification to the user. Unlike
7824 Ex.Error.ignore, this does not effect exceptions. They are still thrown. This value can be
7825 set to false to disable the alert notification (default is true for IE6 and IE7).
7826
7827 Only the first error will generate an alert. Internally this flag is set to false when the
7828 first error occurs prior to displaying the alert.
7829
7830 This flag is not used in a release build.
7831
7832 #Example usage:#
7833
7834     Ext.Error.notify = false;
7835
7836          * @markdown
7837          * @static
7838          */
7839         //notify: Ext.isIE6 || Ext.isIE7,
7840
7841         /**
7842 Raise an error that can include additional data and supports automatic console logging if available.
7843 You can pass a string error message or an object with the `msg` attribute which will be used as the
7844 error message. The object can contain any other name-value attributes (or objects) to be logged
7845 along with the error.
7846
7847 Note that after displaying the error message a JavaScript error will ultimately be thrown so that
7848 execution will halt.
7849
7850 #Example usage:#
7851
7852     Ext.Error.raise('A simple string error message');
7853
7854     // or...
7855
7856     Ext.define('Ext.Foo', {
7857         doSomething: function(option){
7858             if (someCondition === false) {
7859                 Ext.Error.raise({
7860                     msg: 'You cannot do that!',
7861                     option: option,   // whatever was passed into the method
7862                     'error code': 100 // other arbitrary info
7863                 });
7864             }
7865         }
7866     });
7867          * @param {String/Object} err The error message string, or an object containing the
7868          * attribute "msg" that will be used as the error message. Any other data included in
7869          * the object will also be logged to the browser console, if available.
7870          * @static
7871          * @markdown
7872          */
7873         raise: function(err){
7874             err = err || {};
7875             if (Ext.isString(err)) {
7876                 err = { msg: err };
7877             }
7878
7879             var method = this.raise.caller;
7880
7881             if (method) {
7882                 if (method.$name) {
7883                     err.sourceMethod = method.$name;
7884                 }
7885                 if (method.$owner) {
7886                     err.sourceClass = method.$owner.$className;
7887                 }
7888             }
7889
7890             if (Ext.Error.handle(err) !== true) {
7891                 var msg = Ext.Error.prototype.toString.call(err);
7892
7893                 Ext.log({
7894                     msg: msg,
7895                     level: 'error',
7896                     dump: err,
7897                     stack: true
7898                 });
7899
7900                 throw new Ext.Error(err);
7901             }
7902         },
7903
7904         /**
7905 Globally handle any Ext errors that may be raised, optionally providing custom logic to
7906 handle different errors individually. Return true from the function to bypass throwing the
7907 error to the browser, otherwise the error will be thrown and execution will halt.
7908
7909 #Example usage:#
7910
7911     Ext.Error.handle = function(err) {
7912         if (err.someProperty == 'NotReallyAnError') {
7913             // maybe log something to the application here if applicable
7914             return true;
7915         }
7916         // any non-true return value (including none) will cause the error to be thrown
7917     }
7918
7919          * @param {Ext.Error} err The Ext.Error object being raised. It will contain any attributes
7920          * that were originally raised with it, plus properties about the method and class from which
7921          * the error originated (if raised from a class that uses the Ext 4 class system).
7922          * @static
7923          * @markdown
7924          */
7925         handle: function(){
7926             return Ext.Error.ignore;
7927         }
7928     },
7929
7930     // This is the standard property that is the name of the constructor.
7931     name: 'Ext.Error',
7932
7933     /**
7934      * @constructor
7935      * @param {String/Object} config The error message string, or an object containing the
7936      * attribute "msg" that will be used as the error message. Any other data included in
7937      * the object will be applied to the error instance and logged to the browser console, if available.
7938      */
7939     constructor: function(config){
7940         if (Ext.isString(config)) {
7941             config = { msg: config };
7942         }
7943
7944         var me = this;
7945
7946         Ext.apply(me, config);
7947
7948         me.message = me.message || me.msg; // 'message' is standard ('msg' is non-standard)
7949         // note: the above does not work in old WebKit (me.message is readonly) (Safari 4)
7950     },
7951
7952     /**
7953 Provides a custom string representation of the error object. This is an override of the base JavaScript
7954 `Object.toString` method, which is useful so that when logged to the browser console, an error object will
7955 be displayed with a useful message instead of `[object Object]`, the default `toString` result.
7956
7957 The default implementation will include the error message along with the raising class and method, if available,
7958 but this can be overridden with a custom implementation either at the prototype level (for all errors) or on
7959 a particular error instance, if you want to provide a custom description that will show up in the console.
7960      * @markdown
7961      * @return {String} The error message. If raised from within the Ext 4 class system, the error message
7962      * will also include the raising class and method names, if available.
7963      */
7964     toString: function(){
7965         var me = this,
7966             className = me.className ? me.className  : '',
7967             methodName = me.methodName ? '.' + me.methodName + '(): ' : '',
7968             msg = me.msg || '(No description provided)';
7969
7970         return className + methodName + msg;
7971     }
7972 });
7973
7974 /*
7975  * This mechanism is used to notify the user of the first error encountered on the page. This
7976  * was previously internal to Ext.Error.raise and is a desirable feature since errors often
7977  * slip silently under the radar. It cannot live in Ext.Error.raise since there are times
7978  * where exceptions are handled in a try/catch.
7979  */
7980 (function () {
7981     var prevOnError, timer, errors = 0,
7982         extraordinarilyBad = /(out of stack)|(too much recursion)|(stack overflow)|(out of memory)/i,
7983         win = Ext.global;
7984
7985     if (typeof window === 'undefined') {
7986         return; // build system or some such environment...
7987     }
7988
7989     // This method is called to notify the user of the current error status.
7990     function notify () {
7991         var counters = Ext.log.counters,
7992             supports = Ext.supports,
7993             hasOnError = supports && supports.WindowOnError; // TODO - timing
7994
7995         // Put log counters to the status bar (for most browsers):
7996         if (counters && (counters.error + counters.warn + counters.info + counters.log)) {
7997             var msg = [ 'Logged Errors:',counters.error, 'Warnings:',counters.warn,
7998                         'Info:',counters.info, 'Log:',counters.log].join(' ');
7999             if (errors) {
8000                 msg = '*** Errors: ' + errors + ' - ' + msg;
8001             } else if (counters.error) {
8002                 msg = '*** ' + msg;
8003             }
8004             win.status = msg;
8005         }
8006
8007         // Display an alert on the first error:
8008         if (!Ext.isDefined(Ext.Error.notify)) {
8009             Ext.Error.notify = Ext.isIE6 || Ext.isIE7; // TODO - timing
8010         }
8011         if (Ext.Error.notify && (hasOnError ? errors : (counters && counters.error))) {
8012             Ext.Error.notify = false;
8013
8014             if (timer) {
8015                 win.clearInterval(timer); // ticks can queue up so stop...
8016                 timer = null;
8017             }
8018
8019             alert('Unhandled error on page: See console or log');
8020             poll();
8021         }
8022     }
8023
8024     // Sets up polling loop. This is the only way to know about errors in some browsers
8025     // (Opera/Safari) and is the only way to update the status bar for warnings and other
8026     // non-errors.
8027     function poll () {
8028         timer = win.setInterval(notify, 1000);
8029     }
8030
8031     // window.onerror is ideal (esp in IE) because you get full context. This is harmless
8032     // otherwise (never called) which is good because you cannot feature detect it.
8033     prevOnError = win.onerror || Ext.emptyFn;
8034     win.onerror = function (message) {
8035         ++errors;
8036
8037         if (!extraordinarilyBad.test(message)) {
8038             // too much recursion + our alert right now = crash IE
8039             // our polling loop will pick it up even if we don't alert now
8040             notify();
8041         }
8042
8043         return prevOnError.apply(this, arguments);
8044     };
8045     poll();
8046 })();
8047
8048
8049
8050 /*
8051 Ext JS - JavaScript Library
8052 Copyright (c) 2006-2011, Sencha Inc.
8053 All rights reserved.
8054 licensing@sencha.com
8055 */
8056 /**
8057  * @class Ext.JSON
8058  * Modified version of Douglas Crockford"s json.js that doesn"t
8059  * mess with the Object prototype
8060  * http://www.json.org/js.html
8061  * @singleton
8062  */
8063 Ext.JSON = new(function() {
8064     var useHasOwn = !! {}.hasOwnProperty,
8065     isNative = function() {
8066         var useNative = null;
8067
8068         return function() {
8069             if (useNative === null) {
8070                 useNative = Ext.USE_NATIVE_JSON && window.JSON && JSON.toString() == '[object JSON]';
8071             }
8072
8073             return useNative;
8074         };
8075     }(),
8076     pad = function(n) {
8077         return n < 10 ? "0" + n : n;
8078     },
8079     doDecode = function(json) {
8080         return eval("(" + json + ')');
8081     },
8082     doEncode = function(o) {
8083         if (!Ext.isDefined(o) || o === null) {
8084             return "null";
8085         } else if (Ext.isArray(o)) {
8086             return encodeArray(o);
8087         } else if (Ext.isDate(o)) {
8088             return Ext.JSON.encodeDate(o);
8089         } else if (Ext.isString(o)) {
8090             return encodeString(o);
8091         } else if (typeof o == "number") {
8092             //don't use isNumber here, since finite checks happen inside isNumber
8093             return isFinite(o) ? String(o) : "null";
8094         } else if (Ext.isBoolean(o)) {
8095             return String(o);
8096         } else if (Ext.isObject(o)) {
8097             return encodeObject(o);
8098         } else if (typeof o === "function") {
8099             return "null";
8100         }
8101         return 'undefined';
8102     },
8103     m = {
8104         "\b": '\\b',
8105         "\t": '\\t',
8106         "\n": '\\n',
8107         "\f": '\\f',
8108         "\r": '\\r',
8109         '"': '\\"',
8110         "\\": '\\\\',
8111         '\x0b': '\\u000b' //ie doesn't handle \v
8112     },
8113     charToReplace = /[\\\"\x00-\x1f\x7f-\uffff]/g,
8114     encodeString = function(s) {
8115         return '"' + s.replace(charToReplace, function(a) {
8116             var c = m[a];
8117             return typeof c === 'string' ? c : '\\u' + ('0000' + a.charCodeAt(0).toString(16)).slice(-4);
8118         }) + '"';
8119     },
8120     encodeArray = function(o) {
8121         var a = ["[", ""],
8122         // Note empty string in case there are no serializable members.
8123         len = o.length,
8124         i;
8125         for (i = 0; i < len; i += 1) {
8126             a.push(doEncode(o[i]), ',');
8127         }
8128         // Overwrite trailing comma (or empty string)
8129         a[a.length - 1] = ']';
8130         return a.join("");
8131     },
8132     encodeObject = function(o) {
8133         var a = ["{", ""],
8134         // Note empty string in case there are no serializable members.
8135         i;
8136         for (i in o) {
8137             if (!useHasOwn || o.hasOwnProperty(i)) {
8138                 a.push(doEncode(i), ":", doEncode(o[i]), ',');
8139             }
8140         }
8141         // Overwrite trailing comma (or empty string)
8142         a[a.length - 1] = '}';
8143         return a.join("");
8144     };
8145
8146     /**
8147      * <p>Encodes a Date. This returns the actual string which is inserted into the JSON string as the literal expression.
8148      * <b>The returned value includes enclosing double quotation marks.</b></p>
8149      * <p>The default return format is "yyyy-mm-ddThh:mm:ss".</p>
8150      * <p>To override this:</p><pre><code>
8151      Ext.JSON.encodeDate = function(d) {
8152      return d.format('"Y-m-d"');
8153      };
8154      </code></pre>
8155      * @param {Date} d The Date to encode
8156      * @return {String} The string literal to use in a JSON string.
8157      */
8158     this.encodeDate = function(o) {
8159         return '"' + o.getFullYear() + "-" 
8160         + pad(o.getMonth() + 1) + "-"
8161         + pad(o.getDate()) + "T"
8162         + pad(o.getHours()) + ":"
8163         + pad(o.getMinutes()) + ":"
8164         + pad(o.getSeconds()) + '"';
8165     };
8166
8167     /**
8168      * Encodes an Object, Array or other value
8169      * @param {Mixed} o The variable to encode
8170      * @return {String} The JSON string
8171      */
8172     this.encode = function() {
8173         var ec;
8174         return function(o) {
8175             if (!ec) {
8176                 // setup encoding function on first access
8177                 ec = isNative() ? JSON.stringify : doEncode;
8178             }
8179             return ec(o);
8180         };
8181     }();
8182
8183
8184     /**
8185      * Decodes (parses) a JSON string to an object. If the JSON is invalid, this function throws a SyntaxError unless the safe option is set.
8186      * @param {String} json The JSON string
8187      * @param {Boolean} safe (optional) Whether to return null or throw an exception if the JSON is invalid.
8188      * @return {Object} The resulting object
8189      */
8190     this.decode = function() {
8191         var dc;
8192         return function(json, safe) {
8193             if (!dc) {
8194                 // setup decoding function on first access
8195                 dc = isNative() ? JSON.parse : doDecode;
8196             }
8197             try {
8198                 return dc(json);
8199             } catch (e) {
8200                 if (safe === true) {
8201                     return null;
8202                 }
8203                 Ext.Error.raise({
8204                     sourceClass: "Ext.JSON",
8205                     sourceMethod: "decode",
8206                     msg: "You're trying to decode and invalid JSON String: " + json
8207                 });
8208             }
8209         };
8210     }();
8211
8212 })();
8213 /**
8214  * Shorthand for {@link Ext.JSON#encode}
8215  * @param {Mixed} o The variable to encode
8216  * @return {String} The JSON string
8217  * @member Ext
8218  * @method encode
8219  */
8220 Ext.encode = Ext.JSON.encode;
8221 /**
8222  * Shorthand for {@link Ext.JSON#decode}
8223  * @param {String} json The JSON string
8224  * @param {Boolean} safe (optional) Whether to return null or throw an exception if the JSON is invalid.
8225  * @return {Object} The resulting object
8226  * @member Ext
8227  * @method decode
8228  */
8229 Ext.decode = Ext.JSON.decode;
8230
8231
8232 /**
8233  * @class Ext
8234
8235  The Ext namespace (global object) encapsulates all classes, singletons, and utility methods provided by Sencha's libraries.</p>
8236  Most user interface Components are at a lower level of nesting in the namespace, but many common utility functions are provided
8237  as direct properties of the Ext namespace.
8238
8239  Also many frequently used methods from other classes are provided as shortcuts within the Ext namespace.
8240  For example {@link Ext#getCmp Ext.getCmp} aliases {@link Ext.ComponentManager#get Ext.ComponentManager.get}.
8241
8242  Many applications are initiated with {@link Ext#onReady Ext.onReady} which is called once the DOM is ready.
8243  This ensures all scripts have been loaded, preventing dependency issues. For example
8244
8245      Ext.onReady(function(){
8246          new Ext.Component({
8247              renderTo: document.body,
8248              html: 'DOM ready!'
8249          });
8250      });
8251
8252 For more information about how to use the Ext classes, see
8253
8254 - <a href="http://www.sencha.com/learn/">The Learning Center</a>
8255 - <a href="http://www.sencha.com/learn/Ext_FAQ">The FAQ</a>
8256 - <a href="http://www.sencha.com/forum/">The forums</a>
8257
8258  * @singleton
8259  * @markdown
8260  */
8261 Ext.apply(Ext, {
8262     userAgent: navigator.userAgent.toLowerCase(),
8263     cache: {},
8264     idSeed: 1000,
8265     BLANK_IMAGE_URL : 'data:image/gif;base64,R0lGODlhAQABAID/AMDAwAAAACH5BAEAAAAALAAAAAABAAEAAAICRAEAOw==',
8266     isStrict: document.compatMode == "CSS1Compat",
8267     windowId: 'ext-window',
8268     documentId: 'ext-document',
8269
8270     /**
8271      * True when the document is fully initialized and ready for action
8272      * @type Boolean
8273      */
8274     isReady: false,
8275
8276     /**
8277      * True to automatically uncache orphaned Ext.core.Elements periodically (defaults to true)
8278      * @type Boolean
8279      */
8280     enableGarbageCollector: true,
8281
8282     /**
8283      * True to automatically purge event listeners during garbageCollection (defaults to true).
8284      * @type Boolean
8285      */
8286     enableListenerCollection: true,
8287
8288     /**
8289      * Generates unique ids. If the element already has an id, it is unchanged
8290      * @param {Mixed} el (optional) The element to generate an id for
8291      * @param {String} prefix (optional) Id prefix (defaults "ext-gen")
8292      * @return {String} The generated Id.
8293      */
8294     id: function(el, prefix) {
8295         el = Ext.getDom(el, true) || {};
8296         if (el === document) {
8297             el.id = this.documentId;
8298         }
8299         else if (el === window) {
8300             el.id = this.windowId;
8301         }
8302         if (!el.id) {
8303             el.id = (prefix || "ext-gen") + (++Ext.idSeed);
8304         }
8305         return el.id;
8306     },
8307
8308     /**
8309      * Returns the current document body as an {@link Ext.core.Element}.
8310      * @return Ext.core.Element The document body
8311      */
8312     getBody: function() {
8313         return Ext.get(document.body || false);
8314     },
8315
8316     /**
8317      * Returns the current document head as an {@link Ext.core.Element}.
8318      * @return Ext.core.Element The document head
8319      * @method
8320      */
8321     getHead: function() {
8322         var head;
8323
8324         return function() {
8325             if (head == undefined) {
8326                 head = Ext.get(document.getElementsByTagName("head")[0]);
8327             }
8328
8329             return head;
8330         };
8331     }(),
8332
8333     /**
8334      * Returns the current HTML document object as an {@link Ext.core.Element}.
8335      * @return Ext.core.Element The document
8336      */
8337     getDoc: function() {
8338         return Ext.get(document);
8339     },
8340
8341     /**
8342      * This is shorthand reference to {@link Ext.ComponentManager#get}.
8343      * Looks up an existing {@link Ext.Component Component} by {@link Ext.Component#id id}
8344      * @param {String} id The component {@link Ext.Component#id id}
8345      * @return Ext.Component The Component, <tt>undefined</tt> if not found, or <tt>null</tt> if a
8346      * Class was found.
8347     */
8348     getCmp: function(id) {
8349         return Ext.ComponentManager.get(id);
8350     },
8351
8352     /**
8353      * Returns the current orientation of the mobile device
8354      * @return {String} Either 'portrait' or 'landscape'
8355      */
8356     getOrientation: function() {
8357         return window.innerHeight > window.innerWidth ? 'portrait' : 'landscape';
8358     },
8359
8360     /**
8361      * Attempts to destroy any objects passed to it by removing all event listeners, removing them from the
8362      * DOM (if applicable) and calling their destroy functions (if available).  This method is primarily
8363      * intended for arguments of type {@link Ext.core.Element} and {@link Ext.Component}, but any subclass of
8364      * {@link Ext.util.Observable} can be passed in.  Any number of elements and/or components can be
8365      * passed into this function in a single call as separate arguments.
8366      * @param {Mixed} arg1 An {@link Ext.core.Element}, {@link Ext.Component}, or an Array of either of these to destroy
8367      * @param {Mixed} arg2 (optional)
8368      * @param {Mixed} etc... (optional)
8369      */
8370     destroy: function() {
8371         var ln = arguments.length,
8372         i, arg;
8373
8374         for (i = 0; i < ln; i++) {
8375             arg = arguments[i];
8376             if (arg) {
8377                 if (Ext.isArray(arg)) {
8378                     this.destroy.apply(this, arg);
8379                 }
8380                 else if (Ext.isFunction(arg.destroy)) {
8381                     arg.destroy();
8382                 }
8383                 else if (arg.dom) {
8384                     arg.remove();
8385                 }
8386             }
8387         }
8388     },
8389
8390     /**
8391      * Execute a callback function in a particular scope. If no function is passed the call is ignored.
8392      * @param {Function} callback The callback to execute
8393      * @param {Object} scope (optional) The scope to execute in
8394      * @param {Array} args (optional) The arguments to pass to the function
8395      * @param {Number} delay (optional) Pass a number to delay the call by a number of milliseconds.
8396      */
8397     callback: function(callback, scope, args, delay){
8398         if(Ext.isFunction(callback)){
8399             args = args || [];
8400             scope = scope || window;
8401             if (delay) {
8402                 Ext.defer(callback, delay, scope, args);
8403             } else {
8404                 callback.apply(scope, args);
8405             }
8406         }
8407     },
8408
8409     /**
8410      * Convert certain characters (&, <, >, and ') to their HTML character equivalents for literal display in web pages.
8411      * @param {String} value The string to encode
8412      * @return {String} The encoded text
8413      */
8414     htmlEncode : function(value) {
8415         return Ext.String.htmlEncode(value);
8416     },
8417
8418     /**
8419      * Convert certain characters (&, <, >, and ') from their HTML character equivalents.
8420      * @param {String} value The string to decode
8421      * @return {String} The decoded text
8422      */
8423     htmlDecode : function(value) {
8424          return Ext.String.htmlDecode(value);
8425     },
8426
8427     /**
8428      * Appends content to the query string of a URL, handling logic for whether to place
8429      * a question mark or ampersand.
8430      * @param {String} url The URL to append to.
8431      * @param {String} s The content to append to the URL.
8432      * @return (String) The resulting URL
8433      */
8434     urlAppend : function(url, s) {
8435         if (!Ext.isEmpty(s)) {
8436             return url + (url.indexOf('?') === -1 ? '?' : '&') + s;
8437         }
8438         return url;
8439     }
8440 });
8441
8442
8443 Ext.ns = Ext.namespace;
8444
8445 // for old browsers
8446 window.undefined = window.undefined;
8447
8448 /**
8449  * @class Ext
8450  * Ext core utilities and functions.
8451  * @singleton
8452  */
8453 (function(){
8454     var check = function(regex){
8455             return regex.test(Ext.userAgent);
8456         },
8457         docMode = document.documentMode,
8458         isOpera = check(/opera/),
8459         isOpera10_5 = isOpera && check(/version\/10\.5/),
8460         isChrome = check(/\bchrome\b/),
8461         isWebKit = check(/webkit/),
8462         isSafari = !isChrome && check(/safari/),
8463         isSafari2 = isSafari && check(/applewebkit\/4/), // unique to Safari 2
8464         isSafari3 = isSafari && check(/version\/3/),
8465         isSafari4 = isSafari && check(/version\/4/),
8466         isIE = !isOpera && check(/msie/),
8467         isIE7 = isIE && (check(/msie 7/) || docMode == 7),
8468         isIE8 = isIE && (check(/msie 8/) && docMode != 7 && docMode != 9 || docMode == 8),
8469         isIE9 = isIE && (check(/msie 9/) && docMode != 7 && docMode != 8 || docMode == 9),
8470         isIE6 = isIE && check(/msie 6/),
8471         isGecko = !isWebKit && check(/gecko/),
8472         isGecko3 = isGecko && check(/rv:1\.9/),
8473         isGecko4 = isGecko && check(/rv:2\.0/),
8474         isFF3_0 = isGecko3 && check(/rv:1\.9\.0/),
8475         isFF3_5 = isGecko3 && check(/rv:1\.9\.1/),
8476         isFF3_6 = isGecko3 && check(/rv:1\.9\.2/),
8477         isWindows = check(/windows|win32/),
8478         isMac = check(/macintosh|mac os x/),
8479         isLinux = check(/linux/),
8480         scrollWidth = null,
8481         webKitVersion = isWebKit && (/webkit\/(\d+\.\d+)/.exec(Ext.userAgent));
8482
8483     // remove css image flicker
8484     try {
8485         document.execCommand("BackgroundImageCache", false, true);
8486     } catch(e) {}
8487
8488     Ext.setVersion('extjs', '4.0.1');
8489     Ext.apply(Ext, {
8490         /**
8491          * URL to a blank file used by Ext when in secure mode for iframe src and onReady src to prevent
8492          * the IE insecure content warning (<tt>'about:blank'</tt>, except for IE in secure mode, which is <tt>'javascript:""'</tt>).
8493          * @type String
8494          */
8495         SSL_SECURE_URL : Ext.isSecure && isIE ? 'javascript:""' : 'about:blank',
8496
8497         /**
8498          * True if the {@link Ext.fx.Anim} Class is available
8499          * @type Boolean
8500          * @property enableFx
8501          */
8502
8503         /**
8504          * True to scope the reset CSS to be just applied to Ext components. Note that this wraps root containers
8505          * with an additional element. Also remember that when you turn on this option, you have to use ext-all-scoped {
8506          * unless you use the bootstrap.js to load your javascript, in which case it will be handled for you.
8507          * @type Boolean
8508          */
8509         scopeResetCSS : Ext.buildSettings.scopeResetCSS,
8510
8511         /**
8512          * EXPERIMENTAL - True to cascade listener removal to child elements when an element is removed.
8513          * Currently not optimized for performance.
8514          * @type Boolean
8515          */
8516         enableNestedListenerRemoval : false,
8517
8518         /**
8519          * Indicates whether to use native browser parsing for JSON methods.
8520          * This option is ignored if the browser does not support native JSON methods.
8521          * <b>Note: Native JSON methods will not work with objects that have functions.
8522          * Also, property names must be quoted, otherwise the data will not parse.</b> (Defaults to false)
8523          * @type Boolean
8524          */
8525         USE_NATIVE_JSON : false,
8526
8527         /**
8528          * Return the dom node for the passed String (id), dom node, or Ext.core.Element.
8529          * Optional 'strict' flag is needed for IE since it can return 'name' and
8530          * 'id' elements by using getElementById.
8531          * Here are some examples:
8532          * <pre><code>
8533 // gets dom node based on id
8534 var elDom = Ext.getDom('elId');
8535 // gets dom node based on the dom node
8536 var elDom1 = Ext.getDom(elDom);
8537
8538 // If we don&#39;t know if we are working with an
8539 // Ext.core.Element or a dom node use Ext.getDom
8540 function(el){
8541     var dom = Ext.getDom(el);
8542     // do something with the dom node
8543 }
8544          * </code></pre>
8545          * <b>Note</b>: the dom node to be found actually needs to exist (be rendered, etc)
8546          * when this method is called to be successful.
8547          * @param {Mixed} el
8548          * @return HTMLElement
8549          */
8550         getDom : function(el, strict) {
8551             if (!el || !document) {
8552                 return null;
8553             }
8554             if (el.dom) {
8555                 return el.dom;
8556             } else {
8557                 if (typeof el == 'string') {
8558                     var e = document.getElementById(el);
8559                     // IE returns elements with the 'name' and 'id' attribute.
8560                     // we do a strict check to return the element with only the id attribute
8561                     if (e && isIE && strict) {
8562                         if (el == e.getAttribute('id')) {
8563                             return e;
8564                         } else {
8565                             return null;
8566                         }
8567                     }
8568                     return e;
8569                 } else {
8570                     return el;
8571                 }
8572             }
8573         },
8574
8575         /**
8576          * Removes a DOM node from the document.
8577          * <p>Removes this element from the document, removes all DOM event listeners, and deletes the cache reference.
8578          * All DOM event listeners are removed from this element. If {@link Ext#enableNestedListenerRemoval Ext.enableNestedListenerRemoval} is
8579          * <code>true</code>, then DOM event listeners are also removed from all child nodes. The body node
8580          * will be ignored if passed in.</p>
8581          * @param {HTMLElement} node The node to remove
8582          * @method
8583          */
8584         removeNode : isIE6 || isIE7 ? function() {
8585             var d;
8586             return function(n){
8587                 if(n && n.tagName != 'BODY'){
8588                     (Ext.enableNestedListenerRemoval) ? Ext.EventManager.purgeElement(n) : Ext.EventManager.removeAll(n);
8589                     d = d || document.createElement('div');
8590                     d.appendChild(n);
8591                     d.innerHTML = '';
8592                     delete Ext.cache[n.id];
8593                 }
8594             };
8595         }() : function(n) {
8596             if (n && n.parentNode && n.tagName != 'BODY') {
8597                 (Ext.enableNestedListenerRemoval) ? Ext.EventManager.purgeElement(n) : Ext.EventManager.removeAll(n);
8598                 n.parentNode.removeChild(n);
8599                 delete Ext.cache[n.id];
8600             }
8601         },
8602
8603         /**
8604          * True if the detected browser is Opera.
8605          * @type Boolean
8606          */
8607         isOpera : isOpera,
8608
8609         /**
8610          * True if the detected browser is Opera 10.5x.
8611          * @type Boolean
8612          */
8613         isOpera10_5 : isOpera10_5,
8614
8615         /**
8616          * True if the detected browser uses WebKit.
8617          * @type Boolean
8618          */
8619         isWebKit : isWebKit,
8620
8621         /**
8622          * True if the detected browser is Chrome.
8623          * @type Boolean
8624          */
8625         isChrome : isChrome,
8626
8627         /**
8628          * True if the detected browser is Safari.
8629          * @type Boolean
8630          */
8631         isSafari : isSafari,
8632
8633         /**
8634          * True if the detected browser is Safari 3.x.
8635          * @type Boolean
8636          */
8637         isSafari3 : isSafari3,
8638
8639         /**
8640          * True if the detected browser is Safari 4.x.
8641          * @type Boolean
8642          */
8643         isSafari4 : isSafari4,
8644
8645         /**
8646          * True if the detected browser is Safari 2.x.
8647          * @type Boolean
8648          */
8649         isSafari2 : isSafari2,
8650
8651         /**
8652          * True if the detected browser is Internet Explorer.
8653          * @type Boolean
8654          */
8655         isIE : isIE,
8656
8657         /**
8658          * True if the detected browser is Internet Explorer 6.x.
8659          * @type Boolean
8660          */
8661         isIE6 : isIE6,
8662
8663         /**
8664          * True if the detected browser is Internet Explorer 7.x.
8665          * @type Boolean
8666          */
8667         isIE7 : isIE7,
8668
8669         /**
8670          * True if the detected browser is Internet Explorer 8.x.
8671          * @type Boolean
8672          */
8673         isIE8 : isIE8,
8674
8675         /**
8676          * True if the detected browser is Internet Explorer 9.x.
8677          * @type Boolean
8678          */
8679         isIE9 : isIE9,
8680
8681         /**
8682          * True if the detected browser uses the Gecko layout engine (e.g. Mozilla, Firefox).
8683          * @type Boolean
8684          */
8685         isGecko : isGecko,
8686
8687         /**
8688          * True if the detected browser uses a Gecko 1.9+ layout engine (e.g. Firefox 3.x).
8689          * @type Boolean
8690          */
8691         isGecko3 : isGecko3,
8692
8693         /**
8694          * True if the detected browser uses a Gecko 2.0+ layout engine (e.g. Firefox 4.x).
8695          * @type Boolean
8696          */
8697         isGecko4 : isGecko4,
8698
8699         /**
8700          * True if the detected browser uses FireFox 3.0
8701          * @type Boolean
8702          */
8703
8704         isFF3_0 : isFF3_0,
8705         /**
8706          * True if the detected browser uses FireFox 3.5
8707          * @type Boolean
8708          */
8709
8710         isFF3_5 : isFF3_5,
8711         /**
8712          * True if the detected browser uses FireFox 3.6
8713          * @type Boolean
8714          */
8715         isFF3_6 : isFF3_6,
8716
8717         /**
8718          * True if the detected platform is Linux.
8719          * @type Boolean
8720          */
8721         isLinux : isLinux,
8722
8723         /**
8724          * True if the detected platform is Windows.
8725          * @type Boolean
8726          */
8727         isWindows : isWindows,
8728
8729         /**
8730          * True if the detected platform is Mac OS.
8731          * @type Boolean
8732          */
8733         isMac : isMac,
8734
8735         /**
8736          * The current version of WebKit (-1 if the browser does not use WebKit).
8737          * @type Float
8738          */
8739         webKitVersion: webKitVersion ? parseFloat(webKitVersion[1]) : -1,
8740
8741         /**
8742          * URL to a 1x1 transparent gif image used by Ext to create inline icons with CSS background images.
8743          * In older versions of IE, this defaults to "http://sencha.com/s.gif" and you should change this to a URL on your server.
8744          * For other browsers it uses an inline data URL.
8745          * @type String
8746          */
8747         BLANK_IMAGE_URL : (isIE6 || isIE7) ? 'http:/' + '/www.sencha.com/s.gif' : 'data:image/gif;base64,R0lGODlhAQABAID/AMDAwAAAACH5BAEAAAAALAAAAAABAAEAAAICRAEAOw==',
8748
8749         /**
8750          * <p>Utility method for returning a default value if the passed value is empty.</p>
8751          * <p>The value is deemed to be empty if it is<div class="mdetail-params"><ul>
8752          * <li>null</li>
8753          * <li>undefined</li>
8754          * <li>an empty array</li>
8755          * <li>a zero length string (Unless the <tt>allowBlank</tt> parameter is <tt>true</tt>)</li>
8756          * </ul></div>
8757          * @param {Mixed} value The value to test
8758          * @param {Mixed} defaultValue The value to return if the original value is empty
8759          * @param {Boolean} allowBlank (optional) true to allow zero length strings to qualify as non-empty (defaults to false)
8760          * @return {Mixed} value, if non-empty, else defaultValue
8761          * @deprecated 4.0.0 Use {Ext#valueFrom} instead
8762          */
8763         value : function(v, defaultValue, allowBlank){
8764             return Ext.isEmpty(v, allowBlank) ? defaultValue : v;
8765         },
8766
8767         /**
8768          * Escapes the passed string for use in a regular expression
8769          * @param {String} str
8770          * @return {String}
8771          * @deprecated 4.0.0 Use {@link Ext.String#escapeRegex} instead
8772          */
8773         escapeRe : function(s) {
8774             return s.replace(/([-.*+?^${}()|[\]\/\\])/g, "\\$1");
8775         },
8776
8777         /**
8778          * Applies event listeners to elements by selectors when the document is ready.
8779          * The event name is specified with an <tt>&#64;</tt> suffix.
8780          * <pre><code>
8781 Ext.addBehaviors({
8782     // add a listener for click on all anchors in element with id foo
8783     '#foo a&#64;click' : function(e, t){
8784         // do something
8785     },
8786
8787     // add the same listener to multiple selectors (separated by comma BEFORE the &#64;)
8788     '#foo a, #bar span.some-class&#64;mouseover' : function(){
8789         // do something
8790     }
8791 });
8792          * </code></pre>
8793          * @param {Object} obj The list of behaviors to apply
8794          */
8795         addBehaviors : function(o){
8796             if(!Ext.isReady){
8797                 Ext.onReady(function(){
8798                     Ext.addBehaviors(o);
8799                 });
8800             } else {
8801                 var cache = {}, // simple cache for applying multiple behaviors to same selector does query multiple times
8802                     parts,
8803                     b,
8804                     s;
8805                 for (b in o) {
8806                     if ((parts = b.split('@'))[1]) { // for Object prototype breakers
8807                         s = parts[0];
8808                         if(!cache[s]){
8809                             cache[s] = Ext.select(s);
8810                         }
8811                         cache[s].on(parts[1], o[b]);
8812                     }
8813                 }
8814                 cache = null;
8815             }
8816         },
8817
8818         /**
8819          * Utility method for getting the width of the browser scrollbar. This can differ depending on
8820          * operating system settings, such as the theme or font size.
8821          * @param {Boolean} force (optional) true to force a recalculation of the value.
8822          * @return {Number} The width of the scrollbar.
8823          */
8824         getScrollBarWidth: function(force){
8825             if(!Ext.isReady){
8826                 return 0;
8827             }
8828
8829             if(force === true || scrollWidth === null){
8830                 // BrowserBug: IE9
8831                 // When IE9 positions an element offscreen via offsets, the offsetWidth is
8832                 // inaccurately reported. For IE9 only, we render on screen before removing.
8833                 var cssClass = Ext.isIE9 ? '' : Ext.baseCSSPrefix + 'hide-offsets';
8834                     // Append our div, do our calculation and then remove it
8835                 var div = Ext.getBody().createChild('<div class="' + cssClass + '" style="width:100px;height:50px;overflow:hidden;"><div style="height:200px;"></div></div>'),
8836                     child = div.child('div', true);
8837                 var w1 = child.offsetWidth;
8838                 div.setStyle('overflow', (Ext.isWebKit || Ext.isGecko) ? 'auto' : 'scroll');
8839                 var w2 = child.offsetWidth;
8840                 div.remove();
8841                 // Need to add 2 to ensure we leave enough space
8842                 scrollWidth = w1 - w2 + 2;
8843             }
8844             return scrollWidth;
8845         },
8846
8847         /**
8848          * Copies a set of named properties fom the source object to the destination object.
8849          * <p>example:<pre><code>
8850 ImageComponent = Ext.extend(Ext.Component, {
8851     initComponent: function() {
8852         this.autoEl = { tag: 'img' };
8853         MyComponent.superclass.initComponent.apply(this, arguments);
8854         this.initialBox = Ext.copyTo({}, this.initialConfig, 'x,y,width,height');
8855     }
8856 });
8857          * </code></pre>
8858          * Important note: To borrow class prototype methods, use {@link Ext.Base#borrow} instead.
8859          * @param {Object} dest The destination object.
8860          * @param {Object} source The source object.
8861          * @param {Array/String} names Either an Array of property names, or a comma-delimited list
8862          * of property names to copy.
8863          * @param {Boolean} usePrototypeKeys (Optional) Defaults to false. Pass true to copy keys off of the prototype as well as the instance.
8864          * @return {Object} The modified object.
8865         */
8866         copyTo : function(dest, source, names, usePrototypeKeys){
8867             if(typeof names == 'string'){
8868                 names = names.split(/[,;\s]/);
8869             }
8870             Ext.each(names, function(name){
8871                 if(usePrototypeKeys || source.hasOwnProperty(name)){
8872                     dest[name] = source[name];
8873                 }
8874             }, this);
8875             return dest;
8876         },
8877
8878         /**
8879          * Attempts to destroy and then remove a set of named properties of the passed object.
8880          * @param {Object} o The object (most likely a Component) who's properties you wish to destroy.
8881          * @param {Mixed} arg1 The name of the property to destroy and remove from the object.
8882          * @param {Mixed} etc... More property names to destroy and remove.
8883          */
8884         destroyMembers : function(o, arg1, arg2, etc){
8885             for (var i = 1, a = arguments, len = a.length; i < len; i++) {
8886                 Ext.destroy(o[a[i]]);
8887                 delete o[a[i]];
8888             }
8889         },
8890
8891         /**
8892          * Logs a message. If a console is present it will be used. On Opera, the method
8893          * "opera.postError" is called. In other cases, the message is logged to an array
8894          * "Ext.log.out". An attached debugger can watch this array and view the log. The
8895          * log buffer is limited to a maximum of "Ext.log.max" entries (defaults to 100).
8896          *
8897          * If additional parameters are passed, they are joined and appended to the message.
8898          * 
8899          * This method does nothing in a release build.
8900          *
8901          * @param {String|Object} message The message to log or an options object with any
8902          * of the following properties:
8903          *
8904          *  - `msg`: The message to log (required).
8905          *  - `level`: One of: "error", "warn", "info" or "log" (the default is "log").
8906          *  - `dump`: An object to dump to the log as part of the message.
8907          *  - `stack`: True to include a stack trace in the log.
8908          * @markdown
8909          */
8910         log : function (message) {
8911             var options, dump,
8912                 con = Ext.global.console,
8913                 log = Ext.log,
8914                 level = 'log',
8915                 stack,
8916                 members,
8917                 member;
8918
8919             if (!Ext.isString(message)) {
8920                 options = message;
8921                 message = options.msg || '';
8922                 level = options.level || level;
8923                 dump = options.dump;
8924                 stack = options.stack;
8925
8926                 if (dump && !(con && con.dir)) {
8927                     members = [];
8928
8929                     // Cannot use Ext.encode since it can recurse endlessly (if we're lucky)
8930                     // ...and the data could be prettier!
8931                     Ext.Object.each(dump, function (name, value) {
8932                         if (typeof(value) === "function") {
8933                             return;
8934                         }
8935
8936                         if (!Ext.isDefined(value) || value === null ||
8937                                 Ext.isDate(value) ||
8938                                 Ext.isString(value) || (typeof(value) == "number") ||
8939                                 Ext.isBoolean(value)) {
8940                             member = Ext.encode(value);
8941                         } else if (Ext.isArray(value)) {
8942                             member = '[ ]';
8943                         } else if (Ext.isObject(value)) {
8944                             member = '{ }';
8945                         } else {
8946                             member = 'undefined';
8947                         }
8948                         members.push(Ext.encode(name) + ': ' + member);
8949                     });
8950
8951                     if (members.length) {
8952                         message += ' \nData: {\n  ' + members.join(',\n  ') + '\n}';
8953                     }
8954                     dump = null;
8955                 }
8956             }
8957
8958             if (arguments.length > 1) {
8959                 message += Array.prototype.slice.call(arguments, 1).join('');
8960             }
8961
8962             // Not obvious, but 'console' comes and goes when Firebug is turned on/off, so
8963             // an early test may fail either direction if Firebug is toggled.
8964             //
8965             if (con) { // if (Firebug-like console)
8966                 if (con[level]) {
8967                     con[level](message);
8968                 } else {
8969                     con.log(message);
8970                 }
8971
8972                 if (dump) {
8973                     con.dir(dump);
8974                 }
8975
8976                 if (stack && con.trace) {
8977                     // Firebug's console.error() includes a trace already...
8978                     if (!con.firebug || level != 'error') {
8979                         con.trace();
8980                     }
8981                 }
8982             } else {
8983                 // w/o console, all messages are equal, so munge the level into the message:
8984                 if (level != 'log') {
8985                     message = level.toUpperCase() + ': ' + message;
8986                 }
8987
8988                 if (Ext.isOpera) {
8989                     opera.postError(message);
8990                 } else {
8991                     var out = log.out || (log.out = []),
8992                         max = log.max || (log.max = 100);
8993
8994                     if (out.length >= max) {
8995                         // this formula allows out.max to change (via debugger), where the
8996                         // more obvious "max/4" would not quite be the same
8997                         out.splice(0, out.length - 3 * Math.floor(max / 4)); // keep newest 75%
8998                     }
8999
9000                     out.push(message);
9001                 }
9002             }
9003
9004             // Mostly informational, but the Ext.Error notifier uses them:
9005             var counters = log.counters ||
9006                           (log.counters = { error: 0, warn: 0, info: 0, log: 0 });
9007
9008             ++counters[level];
9009         },
9010
9011         /**
9012          * Partitions the set into two sets: a true set and a false set.
9013          * Example:
9014          * Example2:
9015          * <pre><code>
9016 // Example 1:
9017 Ext.partition([true, false, true, true, false]); // [[true, true, true], [false, false]]
9018
9019 // Example 2:
9020 Ext.partition(
9021     Ext.query("p"),
9022     function(val){
9023         return val.className == "class1"
9024     }
9025 );
9026 // true are those paragraph elements with a className of "class1",
9027 // false set are those that do not have that className.
9028          * </code></pre>
9029          * @param {Array|NodeList} arr The array to partition
9030          * @param {Function} truth (optional) a function to determine truth.  If this is omitted the element
9031          *                   itself must be able to be evaluated for its truthfulness.
9032          * @return {Array} [true<Array>,false<Array>]
9033          * @deprecated 4.0.0 Will be removed in the next major version
9034          */
9035         partition : function(arr, truth){
9036             var ret = [[],[]];
9037             Ext.each(arr, function(v, i, a) {
9038                 ret[ (truth && truth(v, i, a)) || (!truth && v) ? 0 : 1].push(v);
9039             });
9040             return ret;
9041         },
9042
9043         /**
9044          * Invokes a method on each item in an Array.
9045          * <pre><code>
9046 // Example:
9047 Ext.invoke(Ext.query("p"), "getAttribute", "id");
9048 // [el1.getAttribute("id"), el2.getAttribute("id"), ..., elN.getAttribute("id")]
9049          * </code></pre>
9050          * @param {Array|NodeList} arr The Array of items to invoke the method on.
9051          * @param {String} methodName The method name to invoke.
9052          * @param {...*} args Arguments to send into the method invocation.
9053          * @return {Array} The results of invoking the method on each item in the array.
9054          * @deprecated 4.0.0 Will be removed in the next major version
9055          */
9056         invoke : function(arr, methodName){
9057             var ret = [],
9058                 args = Array.prototype.slice.call(arguments, 2);
9059             Ext.each(arr, function(v,i) {
9060                 if (v && typeof v[methodName] == 'function') {
9061                     ret.push(v[methodName].apply(v, args));
9062                 } else {
9063                     ret.push(undefined);
9064                 }
9065             });
9066             return ret;
9067         },
9068
9069         /**
9070          * <p>Zips N sets together.</p>
9071          * <pre><code>
9072 // Example 1:
9073 Ext.zip([1,2,3],[4,5,6]); // [[1,4],[2,5],[3,6]]
9074 // Example 2:
9075 Ext.zip(
9076     [ "+", "-", "+"],
9077     [  12,  10,  22],
9078     [  43,  15,  96],
9079     function(a, b, c){
9080         return "$" + a + "" + b + "." + c
9081     }
9082 ); // ["$+12.43", "$-10.15", "$+22.96"]
9083          * </code></pre>
9084          * @param {Arrays|NodeLists} arr This argument may be repeated. Array(s) to contribute values.
9085          * @param {Function} zipper (optional) The last item in the argument list. This will drive how the items are zipped together.
9086          * @return {Array} The zipped set.
9087          * @deprecated 4.0.0 Will be removed in the next major version
9088          */
9089         zip : function(){
9090             var parts = Ext.partition(arguments, function( val ){ return typeof val != 'function'; }),
9091                 arrs = parts[0],
9092                 fn = parts[1][0],
9093                 len = Ext.max(Ext.pluck(arrs, "length")),
9094                 ret = [];
9095
9096             for (var i = 0; i < len; i++) {
9097                 ret[i] = [];
9098                 if(fn){
9099                     ret[i] = fn.apply(fn, Ext.pluck(arrs, i));
9100                 }else{
9101                     for (var j = 0, aLen = arrs.length; j < aLen; j++){
9102                         ret[i].push( arrs[j][i] );
9103                     }
9104                 }
9105             }
9106             return ret;
9107         },
9108
9109         /**
9110          * Turns an array into a sentence, joined by a specified connector - e.g.:
9111          * Ext.toSentence(['Adama', 'Tigh', 'Roslin']); //'Adama, Tigh and Roslin'
9112          * Ext.toSentence(['Adama', 'Tigh', 'Roslin'], 'or'); //'Adama, Tigh or Roslin'
9113          * @param {Array} items The array to create a sentence from
9114          * @param {String} connector The string to use to connect the last two words. Usually 'and' or 'or' - defaults to 'and'.
9115          * @return {String} The sentence string
9116          * @deprecated 4.0.0 Will be removed in the next major version
9117          */
9118         toSentence: function(items, connector) {
9119             var length = items.length;
9120
9121             if (length <= 1) {
9122                 return items[0];
9123             } else {
9124                 var head = items.slice(0, length - 1),
9125                     tail = items[length - 1];
9126
9127                 return Ext.util.Format.format("{0} {1} {2}", head.join(", "), connector || 'and', tail);
9128             }
9129         },
9130
9131         /**
9132          * By default, Ext intelligently decides whether floating elements should be shimmed. If you are using flash,
9133          * you may want to set this to true.
9134          * @type Boolean
9135          */
9136         useShims: isIE6
9137     });
9138 })();
9139
9140 /**
9141  * TBD
9142  * @param {Object} config
9143  * @method
9144  */
9145 Ext.application = function(config) {
9146     Ext.require('Ext.app.Application');
9147
9148     Ext.onReady(function() {
9149         Ext.create('Ext.app.Application', config);
9150     });
9151 };
9152
9153 /**
9154  * @class Ext.util.Format
9155
9156 This class is a centralized place for formatting functions inside the library. It includes
9157 functions to format various different types of data, such as text, dates and numeric values.
9158
9159 __Localization__
9160 This class contains several options for localization. These can be set once the library has loaded,
9161 all calls to the functions from that point will use the locale settings that were specified.
9162 Options include:
9163 - thousandSeparator
9164 - decimalSeparator
9165 - currenyPrecision
9166 - currencySign
9167 - currencyAtEnd
9168 This class also uses the default date format defined here: {@link Ext.date#defaultFormat}.
9169
9170 __Using with renderers__
9171 There are two helper functions that return a new function that can be used in conjunction with 
9172 grid renderers:
9173
9174     columns: [{
9175         dataIndex: 'date',
9176         renderer: Ext.util.Format.dateRenderer('Y-m-d')
9177     }, {
9178         dataIndex: 'time',
9179         renderer: Ext.util.Format.numberRenderer('0.000')
9180     }]
9181     
9182 Functions that only take a single argument can also be passed directly:
9183     columns: [{
9184         dataIndex: 'cost',
9185         renderer: Ext.util.Format.usMoney
9186     }, {
9187         dataIndex: 'productCode',
9188         renderer: Ext.util.Format.uppercase
9189     }]
9190     
9191 __Using with XTemplates__
9192 XTemplates can also directly use Ext.util.Format functions:
9193
9194     new Ext.XTemplate([
9195         'Date: {startDate:date("Y-m-d")}',
9196         'Cost: {cost:usMoney}'
9197     ]);
9198
9199  * @markdown
9200  * @singleton
9201  */
9202 (function() {
9203     Ext.ns('Ext.util');
9204
9205     Ext.util.Format = {};
9206     var UtilFormat     = Ext.util.Format,
9207         stripTagsRE    = /<\/?[^>]+>/gi,
9208         stripScriptsRe = /(?:<script.*?>)((\n|\r|.)*?)(?:<\/script>)/ig,
9209         nl2brRe        = /\r?\n/g,
9210
9211         // A RegExp to remove from a number format string, all characters except digits and '.'
9212         formatCleanRe  = /[^\d\.]/g,
9213
9214         // A RegExp to remove from a number format string, all characters except digits and the local decimal separator.
9215         // Created on first use. The local decimal separator character must be initialized for this to be created.
9216         I18NFormatCleanRe;
9217
9218     Ext.apply(UtilFormat, {
9219         /**
9220          * @type String
9221          * @property thousandSeparator
9222          * <p>The character that the {@link #number} function uses as a thousand separator.</p>
9223          * <p>This defaults to <code>,</code>, but may be overridden in a locale file.</p>
9224          */
9225         thousandSeparator: ',',
9226
9227         /**
9228          * @type String
9229          * @property decimalSeparator
9230          * <p>The character that the {@link #number} function uses as a decimal point.</p>
9231          * <p>This defaults to <code>.</code>, but may be overridden in a locale file.</p>
9232          */
9233         decimalSeparator: '.',
9234
9235         /**
9236          * @type Number
9237          * @property currencyPrecision
9238          * <p>The number of decimal places that the {@link #currency} function displays.</p>
9239          * <p>This defaults to <code>2</code>, but may be overridden in a locale file.</p>
9240          */
9241         currencyPrecision: 2,
9242
9243         /**
9244          * @type String
9245          * @property currencySign
9246          * <p>The currency sign that the {@link #currency} function displays.</p>
9247          * <p>This defaults to <code>$</code>, but may be overridden in a locale file.</p>
9248          */
9249         currencySign: '$',
9250
9251         /**
9252          * @type Boolean
9253          * @property currencyAtEnd
9254          * <p>This may be set to <code>true</code> to make the {@link #currency} function
9255          * append the currency sign to the formatted value.</p>
9256          * <p>This defaults to <code>false</code>, but may be overridden in a locale file.</p>
9257          */
9258         currencyAtEnd: false,
9259
9260         /**
9261          * Checks a reference and converts it to empty string if it is undefined
9262          * @param {Mixed} value Reference to check
9263          * @return {Mixed} Empty string if converted, otherwise the original value
9264          */
9265         undef : function(value) {
9266             return value !== undefined ? value : "";
9267         },
9268
9269         /**
9270          * Checks a reference and converts it to the default value if it's empty
9271          * @param {Mixed} value Reference to check
9272          * @param {String} defaultValue The value to insert of it's undefined (defaults to "")
9273          * @return {String}
9274          */
9275         defaultValue : function(value, defaultValue) {
9276             return value !== undefined && value !== '' ? value : defaultValue;
9277         },
9278
9279         /**
9280          * Returns a substring from within an original string
9281          * @param {String} value The original text
9282          * @param {Number} start The start index of the substring
9283          * @param {Number} length The length of the substring
9284          * @return {String} The substring
9285          */
9286         substr : function(value, start, length) {
9287             return String(value).substr(start, length);
9288         },
9289
9290         /**
9291          * Converts a string to all lower case letters
9292          * @param {String} value The text to convert
9293          * @return {String} The converted text
9294          */
9295         lowercase : function(value) {
9296             return String(value).toLowerCase();
9297         },
9298
9299         /**
9300          * Converts a string to all upper case letters
9301          * @param {String} value The text to convert
9302          * @return {String} The converted text
9303          */
9304         uppercase : function(value) {
9305             return String(value).toUpperCase();
9306         },
9307
9308         /**
9309          * Format a number as US currency
9310          * @param {Number/String} value The numeric value to format
9311          * @return {String} The formatted currency string
9312          */
9313         usMoney : function(v) {
9314             return UtilFormat.currency(v, '$', 2);
9315         },
9316
9317         /**
9318          * Format a number as a currency
9319          * @param {Number/String} value The numeric value to format
9320          * @param {String} sign The currency sign to use (defaults to {@link #currencySign})
9321          * @param {Number} decimals The number of decimals to use for the currency (defaults to {@link #currencyPrecision})
9322          * @param {Boolean} end True if the currency sign should be at the end of the string (defaults to {@link #currencyAtEnd})
9323          * @return {String} The formatted currency string
9324          */
9325         currency: function(v, currencySign, decimals, end) {
9326             var negativeSign = '',
9327                 format = ",0",
9328                 i = 0;
9329             v = v - 0;
9330             if (v < 0) {
9331                 v = -v;
9332                 negativeSign = '-';
9333             }
9334             decimals = decimals || UtilFormat.currencyPrecision;
9335             format += format + (decimals > 0 ? '.' : '');
9336             for (; i < decimals; i++) {
9337                 format += '0';
9338             }
9339             v = UtilFormat.number(v, format); 
9340             if ((end || UtilFormat.currencyAtEnd) === true) {
9341                 return Ext.String.format("{0}{1}{2}", negativeSign, v, currencySign || UtilFormat.currencySign);
9342             } else {
9343                 return Ext.String.format("{0}{1}{2}", negativeSign, currencySign || UtilFormat.currencySign, v);
9344             }
9345         },
9346
9347         /**
9348          * Formats the passed date using the specified format pattern.
9349          * @param {String/Date} value The value to format. If a string is passed, it is converted to a Date by the Javascript
9350          * Date object's <a href="http://www.w3schools.com/jsref/jsref_parse.asp">parse()</a> method.
9351          * @param {String} format (Optional) Any valid date format string. Defaults to {@link Ext.Date#defaultFormat}.
9352          * @return {String} The formatted date string.
9353          */
9354         date: function(v, format) {
9355             if (!v) {
9356                 return "";
9357             }
9358             if (!Ext.isDate(v)) {
9359                 v = new Date(Date.parse(v));
9360             }
9361             return Ext.Date.dateFormat(v, format || Ext.Date.defaultFormat);
9362         },
9363
9364         /**
9365          * Returns a date rendering function that can be reused to apply a date format multiple times efficiently
9366          * @param {String} format Any valid date format string. Defaults to {@link Ext.Date#defaultFormat}.
9367          * @return {Function} The date formatting function
9368          */
9369         dateRenderer : function(format) {
9370             return function(v) {
9371                 return UtilFormat.date(v, format);
9372             };
9373         },
9374
9375         /**
9376          * Strips all HTML tags
9377          * @param {Mixed} value The text from which to strip tags
9378          * @return {String} The stripped text
9379          */
9380         stripTags : function(v) {
9381             return !v ? v : String(v).replace(stripTagsRE, "");
9382         },
9383
9384         /**
9385          * Strips all script tags
9386          * @param {Mixed} value The text from which to strip script tags
9387          * @return {String} The stripped text
9388          */
9389         stripScripts : function(v) {
9390             return !v ? v : String(v).replace(stripScriptsRe, "");
9391         },
9392
9393         /**
9394          * Simple format for a file size (xxx bytes, xxx KB, xxx MB)
9395          * @param {Number/String} size The numeric value to format
9396          * @return {String} The formatted file size
9397          */
9398         fileSize : function(size) {
9399             if (size < 1024) {
9400                 return size + " bytes";
9401             } else if (size < 1048576) {
9402                 return (Math.round(((size*10) / 1024))/10) + " KB";
9403             } else {
9404                 return (Math.round(((size*10) / 1048576))/10) + " MB";
9405             }
9406         },
9407
9408         /**
9409          * It does simple math for use in a template, for example:<pre><code>
9410          * var tpl = new Ext.Template('{value} * 10 = {value:math("* 10")}');
9411          * </code></pre>
9412          * @return {Function} A function that operates on the passed value.
9413          * @method
9414          */
9415         math : function(){
9416             var fns = {};
9417
9418             return function(v, a){
9419                 if (!fns[a]) {
9420                     fns[a] = Ext.functionFactory('v', 'return v ' + a + ';');
9421                 }
9422                 return fns[a](v);
9423             };
9424         }(),
9425
9426         /**
9427          * Rounds the passed number to the required decimal precision.
9428          * @param {Number/String} value The numeric value to round.
9429          * @param {Number} precision The number of decimal places to which to round the first parameter's value.
9430          * @return {Number} The rounded value.
9431          */
9432         round : function(value, precision) {
9433             var result = Number(value);
9434             if (typeof precision == 'number') {
9435                 precision = Math.pow(10, precision);
9436                 result = Math.round(value * precision) / precision;
9437             }
9438             return result;
9439         },
9440
9441         /**
9442          * <p>Formats the passed number according to the passed format string.</p>
9443          * <p>The number of digits after the decimal separator character specifies the number of
9444          * decimal places in the resulting string. The <u>local-specific</u> decimal character is used in the result.</p>
9445          * <p>The <i>presence</i> of a thousand separator character in the format string specifies that
9446          * the <u>locale-specific</u> thousand separator (if any) is inserted separating thousand groups.</p>
9447          * <p>By default, "," is expected as the thousand separator, and "." is expected as the decimal separator.</p>
9448          * <p><b>New to Ext4</b></p>
9449          * <p>Locale-specific characters are always used in the formatted output when inserting
9450          * thousand and decimal separators.</p>
9451          * <p>The format string must specify separator characters according to US/UK conventions ("," as the
9452          * thousand separator, and "." as the decimal separator)</p>
9453          * <p>To allow specification of format strings according to local conventions for separator characters, add
9454          * the string <code>/i</code> to the end of the format string.</p>
9455          * <div style="margin-left:40px">examples (123456.789):
9456          * <div style="margin-left:10px">
9457          * 0 - (123456) show only digits, no precision<br>
9458          * 0.00 - (123456.78) show only digits, 2 precision<br>
9459          * 0.0000 - (123456.7890) show only digits, 4 precision<br>
9460          * 0,000 - (123,456) show comma and digits, no precision<br>
9461          * 0,000.00 - (123,456.78) show comma and digits, 2 precision<br>
9462          * 0,0.00 - (123,456.78) shortcut method, show comma and digits, 2 precision<br>
9463          * To allow specification of the formatting string using UK/US grouping characters (,) and decimal (.) for international numbers, add /i to the end.
9464          * For example: 0.000,00/i
9465          * </div></div>
9466          * @param {Number} v The number to format.
9467          * @param {String} format The way you would like to format this text.
9468          * @return {String} The formatted number.
9469          */
9470         number:
9471             function(v, formatString) {
9472             if (!formatString) {
9473                 return v;
9474             }
9475             v = Ext.Number.from(v, NaN);
9476             if (isNaN(v)) {
9477                 return '';
9478             }
9479             var comma = UtilFormat.thousandSeparator,
9480                 dec   = UtilFormat.decimalSeparator,
9481                 i18n  = false,
9482                 neg   = v < 0,
9483                 hasComma,
9484                 psplit;
9485
9486             v = Math.abs(v);
9487
9488             // The "/i" suffix allows caller to use a locale-specific formatting string.
9489             // Clean the format string by removing all but numerals and the decimal separator.
9490             // Then split the format string into pre and post decimal segments according to *what* the
9491             // decimal separator is. If they are specifying "/i", they are using the local convention in the format string.
9492             if (formatString.substr(formatString.length - 2) == '/i') {
9493                 if (!I18NFormatCleanRe) {
9494                     I18NFormatCleanRe = new RegExp('[^\\d\\' + UtilFormat.decimalSeparator + ']','g');
9495                 }
9496                 formatString = formatString.substr(0, formatString.length - 2);
9497                 i18n   = true;
9498                 hasComma = formatString.indexOf(comma) != -1;
9499                 psplit = formatString.replace(I18NFormatCleanRe, '').split(dec);
9500             } else {
9501                 hasComma = formatString.indexOf(',') != -1;
9502                 psplit = formatString.replace(formatCleanRe, '').split('.');
9503             }
9504
9505             if (1 < psplit.length) {
9506                 v = v.toFixed(psplit[1].length);
9507             } else if(2 < psplit.length) {
9508                 Ext.Error.raise({
9509                     sourceClass: "Ext.util.Format",
9510                     sourceMethod: "number",
9511                     value: v,
9512                     formatString: formatString,
9513                     msg: "Invalid number format, should have no more than 1 decimal"
9514                 });
9515             } else {
9516                 v = v.toFixed(0);
9517             }
9518
9519             var fnum = v.toString();
9520
9521             psplit = fnum.split('.');
9522
9523             if (hasComma) {
9524                 var cnum = psplit[0],
9525                     parr = [],
9526                     j    = cnum.length,
9527                     m    = Math.floor(j / 3),
9528                     n    = cnum.length % 3 || 3,
9529                     i;
9530
9531                 for (i = 0; i < j; i += n) {
9532                     if (i !== 0) {
9533                         n = 3;
9534                     }
9535
9536                     parr[parr.length] = cnum.substr(i, n);
9537                     m -= 1;
9538                 }
9539                 fnum = parr.join(comma);
9540                 if (psplit[1]) {
9541                     fnum += dec + psplit[1];
9542                 }
9543             } else {
9544                 if (psplit[1]) {
9545                     fnum = psplit[0] + dec + psplit[1];
9546                 }
9547             }
9548
9549             return (neg ? '-' : '') + formatString.replace(/[\d,?\.?]+/, fnum);
9550         },
9551
9552         /**
9553          * Returns a number rendering function that can be reused to apply a number format multiple times efficiently
9554          * @param {String} format Any valid number format string for {@link #number}
9555          * @return {Function} The number formatting function
9556          */
9557         numberRenderer : function(format) {
9558             return function(v) {
9559                 return UtilFormat.number(v, format);
9560             };
9561         },
9562
9563         /**
9564          * Selectively do a plural form of a word based on a numeric value. For example, in a template,
9565          * {commentCount:plural("Comment")}  would result in "1 Comment" if commentCount was 1 or would be "x Comments"
9566          * if the value is 0 or greater than 1.
9567          * @param {Number} value The value to compare against
9568          * @param {String} singular The singular form of the word
9569          * @param {String} plural (optional) The plural form of the word (defaults to the singular with an "s")
9570          */
9571         plural : function(v, s, p) {
9572             return v +' ' + (v == 1 ? s : (p ? p : s+'s'));
9573         },
9574
9575         /**
9576          * Converts newline characters to the HTML tag &lt;br/>
9577          * @param {String} The string value to format.
9578          * @return {String} The string with embedded &lt;br/> tags in place of newlines.
9579          */
9580         nl2br : function(v) {
9581             return Ext.isEmpty(v) ? '' : v.replace(nl2brRe, '<br/>');
9582         },
9583
9584         /**
9585          * Capitalize the given string. See {@link Ext.String#capitalize}.
9586          * @method
9587          */
9588         capitalize: Ext.String.capitalize,
9589
9590         /**
9591          * Truncate a string and add an ellipsis ('...') to the end if it exceeds the specified length.
9592          * See {@link Ext.String#ellipsis}.
9593          * @method
9594          */
9595         ellipsis: Ext.String.ellipsis,
9596
9597         /**
9598          * Formats to a string. See {@link Ext.String#format}
9599          * @method
9600          */
9601         format: Ext.String.format,
9602
9603         /**
9604          * Convert certain characters (&, <, >, and ') from their HTML character equivalents.
9605          * See {@link Ext.string#htmlDecode}.
9606          * @method
9607          */
9608         htmlDecode: Ext.String.htmlDecode,
9609
9610         /**
9611          * Convert certain characters (&, <, >, and ') to their HTML character equivalents for literal display in web pages.
9612          * See {@link Ext.String#htmlEncode}.
9613          * @method
9614          */
9615         htmlEncode: Ext.String.htmlEncode,
9616
9617         /**
9618          * Adds left padding to a string. See {@link Ext.String#leftPad}
9619          * @method
9620          */
9621         leftPad: Ext.String.leftPad,
9622
9623         /**
9624          * Trims any whitespace from either side of a string. See {@link Ext.String#trim}.
9625          * @method
9626          */
9627         trim : Ext.String.trim,
9628
9629         /**
9630          * Parses a number or string representing margin sizes into an object. Supports CSS-style margin declarations
9631          * (e.g. 10, "10", "10 10", "10 10 10" and "10 10 10 10" are all valid options and would return the same result)
9632          * @param {Number|String} v The encoded margins
9633          * @return {Object} An object with margin sizes for top, right, bottom and left
9634          */
9635         parseBox : function(box) {
9636             if (Ext.isNumber(box)) {
9637                 box = box.toString();
9638             }
9639             var parts  = box.split(' '),
9640                 ln = parts.length;
9641
9642             if (ln == 1) {
9643                 parts[1] = parts[2] = parts[3] = parts[0];
9644             }
9645             else if (ln == 2) {
9646                 parts[2] = parts[0];
9647                 parts[3] = parts[1];
9648             }
9649             else if (ln == 3) {
9650                 parts[3] = parts[1];
9651             }
9652
9653             return {
9654                 top   :parseInt(parts[0], 10) || 0,
9655                 right :parseInt(parts[1], 10) || 0,
9656                 bottom:parseInt(parts[2], 10) || 0,
9657                 left  :parseInt(parts[3], 10) || 0
9658             };
9659         },
9660
9661         /**
9662          * Escapes the passed string for use in a regular expression
9663          * @param {String} str
9664          * @return {String}
9665          */
9666         escapeRegex : function(s) {
9667             return s.replace(/([\-.*+?\^${}()|\[\]\/\\])/g, "\\$1");
9668         }
9669     });
9670 })();
9671
9672 /**
9673  * @class Ext.util.TaskRunner
9674  * Provides the ability to execute one or more arbitrary tasks in a multithreaded
9675  * manner.  Generally, you can use the singleton {@link Ext.TaskManager} instead, but
9676  * if needed, you can create separate instances of TaskRunner.  Any number of
9677  * separate tasks can be started at any time and will run independently of each
9678  * other. Example usage:
9679  * <pre><code>
9680 // Start a simple clock task that updates a div once per second
9681 var updateClock = function(){
9682     Ext.fly('clock').update(new Date().format('g:i:s A'));
9683
9684 var task = {
9685     run: updateClock,
9686     interval: 1000 //1 second
9687 }
9688 var runner = new Ext.util.TaskRunner();
9689 runner.start(task);
9690
9691 // equivalent using TaskManager
9692 Ext.TaskManager.start({
9693     run: updateClock,
9694     interval: 1000
9695 });
9696
9697  * </code></pre>
9698  * <p>See the {@link #start} method for details about how to configure a task object.</p>
9699  * Also see {@link Ext.util.DelayedTask}. 
9700  * 
9701  * @constructor
9702  * @param {Number} interval (optional) The minimum precision in milliseconds supported by this TaskRunner instance
9703  * (defaults to 10)
9704  */
9705 Ext.ns('Ext.util');
9706
9707 Ext.util.TaskRunner = function(interval) {
9708     interval = interval || 10;
9709     var tasks = [],
9710     removeQueue = [],
9711     id = 0,
9712     running = false,
9713
9714     // private
9715     stopThread = function() {
9716         running = false;
9717         clearInterval(id);
9718         id = 0;
9719     },
9720
9721     // private
9722     startThread = function() {
9723         if (!running) {
9724             running = true;
9725             id = setInterval(runTasks, interval);
9726         }
9727     },
9728
9729     // private
9730     removeTask = function(t) {
9731         removeQueue.push(t);
9732         if (t.onStop) {
9733             t.onStop.apply(t.scope || t);
9734         }
9735     },
9736
9737     // private
9738     runTasks = function() {
9739         var rqLen = removeQueue.length,
9740             now = new Date().getTime(),
9741             i;
9742
9743         if (rqLen > 0) {
9744             for (i = 0; i < rqLen; i++) {
9745                 Ext.Array.remove(tasks, removeQueue[i]);
9746             }
9747             removeQueue = [];
9748             if (tasks.length < 1) {
9749                 stopThread();
9750                 return;
9751             }
9752         }
9753         i = 0;
9754         var t,
9755             itime,
9756             rt,
9757             len = tasks.length;
9758         for (; i < len; ++i) {
9759             t = tasks[i];
9760             itime = now - t.taskRunTime;
9761             if (t.interval <= itime) {
9762                 rt = t.run.apply(t.scope || t, t.args || [++t.taskRunCount]);
9763                 t.taskRunTime = now;
9764                 if (rt === false || t.taskRunCount === t.repeat) {
9765                     removeTask(t);
9766                     return;
9767                 }
9768             }
9769             if (t.duration && t.duration <= (now - t.taskStartTime)) {
9770                 removeTask(t);
9771             }
9772         }
9773     };
9774
9775     /**
9776      * Starts a new task.
9777      * @method start
9778      * @param {Object} task <p>A config object that supports the following properties:<ul>
9779      * <li><code>run</code> : Function<div class="sub-desc"><p>The function to execute each time the task is invoked. The
9780      * function will be called at each interval and passed the <code>args</code> argument if specified, and the
9781      * current invocation count if not.</p>
9782      * <p>If a particular scope (<code>this</code> reference) is required, be sure to specify it using the <code>scope</code> argument.</p>
9783      * <p>Return <code>false</code> from this function to terminate the task.</p></div></li>
9784      * <li><code>interval</code> : Number<div class="sub-desc">The frequency in milliseconds with which the task
9785      * should be invoked.</div></li>
9786      * <li><code>args</code> : Array<div class="sub-desc">(optional) An array of arguments to be passed to the function
9787      * specified by <code>run</code>. If not specified, the current invocation count is passed.</div></li>
9788      * <li><code>scope</code> : Object<div class="sub-desc">(optional) The scope (<tt>this</tt> reference) in which to execute the
9789      * <code>run</code> function. Defaults to the task config object.</div></li>
9790      * <li><code>duration</code> : Number<div class="sub-desc">(optional) The length of time in milliseconds to invoke
9791      * the task before stopping automatically (defaults to indefinite).</div></li>
9792      * <li><code>repeat</code> : Number<div class="sub-desc">(optional) The number of times to invoke the task before
9793      * stopping automatically (defaults to indefinite).</div></li>
9794      * </ul></p>
9795      * <p>Before each invocation, Ext injects the property <code>taskRunCount</code> into the task object so
9796      * that calculations based on the repeat count can be performed.</p>
9797      * @return {Object} The task
9798      */
9799     this.start = function(task) {
9800         tasks.push(task);
9801         task.taskStartTime = new Date().getTime();
9802         task.taskRunTime = 0;
9803         task.taskRunCount = 0;
9804         startThread();
9805         return task;
9806     };
9807
9808     /**
9809      * Stops an existing running task.
9810      * @method stop
9811      * @param {Object} task The task to stop
9812      * @return {Object} The task
9813      */
9814     this.stop = function(task) {
9815         removeTask(task);
9816         return task;
9817     };
9818
9819     /**
9820      * Stops all tasks that are currently running.
9821      * @method stopAll
9822      */
9823     this.stopAll = function() {
9824         stopThread();
9825         for (var i = 0, len = tasks.length; i < len; i++) {
9826             if (tasks[i].onStop) {
9827                 tasks[i].onStop();
9828             }
9829         }
9830         tasks = [];
9831         removeQueue = [];
9832     };
9833 };
9834
9835 /**
9836  * @class Ext.TaskManager
9837  * @extends Ext.util.TaskRunner
9838  * A static {@link Ext.util.TaskRunner} instance that can be used to start and stop arbitrary tasks.  See
9839  * {@link Ext.util.TaskRunner} for supported methods and task config properties.
9840  * <pre><code>
9841 // Start a simple clock task that updates a div once per second
9842 var task = {
9843     run: function(){
9844         Ext.fly('clock').update(new Date().format('g:i:s A'));
9845     },
9846     interval: 1000 //1 second
9847 }
9848 Ext.TaskManager.start(task);
9849 </code></pre>
9850  * <p>See the {@link #start} method for details about how to configure a task object.</p>
9851  * @singleton
9852  */
9853 Ext.TaskManager = Ext.create('Ext.util.TaskRunner');
9854 /**
9855  * @class Ext.is
9856  * 
9857  * Determines information about the current platform the application is running on.
9858  * 
9859  * @singleton
9860  */
9861 Ext.is = {
9862     init : function(navigator) {
9863         var platforms = this.platforms,
9864             ln = platforms.length,
9865             i, platform;
9866
9867         navigator = navigator || window.navigator;
9868
9869         for (i = 0; i < ln; i++) {
9870             platform = platforms[i];
9871             this[platform.identity] = platform.regex.test(navigator[platform.property]);
9872         }
9873
9874         /**
9875          * @property Desktop True if the browser is running on a desktop machine
9876          * @type {Boolean}
9877          */
9878         this.Desktop = this.Mac || this.Windows || (this.Linux && !this.Android);
9879         /**
9880          * @property Tablet True if the browser is running on a tablet (iPad)
9881          */
9882         this.Tablet = this.iPad;
9883         /**
9884          * @property Phone True if the browser is running on a phone.
9885          * @type {Boolean}
9886          */
9887         this.Phone = !this.Desktop && !this.Tablet;
9888         /**
9889          * @property iOS True if the browser is running on iOS
9890          * @type {Boolean}
9891          */
9892         this.iOS = this.iPhone || this.iPad || this.iPod;
9893         
9894         /**
9895          * @property Standalone Detects when application has been saved to homescreen.
9896          * @type {Boolean}
9897          */
9898         this.Standalone = !!window.navigator.standalone;
9899     },
9900     
9901     /**
9902      * @property iPhone True when the browser is running on a iPhone
9903      * @type {Boolean}
9904      */
9905     platforms: [{
9906         property: 'platform',
9907         regex: /iPhone/i,
9908         identity: 'iPhone'
9909     },
9910     
9911     /**
9912      * @property iPod True when the browser is running on a iPod
9913      * @type {Boolean}
9914      */
9915     {
9916         property: 'platform',
9917         regex: /iPod/i,
9918         identity: 'iPod'
9919     },
9920     
9921     /**
9922      * @property iPad True when the browser is running on a iPad
9923      * @type {Boolean}
9924      */
9925     {
9926         property: 'userAgent',
9927         regex: /iPad/i,
9928         identity: 'iPad'
9929     },
9930     
9931     /**
9932      * @property Blackberry True when the browser is running on a Blackberry
9933      * @type {Boolean}
9934      */
9935     {
9936         property: 'userAgent',
9937         regex: /Blackberry/i,
9938         identity: 'Blackberry'
9939     },
9940     
9941     /**
9942      * @property Android True when the browser is running on an Android device
9943      * @type {Boolean}
9944      */
9945     {
9946         property: 'userAgent',
9947         regex: /Android/i,
9948         identity: 'Android'
9949     },
9950     
9951     /**
9952      * @property Mac True when the browser is running on a Mac
9953      * @type {Boolean}
9954      */
9955     {
9956         property: 'platform',
9957         regex: /Mac/i,
9958         identity: 'Mac'
9959     },
9960     
9961     /**
9962      * @property Windows True when the browser is running on Windows
9963      * @type {Boolean}
9964      */
9965     {
9966         property: 'platform',
9967         regex: /Win/i,
9968         identity: 'Windows'
9969     },
9970     
9971     /**
9972      * @property Linux True when the browser is running on Linux
9973      * @type {Boolean}
9974      */
9975     {
9976         property: 'platform',
9977         regex: /Linux/i,
9978         identity: 'Linux'
9979     }]
9980 };
9981
9982 Ext.is.init();
9983
9984 /**
9985  * @class Ext.supports
9986  *
9987  * Determines information about features are supported in the current environment
9988  * 
9989  * @singleton
9990  */
9991 Ext.supports = {
9992     init : function() {
9993         var doc = document,
9994             div = doc.createElement('div'),
9995             tests = this.tests,
9996             ln = tests.length,
9997             i, test;
9998
9999         div.innerHTML = [
10000             '<div style="height:30px;width:50px;">',
10001                 '<div style="height:20px;width:20px;"></div>',
10002             '</div>',
10003             '<div style="width: 200px; height: 200px; position: relative; padding: 5px;">',
10004                 '<div style="position: absolute; top: 0; left: 0; width: 100%; height: 100%;"></div>',
10005             '</div>',
10006             '<div style="float:left; background-color:transparent;"></div>'
10007         ].join('');
10008
10009         doc.body.appendChild(div);
10010
10011         for (i = 0; i < ln; i++) {
10012             test = tests[i];
10013             this[test.identity] = test.fn.call(this, doc, div);
10014         }
10015
10016         doc.body.removeChild(div);
10017     },
10018
10019     /**
10020      * @property CSS3BoxShadow True if document environment supports the CSS3 box-shadow style.
10021      * @type {Boolean}
10022      */
10023     CSS3BoxShadow: Ext.isDefined(document.documentElement.style.boxShadow),
10024
10025     /**
10026      * @property ClassList True if document environment supports the HTML5 classList API.
10027      * @type {Boolean}
10028      */
10029     ClassList: !!document.documentElement.classList,
10030
10031     /**
10032      * @property OrientationChange True if the device supports orientation change
10033      * @type {Boolean}
10034      */
10035     OrientationChange: ((typeof window.orientation != 'undefined') && ('onorientationchange' in window)),
10036     
10037     /**
10038      * @property DeviceMotion True if the device supports device motion (acceleration and rotation rate)
10039      * @type {Boolean}
10040      */
10041     DeviceMotion: ('ondevicemotion' in window),
10042     
10043     /**
10044      * @property Touch True if the device supports touch
10045      * @type {Boolean}
10046      */
10047     // is.Desktop is needed due to the bug in Chrome 5.0.375, Safari 3.1.2
10048     // and Safari 4.0 (they all have 'ontouchstart' in the window object).
10049     Touch: ('ontouchstart' in window) && (!Ext.is.Desktop),
10050
10051     tests: [
10052         /**
10053          * @property Transitions True if the device supports CSS3 Transitions
10054          * @type {Boolean}
10055          */
10056         {
10057             identity: 'Transitions',
10058             fn: function(doc, div) {
10059                 var prefix = [
10060                         'webkit',
10061                         'Moz',
10062                         'o',
10063                         'ms',
10064                         'khtml'
10065                     ],
10066                     TE = 'TransitionEnd',
10067                     transitionEndName = [
10068                         prefix[0] + TE,
10069                         'transitionend', //Moz bucks the prefixing convention
10070                         prefix[2] + TE,
10071                         prefix[3] + TE,
10072                         prefix[4] + TE
10073                     ],
10074                     ln = prefix.length,
10075                     i = 0,
10076                     out = false;
10077                 div = Ext.get(div);
10078                 for (; i < ln; i++) {
10079                     if (div.getStyle(prefix[i] + "TransitionProperty")) {
10080                         Ext.supports.CSS3Prefix = prefix[i];
10081                         Ext.supports.CSS3TransitionEnd = transitionEndName[i];
10082                         out = true;
10083                         break;
10084                     }
10085                 }
10086                 return out;
10087             }
10088         },
10089         
10090         /**
10091          * @property RightMargin True if the device supports right margin.
10092          * See https://bugs.webkit.org/show_bug.cgi?id=13343 for why this is needed.
10093          * @type {Boolean}
10094          */
10095         {
10096             identity: 'RightMargin',
10097             fn: function(doc, div) {
10098                 var view = doc.defaultView;
10099                 return !(view && view.getComputedStyle(div.firstChild.firstChild, null).marginRight != '0px');
10100             }
10101         },
10102
10103         /**
10104          * @property DisplayChangeInputSelectionBug True if INPUT elements lose their
10105          * selection when their display style is changed. Essentially, if a text input
10106          * has focus and its display style is changed, the I-beam disappears.
10107          * 
10108          * This bug is encountered due to the work around in place for the {@link RightMargin}
10109          * bug. This has been observed in Safari 4.0.4 and older, and appears to be fixed
10110          * in Safari 5. It's not clear if Safari 4.1 has the bug, but it has the same WebKit
10111          * version number as Safari 5 (according to http://unixpapa.com/js/gecko.html).
10112          */
10113         {
10114             identity: 'DisplayChangeInputSelectionBug',
10115             fn: function() {
10116                 var webKitVersion = Ext.webKitVersion;
10117                 // WebKit but older than Safari 5 or Chrome 6:
10118                 return 0 < webKitVersion && webKitVersion < 533;
10119             }
10120         },
10121
10122         /**
10123          * @property DisplayChangeTextAreaSelectionBug True if TEXTAREA elements lose their
10124          * selection when their display style is changed. Essentially, if a text area has
10125          * focus and its display style is changed, the I-beam disappears.
10126          *
10127          * This bug is encountered due to the work around in place for the {@link RightMargin}
10128          * bug. This has been observed in Chrome 10 and Safari 5 and older, and appears to
10129          * be fixed in Chrome 11.
10130          */
10131         {
10132             identity: 'DisplayChangeTextAreaSelectionBug',
10133             fn: function() {
10134                 var webKitVersion = Ext.webKitVersion;
10135
10136                 /*
10137                 Has bug w/textarea:
10138
10139                 (Chrome) Mozilla/5.0 (Macintosh; U; Intel Mac OS X 10_6_7; en-US)
10140                             AppleWebKit/534.16 (KHTML, like Gecko) Chrome/10.0.648.127
10141                             Safari/534.16
10142                 (Safari) Mozilla/5.0 (Macintosh; U; Intel Mac OS X 10_6_7; en-us)
10143                             AppleWebKit/533.21.1 (KHTML, like Gecko) Version/5.0.5
10144                             Safari/533.21.1
10145
10146                 No bug:
10147
10148                 (Chrome) Mozilla/5.0 (Macintosh; Intel Mac OS X 10_6_7)
10149                             AppleWebKit/534.24 (KHTML, like Gecko) Chrome/11.0.696.57
10150                             Safari/534.24
10151                 */
10152                 return 0 < webKitVersion && webKitVersion < 534.24;
10153             }
10154         },
10155
10156         /**
10157          * @property TransparentColor True if the device supports transparent color
10158          * @type {Boolean}
10159          */
10160         {
10161             identity: 'TransparentColor',
10162             fn: function(doc, div, view) {
10163                 view = doc.defaultView;
10164                 return !(view && view.getComputedStyle(div.lastChild, null).backgroundColor != 'transparent');
10165             }
10166         },
10167
10168         /**
10169          * @property ComputedStyle True if the browser supports document.defaultView.getComputedStyle()
10170          * @type {Boolean}
10171          */
10172         {
10173             identity: 'ComputedStyle',
10174             fn: function(doc, div, view) {
10175                 view = doc.defaultView;
10176                 return view && view.getComputedStyle;
10177             }
10178         },
10179         
10180         /**
10181          * @property SVG True if the device supports SVG
10182          * @type {Boolean}
10183          */
10184         {
10185             identity: 'Svg',
10186             fn: function(doc) {
10187                 return !!doc.createElementNS && !!doc.createElementNS( "http:/" + "/www.w3.org/2000/svg", "svg").createSVGRect;
10188             }
10189         },
10190     
10191         /**
10192          * @property Canvas True if the device supports Canvas
10193          * @type {Boolean}
10194          */
10195         {
10196             identity: 'Canvas',
10197             fn: function(doc) {
10198                 return !!doc.createElement('canvas').getContext;
10199             }
10200         },
10201         
10202         /**
10203          * @property VML True if the device supports VML
10204          * @type {Boolean}
10205          */
10206         {
10207             identity: 'Vml',
10208             fn: function(doc) {
10209                 var d = doc.createElement("div");
10210                 d.innerHTML = "<!--[if vml]><br><br><![endif]-->";
10211                 return (d.childNodes.length == 2);
10212             }
10213         },
10214         
10215         /**
10216          * @property Float True if the device supports CSS float
10217          * @type {Boolean}
10218          */
10219         {
10220             identity: 'Float',
10221             fn: function(doc, div) {
10222                 return !!div.lastChild.style.cssFloat;
10223             }
10224         },
10225         
10226         /**
10227          * @property AudioTag True if the device supports the HTML5 audio tag
10228          * @type {Boolean}
10229          */
10230         {
10231             identity: 'AudioTag',
10232             fn: function(doc) {
10233                 return !!doc.createElement('audio').canPlayType;
10234             }
10235         },
10236         
10237         /**
10238          * @property History True if the device supports HTML5 history
10239          * @type {Boolean}
10240          */
10241         {
10242             identity: 'History',
10243             fn: function() {
10244                 return !!(window.history && history.pushState);
10245             }
10246         },
10247         
10248         /**
10249          * @property CSS3DTransform True if the device supports CSS3DTransform
10250          * @type {Boolean}
10251          */
10252         {
10253             identity: 'CSS3DTransform',
10254             fn: function() {
10255                 return (typeof WebKitCSSMatrix != 'undefined' && new WebKitCSSMatrix().hasOwnProperty('m41'));
10256             }
10257         },
10258
10259                 /**
10260          * @property CSS3LinearGradient True if the device supports CSS3 linear gradients
10261          * @type {Boolean}
10262          */
10263         {
10264             identity: 'CSS3LinearGradient',
10265             fn: function(doc, div) {
10266                 var property = 'background-image:',
10267                     webkit   = '-webkit-gradient(linear, left top, right bottom, from(black), to(white))',
10268                     w3c      = 'linear-gradient(left top, black, white)',
10269                     moz      = '-moz-' + w3c,
10270                     options  = [property + webkit, property + w3c, property + moz];
10271                 
10272                 div.style.cssText = options.join(';');
10273                 
10274                 return ("" + div.style.backgroundImage).indexOf('gradient') !== -1;
10275             }
10276         },
10277         
10278         /**
10279          * @property CSS3BorderRadius True if the device supports CSS3 border radius
10280          * @type {Boolean}
10281          */
10282         {
10283             identity: 'CSS3BorderRadius',
10284             fn: function(doc, div) {
10285                 var domPrefixes = ['borderRadius', 'BorderRadius', 'MozBorderRadius', 'WebkitBorderRadius', 'OBorderRadius', 'KhtmlBorderRadius'],
10286                     pass = false,
10287                     i;
10288                 for (i = 0; i < domPrefixes.length; i++) {
10289                     if (document.body.style[domPrefixes[i]] !== undefined) {
10290                         return true;
10291                     }
10292                 }
10293                 return pass;
10294             }
10295         },
10296         
10297         /**
10298          * @property GeoLocation True if the device supports GeoLocation
10299          * @type {Boolean}
10300          */
10301         {
10302             identity: 'GeoLocation',
10303             fn: function() {
10304                 return (typeof navigator != 'undefined' && typeof navigator.geolocation != 'undefined') || (typeof google != 'undefined' && typeof google.gears != 'undefined');
10305             }
10306         },
10307         /**
10308          * @property MouseEnterLeave True if the browser supports mouseenter and mouseleave events
10309          * @type {Boolean}
10310          */
10311         {
10312             identity: 'MouseEnterLeave',
10313             fn: function(doc, div){
10314                 return ('onmouseenter' in div && 'onmouseleave' in div);
10315             }
10316         },
10317         /**
10318          * @property MouseWheel True if the browser supports the mousewheel event
10319          * @type {Boolean}
10320          */
10321         {
10322             identity: 'MouseWheel',
10323             fn: function(doc, div) {
10324                 return ('onmousewheel' in div);
10325             }
10326         },
10327         /**
10328          * @property Opacity True if the browser supports normal css opacity
10329          * @type {Boolean}
10330          */
10331         {
10332             identity: 'Opacity',
10333             fn: function(doc, div){
10334                 // Not a strict equal comparison in case opacity can be converted to a number.
10335                 if (Ext.isIE6 || Ext.isIE7 || Ext.isIE8) {
10336                     return false;
10337                 }
10338                 div.firstChild.style.cssText = 'opacity:0.73';
10339                 return div.firstChild.style.opacity == '0.73';
10340             }
10341         },
10342         /**
10343          * @property Placeholder True if the browser supports the HTML5 placeholder attribute on inputs
10344          * @type {Boolean}
10345          */
10346         {
10347             identity: 'Placeholder',
10348             fn: function(doc) {
10349                 return 'placeholder' in doc.createElement('input');
10350             }
10351         },
10352         
10353         /**
10354          * @property Direct2DBug True if when asking for an element's dimension via offsetWidth or offsetHeight, 
10355          * getBoundingClientRect, etc. the browser returns the subpixel width rounded to the nearest pixel.
10356          * @type {Boolean}
10357          */
10358         {
10359             identity: 'Direct2DBug',
10360             fn: function() {
10361                 return Ext.isString(document.body.style.msTransformOrigin);
10362             }
10363         },
10364         /**
10365          * @property BoundingClientRect True if the browser supports the getBoundingClientRect method on elements
10366          * @type {Boolean}
10367          */
10368         {
10369             identity: 'BoundingClientRect',
10370             fn: function(doc, div) {
10371                 return Ext.isFunction(div.getBoundingClientRect);
10372             }
10373         },
10374         {
10375             identity: 'IncludePaddingInWidthCalculation',
10376             fn: function(doc, div){
10377                 var el = Ext.get(div.childNodes[1].firstChild);
10378                 return el.getWidth() == 210;
10379             }
10380         },
10381         {
10382             identity: 'IncludePaddingInHeightCalculation',
10383             fn: function(doc, div){
10384                 var el = Ext.get(div.childNodes[1].firstChild);
10385                 return el.getHeight() == 210;
10386             }
10387         },
10388         
10389         /**
10390          * @property ArraySort True if the Array sort native method isn't bugged.
10391          * @type {Boolean}
10392          */
10393         {
10394             identity: 'ArraySort',
10395             fn: function() {
10396                 var a = [1,2,3,4,5].sort(function(){ return 0; });
10397                 return a[0] === 1 && a[1] === 2 && a[2] === 3 && a[3] === 4 && a[4] === 5;
10398             }
10399         },
10400         /**
10401          * @property Range True if browser support document.createRange native method.
10402          * @type {Boolean}
10403          */
10404         {
10405             identity: 'Range',
10406             fn: function() {
10407                 return !!document.createRange;
10408             }
10409         },
10410         /**
10411          * @property CreateContextualFragment True if browser support CreateContextualFragment range native methods.
10412          * @type {Boolean}
10413          */
10414         {
10415             identity: 'CreateContextualFragment',
10416             fn: function() {
10417                 var range = Ext.supports.Range ? document.createRange() : false;
10418                 
10419                 return range && !!range.createContextualFragment;
10420             }
10421         },
10422
10423         /**
10424          * @property WindowOnError True if browser supports window.onerror.
10425          * @type {Boolean}
10426          */
10427         {
10428             identity: 'WindowOnError',
10429             fn: function () {
10430                 // sadly, we cannot feature detect this...
10431                 return Ext.isIE || Ext.isGecko || Ext.webKitVersion >= 534.16; // Chrome 10+
10432             }
10433         }
10434     ]
10435 };
10436
10437
10438
10439 /*
10440 Ext JS - JavaScript Library
10441 Copyright (c) 2006-2011, Sencha Inc.
10442 All rights reserved.
10443 licensing@sencha.com
10444 */
10445 /**
10446  * @class Ext.core.DomHelper
10447  * <p>The DomHelper class provides a layer of abstraction from DOM and transparently supports creating
10448  * elements via DOM or using HTML fragments. It also has the ability to create HTML fragment templates
10449  * from your DOM building code.</p>
10450  *
10451  * <p><b><u>DomHelper element specification object</u></b></p>
10452  * <p>A specification object is used when creating elements. Attributes of this object
10453  * are assumed to be element attributes, except for 4 special attributes:
10454  * <div class="mdetail-params"><ul>
10455  * <li><b><tt>tag</tt></b> : <div class="sub-desc">The tag name of the element</div></li>
10456  * <li><b><tt>children</tt></b> : or <tt>cn</tt><div class="sub-desc">An array of the
10457  * same kind of element definition objects to be created and appended. These can be nested
10458  * as deep as you want.</div></li>
10459  * <li><b><tt>cls</tt></b> : <div class="sub-desc">The class attribute of the element.
10460  * This will end up being either the "class" attribute on a HTML fragment or className
10461  * for a DOM node, depending on whether DomHelper is using fragments or DOM.</div></li>
10462  * <li><b><tt>html</tt></b> : <div class="sub-desc">The innerHTML for the element</div></li>
10463  * </ul></div></p>
10464  * <p><b>NOTE:</b> For other arbitrary attributes, the value will currently <b>not</b> be automatically
10465  * HTML-escaped prior to building the element's HTML string. This means that if your attribute value
10466  * contains special characters that would not normally be allowed in a double-quoted attribute value,
10467  * you <b>must</b> manually HTML-encode it beforehand (see {@link Ext.String#htmlEncode}) or risk
10468  * malformed HTML being created. This behavior may change in a future release.</p>
10469  *
10470  * <p><b><u>Insertion methods</u></b></p>
10471  * <p>Commonly used insertion methods:
10472  * <div class="mdetail-params"><ul>
10473  * <li><b><tt>{@link #append}</tt></b> : <div class="sub-desc"></div></li>
10474  * <li><b><tt>{@link #insertBefore}</tt></b> : <div class="sub-desc"></div></li>
10475  * <li><b><tt>{@link #insertAfter}</tt></b> : <div class="sub-desc"></div></li>
10476  * <li><b><tt>{@link #overwrite}</tt></b> : <div class="sub-desc"></div></li>
10477  * <li><b><tt>{@link #createTemplate}</tt></b> : <div class="sub-desc"></div></li>
10478  * <li><b><tt>{@link #insertHtml}</tt></b> : <div class="sub-desc"></div></li>
10479  * </ul></div></p>
10480  *
10481  * <p><b><u>Example</u></b></p>
10482  * <p>This is an example, where an unordered list with 3 children items is appended to an existing
10483  * element with id <tt>'my-div'</tt>:<br>
10484  <pre><code>
10485 var dh = Ext.core.DomHelper; // create shorthand alias
10486 // specification object
10487 var spec = {
10488     id: 'my-ul',
10489     tag: 'ul',
10490     cls: 'my-list',
10491     // append children after creating
10492     children: [     // may also specify 'cn' instead of 'children'
10493         {tag: 'li', id: 'item0', html: 'List Item 0'},
10494         {tag: 'li', id: 'item1', html: 'List Item 1'},
10495         {tag: 'li', id: 'item2', html: 'List Item 2'}
10496     ]
10497 };
10498 var list = dh.append(
10499     'my-div', // the context element 'my-div' can either be the id or the actual node
10500     spec      // the specification object
10501 );
10502  </code></pre></p>
10503  * <p>Element creation specification parameters in this class may also be passed as an Array of
10504  * specification objects. This can be used to insert multiple sibling nodes into an existing
10505  * container very efficiently. For example, to add more list items to the example above:<pre><code>
10506 dh.append('my-ul', [
10507     {tag: 'li', id: 'item3', html: 'List Item 3'},
10508     {tag: 'li', id: 'item4', html: 'List Item 4'}
10509 ]);
10510  * </code></pre></p>
10511  *
10512  * <p><b><u>Templating</u></b></p>
10513  * <p>The real power is in the built-in templating. Instead of creating or appending any elements,
10514  * <tt>{@link #createTemplate}</tt> returns a Template object which can be used over and over to
10515  * insert new elements. Revisiting the example above, we could utilize templating this time:
10516  * <pre><code>
10517 // create the node
10518 var list = dh.append('my-div', {tag: 'ul', cls: 'my-list'});
10519 // get template
10520 var tpl = dh.createTemplate({tag: 'li', id: 'item{0}', html: 'List Item {0}'});
10521
10522 for(var i = 0; i < 5, i++){
10523     tpl.append(list, [i]); // use template to append to the actual node
10524 }
10525  * </code></pre></p>
10526  * <p>An example using a template:<pre><code>
10527 var html = '<a id="{0}" href="{1}" class="nav">{2}</a>';
10528
10529 var tpl = new Ext.core.DomHelper.createTemplate(html);
10530 tpl.append('blog-roll', ['link1', 'http://www.edspencer.net/', "Ed&#39;s Site"]);
10531 tpl.append('blog-roll', ['link2', 'http://www.dustindiaz.com/', "Dustin&#39;s Site"]);
10532  * </code></pre></p>
10533  *
10534  * <p>The same example using named parameters:<pre><code>
10535 var html = '<a id="{id}" href="{url}" class="nav">{text}</a>';
10536
10537 var tpl = new Ext.core.DomHelper.createTemplate(html);
10538 tpl.append('blog-roll', {
10539     id: 'link1',
10540     url: 'http://www.edspencer.net/',
10541     text: "Ed&#39;s Site"
10542 });
10543 tpl.append('blog-roll', {
10544     id: 'link2',
10545     url: 'http://www.dustindiaz.com/',
10546     text: "Dustin&#39;s Site"
10547 });
10548  * </code></pre></p>
10549  *
10550  * <p><b><u>Compiling Templates</u></b></p>
10551  * <p>Templates are applied using regular expressions. The performance is great, but if
10552  * you are adding a bunch of DOM elements using the same template, you can increase
10553  * performance even further by {@link Ext.Template#compile "compiling"} the template.
10554  * The way "{@link Ext.Template#compile compile()}" works is the template is parsed and
10555  * broken up at the different variable points and a dynamic function is created and eval'ed.
10556  * The generated function performs string concatenation of these parts and the passed
10557  * variables instead of using regular expressions.
10558  * <pre><code>
10559 var html = '<a id="{id}" href="{url}" class="nav">{text}</a>';
10560
10561 var tpl = new Ext.core.DomHelper.createTemplate(html);
10562 tpl.compile();
10563
10564 //... use template like normal
10565  * </code></pre></p>
10566  *
10567  * <p><b><u>Performance Boost</u></b></p>
10568  * <p>DomHelper will transparently create HTML fragments when it can. Using HTML fragments instead
10569  * of DOM can significantly boost performance.</p>
10570  * <p>Element creation specification parameters may also be strings. If {@link #useDom} is <tt>false</tt>,
10571  * then the string is used as innerHTML. If {@link #useDom} is <tt>true</tt>, a string specification
10572  * results in the creation of a text node. Usage:</p>
10573  * <pre><code>
10574 Ext.core.DomHelper.useDom = true; // force it to use DOM; reduces performance
10575  * </code></pre>
10576  * @singleton
10577  */
10578 Ext.ns('Ext.core');
10579 Ext.core.DomHelper = function(){
10580     var tempTableEl = null,
10581         emptyTags = /^(?:br|frame|hr|img|input|link|meta|range|spacer|wbr|area|param|col)$/i,
10582         tableRe = /^table|tbody|tr|td$/i,
10583         confRe = /tag|children|cn|html$/i,
10584         tableElRe = /td|tr|tbody/i,
10585         endRe = /end/i,
10586         pub,
10587         // kill repeat to save bytes
10588         afterbegin = 'afterbegin',
10589         afterend = 'afterend',
10590         beforebegin = 'beforebegin',
10591         beforeend = 'beforeend',
10592         ts = '<table>',
10593         te = '</table>',
10594         tbs = ts+'<tbody>',
10595         tbe = '</tbody>'+te,
10596         trs = tbs + '<tr>',
10597         tre = '</tr>'+tbe;
10598
10599     // private
10600     function doInsert(el, o, returnElement, pos, sibling, append){
10601         el = Ext.getDom(el);
10602         var newNode;
10603         if (pub.useDom) {
10604             newNode = createDom(o, null);
10605             if (append) {
10606                 el.appendChild(newNode);
10607             } else {
10608                 (sibling == 'firstChild' ? el : el.parentNode).insertBefore(newNode, el[sibling] || el);
10609             }
10610         } else {
10611             newNode = Ext.core.DomHelper.insertHtml(pos, el, Ext.core.DomHelper.createHtml(o));
10612         }
10613         return returnElement ? Ext.get(newNode, true) : newNode;
10614     }
10615     
10616     function createDom(o, parentNode){
10617         var el,
10618             doc = document,
10619             useSet,
10620             attr,
10621             val,
10622             cn;
10623
10624         if (Ext.isArray(o)) {                       // Allow Arrays of siblings to be inserted
10625             el = doc.createDocumentFragment(); // in one shot using a DocumentFragment
10626             for (var i = 0, l = o.length; i < l; i++) {
10627                 createDom(o[i], el);
10628             }
10629         } else if (typeof o == 'string') {         // Allow a string as a child spec.
10630             el = doc.createTextNode(o);
10631         } else {
10632             el = doc.createElement( o.tag || 'div' );
10633             useSet = !!el.setAttribute; // In IE some elements don't have setAttribute
10634             for (attr in o) {
10635                 if(!confRe.test(attr)){
10636                     val = o[attr];
10637                     if(attr == 'cls'){
10638                         el.className = val;
10639                     }else{
10640                         if(useSet){
10641                             el.setAttribute(attr, val);
10642                         }else{
10643                             el[attr] = val;
10644                         }
10645                     }
10646                 }
10647             }
10648             Ext.core.DomHelper.applyStyles(el, o.style);
10649
10650             if ((cn = o.children || o.cn)) {
10651                 createDom(cn, el);
10652             } else if (o.html) {
10653                 el.innerHTML = o.html;
10654             }
10655         }
10656         if(parentNode){
10657            parentNode.appendChild(el);
10658         }
10659         return el;
10660     }
10661
10662     // build as innerHTML where available
10663     function createHtml(o){
10664         var b = '',
10665             attr,
10666             val,
10667             key,
10668             cn,
10669             i;
10670
10671         if(typeof o == "string"){
10672             b = o;
10673         } else if (Ext.isArray(o)) {
10674             for (i=0; i < o.length; i++) {
10675                 if(o[i]) {
10676                     b += createHtml(o[i]);
10677                 }
10678             }
10679         } else {
10680             b += '<' + (o.tag = o.tag || 'div');
10681             for (attr in o) {
10682                 val = o[attr];
10683                 if(!confRe.test(attr)){
10684                     if (typeof val == "object") {
10685                         b += ' ' + attr + '="';
10686                         for (key in val) {
10687                             b += key + ':' + val[key] + ';';
10688                         }
10689                         b += '"';
10690                     }else{
10691                         b += ' ' + ({cls : 'class', htmlFor : 'for'}[attr] || attr) + '="' + val + '"';
10692                     }
10693                 }
10694             }
10695             // Now either just close the tag or try to add children and close the tag.
10696             if (emptyTags.test(o.tag)) {
10697                 b += '/>';
10698             } else {
10699                 b += '>';
10700                 if ((cn = o.children || o.cn)) {
10701                     b += createHtml(cn);
10702                 } else if(o.html){
10703                     b += o.html;
10704                 }
10705                 b += '</' + o.tag + '>';
10706             }
10707         }
10708         return b;
10709     }
10710
10711     function ieTable(depth, s, h, e){
10712         tempTableEl.innerHTML = [s, h, e].join('');
10713         var i = -1,
10714             el = tempTableEl,
10715             ns;
10716         while(++i < depth){
10717             el = el.firstChild;
10718         }
10719 //      If the result is multiple siblings, then encapsulate them into one fragment.
10720         ns = el.nextSibling;
10721         if (ns){
10722             var df = document.createDocumentFragment();
10723             while(el){
10724                 ns = el.nextSibling;
10725                 df.appendChild(el);
10726                 el = ns;
10727             }
10728             el = df;
10729         }
10730         return el;
10731     }
10732
10733     /**
10734      * @ignore
10735      * Nasty code for IE's broken table implementation
10736      */
10737     function insertIntoTable(tag, where, el, html) {
10738         var node,
10739             before;
10740
10741         tempTableEl = tempTableEl || document.createElement('div');
10742
10743         if(tag == 'td' && (where == afterbegin || where == beforeend) ||
10744            !tableElRe.test(tag) && (where == beforebegin || where == afterend)) {
10745             return null;
10746         }
10747         before = where == beforebegin ? el :
10748                  where == afterend ? el.nextSibling :
10749                  where == afterbegin ? el.firstChild : null;
10750
10751         if (where == beforebegin || where == afterend) {
10752             el = el.parentNode;
10753         }
10754
10755         if (tag == 'td' || (tag == 'tr' && (where == beforeend || where == afterbegin))) {
10756             node = ieTable(4, trs, html, tre);
10757         } else if ((tag == 'tbody' && (where == beforeend || where == afterbegin)) ||
10758                    (tag == 'tr' && (where == beforebegin || where == afterend))) {
10759             node = ieTable(3, tbs, html, tbe);
10760         } else {
10761             node = ieTable(2, ts, html, te);
10762         }
10763         el.insertBefore(node, before);
10764         return node;
10765     }
10766     
10767     /**
10768      * @ignore
10769      * Fix for IE9 createContextualFragment missing method
10770      */   
10771     function createContextualFragment(html){
10772         var div = document.createElement("div"),
10773             fragment = document.createDocumentFragment(),
10774             i = 0,
10775             length, childNodes;
10776         
10777         div.innerHTML = html;
10778         childNodes = div.childNodes;
10779         length = childNodes.length;
10780
10781         for (; i < length; i++) {
10782             fragment.appendChild(childNodes[i].cloneNode(true));
10783         }
10784
10785         return fragment;
10786     }
10787     
10788     pub = {
10789         /**
10790          * Returns the markup for the passed Element(s) config.
10791          * @param {Object} o The DOM object spec (and children)
10792          * @return {String}
10793          */
10794         markup : function(o){
10795             return createHtml(o);
10796         },
10797
10798         /**
10799          * Applies a style specification to an element.
10800          * @param {String/HTMLElement} el The element to apply styles to
10801          * @param {String/Object/Function} styles A style specification string e.g. 'width:100px', or object in the form {width:'100px'}, or
10802          * a function which returns such a specification.
10803          */
10804         applyStyles : function(el, styles){
10805             if (styles) {
10806                 el = Ext.fly(el);
10807                 if (typeof styles == "function") {
10808                     styles = styles.call();
10809                 }
10810                 if (typeof styles == "string") {
10811                     styles = Ext.core.Element.parseStyles(styles);
10812                 }
10813                 if (typeof styles == "object") {
10814                     el.setStyle(styles);
10815                 }
10816             }
10817         },
10818
10819         /**
10820          * Inserts an HTML fragment into the DOM.
10821          * @param {String} where Where to insert the html in relation to el - beforeBegin, afterBegin, beforeEnd, afterEnd.
10822          * @param {HTMLElement/TextNode} el The context element
10823          * @param {String} html The HTML fragment
10824          * @return {HTMLElement} The new node
10825          */
10826         insertHtml : function(where, el, html){
10827             var hash = {},
10828                 hashVal,
10829                 range,
10830                 rangeEl,
10831                 setStart,
10832                 frag,
10833                 rs;
10834
10835             where = where.toLowerCase();
10836             // add these here because they are used in both branches of the condition.
10837             hash[beforebegin] = ['BeforeBegin', 'previousSibling'];
10838             hash[afterend] = ['AfterEnd', 'nextSibling'];
10839             
10840             // if IE and context element is an HTMLElement
10841             if (el.insertAdjacentHTML) {
10842                 if(tableRe.test(el.tagName) && (rs = insertIntoTable(el.tagName.toLowerCase(), where, el, html))){
10843                     return rs;
10844                 }
10845                 
10846                 // add these two to the hash.
10847                 hash[afterbegin] = ['AfterBegin', 'firstChild'];
10848                 hash[beforeend] = ['BeforeEnd', 'lastChild'];
10849                 if ((hashVal = hash[where])) {
10850                     el.insertAdjacentHTML(hashVal[0], html);
10851                     return el[hashVal[1]];
10852                 }
10853             // if (not IE and context element is an HTMLElement) or TextNode
10854             } else {
10855                 // we cannot insert anything inside a textnode so...
10856                 if (Ext.isTextNode(el)) {
10857                     where = where === 'afterbegin' ? 'beforebegin' : where; 
10858                     where = where === 'beforeend' ? 'afterend' : where;
10859                 }
10860                 range = Ext.supports.CreateContextualFragment ? el.ownerDocument.createRange() : undefined;
10861                 setStart = 'setStart' + (endRe.test(where) ? 'After' : 'Before');
10862                 if (hash[where]) {
10863                     if (range) {
10864                         range[setStart](el);
10865                         frag = range.createContextualFragment(html);
10866                     } else {
10867                         frag = createContextualFragment(html);
10868                     }
10869                     el.parentNode.insertBefore(frag, where == beforebegin ? el : el.nextSibling);
10870                     return el[(where == beforebegin ? 'previous' : 'next') + 'Sibling'];
10871                 } else {
10872                     rangeEl = (where == afterbegin ? 'first' : 'last') + 'Child';
10873                     if (el.firstChild) {
10874                         if (range) {
10875                             range[setStart](el[rangeEl]);
10876                             frag = range.createContextualFragment(html);
10877                         } else {
10878                             frag = createContextualFragment(html);
10879                         }
10880                         
10881                         if(where == afterbegin){
10882                             el.insertBefore(frag, el.firstChild);
10883                         }else{
10884                             el.appendChild(frag);
10885                         }
10886                     } else {
10887                         el.innerHTML = html;
10888                     }
10889                     return el[rangeEl];
10890                 }
10891             }
10892             Ext.Error.raise({
10893                 sourceClass: 'Ext.core.DomHelper',
10894                 sourceMethod: 'insertHtml',
10895                 htmlToInsert: html,
10896                 targetElement: el,
10897                 msg: 'Illegal insertion point reached: "' + where + '"'
10898             });
10899         },
10900
10901         /**
10902          * Creates new DOM element(s) and inserts them before el.
10903          * @param {Mixed} el The context element
10904          * @param {Object/String} o The DOM object spec (and children) or raw HTML blob
10905          * @param {Boolean} returnElement (optional) true to return a Ext.core.Element
10906          * @return {HTMLElement/Ext.core.Element} The new node
10907          */
10908         insertBefore : function(el, o, returnElement){
10909             return doInsert(el, o, returnElement, beforebegin);
10910         },
10911
10912         /**
10913          * Creates new DOM element(s) and inserts them after el.
10914          * @param {Mixed} el The context element
10915          * @param {Object} o The DOM object spec (and children)
10916          * @param {Boolean} returnElement (optional) true to return a Ext.core.Element
10917          * @return {HTMLElement/Ext.core.Element} The new node
10918          */
10919         insertAfter : function(el, o, returnElement){
10920             return doInsert(el, o, returnElement, afterend, 'nextSibling');
10921         },
10922
10923         /**
10924          * Creates new DOM element(s) and inserts them as the first child of el.
10925          * @param {Mixed} el The context element
10926          * @param {Object/String} o The DOM object spec (and children) or raw HTML blob
10927          * @param {Boolean} returnElement (optional) true to return a Ext.core.Element
10928          * @return {HTMLElement/Ext.core.Element} The new node
10929          */
10930         insertFirst : function(el, o, returnElement){
10931             return doInsert(el, o, returnElement, afterbegin, 'firstChild');
10932         },
10933
10934         /**
10935          * Creates new DOM element(s) and appends them to el.
10936          * @param {Mixed} el The context element
10937          * @param {Object/String} o The DOM object spec (and children) or raw HTML blob
10938          * @param {Boolean} returnElement (optional) true to return a Ext.core.Element
10939          * @return {HTMLElement/Ext.core.Element} The new node
10940          */
10941         append : function(el, o, returnElement){
10942             return doInsert(el, o, returnElement, beforeend, '', true);
10943         },
10944
10945         /**
10946          * Creates new DOM element(s) and overwrites the contents of el with them.
10947          * @param {Mixed} el The context element
10948          * @param {Object/String} o The DOM object spec (and children) or raw HTML blob
10949          * @param {Boolean} returnElement (optional) true to return a Ext.core.Element
10950          * @return {HTMLElement/Ext.core.Element} The new node
10951          */
10952         overwrite : function(el, o, returnElement){
10953             el = Ext.getDom(el);
10954             el.innerHTML = createHtml(o);
10955             return returnElement ? Ext.get(el.firstChild) : el.firstChild;
10956         },
10957
10958         createHtml : createHtml,
10959         
10960         /**
10961          * Creates new DOM element(s) without inserting them to the document.
10962          * @param {Object/String} o The DOM object spec (and children) or raw HTML blob
10963          * @return {HTMLElement} The new uninserted node
10964          * @method
10965          */
10966         createDom: createDom,
10967         
10968         /** True to force the use of DOM instead of html fragments @type Boolean */
10969         useDom : false,
10970         
10971         /**
10972          * Creates a new Ext.Template from the DOM object spec.
10973          * @param {Object} o The DOM object spec (and children)
10974          * @return {Ext.Template} The new template
10975          */
10976         createTemplate : function(o){
10977             var html = Ext.core.DomHelper.createHtml(o);
10978             return Ext.create('Ext.Template', html);
10979         }
10980     };
10981     return pub;
10982 }();
10983
10984 /*
10985  * This is code is also distributed under MIT license for use
10986  * with jQuery and prototype JavaScript libraries.
10987  */
10988 /**
10989  * @class Ext.DomQuery
10990 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).
10991 <p>
10992 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>
10993
10994 <p>
10995 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.
10996 </p>
10997 <h4>Element Selectors:</h4>
10998 <ul class="list">
10999     <li> <b>*</b> any element</li>
11000     <li> <b>E</b> an element with the tag E</li>
11001     <li> <b>E F</b> All descendent elements of E that have the tag F</li>
11002     <li> <b>E > F</b> or <b>E/F</b> all direct children elements of E that have the tag F</li>
11003     <li> <b>E + F</b> all elements with the tag F that are immediately preceded by an element with the tag E</li>
11004     <li> <b>E ~ F</b> all elements with the tag F that are preceded by a sibling element with the tag E</li>
11005 </ul>
11006 <h4>Attribute Selectors:</h4>
11007 <p>The use of &#64; and quotes are optional. For example, div[&#64;foo='bar'] is also a valid attribute selector.</p>
11008 <ul class="list">
11009     <li> <b>E[foo]</b> has an attribute "foo"</li>
11010     <li> <b>E[foo=bar]</b> has an attribute "foo" that equals "bar"</li>
11011     <li> <b>E[foo^=bar]</b> has an attribute "foo" that starts with "bar"</li>
11012     <li> <b>E[foo$=bar]</b> has an attribute "foo" that ends with "bar"</li>
11013     <li> <b>E[foo*=bar]</b> has an attribute "foo" that contains the substring "bar"</li>
11014     <li> <b>E[foo%=2]</b> has an attribute "foo" that is evenly divisible by 2</li>
11015     <li> <b>E[foo!=bar]</b> attribute "foo" does not equal "bar"</li>
11016 </ul>
11017 <h4>Pseudo Classes:</h4>
11018 <ul class="list">
11019     <li> <b>E:first-child</b> E is the first child of its parent</li>
11020     <li> <b>E:last-child</b> E is the last child of its parent</li>
11021     <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>
11022     <li> <b>E:nth-child(odd)</b> E is an odd child of its parent</li>
11023     <li> <b>E:nth-child(even)</b> E is an even child of its parent</li>
11024     <li> <b>E:only-child</b> E is the only child of its parent</li>
11025     <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>
11026     <li> <b>E:first</b> the first E in the resultset</li>
11027     <li> <b>E:last</b> the last E in the resultset</li>
11028     <li> <b>E:nth(<i>n</i>)</b> the <i>n</i>th E in the resultset (1 based)</li>
11029     <li> <b>E:odd</b> shortcut for :nth-child(odd)</li>
11030     <li> <b>E:even</b> shortcut for :nth-child(even)</li>
11031     <li> <b>E:contains(foo)</b> E's innerHTML contains the substring "foo"</li>
11032     <li> <b>E:nodeValue(foo)</b> E contains a textNode with a nodeValue that equals "foo"</li>
11033     <li> <b>E:not(S)</b> an E element that does not match simple selector S</li>
11034     <li> <b>E:has(S)</b> an E element that has a descendent that matches simple selector S</li>
11035     <li> <b>E:next(S)</b> an E element whose next sibling matches simple selector S</li>
11036     <li> <b>E:prev(S)</b> an E element whose previous sibling matches simple selector S</li>
11037     <li> <b>E:any(S1|S2|S2)</b> an E element which matches any of the simple selectors S1, S2 or S3//\\</li>
11038 </ul>
11039 <h4>CSS Value Selectors:</h4>
11040 <ul class="list">
11041     <li> <b>E{display=none}</b> css value "display" that equals "none"</li>
11042     <li> <b>E{display^=none}</b> css value "display" that starts with "none"</li>
11043     <li> <b>E{display$=none}</b> css value "display" that ends with "none"</li>
11044     <li> <b>E{display*=none}</b> css value "display" that contains the substring "none"</li>
11045     <li> <b>E{display%=2}</b> css value "display" that is evenly divisible by 2</li>
11046     <li> <b>E{display!=none}</b> css value "display" that does not equal "none"</li>
11047 </ul>
11048  * @singleton
11049  */
11050 Ext.ns('Ext.core');
11051
11052 Ext.core.DomQuery = Ext.DomQuery = function(){
11053     var cache = {},
11054         simpleCache = {},
11055         valueCache = {},
11056         nonSpace = /\S/,
11057         trimRe = /^\s+|\s+$/g,
11058         tplRe = /\{(\d+)\}/g,
11059         modeRe = /^(\s?[\/>+~]\s?|\s|$)/,
11060         tagTokenRe = /^(#)?([\w-\*]+)/,
11061         nthRe = /(\d*)n\+?(\d*)/,
11062         nthRe2 = /\D/,
11063         // This is for IE MSXML which does not support expandos.
11064     // IE runs the same speed using setAttribute, however FF slows way down
11065     // and Safari completely fails so they need to continue to use expandos.
11066     isIE = window.ActiveXObject ? true : false,
11067     key = 30803;
11068
11069     // this eval is stop the compressor from
11070     // renaming the variable to something shorter
11071     eval("var batch = 30803;");
11072
11073     // Retrieve the child node from a particular
11074     // parent at the specified index.
11075     function child(parent, index){
11076         var i = 0,
11077             n = parent.firstChild;
11078         while(n){
11079             if(n.nodeType == 1){
11080                if(++i == index){
11081                    return n;
11082                }
11083             }
11084             n = n.nextSibling;
11085         }
11086         return null;
11087     }
11088
11089     // retrieve the next element node
11090     function next(n){
11091         while((n = n.nextSibling) && n.nodeType != 1);
11092         return n;
11093     }
11094
11095     // retrieve the previous element node
11096     function prev(n){
11097         while((n = n.previousSibling) && n.nodeType != 1);
11098         return n;
11099     }
11100
11101     // Mark each child node with a nodeIndex skipping and
11102     // removing empty text nodes.
11103     function children(parent){
11104         var n = parent.firstChild,
11105         nodeIndex = -1,
11106         nextNode;
11107         while(n){
11108             nextNode = n.nextSibling;
11109             // clean worthless empty nodes.
11110             if(n.nodeType == 3 && !nonSpace.test(n.nodeValue)){
11111             parent.removeChild(n);
11112             }else{
11113             // add an expando nodeIndex
11114             n.nodeIndex = ++nodeIndex;
11115             }
11116             n = nextNode;
11117         }
11118         return this;
11119     }
11120
11121
11122     // nodeSet - array of nodes
11123     // cls - CSS Class
11124     function byClassName(nodeSet, cls){
11125         if(!cls){
11126             return nodeSet;
11127         }
11128         var result = [], ri = -1;
11129         for(var i = 0, ci; ci = nodeSet[i]; i++){
11130             if((' '+ci.className+' ').indexOf(cls) != -1){
11131                 result[++ri] = ci;
11132             }
11133         }
11134         return result;
11135     };
11136
11137     function attrValue(n, attr){
11138         // if its an array, use the first node.
11139         if(!n.tagName && typeof n.length != "undefined"){
11140             n = n[0];
11141         }
11142         if(!n){
11143             return null;
11144         }
11145
11146         if(attr == "for"){
11147             return n.htmlFor;
11148         }
11149         if(attr == "class" || attr == "className"){
11150             return n.className;
11151         }
11152         return n.getAttribute(attr) || n[attr];
11153
11154     };
11155
11156
11157     // ns - nodes
11158     // mode - false, /, >, +, ~
11159     // tagName - defaults to "*"
11160     function getNodes(ns, mode, tagName){
11161         var result = [], ri = -1, cs;
11162         if(!ns){
11163             return result;
11164         }
11165         tagName = tagName || "*";
11166         // convert to array
11167         if(typeof ns.getElementsByTagName != "undefined"){
11168             ns = [ns];
11169         }
11170
11171         // no mode specified, grab all elements by tagName
11172         // at any depth
11173         if(!mode){
11174             for(var i = 0, ni; ni = ns[i]; i++){
11175                 cs = ni.getElementsByTagName(tagName);
11176                 for(var j = 0, ci; ci = cs[j]; j++){
11177                     result[++ri] = ci;
11178                 }
11179             }
11180         // Direct Child mode (/ or >)
11181         // E > F or E/F all direct children elements of E that have the tag
11182         } else if(mode == "/" || mode == ">"){
11183             var utag = tagName.toUpperCase();
11184             for(var i = 0, ni, cn; ni = ns[i]; i++){
11185                 cn = ni.childNodes;
11186                 for(var j = 0, cj; cj = cn[j]; j++){
11187                     if(cj.nodeName == utag || cj.nodeName == tagName  || tagName == '*'){
11188                         result[++ri] = cj;
11189                     }
11190                 }
11191             }
11192         // Immediately Preceding mode (+)
11193         // E + F all elements with the tag F that are immediately preceded by an element with the tag E
11194         }else if(mode == "+"){
11195             var utag = tagName.toUpperCase();
11196             for(var i = 0, n; n = ns[i]; i++){
11197                 while((n = n.nextSibling) && n.nodeType != 1);
11198                 if(n && (n.nodeName == utag || n.nodeName == tagName || tagName == '*')){
11199                     result[++ri] = n;
11200                 }
11201             }
11202         // Sibling mode (~)
11203         // E ~ F all elements with the tag F that are preceded by a sibling element with the tag E
11204         }else if(mode == "~"){
11205             var utag = tagName.toUpperCase();
11206             for(var i = 0, n; n = ns[i]; i++){
11207                 while((n = n.nextSibling)){
11208                     if (n.nodeName == utag || n.nodeName == tagName || tagName == '*'){
11209                         result[++ri] = n;
11210                     }
11211                 }
11212             }
11213         }
11214         return result;
11215     }
11216
11217     function concat(a, b){
11218         if(b.slice){
11219             return a.concat(b);
11220         }
11221         for(var i = 0, l = b.length; i < l; i++){
11222             a[a.length] = b[i];
11223         }
11224         return a;
11225     }
11226
11227     function byTag(cs, tagName){
11228         if(cs.tagName || cs == document){
11229             cs = [cs];
11230         }
11231         if(!tagName){
11232             return cs;
11233         }
11234         var result = [], ri = -1;
11235         tagName = tagName.toLowerCase();
11236         for(var i = 0, ci; ci = cs[i]; i++){
11237             if(ci.nodeType == 1 && ci.tagName.toLowerCase() == tagName){
11238                 result[++ri] = ci;
11239             }
11240         }
11241         return result;
11242     }
11243
11244     function byId(cs, id){
11245         if(cs.tagName || cs == document){
11246             cs = [cs];
11247         }
11248         if(!id){
11249             return cs;
11250         }
11251         var result = [], ri = -1;
11252         for(var i = 0, ci; ci = cs[i]; i++){
11253             if(ci && ci.id == id){
11254                 result[++ri] = ci;
11255                 return result;
11256             }
11257         }
11258         return result;
11259     }
11260
11261     // operators are =, !=, ^=, $=, *=, %=, |= and ~=
11262     // custom can be "{"
11263     function byAttribute(cs, attr, value, op, custom){
11264         var result = [],
11265             ri = -1,
11266             useGetStyle = custom == "{",
11267             fn = Ext.DomQuery.operators[op],
11268             a,
11269             xml,
11270             hasXml;
11271
11272         for(var i = 0, ci; ci = cs[i]; i++){
11273             // skip non-element nodes.
11274             if(ci.nodeType != 1){
11275                 continue;
11276             }
11277             // only need to do this for the first node
11278             if(!hasXml){
11279                 xml = Ext.DomQuery.isXml(ci);
11280                 hasXml = true;
11281             }
11282
11283             // we only need to change the property names if we're dealing with html nodes, not XML
11284             if(!xml){
11285                 if(useGetStyle){
11286                     a = Ext.DomQuery.getStyle(ci, attr);
11287                 } else if (attr == "class" || attr == "className"){
11288                     a = ci.className;
11289                 } else if (attr == "for"){
11290                     a = ci.htmlFor;
11291                 } else if (attr == "href"){
11292                     // getAttribute href bug
11293                     // http://www.glennjones.net/Post/809/getAttributehrefbug.htm
11294                     a = ci.getAttribute("href", 2);
11295                 } else{
11296                     a = ci.getAttribute(attr);
11297                 }
11298             }else{
11299                 a = ci.getAttribute(attr);
11300             }
11301             if((fn && fn(a, value)) || (!fn && a)){
11302                 result[++ri] = ci;
11303             }
11304         }
11305         return result;
11306     }
11307
11308     function byPseudo(cs, name, value){
11309         return Ext.DomQuery.pseudos[name](cs, value);
11310     }
11311
11312     function nodupIEXml(cs){
11313         var d = ++key,
11314             r;
11315         cs[0].setAttribute("_nodup", d);
11316         r = [cs[0]];
11317         for(var i = 1, len = cs.length; i < len; i++){
11318             var c = cs[i];
11319             if(!c.getAttribute("_nodup") != d){
11320                 c.setAttribute("_nodup", d);
11321                 r[r.length] = c;
11322             }
11323         }
11324         for(var i = 0, len = cs.length; i < len; i++){
11325             cs[i].removeAttribute("_nodup");
11326         }
11327         return r;
11328     }
11329
11330     function nodup(cs){
11331         if(!cs){
11332             return [];
11333         }
11334         var len = cs.length, c, i, r = cs, cj, ri = -1;
11335         if(!len || typeof cs.nodeType != "undefined" || len == 1){
11336             return cs;
11337         }
11338         if(isIE && typeof cs[0].selectSingleNode != "undefined"){
11339             return nodupIEXml(cs);
11340         }
11341         var d = ++key;
11342         cs[0]._nodup = d;
11343         for(i = 1; c = cs[i]; i++){
11344             if(c._nodup != d){
11345                 c._nodup = d;
11346             }else{
11347                 r = [];
11348                 for(var j = 0; j < i; j++){
11349                     r[++ri] = cs[j];
11350                 }
11351                 for(j = i+1; cj = cs[j]; j++){
11352                     if(cj._nodup != d){
11353                         cj._nodup = d;
11354                         r[++ri] = cj;
11355                     }
11356                 }
11357                 return r;
11358             }
11359         }
11360         return r;
11361     }
11362
11363     function quickDiffIEXml(c1, c2){
11364         var d = ++key,
11365             r = [];
11366         for(var i = 0, len = c1.length; i < len; i++){
11367             c1[i].setAttribute("_qdiff", d);
11368         }
11369         for(var i = 0, len = c2.length; i < len; i++){
11370             if(c2[i].getAttribute("_qdiff") != d){
11371                 r[r.length] = c2[i];
11372             }
11373         }
11374         for(var i = 0, len = c1.length; i < len; i++){
11375            c1[i].removeAttribute("_qdiff");
11376         }
11377         return r;
11378     }
11379
11380     function quickDiff(c1, c2){
11381         var len1 = c1.length,
11382             d = ++key,
11383             r = [];
11384         if(!len1){
11385             return c2;
11386         }
11387         if(isIE && typeof c1[0].selectSingleNode != "undefined"){
11388             return quickDiffIEXml(c1, c2);
11389         }
11390         for(var i = 0; i < len1; i++){
11391             c1[i]._qdiff = d;
11392         }
11393         for(var i = 0, len = c2.length; i < len; i++){
11394             if(c2[i]._qdiff != d){
11395                 r[r.length] = c2[i];
11396             }
11397         }
11398         return r;
11399     }
11400
11401     function quickId(ns, mode, root, id){
11402         if(ns == root){
11403            var d = root.ownerDocument || root;
11404            return d.getElementById(id);
11405         }
11406         ns = getNodes(ns, mode, "*");
11407         return byId(ns, id);
11408     }
11409
11410     return {
11411         getStyle : function(el, name){
11412             return Ext.fly(el).getStyle(name);
11413         },
11414         /**
11415          * Compiles a selector/xpath query into a reusable function. The returned function
11416          * takes one parameter "root" (optional), which is the context node from where the query should start.
11417          * @param {String} selector The selector/xpath query
11418          * @param {String} type (optional) Either "select" (the default) or "simple" for a simple selector match
11419          * @return {Function}
11420          */
11421         compile : function(path, type){
11422             type = type || "select";
11423
11424             // setup fn preamble
11425             var fn = ["var f = function(root){\n var mode; ++batch; var n = root || document;\n"],
11426                 mode,
11427                 lastPath,
11428                 matchers = Ext.DomQuery.matchers,
11429                 matchersLn = matchers.length,
11430                 modeMatch,
11431                 // accept leading mode switch
11432                 lmode = path.match(modeRe);
11433
11434             if(lmode && lmode[1]){
11435                 fn[fn.length] = 'mode="'+lmode[1].replace(trimRe, "")+'";';
11436                 path = path.replace(lmode[1], "");
11437             }
11438
11439             // strip leading slashes
11440             while(path.substr(0, 1)=="/"){
11441                 path = path.substr(1);
11442             }
11443
11444             while(path && lastPath != path){
11445                 lastPath = path;
11446                 var tokenMatch = path.match(tagTokenRe);
11447                 if(type == "select"){
11448                     if(tokenMatch){
11449                         // ID Selector
11450                         if(tokenMatch[1] == "#"){
11451                             fn[fn.length] = 'n = quickId(n, mode, root, "'+tokenMatch[2]+'");';
11452                         }else{
11453                             fn[fn.length] = 'n = getNodes(n, mode, "'+tokenMatch[2]+'");';
11454                         }
11455                         path = path.replace(tokenMatch[0], "");
11456                     }else if(path.substr(0, 1) != '@'){
11457                         fn[fn.length] = 'n = getNodes(n, mode, "*");';
11458                     }
11459                 // type of "simple"
11460                 }else{
11461                     if(tokenMatch){
11462                         if(tokenMatch[1] == "#"){
11463                             fn[fn.length] = 'n = byId(n, "'+tokenMatch[2]+'");';
11464                         }else{
11465                             fn[fn.length] = 'n = byTag(n, "'+tokenMatch[2]+'");';
11466                         }
11467                         path = path.replace(tokenMatch[0], "");
11468                     }
11469                 }
11470                 while(!(modeMatch = path.match(modeRe))){
11471                     var matched = false;
11472                     for(var j = 0; j < matchersLn; j++){
11473                         var t = matchers[j];
11474                         var m = path.match(t.re);
11475                         if(m){
11476                             fn[fn.length] = t.select.replace(tplRe, function(x, i){
11477                                 return m[i];
11478                             });
11479                             path = path.replace(m[0], "");
11480                             matched = true;
11481                             break;
11482                         }
11483                     }
11484                     // prevent infinite loop on bad selector
11485                     if(!matched){
11486                         Ext.Error.raise({
11487                             sourceClass: 'Ext.DomQuery',
11488                             sourceMethod: 'compile',
11489                             msg: 'Error parsing selector. Parsing failed at "' + path + '"'
11490                         });
11491                     }
11492                 }
11493                 if(modeMatch[1]){
11494                     fn[fn.length] = 'mode="'+modeMatch[1].replace(trimRe, "")+'";';
11495                     path = path.replace(modeMatch[1], "");
11496                 }
11497             }
11498             // close fn out
11499             fn[fn.length] = "return nodup(n);\n}";
11500
11501             // eval fn and return it
11502             eval(fn.join(""));
11503             return f;
11504         },
11505
11506         /**
11507          * Selects an array of DOM nodes using JavaScript-only implementation.
11508          *
11509          * Use {@link #select} to take advantage of browsers built-in support for CSS selectors.
11510          *
11511          * @param {String} selector The selector/xpath query (can be a comma separated list of selectors)
11512          * @param {Node/String} root (optional) The start of the query (defaults to document).
11513          * @return {Array} An Array of DOM elements which match the selector. If there are
11514          * no matches, and empty Array is returned.
11515          */
11516         jsSelect: function(path, root, type){
11517             // set root to doc if not specified.
11518             root = root || document;
11519
11520             if(typeof root == "string"){
11521                 root = document.getElementById(root);
11522             }
11523             var paths = path.split(","),
11524                 results = [];
11525
11526             // loop over each selector
11527             for(var i = 0, len = paths.length; i < len; i++){
11528                 var subPath = paths[i].replace(trimRe, "");
11529                 // compile and place in cache
11530                 if(!cache[subPath]){
11531                     cache[subPath] = Ext.DomQuery.compile(subPath);
11532                     if(!cache[subPath]){
11533                         Ext.Error.raise({
11534                             sourceClass: 'Ext.DomQuery',
11535                             sourceMethod: 'jsSelect',
11536                             msg: subPath + ' is not a valid selector'
11537                         });
11538                     }
11539                 }
11540                 var result = cache[subPath](root);
11541                 if(result && result != document){
11542                     results = results.concat(result);
11543                 }
11544             }
11545
11546             // if there were multiple selectors, make sure dups
11547             // are eliminated
11548             if(paths.length > 1){
11549                 return nodup(results);
11550             }
11551             return results;
11552         },
11553
11554         isXml: function(el) {
11555             var docEl = (el ? el.ownerDocument || el : 0).documentElement;
11556             return docEl ? docEl.nodeName !== "HTML" : false;
11557         },
11558
11559         /**
11560          * Selects an array of DOM nodes by CSS/XPath selector.
11561          *
11562          * Uses [document.querySelectorAll][0] if browser supports that, otherwise falls back to
11563          * {@link #jsSelect} to do the work.
11564          * 
11565          * Aliased as {@link Ext#query}.
11566          * 
11567          * [0]: https://developer.mozilla.org/en/DOM/document.querySelectorAll
11568          *
11569          * @param {String} path The selector/xpath query
11570          * @param {Node} root (optional) The start of the query (defaults to document).
11571          * @return {Array} An array of DOM elements (not a NodeList as returned by `querySelectorAll`).
11572          * Empty array when no matches.
11573          * @method
11574          */
11575         select : document.querySelectorAll ? function(path, root, type) {
11576             root = root || document;
11577             if (!Ext.DomQuery.isXml(root)) {
11578             try {
11579                 var cs = root.querySelectorAll(path);
11580                 return Ext.Array.toArray(cs);
11581             }
11582             catch (ex) {}
11583             }
11584             return Ext.DomQuery.jsSelect.call(this, path, root, type);
11585         } : function(path, root, type) {
11586             return Ext.DomQuery.jsSelect.call(this, path, root, type);
11587         },
11588
11589         /**
11590          * Selects a single element.
11591          * @param {String} selector The selector/xpath query
11592          * @param {Node} root (optional) The start of the query (defaults to document).
11593          * @return {Element} The DOM element which matched the selector.
11594          */
11595         selectNode : function(path, root){
11596             return Ext.DomQuery.select(path, root)[0];
11597         },
11598
11599         /**
11600          * Selects the value of a node, optionally replacing null with the defaultValue.
11601          * @param {String} selector The selector/xpath query
11602          * @param {Node} root (optional) The start of the query (defaults to document).
11603          * @param {String} defaultValue
11604          * @return {String}
11605          */
11606         selectValue : function(path, root, defaultValue){
11607             path = path.replace(trimRe, "");
11608             if(!valueCache[path]){
11609                 valueCache[path] = Ext.DomQuery.compile(path, "select");
11610             }
11611             var n = valueCache[path](root), v;
11612             n = n[0] ? n[0] : n;
11613
11614             // overcome a limitation of maximum textnode size
11615             // Rumored to potentially crash IE6 but has not been confirmed.
11616             // http://reference.sitepoint.com/javascript/Node/normalize
11617             // https://developer.mozilla.org/En/DOM/Node.normalize
11618             if (typeof n.normalize == 'function') n.normalize();
11619
11620             v = (n && n.firstChild ? n.firstChild.nodeValue : null);
11621             return ((v === null||v === undefined||v==='') ? defaultValue : v);
11622         },
11623
11624         /**
11625          * Selects the value of a node, parsing integers and floats. Returns the defaultValue, or 0 if none is specified.
11626          * @param {String} selector The selector/xpath query
11627          * @param {Node} root (optional) The start of the query (defaults to document).
11628          * @param {Number} defaultValue
11629          * @return {Number}
11630          */
11631         selectNumber : function(path, root, defaultValue){
11632             var v = Ext.DomQuery.selectValue(path, root, defaultValue || 0);
11633             return parseFloat(v);
11634         },
11635
11636         /**
11637          * Returns true if the passed element(s) match the passed simple selector (e.g. div.some-class or span:first-child)
11638          * @param {String/HTMLElement/Array} el An element id, element or array of elements
11639          * @param {String} selector The simple selector to test
11640          * @return {Boolean}
11641          */
11642         is : function(el, ss){
11643             if(typeof el == "string"){
11644                 el = document.getElementById(el);
11645             }
11646             var isArray = Ext.isArray(el),
11647                 result = Ext.DomQuery.filter(isArray ? el : [el], ss);
11648             return isArray ? (result.length == el.length) : (result.length > 0);
11649         },
11650
11651         /**
11652          * Filters an array of elements to only include matches of a simple selector (e.g. div.some-class or span:first-child)
11653          * @param {Array} el An array of elements to filter
11654          * @param {String} selector The simple selector to test
11655          * @param {Boolean} nonMatches If true, it returns the elements that DON'T match
11656          * the selector instead of the ones that match
11657          * @return {Array} An Array of DOM elements which match the selector. If there are
11658          * no matches, and empty Array is returned.
11659          */
11660         filter : function(els, ss, nonMatches){
11661             ss = ss.replace(trimRe, "");
11662             if(!simpleCache[ss]){
11663                 simpleCache[ss] = Ext.DomQuery.compile(ss, "simple");
11664             }
11665             var result = simpleCache[ss](els);
11666             return nonMatches ? quickDiff(result, els) : result;
11667         },
11668
11669         /**
11670          * Collection of matching regular expressions and code snippets.
11671          * Each capture group within () will be replace the {} in the select
11672          * statement as specified by their index.
11673          */
11674         matchers : [{
11675                 re: /^\.([\w-]+)/,
11676                 select: 'n = byClassName(n, " {1} ");'
11677             }, {
11678                 re: /^\:([\w-]+)(?:\(((?:[^\s>\/]*|.*?))\))?/,
11679                 select: 'n = byPseudo(n, "{1}", "{2}");'
11680             },{
11681                 re: /^(?:([\[\{])(?:@)?([\w-]+)\s?(?:(=|.=)\s?['"]?(.*?)["']?)?[\]\}])/,
11682                 select: 'n = byAttribute(n, "{2}", "{4}", "{3}", "{1}");'
11683             }, {
11684                 re: /^#([\w-]+)/,
11685                 select: 'n = byId(n, "{1}");'
11686             },{
11687                 re: /^@([\w-]+)/,
11688                 select: 'return {firstChild:{nodeValue:attrValue(n, "{1}")}};'
11689             }
11690         ],
11691
11692         /**
11693          * Collection of operator comparison functions. The default operators are =, !=, ^=, $=, *=, %=, |= and ~=.
11694          * 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;.
11695          */
11696         operators : {
11697             "=" : function(a, v){
11698                 return a == v;
11699             },
11700             "!=" : function(a, v){
11701                 return a != v;
11702             },
11703             "^=" : function(a, v){
11704                 return a && a.substr(0, v.length) == v;
11705             },
11706             "$=" : function(a, v){
11707                 return a && a.substr(a.length-v.length) == v;
11708             },
11709             "*=" : function(a, v){
11710                 return a && a.indexOf(v) !== -1;
11711             },
11712             "%=" : function(a, v){
11713                 return (a % v) == 0;
11714             },
11715             "|=" : function(a, v){
11716                 return a && (a == v || a.substr(0, v.length+1) == v+'-');
11717             },
11718             "~=" : function(a, v){
11719                 return a && (' '+a+' ').indexOf(' '+v+' ') != -1;
11720             }
11721         },
11722
11723         /**
11724 Object hash of "pseudo class" filter functions which are used when filtering selections. 
11725 Each function is passed two parameters:
11726
11727 - **c** : Array
11728     An Array of DOM elements to filter.
11729     
11730 - **v** : String
11731     The argument (if any) supplied in the selector.
11732
11733 A filter function returns an Array of DOM elements which conform to the pseudo class.
11734 In addition to the provided pseudo classes listed above such as `first-child` and `nth-child`,
11735 developers may add additional, custom psuedo class filters to select elements according to application-specific requirements.
11736
11737 For example, to filter `a` elements to only return links to __external__ resources:
11738
11739     Ext.DomQuery.pseudos.external = function(c, v){
11740         var r = [], ri = -1;
11741         for(var i = 0, ci; ci = c[i]; i++){
11742             // Include in result set only if it's a link to an external resource
11743             if(ci.hostname != location.hostname){
11744                 r[++ri] = ci;
11745             }
11746         }
11747         return r;
11748     };
11749
11750 Then external links could be gathered with the following statement:
11751
11752     var externalLinks = Ext.select("a:external");
11753
11754         * @markdown
11755         */
11756         pseudos : {
11757             "first-child" : function(c){
11758                 var r = [], ri = -1, n;
11759                 for(var i = 0, ci; ci = n = c[i]; i++){
11760                     while((n = n.previousSibling) && n.nodeType != 1);
11761                     if(!n){
11762                         r[++ri] = ci;
11763                     }
11764                 }
11765                 return r;
11766             },
11767
11768             "last-child" : function(c){
11769                 var r = [], ri = -1, n;
11770                 for(var i = 0, ci; ci = n = c[i]; i++){
11771                     while((n = n.nextSibling) && n.nodeType != 1);
11772                     if(!n){
11773                         r[++ri] = ci;
11774                     }
11775                 }
11776                 return r;
11777             },
11778
11779             "nth-child" : function(c, a) {
11780                 var r = [], ri = -1,
11781                     m = nthRe.exec(a == "even" && "2n" || a == "odd" && "2n+1" || !nthRe2.test(a) && "n+" + a || a),
11782                     f = (m[1] || 1) - 0, l = m[2] - 0;
11783                 for(var i = 0, n; n = c[i]; i++){
11784                     var pn = n.parentNode;
11785                     if (batch != pn._batch) {
11786                         var j = 0;
11787                         for(var cn = pn.firstChild; cn; cn = cn.nextSibling){
11788                             if(cn.nodeType == 1){
11789                                cn.nodeIndex = ++j;
11790                             }
11791                         }
11792                         pn._batch = batch;
11793                     }
11794                     if (f == 1) {
11795                         if (l == 0 || n.nodeIndex == l){
11796                             r[++ri] = n;
11797                         }
11798                     } else if ((n.nodeIndex + l) % f == 0){
11799                         r[++ri] = n;
11800                     }
11801                 }
11802
11803                 return r;
11804             },
11805
11806             "only-child" : function(c){
11807                 var r = [], ri = -1;;
11808                 for(var i = 0, ci; ci = c[i]; i++){
11809                     if(!prev(ci) && !next(ci)){
11810                         r[++ri] = ci;
11811                     }
11812                 }
11813                 return r;
11814             },
11815
11816             "empty" : function(c){
11817                 var r = [], ri = -1;
11818                 for(var i = 0, ci; ci = c[i]; i++){
11819                     var cns = ci.childNodes, j = 0, cn, empty = true;
11820                     while(cn = cns[j]){
11821                         ++j;
11822                         if(cn.nodeType == 1 || cn.nodeType == 3){
11823                             empty = false;
11824                             break;
11825                         }
11826                     }
11827                     if(empty){
11828                         r[++ri] = ci;
11829                     }
11830                 }
11831                 return r;
11832             },
11833
11834             "contains" : function(c, v){
11835                 var r = [], ri = -1;
11836                 for(var i = 0, ci; ci = c[i]; i++){
11837                     if((ci.textContent||ci.innerText||'').indexOf(v) != -1){
11838                         r[++ri] = ci;
11839                     }
11840                 }
11841                 return r;
11842             },
11843
11844             "nodeValue" : function(c, v){
11845                 var r = [], ri = -1;
11846                 for(var i = 0, ci; ci = c[i]; i++){
11847                     if(ci.firstChild && ci.firstChild.nodeValue == v){
11848                         r[++ri] = ci;
11849                     }
11850                 }
11851                 return r;
11852             },
11853
11854             "checked" : function(c){
11855                 var r = [], ri = -1;
11856                 for(var i = 0, ci; ci = c[i]; i++){
11857                     if(ci.checked == true){
11858                         r[++ri] = ci;
11859                     }
11860                 }
11861                 return r;
11862             },
11863
11864             "not" : function(c, ss){
11865                 return Ext.DomQuery.filter(c, ss, true);
11866             },
11867
11868             "any" : function(c, selectors){
11869                 var ss = selectors.split('|'),
11870                     r = [], ri = -1, s;
11871                 for(var i = 0, ci; ci = c[i]; i++){
11872                     for(var j = 0; s = ss[j]; j++){
11873                         if(Ext.DomQuery.is(ci, s)){
11874                             r[++ri] = ci;
11875                             break;
11876                         }
11877                     }
11878                 }
11879                 return r;
11880             },
11881
11882             "odd" : function(c){
11883                 return this["nth-child"](c, "odd");
11884             },
11885
11886             "even" : function(c){
11887                 return this["nth-child"](c, "even");
11888             },
11889
11890             "nth" : function(c, a){
11891                 return c[a-1] || [];
11892             },
11893
11894             "first" : function(c){
11895                 return c[0] || [];
11896             },
11897
11898             "last" : function(c){
11899                 return c[c.length-1] || [];
11900             },
11901
11902             "has" : function(c, ss){
11903                 var s = Ext.DomQuery.select,
11904                     r = [], ri = -1;
11905                 for(var i = 0, ci; ci = c[i]; i++){
11906                     if(s(ss, ci).length > 0){
11907                         r[++ri] = ci;
11908                     }
11909                 }
11910                 return r;
11911             },
11912
11913             "next" : function(c, ss){
11914                 var is = Ext.DomQuery.is,
11915                     r = [], ri = -1;
11916                 for(var i = 0, ci; ci = c[i]; i++){
11917                     var n = next(ci);
11918                     if(n && is(n, ss)){
11919                         r[++ri] = ci;
11920                     }
11921                 }
11922                 return r;
11923             },
11924
11925             "prev" : function(c, ss){
11926                 var is = Ext.DomQuery.is,
11927                     r = [], ri = -1;
11928                 for(var i = 0, ci; ci = c[i]; i++){
11929                     var n = prev(ci);
11930                     if(n && is(n, ss)){
11931                         r[++ri] = ci;
11932                     }
11933                 }
11934                 return r;
11935             }
11936         }
11937     };
11938 }();
11939
11940 /**
11941  * Selects an array of DOM nodes by CSS/XPath selector. Shorthand of {@link Ext.DomQuery#select}
11942  * @param {String} path The selector/xpath query
11943  * @param {Node} root (optional) The start of the query (defaults to document).
11944  * @return {Array}
11945  * @member Ext
11946  * @method query
11947  */
11948 Ext.query = Ext.DomQuery.select;
11949
11950 /**
11951  * @class Ext.core.Element
11952  * <p>Encapsulates a DOM element, adding simple DOM manipulation facilities, normalizing for browser differences.</p>
11953  * <p>All instances of this class inherit the methods of {@link Ext.fx.Anim} making visual effects easily available to all DOM elements.</p>
11954  * <p>Note that the events documented in this class are not Ext events, they encapsulate browser events. To
11955  * access the underlying browser event, see {@link Ext.EventObject#browserEvent}. Some older
11956  * browsers may not support the full range of events. Which events are supported is beyond the control of ExtJs.</p>
11957  * Usage:<br>
11958 <pre><code>
11959 // by id
11960 var el = Ext.get("my-div");
11961
11962 // by DOM element reference
11963 var el = Ext.get(myDivElement);
11964 </code></pre>
11965  * <b>Animations</b><br />
11966  * <p>When an element is manipulated, by default there is no animation.</p>
11967  * <pre><code>
11968 var el = Ext.get("my-div");
11969
11970 // no animation
11971 el.setWidth(100);
11972  * </code></pre>
11973  * <p>Many of the functions for manipulating an element have an optional "animate" parameter.  This
11974  * parameter can be specified as boolean (<tt>true</tt>) for default animation effects.</p>
11975  * <pre><code>
11976 // default animation
11977 el.setWidth(100, true);
11978  * </code></pre>
11979  *
11980  * <p>To configure the effects, an object literal with animation options to use as the Element animation
11981  * configuration object can also be specified. Note that the supported Element animation configuration
11982  * options are a subset of the {@link Ext.fx.Anim} animation options specific to Fx effects.  The supported
11983  * Element animation configuration options are:</p>
11984 <pre>
11985 Option    Default   Description
11986 --------- --------  ---------------------------------------------
11987 {@link Ext.fx.Anim#duration duration}  .35       The duration of the animation in seconds
11988 {@link Ext.fx.Anim#easing easing}    easeOut   The easing method
11989 {@link Ext.fx.Anim#callback callback}  none      A function to execute when the anim completes
11990 {@link Ext.fx.Anim#scope scope}     this      The scope (this) of the callback function
11991 </pre>
11992  *
11993  * <pre><code>
11994 // Element animation options object
11995 var opt = {
11996     {@link Ext.fx.Anim#duration duration}: 1,
11997     {@link Ext.fx.Anim#easing easing}: 'elasticIn',
11998     {@link Ext.fx.Anim#callback callback}: this.foo,
11999     {@link Ext.fx.Anim#scope scope}: this
12000 };
12001 // animation with some options set
12002 el.setWidth(100, opt);
12003  * </code></pre>
12004  * <p>The Element animation object being used for the animation will be set on the options
12005  * object as "anim", which allows you to stop or manipulate the animation. Here is an example:</p>
12006  * <pre><code>
12007 // using the "anim" property to get the Anim object
12008 if(opt.anim.isAnimated()){
12009     opt.anim.stop();
12010 }
12011  * </code></pre>
12012  * <p>Also see the <tt>{@link #animate}</tt> method for another animation technique.</p>
12013  * <p><b> Composite (Collections of) Elements</b></p>
12014  * <p>For working with collections of Elements, see {@link Ext.CompositeElement}</p>
12015  * @constructor Create a new Element directly.
12016  * @param {String/HTMLElement} element
12017  * @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).
12018  */
12019  (function() {
12020     var DOC = document,
12021         EC = Ext.cache;
12022
12023     Ext.Element = Ext.core.Element = function(element, forceNew) {
12024         var dom = typeof element == "string" ? DOC.getElementById(element) : element,
12025         id;
12026
12027         if (!dom) {
12028             return null;
12029         }
12030
12031         id = dom.id;
12032
12033         if (!forceNew && id && EC[id]) {
12034             // element object already exists
12035             return EC[id].el;
12036         }
12037
12038         /**
12039      * The DOM element
12040      * @type HTMLElement
12041      */
12042         this.dom = dom;
12043
12044         /**
12045      * The DOM element ID
12046      * @type String
12047      */
12048         this.id = id || Ext.id(dom);
12049     };
12050
12051     var DH = Ext.core.DomHelper,
12052     El = Ext.core.Element;
12053
12054
12055     El.prototype = {
12056         /**
12057      * Sets the passed attributes as attributes of this element (a style attribute can be a string, object or function)
12058      * @param {Object} o The object with the attributes
12059      * @param {Boolean} useSet (optional) false to override the default setAttribute to use expandos.
12060      * @return {Ext.core.Element} this
12061      */
12062         set: function(o, useSet) {
12063             var el = this.dom,
12064                 attr,
12065                 val;
12066             useSet = (useSet !== false) && !!el.setAttribute;
12067
12068             for (attr in o) {
12069                 if (o.hasOwnProperty(attr)) {
12070                     val = o[attr];
12071                     if (attr == 'style') {
12072                         DH.applyStyles(el, val);
12073                     } else if (attr == 'cls') {
12074                         el.className = val;
12075                     } else if (useSet) {
12076                         el.setAttribute(attr, val);
12077                     } else {
12078                         el[attr] = val;
12079                     }
12080                 }
12081             }
12082             return this;
12083         },
12084
12085         //  Mouse events
12086         /**
12087      * @event click
12088      * Fires when a mouse click is detected within the element.
12089      * @param {Ext.EventObject} e The {@link Ext.EventObject} encapsulating the DOM event.
12090      * @param {HtmlElement} t The target of the event.
12091      * @param {Object} o The options configuration passed to the {@link #addListener} call.
12092      */
12093         /**
12094      * @event contextmenu
12095      * Fires when a right click is detected within the element.
12096      * @param {Ext.EventObject} e The {@link Ext.EventObject} encapsulating the DOM event.
12097      * @param {HtmlElement} t The target of the event.
12098      * @param {Object} o The options configuration passed to the {@link #addListener} call.
12099      */
12100         /**
12101      * @event dblclick
12102      * Fires when a mouse double click is detected within the element.
12103      * @param {Ext.EventObject} e The {@link Ext.EventObject} encapsulating the DOM event.
12104      * @param {HtmlElement} t The target of the event.
12105      * @param {Object} o The options configuration passed to the {@link #addListener} call.
12106      */
12107         /**
12108      * @event mousedown
12109      * Fires when a mousedown is detected within the element.
12110      * @param {Ext.EventObject} e The {@link Ext.EventObject} encapsulating the DOM event.
12111      * @param {HtmlElement} t The target of the event.
12112      * @param {Object} o The options configuration passed to the {@link #addListener} call.
12113      */
12114         /**
12115      * @event mouseup
12116      * Fires when a mouseup is detected within the element.
12117      * @param {Ext.EventObject} e The {@link Ext.EventObject} encapsulating the DOM event.
12118      * @param {HtmlElement} t The target of the event.
12119      * @param {Object} o The options configuration passed to the {@link #addListener} call.
12120      */
12121         /**
12122      * @event mouseover
12123      * Fires when a mouseover is detected within the element.
12124      * @param {Ext.EventObject} e The {@link Ext.EventObject} encapsulating the DOM event.
12125      * @param {HtmlElement} t The target of the event.
12126      * @param {Object} o The options configuration passed to the {@link #addListener} call.
12127      */
12128         /**
12129      * @event mousemove
12130      * Fires when a mousemove is detected with the element.
12131      * @param {Ext.EventObject} e The {@link Ext.EventObject} encapsulating the DOM event.
12132      * @param {HtmlElement} t The target of the event.
12133      * @param {Object} o The options configuration passed to the {@link #addListener} call.
12134      */
12135         /**
12136      * @event mouseout
12137      * Fires when a mouseout is detected with the element.
12138      * @param {Ext.EventObject} e The {@link Ext.EventObject} encapsulating the DOM event.
12139      * @param {HtmlElement} t The target of the event.
12140      * @param {Object} o The options configuration passed to the {@link #addListener} call.
12141      */
12142         /**
12143      * @event mouseenter
12144      * Fires when the mouse enters the element.
12145      * @param {Ext.EventObject} e The {@link Ext.EventObject} encapsulating the DOM event.
12146      * @param {HtmlElement} t The target of the event.
12147      * @param {Object} o The options configuration passed to the {@link #addListener} call.
12148      */
12149         /**
12150      * @event mouseleave
12151      * Fires when the mouse leaves the element.
12152      * @param {Ext.EventObject} e The {@link Ext.EventObject} encapsulating the DOM event.
12153      * @param {HtmlElement} t The target of the event.
12154      * @param {Object} o The options configuration passed to the {@link #addListener} call.
12155      */
12156
12157         //  Keyboard events
12158         /**
12159      * @event keypress
12160      * Fires when a keypress is detected within the element.
12161      * @param {Ext.EventObject} e The {@link Ext.EventObject} encapsulating the DOM event.
12162      * @param {HtmlElement} t The target of the event.
12163      * @param {Object} o The options configuration passed to the {@link #addListener} call.
12164      */
12165         /**
12166      * @event keydown
12167      * Fires when a keydown is detected within the element.
12168      * @param {Ext.EventObject} e The {@link Ext.EventObject} encapsulating the DOM event.
12169      * @param {HtmlElement} t The target of the event.
12170      * @param {Object} o The options configuration passed to the {@link #addListener} call.
12171      */
12172         /**
12173      * @event keyup
12174      * Fires when a keyup is detected within the element.
12175      * @param {Ext.EventObject} e The {@link Ext.EventObject} encapsulating the DOM event.
12176      * @param {HtmlElement} t The target of the event.
12177      * @param {Object} o The options configuration passed to the {@link #addListener} call.
12178      */
12179
12180
12181         //  HTML frame/object events
12182         /**
12183      * @event load
12184      * Fires when the user agent finishes loading all content within the element. Only supported by window, frames, objects and images.
12185      * @param {Ext.EventObject} e The {@link Ext.EventObject} encapsulating the DOM event.
12186      * @param {HtmlElement} t The target of the event.
12187      * @param {Object} o The options configuration passed to the {@link #addListener} call.
12188      */
12189         /**
12190      * @event unload
12191      * 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.
12192      * @param {Ext.EventObject} e The {@link Ext.EventObject} encapsulating the DOM event.
12193      * @param {HtmlElement} t The target of the event.
12194      * @param {Object} o The options configuration passed to the {@link #addListener} call.
12195      */
12196         /**
12197      * @event abort
12198      * Fires when an object/image is stopped from loading before completely loaded.
12199      * @param {Ext.EventObject} e The {@link Ext.EventObject} encapsulating the DOM event.
12200      * @param {HtmlElement} t The target of the event.
12201      * @param {Object} o The options configuration passed to the {@link #addListener} call.
12202      */
12203         /**
12204      * @event error
12205      * Fires when an object/image/frame cannot be loaded properly.
12206      * @param {Ext.EventObject} e The {@link Ext.EventObject} encapsulating the DOM event.
12207      * @param {HtmlElement} t The target of the event.
12208      * @param {Object} o The options configuration passed to the {@link #addListener} call.
12209      */
12210         /**
12211      * @event resize
12212      * Fires when a document view is resized.
12213      * @param {Ext.EventObject} e The {@link Ext.EventObject} encapsulating the DOM event.
12214      * @param {HtmlElement} t The target of the event.
12215      * @param {Object} o The options configuration passed to the {@link #addListener} call.
12216      */
12217         /**
12218      * @event scroll
12219      * Fires when a document view is scrolled.
12220      * @param {Ext.EventObject} e The {@link Ext.EventObject} encapsulating the DOM event.
12221      * @param {HtmlElement} t The target of the event.
12222      * @param {Object} o The options configuration passed to the {@link #addListener} call.
12223      */
12224
12225         //  Form events
12226         /**
12227      * @event select
12228      * Fires when a user selects some text in a text field, including input and textarea.
12229      * @param {Ext.EventObject} e The {@link Ext.EventObject} encapsulating the DOM event.
12230      * @param {HtmlElement} t The target of the event.
12231      * @param {Object} o The options configuration passed to the {@link #addListener} call.
12232      */
12233         /**
12234      * @event change
12235      * Fires when a control loses the input focus and its value has been modified since gaining focus.
12236      * @param {Ext.EventObject} e The {@link Ext.EventObject} encapsulating the DOM event.
12237      * @param {HtmlElement} t The target of the event.
12238      * @param {Object} o The options configuration passed to the {@link #addListener} call.
12239      */
12240         /**
12241      * @event submit
12242      * Fires when a form is submitted.
12243      * @param {Ext.EventObject} e The {@link Ext.EventObject} encapsulating the DOM event.
12244      * @param {HtmlElement} t The target of the event.
12245      * @param {Object} o The options configuration passed to the {@link #addListener} call.
12246      */
12247         /**
12248      * @event reset
12249      * Fires when a form is reset.
12250      * @param {Ext.EventObject} e The {@link Ext.EventObject} encapsulating the DOM event.
12251      * @param {HtmlElement} t The target of the event.
12252      * @param {Object} o The options configuration passed to the {@link #addListener} call.
12253      */
12254         /**
12255      * @event focus
12256      * Fires when an element receives focus either via the pointing device or by tab navigation.
12257      * @param {Ext.EventObject} e The {@link Ext.EventObject} encapsulating the DOM event.
12258      * @param {HtmlElement} t The target of the event.
12259      * @param {Object} o The options configuration passed to the {@link #addListener} call.
12260      */
12261         /**
12262      * @event blur
12263      * Fires when an element loses focus either via the pointing device or by tabbing navigation.
12264      * @param {Ext.EventObject} e The {@link Ext.EventObject} encapsulating the DOM event.
12265      * @param {HtmlElement} t The target of the event.
12266      * @param {Object} o The options configuration passed to the {@link #addListener} call.
12267      */
12268
12269         //  User Interface events
12270         /**
12271      * @event DOMFocusIn
12272      * Where supported. Similar to HTML focus event, but can be applied to any focusable element.
12273      * @param {Ext.EventObject} e The {@link Ext.EventObject} encapsulating the DOM event.
12274      * @param {HtmlElement} t The target of the event.
12275      * @param {Object} o The options configuration passed to the {@link #addListener} call.
12276      */
12277         /**
12278      * @event DOMFocusOut
12279      * Where supported. Similar to HTML blur event, but can be applied to any focusable element.
12280      * @param {Ext.EventObject} e The {@link Ext.EventObject} encapsulating the DOM event.
12281      * @param {HtmlElement} t The target of the event.
12282      * @param {Object} o The options configuration passed to the {@link #addListener} call.
12283      */
12284         /**
12285      * @event DOMActivate
12286      * Where supported. Fires when an element is activated, for instance, through a mouse click or a keypress.
12287      * @param {Ext.EventObject} e The {@link Ext.EventObject} encapsulating the DOM event.
12288      * @param {HtmlElement} t The target of the event.
12289      * @param {Object} o The options configuration passed to the {@link #addListener} call.
12290      */
12291
12292         //  DOM Mutation events
12293         /**
12294      * @event DOMSubtreeModified
12295      * Where supported. Fires when the subtree is modified.
12296      * @param {Ext.EventObject} e The {@link Ext.EventObject} encapsulating the DOM event.
12297      * @param {HtmlElement} t The target of the event.
12298      * @param {Object} o The options configuration passed to the {@link #addListener} call.
12299      */
12300         /**
12301      * @event DOMNodeInserted
12302      * Where supported. Fires when a node has been added as a child of another node.
12303      * @param {Ext.EventObject} e The {@link Ext.EventObject} encapsulating the DOM event.
12304      * @param {HtmlElement} t The target of the event.
12305      * @param {Object} o The options configuration passed to the {@link #addListener} call.
12306      */
12307         /**
12308      * @event DOMNodeRemoved
12309      * Where supported. Fires when a descendant node of the element is removed.
12310      * @param {Ext.EventObject} e The {@link Ext.EventObject} encapsulating the DOM event.
12311      * @param {HtmlElement} t The target of the event.
12312      * @param {Object} o The options configuration passed to the {@link #addListener} call.
12313      */
12314         /**
12315      * @event DOMNodeRemovedFromDocument
12316      * Where supported. Fires when a node is being removed from a document.
12317      * @param {Ext.EventObject} e The {@link Ext.EventObject} encapsulating the DOM event.
12318      * @param {HtmlElement} t The target of the event.
12319      * @param {Object} o The options configuration passed to the {@link #addListener} call.
12320      */
12321         /**
12322      * @event DOMNodeInsertedIntoDocument
12323      * Where supported. Fires when a node is being inserted into a document.
12324      * @param {Ext.EventObject} e The {@link Ext.EventObject} encapsulating the DOM event.
12325      * @param {HtmlElement} t The target of the event.
12326      * @param {Object} o The options configuration passed to the {@link #addListener} call.
12327      */
12328         /**
12329      * @event DOMAttrModified
12330      * Where supported. Fires when an attribute has been modified.
12331      * @param {Ext.EventObject} e The {@link Ext.EventObject} encapsulating the DOM event.
12332      * @param {HtmlElement} t The target of the event.
12333      * @param {Object} o The options configuration passed to the {@link #addListener} call.
12334      */
12335         /**
12336      * @event DOMCharacterDataModified
12337      * Where supported. Fires when the character data has been modified.
12338      * @param {Ext.EventObject} e The {@link Ext.EventObject} encapsulating the DOM event.
12339      * @param {HtmlElement} t The target of the event.
12340      * @param {Object} o The options configuration passed to the {@link #addListener} call.
12341      */
12342
12343         /**
12344      * The default unit to append to CSS values where a unit isn't provided (defaults to px).
12345      * @type String
12346      */
12347         defaultUnit: "px",
12348
12349         /**
12350      * Returns true if this element matches the passed simple selector (e.g. div.some-class or span:first-child)
12351      * @param {String} selector The simple selector to test
12352      * @return {Boolean} True if this element matches the selector, else false
12353      */
12354         is: function(simpleSelector) {
12355             return Ext.DomQuery.is(this.dom, simpleSelector);
12356         },
12357
12358         /**
12359      * Tries to focus the element. Any exceptions are caught and ignored.
12360      * @param {Number} defer (optional) Milliseconds to defer the focus
12361      * @return {Ext.core.Element} this
12362      */
12363         focus: function(defer,
12364                         /* private */
12365                         dom) {
12366             var me = this;
12367             dom = dom || me.dom;
12368             try {
12369                 if (Number(defer)) {
12370                     Ext.defer(me.focus, defer, null, [null, dom]);
12371                 } else {
12372                     dom.focus();
12373                 }
12374             } catch(e) {}
12375             return me;
12376         },
12377
12378         /**
12379      * Tries to blur the element. Any exceptions are caught and ignored.
12380      * @return {Ext.core.Element} this
12381      */
12382         blur: function() {
12383             try {
12384                 this.dom.blur();
12385             } catch(e) {}
12386             return this;
12387         },
12388
12389         /**
12390      * Returns the value of the "value" attribute
12391      * @param {Boolean} asNumber true to parse the value as a number
12392      * @return {String/Number}
12393      */
12394         getValue: function(asNumber) {
12395             var val = this.dom.value;
12396             return asNumber ? parseInt(val, 10) : val;
12397         },
12398
12399         /**
12400      * Appends an event handler to this element.  The shorthand version {@link #on} is equivalent.
12401      * @param {String} eventName The name of event to handle.
12402      * @param {Function} fn The handler function the event invokes. This function is passed
12403      * the following parameters:<ul>
12404      * <li><b>evt</b> : EventObject<div class="sub-desc">The {@link Ext.EventObject EventObject} describing the event.</div></li>
12405      * <li><b>el</b> : HtmlElement<div class="sub-desc">The DOM element which was the target of the event.
12406      * Note that this may be filtered by using the <tt>delegate</tt> option.</div></li>
12407      * <li><b>o</b> : Object<div class="sub-desc">The options object from the addListener call.</div></li>
12408      * </ul>
12409      * @param {Object} scope (optional) The scope (<code><b>this</b></code> reference) in which the handler function is executed.
12410      * <b>If omitted, defaults to this Element.</b>.
12411      * @param {Object} options (optional) An object containing handler configuration properties.
12412      * This may contain any of the following properties:<ul>
12413      * <li><b>scope</b> Object : <div class="sub-desc">The scope (<code><b>this</b></code> reference) in which the handler function is executed.
12414      * <b>If omitted, defaults to this Element.</b></div></li>
12415      * <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>
12416      * <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>
12417      * <li><b>preventDefault</b> Boolean: <div class="sub-desc">True to prevent the default action</div></li>
12418      * <li><b>stopPropagation</b> Boolean: <div class="sub-desc">True to prevent event propagation</div></li>
12419      * <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>
12420      * <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>
12421      * <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>
12422      * <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>
12423      * <li><b>buffer</b> Number: <div class="sub-desc">Causes the handler to be scheduled to run in an {@link Ext.util.DelayedTask} delayed
12424      * by the specified number of milliseconds. If the event fires again within that time, the original
12425      * handler is <em>not</em> invoked, but the new handler is scheduled in its place.</div></li>
12426      * </ul><br>
12427      * <p>
12428      * <b>Combining Options</b><br>
12429      * In the following examples, the shorthand form {@link #on} is used rather than the more verbose
12430      * addListener.  The two are equivalent.  Using the options argument, it is possible to combine different
12431      * types of listeners:<br>
12432      * <br>
12433      * A delayed, one-time listener that auto stops the event and adds a custom argument (forumId) to the
12434      * options object. The options object is available as the third parameter in the handler function.<div style="margin: 5px 20px 20px;">
12435      * Code:<pre><code>
12436 el.on('click', this.onClick, this, {
12437     single: true,
12438     delay: 100,
12439     stopEvent : true,
12440     forumId: 4
12441 });</code></pre></p>
12442      * <p>
12443      * <b>Attaching multiple handlers in 1 call</b><br>
12444      * The method also allows for a single argument to be passed which is a config object containing properties
12445      * which specify multiple handlers.</p>
12446      * <p>
12447      * Code:<pre><code>
12448 el.on({
12449     'click' : {
12450         fn: this.onClick,
12451         scope: this,
12452         delay: 100
12453     },
12454     'mouseover' : {
12455         fn: this.onMouseOver,
12456         scope: this
12457     },
12458     'mouseout' : {
12459         fn: this.onMouseOut,
12460         scope: this
12461     }
12462 });</code></pre>
12463      * <p>
12464      * Or a shorthand syntax:<br>
12465      * Code:<pre><code></p>
12466 el.on({
12467     'click' : this.onClick,
12468     'mouseover' : this.onMouseOver,
12469     'mouseout' : this.onMouseOut,
12470     scope: this
12471 });
12472      * </code></pre></p>
12473      * <p><b>delegate</b></p>
12474      * <p>This is a configuration option that you can pass along when registering a handler for
12475      * an event to assist with event delegation. Event delegation is a technique that is used to
12476      * reduce memory consumption and prevent exposure to memory-leaks. By registering an event
12477      * for a container element as opposed to each element within a container. By setting this
12478      * configuration option to a simple selector, the target element will be filtered to look for
12479      * a descendant of the target.
12480      * For example:<pre><code>
12481 // using this markup:
12482 &lt;div id='elId'>
12483     &lt;p id='p1'>paragraph one&lt;/p>
12484     &lt;p id='p2' class='clickable'>paragraph two&lt;/p>
12485     &lt;p id='p3'>paragraph three&lt;/p>
12486 &lt;/div>
12487 // utilize event delegation to registering just one handler on the container element:
12488 el = Ext.get('elId');
12489 el.on(
12490     'click',
12491     function(e,t) {
12492         // handle click
12493         console.info(t.id); // 'p2'
12494     },
12495     this,
12496     {
12497         // filter the target element to be a descendant with the class 'clickable'
12498         delegate: '.clickable'
12499     }
12500 );
12501      * </code></pre></p>
12502      * @return {Ext.core.Element} this
12503      */
12504         addListener: function(eventName, fn, scope, options) {
12505             Ext.EventManager.on(this.dom, eventName, fn, scope || this, options);
12506             return this;
12507         },
12508
12509         /**
12510      * Removes an event handler from this element.  The shorthand version {@link #un} is equivalent.
12511      * <b>Note</b>: if a <i>scope</i> was explicitly specified when {@link #addListener adding} the
12512      * listener, the same scope must be specified here.
12513      * Example:
12514      * <pre><code>
12515 el.removeListener('click', this.handlerFn);
12516 // or
12517 el.un('click', this.handlerFn);
12518 </code></pre>
12519      * @param {String} eventName The name of the event from which to remove the handler.
12520      * @param {Function} fn The handler function to remove. <b>This must be a reference to the function passed into the {@link #addListener} call.</b>
12521      * @param {Object} scope If a scope (<b><code>this</code></b> reference) was specified when the listener was added,
12522      * then this must refer to the same object.
12523      * @return {Ext.core.Element} this
12524      */
12525         removeListener: function(eventName, fn, scope) {
12526             Ext.EventManager.un(this.dom, eventName, fn, scope || this);
12527             return this;
12528         },
12529
12530         /**
12531      * Removes all previous added listeners from this element
12532      * @return {Ext.core.Element} this
12533      */
12534         removeAllListeners: function() {
12535             Ext.EventManager.removeAll(this.dom);
12536             return this;
12537         },
12538
12539         /**
12540          * Recursively removes all previous added listeners from this element and its children
12541          * @return {Ext.core.Element} this
12542          */
12543         purgeAllListeners: function() {
12544             Ext.EventManager.purgeElement(this);
12545             return this;
12546         },
12547
12548         /**
12549          * @private Test if size has a unit, otherwise appends the passed unit string, or the default for this Element.
12550          * @param size {Mixed} The size to set
12551          * @param units {String} The units to append to a numeric size value
12552          */
12553         addUnits: function(size, units) {
12554
12555             // Most common case first: Size is set to a number
12556             if (Ext.isNumber(size)) {
12557                 return size + (units || this.defaultUnit || 'px');
12558             }
12559
12560             // Size set to a value which means "auto"
12561             if (size === "" || size == "auto" || size === undefined || size === null) {
12562                 return size || '';
12563             }
12564
12565             // Otherwise, warn if it's not a valid CSS measurement
12566             if (!unitPattern.test(size)) {
12567                 if (Ext.isDefined(Ext.global.console)) {
12568                     Ext.global.console.warn("Warning, size detected as NaN on Element.addUnits.");
12569                 }
12570                 return size || '';
12571             }
12572             return size;
12573         },
12574
12575         /**
12576          * Tests various css rules/browsers to determine if this element uses a border box
12577          * @return {Boolean}
12578          */
12579         isBorderBox: function() {
12580             return Ext.isBorderBox || noBoxAdjust[(this.dom.tagName || "").toLowerCase()];
12581         },
12582
12583         /**
12584          * <p>Removes this element's dom reference.  Note that event and cache removal is handled at {@link Ext#removeNode Ext.removeNode}</p>
12585          */
12586         remove: function() {
12587             var me = this,
12588             dom = me.dom;
12589
12590             if (dom) {
12591                 delete me.dom;
12592                 Ext.removeNode(dom);
12593             }
12594         },
12595
12596         /**
12597          * Sets up event handlers to call the passed functions when the mouse is moved into and out of the Element.
12598          * @param {Function} overFn The function to call when the mouse enters the Element.
12599          * @param {Function} outFn The function to call when the mouse leaves the Element.
12600          * @param {Object} scope (optional) The scope (<code>this</code> reference) in which the functions are executed. Defaults to the Element's DOM element.
12601          * @param {Object} options (optional) Options for the listener. See {@link Ext.util.Observable#addListener the <tt>options</tt> parameter}.
12602          * @return {Ext.core.Element} this
12603          */
12604         hover: function(overFn, outFn, scope, options) {
12605             var me = this;
12606             me.on('mouseenter', overFn, scope || me.dom, options);
12607             me.on('mouseleave', outFn, scope || me.dom, options);
12608             return me;
12609         },
12610
12611         /**
12612          * Returns true if this element is an ancestor of the passed element
12613          * @param {HTMLElement/String} el The element to check
12614          * @return {Boolean} True if this element is an ancestor of el, else false
12615          */
12616         contains: function(el) {
12617             return ! el ? false: Ext.core.Element.isAncestor(this.dom, el.dom ? el.dom: el);
12618         },
12619
12620         /**
12621          * Returns the value of a namespaced attribute from the element's underlying DOM node.
12622          * @param {String} namespace The namespace in which to look for the attribute
12623          * @param {String} name The attribute name
12624          * @return {String} The attribute value
12625          * @deprecated
12626          */
12627         getAttributeNS: function(ns, name) {
12628             return this.getAttribute(name, ns);
12629         },
12630
12631         /**
12632          * Returns the value of an attribute from the element's underlying DOM node.
12633          * @param {String} name The attribute name
12634          * @param {String} namespace (optional) The namespace in which to look for the attribute
12635          * @return {String} The attribute value
12636          * @method
12637          */
12638         getAttribute: (Ext.isIE && !(Ext.isIE9 && document.documentMode === 9)) ?
12639         function(name, ns) {
12640             var d = this.dom,
12641             type;
12642             if(ns) {
12643                 type = typeof d[ns + ":" + name];
12644                 if (type != 'undefined' && type != 'unknown') {
12645                     return d[ns + ":" + name] || null;
12646                 }
12647                 return null;
12648             }
12649             if (name === "for") {
12650                 name = "htmlFor";
12651             }
12652             return d[name] || null;
12653         }: function(name, ns) {
12654             var d = this.dom;
12655             if (ns) {
12656                return d.getAttributeNS(ns, name) || d.getAttribute(ns + ":" + name);
12657             }
12658             return  d.getAttribute(name) || d[name] || null;
12659         },
12660
12661         /**
12662          * Update the innerHTML of this element
12663          * @param {String} html The new HTML
12664          * @return {Ext.core.Element} this
12665          */
12666         update: function(html) {
12667             if (this.dom) {
12668                 this.dom.innerHTML = html;
12669             }
12670             return this;
12671         }
12672     };
12673
12674     var ep = El.prototype;
12675
12676     El.addMethods = function(o) {
12677         Ext.apply(ep, o);
12678     };
12679
12680     /**
12681      * Appends an event handler (shorthand for {@link #addListener}).
12682      * @param {String} eventName The name of event to handle.
12683      * @param {Function} fn The handler function the event invokes.
12684      * @param {Object} scope (optional) The scope (<code>this</code> reference) in which the handler function is executed.
12685      * @param {Object} options (optional) An object containing standard {@link #addListener} options
12686      * @member Ext.core.Element
12687      * @method on
12688      */
12689     ep.on = ep.addListener;
12690
12691     /**
12692      * Removes an event handler from this element (see {@link #removeListener} for additional notes).
12693      * @param {String} eventName The name of the event from which to remove the handler.
12694      * @param {Function} fn The handler function to remove. <b>This must be a reference to the function passed into the {@link #addListener} call.</b>
12695      * @param {Object} scope If a scope (<b><code>this</code></b> reference) was specified when the listener was added,
12696      * then this must refer to the same object.
12697      * @return {Ext.core.Element} this
12698      * @member Ext.core.Element
12699      * @method un
12700      */
12701     ep.un = ep.removeListener;
12702
12703     /**
12704      * Removes all previous added listeners from this element
12705      * @return {Ext.core.Element} this
12706      * @member Ext.core.Element
12707      * @method clearListeners
12708      */
12709     ep.clearListeners = ep.removeAllListeners;
12710
12711     /**
12712      * Removes this element's dom reference.  Note that event and cache removal is handled at {@link Ext#removeNode Ext.removeNode}.
12713      * Alias to {@link #remove}.
12714      * @member Ext.core.Element
12715      * @method destroy
12716      */
12717     ep.destroy = ep.remove;
12718
12719     /**
12720      * true to automatically adjust width and height settings for box-model issues (default to true)
12721      */
12722     ep.autoBoxAdjust = true;
12723
12724     // private
12725     var unitPattern = /\d+(px|em|%|en|ex|pt|in|cm|mm|pc)$/i,
12726     docEl;
12727
12728     /**
12729      * Retrieves Ext.core.Element objects.
12730      * <p><b>This method does not retrieve {@link Ext.Component Component}s.</b> This method
12731      * retrieves Ext.core.Element objects which encapsulate DOM elements. To retrieve a Component by
12732      * its ID, use {@link Ext.ComponentManager#get}.</p>
12733      * <p>Uses simple caching to consistently return the same object. Automatically fixes if an
12734      * object was recreated with the same id via AJAX or DOM.</p>
12735      * @param {Mixed} el The id of the node, a DOM Node or an existing Element.
12736      * @return {Element} The Element object (or null if no matching element was found)
12737      * @static
12738      * @member Ext.core.Element
12739      * @method get
12740      */
12741     El.get = function(el) {
12742         var ex,
12743         elm,
12744         id;
12745         if (!el) {
12746             return null;
12747         }
12748         if (typeof el == "string") {
12749             // element id
12750             if (! (elm = DOC.getElementById(el))) {
12751                 return null;
12752             }
12753             if (EC[el] && EC[el].el) {
12754                 ex = EC[el].el;
12755                 ex.dom = elm;
12756             } else {
12757                 ex = El.addToCache(new El(elm));
12758             }
12759             return ex;
12760         } else if (el.tagName) {
12761             // dom element
12762             if (! (id = el.id)) {
12763                 id = Ext.id(el);
12764             }
12765             if (EC[id] && EC[id].el) {
12766                 ex = EC[id].el;
12767                 ex.dom = el;
12768             } else {
12769                 ex = El.addToCache(new El(el));
12770             }
12771             return ex;
12772         } else if (el instanceof El) {
12773             if (el != docEl) {
12774                 // refresh dom element in case no longer valid,
12775                 // catch case where it hasn't been appended
12776                 // If an el instance is passed, don't pass to getElementById without some kind of id
12777                 if (Ext.isIE && (el.id == undefined || el.id == '')) {
12778                     el.dom = el.dom;
12779                 } else {
12780                     el.dom = DOC.getElementById(el.id) || el.dom;
12781                 }
12782             }
12783             return el;
12784         } else if (el.isComposite) {
12785             return el;
12786         } else if (Ext.isArray(el)) {
12787             return El.select(el);
12788         } else if (el == DOC) {
12789             // create a bogus element object representing the document object
12790             if (!docEl) {
12791                 var f = function() {};
12792                 f.prototype = El.prototype;
12793                 docEl = new f();
12794                 docEl.dom = DOC;
12795             }
12796             return docEl;
12797         }
12798         return null;
12799     };
12800
12801     El.addToCache = function(el, id) {
12802         if (el) {
12803             id = id || el.id;
12804             EC[id] = {
12805                 el: el,
12806                 data: {},
12807                 events: {}
12808             };
12809         }
12810         return el;
12811     };
12812
12813     // private method for getting and setting element data
12814     El.data = function(el, key, value) {
12815         el = El.get(el);
12816         if (!el) {
12817             return null;
12818         }
12819         var c = EC[el.id].data;
12820         if (arguments.length == 2) {
12821             return c[key];
12822         } else {
12823             return (c[key] = value);
12824         }
12825     };
12826
12827     // private
12828     // Garbage collection - uncache elements/purge listeners on orphaned elements
12829     // so we don't hold a reference and cause the browser to retain them
12830     function garbageCollect() {
12831         if (!Ext.enableGarbageCollector) {
12832             clearInterval(El.collectorThreadId);
12833         } else {
12834             var eid,
12835             el,
12836             d,
12837             o;
12838
12839             for (eid in EC) {
12840                 if (!EC.hasOwnProperty(eid)) {
12841                     continue;
12842                 }
12843                 o = EC[eid];
12844                 if (o.skipGarbageCollection) {
12845                     continue;
12846                 }
12847                 el = o.el;
12848                 d = el.dom;
12849                 // -------------------------------------------------------
12850                 // Determining what is garbage:
12851                 // -------------------------------------------------------
12852                 // !d
12853                 // dom node is null, definitely garbage
12854                 // -------------------------------------------------------
12855                 // !d.parentNode
12856                 // no parentNode == direct orphan, definitely garbage
12857                 // -------------------------------------------------------
12858                 // !d.offsetParent && !document.getElementById(eid)
12859                 // display none elements have no offsetParent so we will
12860                 // also try to look it up by it's id. However, check
12861                 // offsetParent first so we don't do unneeded lookups.
12862                 // This enables collection of elements that are not orphans
12863                 // directly, but somewhere up the line they have an orphan
12864                 // parent.
12865                 // -------------------------------------------------------
12866                 if (!d || !d.parentNode || (!d.offsetParent && !DOC.getElementById(eid))) {
12867                     if (d && Ext.enableListenerCollection) {
12868                         Ext.EventManager.removeAll(d);
12869                     }
12870                     delete EC[eid];
12871                 }
12872             }
12873             // Cleanup IE Object leaks
12874             if (Ext.isIE) {
12875                 var t = {};
12876                 for (eid in EC) {
12877                     if (!EC.hasOwnProperty(eid)) {
12878                         continue;
12879                     }
12880                     t[eid] = EC[eid];
12881                 }
12882                 EC = Ext.cache = t;
12883             }
12884         }
12885     }
12886     El.collectorThreadId = setInterval(garbageCollect, 30000);
12887
12888     var flyFn = function() {};
12889     flyFn.prototype = El.prototype;
12890
12891     // dom is optional
12892     El.Flyweight = function(dom) {
12893         this.dom = dom;
12894     };
12895
12896     El.Flyweight.prototype = new flyFn();
12897     El.Flyweight.prototype.isFlyweight = true;
12898     El._flyweights = {};
12899
12900     /**
12901      * <p>Gets the globally shared flyweight Element, with the passed node as the active element. Do not store a reference to this element -
12902      * the dom node can be overwritten by other code. Shorthand of {@link Ext.core.Element#fly}</p>
12903      * <p>Use this to make one-time references to DOM elements which are not going to be accessed again either by
12904      * application code, or by Ext's classes. If accessing an element which will be processed regularly, then {@link Ext#get Ext.get}
12905      * will be more appropriate to take advantage of the caching provided by the Ext.core.Element class.</p>
12906      * @param {String/HTMLElement} el The dom node or id
12907      * @param {String} named (optional) Allows for creation of named reusable flyweights to prevent conflicts
12908      * (e.g. internally Ext uses "_global")
12909      * @return {Element} The shared Element object (or null if no matching element was found)
12910      * @member Ext.core.Element
12911      * @method fly
12912      */
12913     El.fly = function(el, named) {
12914         var ret = null;
12915         named = named || '_global';
12916         el = Ext.getDom(el);
12917         if (el) {
12918             (El._flyweights[named] = El._flyweights[named] || new El.Flyweight()).dom = el;
12919             ret = El._flyweights[named];
12920         }
12921         return ret;
12922     };
12923
12924     /**
12925      * Retrieves Ext.core.Element objects.
12926      * <p><b>This method does not retrieve {@link Ext.Component Component}s.</b> This method
12927      * retrieves Ext.core.Element objects which encapsulate DOM elements. To retrieve a Component by
12928      * its ID, use {@link Ext.ComponentManager#get}.</p>
12929      * <p>Uses simple caching to consistently return the same object. Automatically fixes if an
12930      * object was recreated with the same id via AJAX or DOM.</p>
12931      * Shorthand of {@link Ext.core.Element#get}
12932      * @param {Mixed} el The id of the node, a DOM Node or an existing Element.
12933      * @return {Element} The Element object (or null if no matching element was found)
12934      * @member Ext
12935      * @method get
12936      */
12937     Ext.get = El.get;
12938
12939     /**
12940      * <p>Gets the globally shared flyweight Element, with the passed node as the active element. Do not store a reference to this element -
12941      * the dom node can be overwritten by other code. Shorthand of {@link Ext.core.Element#fly}</p>
12942      * <p>Use this to make one-time references to DOM elements which are not going to be accessed again either by
12943      * application code, or by Ext's classes. If accessing an element which will be processed regularly, then {@link Ext#get Ext.get}
12944      * will be more appropriate to take advantage of the caching provided by the Ext.core.Element class.</p>
12945      * @param {String/HTMLElement} el The dom node or id
12946      * @param {String} named (optional) Allows for creation of named reusable flyweights to prevent conflicts
12947      * (e.g. internally Ext uses "_global")
12948      * @return {Element} The shared Element object (or null if no matching element was found)
12949      * @member Ext
12950      * @method fly
12951      */
12952     Ext.fly = El.fly;
12953
12954     // speedy lookup for elements never to box adjust
12955     var noBoxAdjust = Ext.isStrict ? {
12956         select: 1
12957     }: {
12958         input: 1,
12959         select: 1,
12960         textarea: 1
12961     };
12962     if (Ext.isIE || Ext.isGecko) {
12963         noBoxAdjust['button'] = 1;
12964     }
12965 })();
12966
12967 /**
12968  * @class Ext.core.Element
12969  */
12970 Ext.core.Element.addMethods({
12971     /**
12972      * 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)
12973      * @param {String} selector The simple selector to test
12974      * @param {Number/Mixed} maxDepth (optional) The max depth to search as a number or element (defaults to 50 || document.body)
12975      * @param {Boolean} returnEl (optional) True to return a Ext.core.Element object instead of DOM node
12976      * @return {HTMLElement} The matching DOM node (or null if no match was found)
12977      */
12978     findParent : function(simpleSelector, maxDepth, returnEl) {
12979         var p = this.dom,
12980             b = document.body,
12981             depth = 0,
12982             stopEl;
12983
12984         maxDepth = maxDepth || 50;
12985         if (isNaN(maxDepth)) {
12986             stopEl = Ext.getDom(maxDepth);
12987             maxDepth = Number.MAX_VALUE;
12988         }
12989         while (p && p.nodeType == 1 && depth < maxDepth && p != b && p != stopEl) {
12990             if (Ext.DomQuery.is(p, simpleSelector)) {
12991                 return returnEl ? Ext.get(p) : p;
12992             }
12993             depth++;
12994             p = p.parentNode;
12995         }
12996         return null;
12997     },
12998     
12999     /**
13000      * Looks at parent nodes for a match of the passed simple selector (e.g. div.some-class or span:first-child)
13001      * @param {String} selector The simple selector to test
13002      * @param {Number/Mixed} maxDepth (optional) The max depth to
13003             search as a number or element (defaults to 10 || document.body)
13004      * @param {Boolean} returnEl (optional) True to return a Ext.core.Element object instead of DOM node
13005      * @return {HTMLElement} The matching DOM node (or null if no match was found)
13006      */
13007     findParentNode : function(simpleSelector, maxDepth, returnEl) {
13008         var p = Ext.fly(this.dom.parentNode, '_internal');
13009         return p ? p.findParent(simpleSelector, maxDepth, returnEl) : null;
13010     },
13011
13012     /**
13013      * Walks up the dom looking for a parent node that matches the passed simple selector (e.g. div.some-class or span:first-child).
13014      * This is a shortcut for findParentNode() that always returns an Ext.core.Element.
13015      * @param {String} selector The simple selector to test
13016      * @param {Number/Mixed} maxDepth (optional) The max depth to
13017             search as a number or element (defaults to 10 || document.body)
13018      * @return {Ext.core.Element} The matching DOM node (or null if no match was found)
13019      */
13020     up : function(simpleSelector, maxDepth) {
13021         return this.findParentNode(simpleSelector, maxDepth, true);
13022     },
13023
13024     /**
13025      * Creates a {@link Ext.CompositeElement} for child nodes based on the passed CSS selector (the selector should not contain an id).
13026      * @param {String} selector The CSS selector
13027      * @return {CompositeElement/CompositeElement} The composite element
13028      */
13029     select : function(selector) {
13030         return Ext.core.Element.select(selector, false,  this.dom);
13031     },
13032
13033     /**
13034      * Selects child nodes based on the passed CSS selector (the selector should not contain an id).
13035      * @param {String} selector The CSS selector
13036      * @return {Array} An array of the matched nodes
13037      */
13038     query : function(selector) {
13039         return Ext.DomQuery.select(selector, this.dom);
13040     },
13041
13042     /**
13043      * Selects a single child at any depth below this element based on the passed CSS selector (the selector should not contain an id).
13044      * @param {String} selector The CSS selector
13045      * @param {Boolean} returnDom (optional) True to return the DOM node instead of Ext.core.Element (defaults to false)
13046      * @return {HTMLElement/Ext.core.Element} The child Ext.core.Element (or DOM node if returnDom = true)
13047      */
13048     down : function(selector, returnDom) {
13049         var n = Ext.DomQuery.selectNode(selector, this.dom);
13050         return returnDom ? n : Ext.get(n);
13051     },
13052
13053     /**
13054      * Selects a single *direct* child based on the passed CSS selector (the selector should not contain an id).
13055      * @param {String} selector The CSS selector
13056      * @param {Boolean} returnDom (optional) True to return the DOM node instead of Ext.core.Element (defaults to false)
13057      * @return {HTMLElement/Ext.core.Element} The child Ext.core.Element (or DOM node if returnDom = true)
13058      */
13059     child : function(selector, returnDom) {
13060         var node,
13061             me = this,
13062             id;
13063         id = Ext.get(me).id;
13064         // Escape . or :
13065         id = id.replace(/[\.:]/g, "\\$0");
13066         node = Ext.DomQuery.selectNode('#' + id + " > " + selector, me.dom);
13067         return returnDom ? node : Ext.get(node);
13068     },
13069
13070      /**
13071      * Gets the parent node for this element, optionally chaining up trying to match a selector
13072      * @param {String} selector (optional) Find a parent node that matches the passed simple selector
13073      * @param {Boolean} returnDom (optional) True to return a raw dom node instead of an Ext.core.Element
13074      * @return {Ext.core.Element/HTMLElement} The parent node or null
13075      */
13076     parent : function(selector, returnDom) {
13077         return this.matchNode('parentNode', 'parentNode', selector, returnDom);
13078     },
13079
13080      /**
13081      * Gets the next sibling, skipping text nodes
13082      * @param {String} selector (optional) Find the next sibling that matches the passed simple selector
13083      * @param {Boolean} returnDom (optional) True to return a raw dom node instead of an Ext.core.Element
13084      * @return {Ext.core.Element/HTMLElement} The next sibling or null
13085      */
13086     next : function(selector, returnDom) {
13087         return this.matchNode('nextSibling', 'nextSibling', selector, returnDom);
13088     },
13089
13090     /**
13091      * Gets the previous sibling, skipping text nodes
13092      * @param {String} selector (optional) Find the previous sibling that matches the passed simple selector
13093      * @param {Boolean} returnDom (optional) True to return a raw dom node instead of an Ext.core.Element
13094      * @return {Ext.core.Element/HTMLElement} The previous sibling or null
13095      */
13096     prev : function(selector, returnDom) {
13097         return this.matchNode('previousSibling', 'previousSibling', selector, returnDom);
13098     },
13099
13100
13101     /**
13102      * Gets the first child, skipping text nodes
13103      * @param {String} selector (optional) Find the next sibling that matches the passed simple selector
13104      * @param {Boolean} returnDom (optional) True to return a raw dom node instead of an Ext.core.Element
13105      * @return {Ext.core.Element/HTMLElement} The first child or null
13106      */
13107     first : function(selector, returnDom) {
13108         return this.matchNode('nextSibling', 'firstChild', selector, returnDom);
13109     },
13110
13111     /**
13112      * Gets the last child, skipping text nodes
13113      * @param {String} selector (optional) Find the previous sibling that matches the passed simple selector
13114      * @param {Boolean} returnDom (optional) True to return a raw dom node instead of an Ext.core.Element
13115      * @return {Ext.core.Element/HTMLElement} The last child or null
13116      */
13117     last : function(selector, returnDom) {
13118         return this.matchNode('previousSibling', 'lastChild', selector, returnDom);
13119     },
13120
13121     matchNode : function(dir, start, selector, returnDom) {
13122         if (!this.dom) {
13123             return null;
13124         }
13125         
13126         var n = this.dom[start];
13127         while (n) {
13128             if (n.nodeType == 1 && (!selector || Ext.DomQuery.is(n, selector))) {
13129                 return !returnDom ? Ext.get(n) : n;
13130             }
13131             n = n[dir];
13132         }
13133         return null;
13134     }
13135 });
13136
13137 /**
13138  * @class Ext.core.Element
13139  */
13140 Ext.core.Element.addMethods({
13141     /**
13142      * Appends the passed element(s) to this element
13143      * @param {String/HTMLElement/Array/Element/CompositeElement} el
13144      * @return {Ext.core.Element} this
13145      */
13146     appendChild : function(el) {
13147         return Ext.get(el).appendTo(this);
13148     },
13149
13150     /**
13151      * Appends this element to the passed element
13152      * @param {Mixed} el The new parent element
13153      * @return {Ext.core.Element} this
13154      */
13155     appendTo : function(el) {
13156         Ext.getDom(el).appendChild(this.dom);
13157         return this;
13158     },
13159
13160     /**
13161      * Inserts this element before the passed element in the DOM
13162      * @param {Mixed} el The element before which this element will be inserted
13163      * @return {Ext.core.Element} this
13164      */
13165     insertBefore : function(el) {
13166         el = Ext.getDom(el);
13167         el.parentNode.insertBefore(this.dom, el);
13168         return this;
13169     },
13170
13171     /**
13172      * Inserts this element after the passed element in the DOM
13173      * @param {Mixed} el The element to insert after
13174      * @return {Ext.core.Element} this
13175      */
13176     insertAfter : function(el) {
13177         el = Ext.getDom(el);
13178         el.parentNode.insertBefore(this.dom, el.nextSibling);
13179         return this;
13180     },
13181
13182     /**
13183      * Inserts (or creates) an element (or DomHelper config) as the first child of this element
13184      * @param {Mixed/Object} el The id or element to insert or a DomHelper config to create and insert
13185      * @return {Ext.core.Element} The new child
13186      */
13187     insertFirst : function(el, returnDom) {
13188         el = el || {};
13189         if (el.nodeType || el.dom || typeof el == 'string') { // element
13190             el = Ext.getDom(el);
13191             this.dom.insertBefore(el, this.dom.firstChild);
13192             return !returnDom ? Ext.get(el) : el;
13193         }
13194         else { // dh config
13195             return this.createChild(el, this.dom.firstChild, returnDom);
13196         }
13197     },
13198
13199     /**
13200      * Inserts (or creates) the passed element (or DomHelper config) as a sibling of this element
13201      * @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.
13202      * @param {String} where (optional) 'before' or 'after' defaults to before
13203      * @param {Boolean} returnDom (optional) True to return the .;ll;l,raw DOM element instead of Ext.core.Element
13204      * @return {Ext.core.Element} The inserted Element. If an array is passed, the last inserted element is returned.
13205      */
13206     insertSibling: function(el, where, returnDom){
13207         var me = this, rt,
13208         isAfter = (where || 'before').toLowerCase() == 'after',
13209         insertEl;
13210
13211         if(Ext.isArray(el)){
13212             insertEl = me;
13213             Ext.each(el, function(e) {
13214                 rt = Ext.fly(insertEl, '_internal').insertSibling(e, where, returnDom);
13215                 if(isAfter){
13216                     insertEl = rt;
13217                 }
13218             });
13219             return rt;
13220         }
13221
13222         el = el || {};
13223
13224         if(el.nodeType || el.dom){
13225             rt = me.dom.parentNode.insertBefore(Ext.getDom(el), isAfter ? me.dom.nextSibling : me.dom);
13226             if (!returnDom) {
13227                 rt = Ext.get(rt);
13228             }
13229         }else{
13230             if (isAfter && !me.dom.nextSibling) {
13231                 rt = Ext.core.DomHelper.append(me.dom.parentNode, el, !returnDom);
13232             } else {
13233                 rt = Ext.core.DomHelper[isAfter ? 'insertAfter' : 'insertBefore'](me.dom, el, !returnDom);
13234             }
13235         }
13236         return rt;
13237     },
13238
13239     /**
13240      * Replaces the passed element with this element
13241      * @param {Mixed} el The element to replace
13242      * @return {Ext.core.Element} this
13243      */
13244     replace : function(el) {
13245         el = Ext.get(el);
13246         this.insertBefore(el);
13247         el.remove();
13248         return this;
13249     },
13250     
13251     /**
13252      * Replaces this element with the passed element
13253      * @param {Mixed/Object} el The new element or a DomHelper config of an element to create
13254      * @return {Ext.core.Element} this
13255      */
13256     replaceWith: function(el){
13257         var me = this;
13258             
13259         if(el.nodeType || el.dom || typeof el == 'string'){
13260             el = Ext.get(el);
13261             me.dom.parentNode.insertBefore(el, me.dom);
13262         }else{
13263             el = Ext.core.DomHelper.insertBefore(me.dom, el);
13264         }
13265         
13266         delete Ext.cache[me.id];
13267         Ext.removeNode(me.dom);      
13268         me.id = Ext.id(me.dom = el);
13269         Ext.core.Element.addToCache(me.isFlyweight ? new Ext.core.Element(me.dom) : me);     
13270         return me;
13271     },
13272     
13273     /**
13274      * Creates the passed DomHelper config and appends it to this element or optionally inserts it before the passed child element.
13275      * @param {Object} config DomHelper element config object.  If no tag is specified (e.g., {tag:'input'}) then a div will be
13276      * automatically generated with the specified attributes.
13277      * @param {HTMLElement} insertBefore (optional) a child element of this element
13278      * @param {Boolean} returnDom (optional) true to return the dom node instead of creating an Element
13279      * @return {Ext.core.Element} The new child element
13280      */
13281     createChild : function(config, insertBefore, returnDom) {
13282         config = config || {tag:'div'};
13283         if (insertBefore) {
13284             return Ext.core.DomHelper.insertBefore(insertBefore, config, returnDom !== true);
13285         }
13286         else {
13287             return Ext.core.DomHelper[!this.dom.firstChild ? 'insertFirst' : 'append'](this.dom, config,  returnDom !== true);
13288         }
13289     },
13290
13291     /**
13292      * Creates and wraps this element with another element
13293      * @param {Object} config (optional) DomHelper element config object for the wrapper element or null for an empty div
13294      * @param {Boolean} returnDom (optional) True to return the raw DOM element instead of Ext.core.Element
13295      * @return {HTMLElement/Element} The newly created wrapper element
13296      */
13297     wrap : function(config, returnDom) {
13298         var newEl = Ext.core.DomHelper.insertBefore(this.dom, config || {tag: "div"}, !returnDom),
13299             d = newEl.dom || newEl;
13300
13301         d.appendChild(this.dom);
13302         return newEl;
13303     },
13304
13305     /**
13306      * Inserts an html fragment into this element
13307      * @param {String} where Where to insert the html in relation to this element - beforeBegin, afterBegin, beforeEnd, afterEnd.
13308      * @param {String} html The HTML fragment
13309      * @param {Boolean} returnEl (optional) True to return an Ext.core.Element (defaults to false)
13310      * @return {HTMLElement/Ext.core.Element} The inserted node (or nearest related if more than 1 inserted)
13311      */
13312     insertHtml : function(where, html, returnEl) {
13313         var el = Ext.core.DomHelper.insertHtml(where, this.dom, html);
13314         return returnEl ? Ext.get(el) : el;
13315     }
13316 });
13317
13318 /**
13319  * @class Ext.core.Element
13320  */
13321 (function(){
13322     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>';
13323     // local style camelizing for speed
13324     var supports = Ext.supports,
13325         view = document.defaultView,
13326         opacityRe = /alpha\(opacity=(.*)\)/i,
13327         trimRe = /^\s+|\s+$/g,
13328         spacesRe = /\s+/,
13329         wordsRe = /\w/g,
13330         adjustDirect2DTableRe = /table-row|table-.*-group/,
13331         INTERNAL = '_internal',
13332         PADDING = 'padding',
13333         MARGIN = 'margin',
13334         BORDER = 'border',
13335         LEFT = '-left',
13336         RIGHT = '-right',
13337         TOP = '-top',
13338         BOTTOM = '-bottom',
13339         WIDTH = '-width',
13340         MATH = Math,
13341         HIDDEN = 'hidden',
13342         ISCLIPPED = 'isClipped',
13343         OVERFLOW = 'overflow',
13344         OVERFLOWX = 'overflow-x',
13345         OVERFLOWY = 'overflow-y',
13346         ORIGINALCLIP = 'originalClip',
13347         // special markup used throughout Ext when box wrapping elements
13348         borders = {l: BORDER + LEFT + WIDTH, r: BORDER + RIGHT + WIDTH, t: BORDER + TOP + WIDTH, b: BORDER + BOTTOM + WIDTH},
13349         paddings = {l: PADDING + LEFT, r: PADDING + RIGHT, t: PADDING + TOP, b: PADDING + BOTTOM},
13350         margins = {l: MARGIN + LEFT, r: MARGIN + RIGHT, t: MARGIN + TOP, b: MARGIN + BOTTOM},
13351         data = Ext.core.Element.data;
13352
13353     Ext.override(Ext.core.Element, {
13354         
13355         /**
13356          * TODO: Look at this
13357          */
13358         // private  ==> used by Fx
13359         adjustWidth : function(width) {
13360             var me = this,
13361                 isNum = (typeof width == 'number');
13362                 
13363             if(isNum && me.autoBoxAdjust && !me.isBorderBox()){
13364                width -= (me.getBorderWidth("lr") + me.getPadding("lr"));
13365             }
13366             return (isNum && width < 0) ? 0 : width;
13367         },
13368
13369         // private   ==> used by Fx
13370         adjustHeight : function(height) {
13371             var me = this,
13372                 isNum = (typeof height == "number");
13373                 
13374             if(isNum && me.autoBoxAdjust && !me.isBorderBox()){
13375                height -= (me.getBorderWidth("tb") + me.getPadding("tb"));
13376             }
13377             return (isNum && height < 0) ? 0 : height;
13378         },
13379
13380
13381         /**
13382          * Adds one or more CSS classes to the element. Duplicate classes are automatically filtered out.
13383          * @param {String/Array} className The CSS classes to add separated by space, or an array of classes
13384          * @return {Ext.core.Element} this
13385          */
13386         addCls : function(className){
13387             var me = this,
13388                 cls = [],
13389                 space = ((me.dom.className.replace(trimRe, '') == '') ? "" : " "),
13390                 i, len, v;
13391             if (!Ext.isDefined(className)) {
13392                 return me;
13393             }
13394             // Separate case is for speed
13395             if (!Ext.isArray(className)) {
13396                 if (typeof className === 'string') {
13397                     className = className.replace(trimRe, '').split(spacesRe);
13398                     if (className.length === 1) {
13399                         className = className[0];
13400                         if (!me.hasCls(className)) {
13401                             me.dom.className += space + className;
13402                         }
13403                     } else {
13404                         this.addCls(className);
13405                     }
13406                 }
13407             } else {
13408                 for (i = 0, len = className.length; i < len; i++) {
13409                     v = className[i];
13410                     if (typeof v == 'string' && (' ' + me.dom.className + ' ').indexOf(' ' + v + ' ') == -1) {
13411                         cls.push(v);
13412                     }
13413                 }
13414                 if (cls.length) {
13415                     me.dom.className += space + cls.join(" ");
13416                 }
13417             }
13418             return me;
13419         },
13420
13421         /**
13422          * Removes one or more CSS classes from the element.
13423          * @param {String/Array} className The CSS classes to remove separated by space, or an array of classes
13424          * @return {Ext.core.Element} this
13425          */
13426         removeCls : function(className){
13427             var me = this,
13428                 i, idx, len, cls, elClasses;
13429             if (!Ext.isDefined(className)) {
13430                 return me;
13431             }
13432             if (!Ext.isArray(className)){
13433                 className = className.replace(trimRe, '').split(spacesRe);
13434             }
13435             if (me.dom && me.dom.className) {
13436                 elClasses = me.dom.className.replace(trimRe, '').split(spacesRe);
13437                 for (i = 0, len = className.length; i < len; i++) {
13438                     cls = className[i];
13439                     if (typeof cls == 'string') {
13440                         cls = cls.replace(trimRe, '');
13441                         idx = Ext.Array.indexOf(elClasses, cls);
13442                         if (idx != -1) {
13443                             elClasses.splice(idx, 1);
13444                         }
13445                     }
13446                 }
13447                 me.dom.className = elClasses.join(" ");
13448             }
13449             return me;
13450         },
13451
13452         /**
13453          * Adds one or more CSS classes to this element and removes the same class(es) from all siblings.
13454          * @param {String/Array} className The CSS class to add, or an array of classes
13455          * @return {Ext.core.Element} this
13456          */
13457         radioCls : function(className){
13458             var cn = this.dom.parentNode.childNodes,
13459                 v, i, len;
13460             className = Ext.isArray(className) ? className : [className];
13461             for (i = 0, len = cn.length; i < len; i++) {
13462                 v = cn[i];
13463                 if (v && v.nodeType == 1) {
13464                     Ext.fly(v, '_internal').removeCls(className);
13465                 }
13466             }
13467             return this.addCls(className);
13468         },
13469
13470         /**
13471          * Toggles the specified CSS class on this element (removes it if it already exists, otherwise adds it).
13472          * @param {String} className The CSS class to toggle
13473          * @return {Ext.core.Element} this
13474          * @method
13475          */
13476         toggleCls : Ext.supports.ClassList ?
13477             function(className) {
13478                 this.dom.classList.toggle(Ext.String.trim(className));
13479                 return this;
13480             } :
13481             function(className) {
13482                 return this.hasCls(className) ? this.removeCls(className) : this.addCls(className);
13483             },
13484
13485         /**
13486          * Checks if the specified CSS class exists on this element's DOM node.
13487          * @param {String} className The CSS class to check for
13488          * @return {Boolean} True if the class exists, else false
13489          * @method
13490          */
13491         hasCls : Ext.supports.ClassList ?
13492             function(className) {
13493                 if (!className) {
13494                     return false;
13495                 }
13496                 className = className.split(spacesRe);
13497                 var ln = className.length,
13498                     i = 0;
13499                 for (; i < ln; i++) {
13500                     if (className[i] && this.dom.classList.contains(className[i])) {
13501                         return true;
13502                     }
13503                 }
13504                 return false;
13505             } :
13506             function(className){
13507                 return className && (' ' + this.dom.className + ' ').indexOf(' ' + className + ' ') != -1;
13508             },
13509
13510         /**
13511          * Replaces a CSS class on the element with another.  If the old name does not exist, the new name will simply be added.
13512          * @param {String} oldClassName The CSS class to replace
13513          * @param {String} newClassName The replacement CSS class
13514          * @return {Ext.core.Element} this
13515          */
13516         replaceCls : function(oldClassName, newClassName){
13517             return this.removeCls(oldClassName).addCls(newClassName);
13518         },
13519
13520         isStyle : function(style, val) {
13521             return this.getStyle(style) == val;
13522         },
13523
13524         /**
13525          * Normalizes currentStyle and computedStyle.
13526          * @param {String} property The style property whose value is returned.
13527          * @return {String} The current value of the style property for this element.
13528          * @method
13529          */
13530         getStyle : function(){
13531             return view && view.getComputedStyle ?
13532                 function(prop){
13533                     var el = this.dom,
13534                         v, cs, out, display, cleaner;
13535
13536                     if(el == document){
13537                         return null;
13538                     }
13539                     prop = Ext.core.Element.normalize(prop);
13540                     out = (v = el.style[prop]) ? v :
13541                            (cs = view.getComputedStyle(el, "")) ? cs[prop] : null;
13542                            
13543                     // Ignore cases when the margin is correctly reported as 0, the bug only shows
13544                     // numbers larger.
13545                     if(prop == 'marginRight' && out != '0px' && !supports.RightMargin){
13546                         cleaner = Ext.core.Element.getRightMarginFixCleaner(el);
13547                         display = this.getStyle('display');
13548                         el.style.display = 'inline-block';
13549                         out = view.getComputedStyle(el, '').marginRight;
13550                         el.style.display = display;
13551                         cleaner();
13552                     }
13553                     
13554                     if(prop == 'backgroundColor' && out == 'rgba(0, 0, 0, 0)' && !supports.TransparentColor){
13555                         out = 'transparent';
13556                     }
13557                     return out;
13558                 } :
13559                 function(prop){
13560                     var el = this.dom,
13561                         m, cs;
13562
13563                     if (el == document) {
13564                         return null;
13565                     }
13566                     
13567                     if (prop == 'opacity') {
13568                         if (el.style.filter.match) {
13569                             m = el.style.filter.match(opacityRe);
13570                             if(m){
13571                                 var fv = parseFloat(m[1]);
13572                                 if(!isNaN(fv)){
13573                                     return fv ? fv / 100 : 0;
13574                                 }
13575                             }
13576                         }
13577                         return 1;
13578                     }
13579                     prop = Ext.core.Element.normalize(prop);
13580                     return el.style[prop] || ((cs = el.currentStyle) ? cs[prop] : null);
13581                 };
13582         }(),
13583
13584         /**
13585          * Return the CSS color for the specified CSS attribute. rgb, 3 digit (like #fff) and valid values
13586          * are convert to standard 6 digit hex color.
13587          * @param {String} attr The css attribute
13588          * @param {String} defaultValue The default value to use when a valid color isn't found
13589          * @param {String} prefix (optional) defaults to #. Use an empty string when working with
13590          * color anims.
13591          */
13592         getColor : function(attr, defaultValue, prefix){
13593             var v = this.getStyle(attr),
13594                 color = prefix || prefix === '' ? prefix : '#',
13595                 h;
13596
13597             if(!v || (/transparent|inherit/.test(v))) {
13598                 return defaultValue;
13599             }
13600             if(/^r/.test(v)){
13601                 Ext.each(v.slice(4, v.length -1).split(','), function(s){
13602                     h = parseInt(s, 10);
13603                     color += (h < 16 ? '0' : '') + h.toString(16);
13604                 });
13605             }else{
13606                 v = v.replace('#', '');
13607                 color += v.length == 3 ? v.replace(/^(\w)(\w)(\w)$/, '$1$1$2$2$3$3') : v;
13608             }
13609             return(color.length > 5 ? color.toLowerCase() : defaultValue);
13610         },
13611
13612         /**
13613          * Wrapper for setting style properties, also takes single object parameter of multiple styles.
13614          * @param {String/Object} property The style property to be set, or an object of multiple styles.
13615          * @param {String} value (optional) The value to apply to the given property, or null if an object was passed.
13616          * @return {Ext.core.Element} this
13617          */
13618         setStyle : function(prop, value){
13619             var me = this,
13620                 tmp, style;
13621
13622             if (!me.dom) {
13623                 return me;
13624             }
13625
13626             if (!Ext.isObject(prop)) {
13627                 tmp = {};
13628                 tmp[prop] = value;
13629                 prop = tmp;
13630             }
13631             for (style in prop) {
13632                 if (prop.hasOwnProperty(style)) {
13633                     value = Ext.value(prop[style], '');
13634                     if (style == 'opacity') {
13635                         me.setOpacity(value);
13636                     }
13637                     else {
13638                         me.dom.style[Ext.core.Element.normalize(style)] = value;
13639                     }
13640                 }
13641             }
13642             return me;
13643         },
13644
13645         /**
13646          * Set the opacity of the element
13647          * @param {Float} opacity The new opacity. 0 = transparent, .5 = 50% visibile, 1 = fully visible, etc
13648          * @param {Boolean/Object} animate (optional) a standard Element animation config object or <tt>true</tt> for
13649          * the default animation (<tt>{duration: .35, easing: 'easeIn'}</tt>)
13650          * @return {Ext.core.Element} this
13651          */
13652         setOpacity: function(opacity, animate) {
13653             var me = this,
13654                 dom = me.dom,
13655                 val,
13656                 style;
13657
13658             if (!me.dom) {
13659                 return me;
13660             }
13661
13662             style = me.dom.style;
13663
13664             if (!animate || !me.anim) {
13665                 if (!Ext.supports.Opacity) {
13666                     opacity = opacity < 1 ? 'alpha(opacity=' + opacity * 100 + ')': '';
13667                     val = style.filter.replace(opacityRe, '').replace(trimRe, '');
13668
13669                     style.zoom = 1;
13670                     style.filter = val + (val.length > 0 ? ' ': '') + opacity;
13671                 }
13672                 else {
13673                     style.opacity = opacity;
13674                 }
13675             }
13676             else {
13677                 if (!Ext.isObject(animate)) {
13678                     animate = {
13679                         duration: 350,
13680                         easing: 'ease-in'
13681                     };
13682                 }
13683                 me.animate(Ext.applyIf({
13684                     to: {
13685                         opacity: opacity
13686                     }
13687                 },
13688                 animate));
13689             }
13690             return me;
13691         },
13692
13693
13694         /**
13695          * Clears any opacity settings from this element. Required in some cases for IE.
13696          * @return {Ext.core.Element} this
13697          */
13698         clearOpacity : function(){
13699             var style = this.dom.style;
13700             if(!Ext.supports.Opacity){
13701                 if(!Ext.isEmpty(style.filter)){
13702                     style.filter = style.filter.replace(opacityRe, '').replace(trimRe, '');
13703                 }
13704             }else{
13705                 style.opacity = style['-moz-opacity'] = style['-khtml-opacity'] = '';
13706             }
13707             return this;
13708         },
13709         
13710         /**
13711          * @private
13712          * Returns 1 if the browser returns the subpixel dimension rounded to the lowest pixel.
13713          * @return {Number} 0 or 1 
13714          */
13715         adjustDirect2DDimension: function(dimension) {
13716             var me = this,
13717                 dom = me.dom,
13718                 display = me.getStyle('display'),
13719                 inlineDisplay = dom.style['display'],
13720                 inlinePosition = dom.style['position'],
13721                 originIndex = dimension === 'width' ? 0 : 1,
13722                 floating;
13723                 
13724             if (display === 'inline') {
13725                 dom.style['display'] = 'inline-block';
13726             }
13727
13728             dom.style['position'] = display.match(adjustDirect2DTableRe) ? 'absolute' : 'static';
13729
13730             // floating will contain digits that appears after the decimal point
13731             // if height or width are set to auto we fallback to msTransformOrigin calculation
13732             floating = (parseFloat(me.getStyle(dimension)) || parseFloat(dom.currentStyle.msTransformOrigin.split(' ')[originIndex]) * 2) % 1;
13733             
13734             dom.style['position'] = inlinePosition;
13735             
13736             if (display === 'inline') {
13737                 dom.style['display'] = inlineDisplay;
13738             }
13739
13740             return floating;
13741         },
13742         
13743         /**
13744          * Returns the offset height of the element
13745          * @param {Boolean} contentHeight (optional) true to get the height minus borders and padding
13746          * @return {Number} The element's height
13747          */
13748         getHeight: function(contentHeight, preciseHeight) {
13749             var me = this,
13750                 dom = me.dom,
13751                 hidden = Ext.isIE && me.isStyle('display', 'none'),
13752                 height, overflow, style, floating;
13753
13754             // IE Quirks mode acts more like a max-size measurement unless overflow is hidden during measurement.
13755             // We will put the overflow back to it's original value when we are done measuring.
13756             if (Ext.isIEQuirks) {
13757                 style = dom.style;
13758                 overflow = style.overflow;
13759                 me.setStyle({ overflow: 'hidden'});
13760             }
13761
13762             height = dom.offsetHeight;
13763
13764             height = MATH.max(height, hidden ? 0 : dom.clientHeight) || 0;
13765
13766             // IE9 Direct2D dimension rounding bug
13767             if (!hidden && Ext.supports.Direct2DBug) {
13768                 floating = me.adjustDirect2DDimension('height');
13769                 if (preciseHeight) {
13770                     height += floating;
13771                 }
13772                 else if (floating > 0 && floating < 0.5) {
13773                     height++;
13774                 }
13775             }
13776
13777             if (contentHeight) {
13778                 height -= (me.getBorderWidth("tb") + me.getPadding("tb"));
13779             }
13780
13781             if (Ext.isIEQuirks) {
13782                 me.setStyle({ overflow: overflow});
13783             }
13784
13785             if (height < 0) {
13786                 height = 0;
13787             }
13788             return height;
13789         },
13790                 
13791         /**
13792          * Returns the offset width of the element
13793          * @param {Boolean} contentWidth (optional) true to get the width minus borders and padding
13794          * @return {Number} The element's width
13795          */
13796         getWidth: function(contentWidth, preciseWidth) {
13797             var me = this,
13798                 dom = me.dom,
13799                 hidden = Ext.isIE && me.isStyle('display', 'none'),
13800                 rect, width, overflow, style, floating, parentPosition;
13801
13802             // IE Quirks mode acts more like a max-size measurement unless overflow is hidden during measurement.
13803             // We will put the overflow back to it's original value when we are done measuring.
13804             if (Ext.isIEQuirks) {
13805                 style = dom.style;
13806                 overflow = style.overflow;
13807                 me.setStyle({overflow: 'hidden'});
13808             }
13809             
13810             // Fix Opera 10.5x width calculation issues 
13811             if (Ext.isOpera10_5) {
13812                 if (dom.parentNode.currentStyle.position === 'relative') {
13813                     parentPosition = dom.parentNode.style.position;
13814                     dom.parentNode.style.position = 'static';
13815                     width = dom.offsetWidth;
13816                     dom.parentNode.style.position = parentPosition;
13817                 }
13818                 width = Math.max(width || 0, dom.offsetWidth);
13819             
13820             // Gecko will in some cases report an offsetWidth that is actually less than the width of the
13821             // text contents, because it measures fonts with sub-pixel precision but rounds the calculated
13822             // value down. Using getBoundingClientRect instead of offsetWidth allows us to get the precise
13823             // subpixel measurements so we can force them to always be rounded up. See
13824             // https://bugzilla.mozilla.org/show_bug.cgi?id=458617
13825             } else if (Ext.supports.BoundingClientRect) {
13826                 rect = dom.getBoundingClientRect();
13827                 width = rect.right - rect.left;
13828                 width = preciseWidth ? width : Math.ceil(width);
13829             } else {
13830                 width = dom.offsetWidth;
13831             }
13832
13833             width = MATH.max(width, hidden ? 0 : dom.clientWidth) || 0;
13834
13835             // IE9 Direct2D dimension rounding bug
13836             if (!hidden && Ext.supports.Direct2DBug) {
13837                 floating = me.adjustDirect2DDimension('width');
13838                 if (preciseWidth) {
13839                     width += floating;
13840                 }
13841                 else if (floating > 0 && floating < 0.5) {
13842                     width++;
13843                 }
13844             }
13845             
13846             if (contentWidth) {
13847                 width -= (me.getBorderWidth("lr") + me.getPadding("lr"));
13848             }
13849             
13850             if (Ext.isIEQuirks) {
13851                 me.setStyle({ overflow: overflow});
13852             }
13853
13854             if (width < 0) {
13855                 width = 0;
13856             }
13857             return width;
13858         },
13859
13860         /**
13861          * Set the width of this Element.
13862          * @param {Mixed} width The new width. This may be one of:<div class="mdetail-params"><ul>
13863          * <li>A Number specifying the new width in this Element's {@link #defaultUnit}s (by default, pixels).</li>
13864          * <li>A String used to set the CSS width style. Animation may <b>not</b> be used.
13865          * </ul></div>
13866          * @param {Boolean/Object} animate (optional) true for the default animation or a standard Element animation config object
13867          * @return {Ext.core.Element} this
13868          */
13869         setWidth : function(width, animate){
13870             var me = this;
13871             width = me.adjustWidth(width);
13872             if (!animate || !me.anim) {
13873                 me.dom.style.width = me.addUnits(width);
13874             }
13875             else {
13876                 if (!Ext.isObject(animate)) {
13877                     animate = {};
13878                 }
13879                 me.animate(Ext.applyIf({
13880                     to: {
13881                         width: width
13882                     }
13883                 }, animate));
13884             }
13885             return me;
13886         },
13887
13888         /**
13889          * Set the height of this Element.
13890          * <pre><code>
13891 // change the height to 200px and animate with default configuration
13892 Ext.fly('elementId').setHeight(200, true);
13893
13894 // change the height to 150px and animate with a custom configuration
13895 Ext.fly('elId').setHeight(150, {
13896     duration : .5, // animation will have a duration of .5 seconds
13897     // will change the content to "finished"
13898     callback: function(){ this.{@link #update}("finished"); }
13899 });
13900          * </code></pre>
13901          * @param {Mixed} height The new height. This may be one of:<div class="mdetail-params"><ul>
13902          * <li>A Number specifying the new height in this Element's {@link #defaultUnit}s (by default, pixels.)</li>
13903          * <li>A String used to set the CSS height style. Animation may <b>not</b> be used.</li>
13904          * </ul></div>
13905          * @param {Boolean/Object} animate (optional) true for the default animation or a standard Element animation config object
13906          * @return {Ext.core.Element} this
13907          */
13908          setHeight : function(height, animate){
13909             var me = this;
13910             height = me.adjustHeight(height);
13911             if (!animate || !me.anim) {
13912                 me.dom.style.height = me.addUnits(height);
13913             }
13914             else {
13915                 if (!Ext.isObject(animate)) {
13916                     animate = {};
13917                 }
13918                 me.animate(Ext.applyIf({
13919                     to: {
13920                         height: height
13921                     }
13922                 }, animate));
13923             }
13924             return me;
13925         },
13926
13927         /**
13928          * Gets the width of the border(s) for the specified side(s)
13929          * @param {String} side Can be t, l, r, b or any combination of those to add multiple values. For example,
13930          * passing <tt>'lr'</tt> would get the border <b><u>l</u></b>eft width + the border <b><u>r</u></b>ight width.
13931          * @return {Number} The width of the sides passed added together
13932          */
13933         getBorderWidth : function(side){
13934             return this.addStyles(side, borders);
13935         },
13936
13937         /**
13938          * Gets the width of the padding(s) for the specified side(s)
13939          * @param {String} side Can be t, l, r, b or any combination of those to add multiple values. For example,
13940          * passing <tt>'lr'</tt> would get the padding <b><u>l</u></b>eft + the padding <b><u>r</u></b>ight.
13941          * @return {Number} The padding of the sides passed added together
13942          */
13943         getPadding : function(side){
13944             return this.addStyles(side, paddings);
13945         },
13946
13947         /**
13948          *  Store the current overflow setting and clip overflow on the element - use <tt>{@link #unclip}</tt> to remove
13949          * @return {Ext.core.Element} this
13950          */
13951         clip : function(){
13952             var me = this,
13953                 dom = me.dom;
13954
13955             if(!data(dom, ISCLIPPED)){
13956                 data(dom, ISCLIPPED, true);
13957                 data(dom, ORIGINALCLIP, {
13958                     o: me.getStyle(OVERFLOW),
13959                     x: me.getStyle(OVERFLOWX),
13960                     y: me.getStyle(OVERFLOWY)
13961                 });
13962                 me.setStyle(OVERFLOW, HIDDEN);
13963                 me.setStyle(OVERFLOWX, HIDDEN);
13964                 me.setStyle(OVERFLOWY, HIDDEN);
13965             }
13966             return me;
13967         },
13968
13969         /**
13970          *  Return clipping (overflow) to original clipping before <tt>{@link #clip}</tt> was called
13971          * @return {Ext.core.Element} this
13972          */
13973         unclip : function(){
13974             var me = this,
13975                 dom = me.dom,
13976                 clip;
13977
13978             if(data(dom, ISCLIPPED)){
13979                 data(dom, ISCLIPPED, false);
13980                 clip = data(dom, ORIGINALCLIP);
13981                 if(o.o){
13982                     me.setStyle(OVERFLOW, o.o);
13983                 }
13984                 if(o.x){
13985                     me.setStyle(OVERFLOWX, o.x);
13986                 }
13987                 if(o.y){
13988                     me.setStyle(OVERFLOWY, o.y);
13989                 }
13990             }
13991             return me;
13992         },
13993
13994         // private
13995         addStyles : function(sides, styles){
13996             var totalSize = 0,
13997                 sidesArr = sides.match(wordsRe),
13998                 i = 0,
13999                 len = sidesArr.length,
14000                 side, size;
14001             for (; i < len; i++) {
14002                 side = sidesArr[i];
14003                 size = side && parseInt(this.getStyle(styles[side]), 10);
14004                 if (size) {
14005                     totalSize += MATH.abs(size);
14006                 }
14007             }
14008             return totalSize;
14009         },
14010
14011         margins : margins,
14012         
14013         /**
14014          * More flexible version of {@link #setStyle} for setting style properties.
14015          * @param {String/Object/Function} styles A style specification string, e.g. "width:100px", or object in the form {width:"100px"}, or
14016          * a function which returns such a specification.
14017          * @return {Ext.core.Element} this
14018          */
14019         applyStyles : function(style){
14020             Ext.core.DomHelper.applyStyles(this.dom, style);
14021             return this;
14022         },
14023
14024         /**
14025          * Returns an object with properties matching the styles requested.
14026          * For example, el.getStyles('color', 'font-size', 'width') might return
14027          * {'color': '#FFFFFF', 'font-size': '13px', 'width': '100px'}.
14028          * @param {String} style1 A style name
14029          * @param {String} style2 A style name
14030          * @param {String} etc.
14031          * @return {Object} The style object
14032          */
14033         getStyles : function(){
14034             var styles = {},
14035                 len = arguments.length,
14036                 i = 0, style;
14037                 
14038             for(; i < len; ++i) {
14039                 style = arguments[i];
14040                 styles[style] = this.getStyle(style);
14041             }
14042             return styles;
14043         },
14044
14045        /**
14046         * <p>Wraps the specified element with a special 9 element markup/CSS block that renders by default as
14047         * a gray container with a gradient background, rounded corners and a 4-way shadow.</p>
14048         * <p>This special markup is used throughout Ext when box wrapping elements ({@link Ext.button.Button},
14049         * {@link Ext.panel.Panel} when <tt>{@link Ext.panel.Panel#frame frame=true}</tt>, {@link Ext.window.Window}).  The markup
14050         * is of this form:</p>
14051         * <pre><code>
14052     Ext.core.Element.boxMarkup =
14053     &#39;&lt;div class="{0}-tl">&lt;div class="{0}-tr">&lt;div class="{0}-tc">&lt;/div>&lt;/div>&lt;/div>
14054      &lt;div class="{0}-ml">&lt;div class="{0}-mr">&lt;div class="{0}-mc">&lt;/div>&lt;/div>&lt;/div>
14055      &lt;div class="{0}-bl">&lt;div class="{0}-br">&lt;div class="{0}-bc">&lt;/div>&lt;/div>&lt;/div>&#39;;
14056         * </code></pre>
14057         * <p>Example usage:</p>
14058         * <pre><code>
14059     // Basic box wrap
14060     Ext.get("foo").boxWrap();
14061
14062     // You can also add a custom class and use CSS inheritance rules to customize the box look.
14063     // 'x-box-blue' is a built-in alternative -- look at the related CSS definitions as an example
14064     // for how to create a custom box wrap style.
14065     Ext.get("foo").boxWrap().addCls("x-box-blue");
14066         * </code></pre>
14067         * @param {String} class (optional) A base CSS class to apply to the containing wrapper element
14068         * (defaults to <tt>'x-box'</tt>). Note that there are a number of CSS rules that are dependent on
14069         * this name to make the overall effect work, so if you supply an alternate base class, make sure you
14070         * also supply all of the necessary rules.
14071         * @return {Ext.core.Element} The outermost wrapping element of the created box structure.
14072         */
14073         boxWrap : function(cls){
14074             cls = cls || Ext.baseCSSPrefix + 'box';
14075             var el = Ext.get(this.insertHtml("beforeBegin", "<div class='" + cls + "'>" + Ext.String.format(Ext.core.Element.boxMarkup, cls) + "</div>"));
14076             Ext.DomQuery.selectNode('.' + cls + '-mc', el.dom).appendChild(this.dom);
14077             return el;
14078         },
14079
14080         /**
14081          * Set the size of this Element. If animation is true, both width and height will be animated concurrently.
14082          * @param {Mixed} width The new width. This may be one of:<div class="mdetail-params"><ul>
14083          * <li>A Number specifying the new width in this Element's {@link #defaultUnit}s (by default, pixels).</li>
14084          * <li>A String used to set the CSS width style. Animation may <b>not</b> be used.
14085          * <li>A size object in the format <code>{width: widthValue, height: heightValue}</code>.</li>
14086          * </ul></div>
14087          * @param {Mixed} height The new height. This may be one of:<div class="mdetail-params"><ul>
14088          * <li>A Number specifying the new height in this Element's {@link #defaultUnit}s (by default, pixels).</li>
14089          * <li>A String used to set the CSS height style. Animation may <b>not</b> be used.</li>
14090          * </ul></div>
14091          * @param {Boolean/Object} animate (optional) true for the default animation or a standard Element animation config object
14092          * @return {Ext.core.Element} this
14093          */
14094         setSize : function(width, height, animate){
14095             var me = this;
14096             if (Ext.isObject(width)){ // in case of object from getSize()
14097                 height = width.height;
14098                 width = width.width;
14099             }
14100             width = me.adjustWidth(width);
14101             height = me.adjustHeight(height);
14102             if(!animate || !me.anim){
14103                 me.dom.style.width = me.addUnits(width);
14104                 me.dom.style.height = me.addUnits(height);
14105             }
14106             else {
14107                 if (!Ext.isObject(animate)) {
14108                     animate = {};
14109                 }
14110                 me.animate(Ext.applyIf({
14111                     to: {
14112                         width: width,
14113                         height: height
14114                     }
14115                 }, animate));
14116             }
14117             return me;
14118         },
14119
14120         /**
14121          * Returns either the offsetHeight or the height of this element based on CSS height adjusted by padding or borders
14122          * when needed to simulate offsetHeight when offsets aren't available. This may not work on display:none elements
14123          * if a height has not been set using CSS.
14124          * @return {Number}
14125          */
14126         getComputedHeight : function(){
14127             var me = this,
14128                 h = Math.max(me.dom.offsetHeight, me.dom.clientHeight);
14129             if(!h){
14130                 h = parseFloat(me.getStyle('height')) || 0;
14131                 if(!me.isBorderBox()){
14132                     h += me.getFrameWidth('tb');
14133                 }
14134             }
14135             return h;
14136         },
14137
14138         /**
14139          * Returns either the offsetWidth or the width of this element based on CSS width adjusted by padding or borders
14140          * when needed to simulate offsetWidth when offsets aren't available. This may not work on display:none elements
14141          * if a width has not been set using CSS.
14142          * @return {Number}
14143          */
14144         getComputedWidth : function(){
14145             var me = this,
14146                 w = Math.max(me.dom.offsetWidth, me.dom.clientWidth);
14147                 
14148             if(!w){
14149                 w = parseFloat(me.getStyle('width')) || 0;
14150                 if(!me.isBorderBox()){
14151                     w += me.getFrameWidth('lr');
14152                 }
14153             }
14154             return w;
14155         },
14156
14157         /**
14158          * Returns the sum width of the padding and borders for the passed "sides". See getBorderWidth()
14159          for more information about the sides.
14160          * @param {String} sides
14161          * @return {Number}
14162          */
14163         getFrameWidth : function(sides, onlyContentBox){
14164             return onlyContentBox && this.isBorderBox() ? 0 : (this.getPadding(sides) + this.getBorderWidth(sides));
14165         },
14166
14167         /**
14168          * Sets up event handlers to add and remove a css class when the mouse is over this element
14169          * @param {String} className
14170          * @return {Ext.core.Element} this
14171          */
14172         addClsOnOver : function(className){
14173             var dom = this.dom;
14174             this.hover(
14175                 function(){
14176                     Ext.fly(dom, INTERNAL).addCls(className);
14177                 },
14178                 function(){
14179                     Ext.fly(dom, INTERNAL).removeCls(className);
14180                 }
14181             );
14182             return this;
14183         },
14184
14185         /**
14186          * Sets up event handlers to add and remove a css class when this element has the focus
14187          * @param {String} className
14188          * @return {Ext.core.Element} this
14189          */
14190         addClsOnFocus : function(className){
14191             var me = this,
14192                 dom = me.dom;
14193             me.on("focus", function(){
14194                 Ext.fly(dom, INTERNAL).addCls(className);
14195             });
14196             me.on("blur", function(){
14197                 Ext.fly(dom, INTERNAL).removeCls(className);
14198             });
14199             return me;
14200         },
14201
14202         /**
14203          * 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)
14204          * @param {String} className
14205          * @return {Ext.core.Element} this
14206          */
14207         addClsOnClick : function(className){
14208             var dom = this.dom;
14209             this.on("mousedown", function(){
14210                 Ext.fly(dom, INTERNAL).addCls(className);
14211                 var d = Ext.getDoc(),
14212                     fn = function(){
14213                         Ext.fly(dom, INTERNAL).removeCls(className);
14214                         d.removeListener("mouseup", fn);
14215                     };
14216                 d.on("mouseup", fn);
14217             });
14218             return this;
14219         },
14220
14221         /**
14222          * <p>Returns the dimensions of the element available to lay content out in.<p>
14223          * <p>If the element (or any ancestor element) has CSS style <code>display : none</code>, the dimensions will be zero.</p>
14224          * example:<pre><code>
14225         var vpSize = Ext.getBody().getViewSize();
14226
14227         // all Windows created afterwards will have a default value of 90% height and 95% width
14228         Ext.Window.override({
14229             width: vpSize.width * 0.9,
14230             height: vpSize.height * 0.95
14231         });
14232         // To handle window resizing you would have to hook onto onWindowResize.
14233         * </code></pre>
14234         *
14235         * getViewSize utilizes clientHeight/clientWidth which excludes sizing of scrollbars.
14236         * To obtain the size including scrollbars, use getStyleSize
14237         *
14238         * Sizing of the document body is handled at the adapter level which handles special cases for IE and strict modes, etc.
14239         */
14240
14241         getViewSize : function(){
14242             var me = this,
14243                 dom = me.dom,
14244                 isDoc = (dom == Ext.getDoc().dom || dom == Ext.getBody().dom),
14245                 style, overflow, ret;
14246
14247             // If the body, use static methods
14248             if (isDoc) {
14249                 ret = {
14250                     width : Ext.core.Element.getViewWidth(),
14251                     height : Ext.core.Element.getViewHeight()
14252                 };
14253
14254             // Else use clientHeight/clientWidth
14255             }
14256             else {
14257                 // IE 6 & IE Quirks mode acts more like a max-size measurement unless overflow is hidden during measurement.
14258                 // We will put the overflow back to it's original value when we are done measuring.
14259                 if (Ext.isIE6 || Ext.isIEQuirks) {
14260                     style = dom.style;
14261                     overflow = style.overflow;
14262                     me.setStyle({ overflow: 'hidden'});
14263                 }
14264                 ret = {
14265                     width : dom.clientWidth,
14266                     height : dom.clientHeight
14267                 };
14268                 if (Ext.isIE6 || Ext.isIEQuirks) {
14269                     me.setStyle({ overflow: overflow });
14270                 }
14271             }
14272             return ret;
14273         },
14274
14275         /**
14276         * <p>Returns the dimensions of the element available to lay content out in.<p>
14277         *
14278         * getStyleSize utilizes prefers style sizing if present, otherwise it chooses the larger of offsetHeight/clientHeight and offsetWidth/clientWidth.
14279         * To obtain the size excluding scrollbars, use getViewSize
14280         *
14281         * Sizing of the document body is handled at the adapter level which handles special cases for IE and strict modes, etc.
14282         */
14283
14284         getStyleSize : function(){
14285             var me = this,
14286                 doc = document,
14287                 d = this.dom,
14288                 isDoc = (d == doc || d == doc.body),
14289                 s = d.style,
14290                 w, h;
14291
14292             // If the body, use static methods
14293             if (isDoc) {
14294                 return {
14295                     width : Ext.core.Element.getViewWidth(),
14296                     height : Ext.core.Element.getViewHeight()
14297                 };
14298             }
14299             // Use Styles if they are set
14300             if(s.width && s.width != 'auto'){
14301                 w = parseFloat(s.width);
14302                 if(me.isBorderBox()){
14303                    w -= me.getFrameWidth('lr');
14304                 }
14305             }
14306             // Use Styles if they are set
14307             if(s.height && s.height != 'auto'){
14308                 h = parseFloat(s.height);
14309                 if(me.isBorderBox()){
14310                    h -= me.getFrameWidth('tb');
14311                 }
14312             }
14313             // Use getWidth/getHeight if style not set.
14314             return {width: w || me.getWidth(true), height: h || me.getHeight(true)};
14315         },
14316
14317         /**
14318          * Returns the size of the element.
14319          * @param {Boolean} contentSize (optional) true to get the width/size minus borders and padding
14320          * @return {Object} An object containing the element's size {width: (element width), height: (element height)}
14321          */
14322         getSize : function(contentSize){
14323             return {width: this.getWidth(contentSize), height: this.getHeight(contentSize)};
14324         },
14325
14326         /**
14327          * Forces the browser to repaint this element
14328          * @return {Ext.core.Element} this
14329          */
14330         repaint : function(){
14331             var dom = this.dom;
14332             this.addCls(Ext.baseCSSPrefix + 'repaint');
14333             setTimeout(function(){
14334                 Ext.fly(dom).removeCls(Ext.baseCSSPrefix + 'repaint');
14335             }, 1);
14336             return this;
14337         },
14338
14339         /**
14340          * Disables text selection for this element (normalized across browsers)
14341          * @return {Ext.core.Element} this
14342          */
14343         unselectable : function(){
14344             var me = this;
14345             me.dom.unselectable = "on";
14346
14347             me.swallowEvent("selectstart", true);
14348             me.applyStyles("-moz-user-select:none;-khtml-user-select:none;");
14349             me.addCls(Ext.baseCSSPrefix + 'unselectable');
14350             
14351             return me;
14352         },
14353
14354         /**
14355          * Returns an object with properties top, left, right and bottom representing the margins of this element unless sides is passed,
14356          * then it returns the calculated width of the sides (see getPadding)
14357          * @param {String} sides (optional) Any combination of l, r, t, b to get the sum of those sides
14358          * @return {Object/Number}
14359          */
14360         getMargin : function(side){
14361             var me = this,
14362                 hash = {t:"top", l:"left", r:"right", b: "bottom"},
14363                 o = {},
14364                 key;
14365
14366             if (!side) {
14367                 for (key in me.margins){
14368                     o[hash[key]] = parseFloat(me.getStyle(me.margins[key])) || 0;
14369                 }
14370                 return o;
14371             } else {
14372                 return me.addStyles.call(me, side, me.margins);
14373             }
14374         }
14375     });
14376 })();
14377 /**
14378  * @class Ext.core.Element
14379  */
14380 /**
14381  * Visibility mode constant for use with {@link #setVisibilityMode}. Use visibility to hide element
14382  * @static
14383  * @type Number
14384  */
14385 Ext.core.Element.VISIBILITY = 1;
14386 /**
14387  * Visibility mode constant for use with {@link #setVisibilityMode}. Use display to hide element
14388  * @static
14389  * @type Number
14390  */
14391 Ext.core.Element.DISPLAY = 2;
14392
14393 /**
14394  * Visibility mode constant for use with {@link #setVisibilityMode}. Use offsets (x and y positioning offscreen)
14395  * to hide element.
14396  * @static
14397  * @type Number
14398  */
14399 Ext.core.Element.OFFSETS = 3;
14400
14401
14402 Ext.core.Element.ASCLASS = 4;
14403
14404 /**
14405  * Defaults to 'x-hide-nosize'
14406  * @static
14407  * @type String
14408  */
14409 Ext.core.Element.visibilityCls = Ext.baseCSSPrefix + 'hide-nosize';
14410
14411 Ext.core.Element.addMethods(function(){
14412     var El = Ext.core.Element,
14413         OPACITY = "opacity",
14414         VISIBILITY = "visibility",
14415         DISPLAY = "display",
14416         HIDDEN = "hidden",
14417         OFFSETS = "offsets",
14418         ASCLASS = "asclass",
14419         NONE = "none",
14420         NOSIZE = 'nosize',
14421         ORIGINALDISPLAY = 'originalDisplay',
14422         VISMODE = 'visibilityMode',
14423         ISVISIBLE = 'isVisible',
14424         data = El.data,
14425         getDisplay = function(dom){
14426             var d = data(dom, ORIGINALDISPLAY);
14427             if(d === undefined){
14428                 data(dom, ORIGINALDISPLAY, d = '');
14429             }
14430             return d;
14431         },
14432         getVisMode = function(dom){
14433             var m = data(dom, VISMODE);
14434             if(m === undefined){
14435                 data(dom, VISMODE, m = 1);
14436             }
14437             return m;
14438         };
14439
14440     return {
14441         /**
14442          * The element's default display mode  (defaults to "")
14443          * @type String
14444          */
14445         originalDisplay : "",
14446         visibilityMode : 1,
14447
14448         /**
14449          * Sets the element's visibility mode. When setVisible() is called it
14450          * will use this to determine whether to set the visibility or the display property.
14451          * @param {Number} visMode Ext.core.Element.VISIBILITY or Ext.core.Element.DISPLAY
14452          * @return {Ext.core.Element} this
14453          */
14454         setVisibilityMode : function(visMode){
14455             data(this.dom, VISMODE, visMode);
14456             return this;
14457         },
14458
14459         /**
14460          * Checks whether the element is currently visible using both visibility and display properties.
14461          * @return {Boolean} True if the element is currently visible, else false
14462          */
14463         isVisible : function() {
14464             var me = this,
14465                 dom = me.dom,
14466                 visible = data(dom, ISVISIBLE);
14467
14468             if(typeof visible == 'boolean'){ //return the cached value if registered
14469                 return visible;
14470             }
14471             //Determine the current state based on display states
14472             visible = !me.isStyle(VISIBILITY, HIDDEN) &&
14473                       !me.isStyle(DISPLAY, NONE) &&
14474                       !((getVisMode(dom) == El.ASCLASS) && me.hasCls(me.visibilityCls || El.visibilityCls));
14475
14476             data(dom, ISVISIBLE, visible);
14477             return visible;
14478         },
14479
14480         /**
14481          * Sets the visibility of the element (see details). If the visibilityMode is set to Element.DISPLAY, it will use
14482          * the display property to hide the element, otherwise it uses visibility. The default is to hide and show using the visibility property.
14483          * @param {Boolean} visible Whether the element is visible
14484          * @param {Boolean/Object} animate (optional) True for the default animation, or a standard Element animation config object
14485          * @return {Ext.core.Element} this
14486          */
14487         setVisible : function(visible, animate){
14488             var me = this, isDisplay, isVisibility, isOffsets, isNosize,
14489                 dom = me.dom,
14490                 visMode = getVisMode(dom);
14491
14492
14493             // hideMode string override
14494             if (typeof animate == 'string'){
14495                 switch (animate) {
14496                     case DISPLAY:
14497                         visMode = El.DISPLAY;
14498                         break;
14499                     case VISIBILITY:
14500                         visMode = El.VISIBILITY;
14501                         break;
14502                     case OFFSETS:
14503                         visMode = El.OFFSETS;
14504                         break;
14505                     case NOSIZE:
14506                     case ASCLASS:
14507                         visMode = El.ASCLASS;
14508                         break;
14509                 }
14510                 me.setVisibilityMode(visMode);
14511                 animate = false;
14512             }
14513
14514             if (!animate || !me.anim) {
14515                 if(visMode == El.ASCLASS ){
14516
14517                     me[visible?'removeCls':'addCls'](me.visibilityCls || El.visibilityCls);
14518
14519                 } else if (visMode == El.DISPLAY){
14520
14521                     return me.setDisplayed(visible);
14522
14523                 } else if (visMode == El.OFFSETS){
14524
14525                     if (!visible){
14526                         // Remember position for restoring, if we are not already hidden by offsets.
14527                         if (!me.hideModeStyles) {
14528                             me.hideModeStyles = {
14529                                 position: me.getStyle('position'),
14530                                 top: me.getStyle('top'),
14531                                 left: me.getStyle('left')
14532                             };
14533                         }
14534                         me.applyStyles({position: 'absolute', top: '-10000px', left: '-10000px'});
14535                     }
14536
14537                     // Only "restore" as position if we have actually been hidden using offsets.
14538                     // Calling setVisible(true) on a positioned element should not reposition it.
14539                     else if (me.hideModeStyles) {
14540                         me.applyStyles(me.hideModeStyles || {position: '', top: '', left: ''});
14541                         delete me.hideModeStyles;
14542                     }
14543
14544                 }else{
14545                     me.fixDisplay();
14546                     // Show by clearing visibility style. Explicitly setting to "visible" overrides parent visibility setting.
14547                     dom.style.visibility = visible ? '' : HIDDEN;
14548                 }
14549             }else{
14550                 // closure for composites
14551                 if(visible){
14552                     me.setOpacity(0.01);
14553                     me.setVisible(true);
14554                 }
14555                 if (!Ext.isObject(animate)) {
14556                     animate = {
14557                         duration: 350,
14558                         easing: 'ease-in'
14559                     };
14560                 }
14561                 me.animate(Ext.applyIf({
14562                     callback: function() {
14563                         visible || me.setVisible(false).setOpacity(1);
14564                     },
14565                     to: {
14566                         opacity: (visible) ? 1 : 0
14567                     }
14568                 }, animate));
14569             }
14570             data(dom, ISVISIBLE, visible);  //set logical visibility state
14571             return me;
14572         },
14573
14574
14575         /**
14576          * @private
14577          * Determine if the Element has a relevant height and width available based
14578          * upon current logical visibility state
14579          */
14580         hasMetrics  : function(){
14581             var dom = this.dom;
14582             return this.isVisible() || (getVisMode(dom) == El.OFFSETS) || (getVisMode(dom) == El.VISIBILITY);
14583         },
14584
14585         /**
14586          * Toggles the element's visibility or display, depending on visibility mode.
14587          * @param {Boolean/Object} animate (optional) True for the default animation, or a standard Element animation config object
14588          * @return {Ext.core.Element} this
14589          */
14590         toggle : function(animate){
14591             var me = this;
14592             me.setVisible(!me.isVisible(), me.anim(animate));
14593             return me;
14594         },
14595
14596         /**
14597          * Sets the CSS display property. Uses originalDisplay if the specified value is a boolean true.
14598          * @param {Mixed} value Boolean value to display the element using its default display, or a string to set the display directly.
14599          * @return {Ext.core.Element} this
14600          */
14601         setDisplayed : function(value) {
14602             if(typeof value == "boolean"){
14603                value = value ? getDisplay(this.dom) : NONE;
14604             }
14605             this.setStyle(DISPLAY, value);
14606             return this;
14607         },
14608
14609         // private
14610         fixDisplay : function(){
14611             var me = this;
14612             if (me.isStyle(DISPLAY, NONE)) {
14613                 me.setStyle(VISIBILITY, HIDDEN);
14614                 me.setStyle(DISPLAY, getDisplay(this.dom)); // first try reverting to default
14615                 if (me.isStyle(DISPLAY, NONE)) { // if that fails, default to block
14616                     me.setStyle(DISPLAY, "block");
14617                 }
14618             }
14619         },
14620
14621         /**
14622          * Hide this element - Uses display mode to determine whether to use "display" or "visibility". See {@link #setVisible}.
14623          * @param {Boolean/Object} animate (optional) true for the default animation or a standard Element animation config object
14624          * @return {Ext.core.Element} this
14625          */
14626         hide : function(animate){
14627             // hideMode override
14628             if (typeof animate == 'string'){
14629                 this.setVisible(false, animate);
14630                 return this;
14631             }
14632             this.setVisible(false, this.anim(animate));
14633             return this;
14634         },
14635
14636         /**
14637         * Show this element - Uses display mode to determine whether to use "display" or "visibility". See {@link #setVisible}.
14638         * @param {Boolean/Object} animate (optional) true for the default animation or a standard Element animation config object
14639          * @return {Ext.core.Element} this
14640          */
14641         show : function(animate){
14642             // hideMode override
14643             if (typeof animate == 'string'){
14644                 this.setVisible(true, animate);
14645                 return this;
14646             }
14647             this.setVisible(true, this.anim(animate));
14648             return this;
14649         }
14650     };
14651 }());
14652 /**
14653  * @class Ext.core.Element
14654  */
14655 Ext.applyIf(Ext.core.Element.prototype, {
14656     // @private override base Ext.util.Animate mixin for animate for backwards compatibility
14657     animate: function(config) {
14658         var me = this;
14659         if (!me.id) {
14660             me = Ext.get(me.dom);
14661         }
14662         if (Ext.fx.Manager.hasFxBlock(me.id)) {
14663             return me;
14664         }
14665         Ext.fx.Manager.queueFx(Ext.create('Ext.fx.Anim', me.anim(config)));
14666         return this;
14667     },
14668
14669     // @private override base Ext.util.Animate mixin for animate for backwards compatibility
14670     anim: function(config) {
14671         if (!Ext.isObject(config)) {
14672             return (config) ? {} : false;
14673         }
14674
14675         var me = this,
14676             duration = config.duration || Ext.fx.Anim.prototype.duration,
14677             easing = config.easing || 'ease',
14678             animConfig;
14679
14680         if (config.stopAnimation) {
14681             me.stopAnimation();
14682         }
14683
14684         Ext.applyIf(config, Ext.fx.Manager.getFxDefaults(me.id));
14685
14686         // Clear any 'paused' defaults.
14687         Ext.fx.Manager.setFxDefaults(me.id, {
14688             delay: 0
14689         });
14690
14691         animConfig = {
14692             target: me,
14693             remove: config.remove,
14694             alternate: config.alternate || false,
14695             duration: duration,
14696             easing: easing,
14697             callback: config.callback,
14698             listeners: config.listeners,
14699             iterations: config.iterations || 1,
14700             scope: config.scope,
14701             block: config.block,
14702             concurrent: config.concurrent,
14703             delay: config.delay || 0,
14704             paused: true,
14705             keyframes: config.keyframes,
14706             from: config.from || {},
14707             to: Ext.apply({}, config)
14708         };
14709         Ext.apply(animConfig.to, config.to);
14710
14711         // Anim API properties - backward compat
14712         delete animConfig.to.to;
14713         delete animConfig.to.from;
14714         delete animConfig.to.remove;
14715         delete animConfig.to.alternate;
14716         delete animConfig.to.keyframes;
14717         delete animConfig.to.iterations;
14718         delete animConfig.to.listeners;
14719         delete animConfig.to.target;
14720         delete animConfig.to.paused;
14721         delete animConfig.to.callback;
14722         delete animConfig.to.scope;
14723         delete animConfig.to.duration;
14724         delete animConfig.to.easing;
14725         delete animConfig.to.concurrent;
14726         delete animConfig.to.block;
14727         delete animConfig.to.stopAnimation;
14728         delete animConfig.to.delay;
14729         return animConfig;
14730     },
14731
14732     /**
14733      * Slides the element into view.  An anchor point can be optionally passed to set the point of
14734      * origin for the slide effect.  This function automatically handles wrapping the element with
14735      * a fixed-size container if needed.  See the Fx class overview for valid anchor point options.
14736      * Usage:
14737      *<pre><code>
14738 // default: slide the element in from the top
14739 el.slideIn();
14740
14741 // custom: slide the element in from the right with a 2-second duration
14742 el.slideIn('r', { duration: 2 });
14743
14744 // common config options shown with default values
14745 el.slideIn('t', {
14746     easing: 'easeOut',
14747     duration: 500
14748 });
14749 </code></pre>
14750      * @param {String} anchor (optional) One of the valid Fx anchor positions (defaults to top: 't')
14751      * @param {Object} options (optional) Object literal with any of the Fx config options
14752      * @return {Ext.core.Element} The Element
14753      */
14754     slideIn: function(anchor, obj, slideOut) { 
14755         var me = this,
14756             elStyle = me.dom.style,
14757             beforeAnim, wrapAnim;
14758
14759         anchor = anchor || "t";
14760         obj = obj || {};
14761
14762         beforeAnim = function() {
14763             var animScope = this,
14764                 listeners = obj.listeners,
14765                 box, position, restoreSize, wrap, anim;
14766
14767             if (!slideOut) {
14768                 me.fixDisplay();
14769             }
14770
14771             box = me.getBox();
14772             if ((anchor == 't' || anchor == 'b') && box.height == 0) {
14773                 box.height = me.dom.scrollHeight;
14774             }
14775             else if ((anchor == 'l' || anchor == 'r') && box.width == 0) {
14776                 box.width = me.dom.scrollWidth;
14777             }
14778             
14779             position = me.getPositioning();
14780             me.setSize(box.width, box.height);
14781
14782             wrap = me.wrap({
14783                 style: {
14784                     visibility: slideOut ? 'visible' : 'hidden'
14785                 }
14786             });
14787             wrap.setPositioning(position);
14788             if (wrap.isStyle('position', 'static')) {
14789                 wrap.position('relative');
14790             }
14791             me.clearPositioning('auto');
14792             wrap.clip();
14793
14794             // This element is temporarily positioned absolute within its wrapper.
14795             // Restore to its default, CSS-inherited visibility setting.
14796             // We cannot explicitly poke visibility:visible into its style because that overrides the visibility of the wrap.
14797             me.setStyle({
14798                 visibility: '',
14799                 position: 'absolute'
14800             });
14801             if (slideOut) {
14802                 wrap.setSize(box.width, box.height);
14803             }
14804
14805             switch (anchor) {
14806                 case 't':
14807                     anim = {
14808                         from: {
14809                             width: box.width + 'px',
14810                             height: '0px'
14811                         },
14812                         to: {
14813                             width: box.width + 'px',
14814                             height: box.height + 'px'
14815                         }
14816                     };
14817                     elStyle.bottom = '0px';
14818                     break;
14819                 case 'l':
14820                     anim = {
14821                         from: {
14822                             width: '0px',
14823                             height: box.height + 'px'
14824                         },
14825                         to: {
14826                             width: box.width + 'px',
14827                             height: box.height + 'px'
14828                         }
14829                     };
14830                     elStyle.right = '0px';
14831                     break;
14832                 case 'r':
14833                     anim = {
14834                         from: {
14835                             x: box.x + box.width,
14836                             width: '0px',
14837                             height: box.height + 'px'
14838                         },
14839                         to: {
14840                             x: box.x,
14841                             width: box.width + 'px',
14842                             height: box.height + 'px'
14843                         }
14844                     };
14845                     break;
14846                 case 'b':
14847                     anim = {
14848                         from: {
14849                             y: box.y + box.height,
14850                             width: box.width + 'px',
14851                             height: '0px'
14852                         },
14853                         to: {
14854                             y: box.y,
14855                             width: box.width + 'px',
14856                             height: box.height + 'px'
14857                         }
14858                     };
14859                     break;
14860                 case 'tl':
14861                     anim = {
14862                         from: {
14863                             x: box.x,
14864                             y: box.y,
14865                             width: '0px',
14866                             height: '0px'
14867                         },
14868                         to: {
14869                             width: box.width + 'px',
14870                             height: box.height + 'px'
14871                         }
14872                     };
14873                     elStyle.bottom = '0px';
14874                     elStyle.right = '0px';
14875                     break;
14876                 case 'bl':
14877                     anim = {
14878                         from: {
14879                             x: box.x + box.width,
14880                             width: '0px',
14881                             height: '0px'
14882                         },
14883                         to: {
14884                             x: box.x,
14885                             width: box.width + 'px',
14886                             height: box.height + 'px'
14887                         }
14888                     };
14889                     elStyle.right = '0px';
14890                     break;
14891                 case 'br':
14892                     anim = {
14893                         from: {
14894                             x: box.x + box.width,
14895                             y: box.y + box.height,
14896                             width: '0px',
14897                             height: '0px'
14898                         },
14899                         to: {
14900                             x: box.x,
14901                             y: box.y,
14902                             width: box.width + 'px',
14903                             height: box.height + 'px'
14904                         }
14905                     };
14906                     break;
14907                 case 'tr':
14908                     anim = {
14909                         from: {
14910                             y: box.y + box.height,
14911                             width: '0px',
14912                             height: '0px'
14913                         },
14914                         to: {
14915                             y: box.y,
14916                             width: box.width + 'px',
14917                             height: box.height + 'px'
14918                         }
14919                     };
14920                     elStyle.bottom = '0px';
14921                     break;
14922             }
14923
14924             wrap.show();
14925             wrapAnim = Ext.apply({}, obj);
14926             delete wrapAnim.listeners;
14927             wrapAnim = Ext.create('Ext.fx.Anim', Ext.applyIf(wrapAnim, {
14928                 target: wrap,
14929                 duration: 500,
14930                 easing: 'ease-out',
14931                 from: slideOut ? anim.to : anim.from,
14932                 to: slideOut ? anim.from : anim.to
14933             }));
14934
14935             // In the absence of a callback, this listener MUST be added first
14936             wrapAnim.on('afteranimate', function() {
14937                 if (slideOut) {
14938                     me.setPositioning(position);
14939                     if (obj.useDisplay) {
14940                         me.setDisplayed(false);
14941                     } else {
14942                         me.hide();   
14943                     }
14944                 }
14945                 else {
14946                     me.clearPositioning();
14947                     me.setPositioning(position);
14948                 }
14949                 if (wrap.dom) {
14950                     wrap.dom.parentNode.insertBefore(me.dom, wrap.dom); 
14951                     wrap.remove();
14952                 }
14953                 me.setSize(box.width, box.height);
14954                 animScope.end();
14955             });
14956             // Add configured listeners after
14957             if (listeners) {
14958                 wrapAnim.on(listeners);
14959             }
14960         };
14961
14962         me.animate({
14963             duration: obj.duration ? obj.duration * 2 : 1000,
14964             listeners: {
14965                 beforeanimate: {
14966                     fn: beforeAnim
14967                 },
14968                 afteranimate: {
14969                     fn: function() {
14970                         if (wrapAnim && wrapAnim.running) {
14971                             wrapAnim.end();
14972                         }
14973                     }
14974                 }
14975             }
14976         });
14977         return me;
14978     },
14979
14980     
14981     /**
14982      * Slides the element out of view.  An anchor point can be optionally passed to set the end point
14983      * for the slide effect.  When the effect is completed, the element will be hidden (visibility = 
14984      * 'hidden') but block elements will still take up space in the document.  The element must be removed
14985      * from the DOM using the 'remove' config option if desired.  This function automatically handles 
14986      * wrapping the element with a fixed-size container if needed.  See the Fx class overview for valid anchor point options.
14987      * Usage:
14988      *<pre><code>
14989 // default: slide the element out to the top
14990 el.slideOut();
14991
14992 // custom: slide the element out to the right with a 2-second duration
14993 el.slideOut('r', { duration: 2 });
14994
14995 // common config options shown with default values
14996 el.slideOut('t', {
14997     easing: 'easeOut',
14998     duration: 500,
14999     remove: false,
15000     useDisplay: false
15001 });
15002 </code></pre>
15003      * @param {String} anchor (optional) One of the valid Fx anchor positions (defaults to top: 't')
15004      * @param {Object} options (optional) Object literal with any of the Fx config options
15005      * @return {Ext.core.Element} The Element
15006      */
15007     slideOut: function(anchor, o) {
15008         return this.slideIn(anchor, o, true);
15009     },
15010
15011     /**
15012      * Fades the element out while slowly expanding it in all directions.  When the effect is completed, the 
15013      * element will be hidden (visibility = 'hidden') but block elements will still take up space in the document.
15014      * Usage:
15015      *<pre><code>
15016 // default
15017 el.puff();
15018
15019 // common config options shown with default values
15020 el.puff({
15021     easing: 'easeOut',
15022     duration: 500,
15023     useDisplay: false
15024 });
15025 </code></pre>
15026      * @param {Object} options (optional) Object literal with any of the Fx config options
15027      * @return {Ext.core.Element} The Element
15028      */
15029
15030     puff: function(obj) {
15031         var me = this,
15032             beforeAnim;
15033         obj = Ext.applyIf(obj || {}, {
15034             easing: 'ease-out',
15035             duration: 500,
15036             useDisplay: false
15037         });
15038
15039         beforeAnim = function() {
15040             me.clearOpacity();
15041             me.show();
15042
15043             var box = me.getBox(),
15044                 fontSize = me.getStyle('fontSize'),
15045                 position = me.getPositioning();
15046             this.to = {
15047                 width: box.width * 2,
15048                 height: box.height * 2,
15049                 x: box.x - (box.width / 2),
15050                 y: box.y - (box.height /2),
15051                 opacity: 0,
15052                 fontSize: '200%'
15053             };
15054             this.on('afteranimate',function() {
15055                 if (me.dom) {
15056                     if (obj.useDisplay) {
15057                         me.setDisplayed(false);
15058                     } else {
15059                         me.hide();
15060                     }
15061                     me.clearOpacity();  
15062                     me.setPositioning(position);
15063                     me.setStyle({fontSize: fontSize});
15064                 }
15065             });
15066         };
15067
15068         me.animate({
15069             duration: obj.duration,
15070             easing: obj.easing,
15071             listeners: {
15072                 beforeanimate: {
15073                     fn: beforeAnim
15074                 }
15075             }
15076         });
15077         return me;
15078     },
15079
15080     /**
15081      * Blinks the element as if it was clicked and then collapses on its center (similar to switching off a television).
15082      * When the effect is completed, the element will be hidden (visibility = 'hidden') but block elements will still 
15083      * take up space in the document. The element must be removed from the DOM using the 'remove' config option if desired.
15084      * Usage:
15085      *<pre><code>
15086 // default
15087 el.switchOff();
15088
15089 // all config options shown with default values
15090 el.switchOff({
15091     easing: 'easeIn',
15092     duration: .3,
15093     remove: false,
15094     useDisplay: false
15095 });
15096 </code></pre>
15097      * @param {Object} options (optional) Object literal with any of the Fx config options
15098      * @return {Ext.core.Element} The Element
15099      */
15100     switchOff: function(obj) {
15101         var me = this,
15102             beforeAnim;
15103         
15104         obj = Ext.applyIf(obj || {}, {
15105             easing: 'ease-in',
15106             duration: 500,
15107             remove: false,
15108             useDisplay: false
15109         });
15110
15111         beforeAnim = function() {
15112             var animScope = this,
15113                 size = me.getSize(),
15114                 xy = me.getXY(),
15115                 keyframe, position;
15116             me.clearOpacity();
15117             me.clip();
15118             position = me.getPositioning();
15119
15120             keyframe = Ext.create('Ext.fx.Animator', {
15121                 target: me,
15122                 duration: obj.duration,
15123                 easing: obj.easing,
15124                 keyframes: {
15125                     33: {
15126                         opacity: 0.3
15127                     },
15128                     66: {
15129                         height: 1,
15130                         y: xy[1] + size.height / 2
15131                     },
15132                     100: {
15133                         width: 1,
15134                         x: xy[0] + size.width / 2
15135                     }
15136                 }
15137             });
15138             keyframe.on('afteranimate', function() {
15139                 if (obj.useDisplay) {
15140                     me.setDisplayed(false);
15141                 } else {
15142                     me.hide();
15143                 }  
15144                 me.clearOpacity();
15145                 me.setPositioning(position);
15146                 me.setSize(size);
15147                 animScope.end();
15148             });
15149         };
15150         me.animate({
15151             duration: (obj.duration * 2),
15152             listeners: {
15153                 beforeanimate: {
15154                     fn: beforeAnim
15155                 }
15156             }
15157         });
15158         return me;
15159     },
15160
15161    /**
15162     * Shows a ripple of exploding, attenuating borders to draw attention to an Element.
15163     * Usage:
15164 <pre><code>
15165 // default: a single light blue ripple
15166 el.frame();
15167
15168 // custom: 3 red ripples lasting 3 seconds total
15169 el.frame("#ff0000", 3, { duration: 3 });
15170
15171 // common config options shown with default values
15172 el.frame("#C3DAF9", 1, {
15173     duration: 1 //duration of each individual ripple.
15174     // Note: Easing is not configurable and will be ignored if included
15175 });
15176 </code></pre>
15177     * @param {String} color (optional) The color of the border.  Should be a 6 char hex color without the leading # (defaults to light blue: 'C3DAF9').
15178     * @param {Number} count (optional) The number of ripples to display (defaults to 1)
15179     * @param {Object} options (optional) Object literal with any of the Fx config options
15180     * @return {Ext.core.Element} The Element
15181     */
15182     frame : function(color, count, obj){
15183         var me = this,
15184             beforeAnim;
15185
15186         color = color || '#C3DAF9';
15187         count = count || 1;
15188         obj = obj || {};
15189
15190         beforeAnim = function() {
15191             me.show();
15192             var animScope = this,
15193                 box = me.getBox(),
15194                 proxy = Ext.getBody().createChild({
15195                     style: {
15196                         position : 'absolute',
15197                         'pointer-events': 'none',
15198                         'z-index': 35000,
15199                         border : '0px solid ' + color
15200                     }
15201                 }),
15202                 proxyAnim;
15203             proxyAnim = Ext.create('Ext.fx.Anim', {
15204                 target: proxy,
15205                 duration: obj.duration || 1000,
15206                 iterations: count,
15207                 from: {
15208                     top: box.y,
15209                     left: box.x,
15210                     borderWidth: 0,
15211                     opacity: 1,
15212                     height: box.height,
15213                     width: box.width
15214                 },
15215                 to: {
15216                     top: box.y - 20,
15217                     left: box.x - 20,
15218                     borderWidth: 10,
15219                     opacity: 0,
15220                     height: box.height + 40,
15221                     width: box.width + 40
15222                 }
15223             });
15224             proxyAnim.on('afteranimate', function() {
15225                 proxy.remove();
15226                 animScope.end();
15227             });
15228         };
15229
15230         me.animate({
15231             duration: (obj.duration * 2) || 2000,
15232             listeners: {
15233                 beforeanimate: {
15234                     fn: beforeAnim
15235                 }
15236             }
15237         });
15238         return me;
15239     },
15240
15241     /**
15242      * Slides the element while fading it out of view.  An anchor point can be optionally passed to set the 
15243      * ending point of the effect.
15244      * Usage:
15245      *<pre><code>
15246 // default: slide the element downward while fading out
15247 el.ghost();
15248
15249 // custom: slide the element out to the right with a 2-second duration
15250 el.ghost('r', { duration: 2 });
15251
15252 // common config options shown with default values
15253 el.ghost('b', {
15254     easing: 'easeOut',
15255     duration: 500
15256 });
15257 </code></pre>
15258      * @param {String} anchor (optional) One of the valid Fx anchor positions (defaults to bottom: 'b')
15259      * @param {Object} options (optional) Object literal with any of the Fx config options
15260      * @return {Ext.core.Element} The Element
15261      */
15262     ghost: function(anchor, obj) {
15263         var me = this,
15264             beforeAnim;
15265
15266         anchor = anchor || "b";
15267         beforeAnim = function() {
15268             var width = me.getWidth(),
15269                 height = me.getHeight(),
15270                 xy = me.getXY(),
15271                 position = me.getPositioning(),
15272                 to = {
15273                     opacity: 0
15274                 };
15275             switch (anchor) {
15276                 case 't':
15277                     to.y = xy[1] - height;
15278                     break;
15279                 case 'l':
15280                     to.x = xy[0] - width;
15281                     break;
15282                 case 'r':
15283                     to.x = xy[0] + width;
15284                     break;
15285                 case 'b':
15286                     to.y = xy[1] + height;
15287                     break;
15288                 case 'tl':
15289                     to.x = xy[0] - width;
15290                     to.y = xy[1] - height;
15291                     break;
15292                 case 'bl':
15293                     to.x = xy[0] - width;
15294                     to.y = xy[1] + height;
15295                     break;
15296                 case 'br':
15297                     to.x = xy[0] + width;
15298                     to.y = xy[1] + height;
15299                     break;
15300                 case 'tr':
15301                     to.x = xy[0] + width;
15302                     to.y = xy[1] - height;
15303                     break;
15304             }
15305             this.to = to;
15306             this.on('afteranimate', function () {
15307                 if (me.dom) {
15308                     me.hide();
15309                     me.clearOpacity();
15310                     me.setPositioning(position);
15311                 }
15312             });
15313         };
15314
15315         me.animate(Ext.applyIf(obj || {}, {
15316             duration: 500,
15317             easing: 'ease-out',
15318             listeners: {
15319                 beforeanimate: {
15320                     fn: beforeAnim
15321                 }
15322             }
15323         }));
15324         return me;
15325     },
15326
15327     /**
15328      * Highlights the Element by setting a color (applies to the background-color by default, but can be
15329      * changed using the "attr" config option) and then fading back to the original color. If no original
15330      * color is available, you should provide the "endColor" config option which will be cleared after the animation.
15331      * Usage:
15332 <pre><code>
15333 // default: highlight background to yellow
15334 el.highlight();
15335
15336 // custom: highlight foreground text to blue for 2 seconds
15337 el.highlight("0000ff", { attr: 'color', duration: 2 });
15338
15339 // common config options shown with default values
15340 el.highlight("ffff9c", {
15341     attr: "backgroundColor", //can be any valid CSS property (attribute) that supports a color value
15342     endColor: (current color) or "ffffff",
15343     easing: 'easeIn',
15344     duration: 1000
15345 });
15346 </code></pre>
15347      * @param {String} color (optional) The highlight color. Should be a 6 char hex color without the leading # (defaults to yellow: 'ffff9c')
15348      * @param {Object} options (optional) Object literal with any of the Fx config options
15349      * @return {Ext.core.Element} The Element
15350      */ 
15351     highlight: function(color, o) {
15352         var me = this,
15353             dom = me.dom,
15354             from = {},
15355             restore, to, attr, lns, event, fn;
15356
15357         o = o || {};
15358         lns = o.listeners || {};
15359         attr = o.attr || 'backgroundColor';
15360         from[attr] = color || 'ffff9c';
15361         
15362         if (!o.to) {
15363             to = {};
15364             to[attr] = o.endColor || me.getColor(attr, 'ffffff', '');
15365         }
15366         else {
15367             to = o.to;
15368         }
15369         
15370         // Don't apply directly on lns, since we reference it in our own callbacks below
15371         o.listeners = Ext.apply(Ext.apply({}, lns), {
15372             beforeanimate: function() {
15373                 restore = dom.style[attr];
15374                 me.clearOpacity();
15375                 me.show();
15376                 
15377                 event = lns.beforeanimate;
15378                 if (event) {
15379                     fn = event.fn || event;
15380                     return fn.apply(event.scope || lns.scope || window, arguments);
15381                 }
15382             },
15383             afteranimate: function() {
15384                 if (dom) {
15385                     dom.style[attr] = restore;
15386                 }
15387                 
15388                 event = lns.afteranimate;
15389                 if (event) {
15390                     fn = event.fn || event;
15391                     fn.apply(event.scope || lns.scope || window, arguments);
15392                 }
15393             }
15394         });
15395
15396         me.animate(Ext.apply({}, o, {
15397             duration: 1000,
15398             easing: 'ease-in',
15399             from: from,
15400             to: to
15401         }));
15402         return me;
15403     },
15404
15405    /**
15406     * @deprecated 4.0
15407     * Creates a pause before any subsequent queued effects begin.  If there are
15408     * no effects queued after the pause it will have no effect.
15409     * Usage:
15410 <pre><code>
15411 el.pause(1);
15412 </code></pre>
15413     * @param {Number} seconds The length of time to pause (in seconds)
15414     * @return {Ext.Element} The Element
15415     */
15416     pause: function(ms) {
15417         var me = this;
15418         Ext.fx.Manager.setFxDefaults(me.id, {
15419             delay: ms
15420         });
15421         return me;
15422     },
15423
15424    /**
15425     * Fade an element in (from transparent to opaque).  The ending opacity can be specified
15426     * using the <tt>{@link #endOpacity}</tt> config option.
15427     * Usage:
15428 <pre><code>
15429 // default: fade in from opacity 0 to 100%
15430 el.fadeIn();
15431
15432 // custom: fade in from opacity 0 to 75% over 2 seconds
15433 el.fadeIn({ endOpacity: .75, duration: 2});
15434
15435 // common config options shown with default values
15436 el.fadeIn({
15437     endOpacity: 1, //can be any value between 0 and 1 (e.g. .5)
15438     easing: 'easeOut',
15439     duration: 500
15440 });
15441 </code></pre>
15442     * @param {Object} options (optional) Object literal with any of the Fx config options
15443     * @return {Ext.Element} The Element
15444     */
15445     fadeIn: function(o) {
15446         this.animate(Ext.apply({}, o, {
15447             opacity: 1
15448         }));
15449         return this;
15450     },
15451
15452    /**
15453     * Fade an element out (from opaque to transparent).  The ending opacity can be specified
15454     * using the <tt>{@link #endOpacity}</tt> config option.  Note that IE may require
15455     * <tt>{@link #useDisplay}:true</tt> in order to redisplay correctly.
15456     * Usage:
15457 <pre><code>
15458 // default: fade out from the element's current opacity to 0
15459 el.fadeOut();
15460
15461 // custom: fade out from the element's current opacity to 25% over 2 seconds
15462 el.fadeOut({ endOpacity: .25, duration: 2});
15463
15464 // common config options shown with default values
15465 el.fadeOut({
15466     endOpacity: 0, //can be any value between 0 and 1 (e.g. .5)
15467     easing: 'easeOut',
15468     duration: 500,
15469     remove: false,
15470     useDisplay: false
15471 });
15472 </code></pre>
15473     * @param {Object} options (optional) Object literal with any of the Fx config options
15474     * @return {Ext.Element} The Element
15475     */
15476     fadeOut: function(o) {
15477         this.animate(Ext.apply({}, o, {
15478             opacity: 0
15479         }));
15480         return this;
15481     },
15482
15483    /**
15484     * @deprecated 4.0
15485     * Animates the transition of an element's dimensions from a starting height/width
15486     * to an ending height/width.  This method is a convenience implementation of {@link shift}.
15487     * Usage:
15488 <pre><code>
15489 // change height and width to 100x100 pixels
15490 el.scale(100, 100);
15491
15492 // common config options shown with default values.  The height and width will default to
15493 // the element&#39;s existing values if passed as null.
15494 el.scale(
15495     [element&#39;s width],
15496     [element&#39;s height], {
15497         easing: 'easeOut',
15498         duration: .35
15499     }
15500 );
15501 </code></pre>
15502     * @param {Number} width  The new width (pass undefined to keep the original width)
15503     * @param {Number} height  The new height (pass undefined to keep the original height)
15504     * @param {Object} options (optional) Object literal with any of the Fx config options
15505     * @return {Ext.Element} The Element
15506     */
15507     scale: function(w, h, o) {
15508         this.animate(Ext.apply({}, o, {
15509             width: w,
15510             height: h
15511         }));
15512         return this;
15513     },
15514
15515    /**
15516     * @deprecated 4.0
15517     * Animates the transition of any combination of an element's dimensions, xy position and/or opacity.
15518     * Any of these properties not specified in the config object will not be changed.  This effect 
15519     * requires that at least one new dimension, position or opacity setting must be passed in on
15520     * the config object in order for the function to have any effect.
15521     * Usage:
15522 <pre><code>
15523 // slide the element horizontally to x position 200 while changing the height and opacity
15524 el.shift({ x: 200, height: 50, opacity: .8 });
15525
15526 // common config options shown with default values.
15527 el.shift({
15528     width: [element&#39;s width],
15529     height: [element&#39;s height],
15530     x: [element&#39;s x position],
15531     y: [element&#39;s y position],
15532     opacity: [element&#39;s opacity],
15533     easing: 'easeOut',
15534     duration: .35
15535 });
15536 </code></pre>
15537     * @param {Object} options  Object literal with any of the Fx config options
15538     * @return {Ext.Element} The Element
15539     */
15540     shift: function(config) {
15541         this.animate(config);
15542         return this;
15543     }
15544 });
15545
15546 /**
15547  * @class Ext.core.Element
15548  */
15549 Ext.applyIf(Ext.core.Element, {
15550     unitRe: /\d+(px|em|%|en|ex|pt|in|cm|mm|pc)$/i,
15551     camelRe: /(-[a-z])/gi,
15552     opacityRe: /alpha\(opacity=(.*)\)/i,
15553     cssRe: /([a-z0-9-]+)\s*:\s*([^;\s]+(?:\s*[^;\s]+)*);?/gi,
15554     propertyCache: {},
15555     defaultUnit : "px",
15556     borders: {l: 'border-left-width', r: 'border-right-width', t: 'border-top-width', b: 'border-bottom-width'},
15557     paddings: {l: 'padding-left', r: 'padding-right', t: 'padding-top', b: 'padding-bottom'},
15558     margins: {l: 'margin-left', r: 'margin-right', t: 'margin-top', b: 'margin-bottom'},
15559
15560     // Reference the prototype's version of the method. Signatures are identical.
15561     addUnits : Ext.core.Element.prototype.addUnits,
15562
15563     /**
15564      * Parses a number or string representing margin sizes into an object. Supports CSS-style margin declarations
15565      * (e.g. 10, "10", "10 10", "10 10 10" and "10 10 10 10" are all valid options and would return the same result)
15566      * @static
15567      * @param {Number|String} box The encoded margins
15568      * @return {Object} An object with margin sizes for top, right, bottom and left
15569      */
15570     parseBox : function(box) {
15571         if (Ext.isObject(box)) {
15572             return {
15573                 top: box.top || 0,
15574                 right: box.right || 0,
15575                 bottom: box.bottom || 0,
15576                 left: box.left || 0
15577             };
15578         } else {
15579             if (typeof box != 'string') {
15580                 box = box.toString();
15581             }
15582             var parts  = box.split(' '),
15583                 ln = parts.length;
15584     
15585             if (ln == 1) {
15586                 parts[1] = parts[2] = parts[3] = parts[0];
15587             }
15588             else if (ln == 2) {
15589                 parts[2] = parts[0];
15590                 parts[3] = parts[1];
15591             }
15592             else if (ln == 3) {
15593                 parts[3] = parts[1];
15594             }
15595     
15596             return {
15597                 top   :parseFloat(parts[0]) || 0,
15598                 right :parseFloat(parts[1]) || 0,
15599                 bottom:parseFloat(parts[2]) || 0,
15600                 left  :parseFloat(parts[3]) || 0
15601             };
15602         }
15603         
15604     },
15605     
15606     /**
15607      * Parses a number or string representing margin sizes into an object. Supports CSS-style margin declarations
15608      * (e.g. 10, "10", "10 10", "10 10 10" and "10 10 10 10" are all valid options and would return the same result)
15609      * @static
15610      * @param {Number|String} box The encoded margins
15611      * @param {String} units The type of units to add
15612      * @return {String} An string with unitized (px if units is not specified) metrics for top, right, bottom and left
15613      */
15614     unitizeBox : function(box, units) {
15615         var A = this.addUnits,
15616             B = this.parseBox(box);
15617             
15618         return A(B.top, units) + ' ' +
15619                A(B.right, units) + ' ' +
15620                A(B.bottom, units) + ' ' +
15621                A(B.left, units);
15622         
15623     },
15624
15625     // private
15626     camelReplaceFn : function(m, a) {
15627         return a.charAt(1).toUpperCase();
15628     },
15629
15630     /**
15631      * Normalizes CSS property keys from dash delimited to camel case JavaScript Syntax.
15632      * For example:
15633      * <ul>
15634      *  <li>border-width -> borderWidth</li>
15635      *  <li>padding-top -> paddingTop</li>
15636      * </ul>
15637      * @static
15638      * @param {String} prop The property to normalize
15639      * @return {String} The normalized string
15640      */
15641     normalize : function(prop) {
15642         if (prop == 'float') {
15643             prop = Ext.supports.Float ? 'cssFloat' : 'styleFloat';
15644         }
15645         return this.propertyCache[prop] || (this.propertyCache[prop] = prop.replace(this.camelRe, this.camelReplaceFn));
15646     },
15647
15648     /**
15649      * Retrieves the document height
15650      * @static
15651      * @return {Number} documentHeight
15652      */
15653     getDocumentHeight: function() {
15654         return Math.max(!Ext.isStrict ? document.body.scrollHeight : document.documentElement.scrollHeight, this.getViewportHeight());
15655     },
15656
15657     /**
15658      * Retrieves the document width
15659      * @static
15660      * @return {Number} documentWidth
15661      */
15662     getDocumentWidth: function() {
15663         return Math.max(!Ext.isStrict ? document.body.scrollWidth : document.documentElement.scrollWidth, this.getViewportWidth());
15664     },
15665
15666     /**
15667      * Retrieves the viewport height of the window.
15668      * @static
15669      * @return {Number} viewportHeight
15670      */
15671     getViewportHeight: function(){
15672         return window.innerHeight;
15673     },
15674
15675     /**
15676      * Retrieves the viewport width of the window.
15677      * @static
15678      * @return {Number} viewportWidth
15679      */
15680     getViewportWidth : function() {
15681         return window.innerWidth;
15682     },
15683
15684     /**
15685      * Retrieves the viewport size of the window.
15686      * @static
15687      * @return {Object} object containing width and height properties
15688      */
15689     getViewSize : function() {
15690         return {
15691             width: window.innerWidth,
15692             height: window.innerHeight
15693         };
15694     },
15695
15696     /**
15697      * Retrieves the current orientation of the window. This is calculated by
15698      * determing if the height is greater than the width.
15699      * @static
15700      * @return {String} Orientation of window: 'portrait' or 'landscape'
15701      */
15702     getOrientation : function() {
15703         if (Ext.supports.OrientationChange) {
15704             return (window.orientation == 0) ? 'portrait' : 'landscape';
15705         }
15706         
15707         return (window.innerHeight > window.innerWidth) ? 'portrait' : 'landscape';
15708     },
15709
15710     /** 
15711      * Returns the top Element that is located at the passed coordinates
15712      * @static
15713      * @param {Number} x The x coordinate
15714      * @param {Number} x The y coordinate
15715      * @return {String} The found Element
15716      */
15717     fromPoint: function(x, y) {
15718         return Ext.get(document.elementFromPoint(x, y));
15719     },
15720     
15721     /**
15722      * Converts a CSS string into an object with a property for each style.
15723      * <p>
15724      * The sample code below would return an object with 2 properties, one
15725      * for background-color and one for color.</p>
15726      * <pre><code>
15727 var css = 'background-color: red;color: blue; ';
15728 console.log(Ext.core.Element.parseStyles(css));
15729      * </code></pre>
15730      * @static
15731      * @param {String} styles A CSS string
15732      * @return {Object} styles
15733      */
15734     parseStyles: function(styles){
15735         var out = {},
15736             cssRe = this.cssRe,
15737             matches;
15738             
15739         if (styles) {
15740             // Since we're using the g flag on the regex, we need to set the lastIndex.
15741             // This automatically happens on some implementations, but not others, see:
15742             // http://stackoverflow.com/questions/2645273/javascript-regular-expression-literal-persists-between-function-calls
15743             // http://blog.stevenlevithan.com/archives/fixing-javascript-regexp
15744             cssRe.lastIndex = 0;
15745             while ((matches = cssRe.exec(styles))) {
15746                 out[matches[1]] = matches[2];
15747             }
15748         }
15749         return out;
15750     }
15751 });
15752
15753 /**
15754  * @class Ext.CompositeElementLite
15755  * <p>This class encapsulates a <i>collection</i> of DOM elements, providing methods to filter
15756  * members, or to perform collective actions upon the whole set.</p>
15757  * <p>Although they are not listed, this class supports all of the methods of {@link Ext.core.Element} and
15758  * {@link Ext.fx.Anim}. The methods from these classes will be performed on all the elements in this collection.</p>
15759  * Example:<pre><code>
15760 var els = Ext.select("#some-el div.some-class");
15761 // or select directly from an existing element
15762 var el = Ext.get('some-el');
15763 el.select('div.some-class');
15764
15765 els.setWidth(100); // all elements become 100 width
15766 els.hide(true); // all elements fade out and hide
15767 // or
15768 els.setWidth(100).hide(true);
15769 </code></pre>
15770  */
15771 Ext.CompositeElementLite = function(els, root){
15772     /**
15773      * <p>The Array of DOM elements which this CompositeElement encapsulates. Read-only.</p>
15774      * <p>This will not <i>usually</i> be accessed in developers' code, but developers wishing
15775      * to augment the capabilities of the CompositeElementLite class may use it when adding
15776      * methods to the class.</p>
15777      * <p>For example to add the <code>nextAll</code> method to the class to <b>add</b> all
15778      * following siblings of selected elements, the code would be</p><code><pre>
15779 Ext.override(Ext.CompositeElementLite, {
15780     nextAll: function() {
15781         var els = this.elements, i, l = els.length, n, r = [], ri = -1;
15782
15783 //      Loop through all elements in this Composite, accumulating
15784 //      an Array of all siblings.
15785         for (i = 0; i < l; i++) {
15786             for (n = els[i].nextSibling; n; n = n.nextSibling) {
15787                 r[++ri] = n;
15788             }
15789         }
15790
15791 //      Add all found siblings to this Composite
15792         return this.add(r);
15793     }
15794 });</pre></code>
15795      * @type Array
15796      * @property elements
15797      */
15798     this.elements = [];
15799     this.add(els, root);
15800     this.el = new Ext.core.Element.Flyweight();
15801 };
15802
15803 Ext.CompositeElementLite.prototype = {
15804     isComposite: true,
15805
15806     // private
15807     getElement : function(el){
15808         // Set the shared flyweight dom property to the current element
15809         var e = this.el;
15810         e.dom = el;
15811         e.id = el.id;
15812         return e;
15813     },
15814
15815     // private
15816     transformElement : function(el){
15817         return Ext.getDom(el);
15818     },
15819
15820     /**
15821      * Returns the number of elements in this Composite.
15822      * @return Number
15823      */
15824     getCount : function(){
15825         return this.elements.length;
15826     },
15827     /**
15828      * Adds elements to this Composite object.
15829      * @param {Mixed} els Either an Array of DOM elements to add, or another Composite object who's elements should be added.
15830      * @return {CompositeElement} This Composite object.
15831      */
15832     add : function(els, root){
15833         var me = this,
15834             elements = me.elements;
15835         if(!els){
15836             return this;
15837         }
15838         if(typeof els == "string"){
15839             els = Ext.core.Element.selectorFunction(els, root);
15840         }else if(els.isComposite){
15841             els = els.elements;
15842         }else if(!Ext.isIterable(els)){
15843             els = [els];
15844         }
15845
15846         for(var i = 0, len = els.length; i < len; ++i){
15847             elements.push(me.transformElement(els[i]));
15848         }
15849         return me;
15850     },
15851
15852     invoke : function(fn, args){
15853         var me = this,
15854             els = me.elements,
15855             len = els.length,
15856             e,
15857             i;
15858
15859         for(i = 0; i < len; i++) {
15860             e = els[i];
15861             if(e){
15862                 Ext.core.Element.prototype[fn].apply(me.getElement(e), args);
15863             }
15864         }
15865         return me;
15866     },
15867     /**
15868      * Returns a flyweight Element of the dom element object at the specified index
15869      * @param {Number} index
15870      * @return {Ext.core.Element}
15871      */
15872     item : function(index){
15873         var me = this,
15874             el = me.elements[index],
15875             out = null;
15876
15877         if(el){
15878             out = me.getElement(el);
15879         }
15880         return out;
15881     },
15882
15883     // fixes scope with flyweight
15884     addListener : function(eventName, handler, scope, opt){
15885         var els = this.elements,
15886             len = els.length,
15887             i, e;
15888
15889         for(i = 0; i<len; i++) {
15890             e = els[i];
15891             if(e) {
15892                 Ext.EventManager.on(e, eventName, handler, scope || e, opt);
15893             }
15894         }
15895         return this;
15896     },
15897     /**
15898      * <p>Calls the passed function for each element in this composite.</p>
15899      * @param {Function} fn The function to call. The function is passed the following parameters:<ul>
15900      * <li><b>el</b> : Element<div class="sub-desc">The current Element in the iteration.
15901      * <b>This is the flyweight (shared) Ext.core.Element instance, so if you require a
15902      * a reference to the dom node, use el.dom.</b></div></li>
15903      * <li><b>c</b> : Composite<div class="sub-desc">This Composite object.</div></li>
15904      * <li><b>idx</b> : Number<div class="sub-desc">The zero-based index in the iteration.</div></li>
15905      * </ul>
15906      * @param {Object} scope (optional) The scope (<i>this</i> reference) in which the function is executed. (defaults to the Element)
15907      * @return {CompositeElement} this
15908      */
15909     each : function(fn, scope){
15910         var me = this,
15911             els = me.elements,
15912             len = els.length,
15913             i, e;
15914
15915         for(i = 0; i<len; i++) {
15916             e = els[i];
15917             if(e){
15918                 e = this.getElement(e);
15919                 if(fn.call(scope || e, e, me, i) === false){
15920                     break;
15921                 }
15922             }
15923         }
15924         return me;
15925     },
15926
15927     /**
15928     * Clears this Composite and adds the elements passed.
15929     * @param {Mixed} els Either an array of DOM elements, or another Composite from which to fill this Composite.
15930     * @return {CompositeElement} this
15931     */
15932     fill : function(els){
15933         var me = this;
15934         me.elements = [];
15935         me.add(els);
15936         return me;
15937     },
15938
15939     /**
15940      * Filters this composite to only elements that match the passed selector.
15941      * @param {String/Function} selector A string CSS selector or a comparison function.
15942      * The comparison function will be called with the following arguments:<ul>
15943      * <li><code>el</code> : Ext.core.Element<div class="sub-desc">The current DOM element.</div></li>
15944      * <li><code>index</code> : Number<div class="sub-desc">The current index within the collection.</div></li>
15945      * </ul>
15946      * @return {CompositeElement} this
15947      */
15948     filter : function(selector){
15949         var els = [],
15950             me = this,
15951             fn = Ext.isFunction(selector) ? selector
15952                 : function(el){
15953                     return el.is(selector);
15954                 };
15955
15956         me.each(function(el, self, i) {
15957             if (fn(el, i) !== false) {
15958                 els[els.length] = me.transformElement(el);
15959             }
15960         });
15961         
15962         me.elements = els;
15963         return me;
15964     },
15965
15966     /**
15967      * Find the index of the passed element within the composite collection.
15968      * @param el {Mixed} The id of an element, or an Ext.core.Element, or an HtmlElement to find within the composite collection.
15969      * @return Number The index of the passed Ext.core.Element in the composite collection, or -1 if not found.
15970      */
15971     indexOf : function(el){
15972         return Ext.Array.indexOf(this.elements, this.transformElement(el));
15973     },
15974
15975     /**
15976     * Replaces the specified element with the passed element.
15977     * @param {Mixed} el The id of an element, the Element itself, the index of the element in this composite
15978     * to replace.
15979     * @param {Mixed} replacement The id of an element or the Element itself.
15980     * @param {Boolean} domReplace (Optional) True to remove and replace the element in the document too.
15981     * @return {CompositeElement} this
15982     */
15983     replaceElement : function(el, replacement, domReplace){
15984         var index = !isNaN(el) ? el : this.indexOf(el),
15985             d;
15986         if(index > -1){
15987             replacement = Ext.getDom(replacement);
15988             if(domReplace){
15989                 d = this.elements[index];
15990                 d.parentNode.insertBefore(replacement, d);
15991                 Ext.removeNode(d);
15992             }
15993             this.elements.splice(index, 1, replacement);
15994         }
15995         return this;
15996     },
15997
15998     /**
15999      * Removes all elements.
16000      */
16001     clear : function(){
16002         this.elements = [];
16003     }
16004 };
16005
16006 Ext.CompositeElementLite.prototype.on = Ext.CompositeElementLite.prototype.addListener;
16007
16008 /**
16009  * @private
16010  * Copies all of the functions from Ext.core.Element's prototype onto CompositeElementLite's prototype.
16011  * This is called twice - once immediately below, and once again after additional Ext.core.Element
16012  * are added in Ext JS
16013  */
16014 Ext.CompositeElementLite.importElementMethods = function() {
16015     var fnName,
16016         ElProto = Ext.core.Element.prototype,
16017         CelProto = Ext.CompositeElementLite.prototype;
16018
16019     for (fnName in ElProto) {
16020         if (typeof ElProto[fnName] == 'function'){
16021             (function(fnName) {
16022                 CelProto[fnName] = CelProto[fnName] || function() {
16023                     return this.invoke(fnName, arguments);
16024                 };
16025             }).call(CelProto, fnName);
16026
16027         }
16028     }
16029 };
16030
16031 Ext.CompositeElementLite.importElementMethods();
16032
16033 if(Ext.DomQuery){
16034     Ext.core.Element.selectorFunction = Ext.DomQuery.select;
16035 }
16036
16037 /**
16038  * Selects elements based on the passed CSS selector to enable {@link Ext.core.Element Element} methods
16039  * to be applied to many related elements in one statement through the returned {@link Ext.CompositeElement CompositeElement} or
16040  * {@link Ext.CompositeElementLite CompositeElementLite} object.
16041  * @param {String/Array} selector The CSS selector or an array of elements
16042  * @param {HTMLElement/String} root (optional) The root element of the query or id of the root
16043  * @return {CompositeElementLite/CompositeElement}
16044  * @member Ext.core.Element
16045  * @method select
16046  */
16047 Ext.core.Element.select = function(selector, root){
16048     var els;
16049     if(typeof selector == "string"){
16050         els = Ext.core.Element.selectorFunction(selector, root);
16051     }else if(selector.length !== undefined){
16052         els = selector;
16053     }else{
16054         Ext.Error.raise({
16055             sourceClass: "Ext.core.Element",
16056             sourceMethod: "select",
16057             selector: selector,
16058             root: root,
16059             msg: "Invalid selector specified: " + selector
16060         });
16061     }
16062     return new Ext.CompositeElementLite(els);
16063 };
16064 /**
16065  * Selects elements based on the passed CSS selector to enable {@link Ext.core.Element Element} methods
16066  * to be applied to many related elements in one statement through the returned {@link Ext.CompositeElement CompositeElement} or
16067  * {@link Ext.CompositeElementLite CompositeElementLite} object.
16068  * @param {String/Array} selector The CSS selector or an array of elements
16069  * @param {HTMLElement/String} root (optional) The root element of the query or id of the root
16070  * @return {CompositeElementLite/CompositeElement}
16071  * @member Ext
16072  * @method select
16073  */
16074 Ext.select = Ext.core.Element.select;
16075
16076 /**
16077  * @class Ext.util.DelayedTask
16078  * 
16079  * The DelayedTask class provides a convenient way to "buffer" the execution of a method,
16080  * performing setTimeout where a new timeout cancels the old timeout. When called, the
16081  * task will wait the specified time period before executing. If durng that time period,
16082  * the task is called again, the original call will be cancelled. This continues so that
16083  * the function is only called a single time for each iteration.
16084  * 
16085  * This method is especially useful for things like detecting whether a user has finished
16086  * typing in a text field. An example would be performing validation on a keypress. You can
16087  * use this class to buffer the keypress events for a certain number of milliseconds, and
16088  * perform only if they stop for that amount of time.  
16089  * 
16090  * ## Usage
16091  * 
16092  *     var task = new Ext.util.DelayedTask(function(){
16093  *         alert(Ext.getDom('myInputField').value.length);
16094  *     });
16095  *     
16096  *     // Wait 500ms before calling our function. If the user presses another key
16097  *     // during that 500ms, it will be cancelled and we'll wait another 500ms.
16098  *     Ext.get('myInputField').on('keypress', function(){
16099  *         task.{@link #delay}(500);
16100  *     });
16101  * 
16102  * Note that we are using a DelayedTask here to illustrate a point. The configuration
16103  * option `buffer` for {@link Ext.util.Observable#addListener addListener/on} will
16104  * also setup a delayed task for you to buffer events.
16105  * 
16106  * @constructor The parameters to this constructor serve as defaults and are not required.
16107  * @param {Function} fn (optional) The default function to call.
16108  * @param {Object} scope The default scope (The <code><b>this</b></code> reference) in which the
16109  * function is called. If not specified, <code>this</code> will refer to the browser window.
16110  * @param {Array} args (optional) The default Array of arguments.
16111  */
16112 Ext.util.DelayedTask = function(fn, scope, args) {
16113     var me = this,
16114         id,
16115         call = function() {
16116             clearInterval(id);
16117             id = null;
16118             fn.apply(scope, args || []);
16119         };
16120
16121     /**
16122      * Cancels any pending timeout and queues a new one
16123      * @param {Number} delay The milliseconds to delay
16124      * @param {Function} newFn (optional) Overrides function passed to constructor
16125      * @param {Object} newScope (optional) Overrides scope passed to constructor. Remember that if no scope
16126      * is specified, <code>this</code> will refer to the browser window.
16127      * @param {Array} newArgs (optional) Overrides args passed to constructor
16128      */
16129     this.delay = function(delay, newFn, newScope, newArgs) {
16130         me.cancel();
16131         fn = newFn || fn;
16132         scope = newScope || scope;
16133         args = newArgs || args;
16134         id = setInterval(call, delay);
16135     };
16136
16137     /**
16138      * Cancel the last queued timeout
16139      */
16140     this.cancel = function(){
16141         if (id) {
16142             clearInterval(id);
16143             id = null;
16144         }
16145     };
16146 };
16147 Ext.require('Ext.util.DelayedTask', function() {
16148
16149     Ext.util.Event = Ext.extend(Object, (function() {
16150         function createBuffered(handler, listener, o, scope) {
16151             listener.task = new Ext.util.DelayedTask();
16152             return function() {
16153                 listener.task.delay(o.buffer, handler, scope, Ext.Array.toArray(arguments));
16154             };
16155         }
16156
16157         function createDelayed(handler, listener, o, scope) {
16158             return function() {
16159                 var task = new Ext.util.DelayedTask();
16160                 if (!listener.tasks) {
16161                     listener.tasks = [];
16162                 }
16163                 listener.tasks.push(task);
16164                 task.delay(o.delay || 10, handler, scope, Ext.Array.toArray(arguments));
16165             };
16166         }
16167
16168         function createSingle(handler, listener, o, scope) {
16169             return function() {
16170                 listener.ev.removeListener(listener.fn, scope);
16171                 return handler.apply(scope, arguments);
16172             };
16173         }
16174
16175         return {
16176             isEvent: true,
16177
16178             constructor: function(observable, name) {
16179                 this.name = name;
16180                 this.observable = observable;
16181                 this.listeners = [];
16182             },
16183
16184             addListener: function(fn, scope, options) {
16185                 var me = this,
16186                     listener;
16187                     scope = scope || me.observable;
16188
16189                 if (!fn) {
16190                     Ext.Error.raise({
16191                         sourceClass: Ext.getClassName(this.observable),
16192                         sourceMethod: "addListener",
16193                         msg: "The specified callback function is undefined"
16194                     });
16195                 }
16196
16197                 if (!me.isListening(fn, scope)) {
16198                     listener = me.createListener(fn, scope, options);
16199                     if (me.firing) {
16200                         // if we are currently firing this event, don't disturb the listener loop
16201                         me.listeners = me.listeners.slice(0);
16202                     }
16203                     me.listeners.push(listener);
16204                 }
16205             },
16206
16207             createListener: function(fn, scope, o) {
16208                 o = o || {};
16209                 scope = scope || this.observable;
16210
16211                 var listener = {
16212                         fn: fn,
16213                         scope: scope,
16214                         o: o,
16215                         ev: this
16216                     },
16217                     handler = fn;
16218
16219                 // The order is important. The 'single' wrapper must be wrapped by the 'buffer' and 'delayed' wrapper
16220                 // because the event removal that the single listener does destroys the listener's DelayedTask(s)
16221                 if (o.single) {
16222                     handler = createSingle(handler, listener, o, scope);
16223                 }
16224                 if (o.delay) {
16225                     handler = createDelayed(handler, listener, o, scope);
16226                 }
16227                 if (o.buffer) {
16228                     handler = createBuffered(handler, listener, o, scope);
16229                 }
16230
16231                 listener.fireFn = handler;
16232                 return listener;
16233             },
16234
16235             findListener: function(fn, scope) {
16236                 var listeners = this.listeners,
16237                 i = listeners.length,
16238                 listener,
16239                 s;
16240
16241                 while (i--) {
16242                     listener = listeners[i];
16243                     if (listener) {
16244                         s = listener.scope;
16245                         if (listener.fn == fn && (s == scope || s == this.observable)) {
16246                             return i;
16247                         }
16248                     }
16249                 }
16250
16251                 return - 1;
16252             },
16253
16254             isListening: function(fn, scope) {
16255                 return this.findListener(fn, scope) !== -1;
16256             },
16257
16258             removeListener: function(fn, scope) {
16259                 var me = this,
16260                     index,
16261                     listener,
16262                     k;
16263                 index = me.findListener(fn, scope);
16264                 if (index != -1) {
16265                     listener = me.listeners[index];
16266
16267                     if (me.firing) {
16268                         me.listeners = me.listeners.slice(0);
16269                     }
16270
16271                     // cancel and remove a buffered handler that hasn't fired yet
16272                     if (listener.task) {
16273                         listener.task.cancel();
16274                         delete listener.task;
16275                     }
16276
16277                     // cancel and remove all delayed handlers that haven't fired yet
16278                     k = listener.tasks && listener.tasks.length;
16279                     if (k) {
16280                         while (k--) {
16281                             listener.tasks[k].cancel();
16282                         }
16283                         delete listener.tasks;
16284                     }
16285
16286                     // remove this listener from the listeners array
16287                     me.listeners.splice(index, 1);
16288                     return true;
16289                 }
16290
16291                 return false;
16292             },
16293
16294             // Iterate to stop any buffered/delayed events
16295             clearListeners: function() {
16296                 var listeners = this.listeners,
16297                     i = listeners.length;
16298
16299                 while (i--) {
16300                     this.removeListener(listeners[i].fn, listeners[i].scope);
16301                 }
16302             },
16303
16304             fire: function() {
16305                 var me = this,
16306                     listeners = me.listeners,
16307                     count = listeners.length,
16308                     i,
16309                     args,
16310                     listener;
16311
16312                 if (count > 0) {
16313                     me.firing = true;
16314                     for (i = 0; i < count; i++) {
16315                         listener = listeners[i];
16316                         args = arguments.length ? Array.prototype.slice.call(arguments, 0) : [];
16317                         if (listener.o) {
16318                             args.push(listener.o);
16319                         }
16320                         if (listener && listener.fireFn.apply(listener.scope || me.observable, args) === false) {
16321                             return (me.firing = false);
16322                         }
16323                     }
16324                 }
16325                 me.firing = false;
16326                 return true;
16327             }
16328         };
16329     })());
16330 });
16331
16332 /**
16333  * @class Ext.EventManager
16334  * Registers event handlers that want to receive a normalized EventObject instead of the standard browser event and provides
16335  * several useful events directly.
16336  * See {@link Ext.EventObject} for more details on normalized event objects.
16337  * @singleton
16338  */
16339 Ext.EventManager = {
16340
16341     // --------------------- onReady ---------------------
16342
16343     /**
16344      * Check if we have bound our global onReady listener
16345      * @private
16346      */
16347     hasBoundOnReady: false,
16348
16349     /**
16350      * Check if fireDocReady has been called
16351      * @private
16352      */
16353     hasFiredReady: false,
16354
16355     /**
16356      * Timer for the document ready event in old IE versions
16357      * @private
16358      */
16359     readyTimeout: null,
16360
16361     /**
16362      * Checks if we have bound an onreadystatechange event
16363      * @private
16364      */
16365     hasOnReadyStateChange: false,
16366
16367     /**
16368      * Holds references to any onReady functions
16369      * @private
16370      */
16371     readyEvent: new Ext.util.Event(),
16372
16373     /**
16374      * Check the ready state for old IE versions
16375      * @private
16376      * @return {Boolean} True if the document is ready
16377      */
16378     checkReadyState: function(){
16379         var me = Ext.EventManager;
16380
16381         if(window.attachEvent){
16382             // See here for reference: http://javascript.nwbox.com/IEContentLoaded/
16383             if (window != top) {
16384                 return false;
16385             }
16386             try{
16387                 document.documentElement.doScroll('left');
16388             }catch(e){
16389                 return false;
16390             }
16391             me.fireDocReady();
16392             return true;
16393         }
16394         if (document.readyState == 'complete') {
16395             me.fireDocReady();
16396             return true;
16397         }
16398         me.readyTimeout = setTimeout(arguments.callee, 2);
16399         return false;
16400     },
16401
16402     /**
16403      * Binds the appropriate browser event for checking if the DOM has loaded.
16404      * @private
16405      */
16406     bindReadyEvent: function(){
16407         var me = Ext.EventManager;
16408         if (me.hasBoundOnReady) {
16409             return;
16410         }
16411
16412         if (document.addEventListener) {
16413             document.addEventListener('DOMContentLoaded', me.fireDocReady, false);
16414             // fallback, load will ~always~ fire
16415             window.addEventListener('load', me.fireDocReady, false);
16416         } else {
16417             // check if the document is ready, this will also kick off the scroll checking timer
16418             if (!me.checkReadyState()) {
16419                 document.attachEvent('onreadystatechange', me.checkReadyState);
16420                 me.hasOnReadyStateChange = true;
16421             }
16422             // fallback, onload will ~always~ fire
16423             window.attachEvent('onload', me.fireDocReady, false);
16424         }
16425         me.hasBoundOnReady = true;
16426     },
16427
16428     /**
16429      * We know the document is loaded, so trigger any onReady events.
16430      * @private
16431      */
16432     fireDocReady: function(){
16433         var me = Ext.EventManager;
16434
16435         // only unbind these events once
16436         if (!me.hasFiredReady) {
16437             me.hasFiredReady = true;
16438
16439             if (document.addEventListener) {
16440                 document.removeEventListener('DOMContentLoaded', me.fireDocReady, false);
16441                 window.removeEventListener('load', me.fireDocReady, false);
16442             } else {
16443                 if (me.readyTimeout !== null) {
16444                     clearTimeout(me.readyTimeout);
16445                 }
16446                 if (me.hasOnReadyStateChange) {
16447                     document.detachEvent('onreadystatechange', me.checkReadyState);
16448                 }
16449                 window.detachEvent('onload', me.fireDocReady);
16450             }
16451             Ext.supports.init();
16452         }
16453         if (!Ext.isReady) {
16454             Ext.isReady = true;
16455             me.onWindowUnload();
16456             me.readyEvent.fire();
16457         }
16458     },
16459
16460     /**
16461      * Adds a listener to be notified when the document is ready (before onload and before images are loaded). Can be
16462      * accessed shorthanded as Ext.onReady().
16463      * @param {Function} fn The method the event invokes.
16464      * @param {Object} scope (optional) The scope (<code>this</code> reference) in which the handler function executes. Defaults to the browser window.
16465      * @param {boolean} options (optional) Options object as passed to {@link Ext.core.Element#addListener}.
16466      */
16467     onDocumentReady: function(fn, scope, options){
16468         options = options || {};
16469         var me = Ext.EventManager,
16470             readyEvent = me.readyEvent;
16471
16472         // force single to be true so our event is only ever fired once.
16473         options.single = true;
16474
16475         // Document already loaded, let's just fire it
16476         if (Ext.isReady) {
16477             readyEvent.addListener(fn, scope, options);
16478             readyEvent.fire();
16479         } else {
16480             options.delay = options.delay || 1;
16481             readyEvent.addListener(fn, scope, options);
16482             me.bindReadyEvent();
16483         }
16484     },
16485
16486
16487     // --------------------- event binding ---------------------
16488
16489     /**
16490      * Contains a list of all document mouse downs, so we can ensure they fire even when stopEvent is called.
16491      * @private
16492      */
16493     stoppedMouseDownEvent: new Ext.util.Event(),
16494
16495     /**
16496      * Options to parse for the 4th argument to addListener.
16497      * @private
16498      */
16499     propRe: /^(?:scope|delay|buffer|single|stopEvent|preventDefault|stopPropagation|normalized|args|delegate|freezeEvent)$/,
16500
16501     /**
16502      * Get the id of the element. If one has not been assigned, automatically assign it.
16503      * @param {Mixed} element The element to get the id for.
16504      * @return {String} id
16505      */
16506     getId : function(element) {
16507         var skipGarbageCollection = false,
16508             id;
16509     
16510         element = Ext.getDom(element);
16511     
16512         if (element === document || element === window) {
16513             id = element === document ? Ext.documentId : Ext.windowId;
16514         }
16515         else {
16516             id = Ext.id(element);
16517         }
16518         // skip garbage collection for special elements (window, document, iframes)
16519         if (element && (element.getElementById || element.navigator)) {
16520             skipGarbageCollection = true;
16521         }
16522     
16523         if (!Ext.cache[id]){
16524             Ext.core.Element.addToCache(new Ext.core.Element(element), id);
16525             if (skipGarbageCollection) {
16526                 Ext.cache[id].skipGarbageCollection = true;
16527             }
16528         }
16529         return id;
16530     },
16531
16532     /**
16533      * Convert a "config style" listener into a set of flat arguments so they can be passed to addListener
16534      * @private
16535      * @param {Object} element The element the event is for
16536      * @param {Object} event The event configuration
16537      * @param {Object} isRemove True if a removal should be performed, otherwise an add will be done.
16538      */
16539     prepareListenerConfig: function(element, config, isRemove){
16540         var me = this,
16541             propRe = me.propRe,
16542             key, value, args;
16543
16544         // loop over all the keys in the object
16545         for (key in config) {
16546             if (config.hasOwnProperty(key)) {
16547                 // if the key is something else then an event option
16548                 if (!propRe.test(key)) {
16549                     value = config[key];
16550                     // if the value is a function it must be something like click: function(){}, scope: this
16551                     // which means that there might be multiple event listeners with shared options
16552                     if (Ext.isFunction(value)) {
16553                         // shared options
16554                         args = [element, key, value, config.scope, config];
16555                     } else {
16556                         // if its not a function, it must be an object like click: {fn: function(){}, scope: this}
16557                         args = [element, key, value.fn, value.scope, value];
16558                     }
16559
16560                     if (isRemove === true) {
16561                         me.removeListener.apply(this, args);
16562                     } else {
16563                         me.addListener.apply(me, args);
16564                     }
16565                 }
16566             }
16567         }
16568     },
16569
16570     /**
16571      * Normalize cross browser event differences
16572      * @private
16573      * @param {Object} eventName The event name
16574      * @param {Object} fn The function to execute
16575      * @return {Object} The new event name/function
16576      */
16577     normalizeEvent: function(eventName, fn){
16578         if (/mouseenter|mouseleave/.test(eventName) && !Ext.supports.MouseEnterLeave) {
16579             if (fn) {
16580                 fn = Ext.Function.createInterceptor(fn, this.contains, this);
16581             }
16582             eventName = eventName == 'mouseenter' ? 'mouseover' : 'mouseout';
16583         } else if (eventName == 'mousewheel' && !Ext.supports.MouseWheel && !Ext.isOpera){
16584             eventName = 'DOMMouseScroll';
16585         }
16586         return {
16587             eventName: eventName,
16588             fn: fn
16589         };
16590     },
16591
16592     /**
16593      * Checks whether the event's relatedTarget is contained inside (or <b>is</b>) the element.
16594      * @private
16595      * @param {Object} event
16596      */
16597     contains: function(event){
16598         var parent = event.browserEvent.currentTarget,
16599             child = this.getRelatedTarget(event);
16600
16601         if (parent && parent.firstChild) {
16602             while (child) {
16603                 if (child === parent) {
16604                     return false;
16605                 }
16606                 child = child.parentNode;
16607                 if (child && (child.nodeType != 1)) {
16608                     child = null;
16609                 }
16610             }
16611         }
16612         return true;
16613     },
16614
16615     /**
16616     * Appends an event handler to an element.  The shorthand version {@link #on} is equivalent.  Typically you will
16617     * use {@link Ext.core.Element#addListener} directly on an Element in favor of calling this version.
16618     * @param {String/HTMLElement} el The html element or id to assign the event handler to.
16619     * @param {String} eventName The name of the event to listen for.
16620     * @param {Function} handler The handler function the event invokes. This function is passed
16621     * the following parameters:<ul>
16622     * <li>evt : EventObject<div class="sub-desc">The {@link Ext.EventObject EventObject} describing the event.</div></li>
16623     * <li>t : Element<div class="sub-desc">The {@link Ext.core.Element Element} which was the target of the event.
16624     * Note that this may be filtered by using the <tt>delegate</tt> option.</div></li>
16625     * <li>o : Object<div class="sub-desc">The options object from the addListener call.</div></li>
16626     * </ul>
16627     * @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>.
16628     * @param {Object} options (optional) An object containing handler configuration properties.
16629     * This may contain any of the following properties:<ul>
16630     * <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>
16631     * <li>delegate : String<div class="sub-desc">A simple selector to filter the target or look for a descendant of the target</div></li>
16632     * <li>stopEvent : Boolean<div class="sub-desc">True to stop the event. That is stop propagation, and prevent the default action.</div></li>
16633     * <li>preventDefault : Boolean<div class="sub-desc">True to prevent the default action</div></li>
16634     * <li>stopPropagation : Boolean<div class="sub-desc">True to prevent event propagation</div></li>
16635     * <li>normalized : Boolean<div class="sub-desc">False to pass a browser event to the handler function instead of an Ext.EventObject</div></li>
16636     * <li>delay : Number<div class="sub-desc">The number of milliseconds to delay the invocation of the handler after te event fires.</div></li>
16637     * <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>
16638     * <li>buffer : Number<div class="sub-desc">Causes the handler to be scheduled to run in an {@link Ext.util.DelayedTask} delayed
16639     * by the specified number of milliseconds. If the event fires again within that time, the original
16640     * handler is <em>not</em> invoked, but the new handler is scheduled in its place.</div></li>
16641     * <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>
16642     * </ul><br>
16643     * <p>See {@link Ext.core.Element#addListener} for examples of how to use these options.</p>
16644     */
16645     addListener: function(element, eventName, fn, scope, options){
16646         // Check if we've been passed a "config style" event.
16647         if (Ext.isObject(eventName)) {
16648             this.prepareListenerConfig(element, eventName);
16649             return;
16650         }
16651
16652         var dom = Ext.getDom(element),
16653             bind,
16654             wrap;
16655
16656         if (!dom){
16657             Ext.Error.raise({
16658                 sourceClass: 'Ext.EventManager',
16659                 sourceMethod: 'addListener',
16660                 targetElement: element,
16661                 eventName: eventName,
16662                 msg: 'Error adding "' + eventName + '\" listener for nonexistent element "' + element + '"'
16663             });
16664         }
16665         if (!fn) {
16666             Ext.Error.raise({
16667                 sourceClass: 'Ext.EventManager',
16668                 sourceMethod: 'addListener',
16669                 targetElement: element,
16670                 eventName: eventName,
16671                 msg: 'Error adding "' + eventName + '\" listener. The handler function is undefined.'
16672             });
16673         }
16674
16675         // create the wrapper function
16676         options = options || {};
16677
16678         bind = this.normalizeEvent(eventName, fn);
16679         wrap = this.createListenerWrap(dom, eventName, bind.fn, scope, options);
16680
16681
16682         if (dom.attachEvent) {
16683             dom.attachEvent('on' + bind.eventName, wrap);
16684         } else {
16685             dom.addEventListener(bind.eventName, wrap, options.capture || false);
16686         }
16687
16688         if (dom == document && eventName == 'mousedown') {
16689             this.stoppedMouseDownEvent.addListener(wrap);
16690         }
16691
16692         // add all required data into the event cache
16693         this.getEventListenerCache(dom, eventName).push({
16694             fn: fn,
16695             wrap: wrap,
16696             scope: scope
16697         });
16698     },
16699
16700     /**
16701     * Removes an event handler from an element.  The shorthand version {@link #un} is equivalent.  Typically
16702     * you will use {@link Ext.core.Element#removeListener} directly on an Element in favor of calling this version.
16703     * @param {String/HTMLElement} el The id or html element from which to remove the listener.
16704     * @param {String} eventName The name of the event.
16705     * @param {Function} fn The handler function to remove. <b>This must be a reference to the function passed into the {@link #addListener} call.</b>
16706     * @param {Object} scope If a scope (<b><code>this</code></b> reference) was specified when the listener was added,
16707     * then this must refer to the same object.
16708     */
16709     removeListener : function(element, eventName, fn, scope) {
16710         // handle our listener config object syntax
16711         if (Ext.isObject(eventName)) {
16712             this.prepareListenerConfig(element, eventName, true);
16713             return;
16714         }
16715
16716         var dom = Ext.getDom(element),
16717             cache = this.getEventListenerCache(dom, eventName),
16718             bindName = this.normalizeEvent(eventName).eventName,
16719             i = cache.length, j,
16720             listener, wrap, tasks;
16721
16722
16723         while (i--) {
16724             listener = cache[i];
16725
16726             if (listener && (!fn || listener.fn == fn) && (!scope || listener.scope === scope)) {
16727                 wrap = listener.wrap;
16728
16729                 // clear buffered calls
16730                 if (wrap.task) {
16731                     clearTimeout(wrap.task);
16732                     delete wrap.task;
16733                 }
16734
16735                 // clear delayed calls
16736                 j = wrap.tasks && wrap.tasks.length;
16737                 if (j) {
16738                     while (j--) {
16739                         clearTimeout(wrap.tasks[j]);
16740                     }
16741                     delete wrap.tasks;
16742                 }
16743
16744                 if (dom.detachEvent) {
16745                     dom.detachEvent('on' + bindName, wrap);
16746                 } else {
16747                     dom.removeEventListener(bindName, wrap, false);
16748                 }
16749
16750                 if (wrap && dom == document && eventName == 'mousedown') {
16751                     this.stoppedMouseDownEvent.removeListener(wrap);
16752                 }
16753
16754                 // remove listener from cache
16755                 cache.splice(i, 1);
16756             }
16757         }
16758     },
16759
16760     /**
16761     * Removes all event handers from an element.  Typically you will use {@link Ext.core.Element#removeAllListeners}
16762     * directly on an Element in favor of calling this version.
16763     * @param {String/HTMLElement} el The id or html element from which to remove all event handlers.
16764     */
16765     removeAll : function(element){
16766         var dom = Ext.getDom(element),
16767             cache, ev;
16768         if (!dom) {
16769             return;
16770         }
16771         cache = this.getElementEventCache(dom);
16772
16773         for (ev in cache) {
16774             if (cache.hasOwnProperty(ev)) {
16775                 this.removeListener(dom, ev);
16776             }
16777         }
16778         Ext.cache[dom.id].events = {};
16779     },
16780
16781     /**
16782      * Recursively removes all previous added listeners from an element and its children. Typically you will use {@link Ext.core.Element#purgeAllListeners}
16783      * directly on an Element in favor of calling this version.
16784      * @param {String/HTMLElement} el The id or html element from which to remove all event handlers.
16785      * @param {String} eventName (optional) The name of the event.
16786      */
16787     purgeElement : function(element, eventName) {
16788         var dom = Ext.getDom(element),
16789             i = 0, len;
16790
16791         if(eventName) {
16792             this.removeListener(dom, eventName);
16793         }
16794         else {
16795             this.removeAll(dom);
16796         }
16797
16798         if(dom && dom.childNodes) {
16799             for(len = element.childNodes.length; i < len; i++) {
16800                 this.purgeElement(element.childNodes[i], eventName);
16801             }
16802         }
16803     },
16804
16805     /**
16806      * Create the wrapper function for the event
16807      * @private
16808      * @param {HTMLElement} dom The dom element
16809      * @param {String} ename The event name
16810      * @param {Function} fn The function to execute
16811      * @param {Object} scope The scope to execute callback in
16812      * @param {Object} options The options
16813      * @return {Function} the wrapper function
16814      */
16815     createListenerWrap : function(dom, ename, fn, scope, options) {
16816         options = !Ext.isObject(options) ? {} : options;
16817
16818         var f, gen;
16819
16820         return function wrap(e, args) {
16821             // Compile the implementation upon first firing
16822             if (!gen) {
16823                 f = ['if(!Ext) {return;}'];
16824
16825                 if(options.buffer || options.delay || options.freezeEvent) {
16826                     f.push('e = new Ext.EventObjectImpl(e, ' + (options.freezeEvent ? 'true' : 'false' ) + ');');
16827                 } else {
16828                     f.push('e = Ext.EventObject.setEvent(e);');
16829                 }
16830
16831                 if (options.delegate) {
16832                     f.push('var t = e.getTarget("' + options.delegate + '", this);');
16833                     f.push('if(!t) {return;}');
16834                 } else {
16835                     f.push('var t = e.target;');
16836                 }
16837
16838                 if (options.target) {
16839                     f.push('if(e.target !== options.target) {return;}');
16840                 }
16841
16842                 if(options.stopEvent) {
16843                     f.push('e.stopEvent();');
16844                 } else {
16845                     if(options.preventDefault) {
16846                         f.push('e.preventDefault();');
16847                     }
16848                     if(options.stopPropagation) {
16849                         f.push('e.stopPropagation();');
16850                     }
16851                 }
16852
16853                 if(options.normalized === false) {
16854                     f.push('e = e.browserEvent;');
16855                 }
16856
16857                 if(options.buffer) {
16858                     f.push('(wrap.task && clearTimeout(wrap.task));');
16859                     f.push('wrap.task = setTimeout(function(){');
16860                 }
16861
16862                 if(options.delay) {
16863                     f.push('wrap.tasks = wrap.tasks || [];');
16864                     f.push('wrap.tasks.push(setTimeout(function(){');
16865                 }
16866
16867                 // finally call the actual handler fn
16868                 f.push('fn.call(scope || dom, e, t, options);');
16869
16870                 if(options.single) {
16871                     f.push('Ext.EventManager.removeListener(dom, ename, fn, scope);');
16872                 }
16873
16874                 if(options.delay) {
16875                     f.push('}, ' + options.delay + '));');
16876                 }
16877
16878                 if(options.buffer) {
16879                     f.push('}, ' + options.buffer + ');');
16880                 }
16881
16882                 gen = Ext.functionFactory('e', 'options', 'fn', 'scope', 'ename', 'dom', 'wrap', 'args', f.join('\n'));
16883             }
16884
16885             gen.call(dom, e, options, fn, scope, ename, dom, wrap, args);
16886         };
16887     },
16888
16889     /**
16890      * Get the event cache for a particular element for a particular event
16891      * @private
16892      * @param {HTMLElement} element The element
16893      * @param {Object} eventName The event name
16894      * @return {Array} The events for the element
16895      */
16896     getEventListenerCache : function(element, eventName) {
16897         var eventCache = this.getElementEventCache(element);
16898         return eventCache[eventName] || (eventCache[eventName] = []);
16899     },
16900
16901     /**
16902      * Gets the event cache for the object
16903      * @private
16904      * @param {HTMLElement} element The element
16905      * @return {Object} The event cache for the object
16906      */
16907     getElementEventCache : function(element) {
16908         var elementCache = Ext.cache[this.getId(element)];
16909         return elementCache.events || (elementCache.events = {});
16910     },
16911
16912     // --------------------- utility methods ---------------------
16913     mouseLeaveRe: /(mouseout|mouseleave)/,
16914     mouseEnterRe: /(mouseover|mouseenter)/,
16915
16916     /**
16917      * Stop the event (preventDefault and stopPropagation)
16918      * @param {Event} The event to stop
16919      */
16920     stopEvent: function(event) {
16921         this.stopPropagation(event);
16922         this.preventDefault(event);
16923     },
16924
16925     /**
16926      * Cancels bubbling of the event.
16927      * @param {Event} The event to stop bubbling.
16928      */
16929     stopPropagation: function(event) {
16930         event = event.browserEvent || event;
16931         if (event.stopPropagation) {
16932             event.stopPropagation();
16933         } else {
16934             event.cancelBubble = true;
16935         }
16936     },
16937
16938     /**
16939      * Prevents the browsers default handling of the event.
16940      * @param {Event} The event to prevent the default
16941      */
16942     preventDefault: function(event) {
16943         event = event.browserEvent || event;
16944         if (event.preventDefault) {
16945             event.preventDefault();
16946         } else {
16947             event.returnValue = false;
16948             // Some keys events require setting the keyCode to -1 to be prevented
16949             try {
16950               // all ctrl + X and F1 -> F12
16951               if (event.ctrlKey || event.keyCode > 111 && event.keyCode < 124) {
16952                   event.keyCode = -1;
16953               }
16954             } catch (e) {
16955                 // see this outdated document http://support.microsoft.com/kb/934364/en-us for more info
16956             }
16957         }
16958     },
16959
16960     /**
16961      * Gets the related target from the event.
16962      * @param {Object} event The event
16963      * @return {HTMLElement} The related target.
16964      */
16965     getRelatedTarget: function(event) {
16966         event = event.browserEvent || event;
16967         var target = event.relatedTarget;
16968         if (!target) {
16969             if (this.mouseLeaveRe.test(event.type)) {
16970                 target = event.toElement;
16971             } else if (this.mouseEnterRe.test(event.type)) {
16972                 target = event.fromElement;
16973             }
16974         }
16975         return this.resolveTextNode(target);
16976     },
16977
16978     /**
16979      * Gets the x coordinate from the event
16980      * @param {Object} event The event
16981      * @return {Number} The x coordinate
16982      */
16983     getPageX: function(event) {
16984         return this.getXY(event)[0];
16985     },
16986
16987     /**
16988      * Gets the y coordinate from the event
16989      * @param {Object} event The event
16990      * @return {Number} The y coordinate
16991      */
16992     getPageY: function(event) {
16993         return this.getXY(event)[1];
16994     },
16995
16996     /**
16997      * Gets the x & ycoordinate from the event
16998      * @param {Object} event The event
16999      * @return {Array} The x/y coordinate
17000      */
17001     getPageXY: function(event) {
17002         event = event.browserEvent || event;
17003         var x = event.pageX,
17004             y = event.pageY,
17005             doc = document.documentElement,
17006             body = document.body;
17007
17008         // pageX/pageY not available (undefined, not null), use clientX/clientY instead
17009         if (!x && x !== 0) {
17010             x = event.clientX + (doc && doc.scrollLeft || body && body.scrollLeft || 0) - (doc && doc.clientLeft || body && body.clientLeft || 0);
17011             y = event.clientY + (doc && doc.scrollTop  || body && body.scrollTop  || 0) - (doc && doc.clientTop  || body && body.clientTop  || 0);
17012         }
17013         return [x, y];
17014     },
17015
17016     /**
17017      * Gets the target of the event.
17018      * @param {Object} event The event
17019      * @return {HTMLElement} target
17020      */
17021     getTarget: function(event) {
17022         event = event.browserEvent || event;
17023         return this.resolveTextNode(event.target || event.srcElement);
17024     },
17025
17026     /**
17027      * Resolve any text nodes accounting for browser differences.
17028      * @private
17029      * @param {HTMLElement} node The node
17030      * @return {HTMLElement} The resolved node
17031      */
17032     // 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.
17033     resolveTextNode: Ext.isGecko ?
17034         function(node) {
17035             if (!node) {
17036                 return;
17037             }
17038             // work around firefox bug, https://bugzilla.mozilla.org/show_bug.cgi?id=101197
17039             var s = HTMLElement.prototype.toString.call(node);
17040             if (s == '[xpconnect wrapped native prototype]' || s == '[object XULElement]') {
17041                 return;
17042             }
17043                 return node.nodeType == 3 ? node.parentNode: node;
17044             }: function(node) {
17045                 return node && node.nodeType == 3 ? node.parentNode: node;
17046             },
17047
17048     // --------------------- custom event binding ---------------------
17049
17050     // Keep track of the current width/height
17051     curWidth: 0,
17052     curHeight: 0,
17053
17054     /**
17055      * Adds a listener to be notified when the browser window is resized and provides resize event buffering (100 milliseconds),
17056      * passes new viewport width and height to handlers.
17057      * @param {Function} fn      The handler function the window resize event invokes.
17058      * @param {Object}   scope   The scope (<code>this</code> reference) in which the handler function executes. Defaults to the browser window.
17059      * @param {boolean}  options Options object as passed to {@link Ext.core.Element#addListener}
17060      */
17061     onWindowResize: function(fn, scope, options){
17062         var resize = this.resizeEvent;
17063         if(!resize){
17064             this.resizeEvent = resize = new Ext.util.Event();
17065             this.on(window, 'resize', this.fireResize, this, {buffer: 100});
17066         }
17067         resize.addListener(fn, scope, options);
17068     },
17069
17070     /**
17071      * Fire the resize event.
17072      * @private
17073      */
17074     fireResize: function(){
17075         var me = this,
17076             w = Ext.core.Element.getViewWidth(),
17077             h = Ext.core.Element.getViewHeight();
17078
17079          //whacky problem in IE where the resize event will sometimes fire even though the w/h are the same.
17080          if(me.curHeight != h || me.curWidth != w){
17081              me.curHeight = h;
17082              me.curWidth = w;
17083              me.resizeEvent.fire(w, h);
17084          }
17085     },
17086
17087     /**
17088      * Removes the passed window resize listener.
17089      * @param {Function} fn        The method the event invokes
17090      * @param {Object}   scope    The scope of handler
17091      */
17092     removeResizeListener: function(fn, scope){
17093         if (this.resizeEvent) {
17094             this.resizeEvent.removeListener(fn, scope);
17095         }
17096     },
17097
17098     onWindowUnload: function() {
17099         var unload = this.unloadEvent;
17100         if (!unload) {
17101             this.unloadEvent = unload = new Ext.util.Event();
17102             this.addListener(window, 'unload', this.fireUnload, this);
17103         }
17104     },
17105
17106     /**
17107      * Fires the unload event for items bound with onWindowUnload
17108      * @private
17109      */
17110     fireUnload: function() {
17111         // wrap in a try catch, could have some problems during unload
17112         try {
17113             this.removeUnloadListener();
17114             // Work around FF3 remembering the last scroll position when refreshing the grid and then losing grid view
17115             if (Ext.isGecko3) {
17116                 var gridviews = Ext.ComponentQuery.query('gridview'),
17117                     i = 0,
17118                     ln = gridviews.length;
17119                 for (; i < ln; i++) {
17120                     gridviews[i].scrollToTop();
17121                 }
17122             }
17123             // Purge all elements in the cache
17124             var el,
17125                 cache = Ext.cache;
17126             for (el in cache) {
17127                 if (cache.hasOwnProperty(el)) {
17128                     Ext.EventManager.removeAll(el);
17129                 }
17130             }
17131         } catch(e) {
17132         }
17133     },
17134
17135     /**
17136      * Removes the passed window unload listener.
17137      * @param {Function} fn        The method the event invokes
17138      * @param {Object}   scope    The scope of handler
17139      */
17140     removeUnloadListener: function(){
17141         if (this.unloadEvent) {
17142             this.removeListener(window, 'unload', this.fireUnload);
17143         }
17144     },
17145
17146     /**
17147      * note 1: IE fires ONLY the keydown event on specialkey autorepeat
17148      * note 2: Safari < 3.1, Gecko (Mac/Linux) & Opera fire only the keypress event on specialkey autorepeat
17149      * (research done by @Jan Wolter at http://unixpapa.com/js/key.html)
17150      * @private
17151      */
17152     useKeyDown: Ext.isWebKit ?
17153                    parseInt(navigator.userAgent.match(/AppleWebKit\/(\d+)/)[1], 10) >= 525 :
17154                    !((Ext.isGecko && !Ext.isWindows) || Ext.isOpera),
17155
17156     /**
17157      * Indicates which event to use for getting key presses.
17158      * @return {String} The appropriate event name.
17159      */
17160     getKeyEvent: function(){
17161         return this.useKeyDown ? 'keydown' : 'keypress';
17162     }
17163 };
17164
17165 /**
17166  * Alias for {@link Ext.Loader#onReady Ext.Loader.onReady} with withDomReady set to true
17167  * @member Ext
17168  * @method onReady
17169  */
17170 Ext.onReady = function(fn, scope, options) {
17171     Ext.Loader.onReady(fn, scope, true, options);
17172 };
17173
17174 /**
17175  * Alias for {@link Ext.EventManager#onDocumentReady Ext.EventManager.onDocumentReady}
17176  * @member Ext
17177  * @method onDocumentReady
17178  */
17179 Ext.onDocumentReady = Ext.EventManager.onDocumentReady;
17180
17181 /**
17182  * Alias for {@link Ext.EventManager#addListener Ext.EventManager.addListener}
17183  * @member Ext.EventManager
17184  * @method on
17185  */
17186 Ext.EventManager.on = Ext.EventManager.addListener;
17187
17188 /**
17189  * Alias for {@link Ext.EventManager#removeListener Ext.EventManager.removeListener}
17190  * @member Ext.EventManager
17191  * @method un
17192  */
17193 Ext.EventManager.un = Ext.EventManager.removeListener;
17194
17195 (function(){
17196     var initExtCss = function() {
17197         // find the body element
17198         var bd = document.body || document.getElementsByTagName('body')[0],
17199             baseCSSPrefix = Ext.baseCSSPrefix,
17200             cls = [],
17201             htmlCls = [],
17202             html;
17203
17204         if (!bd) {
17205             return false;
17206         }
17207
17208         html = bd.parentNode;
17209
17210         //Let's keep this human readable!
17211         if (Ext.isIE) {
17212             cls.push(baseCSSPrefix + 'ie');
17213         }
17214         if (Ext.isIE6) {
17215             cls.push(baseCSSPrefix + 'ie6');
17216         }
17217         if (Ext.isIE7) {
17218             cls.push(baseCSSPrefix + 'ie7');
17219         }
17220         if (Ext.isIE8) {
17221             cls.push(baseCSSPrefix + 'ie8');
17222         }
17223         if (Ext.isIE9) {
17224             cls.push(baseCSSPrefix + 'ie9');
17225         }
17226         if (Ext.isGecko) {
17227             cls.push(baseCSSPrefix + 'gecko');
17228         }
17229         if (Ext.isGecko3) {
17230             cls.push(baseCSSPrefix + 'gecko3');
17231         }
17232         if (Ext.isGecko4) {
17233             cls.push(baseCSSPrefix + 'gecko4');
17234         }
17235         if (Ext.isOpera) {
17236             cls.push(baseCSSPrefix + 'opera');
17237         }
17238         if (Ext.isWebKit) {
17239             cls.push(baseCSSPrefix + 'webkit');
17240         }
17241         if (Ext.isSafari) {
17242             cls.push(baseCSSPrefix + 'safari');
17243         }
17244         if (Ext.isSafari2) {
17245             cls.push(baseCSSPrefix + 'safari2');
17246         }
17247         if (Ext.isSafari3) {
17248             cls.push(baseCSSPrefix + 'safari3');
17249         }
17250         if (Ext.isSafari4) {
17251             cls.push(baseCSSPrefix + 'safari4');
17252         }
17253         if (Ext.isChrome) {
17254             cls.push(baseCSSPrefix + 'chrome');
17255         }
17256         if (Ext.isMac) {
17257             cls.push(baseCSSPrefix + 'mac');
17258         }
17259         if (Ext.isLinux) {
17260             cls.push(baseCSSPrefix + 'linux');
17261         }
17262         if (!Ext.supports.CSS3BorderRadius) {
17263             cls.push(baseCSSPrefix + 'nbr');
17264         }
17265         if (!Ext.supports.CSS3LinearGradient) {
17266             cls.push(baseCSSPrefix + 'nlg');
17267         }
17268         if (!Ext.scopeResetCSS) {
17269             cls.push(baseCSSPrefix + 'reset');
17270         }
17271
17272         // add to the parent to allow for selectors x-strict x-border-box, also set the isBorderBox property correctly
17273         if (html) {
17274             if (Ext.isStrict && (Ext.isIE6 || Ext.isIE7)) {
17275                 Ext.isBorderBox = false;
17276             }
17277             else {
17278                 Ext.isBorderBox = true;
17279             }
17280
17281             htmlCls.push(baseCSSPrefix + (Ext.isBorderBox ? 'border-box' : 'strict'));
17282             if (!Ext.isStrict) {
17283                 htmlCls.push(baseCSSPrefix + 'quirks');
17284                 if (Ext.isIE && !Ext.isStrict) {
17285                     Ext.isIEQuirks = true;
17286                 }
17287             }
17288             Ext.fly(html, '_internal').addCls(htmlCls);
17289         }
17290
17291         Ext.fly(bd, '_internal').addCls(cls);
17292         return true;
17293     };
17294
17295     Ext.onReady(initExtCss);
17296 })();
17297
17298 /**
17299  * @class Ext.EventObject
17300
17301 Just as {@link Ext.core.Element} wraps around a native DOM node, Ext.EventObject
17302 wraps the browser's native event-object normalizing cross-browser differences,
17303 such as which mouse button is clicked, keys pressed, mechanisms to stop
17304 event-propagation along with a method to prevent default actions from taking place.
17305
17306 For example:
17307
17308     function handleClick(e, t){ // e is not a standard event object, it is a Ext.EventObject
17309         e.preventDefault();
17310         var target = e.getTarget(); // same as t (the target HTMLElement)
17311         ...
17312     }
17313
17314     var myDiv = {@link Ext#get Ext.get}("myDiv");  // get reference to an {@link Ext.core.Element}
17315     myDiv.on(         // 'on' is shorthand for addListener
17316         "click",      // perform an action on click of myDiv
17317         handleClick   // reference to the action handler
17318     );
17319
17320     // other methods to do the same:
17321     Ext.EventManager.on("myDiv", 'click', handleClick);
17322     Ext.EventManager.addListener("myDiv", 'click', handleClick);
17323
17324  * @singleton
17325  * @markdown
17326  */
17327 Ext.define('Ext.EventObjectImpl', {
17328     uses: ['Ext.util.Point'],
17329
17330     /** Key constant @type Number */
17331     BACKSPACE: 8,
17332     /** Key constant @type Number */
17333     TAB: 9,
17334     /** Key constant @type Number */
17335     NUM_CENTER: 12,
17336     /** Key constant @type Number */
17337     ENTER: 13,
17338     /** Key constant @type Number */
17339     RETURN: 13,
17340     /** Key constant @type Number */
17341     SHIFT: 16,
17342     /** Key constant @type Number */
17343     CTRL: 17,
17344     /** Key constant @type Number */
17345     ALT: 18,
17346     /** Key constant @type Number */
17347     PAUSE: 19,
17348     /** Key constant @type Number */
17349     CAPS_LOCK: 20,
17350     /** Key constant @type Number */
17351     ESC: 27,
17352     /** Key constant @type Number */
17353     SPACE: 32,
17354     /** Key constant @type Number */
17355     PAGE_UP: 33,
17356     /** Key constant @type Number */
17357     PAGE_DOWN: 34,
17358     /** Key constant @type Number */
17359     END: 35,
17360     /** Key constant @type Number */
17361     HOME: 36,
17362     /** Key constant @type Number */
17363     LEFT: 37,
17364     /** Key constant @type Number */
17365     UP: 38,
17366     /** Key constant @type Number */
17367     RIGHT: 39,
17368     /** Key constant @type Number */
17369     DOWN: 40,
17370     /** Key constant @type Number */
17371     PRINT_SCREEN: 44,
17372     /** Key constant @type Number */
17373     INSERT: 45,
17374     /** Key constant @type Number */
17375     DELETE: 46,
17376     /** Key constant @type Number */
17377     ZERO: 48,
17378     /** Key constant @type Number */
17379     ONE: 49,
17380     /** Key constant @type Number */
17381     TWO: 50,
17382     /** Key constant @type Number */
17383     THREE: 51,
17384     /** Key constant @type Number */
17385     FOUR: 52,
17386     /** Key constant @type Number */
17387     FIVE: 53,
17388     /** Key constant @type Number */
17389     SIX: 54,
17390     /** Key constant @type Number */
17391     SEVEN: 55,
17392     /** Key constant @type Number */
17393     EIGHT: 56,
17394     /** Key constant @type Number */
17395     NINE: 57,
17396     /** Key constant @type Number */
17397     A: 65,
17398     /** Key constant @type Number */
17399     B: 66,
17400     /** Key constant @type Number */
17401     C: 67,
17402     /** Key constant @type Number */
17403     D: 68,
17404     /** Key constant @type Number */
17405     E: 69,
17406     /** Key constant @type Number */
17407     F: 70,
17408     /** Key constant @type Number */
17409     G: 71,
17410     /** Key constant @type Number */
17411     H: 72,
17412     /** Key constant @type Number */
17413     I: 73,
17414     /** Key constant @type Number */
17415     J: 74,
17416     /** Key constant @type Number */
17417     K: 75,
17418     /** Key constant @type Number */
17419     L: 76,
17420     /** Key constant @type Number */
17421     M: 77,
17422     /** Key constant @type Number */
17423     N: 78,
17424     /** Key constant @type Number */
17425     O: 79,
17426     /** Key constant @type Number */
17427     P: 80,
17428     /** Key constant @type Number */
17429     Q: 81,
17430     /** Key constant @type Number */
17431     R: 82,
17432     /** Key constant @type Number */
17433     S: 83,
17434     /** Key constant @type Number */
17435     T: 84,
17436     /** Key constant @type Number */
17437     U: 85,
17438     /** Key constant @type Number */
17439     V: 86,
17440     /** Key constant @type Number */
17441     W: 87,
17442     /** Key constant @type Number */
17443     X: 88,
17444     /** Key constant @type Number */
17445     Y: 89,
17446     /** Key constant @type Number */
17447     Z: 90,
17448     /** Key constant @type Number */
17449     CONTEXT_MENU: 93,
17450     /** Key constant @type Number */
17451     NUM_ZERO: 96,
17452     /** Key constant @type Number */
17453     NUM_ONE: 97,
17454     /** Key constant @type Number */
17455     NUM_TWO: 98,
17456     /** Key constant @type Number */
17457     NUM_THREE: 99,
17458     /** Key constant @type Number */
17459     NUM_FOUR: 100,
17460     /** Key constant @type Number */
17461     NUM_FIVE: 101,
17462     /** Key constant @type Number */
17463     NUM_SIX: 102,
17464     /** Key constant @type Number */
17465     NUM_SEVEN: 103,
17466     /** Key constant @type Number */
17467     NUM_EIGHT: 104,
17468     /** Key constant @type Number */
17469     NUM_NINE: 105,
17470     /** Key constant @type Number */
17471     NUM_MULTIPLY: 106,
17472     /** Key constant @type Number */
17473     NUM_PLUS: 107,
17474     /** Key constant @type Number */
17475     NUM_MINUS: 109,
17476     /** Key constant @type Number */
17477     NUM_PERIOD: 110,
17478     /** Key constant @type Number */
17479     NUM_DIVISION: 111,
17480     /** Key constant @type Number */
17481     F1: 112,
17482     /** Key constant @type Number */
17483     F2: 113,
17484     /** Key constant @type Number */
17485     F3: 114,
17486     /** Key constant @type Number */
17487     F4: 115,
17488     /** Key constant @type Number */
17489     F5: 116,
17490     /** Key constant @type Number */
17491     F6: 117,
17492     /** Key constant @type Number */
17493     F7: 118,
17494     /** Key constant @type Number */
17495     F8: 119,
17496     /** Key constant @type Number */
17497     F9: 120,
17498     /** Key constant @type Number */
17499     F10: 121,
17500     /** Key constant @type Number */
17501     F11: 122,
17502     /** Key constant @type Number */
17503     F12: 123,
17504
17505     /**
17506      * Simple click regex
17507      * @private
17508      */
17509     clickRe: /(dbl)?click/,
17510     // safari keypress events for special keys return bad keycodes
17511     safariKeys: {
17512         3: 13, // enter
17513         63234: 37, // left
17514         63235: 39, // right
17515         63232: 38, // up
17516         63233: 40, // down
17517         63276: 33, // page up
17518         63277: 34, // page down
17519         63272: 46, // delete
17520         63273: 36, // home
17521         63275: 35 // end
17522     },
17523     // normalize button clicks, don't see any way to feature detect this.
17524     btnMap: Ext.isIE ? {
17525         1: 0,
17526         4: 1,
17527         2: 2
17528     } : {
17529         0: 0,
17530         1: 1,
17531         2: 2
17532     },
17533
17534     constructor: function(event, freezeEvent){
17535         if (event) {
17536             this.setEvent(event.browserEvent || event, freezeEvent);
17537         }
17538     },
17539
17540     setEvent: function(event, freezeEvent){
17541         var me = this, button, options;
17542
17543         if (event == me || (event && event.browserEvent)) { // already wrapped
17544             return event;
17545         }
17546         me.browserEvent = event;
17547         if (event) {
17548             // normalize buttons
17549             button = event.button ? me.btnMap[event.button] : (event.which ? event.which - 1 : -1);
17550             if (me.clickRe.test(event.type) && button == -1) {
17551                 button = 0;
17552             }
17553             options = {
17554                 type: event.type,
17555                 button: button,
17556                 shiftKey: event.shiftKey,
17557                 // mac metaKey behaves like ctrlKey
17558                 ctrlKey: event.ctrlKey || event.metaKey || false,
17559                 altKey: event.altKey,
17560                 // in getKey these will be normalized for the mac
17561                 keyCode: event.keyCode,
17562                 charCode: event.charCode,
17563                 // cache the targets for the delayed and or buffered events
17564                 target: Ext.EventManager.getTarget(event),
17565                 relatedTarget: Ext.EventManager.getRelatedTarget(event),
17566                 currentTarget: event.currentTarget,
17567                 xy: (freezeEvent ? me.getXY() : null)
17568             };
17569         } else {
17570             options = {
17571                 button: -1,
17572                 shiftKey: false,
17573                 ctrlKey: false,
17574                 altKey: false,
17575                 keyCode: 0,
17576                 charCode: 0,
17577                 target: null,
17578                 xy: [0, 0]
17579             };
17580         }
17581         Ext.apply(me, options);
17582         return me;
17583     },
17584
17585     /**
17586      * Stop the event (preventDefault and stopPropagation)
17587      */
17588     stopEvent: function(){
17589         this.stopPropagation();
17590         this.preventDefault();
17591     },
17592
17593     /**
17594      * Prevents the browsers default handling of the event.
17595      */
17596     preventDefault: function(){
17597         if (this.browserEvent) {
17598             Ext.EventManager.preventDefault(this.browserEvent);
17599         }
17600     },
17601
17602     /**
17603      * Cancels bubbling of the event.
17604      */
17605     stopPropagation: function(){
17606         var browserEvent = this.browserEvent;
17607
17608         if (browserEvent) {
17609             if (browserEvent.type == 'mousedown') {
17610                 Ext.EventManager.stoppedMouseDownEvent.fire(this);
17611             }
17612             Ext.EventManager.stopPropagation(browserEvent);
17613         }
17614     },
17615
17616     /**
17617      * Gets the character code for the event.
17618      * @return {Number}
17619      */
17620     getCharCode: function(){
17621         return this.charCode || this.keyCode;
17622     },
17623
17624     /**
17625      * Returns a normalized keyCode for the event.
17626      * @return {Number} The key code
17627      */
17628     getKey: function(){
17629         return this.normalizeKey(this.keyCode || this.charCode);
17630     },
17631
17632     /**
17633      * Normalize key codes across browsers
17634      * @private
17635      * @param {Number} key The key code
17636      * @return {Number} The normalized code
17637      */
17638     normalizeKey: function(key){
17639         // can't feature detect this
17640         return Ext.isWebKit ? (this.safariKeys[key] || key) : key;
17641     },
17642
17643     /**
17644      * Gets the x coordinate of the event.
17645      * @return {Number}
17646      * @deprecated 4.0 Replaced by {@link #getX}
17647      */
17648     getPageX: function(){
17649         return this.getX();
17650     },
17651
17652     /**
17653      * Gets the y coordinate of the event.
17654      * @return {Number}
17655      * @deprecated 4.0 Replaced by {@link #getY}
17656      */
17657     getPageY: function(){
17658         return this.getY();
17659     },
17660     
17661     /**
17662      * Gets the x coordinate of the event.
17663      * @return {Number}
17664      */
17665     getX: function() {
17666         return this.getXY()[0];
17667     },    
17668     
17669     /**
17670      * Gets the y coordinate of the event.
17671      * @return {Number}
17672      */
17673     getY: function() {
17674         return this.getXY()[1];
17675     },
17676         
17677     /**
17678      * Gets the page coordinates of the event.
17679      * @return {Array} The xy values like [x, y]
17680      */
17681     getXY: function() {
17682         if (!this.xy) {
17683             // same for XY
17684             this.xy = Ext.EventManager.getPageXY(this.browserEvent);
17685         }
17686         return this.xy;
17687     },
17688
17689     /**
17690      * Gets the target for the event.
17691      * @param {String} selector (optional) A simple selector to filter the target or look for an ancestor of the target
17692      * @param {Number/Mixed} maxDepth (optional) The max depth to search as a number or element (defaults to 10 || document.body)
17693      * @param {Boolean} returnEl (optional) True to return a Ext.core.Element object instead of DOM node
17694      * @return {HTMLelement}
17695      */
17696     getTarget : function(selector, maxDepth, returnEl){
17697         if (selector) {
17698             return Ext.fly(this.target).findParent(selector, maxDepth, returnEl);
17699         }
17700         return returnEl ? Ext.get(this.target) : this.target;
17701     },
17702
17703     /**
17704      * Gets the related target.
17705      * @param {String} selector (optional) A simple selector to filter the target or look for an ancestor of the target
17706      * @param {Number/Mixed} maxDepth (optional) The max depth to search as a number or element (defaults to 10 || document.body)
17707      * @param {Boolean} returnEl (optional) True to return a Ext.core.Element object instead of DOM node
17708      * @return {HTMLElement}
17709      */
17710     getRelatedTarget : function(selector, maxDepth, returnEl){
17711         if (selector) {
17712             return Ext.fly(this.relatedTarget).findParent(selector, maxDepth, returnEl);
17713         }
17714         return returnEl ? Ext.get(this.relatedTarget) : this.relatedTarget;
17715     },
17716
17717     /**
17718      * Normalizes mouse wheel delta across browsers
17719      * @return {Number} The delta
17720      */
17721     getWheelDelta : function(){
17722         var event = this.browserEvent,
17723             delta = 0;
17724
17725         if (event.wheelDelta) { /* IE/Opera. */
17726             delta = event.wheelDelta / 120;
17727         } else if (event.detail){ /* Mozilla case. */
17728             delta = -event.detail / 3;
17729         }
17730         return delta;
17731     },
17732
17733     /**
17734     * 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.
17735     * Example usage:<pre><code>
17736 // Handle click on any child of an element
17737 Ext.getBody().on('click', function(e){
17738     if(e.within('some-el')){
17739         alert('Clicked on a child of some-el!');
17740     }
17741 });
17742
17743 // Handle click directly on an element, ignoring clicks on child nodes
17744 Ext.getBody().on('click', function(e,t){
17745     if((t.id == 'some-el') && !e.within(t, true)){
17746         alert('Clicked directly on some-el!');
17747     }
17748 });
17749 </code></pre>
17750      * @param {Mixed} el The id, DOM element or Ext.core.Element to check
17751      * @param {Boolean} related (optional) true to test if the related target is within el instead of the target
17752      * @param {Boolean} allowEl {optional} true to also check if the passed element is the target or related target
17753      * @return {Boolean}
17754      */
17755     within : function(el, related, allowEl){
17756         if(el){
17757             var t = related ? this.getRelatedTarget() : this.getTarget(),
17758                 result;
17759
17760             if (t) {
17761                 result = Ext.fly(el).contains(t);
17762                 if (!result && allowEl) {
17763                     result = t == Ext.getDom(el);
17764                 }
17765                 return result;
17766             }
17767         }
17768         return false;
17769     },
17770
17771     /**
17772      * Checks if the key pressed was a "navigation" key
17773      * @return {Boolean} True if the press is a navigation keypress
17774      */
17775     isNavKeyPress : function(){
17776         var me = this,
17777             k = this.normalizeKey(me.keyCode);
17778
17779        return (k >= 33 && k <= 40) ||  // Page Up/Down, End, Home, Left, Up, Right, Down
17780        k == me.RETURN ||
17781        k == me.TAB ||
17782        k == me.ESC;
17783     },
17784
17785     /**
17786      * Checks if the key pressed was a "special" key
17787      * @return {Boolean} True if the press is a special keypress
17788      */
17789     isSpecialKey : function(){
17790         var k = this.normalizeKey(this.keyCode);
17791         return (this.type == 'keypress' && this.ctrlKey) ||
17792         this.isNavKeyPress() ||
17793         (k == this.BACKSPACE) || // Backspace
17794         (k >= 16 && k <= 20) || // Shift, Ctrl, Alt, Pause, Caps Lock
17795         (k >= 44 && k <= 46);   // Print Screen, Insert, Delete
17796     },
17797
17798     /**
17799      * Returns a point object that consists of the object coordinates.
17800      * @return {Ext.util.Point} point
17801      */
17802     getPoint : function(){
17803         var xy = this.getXY();
17804         return Ext.create('Ext.util.Point', xy[0], xy[1]);
17805     },
17806
17807    /**
17808     * Returns true if the control, meta, shift or alt key was pressed during this event.
17809     * @return {Boolean}
17810     */
17811     hasModifier : function(){
17812         return this.ctrlKey || this.altKey || this.shiftKey || this.metaKey;
17813     },
17814
17815     /**
17816      * Injects a DOM event using the data in this object and (optionally) a new target.
17817      * This is a low-level technique and not likely to be used by application code. The
17818      * currently supported event types are:
17819      * <p><b>HTMLEvents</b></p>
17820      * <ul>
17821      * <li>load</li>
17822      * <li>unload</li>
17823      * <li>select</li>
17824      * <li>change</li>
17825      * <li>submit</li>
17826      * <li>reset</li>
17827      * <li>resize</li>
17828      * <li>scroll</li>
17829      * </ul>
17830      * <p><b>MouseEvents</b></p>
17831      * <ul>
17832      * <li>click</li>
17833      * <li>dblclick</li>
17834      * <li>mousedown</li>
17835      * <li>mouseup</li>
17836      * <li>mouseover</li>
17837      * <li>mousemove</li>
17838      * <li>mouseout</li>
17839      * </ul>
17840      * <p><b>UIEvents</b></p>
17841      * <ul>
17842      * <li>focusin</li>
17843      * <li>focusout</li>
17844      * <li>activate</li>
17845      * <li>focus</li>
17846      * <li>blur</li>
17847      * </ul>
17848      * @param {Element/HTMLElement} target If specified, the target for the event. This
17849      * is likely to be used when relaying a DOM event. If not specified, {@link #getTarget}
17850      * is used to determine the target.
17851      */
17852     injectEvent: function () {
17853         var API,
17854             dispatchers = {}; // keyed by event type (e.g., 'mousedown')
17855
17856         // Good reference: http://developer.yahoo.com/yui/docs/UserAction.js.html
17857
17858         // IE9 has createEvent, but this code causes major problems with htmleditor (it
17859         // blocks all mouse events and maybe more). TODO
17860
17861         if (!Ext.isIE && document.createEvent) { // if (DOM compliant)
17862             API = {
17863                 createHtmlEvent: function (doc, type, bubbles, cancelable) {
17864                     var event = doc.createEvent('HTMLEvents');
17865
17866                     event.initEvent(type, bubbles, cancelable);
17867                     return event;
17868                 },
17869
17870                 createMouseEvent: function (doc, type, bubbles, cancelable, detail,
17871                                             clientX, clientY, ctrlKey, altKey, shiftKey, metaKey,
17872                                             button, relatedTarget) {
17873                     var event = doc.createEvent('MouseEvents'),
17874                         view = doc.defaultView || window;
17875
17876                     if (event.initMouseEvent) {
17877                         event.initMouseEvent(type, bubbles, cancelable, view, detail,
17878                                     clientX, clientY, clientX, clientY, ctrlKey, altKey,
17879                                     shiftKey, metaKey, button, relatedTarget);
17880                     } else { // old Safari
17881                         event = doc.createEvent('UIEvents');
17882                         event.initEvent(type, bubbles, cancelable);
17883                         event.view = view;
17884                         event.detail = detail;
17885                         event.screenX = clientX;
17886                         event.screenY = clientY;
17887                         event.clientX = clientX;
17888                         event.clientY = clientY;
17889                         event.ctrlKey = ctrlKey;
17890                         event.altKey = altKey;
17891                         event.metaKey = metaKey;
17892                         event.shiftKey = shiftKey;
17893                         event.button = button;
17894                         event.relatedTarget = relatedTarget;
17895                     }
17896
17897                     return event;
17898                 },
17899
17900                 createUIEvent: function (doc, type, bubbles, cancelable, detail) {
17901                     var event = doc.createEvent('UIEvents'),
17902                         view = doc.defaultView || window;
17903
17904                     event.initUIEvent(type, bubbles, cancelable, view, detail);
17905                     return event;
17906                 },
17907
17908                 fireEvent: function (target, type, event) {
17909                     target.dispatchEvent(event);
17910                 },
17911
17912                 fixTarget: function (target) {
17913                     // Safari3 doesn't have window.dispatchEvent()
17914                     if (target == window && !target.dispatchEvent) {
17915                         return document;
17916                     }
17917
17918                     return target;
17919                 }
17920             }
17921         } else if (document.createEventObject) { // else if (IE)
17922             var crazyIEButtons = { 0: 1, 1: 4, 2: 2 };
17923
17924             API = {
17925                 createHtmlEvent: function (doc, type, bubbles, cancelable) {
17926                     var event = doc.createEventObject();
17927                     event.bubbles = bubbles;
17928                     event.cancelable = cancelable;
17929                     return event;
17930                 },
17931
17932                 createMouseEvent: function (doc, type, bubbles, cancelable, detail,
17933                                             clientX, clientY, ctrlKey, altKey, shiftKey, metaKey,
17934                                             button, relatedTarget) {
17935                     var event = doc.createEventObject();
17936                     event.bubbles = bubbles;
17937                     event.cancelable = cancelable;
17938                     event.detail = detail;
17939                     event.screenX = clientX;
17940                     event.screenY = clientY;
17941                     event.clientX = clientX;
17942                     event.clientY = clientY;
17943                     event.ctrlKey = ctrlKey;
17944                     event.altKey = altKey;
17945                     event.shiftKey = shiftKey;
17946                     event.metaKey = metaKey;
17947                     event.button = crazyIEButtons[button] || button;
17948                     event.relatedTarget = relatedTarget; // cannot assign to/fromElement
17949                     return event;
17950                 },
17951
17952                 createUIEvent: function (doc, type, bubbles, cancelable, detail) {
17953                     var event = doc.createEventObject();
17954                     event.bubbles = bubbles;
17955                     event.cancelable = cancelable;
17956                     return event;
17957                 },
17958
17959                 fireEvent: function (target, type, event) {
17960                     target.fireEvent('on' + type, event);
17961                 },
17962
17963                 fixTarget: function (target) {
17964                     if (target == document) {
17965                         // IE6,IE7 thinks window==document and doesn't have window.fireEvent()
17966                         // IE6,IE7 cannot properly call document.fireEvent()
17967                         return document.documentElement;
17968                     }
17969
17970                     return target;
17971                 }
17972             };
17973         }
17974
17975         //----------------
17976         // HTMLEvents
17977
17978         Ext.Object.each({
17979                 load:   [false, false],
17980                 unload: [false, false],
17981                 select: [true, false],
17982                 change: [true, false],
17983                 submit: [true, true],
17984                 reset:  [true, false],
17985                 resize: [true, false],
17986                 scroll: [true, false]
17987             },
17988             function (name, value) {
17989                 var bubbles = value[0], cancelable = value[1];
17990                 dispatchers[name] = function (targetEl, srcEvent) {
17991                     var e = API.createHtmlEvent(name, bubbles, cancelable);
17992                     API.fireEvent(targetEl, name, e);
17993                 };
17994             });
17995
17996         //----------------
17997         // MouseEvents
17998
17999         function createMouseEventDispatcher (type, detail) {
18000             var cancelable = (type != 'mousemove');
18001             return function (targetEl, srcEvent) {
18002                 var xy = srcEvent.getXY(),
18003                     e = API.createMouseEvent(targetEl.ownerDocument, type, true, cancelable,
18004                                 detail, xy[0], xy[1], srcEvent.ctrlKey, srcEvent.altKey,
18005                                 srcEvent.shiftKey, srcEvent.metaKey, srcEvent.button,
18006                                 srcEvent.relatedTarget);
18007                 API.fireEvent(targetEl, type, e);
18008             };
18009         }
18010
18011         Ext.each(['click', 'dblclick', 'mousedown', 'mouseup', 'mouseover', 'mousemove', 'mouseout'],
18012             function (eventName) {
18013                 dispatchers[eventName] = createMouseEventDispatcher(eventName, 1);
18014             });
18015
18016         //----------------
18017         // UIEvents
18018
18019         Ext.Object.each({
18020                 focusin:  [true, false],
18021                 focusout: [true, false],
18022                 activate: [true, true],
18023                 focus:    [false, false],
18024                 blur:     [false, false]
18025             },
18026             function (name, value) {
18027                 var bubbles = value[0], cancelable = value[1];
18028                 dispatchers[name] = function (targetEl, srcEvent) {
18029                     var e = API.createUIEvent(targetEl.ownerDocument, name, bubbles, cancelable, 1);
18030                     API.fireEvent(targetEl, name, e);
18031                 };
18032             });
18033
18034         //---------
18035         if (!API) {
18036             // not even sure what ancient browsers fall into this category...
18037
18038             dispatchers = {}; // never mind all those we just built :P
18039
18040             API = {
18041                 fixTarget: function (t) {
18042                     return t;
18043                 }
18044             };
18045         }
18046
18047         function cannotInject (target, srcEvent) {
18048             // TODO log something
18049         }
18050
18051         return function (target) {
18052             var me = this,
18053                 dispatcher = dispatchers[me.type] || cannotInject,
18054                 t = target ? (target.dom || target) : me.getTarget();
18055
18056             t = API.fixTarget(t);
18057             dispatcher(t, me);
18058         };
18059     }() // call to produce method
18060
18061 }, function() {
18062
18063 Ext.EventObject = new Ext.EventObjectImpl();
18064
18065 });
18066
18067
18068 /**
18069  * @class Ext.core.Element
18070  */
18071 (function(){
18072     var doc = document,
18073         activeElement = null,
18074         isCSS1 = doc.compatMode == "CSS1Compat",
18075         ELEMENT = Ext.core.Element,
18076         fly = function(el){
18077             if (!_fly) {
18078                 _fly = new Ext.core.Element.Flyweight();
18079             }
18080             _fly.dom = el;
18081             return _fly;
18082         }, _fly;
18083
18084     // If the browser does not support document.activeElement we need some assistance.
18085     // This covers old Safari 3.2 (4.0 added activeElement along with just about all
18086     // other browsers). We need this support to handle issues with old Safari.
18087     if (!('activeElement' in doc) && doc.addEventListener) {
18088         doc.addEventListener('focus',
18089             function (ev) {
18090                 if (ev && ev.target) {
18091                     activeElement = (ev.target == doc) ? null : ev.target;
18092                 }
18093             }, true);
18094     }
18095
18096     /*
18097      * Helper function to create the function that will restore the selection.
18098      */
18099     function makeSelectionRestoreFn (activeEl, start, end) {
18100         return function () {
18101             activeEl.selectionStart = start;
18102             activeEl.selectionEnd = end;
18103         };
18104     }
18105
18106     Ext.apply(ELEMENT, {
18107         isAncestor : function(p, c) {
18108             var ret = false;
18109
18110             p = Ext.getDom(p);
18111             c = Ext.getDom(c);
18112             if (p && c) {
18113                 if (p.contains) {
18114                     return p.contains(c);
18115                 } else if (p.compareDocumentPosition) {
18116                     return !!(p.compareDocumentPosition(c) & 16);
18117                 } else {
18118                     while ((c = c.parentNode)) {
18119                         ret = c == p || ret;
18120                     }
18121                 }
18122             }
18123             return ret;
18124         },
18125
18126         /**
18127          * Returns the active element in the DOM. If the browser supports activeElement
18128          * on the document, this is returned. If not, the focus is tracked and the active
18129          * element is maintained internally.
18130          * @return {HTMLElement} The active (focused) element in the document.
18131          */
18132         getActiveElement: function () {
18133             return doc.activeElement || activeElement;
18134         },
18135
18136         /**
18137          * Creates a function to call to clean up problems with the work-around for the
18138          * WebKit RightMargin bug. The work-around is to add "display: 'inline-block'" to
18139          * the element before calling getComputedStyle and then to restore its original
18140          * display value. The problem with this is that it corrupts the selection of an
18141          * INPUT or TEXTAREA element (as in the "I-beam" goes away but ths focus remains).
18142          * To cleanup after this, we need to capture the selection of any such element and
18143          * then restore it after we have restored the display style.
18144          *
18145          * @param target {Element} The top-most element being adjusted.
18146          * @private
18147          */
18148         getRightMarginFixCleaner: function (target) {
18149             var supports = Ext.supports,
18150                 hasInputBug = supports.DisplayChangeInputSelectionBug,
18151                 hasTextAreaBug = supports.DisplayChangeTextAreaSelectionBug;
18152
18153             if (hasInputBug || hasTextAreaBug) {
18154                 var activeEl = doc.activeElement || activeElement, // save a call
18155                     tag = activeEl && activeEl.tagName,
18156                     start,
18157                     end;
18158
18159                 if ((hasTextAreaBug && tag == 'TEXTAREA') ||
18160                     (hasInputBug && tag == 'INPUT' && activeEl.type == 'text')) {
18161                     if (ELEMENT.isAncestor(target, activeEl)) {
18162                         start = activeEl.selectionStart;
18163                         end = activeEl.selectionEnd;
18164
18165                         if (Ext.isNumber(start) && Ext.isNumber(end)) { // to be safe...
18166                             // We don't create the raw closure here inline because that
18167                             // will be costly even if we don't want to return it (nested
18168                             // function decls and exprs are often instantiated on entry
18169                             // regardless of whether execution ever reaches them):
18170                             return makeSelectionRestoreFn(activeEl, start, end);
18171                         }
18172                     }
18173                 }
18174             }
18175
18176             return Ext.emptyFn; // avoid special cases, just return a nop
18177         },
18178
18179         getViewWidth : function(full) {
18180             return full ? ELEMENT.getDocumentWidth() : ELEMENT.getViewportWidth();
18181         },
18182
18183         getViewHeight : function(full) {
18184             return full ? ELEMENT.getDocumentHeight() : ELEMENT.getViewportHeight();
18185         },
18186
18187         getDocumentHeight: function() {
18188             return Math.max(!isCSS1 ? doc.body.scrollHeight : doc.documentElement.scrollHeight, ELEMENT.getViewportHeight());
18189         },
18190
18191         getDocumentWidth: function() {
18192             return Math.max(!isCSS1 ? doc.body.scrollWidth : doc.documentElement.scrollWidth, ELEMENT.getViewportWidth());
18193         },
18194
18195         getViewportHeight: function(){
18196             return Ext.isIE ?
18197                    (Ext.isStrict ? doc.documentElement.clientHeight : doc.body.clientHeight) :
18198                    self.innerHeight;
18199         },
18200
18201         getViewportWidth : function() {
18202             return (!Ext.isStrict && !Ext.isOpera) ? doc.body.clientWidth :
18203                    Ext.isIE ? doc.documentElement.clientWidth : self.innerWidth;
18204         },
18205
18206         getY : function(el) {
18207             return ELEMENT.getXY(el)[1];
18208         },
18209
18210         getX : function(el) {
18211             return ELEMENT.getXY(el)[0];
18212         },
18213
18214         getXY : function(el) {
18215             var p,
18216                 pe,
18217                 b,
18218                 bt,
18219                 bl,
18220                 dbd,
18221                 x = 0,
18222                 y = 0,
18223                 scroll,
18224                 hasAbsolute,
18225                 bd = (doc.body || doc.documentElement),
18226                 ret = [0,0];
18227
18228             el = Ext.getDom(el);
18229
18230             if(el != bd){
18231                 hasAbsolute = fly(el).isStyle("position", "absolute");
18232
18233                 if (el.getBoundingClientRect) {
18234                     b = el.getBoundingClientRect();
18235                     scroll = fly(document).getScroll();
18236                     ret = [Math.round(b.left + scroll.left), Math.round(b.top + scroll.top)];
18237                 } else {
18238                     p = el;
18239
18240                     while (p) {
18241                         pe = fly(p);
18242                         x += p.offsetLeft;
18243                         y += p.offsetTop;
18244
18245                         hasAbsolute = hasAbsolute || pe.isStyle("position", "absolute");
18246
18247                         if (Ext.isGecko) {
18248                             y += bt = parseInt(pe.getStyle("borderTopWidth"), 10) || 0;
18249                             x += bl = parseInt(pe.getStyle("borderLeftWidth"), 10) || 0;
18250
18251                             if (p != el && !pe.isStyle('overflow','visible')) {
18252                                 x += bl;
18253                                 y += bt;
18254                             }
18255                         }
18256                         p = p.offsetParent;
18257                     }
18258
18259                     if (Ext.isSafari && hasAbsolute) {
18260                         x -= bd.offsetLeft;
18261                         y -= bd.offsetTop;
18262                     }
18263
18264                     if (Ext.isGecko && !hasAbsolute) {
18265                         dbd = fly(bd);
18266                         x += parseInt(dbd.getStyle("borderLeftWidth"), 10) || 0;
18267                         y += parseInt(dbd.getStyle("borderTopWidth"), 10) || 0;
18268                     }
18269
18270                     p = el.parentNode;
18271                     while (p && p != bd) {
18272                         if (!Ext.isOpera || (p.tagName != 'TR' && !fly(p).isStyle("display", "inline"))) {
18273                             x -= p.scrollLeft;
18274                             y -= p.scrollTop;
18275                         }
18276                         p = p.parentNode;
18277                     }
18278                     ret = [x,y];
18279                 }
18280             }
18281             return ret;
18282         },
18283
18284         setXY : function(el, xy) {
18285             (el = Ext.fly(el, '_setXY')).position();
18286
18287             var pts = el.translatePoints(xy),
18288                 style = el.dom.style,
18289                 pos;
18290
18291             for (pos in pts) {
18292                 if (!isNaN(pts[pos])) {
18293                     style[pos] = pts[pos] + "px";
18294                 }
18295             }
18296         },
18297
18298         setX : function(el, x) {
18299             ELEMENT.setXY(el, [x, false]);
18300         },
18301
18302         setY : function(el, y) {
18303             ELEMENT.setXY(el, [false, y]);
18304         },
18305
18306         /**
18307          * Serializes a DOM form into a url encoded string
18308          * @param {Object} form The form
18309          * @return {String} The url encoded form
18310          */
18311         serializeForm: function(form) {
18312             var fElements = form.elements || (document.forms[form] || Ext.getDom(form)).elements,
18313                 hasSubmit = false,
18314                 encoder = encodeURIComponent,
18315                 name,
18316                 data = '',
18317                 type,
18318                 hasValue;
18319
18320             Ext.each(fElements, function(element){
18321                 name = element.name;
18322                 type = element.type;
18323
18324                 if (!element.disabled && name) {
18325                     if (/select-(one|multiple)/i.test(type)) {
18326                         Ext.each(element.options, function(opt){
18327                             if (opt.selected) {
18328                                 hasValue = opt.hasAttribute ? opt.hasAttribute('value') : opt.getAttributeNode('value').specified;
18329                                 data += Ext.String.format("{0}={1}&", encoder(name), encoder(hasValue ? opt.value : opt.text));
18330                             }
18331                         });
18332                     } else if (!(/file|undefined|reset|button/i.test(type))) {
18333                         if (!(/radio|checkbox/i.test(type) && !element.checked) && !(type == 'submit' && hasSubmit)) {
18334                             data += encoder(name) + '=' + encoder(element.value) + '&';
18335                             hasSubmit = /submit/i.test(type);
18336                         }
18337                     }
18338                 }
18339             });
18340             return data.substr(0, data.length - 1);
18341         }
18342     });
18343 })();
18344
18345 /**
18346  * @class Ext.core.Element
18347  */
18348
18349 Ext.core.Element.addMethods({
18350
18351     /**
18352      * Monitors this Element for the mouse leaving. Calls the function after the specified delay only if
18353      * the mouse was not moved back into the Element within the delay. If the mouse <i>was</i> moved
18354      * back in, the function is not called.
18355      * @param {Number} delay The delay <b>in milliseconds</b> to wait for possible mouse re-entry before calling the handler function.
18356      * @param {Function} handler The function to call if the mouse remains outside of this Element for the specified time.
18357      * @param {Object} scope The scope (<code>this</code> reference) in which the handler function executes. Defaults to this Element.
18358      * @return {Object} The listeners object which was added to this element so that monitoring can be stopped. Example usage:</pre><code>
18359 // Hide the menu if the mouse moves out for 250ms or more
18360 this.mouseLeaveMonitor = this.menuEl.monitorMouseLeave(250, this.hideMenu, this);
18361
18362 ...
18363 // Remove mouseleave monitor on menu destroy
18364 this.menuEl.un(this.mouseLeaveMonitor);
18365 </code></pre>
18366      */
18367     monitorMouseLeave: function(delay, handler, scope) {
18368         var me = this,
18369             timer,
18370             listeners = {
18371                 mouseleave: function(e) {
18372                     timer = setTimeout(Ext.Function.bind(handler, scope||me, [e]), delay);
18373                 },
18374                 mouseenter: function() {
18375                     clearTimeout(timer);
18376                 },
18377                 freezeEvent: true
18378             };
18379
18380         me.on(listeners);
18381         return listeners;
18382     },
18383
18384     /**
18385      * Stops the specified event(s) from bubbling and optionally prevents the default action
18386      * @param {String/Array} eventName an event / array of events to stop from bubbling
18387      * @param {Boolean} preventDefault (optional) true to prevent the default action too
18388      * @return {Ext.core.Element} this
18389      */
18390     swallowEvent : function(eventName, preventDefault) {
18391         var me = this;
18392         function fn(e) {
18393             e.stopPropagation();
18394             if (preventDefault) {
18395                 e.preventDefault();
18396             }
18397         }
18398         
18399         if (Ext.isArray(eventName)) {
18400             Ext.each(eventName, function(e) {
18401                  me.on(e, fn);
18402             });
18403             return me;
18404         }
18405         me.on(eventName, fn);
18406         return me;
18407     },
18408
18409     /**
18410      * Create an event handler on this element such that when the event fires and is handled by this element,
18411      * it will be relayed to another object (i.e., fired again as if it originated from that object instead).
18412      * @param {String} eventName The type of event to relay
18413      * @param {Object} object Any object that extends {@link Ext.util.Observable} that will provide the context
18414      * for firing the relayed event
18415      */
18416     relayEvent : function(eventName, observable) {
18417         this.on(eventName, function(e) {
18418             observable.fireEvent(eventName, e);
18419         });
18420     },
18421
18422     /**
18423      * Removes Empty, or whitespace filled text nodes. Combines adjacent text nodes.
18424      * @param {Boolean} forceReclean (optional) By default the element
18425      * keeps track if it has been cleaned already so
18426      * you can call this over and over. However, if you update the element and
18427      * need to force a reclean, you can pass true.
18428      */
18429     clean : function(forceReclean) {
18430         var me  = this,
18431             dom = me.dom,
18432             n   = dom.firstChild,
18433             nx,
18434             ni  = -1;
18435
18436         if (Ext.core.Element.data(dom, 'isCleaned') && forceReclean !== true) {
18437             return me;
18438         }
18439
18440         while (n) {
18441             nx = n.nextSibling;
18442             if (n.nodeType == 3) {
18443                 // Remove empty/whitespace text nodes
18444                 if (!(/\S/.test(n.nodeValue))) {
18445                     dom.removeChild(n);
18446                 // Combine adjacent text nodes
18447                 } else if (nx && nx.nodeType == 3) {
18448                     n.appendData(Ext.String.trim(nx.data));
18449                     dom.removeChild(nx);
18450                     nx = n.nextSibling;
18451                     n.nodeIndex = ++ni;
18452                 }
18453             } else {
18454                 // Recursively clean
18455                 Ext.fly(n).clean();
18456                 n.nodeIndex = ++ni;
18457             }
18458             n = nx;
18459         }
18460
18461         Ext.core.Element.data(dom, 'isCleaned', true);
18462         return me;
18463     },
18464
18465     /**
18466      * Direct access to the Ext.ElementLoader {@link Ext.ElementLoader#load} method. The method takes the same object
18467      * parameter as {@link Ext.ElementLoader#load}
18468      * @return {Ext.core.Element} this
18469      */
18470     load : function(options) {
18471         this.getLoader().load(options);
18472         return this;
18473     },
18474
18475     /**
18476     * Gets this element's {@link Ext.ElementLoader ElementLoader}
18477     * @return {Ext.ElementLoader} The loader
18478     */
18479     getLoader : function() {
18480         var dom = this.dom,
18481             data = Ext.core.Element.data,
18482             loader = data(dom, 'loader');
18483             
18484         if (!loader) {
18485             loader = Ext.create('Ext.ElementLoader', {
18486                 target: this
18487             });
18488             data(dom, 'loader', loader);
18489         }
18490         return loader;
18491     },
18492
18493     /**
18494     * Update the innerHTML of this element, optionally searching for and processing scripts
18495     * @param {String} html The new HTML
18496     * @param {Boolean} loadScripts (optional) True to look for and process scripts (defaults to false)
18497     * @param {Function} callback (optional) For async script loading you can be notified when the update completes
18498     * @return {Ext.core.Element} this
18499      */
18500     update : function(html, loadScripts, callback) {
18501         var me = this,
18502             id,
18503             dom,
18504             interval;
18505             
18506         if (!me.dom) {
18507             return me;
18508         }
18509         html = html || '';
18510         dom = me.dom;
18511
18512         if (loadScripts !== true) {
18513             dom.innerHTML = html;
18514             Ext.callback(callback, me);
18515             return me;
18516         }
18517
18518         id  = Ext.id();
18519         html += '<span id="' + id + '"></span>';
18520
18521         interval = setInterval(function(){
18522             if (!document.getElementById(id)) {
18523                 return false;    
18524             }
18525             clearInterval(interval);
18526             var DOC    = document,
18527                 hd     = DOC.getElementsByTagName("head")[0],
18528                 re     = /(?:<script([^>]*)?>)((\n|\r|.)*?)(?:<\/script>)/ig,
18529                 srcRe  = /\ssrc=([\'\"])(.*?)\1/i,
18530                 typeRe = /\stype=([\'\"])(.*?)\1/i,
18531                 match,
18532                 attrs,
18533                 srcMatch,
18534                 typeMatch,
18535                 el,
18536                 s;
18537
18538             while ((match = re.exec(html))) {
18539                 attrs = match[1];
18540                 srcMatch = attrs ? attrs.match(srcRe) : false;
18541                 if (srcMatch && srcMatch[2]) {
18542                    s = DOC.createElement("script");
18543                    s.src = srcMatch[2];
18544                    typeMatch = attrs.match(typeRe);
18545                    if (typeMatch && typeMatch[2]) {
18546                        s.type = typeMatch[2];
18547                    }
18548                    hd.appendChild(s);
18549                 } else if (match[2] && match[2].length > 0) {
18550                     if (window.execScript) {
18551                        window.execScript(match[2]);
18552                     } else {
18553                        window.eval(match[2]);
18554                     }
18555                 }
18556             }
18557             
18558             el = DOC.getElementById(id);
18559             if (el) {
18560                 Ext.removeNode(el);
18561             }
18562             Ext.callback(callback, me);
18563         }, 20);
18564         dom.innerHTML = html.replace(/(?:<script.*?>)((\n|\r|.)*?)(?:<\/script>)/ig, '');
18565         return me;
18566     },
18567
18568     // inherit docs, overridden so we can add removeAnchor
18569     removeAllListeners : function() {
18570         this.removeAnchor();
18571         Ext.EventManager.removeAll(this.dom);
18572         return this;
18573     },
18574
18575     /**
18576      * Creates a proxy element of this element
18577      * @param {String/Object} config The class name of the proxy element or a DomHelper config object
18578      * @param {String/HTMLElement} renderTo (optional) The element or element id to render the proxy to (defaults to document.body)
18579      * @param {Boolean} matchBox (optional) True to align and size the proxy to this element now (defaults to false)
18580      * @return {Ext.core.Element} The new proxy element
18581      */
18582     createProxy : function(config, renderTo, matchBox) {
18583         config = (typeof config == 'object') ? config : {tag : "div", cls: config};
18584
18585         var me = this,
18586             proxy = renderTo ? Ext.core.DomHelper.append(renderTo, config, true) :
18587                                Ext.core.DomHelper.insertBefore(me.dom, config, true);
18588
18589         proxy.setVisibilityMode(Ext.core.Element.DISPLAY);
18590         proxy.hide();
18591         if (matchBox && me.setBox && me.getBox) { // check to make sure Element.position.js is loaded
18592            proxy.setBox(me.getBox());
18593         }
18594         return proxy;
18595     }
18596 });
18597 Ext.core.Element.prototype.clearListeners = Ext.core.Element.prototype.removeAllListeners;
18598
18599 /**
18600  * @class Ext.core.Element
18601  */
18602 Ext.core.Element.addMethods({
18603     /**
18604      * Gets the x,y coordinates specified by the anchor position on the element.
18605      * @param {String} anchor (optional) The specified anchor position (defaults to "c").  See {@link #alignTo}
18606      * for details on supported anchor positions.
18607      * @param {Boolean} local (optional) True to get the local (element top/left-relative) anchor position instead
18608      * of page coordinates
18609      * @param {Object} size (optional) An object containing the size to use for calculating anchor position
18610      * {width: (target width), height: (target height)} (defaults to the element's current size)
18611      * @return {Array} [x, y] An array containing the element's x and y coordinates
18612      */
18613     getAnchorXY : function(anchor, local, s){
18614         //Passing a different size is useful for pre-calculating anchors,
18615         //especially for anchored animations that change the el size.
18616         anchor = (anchor || "tl").toLowerCase();
18617         s = s || {};
18618
18619         var me = this,
18620             vp = me.dom == document.body || me.dom == document,
18621             w = s.width || vp ? Ext.core.Element.getViewWidth() : me.getWidth(),
18622             h = s.height || vp ? Ext.core.Element.getViewHeight() : me.getHeight(),
18623             xy,
18624             r = Math.round,
18625             o = me.getXY(),
18626             scroll = me.getScroll(),
18627             extraX = vp ? scroll.left : !local ? o[0] : 0,
18628             extraY = vp ? scroll.top : !local ? o[1] : 0,
18629             hash = {
18630                 c  : [r(w * 0.5), r(h * 0.5)],
18631                 t  : [r(w * 0.5), 0],
18632                 l  : [0, r(h * 0.5)],
18633                 r  : [w, r(h * 0.5)],
18634                 b  : [r(w * 0.5), h],
18635                 tl : [0, 0],
18636                 bl : [0, h],
18637                 br : [w, h],
18638                 tr : [w, 0]
18639             };
18640
18641         xy = hash[anchor];
18642         return [xy[0] + extraX, xy[1] + extraY];
18643     },
18644
18645     /**
18646      * Anchors an element to another element and realigns it when the window is resized.
18647      * @param {Mixed} element The element to align to.
18648      * @param {String} position The position to align to.
18649      * @param {Array} offsets (optional) Offset the positioning by [x, y]
18650      * @param {Boolean/Object} animate (optional) True for the default animation or a standard Element animation config object
18651      * @param {Boolean/Number} monitorScroll (optional) True to monitor body scroll and reposition. If this parameter
18652      * is a number, it is used as the buffer delay (defaults to 50ms).
18653      * @param {Function} callback The function to call after the animation finishes
18654      * @return {Ext.core.Element} this
18655      */
18656     anchorTo : function(el, alignment, offsets, animate, monitorScroll, callback){
18657         var me = this,
18658             dom = me.dom,
18659             scroll = !Ext.isEmpty(monitorScroll),
18660             action = function(){
18661                 Ext.fly(dom).alignTo(el, alignment, offsets, animate);
18662                 Ext.callback(callback, Ext.fly(dom));
18663             },
18664             anchor = this.getAnchor();
18665
18666         // previous listener anchor, remove it
18667         this.removeAnchor();
18668         Ext.apply(anchor, {
18669             fn: action,
18670             scroll: scroll
18671         });
18672
18673         Ext.EventManager.onWindowResize(action, null);
18674
18675         if(scroll){
18676             Ext.EventManager.on(window, 'scroll', action, null,
18677                 {buffer: !isNaN(monitorScroll) ? monitorScroll : 50});
18678         }
18679         action.call(me); // align immediately
18680         return me;
18681     },
18682
18683     /**
18684      * Remove any anchor to this element. See {@link #anchorTo}.
18685      * @return {Ext.core.Element} this
18686      */
18687     removeAnchor : function(){
18688         var me = this,
18689             anchor = this.getAnchor();
18690
18691         if(anchor && anchor.fn){
18692             Ext.EventManager.removeResizeListener(anchor.fn);
18693             if(anchor.scroll){
18694                 Ext.EventManager.un(window, 'scroll', anchor.fn);
18695             }
18696             delete anchor.fn;
18697         }
18698         return me;
18699     },
18700
18701     // private
18702     getAnchor : function(){
18703         var data = Ext.core.Element.data,
18704             dom = this.dom;
18705             if (!dom) {
18706                 return;
18707             }
18708             var anchor = data(dom, '_anchor');
18709
18710         if(!anchor){
18711             anchor = data(dom, '_anchor', {});
18712         }
18713         return anchor;
18714     },
18715
18716     getAlignVector: function(el, spec, offset) {
18717         var me = this,
18718             side = {t:"top", l:"left", r:"right", b: "bottom"},
18719             thisRegion = me.getRegion(),
18720             elRegion;
18721
18722         el = Ext.get(el);
18723         if(!el || !el.dom){
18724             Ext.Error.raise({
18725                 sourceClass: 'Ext.core.Element',
18726                 sourceMethod: 'getAlignVector',
18727                 msg: 'Attempted to align an element that doesn\'t exist'
18728             });
18729         }
18730
18731         elRegion = el.getRegion();
18732     },
18733
18734     /**
18735      * Gets the x,y coordinates to align this element with another element. See {@link #alignTo} for more info on the
18736      * supported position values.
18737      * @param {Mixed} element The element to align to.
18738      * @param {String} position (optional, defaults to "tl-bl?") The position to align to.
18739      * @param {Array} offsets (optional) Offset the positioning by [x, y]
18740      * @return {Array} [x, y]
18741      */
18742     getAlignToXY : function(el, p, o){
18743         el = Ext.get(el);
18744
18745         if(!el || !el.dom){
18746             Ext.Error.raise({
18747                 sourceClass: 'Ext.core.Element',
18748                 sourceMethod: 'getAlignToXY',
18749                 msg: 'Attempted to align an element that doesn\'t exist'
18750             });
18751         }
18752
18753         o = o || [0,0];
18754         p = (!p || p == "?" ? "tl-bl?" : (!(/-/).test(p) && p !== "" ? "tl-" + p : p || "tl-bl")).toLowerCase();
18755
18756         var me = this,
18757             d = me.dom,
18758             a1,
18759             a2,
18760             x,
18761             y,
18762             //constrain the aligned el to viewport if necessary
18763             w,
18764             h,
18765             r,
18766             dw = Ext.core.Element.getViewWidth() -10, // 10px of margin for ie
18767             dh = Ext.core.Element.getViewHeight()-10, // 10px of margin for ie
18768             p1y,
18769             p1x,
18770             p2y,
18771             p2x,
18772             swapY,
18773             swapX,
18774             doc = document,
18775             docElement = doc.documentElement,
18776             docBody = doc.body,
18777             scrollX = (docElement.scrollLeft || docBody.scrollLeft || 0)+5,
18778             scrollY = (docElement.scrollTop || docBody.scrollTop || 0)+5,
18779             c = false, //constrain to viewport
18780             p1 = "",
18781             p2 = "",
18782             m = p.match(/^([a-z]+)-([a-z]+)(\?)?$/);
18783
18784         if(!m){
18785             Ext.Error.raise({
18786                 sourceClass: 'Ext.core.Element',
18787                 sourceMethod: 'getAlignToXY',
18788                 el: el,
18789                 position: p,
18790                 offset: o,
18791                 msg: 'Attemmpted to align an element with an invalid position: "' + p + '"'
18792             });
18793         }
18794
18795         p1 = m[1];
18796         p2 = m[2];
18797         c = !!m[3];
18798
18799         //Subtract the aligned el's internal xy from the target's offset xy
18800         //plus custom offset to get the aligned el's new offset xy
18801         a1 = me.getAnchorXY(p1, true);
18802         a2 = el.getAnchorXY(p2, false);
18803
18804         x = a2[0] - a1[0] + o[0];
18805         y = a2[1] - a1[1] + o[1];
18806
18807         if(c){
18808            w = me.getWidth();
18809            h = me.getHeight();
18810            r = el.getRegion();
18811            //If we are at a viewport boundary and the aligned el is anchored on a target border that is
18812            //perpendicular to the vp border, allow the aligned el to slide on that border,
18813            //otherwise swap the aligned el to the opposite border of the target.
18814            p1y = p1.charAt(0);
18815            p1x = p1.charAt(p1.length-1);
18816            p2y = p2.charAt(0);
18817            p2x = p2.charAt(p2.length-1);
18818            swapY = ((p1y=="t" && p2y=="b") || (p1y=="b" && p2y=="t"));
18819            swapX = ((p1x=="r" && p2x=="l") || (p1x=="l" && p2x=="r"));
18820
18821
18822            if (x + w > dw + scrollX) {
18823                 x = swapX ? r.left-w : dw+scrollX-w;
18824            }
18825            if (x < scrollX) {
18826                x = swapX ? r.right : scrollX;
18827            }
18828            if (y + h > dh + scrollY) {
18829                 y = swapY ? r.top-h : dh+scrollY-h;
18830             }
18831            if (y < scrollY){
18832                y = swapY ? r.bottom : scrollY;
18833            }
18834         }
18835         return [x,y];
18836     },
18837
18838     /**
18839      * Aligns this element with another element relative to the specified anchor points. If the other element is the
18840      * document it aligns it to the viewport.
18841      * The position parameter is optional, and can be specified in any one of the following formats:
18842      * <ul>
18843      *   <li><b>Blank</b>: Defaults to aligning the element's top-left corner to the target's bottom-left corner ("tl-bl").</li>
18844      *   <li><b>One anchor (deprecated)</b>: The passed anchor position is used as the target element's anchor point.
18845      *       The element being aligned will position its top-left corner (tl) to that point.  <i>This method has been
18846      *       deprecated in favor of the newer two anchor syntax below</i>.</li>
18847      *   <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
18848      *       element's anchor point, and the second value is used as the target's anchor point.</li>
18849      * </ul>
18850      * In addition to the anchor points, the position parameter also supports the "?" character.  If "?" is passed at the end of
18851      * the position string, the element will attempt to align as specified, but the position will be adjusted to constrain to
18852      * the viewport if necessary.  Note that the element being aligned might be swapped to align to a different position than
18853      * that specified in order to enforce the viewport constraints.
18854      * Following are all of the supported anchor positions:
18855 <pre>
18856 Value  Description
18857 -----  -----------------------------
18858 tl     The top left corner (default)
18859 t      The center of the top edge
18860 tr     The top right corner
18861 l      The center of the left edge
18862 c      In the center of the element
18863 r      The center of the right edge
18864 bl     The bottom left corner
18865 b      The center of the bottom edge
18866 br     The bottom right corner
18867 </pre>
18868 Example Usage:
18869 <pre><code>
18870 // align el to other-el using the default positioning ("tl-bl", non-constrained)
18871 el.alignTo("other-el");
18872
18873 // align the top left corner of el with the top right corner of other-el (constrained to viewport)
18874 el.alignTo("other-el", "tr?");
18875
18876 // align the bottom right corner of el with the center left edge of other-el
18877 el.alignTo("other-el", "br-l?");
18878
18879 // align the center of el with the bottom left corner of other-el and
18880 // adjust the x position by -6 pixels (and the y position by 0)
18881 el.alignTo("other-el", "c-bl", [-6, 0]);
18882 </code></pre>
18883      * @param {Mixed} element The element to align to.
18884      * @param {String} position (optional, defaults to "tl-bl?") The position to align to.
18885      * @param {Array} offsets (optional) Offset the positioning by [x, y]
18886      * @param {Boolean/Object} animate (optional) true for the default animation or a standard Element animation config object
18887      * @return {Ext.core.Element} this
18888      */
18889     alignTo : function(element, position, offsets, animate){
18890         var me = this;
18891         return me.setXY(me.getAlignToXY(element, position, offsets),
18892                         me.anim && !!animate ? me.anim(animate) : false);
18893     },
18894
18895     // private ==>  used outside of core
18896     adjustForConstraints : function(xy, parent) {
18897         var vector = this.getConstrainVector(parent, xy);
18898         if (vector) {
18899             xy[0] += vector[0];
18900             xy[1] += vector[1];
18901         }
18902         return xy;
18903     },
18904
18905     /**
18906      * <p>Returns the <code>[X, Y]</code> vector by which this element must be translated to make a best attempt
18907      * to constrain within the passed constraint. Returns <code>false</code> is this element does not need to be moved.</p>
18908      * <p>Priority is given to constraining the top and left within the constraint.</p>
18909      * <p>The constraint may either be an existing element into which this element is to be constrained, or
18910      * an {@link Ext.util.Region Region} into which this element is to be constrained.</p>
18911      * @param constrainTo {Mixed} The Element or {@link Ext.util.Region Region} into which this element is to be constrained.
18912      * @param proposedPosition {Array} A proposed <code>[X, Y]</code> position to test for validity and to produce a vector for instead
18913      * of using this Element's current position;
18914      * @returns {Array} <b>If</b> this element <i>needs</i> to be translated, an <code>[X, Y]</code>
18915      * vector by which this element must be translated. Otherwise, <code>false</code>.
18916      */
18917     getConstrainVector: function(constrainTo, proposedPosition) {
18918         if (!(constrainTo instanceof Ext.util.Region)) {
18919             constrainTo = Ext.get(constrainTo).getViewRegion();
18920         }
18921         var thisRegion = this.getRegion(),
18922             vector = [0, 0],
18923             shadowSize = this.shadow && this.shadow.offset,
18924             overflowed = false;
18925
18926         // Shift this region to occupy the proposed position
18927         if (proposedPosition) {
18928             thisRegion.translateBy(proposedPosition[0] - thisRegion.x, proposedPosition[1] - thisRegion.y);
18929         }
18930
18931         // Reduce the constrain region to allow for shadow
18932         // TODO: Rewrite the Shadow class. When that's done, get the extra for each side from the Shadow.
18933         if (shadowSize) {
18934             constrainTo.adjust(0, -shadowSize, -shadowSize, shadowSize);
18935         }
18936
18937         // Constrain the X coordinate by however much this Element overflows
18938         if (thisRegion.right > constrainTo.right) {
18939             overflowed = true;
18940             vector[0] = (constrainTo.right - thisRegion.right);    // overflowed the right
18941         }
18942         if (thisRegion.left + vector[0] < constrainTo.left) {
18943             overflowed = true;
18944             vector[0] = (constrainTo.left - thisRegion.left);      // overflowed the left
18945         }
18946
18947         // Constrain the Y coordinate by however much this Element overflows
18948         if (thisRegion.bottom > constrainTo.bottom) {
18949             overflowed = true;
18950             vector[1] = (constrainTo.bottom - thisRegion.bottom);  // overflowed the bottom
18951         }
18952         if (thisRegion.top + vector[1] < constrainTo.top) {
18953             overflowed = true;
18954             vector[1] = (constrainTo.top - thisRegion.top);        // overflowed the top
18955         }
18956         return overflowed ? vector : false;
18957     },
18958
18959     /**
18960     * Calculates the x, y to center this element on the screen
18961     * @return {Array} The x, y values [x, y]
18962     */
18963     getCenterXY : function(){
18964         return this.getAlignToXY(document, 'c-c');
18965     },
18966
18967     /**
18968     * Centers the Element in either the viewport, or another Element.
18969     * @param {Mixed} centerIn (optional) The element in which to center the element.
18970     */
18971     center : function(centerIn){
18972         return this.alignTo(centerIn || document, 'c-c');
18973     }
18974 });
18975
18976 /**
18977  * @class Ext.core.Element
18978  */
18979 (function(){
18980
18981 var ELEMENT = Ext.core.Element,
18982     LEFT = "left",
18983     RIGHT = "right",
18984     TOP = "top",
18985     BOTTOM = "bottom",
18986     POSITION = "position",
18987     STATIC = "static",
18988     RELATIVE = "relative",
18989     AUTO = "auto",
18990     ZINDEX = "z-index";
18991
18992 Ext.override(Ext.core.Element, {
18993     /**
18994       * 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).
18995       * @return {Number} The X position of the element
18996       */
18997     getX : function(){
18998         return ELEMENT.getX(this.dom);
18999     },
19000
19001     /**
19002       * 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).
19003       * @return {Number} The Y position of the element
19004       */
19005     getY : function(){
19006         return ELEMENT.getY(this.dom);
19007     },
19008
19009     /**
19010       * 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).
19011       * @return {Array} The XY position of the element
19012       */
19013     getXY : function(){
19014         return ELEMENT.getXY(this.dom);
19015     },
19016
19017     /**
19018       * 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.
19019       * @param {Mixed} element The element to get the offsets from.
19020       * @return {Array} The XY page offsets (e.g. [100, -200])
19021       */
19022     getOffsetsTo : function(el){
19023         var o = this.getXY(),
19024             e = Ext.fly(el, '_internal').getXY();
19025         return [o[0]-e[0],o[1]-e[1]];
19026     },
19027
19028     /**
19029      * 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).
19030      * @param {Number} The X position of the element
19031      * @param {Boolean/Object} animate (optional) True for the default animation, or a standard Element animation config object
19032      * @return {Ext.core.Element} this
19033      */
19034     setX : function(x, animate){
19035         return this.setXY([x, this.getY()], animate);
19036     },
19037
19038     /**
19039      * 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).
19040      * @param {Number} The Y position of the element
19041      * @param {Boolean/Object} animate (optional) True for the default animation, or a standard Element animation config object
19042      * @return {Ext.core.Element} this
19043      */
19044     setY : function(y, animate){
19045         return this.setXY([this.getX(), y], animate);
19046     },
19047
19048     /**
19049      * Sets the element's left position directly using CSS style (instead of {@link #setX}).
19050      * @param {String} left The left CSS property value
19051      * @return {Ext.core.Element} this
19052      */
19053     setLeft : function(left){
19054         this.setStyle(LEFT, this.addUnits(left));
19055         return this;
19056     },
19057
19058     /**
19059      * Sets the element's top position directly using CSS style (instead of {@link #setY}).
19060      * @param {String} top The top CSS property value
19061      * @return {Ext.core.Element} this
19062      */
19063     setTop : function(top){
19064         this.setStyle(TOP, this.addUnits(top));
19065         return this;
19066     },
19067
19068     /**
19069      * Sets the element's CSS right style.
19070      * @param {String} right The right CSS property value
19071      * @return {Ext.core.Element} this
19072      */
19073     setRight : function(right){
19074         this.setStyle(RIGHT, this.addUnits(right));
19075         return this;
19076     },
19077
19078     /**
19079      * Sets the element's CSS bottom style.
19080      * @param {String} bottom The bottom CSS property value
19081      * @return {Ext.core.Element} this
19082      */
19083     setBottom : function(bottom){
19084         this.setStyle(BOTTOM, this.addUnits(bottom));
19085         return this;
19086     },
19087
19088     /**
19089      * Sets the position of the element in page coordinates, regardless of how the element is positioned.
19090      * The element must be part of the DOM tree to have page coordinates (display:none or elements not appended return false).
19091      * @param {Array} pos Contains X & Y [x, y] values for new position (coordinates are page-based)
19092      * @param {Boolean/Object} animate (optional) True for the default animation, or a standard Element animation config object
19093      * @return {Ext.core.Element} this
19094      */
19095     setXY: function(pos, animate) {
19096         var me = this;
19097         if (!animate || !me.anim) {
19098             ELEMENT.setXY(me.dom, pos);
19099         }
19100         else {
19101             if (!Ext.isObject(animate)) {
19102                 animate = {};
19103             }
19104             me.animate(Ext.applyIf({ to: { x: pos[0], y: pos[1] } }, animate));
19105         }
19106         return me;
19107     },
19108
19109     /**
19110      * Sets the position of the element in page coordinates, regardless of how the element is positioned.
19111      * The element must be part of the DOM tree to have page coordinates (display:none or elements not appended return false).
19112      * @param {Number} x X value for new position (coordinates are page-based)
19113      * @param {Number} y Y value for new position (coordinates are page-based)
19114      * @param {Boolean/Object} animate (optional) True for the default animation, or a standard Element animation config object
19115      * @return {Ext.core.Element} this
19116      */
19117     setLocation : function(x, y, animate){
19118         return this.setXY([x, y], animate);
19119     },
19120
19121     /**
19122      * Sets the position of the element in page coordinates, regardless of how the element is positioned.
19123      * The element must be part of the DOM tree to have page coordinates (display:none or elements not appended return false).
19124      * @param {Number} x X value for new position (coordinates are page-based)
19125      * @param {Number} y Y value for new position (coordinates are page-based)
19126      * @param {Boolean/Object} animate (optional) True for the default animation, or a standard Element animation config object
19127      * @return {Ext.core.Element} this
19128      */
19129     moveTo : function(x, y, animate){
19130         return this.setXY([x, y], animate);
19131     },
19132
19133     /**
19134      * Gets the left X coordinate
19135      * @param {Boolean} local True to get the local css position instead of page coordinate
19136      * @return {Number}
19137      */
19138     getLeft : function(local){
19139         return !local ? this.getX() : parseInt(this.getStyle(LEFT), 10) || 0;
19140     },
19141
19142     /**
19143      * Gets the right X coordinate of the element (element X position + element width)
19144      * @param {Boolean} local True to get the local css position instead of page coordinate
19145      * @return {Number}
19146      */
19147     getRight : function(local){
19148         var me = this;
19149         return !local ? me.getX() + me.getWidth() : (me.getLeft(true) + me.getWidth()) || 0;
19150     },
19151
19152     /**
19153      * Gets the top Y coordinate
19154      * @param {Boolean} local True to get the local css position instead of page coordinate
19155      * @return {Number}
19156      */
19157     getTop : function(local) {
19158         return !local ? this.getY() : parseInt(this.getStyle(TOP), 10) || 0;
19159     },
19160
19161     /**
19162      * Gets the bottom Y coordinate of the element (element Y position + element height)
19163      * @param {Boolean} local True to get the local css position instead of page coordinate
19164      * @return {Number}
19165      */
19166     getBottom : function(local){
19167         var me = this;
19168         return !local ? me.getY() + me.getHeight() : (me.getTop(true) + me.getHeight()) || 0;
19169     },
19170
19171     /**
19172     * Initializes positioning on this element. If a desired position is not passed, it will make the
19173     * the element positioned relative IF it is not already positioned.
19174     * @param {String} pos (optional) Positioning to use "relative", "absolute" or "fixed"
19175     * @param {Number} zIndex (optional) The zIndex to apply
19176     * @param {Number} x (optional) Set the page X position
19177     * @param {Number} y (optional) Set the page Y position
19178     */
19179     position : function(pos, zIndex, x, y) {
19180         var me = this;
19181
19182         if (!pos && me.isStyle(POSITION, STATIC)){
19183             me.setStyle(POSITION, RELATIVE);
19184         } else if(pos) {
19185             me.setStyle(POSITION, pos);
19186         }
19187         if (zIndex){
19188             me.setStyle(ZINDEX, zIndex);
19189         }
19190         if (x || y) {
19191             me.setXY([x || false, y || false]);
19192         }
19193     },
19194
19195     /**
19196     * Clear positioning back to the default when the document was loaded
19197     * @param {String} value (optional) The value to use for the left,right,top,bottom, defaults to '' (empty string). You could use 'auto'.
19198     * @return {Ext.core.Element} this
19199      */
19200     clearPositioning : function(value){
19201         value = value || '';
19202         this.setStyle({
19203             left : value,
19204             right : value,
19205             top : value,
19206             bottom : value,
19207             "z-index" : "",
19208             position : STATIC
19209         });
19210         return this;
19211     },
19212
19213     /**
19214     * Gets an object with all CSS positioning properties. Useful along with setPostioning to get
19215     * snapshot before performing an update and then restoring the element.
19216     * @return {Object}
19217     */
19218     getPositioning : function(){
19219         var l = this.getStyle(LEFT);
19220         var t = this.getStyle(TOP);
19221         return {
19222             "position" : this.getStyle(POSITION),
19223             "left" : l,
19224             "right" : l ? "" : this.getStyle(RIGHT),
19225             "top" : t,
19226             "bottom" : t ? "" : this.getStyle(BOTTOM),
19227             "z-index" : this.getStyle(ZINDEX)
19228         };
19229     },
19230
19231     /**
19232     * Set positioning with an object returned by getPositioning().
19233     * @param {Object} posCfg
19234     * @return {Ext.core.Element} this
19235      */
19236     setPositioning : function(pc){
19237         var me = this,
19238             style = me.dom.style;
19239
19240         me.setStyle(pc);
19241
19242         if(pc.right == AUTO){
19243             style.right = "";
19244         }
19245         if(pc.bottom == AUTO){
19246             style.bottom = "";
19247         }
19248
19249         return me;
19250     },
19251
19252     /**
19253      * Translates the passed page coordinates into left/top css values for this element
19254      * @param {Number/Array} x The page x or an array containing [x, y]
19255      * @param {Number} y (optional) The page y, required if x is not an array
19256      * @return {Object} An object with left and top properties. e.g. {left: (value), top: (value)}
19257      */
19258     translatePoints: function(x, y) {
19259         if (Ext.isArray(x)) {
19260              y = x[1];
19261              x = x[0];
19262         }
19263         var me = this,
19264             relative = me.isStyle(POSITION, RELATIVE),
19265             o = me.getXY(),
19266             left = parseInt(me.getStyle(LEFT), 10),
19267             top = parseInt(me.getStyle(TOP), 10);
19268
19269         if (!Ext.isNumber(left)) {
19270             left = relative ? 0 : me.dom.offsetLeft;
19271         }
19272         if (!Ext.isNumber(top)) {
19273             top = relative ? 0 : me.dom.offsetTop;
19274         }
19275         left = (Ext.isNumber(x)) ? x - o[0] + left : undefined;
19276         top = (Ext.isNumber(y)) ? y - o[1] + top : undefined;
19277         return {
19278             left: left,
19279             top: top
19280         };
19281     },
19282
19283     /**
19284      * 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.
19285      * @param {Object} box The box to fill {x, y, width, height}
19286      * @param {Boolean} adjust (optional) Whether to adjust for box-model issues automatically
19287      * @param {Boolean/Object} animate (optional) true for the default animation or a standard Element animation config object
19288      * @return {Ext.core.Element} this
19289      */
19290     setBox: function(box, adjust, animate) {
19291         var me = this,
19292             w = box.width,
19293             h = box.height;
19294         if ((adjust && !me.autoBoxAdjust) && !me.isBorderBox()) {
19295             w -= (me.getBorderWidth("lr") + me.getPadding("lr"));
19296             h -= (me.getBorderWidth("tb") + me.getPadding("tb"));
19297         }
19298         me.setBounds(box.x, box.y, w, h, animate);
19299         return me;
19300     },
19301
19302     /**
19303      * Return an object defining the area of this Element which can be passed to {@link #setBox} to
19304      * set another Element's size/location to match this element.
19305      * @param {Boolean} contentBox (optional) If true a box for the content of the element is returned.
19306      * @param {Boolean} local (optional) If true the element's left and top are returned instead of page x/y.
19307      * @return {Object} box An object in the format<pre><code>
19308 {
19309     x: &lt;Element's X position>,
19310     y: &lt;Element's Y position>,
19311     width: &lt;Element's width>,
19312     height: &lt;Element's height>,
19313     bottom: &lt;Element's lower bound>,
19314     right: &lt;Element's rightmost bound>
19315 }
19316 </code></pre>
19317      * The returned object may also be addressed as an Array where index 0 contains the X position
19318      * and index 1 contains the Y position. So the result may also be used for {@link #setXY}
19319      */
19320     getBox: function(contentBox, local) {
19321         var me = this,
19322             xy,
19323             left,
19324             top,
19325             getBorderWidth = me.getBorderWidth,
19326             getPadding = me.getPadding,
19327             l, r, t, b, w, h, bx;
19328         if (!local) {
19329             xy = me.getXY();
19330         } else {
19331             left = parseInt(me.getStyle("left"), 10) || 0;
19332             top = parseInt(me.getStyle("top"), 10) || 0;
19333             xy = [left, top];
19334         }
19335         w = me.getWidth();
19336         h = me.getHeight();
19337         if (!contentBox) {
19338             bx = {
19339                 x: xy[0],
19340                 y: xy[1],
19341                 0: xy[0],
19342                 1: xy[1],
19343                 width: w,
19344                 height: h
19345             };
19346         } else {
19347             l = getBorderWidth.call(me, "l") + getPadding.call(me, "l");
19348             r = getBorderWidth.call(me, "r") + getPadding.call(me, "r");
19349             t = getBorderWidth.call(me, "t") + getPadding.call(me, "t");
19350             b = getBorderWidth.call(me, "b") + getPadding.call(me, "b");
19351             bx = {
19352                 x: xy[0] + l,
19353                 y: xy[1] + t,
19354                 0: xy[0] + l,
19355                 1: xy[1] + t,
19356                 width: w - (l + r),
19357                 height: h - (t + b)
19358             };
19359         }
19360         bx.right = bx.x + bx.width;
19361         bx.bottom = bx.y + bx.height;
19362         return bx;
19363     },
19364
19365     /**
19366      * Move this element relative to its current position.
19367      * @param {String} direction Possible values are: "l" (or "left"), "r" (or "right"), "t" (or "top", or "up"), "b" (or "bottom", or "down").
19368      * @param {Number} distance How far to move the element in pixels
19369      * @param {Boolean/Object} animate (optional) true for the default animation or a standard Element animation config object
19370      * @return {Ext.core.Element} this
19371      */
19372     move: function(direction, distance, animate) {
19373         var me = this,
19374             xy = me.getXY(),
19375             x = xy[0],
19376             y = xy[1],
19377             left = [x - distance, y],
19378             right = [x + distance, y],
19379             top = [x, y - distance],
19380             bottom = [x, y + distance],
19381             hash = {
19382                 l: left,
19383                 left: left,
19384                 r: right,
19385                 right: right,
19386                 t: top,
19387                 top: top,
19388                 up: top,
19389                 b: bottom,
19390                 bottom: bottom,
19391                 down: bottom
19392             };
19393
19394         direction = direction.toLowerCase();
19395         me.moveTo(hash[direction][0], hash[direction][1], animate);
19396     },
19397
19398     /**
19399      * Quick set left and top adding default units
19400      * @param {String} left The left CSS property value
19401      * @param {String} top The top CSS property value
19402      * @return {Ext.core.Element} this
19403      */
19404     setLeftTop: function(left, top) {
19405         var me = this,
19406             style = me.dom.style;
19407         style.left = me.addUnits(left);
19408         style.top = me.addUnits(top);
19409         return me;
19410     },
19411
19412     /**
19413      * Returns the region of this element.
19414      * The element must be part of the DOM tree to have a region (display:none or elements not appended return false).
19415      * @return {Region} A Ext.util.Region containing "top, left, bottom, right" member data.
19416      */
19417     getRegion: function() {
19418         return this.getPageBox(true);
19419     },
19420
19421     /**
19422      * Returns the <b>content</b> region of this element. That is the region within the borders and padding.
19423      * @return {Region} A Ext.util.Region containing "top, left, bottom, right" member data.
19424      */
19425     getViewRegion: function() {
19426         var me = this,
19427             isBody = me.dom === document.body,
19428             scroll, pos, top, left, width, height;
19429             
19430         // For the body we want to do some special logic
19431         if (isBody) {
19432             scroll = me.getScroll();
19433             left = scroll.left;
19434             top = scroll.top;
19435             width = Ext.core.Element.getViewportWidth();
19436             height = Ext.core.Element.getViewportHeight();
19437         }
19438         else {
19439             pos = me.getXY();
19440             left = pos[0] + me.getBorderWidth('l') + me.getPadding('l');
19441             top = pos[1] + me.getBorderWidth('t') + me.getPadding('t');
19442             width = me.getWidth(true);
19443             height = me.getHeight(true);
19444         }
19445
19446         return Ext.create('Ext.util.Region', top, left + width, top + height, left);
19447     },
19448
19449     /**
19450      * Return an object defining the area of this Element which can be passed to {@link #setBox} to
19451      * set another Element's size/location to match this element.
19452      * @param {Boolean} asRegion(optional) If true an Ext.util.Region will be returned
19453      * @return {Object} box An object in the format<pre><code>
19454 {
19455     x: &lt;Element's X position>,
19456     y: &lt;Element's Y position>,
19457     width: &lt;Element's width>,
19458     height: &lt;Element's height>,
19459     bottom: &lt;Element's lower bound>,
19460     right: &lt;Element's rightmost bound>
19461 }
19462 </code></pre>
19463      * The returned object may also be addressed as an Array where index 0 contains the X position
19464      * and index 1 contains the Y position. So the result may also be used for {@link #setXY}
19465      */
19466     getPageBox : function(getRegion) {
19467         var me = this,
19468             el = me.dom,
19469             isDoc = el === document.body,
19470             w = isDoc ? Ext.core.Element.getViewWidth()  : el.offsetWidth,
19471             h = isDoc ? Ext.core.Element.getViewHeight() : el.offsetHeight,
19472             xy = me.getXY(),
19473             t = xy[1],
19474             r = xy[0] + w,
19475             b = xy[1] + h,
19476             l = xy[0];
19477
19478         if (getRegion) {
19479             return Ext.create('Ext.util.Region', t, r, b, l);
19480         }
19481         else {
19482             return {
19483                 left: l,
19484                 top: t,
19485                 width: w,
19486                 height: h,
19487                 right: r,
19488                 bottom: b
19489             };
19490         }
19491     },
19492
19493     /**
19494      * Sets the element's position and size in one shot. If animation is true then width, height, x and y will be animated concurrently.
19495      * @param {Number} x X value for new position (coordinates are page-based)
19496      * @param {Number} y Y value for new position (coordinates are page-based)
19497      * @param {Mixed} width The new width. This may be one of:<div class="mdetail-params"><ul>
19498      * <li>A Number specifying the new width in this Element's {@link #defaultUnit}s (by default, pixels)</li>
19499      * <li>A String used to set the CSS width style. Animation may <b>not</b> be used.
19500      * </ul></div>
19501      * @param {Mixed} height The new height. This may be one of:<div class="mdetail-params"><ul>
19502      * <li>A Number specifying the new height in this Element's {@link #defaultUnit}s (by default, pixels)</li>
19503      * <li>A String used to set the CSS height style. Animation may <b>not</b> be used.</li>
19504      * </ul></div>
19505      * @param {Boolean/Object} animate (optional) true for the default animation or a standard Element animation config object
19506      * @return {Ext.core.Element} this
19507      */
19508     setBounds: function(x, y, width, height, animate) {
19509         var me = this;
19510         if (!animate || !me.anim) {
19511             me.setSize(width, height);
19512             me.setLocation(x, y);
19513         } else {
19514             if (!Ext.isObject(animate)) {
19515                 animate = {};
19516             }
19517             me.animate(Ext.applyIf({
19518                 to: {
19519                     x: x,
19520                     y: y,
19521                     width: me.adjustWidth(width),
19522                     height: me.adjustHeight(height)
19523                 }
19524             }, animate));
19525         }
19526         return me;
19527     },
19528
19529     /**
19530      * Sets the element's position and size the specified region. If animation is true then width, height, x and y will be animated concurrently.
19531      * @param {Ext.util.Region} region The region to fill
19532      * @param {Boolean/Object} animate (optional) true for the default animation or a standard Element animation config object
19533      * @return {Ext.core.Element} this
19534      */
19535     setRegion: function(region, animate) {
19536         return this.setBounds(region.left, region.top, region.right - region.left, region.bottom - region.top, animate);
19537     }
19538 });
19539 })();
19540
19541 /**
19542  * @class Ext.core.Element
19543  */
19544 Ext.override(Ext.core.Element, {
19545     /**
19546      * Returns true if this element is scrollable.
19547      * @return {Boolean}
19548      */
19549     isScrollable : function(){
19550         var dom = this.dom;
19551         return dom.scrollHeight > dom.clientHeight || dom.scrollWidth > dom.clientWidth;
19552     },
19553
19554     /**
19555      * Returns the current scroll position of the element.
19556      * @return {Object} An object containing the scroll position in the format {left: (scrollLeft), top: (scrollTop)}
19557      */
19558     getScroll : function() {
19559         var d = this.dom, 
19560             doc = document,
19561             body = doc.body,
19562             docElement = doc.documentElement,
19563             l,
19564             t,
19565             ret;
19566
19567         if (d == doc || d == body) {
19568             if (Ext.isIE && Ext.isStrict) {
19569                 l = docElement.scrollLeft; 
19570                 t = docElement.scrollTop;
19571             } else {
19572                 l = window.pageXOffset;
19573                 t = window.pageYOffset;
19574             }
19575             ret = {
19576                 left: l || (body ? body.scrollLeft : 0), 
19577                 top : t || (body ? body.scrollTop : 0)
19578             };
19579         } else {
19580             ret = {
19581                 left: d.scrollLeft, 
19582                 top : d.scrollTop
19583             };
19584         }
19585         
19586         return ret;
19587     },
19588     
19589     /**
19590      * 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().
19591      * @param {String} side Either "left" for scrollLeft values or "top" for scrollTop values.
19592      * @param {Number} value The new scroll value
19593      * @param {Boolean/Object} animate (optional) true for the default animation or a standard Element animation config object
19594      * @return {Element} this
19595      */
19596     scrollTo : function(side, value, animate) {
19597         //check if we're scrolling top or left
19598         var top = /top/i.test(side),
19599             me = this,
19600             dom = me.dom,
19601             obj = {},
19602             prop;
19603         if (!animate || !me.anim) {
19604             // just setting the value, so grab the direction
19605             prop = 'scroll' + (top ? 'Top' : 'Left');
19606             dom[prop] = value;
19607         }
19608         else {
19609             if (!Ext.isObject(animate)) {
19610                 animate = {};
19611             }
19612             obj['scroll' + (top ? 'Top' : 'Left')] = value;
19613             me.animate(Ext.applyIf({
19614                 to: obj
19615             }, animate));
19616         }
19617         return me;
19618     },
19619
19620     /**
19621      * Scrolls this element into view within the passed container.
19622      * @param {Mixed} container (optional) The container element to scroll (defaults to document.body).  Should be a
19623      * string (id), dom node, or Ext.core.Element.
19624      * @param {Boolean} hscroll (optional) False to disable horizontal scroll (defaults to true)
19625      * @return {Ext.core.Element} this
19626      */
19627     scrollIntoView : function(container, hscroll) {
19628         container = Ext.getDom(container) || Ext.getBody().dom;
19629         var el = this.dom,
19630             offsets = this.getOffsetsTo(container),
19631             // el's box
19632             left = offsets[0] + container.scrollLeft,
19633             top = offsets[1] + container.scrollTop,
19634             bottom = top + el.offsetHeight,
19635             right = left + el.offsetWidth,
19636             // ct's box
19637             ctClientHeight = container.clientHeight,
19638             ctScrollTop = parseInt(container.scrollTop, 10),
19639             ctScrollLeft = parseInt(container.scrollLeft, 10),
19640             ctBottom = ctScrollTop + ctClientHeight,
19641             ctRight = ctScrollLeft + container.clientWidth;
19642
19643         if (el.offsetHeight > ctClientHeight || top < ctScrollTop) {
19644             container.scrollTop = top;
19645         } else if (bottom > ctBottom) {
19646             container.scrollTop = bottom - ctClientHeight;
19647         }
19648         // corrects IE, other browsers will ignore
19649         container.scrollTop = container.scrollTop;
19650
19651         if (hscroll !== false) {
19652             if (el.offsetWidth > container.clientWidth || left < ctScrollLeft) {
19653                 container.scrollLeft = left;
19654             }
19655             else if (right > ctRight) {
19656                 container.scrollLeft = right - container.clientWidth;
19657             }
19658             container.scrollLeft = container.scrollLeft;
19659         }
19660         return this;
19661     },
19662
19663     // private
19664     scrollChildIntoView : function(child, hscroll) {
19665         Ext.fly(child, '_scrollChildIntoView').scrollIntoView(this, hscroll);
19666     },
19667
19668     /**
19669      * Scrolls this element the specified direction. Does bounds checking to make sure the scroll is
19670      * within this element's scrollable range.
19671      * @param {String} direction Possible values are: "l" (or "left"), "r" (or "right"), "t" (or "top", or "up"), "b" (or "bottom", or "down").
19672      * @param {Number} distance How far to scroll the element in pixels
19673      * @param {Boolean/Object} animate (optional) true for the default animation or a standard Element animation config object
19674      * @return {Boolean} Returns true if a scroll was triggered or false if the element
19675      * was scrolled as far as it could go.
19676      */
19677      scroll : function(direction, distance, animate) {
19678         if (!this.isScrollable()) {
19679             return false;
19680         }
19681         var el = this.dom,
19682             l = el.scrollLeft, t = el.scrollTop,
19683             w = el.scrollWidth, h = el.scrollHeight,
19684             cw = el.clientWidth, ch = el.clientHeight,
19685             scrolled = false, v,
19686             hash = {
19687                 l: Math.min(l + distance, w-cw),
19688                 r: v = Math.max(l - distance, 0),
19689                 t: Math.max(t - distance, 0),
19690                 b: Math.min(t + distance, h-ch)
19691             };
19692             hash.d = hash.b;
19693             hash.u = hash.t;
19694
19695         direction = direction.substr(0, 1);
19696         if ((v = hash[direction]) > -1) {
19697             scrolled = true;
19698             this.scrollTo(direction == 'l' || direction == 'r' ? 'left' : 'top', v, this.anim(animate));
19699         }
19700         return scrolled;
19701     }
19702 });
19703 /**
19704  * @class Ext.core.Element
19705  */
19706 Ext.core.Element.addMethods(
19707     function() {
19708         var VISIBILITY      = "visibility",
19709             DISPLAY         = "display",
19710             HIDDEN          = "hidden",
19711             NONE            = "none",
19712             XMASKED         = Ext.baseCSSPrefix + "masked",
19713             XMASKEDRELATIVE = Ext.baseCSSPrefix + "masked-relative",
19714             data            = Ext.core.Element.data;
19715
19716         return {
19717             /**
19718              * Checks whether the element is currently visible using both visibility and display properties.
19719              * @param {Boolean} deep (optional) True to walk the dom and see if parent elements are hidden (defaults to false)
19720              * @return {Boolean} True if the element is currently visible, else false
19721              */
19722             isVisible : function(deep) {
19723                 var vis = !this.isStyle(VISIBILITY, HIDDEN) && !this.isStyle(DISPLAY, NONE),
19724                     p   = this.dom.parentNode;
19725
19726                 if (deep !== true || !vis) {
19727                     return vis;
19728                 }
19729
19730                 while (p && !(/^body/i.test(p.tagName))) {
19731                     if (!Ext.fly(p, '_isVisible').isVisible()) {
19732                         return false;
19733                     }
19734                     p = p.parentNode;
19735                 }
19736                 return true;
19737             },
19738
19739             /**
19740              * Returns true if display is not "none"
19741              * @return {Boolean}
19742              */
19743             isDisplayed : function() {
19744                 return !this.isStyle(DISPLAY, NONE);
19745             },
19746
19747             /**
19748              * Convenience method for setVisibilityMode(Element.DISPLAY)
19749              * @param {String} display (optional) What to set display to when visible
19750              * @return {Ext.core.Element} this
19751              */
19752             enableDisplayMode : function(display) {
19753                 this.setVisibilityMode(Ext.core.Element.DISPLAY);
19754
19755                 if (!Ext.isEmpty(display)) {
19756                     data(this.dom, 'originalDisplay', display);
19757                 }
19758
19759                 return this;
19760             },
19761
19762             /**
19763              * Puts a mask over this element to disable user interaction. Requires core.css.
19764              * This method can only be applied to elements which accept child nodes.
19765              * @param {String} msg (optional) A message to display in the mask
19766              * @param {String} msgCls (optional) A css class to apply to the msg element
19767              * @return {Element} The mask element
19768              */
19769             mask : function(msg, msgCls) {
19770                 var me  = this,
19771                     dom = me.dom,
19772                     setExpression = dom.style.setExpression,
19773                     dh  = Ext.core.DomHelper,
19774                     EXTELMASKMSG = Ext.baseCSSPrefix + "mask-msg",
19775                     el,
19776                     mask;
19777
19778                 if (!(/^body/i.test(dom.tagName) && me.getStyle('position') == 'static')) {
19779                     me.addCls(XMASKEDRELATIVE);
19780                 }
19781                 el = data(dom, 'maskMsg');
19782                 if (el) {
19783                     el.remove();
19784                 }
19785                 el = data(dom, 'mask');
19786                 if (el) {
19787                     el.remove();
19788                 }
19789
19790                 mask = dh.append(dom, {cls : Ext.baseCSSPrefix + "mask"}, true);
19791                 data(dom, 'mask', mask);
19792
19793                 me.addCls(XMASKED);
19794                 mask.setDisplayed(true);
19795
19796                 if (typeof msg == 'string') {
19797                     var mm = dh.append(dom, {cls : EXTELMASKMSG, cn:{tag:'div'}}, true);
19798                     data(dom, 'maskMsg', mm);
19799                     mm.dom.className = msgCls ? EXTELMASKMSG + " " + msgCls : EXTELMASKMSG;
19800                     mm.dom.firstChild.innerHTML = msg;
19801                     mm.setDisplayed(true);
19802                     mm.center(me);
19803                 }
19804                 // NOTE: CSS expressions are resource intensive and to be used only as a last resort
19805                 // These expressions are removed as soon as they are no longer necessary - in the unmask method.
19806                 // In normal use cases an element will be masked for a limited period of time.
19807                 // Fix for https://sencha.jira.com/browse/EXTJSIV-19.
19808                 // IE6 strict mode and IE6-9 quirks mode takes off left+right padding when calculating width!
19809                 if (!Ext.supports.IncludePaddingInWidthCalculation && setExpression) {
19810                     mask.dom.style.setExpression('width', 'this.parentNode.offsetWidth + "px"');
19811                 }
19812
19813                 // Some versions and modes of IE subtract top+bottom padding when calculating height.
19814                 // Different versions from those which make the same error for width!
19815                 if (!Ext.supports.IncludePaddingInHeightCalculation && setExpression) {
19816                     mask.dom.style.setExpression('height', 'this.parentNode.offsetHeight + "px"');
19817                 }
19818                 // ie will not expand full height automatically
19819                 else if (Ext.isIE && !(Ext.isIE7 && Ext.isStrict) && me.getStyle('height') == 'auto') {
19820                     mask.setSize(undefined, me.getHeight());
19821                 }
19822                 return mask;
19823             },
19824
19825             /**
19826              * Removes a previously applied mask.
19827              */
19828             unmask : function() {
19829                 var me      = this,
19830                     dom     = me.dom,
19831                     mask    = data(dom, 'mask'),
19832                     maskMsg = data(dom, 'maskMsg');
19833
19834                 if (mask) {
19835                     // Remove resource-intensive CSS expressions as soon as they are not required.
19836                     if (mask.dom.style.clearExpression) {
19837                         mask.dom.style.clearExpression('width');
19838                         mask.dom.style.clearExpression('height');
19839                     }
19840                     if (maskMsg) {
19841                         maskMsg.remove();
19842                         data(dom, 'maskMsg', undefined);
19843                     }
19844
19845                     mask.remove();
19846                     data(dom, 'mask', undefined);
19847                     me.removeCls([XMASKED, XMASKEDRELATIVE]);
19848                 }
19849             },
19850             /**
19851              * Returns true if this element is masked. Also re-centers any displayed message within the mask.
19852              * @return {Boolean}
19853              */
19854             isMasked : function() {
19855                 var me = this,
19856                     mask = data(me.dom, 'mask'),
19857                     maskMsg = data(me.dom, 'maskMsg');
19858
19859                 if (mask && mask.isVisible()) {
19860                     if (maskMsg) {
19861                         maskMsg.center(me);
19862                     }
19863                     return true;
19864                 }
19865                 return false;
19866             },
19867
19868             /**
19869              * Creates an iframe shim for this element to keep selects and other windowed objects from
19870              * showing through.
19871              * @return {Ext.core.Element} The new shim element
19872              */
19873             createShim : function() {
19874                 var el = document.createElement('iframe'),
19875                     shim;
19876
19877                 el.frameBorder = '0';
19878                 el.className = Ext.baseCSSPrefix + 'shim';
19879                 el.src = Ext.SSL_SECURE_URL;
19880                 shim = Ext.get(this.dom.parentNode.insertBefore(el, this.dom));
19881                 shim.autoBoxAdjust = false;
19882                 return shim;
19883             }
19884         };
19885     }()
19886 );
19887 /**
19888  * @class Ext.core.Element
19889  */
19890 Ext.core.Element.addMethods({
19891     /**
19892      * Convenience method for constructing a KeyMap
19893      * @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:
19894      * <code>{key: (number or array), shift: (true/false), ctrl: (true/false), alt: (true/false)}</code>
19895      * @param {Function} fn The function to call
19896      * @param {Object} scope (optional) The scope (<code>this</code> reference) in which the specified function is executed. Defaults to this Element.
19897      * @return {Ext.util.KeyMap} The KeyMap created
19898      */
19899     addKeyListener : function(key, fn, scope){
19900         var config;
19901         if(typeof key != 'object' || Ext.isArray(key)){
19902             config = {
19903                 key: key,
19904                 fn: fn,
19905                 scope: scope
19906             };
19907         }else{
19908             config = {
19909                 key : key.key,
19910                 shift : key.shift,
19911                 ctrl : key.ctrl,
19912                 alt : key.alt,
19913                 fn: fn,
19914                 scope: scope
19915             };
19916         }
19917         return Ext.create('Ext.util.KeyMap', this, config);
19918     },
19919
19920     /**
19921      * Creates a KeyMap for this element
19922      * @param {Object} config The KeyMap config. See {@link Ext.util.KeyMap} for more details
19923      * @return {Ext.util.KeyMap} The KeyMap created
19924      */
19925     addKeyMap : function(config){
19926         return Ext.create('Ext.util.KeyMap', this, config);
19927     }
19928 });
19929
19930 //Import the newly-added Ext.core.Element functions into CompositeElementLite. We call this here because
19931 //Element.keys.js is the last extra Ext.core.Element include in the ext-all.js build
19932 Ext.CompositeElementLite.importElementMethods();
19933
19934 /**
19935  * @class Ext.CompositeElementLite
19936  */
19937 Ext.apply(Ext.CompositeElementLite.prototype, {
19938     addElements : function(els, root){
19939         if(!els){
19940             return this;
19941         }
19942         if(typeof els == "string"){
19943             els = Ext.core.Element.selectorFunction(els, root);
19944         }
19945         var yels = this.elements;
19946         Ext.each(els, function(e) {
19947             yels.push(Ext.get(e));
19948         });
19949         return this;
19950     },
19951
19952     /**
19953      * Returns the first Element
19954      * @return {Ext.core.Element}
19955      */
19956     first : function(){
19957         return this.item(0);
19958     },
19959
19960     /**
19961      * Returns the last Element
19962      * @return {Ext.core.Element}
19963      */
19964     last : function(){
19965         return this.item(this.getCount()-1);
19966     },
19967
19968     /**
19969      * Returns true if this composite contains the passed element
19970      * @param el {Mixed} The id of an element, or an Ext.core.Element, or an HtmlElement to find within the composite collection.
19971      * @return Boolean
19972      */
19973     contains : function(el){
19974         return this.indexOf(el) != -1;
19975     },
19976
19977     /**
19978     * Removes the specified element(s).
19979     * @param {Mixed} el The id of an element, the Element itself, the index of the element in this composite
19980     * or an array of any of those.
19981     * @param {Boolean} removeDom (optional) True to also remove the element from the document
19982     * @return {CompositeElement} this
19983     */
19984     removeElement : function(keys, removeDom){
19985         var me = this,
19986             els = this.elements,
19987             el;
19988         Ext.each(keys, function(val){
19989             if ((el = (els[val] || els[val = me.indexOf(val)]))) {
19990                 if(removeDom){
19991                     if(el.dom){
19992                         el.remove();
19993                     }else{
19994                         Ext.removeNode(el);
19995                     }
19996                 }
19997                 els.splice(val, 1);
19998             }
19999         });
20000         return this;
20001     }
20002 });
20003
20004 /**
20005  * @class Ext.CompositeElement
20006  * @extends Ext.CompositeElementLite
20007  * <p>This class encapsulates a <i>collection</i> of DOM elements, providing methods to filter
20008  * members, or to perform collective actions upon the whole set.</p>
20009  * <p>Although they are not listed, this class supports all of the methods of {@link Ext.core.Element} and
20010  * {@link Ext.fx.Anim}. The methods from these classes will be performed on all the elements in this collection.</p>
20011  * <p>All methods return <i>this</i> and can be chained.</p>
20012  * Usage:
20013 <pre><code>
20014 var els = Ext.select("#some-el div.some-class", true);
20015 // or select directly from an existing element
20016 var el = Ext.get('some-el');
20017 el.select('div.some-class', true);
20018
20019 els.setWidth(100); // all elements become 100 width
20020 els.hide(true); // all elements fade out and hide
20021 // or
20022 els.setWidth(100).hide(true);
20023 </code></pre>
20024  */
20025 Ext.CompositeElement = Ext.extend(Ext.CompositeElementLite, {
20026     
20027     constructor : function(els, root){
20028         this.elements = [];
20029         this.add(els, root);
20030     },
20031     
20032     // private
20033     getElement : function(el){
20034         // In this case just return it, since we already have a reference to it
20035         return el;
20036     },
20037     
20038     // private
20039     transformElement : function(el){
20040         return Ext.get(el);
20041     }
20042
20043     /**
20044     * Adds elements to this composite.
20045     * @param {String/Array} els A string CSS selector, an array of elements or an element
20046     * @return {CompositeElement} this
20047     */
20048
20049     /**
20050      * Returns the Element object at the specified index
20051      * @param {Number} index
20052      * @return {Ext.core.Element}
20053      */
20054
20055     /**
20056      * Iterates each `element` in this `composite` calling the supplied function using {@link Ext#each Ext.each}.
20057      * @param {Function} fn 
20058
20059 The function to be called with each
20060 `element`. If the supplied function returns <tt>false</tt>,
20061 iteration stops. This function is called with the following arguments:
20062
20063 - `element` : __Ext.core.Element++
20064     The element at the current `index` in the `composite`
20065     
20066 - `composite` : __Object__ 
20067     This composite.
20068
20069 - `index` : __Number__ 
20070     The current index within the `composite`
20071
20072      * @param {Object} scope (optional) The scope (<code>this</code> reference) in which the specified function is executed.
20073      * Defaults to the <code>element</code> at the current <code>index</code>
20074      * within the composite.
20075      * @return {CompositeElement} this
20076      * @markdown
20077      */
20078 });
20079
20080 /**
20081  * Selects elements based on the passed CSS selector to enable {@link Ext.core.Element Element} methods
20082  * to be applied to many related elements in one statement through the returned {@link Ext.CompositeElement CompositeElement} or
20083  * {@link Ext.CompositeElementLite CompositeElementLite} object.
20084  * @param {String/Array} selector The CSS selector or an array of elements
20085  * @param {Boolean} unique (optional) true to create a unique Ext.core.Element for each element (defaults to a shared flyweight object)
20086  * @param {HTMLElement/String} root (optional) The root element of the query or id of the root
20087  * @return {CompositeElementLite/CompositeElement}
20088  * @member Ext.core.Element
20089  * @method select
20090  */
20091 Ext.core.Element.select = function(selector, unique, root){
20092     var els;
20093     if(typeof selector == "string"){
20094         els = Ext.core.Element.selectorFunction(selector, root);
20095     }else if(selector.length !== undefined){
20096         els = selector;
20097     }else{
20098         Ext.Error.raise({
20099             sourceClass: "Ext.core.Element",
20100             sourceMethod: "select",
20101             selector: selector,
20102             unique: unique,
20103             root: root,
20104             msg: "Invalid selector specified: " + selector
20105         });
20106     }
20107     return (unique === true) ? new Ext.CompositeElement(els) : new Ext.CompositeElementLite(els);
20108 };
20109
20110 /**
20111  * Selects elements based on the passed CSS selector to enable {@link Ext.core.Element Element} methods
20112  * to be applied to many related elements in one statement through the returned {@link Ext.CompositeElement CompositeElement} or
20113  * {@link Ext.CompositeElementLite CompositeElementLite} object.
20114  * @param {String/Array} selector The CSS selector or an array of elements
20115  * @param {Boolean} unique (optional) true to create a unique Ext.core.Element for each element (defaults to a shared flyweight object)
20116  * @param {HTMLElement/String} root (optional) The root element of the query or id of the root
20117  * @return {CompositeElementLite/CompositeElement}
20118  * @member Ext
20119  * @method select
20120  */
20121 Ext.select = Ext.core.Element.select;
20122
20123
20124 /*
20125 Ext JS - JavaScript Library
20126 Copyright (c) 2006-2011, Sencha Inc.
20127 All rights reserved.
20128 licensing@sencha.com
20129 */
20130 (function(){ var data = {
20131     "nameToAliasesMap":{
20132         "Ext.AbstractComponent":[""
20133         ],
20134         "Ext.AbstractManager":[""
20135         ],
20136         "Ext.AbstractPlugin":[""
20137         ],
20138         "Ext.Ajax":[""
20139         ],
20140         "Ext.ComponentLoader":[""
20141         ],
20142         "Ext.ComponentManager":[""
20143         ],
20144         "Ext.ComponentQuery":[""
20145         ],
20146         "Ext.ElementLoader":[""
20147         ],
20148         "Ext.LoadMask":[""
20149         ],
20150         "Ext.ModelManager":[""
20151         ],
20152         "Ext.PluginManager":[""
20153         ],
20154         "Ext.Template":[""
20155         ],
20156         "Ext.XTemplate":[""
20157         ],
20158         "Ext.app.Application":[""
20159         ],
20160         "Ext.app.Controller":[""
20161         ],
20162         "Ext.app.EventBus":[""
20163         ],
20164         "Ext.chart.Callout":[""
20165         ],
20166         "Ext.chart.Chart":["widget.chart"
20167         ],
20168         "Ext.chart.Highlight":[""
20169         ],
20170         "Ext.chart.Label":[""
20171         ],
20172         "Ext.chart.Legend":[""
20173         ],
20174         "Ext.chart.LegendItem":[""
20175         ],
20176         "Ext.chart.Mask":[""
20177         ],
20178         "Ext.chart.MaskLayer":[""
20179         ],
20180         "Ext.chart.Navigation":[""
20181         ],
20182         "Ext.chart.Shape":[""
20183         ],
20184         "Ext.chart.Tip":[""
20185         ],
20186         "Ext.chart.TipSurface":[""
20187         ],
20188         "Ext.chart.axis.Abstract":[""
20189         ],
20190         "Ext.chart.axis.Axis":[""
20191         ],
20192         "Ext.chart.axis.Category":["axis.category"
20193         ],
20194         "Ext.chart.axis.Gauge":["axis.gauge"
20195         ],
20196         "Ext.chart.axis.Numeric":["axis.numeric"
20197         ],
20198         "Ext.chart.axis.Radial":["axis.radial"
20199         ],
20200         "Ext.chart.axis.Time":["axis.time"
20201         ],
20202         "Ext.chart.series.Area":["series.area"
20203         ],
20204         "Ext.chart.series.Bar":["series.bar"
20205         ],
20206         "Ext.chart.series.Cartesian":[""
20207         ],
20208         "Ext.chart.series.Column":["series.column"
20209         ],
20210         "Ext.chart.series.Gauge":["series.gauge"
20211         ],
20212         "Ext.chart.series.Line":["series.line"
20213         ],
20214         "Ext.chart.series.Pie":["series.pie"
20215         ],
20216         "Ext.chart.series.Radar":["series.radar"
20217         ],
20218         "Ext.chart.series.Scatter":["series.scatter"
20219         ],
20220         "Ext.chart.series.Series":[""
20221         ],
20222         "Ext.chart.theme.Base":[""
20223         ],
20224         "Ext.chart.theme.Theme":[""
20225         ],
20226         "Ext.container.AbstractContainer":[""
20227         ],
20228         "Ext.data.AbstractStore":[""
20229         ],
20230         "Ext.data.ArrayStore":["store.array"
20231         ],
20232         "Ext.data.Association":[""
20233         ],
20234         "Ext.data.Batch":[""
20235         ],
20236         "Ext.data.BelongsToAssociation":["association.belongsto"
20237         ],
20238         "Ext.data.BufferStore":["store.buffer"
20239         ],
20240         "Ext.data.Connection":[""
20241         ],
20242         "Ext.data.DirectStore":["store.direct"
20243         ],
20244         "Ext.data.Errors":[""
20245         ],
20246         "Ext.data.Field":["data.field"
20247         ],
20248         "Ext.data.HasManyAssociation":["association.hasmany"
20249         ],
20250         "Ext.data.JsonP":[""
20251         ],
20252         "Ext.data.JsonPStore":["store.jsonp"
20253         ],
20254         "Ext.data.JsonStore":["store.json"
20255         ],
20256         "Ext.data.Model":[""
20257         ],
20258         "Ext.data.NodeInterface":[""
20259         ],
20260         "Ext.data.NodeStore":["store.node"
20261         ],
20262         "Ext.data.Operation":[""
20263         ],
20264         "Ext.data.Request":[""
20265         ],
20266         "Ext.data.ResultSet":[""
20267         ],
20268         "Ext.data.SortTypes":[""
20269         ],
20270         "Ext.data.Store":["store.store"
20271         ],
20272         "Ext.data.StoreManager":[""
20273         ],
20274         "Ext.data.Tree":["data.tree"
20275         ],
20276         "Ext.data.TreeStore":["store.tree"
20277         ],
20278         "Ext.data.Types":[""
20279         ],
20280         "Ext.data.validations":[""
20281         ],
20282         "Ext.data.XmlStore":["store.xml"
20283         ],
20284         "Ext.data.proxy.Ajax":["proxy.ajax"
20285         ],
20286         "Ext.data.proxy.Client":[""
20287         ],
20288         "Ext.data.proxy.Direct":["proxy.direct"
20289         ],
20290         "Ext.data.proxy.JsonP":["proxy.jsonp",
20291             "proxy.scripttag"
20292         ],
20293         "Ext.data.proxy.LocalStorage":["proxy.localstorage"
20294         ],
20295         "Ext.data.proxy.Memory":["proxy.memory"
20296         ],
20297         "Ext.data.proxy.Proxy":["proxy.proxy"
20298         ],
20299         "Ext.data.proxy.Rest":["proxy.rest"
20300         ],
20301         "Ext.data.proxy.Server":["proxy.server"
20302         ],
20303         "Ext.data.proxy.SessionStorage":["proxy.sessionstorage"
20304         ],
20305         "Ext.data.proxy.WebStorage":[""
20306         ],
20307         "Ext.data.reader.Array":["reader.array"
20308         ],
20309         "Ext.data.reader.Json":["reader.json"
20310         ],
20311         "Ext.data.reader.Reader":[""
20312         ],
20313         "Ext.data.reader.Xml":["reader.xml"
20314         ],
20315         "Ext.data.writer.Json":["writer.json"
20316         ],
20317         "Ext.data.writer.Writer":["writer.base"
20318         ],
20319         "Ext.data.writer.Xml":["writer.xml"
20320         ],
20321         "Ext.direct.Event":["direct.event"
20322         ],
20323         "Ext.direct.ExceptionEvent":["direct.exception"
20324         ],
20325         "Ext.direct.JsonProvider":["direct.jsonprovider"
20326         ],
20327         "Ext.direct.Manager":[""
20328         ],
20329         "Ext.direct.PollingProvider":["direct.pollingprovider"
20330         ],
20331         "Ext.direct.Provider":["direct.provider"
20332         ],
20333         "Ext.direct.RemotingEvent":["direct.rpc"
20334         ],
20335         "Ext.direct.RemotingMethod":[""
20336         ],
20337         "Ext.direct.RemotingProvider":["direct.remotingprovider"
20338         ],
20339         "Ext.direct.Transaction":["direct.transaction"
20340         ],
20341         "Ext.draw.Color":[""
20342         ],
20343         "Ext.draw.Component":["widget.draw"
20344         ],
20345         "Ext.draw.CompositeSprite":[""
20346         ],
20347         "Ext.draw.Draw":[""
20348         ],
20349         "Ext.draw.Matrix":[""
20350         ],
20351         "Ext.draw.Sprite":[""
20352         ],
20353         "Ext.draw.SpriteDD":[""
20354         ],
20355         "Ext.draw.Surface":[""
20356         ],
20357         "Ext.draw.engine.Svg":[""
20358         ],
20359         "Ext.draw.engine.Vml":[""
20360         ],
20361         "Ext.fx.Anim":[""
20362         ],
20363         "Ext.fx.Animator":[""
20364         ],
20365         "Ext.fx.CubicBezier":[""
20366         ],
20367         "Ext.fx.Easing":[],
20368         "Ext.fx.Manager":[""
20369         ],
20370         "Ext.fx.PropertyHandler":[""
20371         ],
20372         "Ext.fx.Queue":[""
20373         ],
20374         "Ext.fx.target.Component":[""
20375         ],
20376         "Ext.fx.target.CompositeElement":[""
20377         ],
20378         "Ext.fx.target.CompositeElementCSS":[""
20379         ],
20380         "Ext.fx.target.CompositeSprite":[""
20381         ],
20382         "Ext.fx.target.Element":[""
20383         ],
20384         "Ext.fx.target.ElementCSS":[""
20385         ],
20386         "Ext.fx.target.Sprite":[""
20387         ],
20388         "Ext.fx.target.Target":[""
20389         ],
20390         "Ext.layout.Layout":[""
20391         ],
20392         "Ext.layout.component.AbstractDock":[""
20393         ],
20394         "Ext.layout.component.Auto":["layout.autocomponent"
20395         ],
20396         "Ext.layout.component.Component":[""
20397         ],
20398         "Ext.layout.component.Draw":["layout.draw"
20399         ],
20400         "Ext.layout.container.AbstractCard":[""
20401         ],
20402         "Ext.layout.container.AbstractContainer":[""
20403         ],
20404         "Ext.layout.container.AbstractFit":[""
20405         ],
20406         "Ext.layout.container.Auto":["layout.auto",
20407             "layout.autocontainer"
20408         ],
20409         "Ext.panel.AbstractPanel":[""
20410         ],
20411         "Ext.selection.DataViewModel":[""
20412         ],
20413         "Ext.selection.Model":[""
20414         ],
20415         "Ext.state.CookieProvider":[""
20416         ],
20417         "Ext.state.LocalStorageProvider":["state.localstorage"
20418         ],
20419         "Ext.state.Manager":[""
20420         ],
20421         "Ext.state.Provider":[""
20422         ],
20423         "Ext.state.Stateful":[""
20424         ],
20425         "Ext.util.AbstractMixedCollection":[""
20426         ],
20427         "Ext.util.Filter":[""
20428         ],
20429         "Ext.util.Grouper":[""
20430         ],
20431         "Ext.util.HashMap":[""
20432         ],
20433         "Ext.util.Inflector":[""
20434         ],
20435         "Ext.util.MixedCollection":[""
20436         ],
20437         "Ext.util.Observable":[""
20438         ],
20439         "Ext.util.Offset":[""
20440         ],
20441         "Ext.util.Point":[""
20442         ],
20443         "Ext.util.Region":[""
20444         ],
20445         "Ext.util.Sortable":[""
20446         ],
20447         "Ext.util.Sorter":[""
20448         ],
20449         "Ext.view.AbstractView":[""
20450         ],
20451         "Ext.Action":[""
20452         ],
20453         "Ext.Component":["widget.component",
20454             "widget.box"
20455         ],
20456         "Ext.Editor":["widget.editor"
20457         ],
20458         "Ext.FocusManager":[""
20459         ],
20460         "Ext.Img":["widget.image",
20461             "widget.imagecomponent"
20462         ],
20463         "Ext.Layer":[""
20464         ],
20465         "Ext.ProgressBar":["widget.progressbar"
20466         ],
20467         "Ext.Shadow":[""
20468         ],
20469         "Ext.ShadowPool":[""
20470         ],
20471         "Ext.ZIndexManager":[""
20472         ],
20473         "Ext.button.Button":["widget.button"
20474         ],
20475         "Ext.button.Cycle":["widget.cycle"
20476         ],
20477         "Ext.button.Split":["widget.splitbutton"
20478         ],
20479         "Ext.container.ButtonGroup":["widget.buttongroup"
20480         ],
20481         "Ext.container.Container":["widget.container"
20482         ],
20483         "Ext.container.Viewport":["widget.viewport"
20484         ],
20485         "Ext.dd.DD":[""
20486         ],
20487         "Ext.dd.DDProxy":[""
20488         ],
20489         "Ext.dd.DDTarget":[""
20490         ],
20491         "Ext.dd.DragDrop":[""
20492         ],
20493         "Ext.dd.DragDropManager":[""
20494         ],
20495         "Ext.dd.DragSource":[""
20496         ],
20497         "Ext.dd.DragTracker":[""
20498         ],
20499         "Ext.dd.DragZone":[""
20500         ],
20501         "Ext.dd.DropTarget":[""
20502         ],
20503         "Ext.dd.DropZone":[""
20504         ],
20505         "Ext.dd.Registry":[""
20506         ],
20507         "Ext.dd.ScrollManager":[""
20508         ],
20509         "Ext.dd.StatusProxy":[""
20510         ],
20511         "Ext.flash.Component":["widget.flash"
20512         ],
20513         "Ext.form.Basic":[""
20514         ],
20515         "Ext.form.CheckboxGroup":["widget.checkboxgroup"
20516         ],
20517         "Ext.form.CheckboxManager":[""
20518         ],
20519         "Ext.form.FieldAncestor":[""
20520         ],
20521         "Ext.form.FieldContainer":["widget.fieldcontainer"
20522         ],
20523         "Ext.form.FieldSet":["widget.fieldset"
20524         ],
20525         "Ext.form.Label":["widget.label"
20526         ],
20527         "Ext.form.Labelable":[""
20528         ],
20529         "Ext.form.Panel":["widget.form"
20530         ],
20531         "Ext.form.RadioGroup":["widget.radiogroup"
20532         ],
20533         "Ext.form.RadioManager":[""
20534         ],
20535         "Ext.form.action.Action":[""
20536         ],
20537         "Ext.form.action.DirectLoad":["formaction.directload"
20538         ],
20539         "Ext.form.action.DirectSubmit":["formaction.directsubmit"
20540         ],
20541         "Ext.form.action.Load":["formaction.load"
20542         ],
20543         "Ext.form.action.StandardSubmit":["formaction.standardsubmit"
20544         ],
20545         "Ext.form.action.Submit":["formaction.submit"
20546         ],
20547         "Ext.form.field.Base":["widget.field"
20548         ],
20549         "Ext.form.field.Checkbox":["widget.checkboxfield",
20550             "widget.checkbox"
20551         ],
20552         "Ext.form.field.ComboBox":["widget.combobox",
20553             "widget.combo"
20554         ],
20555         "Ext.form.field.Date":["widget.datefield"
20556         ],
20557         "Ext.form.field.Display":["widget.displayfield"
20558         ],
20559         "Ext.form.field.Field":[""
20560         ],
20561         "Ext.form.field.File":["widget.filefield",
20562             "widget.fileuploadfield"
20563         ],
20564         "Ext.form.field.Hidden":["widget.hiddenfield",
20565             "widget.hidden"
20566         ],
20567         "Ext.form.field.HtmlEditor":["widget.htmleditor"
20568         ],
20569         "Ext.form.field.Number":["widget.numberfield"
20570         ],
20571         "Ext.form.field.Picker":["widget.pickerfield"
20572         ],
20573         "Ext.form.field.Radio":["widget.radiofield",
20574             "widget.radio"
20575         ],
20576         "Ext.form.field.Spinner":["widget.spinnerfield"
20577         ],
20578         "Ext.form.field.Text":["widget.textfield"
20579         ],
20580         "Ext.form.field.TextArea":["widget.textareafield",
20581             "widget.textarea"
20582         ],
20583         "Ext.form.field.Time":["widget.timefield"
20584         ],
20585         "Ext.form.field.Trigger":["widget.triggerfield",
20586             "widget.trigger"
20587         ],
20588         "Ext.form.field.VTypes":[""
20589         ],
20590         "Ext.grid.CellEditor":[""
20591         ],
20592         "Ext.grid.ColumnLayout":["layout.gridcolumn"
20593         ],
20594         "Ext.grid.Lockable":[""
20595         ],
20596         "Ext.grid.LockingView":[""
20597         ],
20598         "Ext.grid.PagingScroller":["widget.paginggridscroller"
20599         ],
20600         "Ext.grid.Panel":["widget.gridpanel",
20601             "widget.grid"
20602         ],
20603         "Ext.grid.RowEditor":[""
20604         ],
20605         "Ext.grid.RowNumberer":["widget.rownumberer"
20606         ],
20607         "Ext.grid.Scroller":["widget.gridscroller"
20608         ],
20609         "Ext.grid.View":["widget.gridview"
20610         ],
20611         "Ext.grid.ViewDropZone":[""
20612         ],
20613         "Ext.grid.column.Action":["widget.actioncolumn"
20614         ],
20615         "Ext.grid.column.Boolean":["widget.booleancolumn"
20616         ],
20617         "Ext.grid.column.Column":["widget.gridcolumn"
20618         ],
20619         "Ext.grid.column.Date":["widget.datecolumn"
20620         ],
20621         "Ext.grid.column.Number":["widget.numbercolumn"
20622         ],
20623         "Ext.grid.column.Template":["widget.templatecolumn"
20624         ],
20625         "Ext.grid.feature.AbstractSummary":["feature.abstractsummary"
20626         ],
20627         "Ext.grid.feature.Chunking":["feature.chunking"
20628         ],
20629         "Ext.grid.feature.Feature":["feature.feature"
20630         ],
20631         "Ext.grid.feature.Grouping":["feature.grouping"
20632         ],
20633         "Ext.grid.feature.GroupingSummary":["feature.groupingsummary"
20634         ],
20635         "Ext.grid.feature.RowBody":["feature.rowbody"
20636         ],
20637         "Ext.grid.feature.RowWrap":["feature.rowwrap"
20638         ],
20639         "Ext.grid.feature.Summary":["feature.summary"
20640         ],
20641         "Ext.grid.header.Container":["widget.headercontainer"
20642         ],
20643         "Ext.grid.header.DragZone":[""
20644         ],
20645         "Ext.grid.header.DropZone":[""
20646         ],
20647         "Ext.grid.plugin.CellEditing":["plugin.cellediting"
20648         ],
20649         "Ext.grid.plugin.DragDrop":["plugin.gridviewdragdrop"
20650         ],
20651         "Ext.grid.plugin.Editing":["editing.editing"
20652         ],
20653         "Ext.grid.plugin.HeaderReorderer":["plugin.gridheaderreorderer"
20654         ],
20655         "Ext.grid.plugin.HeaderResizer":["plugin.gridheaderresizer"
20656         ],
20657         "Ext.grid.plugin.RowEditing":["plugin.rowediting"
20658         ],
20659         "Ext.grid.property.Grid":["widget.propertygrid"
20660         ],
20661         "Ext.grid.property.HeaderContainer":[""
20662         ],
20663         "Ext.grid.property.Property":[""
20664         ],
20665         "Ext.grid.property.Store":[""
20666         ],
20667         "Ext.layout.component.Body":["layout.body"
20668         ],
20669         "Ext.layout.component.BoundList":["layout.boundlist"
20670         ],
20671         "Ext.layout.component.Button":["layout.button"
20672         ],
20673         "Ext.layout.component.Dock":["layout.dock"
20674         ],
20675         "Ext.layout.component.Editor":["layout.editor"
20676         ],
20677         "Ext.layout.component.FieldSet":["layout.fieldset"
20678         ],
20679         "Ext.layout.component.ProgressBar":["layout.progressbar"
20680         ],
20681         "Ext.layout.component.Tab":["layout.tab"
20682         ],
20683         "Ext.layout.component.Tip":["layout.tip"
20684         ],
20685         "Ext.layout.component.field.Field":["layout.field"
20686         ],
20687         "Ext.layout.component.field.File":["layout.filefield"
20688         ],
20689         "Ext.layout.component.field.HtmlEditor":["layout.htmleditor"
20690         ],
20691         "Ext.layout.component.field.Slider":["layout.sliderfield"
20692         ],
20693         "Ext.layout.component.field.Text":["layout.textfield"
20694         ],
20695         "Ext.layout.component.field.TextArea":["layout.textareafield"
20696         ],
20697         "Ext.layout.component.field.Trigger":["layout.triggerfield"
20698         ],
20699         "Ext.layout.container.Absolute":["layout.absolute"
20700         ],
20701         "Ext.layout.container.Accordion":["layout.accordion"
20702         ],
20703         "Ext.layout.container.Anchor":["layout.anchor"
20704         ],
20705         "Ext.layout.container.Border":["layout.border"
20706         ],
20707         "Ext.layout.container.Box":["layout.box"
20708         ],
20709         "Ext.layout.container.Card":["layout.card"
20710         ],
20711         "Ext.layout.container.CheckboxGroup":["layout.checkboxgroup"
20712         ],
20713         "Ext.layout.container.Column":["layout.column"
20714         ],
20715         "Ext.layout.container.Container":[""
20716         ],
20717         "Ext.layout.container.Fit":["layout.fit"
20718         ],
20719         "Ext.layout.container.HBox":["layout.hbox"
20720         ],
20721         "Ext.layout.container.Table":["layout.table"
20722         ],
20723         "Ext.layout.container.VBox":["layout.vbox"
20724         ],
20725         "Ext.layout.container.boxOverflow.Menu":[""
20726         ],
20727         "Ext.layout.container.boxOverflow.None":[""
20728         ],
20729         "Ext.layout.container.boxOverflow.Scroller":[""
20730         ],
20731         "Ext.menu.CheckItem":["widget.menucheckitem"
20732         ],
20733         "Ext.menu.ColorPicker":["widget.colormenu"
20734         ],
20735         "Ext.menu.DatePicker":["widget.datemenu"
20736         ],
20737         "Ext.menu.Item":["widget.menuitem"
20738         ],
20739         "Ext.menu.KeyNav":[""
20740         ],
20741         "Ext.menu.Manager":[""
20742         ],
20743         "Ext.menu.Menu":["widget.menu"
20744         ],
20745         "Ext.menu.Separator":["widget.menuseparator"
20746         ],
20747         "Ext.panel.DD":[""
20748         ],
20749         "Ext.panel.Header":["widget.header"
20750         ],
20751         "Ext.panel.Panel":["widget.panel"
20752         ],
20753         "Ext.panel.Proxy":[""
20754         ],
20755         "Ext.panel.Table":["widget.tablepanel"
20756         ],
20757         "Ext.panel.Tool":["widget.tool"
20758         ],
20759         "Ext.picker.Color":["widget.colorpicker"
20760         ],
20761         "Ext.picker.Date":["widget.datepicker"
20762         ],
20763         "Ext.picker.Month":["widget.monthpicker"
20764         ],
20765         "Ext.picker.Time":["widget.timepicker"
20766         ],
20767         "Ext.resizer.Handle":[""
20768         ],
20769         "Ext.resizer.Resizer":[""
20770         ],
20771         "Ext.resizer.ResizeTracker":[""
20772         ],
20773         "Ext.resizer.Splitter":["widget.splitter"
20774         ],
20775         "Ext.resizer.SplitterTracker":[""
20776         ],
20777         "Ext.selection.CellModel":["selection.cellmodel"
20778         ],
20779         "Ext.selection.CheckboxModel":["selection.checkboxmodel"
20780         ],
20781         "Ext.selection.RowModel":["selection.rowmodel"
20782         ],
20783         "Ext.selection.TreeModel":["selection.treemodel"
20784         ],
20785         "Ext.slider.Multi":["widget.multislider"
20786         ],
20787         "Ext.slider.Single":["widget.slider",
20788             "widget.sliderfield"
20789         ],
20790         "Ext.slider.Thumb":[""
20791         ],
20792         "Ext.slider.Tip":["widget.slidertip"
20793         ],
20794         "Ext.tab.Bar":["widget.tabbar"
20795         ],
20796         "Ext.tab.Panel":["widget.tabpanel"
20797         ],
20798         "Ext.tab.Tab":["widget.tab"
20799         ],
20800         "Ext.tip.QuickTip":[""
20801         ],
20802         "Ext.tip.QuickTipManager":[""
20803         ],
20804         "Ext.tip.Tip":[""
20805         ],
20806         "Ext.tip.ToolTip":["widget.tooltip"
20807         ],
20808         "Ext.toolbar.Fill":["widget.tbfill"
20809         ],
20810         "Ext.toolbar.Item":["widget.tbitem"
20811         ],
20812         "Ext.toolbar.Paging":["widget.pagingtoolbar"
20813         ],
20814         "Ext.toolbar.Separator":["widget.tbseparator"
20815         ],
20816         "Ext.toolbar.Spacer":["widget.tbspacer"
20817         ],
20818         "Ext.toolbar.TextItem":["widget.tbtext"
20819         ],
20820         "Ext.toolbar.Toolbar":["widget.toolbar"
20821         ],
20822         "Ext.tree.Column":["widget.treecolumn"
20823         ],
20824         "Ext.tree.Panel":["widget.treepanel"
20825         ],
20826         "Ext.tree.View":["widget.treeview"
20827         ],
20828         "Ext.tree.ViewDragZone":[""
20829         ],
20830         "Ext.tree.ViewDropZone":[""
20831         ],
20832         "Ext.tree.plugin.TreeViewDragDrop":["plugin.treeviewdragdrop"
20833         ],
20834         "Ext.util.Animate":[""
20835         ],
20836         "Ext.util.ClickRepeater":[""
20837         ],
20838         "Ext.util.ComponentDragger":[""
20839         ],
20840         "Ext.util.Cookies":[""
20841         ],
20842         "Ext.util.CSS":[""
20843         ],
20844         "Ext.util.Floating":[""
20845         ],
20846         "Ext.util.History":[""
20847         ],
20848         "Ext.util.KeyMap":[""
20849         ],
20850         "Ext.util.KeyNav":[""
20851         ],
20852         "Ext.util.TextMetrics":[""
20853         ],
20854         "Ext.view.BoundList":["widget.boundlist"
20855         ],
20856         "Ext.view.BoundListKeyNav":[""
20857         ],
20858         "Ext.view.DragZone":[""
20859         ],
20860         "Ext.view.DropZone":[""
20861         ],
20862         "Ext.view.Table":["widget.tableview"
20863         ],
20864         "Ext.view.TableChunker":[""
20865         ],
20866         "Ext.view.View":["widget.dataview"
20867         ],
20868         "Ext.window.MessageBox":["widget.messagebox"
20869         ],
20870         "Ext.window.Window":["widget.window"
20871         ]
20872     },
20873     "alternateToNameMap":{
20874         "Ext.ComponentMgr":"Ext.ComponentManager",
20875         "Ext.ModelMgr":"Ext.ModelManager",
20876         "Ext.PluginMgr":"Ext.PluginManager",
20877         "Ext.chart.Axis":"Ext.chart.axis.Axis",
20878         "Ext.chart.CategoryAxis":"Ext.chart.axis.Category",
20879         "Ext.chart.NumericAxis":"Ext.chart.axis.Numeric",
20880         "Ext.chart.TimeAxis":"Ext.chart.axis.Time",
20881         "Ext.chart.BarSeries":"Ext.chart.series.Bar",
20882         "Ext.chart.BarChart":"Ext.chart.series.Bar",
20883         "Ext.chart.StackedBarChart":"Ext.chart.series.Bar",
20884         "Ext.chart.CartesianSeries":"Ext.chart.series.Cartesian",
20885         "Ext.chart.CartesianChart":"Ext.chart.series.Cartesian",
20886         "Ext.chart.ColumnSeries":"Ext.chart.series.Column",
20887         "Ext.chart.ColumnChart":"Ext.chart.series.Column",
20888         "Ext.chart.StackedColumnChart":"Ext.chart.series.Column",
20889         "Ext.chart.LineSeries":"Ext.chart.series.Line",
20890         "Ext.chart.LineChart":"Ext.chart.series.Line",
20891         "Ext.chart.PieSeries":"Ext.chart.series.Pie",
20892         "Ext.chart.PieChart":"Ext.chart.series.Pie",
20893         "Ext.data.Record":"Ext.data.Model",
20894         "Ext.StoreMgr":"Ext.data.StoreManager",
20895         "Ext.data.StoreMgr":"Ext.data.StoreManager",
20896         "Ext.StoreManager":"Ext.data.StoreManager",
20897         "Ext.data.XmlStore":"Ext.data.XmlStore",
20898         "Ext.data.HttpProxy":"Ext.data.proxy.Ajax",
20899         "Ext.data.AjaxProxy":"Ext.data.proxy.Ajax",
20900         "Ext.data.ClientProxy":"Ext.data.proxy.Client",
20901         "Ext.data.DirectProxy":"Ext.data.proxy.Direct",
20902         "Ext.data.ScriptTagProxy":"Ext.data.proxy.JsonP",
20903         "Ext.data.LocalStorageProxy":"Ext.data.proxy.LocalStorage",
20904         "Ext.data.MemoryProxy":"Ext.data.proxy.Memory",
20905         "Ext.data.DataProxy":"Ext.data.proxy.Proxy",
20906         "Ext.data.Proxy":"Ext.data.proxy.Proxy",
20907         "Ext.data.RestProxy":"Ext.data.proxy.Rest",
20908         "Ext.data.ServerProxy":"Ext.data.proxy.Server",
20909         "Ext.data.SessionStorageProxy":"Ext.data.proxy.SessionStorage",
20910         "Ext.data.WebStorageProxy":"Ext.data.proxy.WebStorage",
20911         "Ext.data.ArrayReader":"Ext.data.reader.Array",
20912         "Ext.data.JsonReader":"Ext.data.reader.Json",
20913         "Ext.data.Reader":"Ext.data.reader.Reader",
20914         "Ext.data.DataReader":"Ext.data.reader.Reader",
20915         "Ext.data.XmlReader":"Ext.data.reader.Xml",
20916         "Ext.data.JsonWriter":"Ext.data.writer.Json",
20917         "Ext.data.DataWriter":"Ext.data.writer.Writer",
20918         "Ext.data.Writer":"Ext.data.writer.Writer",
20919         "Ext.data.XmlWriter":"Ext.data.writer.Xml",
20920         "Ext.Direct.Transaction":"Ext.direct.Transaction",
20921         "Ext.AbstractStoreSelectionModel":"Ext.selection.Model",
20922         "Ext.view.AbstractView":"Ext.view.AbstractView",
20923         "Ext.FocusMgr":"Ext.FocusManager",
20924         "Ext.WindowGroup":"Ext.ZIndexManager",
20925         "Ext.Button":"Ext.button.Button",
20926         "Ext.CycleButton":"Ext.button.Cycle",
20927         "Ext.SplitButton":"Ext.button.Split",
20928         "Ext.ButtonGroup":"Ext.container.ButtonGroup",
20929         "Ext.Container":"Ext.container.Container",
20930         "Ext.Viewport":"Ext.container.Viewport",
20931         "Ext.dd.DragDropMgr":"Ext.dd.DragDropManager",
20932         "Ext.dd.DDM":"Ext.dd.DragDropManager",
20933         "Ext.FlashComponent":"Ext.flash.Component",
20934         "Ext.form.BasicForm":"Ext.form.Basic",
20935         "Ext.FormPanel":"Ext.form.Panel",
20936         "Ext.form.FormPanel":"Ext.form.Panel",
20937         "Ext.form.Action":"Ext.form.action.Action",
20938         "Ext.form.Action.DirectLoad":"Ext.form.action.DirectLoad",
20939         "Ext.form.Action.DirectSubmit":"Ext.form.action.DirectSubmit",
20940         "Ext.form.Action.Load":"Ext.form.action.Load",
20941         "Ext.form.Action.Submit":"Ext.form.action.Submit",
20942         "Ext.form.Field":"Ext.form.field.Base",
20943         "Ext.form.BaseField":"Ext.form.field.Base",
20944         "Ext.form.Checkbox":"Ext.form.field.Checkbox",
20945         "Ext.form.ComboBox":"Ext.form.field.ComboBox",
20946         "Ext.form.DateField":"Ext.form.field.Date",
20947         "Ext.form.Date":"Ext.form.field.Date",
20948         "Ext.form.DisplayField":"Ext.form.field.Display",
20949         "Ext.form.Display":"Ext.form.field.Display",
20950         "Ext.form.FileUploadField":"Ext.form.field.File",
20951         "Ext.ux.form.FileUploadField":"Ext.form.field.File",
20952         "Ext.form.File":"Ext.form.field.File",
20953         "Ext.form.Hidden":"Ext.form.field.Hidden",
20954         "Ext.form.HtmlEditor":"Ext.form.field.HtmlEditor",
20955         "Ext.form.NumberField":"Ext.form.field.Number",
20956         "Ext.form.Number":"Ext.form.field.Number",
20957         "Ext.form.Picker":"Ext.form.field.Picker",
20958         "Ext.form.Radio":"Ext.form.field.Radio",
20959         "Ext.form.Spinner":"Ext.form.field.Spinner",
20960         "Ext.form.TextField":"Ext.form.field.Text",
20961         "Ext.form.Text":"Ext.form.field.Text",
20962         "Ext.form.TextArea":"Ext.form.field.TextArea",
20963         "Ext.form.TimeField":"Ext.form.field.Time",
20964         "Ext.form.Time":"Ext.form.field.Time",
20965         "Ext.form.TriggerField":"Ext.form.field.Trigger",
20966         "Ext.form.TwinTriggerField":"Ext.form.field.Trigger",
20967         "Ext.form.Trigger":"Ext.form.field.Trigger",
20968         "Ext.list.ListView":"Ext.grid.Panel",
20969         "Ext.ListView":"Ext.grid.Panel",
20970         "Ext.grid.GridPanel":"Ext.grid.Panel",
20971         "Ext.grid.ActionColumn":"Ext.grid.column.Action",
20972         "Ext.grid.BooleanColumn":"Ext.grid.column.Boolean",
20973         "Ext.grid.Column":"Ext.grid.column.Column",
20974         "Ext.grid.DateColumn":"Ext.grid.column.Date",
20975         "Ext.grid.NumberColumn":"Ext.grid.column.Number",
20976         "Ext.grid.TemplateColumn":"Ext.grid.column.Template",
20977         "Ext.grid.PropertyGrid":"Ext.grid.property.Grid",
20978         "Ext.grid.PropertyColumnModel":"Ext.grid.property.HeaderContainer",
20979         "Ext.PropGridProperty":"Ext.grid.property.Property",
20980         "Ext.grid.PropertyStore":"Ext.grid.property.Store",
20981         "Ext.layout.AbsoluteLayout":"Ext.layout.container.Absolute",
20982         "Ext.layout.AccordionLayout":"Ext.layout.container.Accordion",
20983         "Ext.layout.AnchorLayout":"Ext.layout.container.Anchor",
20984         "Ext.layout.BorderLayout":"Ext.layout.container.Border",
20985         "Ext.layout.BoxLayout":"Ext.layout.container.Box",
20986         "Ext.layout.CardLayout":"Ext.layout.container.Card",
20987         "Ext.layout.ColumnLayout":"Ext.layout.container.Column",
20988         "Ext.layout.ContainerLayout":"Ext.layout.container.Container",
20989         "Ext.layout.FitLayout":"Ext.layout.container.Fit",
20990         "Ext.layout.HBoxLayout":"Ext.layout.container.HBox",
20991         "Ext.layout.TableLayout":"Ext.layout.container.Table",
20992         "Ext.layout.VBoxLayout":"Ext.layout.container.VBox",
20993         "Ext.layout.boxOverflow.Menu":"Ext.layout.container.boxOverflow.Menu",
20994         "Ext.layout.boxOverflow.None":"Ext.layout.container.boxOverflow.None",
20995         "Ext.layout.boxOverflow.Scroller":"Ext.layout.container.boxOverflow.Scroller",
20996         "Ext.menu.TextItem":"Ext.menu.Item",
20997         "Ext.menu.MenuMgr":"Ext.menu.Manager",
20998         "Ext.Panel":"Ext.panel.Panel",
20999         "Ext.dd.PanelProxy":"Ext.panel.Proxy",
21000         "Ext.ColorPalette":"Ext.picker.Color",
21001         "Ext.DatePicker":"Ext.picker.Date",
21002         "Ext.MonthPicker":"Ext.picker.Month",
21003         "Ext.Resizable":"Ext.resizer.Resizer",
21004         "Ext.slider.MultiSlider":"Ext.slider.Multi",
21005         "Ext.Slider":"Ext.slider.Single",
21006         "Ext.form.SliderField":"Ext.slider.Single",
21007         "Ext.slider.SingleSlider":"Ext.slider.Single",
21008         "Ext.slider.Slider":"Ext.slider.Single",
21009         "Ext.TabPanel":"Ext.tab.Panel",
21010         "Ext.QuickTip":"Ext.tip.QuickTip",
21011         "Ext.Tip":"Ext.tip.Tip",
21012         "Ext.ToolTip":"Ext.tip.ToolTip",
21013         "Ext.Toolbar.Fill":"Ext.toolbar.Fill",
21014         "Ext.Toolbar.Item":"Ext.toolbar.Item",
21015         "Ext.PagingToolbar":"Ext.toolbar.Paging",
21016         "Ext.Toolbar.Separator":"Ext.toolbar.Separator",
21017         "Ext.Toolbar.Spacer":"Ext.toolbar.Spacer",
21018         "Ext.Toolbar.TextItem":"Ext.toolbar.TextItem",
21019         "Ext.Toolbar":"Ext.toolbar.Toolbar",
21020         "Ext.tree.TreePanel":"Ext.tree.Panel",
21021         "Ext.TreePanel":"Ext.tree.Panel",
21022         "Ext.History":"Ext.util.History",
21023         "Ext.KeyMap":"Ext.util.KeyMap",
21024         "Ext.KeyNav":"Ext.util.KeyNav",
21025         "Ext.BoundList":"Ext.view.BoundList",
21026         "Ext.view.View":"Ext.view.View",
21027         "Ext.MessageBox":"Ext.window.MessageBox",
21028         "Ext.Window":"Ext.window.Window"
21029     }
21030 };var scripts = document.getElementsByTagName('script'),
21031     path = '',
21032     i, ln, src, match;
21033
21034 for (i = 0, ln = scripts.length; i < ln; i++) {
21035     src = scripts[i].src;
21036
21037     match = src.match(/ext(-debug)?\.js$/);
21038
21039     if (match) {
21040         path = src.substring(0, src.length - match[0].length);
21041         break;
21042     }
21043 }
21044
21045 var nameToAliasesMap = data.nameToAliasesMap,
21046     alternateToNameMap = data.alternateToNameMap,
21047     classManager = Ext.ClassManager,
21048     name, aliases;
21049
21050 for (name in nameToAliasesMap) {
21051     if (nameToAliasesMap.hasOwnProperty(name)) {
21052         aliases = nameToAliasesMap[name];
21053
21054         if (aliases.length > 0) {
21055             for (i = 0, ln = aliases.length; i < ln; i++) {
21056                 classManager.setAlias(name, aliases[i]);
21057             }
21058         }
21059         else {
21060             classManager.setAlias(name, null);
21061         }
21062     }
21063 }
21064
21065 Ext.Object.merge(classManager.maps.alternateToName, alternateToNameMap);
21066
21067 Ext.Loader.setConfig({
21068     enabled: true,
21069     disableCaching: true,
21070     paths: {
21071         'Ext': path + 'src'
21072     }
21073 });
21074 })();
21075
21076
21077
21078