Upgrade to ExtJS 4.0.2 - Released 06/09/2011
[extjs.git] / builds / ext-core-debug.js
1 /*
2
3 This file is part of Ext JS 4
4
5 Copyright (c) 2011 Sencha Inc
6
7 Contact:  http://www.sencha.com/contact
8
9 GNU General Public License Usage
10 This file may be used under the terms of the GNU General Public License version 3.0 as published by the Free Software Foundation and appearing in the file LICENSE included in the packaging of this file.  Please review the following information to ensure the GNU General Public License version 3.0 requirements will be met: http://www.gnu.org/copyleft/gpl.html.
11
12 If you are unsure which license is appropriate for your use, please contact the sales department at http://www.sencha.com/contact.
13
14 */
15 /**
16  * @class Ext
17  * @singleton
18  */
19 (function() {
20     var global = this,
21         objectPrototype = Object.prototype,
22         toString = objectPrototype.toString,
23         enumerables = true,
24         enumerablesTest = { toString: 1 },
25         i;
26
27     if (typeof Ext === 'undefined') {
28         global.Ext = {};
29     }
30
31     Ext.global = global;
32
33     for (i in enumerablesTest) {
34         enumerables = null;
35     }
36
37     if (enumerables) {
38         enumerables = ['hasOwnProperty', 'valueOf', 'isPrototypeOf', 'propertyIsEnumerable',
39                        'toLocaleString', 'toString', 'constructor'];
40     }
41
42     /**
43      * An array containing extra enumerables for old browsers
44      * @type Array
45      */
46     Ext.enumerables = enumerables;
47
48     /**
49      * Copies all the properties of config to the specified object.
50      * Note that if recursive merging and cloning without referencing the original objects / arrays is needed, use
51      * {@link Ext.Object#merge} instead.
52      * @param {Object} object The receiver of the properties
53      * @param {Object} config The source of the properties
54      * @param {Object} defaults A different object that will also be applied for default values
55      * @return {Object} returns obj
56      */
57     Ext.apply = function(object, config, defaults) {
58         if (defaults) {
59             Ext.apply(object, defaults);
60         }
61
62         if (object && config && typeof config === 'object') {
63             var i, j, k;
64
65             for (i in config) {
66                 object[i] = config[i];
67             }
68
69             if (enumerables) {
70                 for (j = enumerables.length; j--;) {
71                     k = enumerables[j];
72                     if (config.hasOwnProperty(k)) {
73                         object[k] = config[k];
74                     }
75                 }
76             }
77         }
78
79         return object;
80     };
81
82     Ext.buildSettings = Ext.apply({
83         baseCSSPrefix: 'x-',
84         scopeResetCSS: false
85     }, Ext.buildSettings || {});
86
87     Ext.apply(Ext, {
88         /**
89          * A reusable empty function
90          */
91         emptyFn: function() {},
92
93         baseCSSPrefix: Ext.buildSettings.baseCSSPrefix,
94
95         /**
96          * Copies all the properties of config to object if they don't already exist.
97          * @param {Object} object The receiver of the properties
98          * @param {Object} config The source of the properties
99          * @return {Object} returns obj
100          */
101         applyIf: function(object, config) {
102             var property;
103
104             if (object) {
105                 for (property in config) {
106                     if (object[property] === undefined) {
107                         object[property] = config[property];
108                     }
109                 }
110             }
111
112             return object;
113         },
114
115         /**
116          * Iterates either an array or an object. This method delegates to
117          * {@link Ext.Array#each Ext.Array.each} if the given value is iterable, and {@link Ext.Object#each Ext.Object.each} otherwise.
118          *
119          * @param {Object/Array} object The object or array to be iterated.
120          * @param {Function} fn The function to be called for each iteration. See and {@link Ext.Array#each Ext.Array.each} and
121          * {@link Ext.Object#each Ext.Object.each} for detailed lists of arguments passed to this function depending on the given object
122          * type that is being iterated.
123          * @param {Object} scope (Optional) The scope (`this` reference) in which the specified function is executed.
124          * Defaults to the object being iterated itself.
125          * @markdown
126          */
127         iterate: function(object, fn, scope) {
128             if (Ext.isEmpty(object)) {
129                 return;
130             }
131
132             if (scope === undefined) {
133                 scope = object;
134             }
135
136             if (Ext.isIterable(object)) {
137                 Ext.Array.each.call(Ext.Array, object, fn, scope);
138             }
139             else {
140                 Ext.Object.each.call(Ext.Object, object, fn, scope);
141             }
142         }
143     });
144
145     Ext.apply(Ext, {
146
147         /**
148          * This method deprecated. Use {@link Ext#define Ext.define} instead.
149          * @method
150          * @param {Function} superclass
151          * @param {Object} overrides
152          * @return {Function} The subclass constructor from the <tt>overrides</tt> parameter, or a generated one if not provided.
153          * @deprecated 4.0.0 Use {@link Ext#define Ext.define} instead
154          */
155         extend: function() {
156             // inline overrides
157             var objectConstructor = objectPrototype.constructor,
158                 inlineOverrides = function(o) {
159                 for (var m in o) {
160                     if (!o.hasOwnProperty(m)) {
161                         continue;
162                     }
163                     this[m] = o[m];
164                 }
165             };
166
167             return function(subclass, superclass, overrides) {
168                 // First we check if the user passed in just the superClass with overrides
169                 if (Ext.isObject(superclass)) {
170                     overrides = superclass;
171                     superclass = subclass;
172                     subclass = overrides.constructor !== objectConstructor ? overrides.constructor : function() {
173                         superclass.apply(this, arguments);
174                     };
175                 }
176
177
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         },
328
329         /**
330          * Returns true if the passed value is empty, false otherwise. The value is deemed to be empty if it is either:
331          *
332          * - `null`
333          * - `undefined`
334          * - a zero-length array
335          * - a zero-length string (Unless the `allowEmptyString` parameter is set to `true`)
336          *
337          * @param {Mixed} value The value to test
338          * @param {Boolean} allowEmptyString (optional) true to allow empty strings (defaults to false)
339          * @return {Boolean}
340          * @markdown
341          */
342         isEmpty: function(value, allowEmptyString) {
343             return (value === null) || (value === undefined) || (!allowEmptyString ? value === '' : false) || (Ext.isArray(value) && value.length === 0);
344         },
345
346         /**
347          * Returns true if the passed value is a JavaScript Array, false otherwise.
348          *
349          * @param {Mixed} target The target to test
350          * @return {Boolean}
351          * @method
352          */
353         isArray: ('isArray' in Array) ? Array.isArray : function(value) {
354             return toString.call(value) === '[object Array]';
355         },
356
357         /**
358          * Returns true if the passed value is a JavaScript Date object, false otherwise.
359          * @param {Object} object The object to test
360          * @return {Boolean}
361          */
362         isDate: function(value) {
363             return toString.call(value) === '[object Date]';
364         },
365
366         /**
367          * Returns true if the passed value is a JavaScript Object, false otherwise.
368          * @param {Mixed} value The value to test
369          * @return {Boolean}
370          * @method
371          */
372         isObject: (toString.call(null) === '[object Object]') ?
373         function(value) {
374             // check ownerDocument here as well to exclude DOM nodes
375             return value !== null && value !== undefined && toString.call(value) === '[object Object]' && value.ownerDocument === undefined;
376         } :
377         function(value) {
378             return toString.call(value) === '[object Object]';
379         },
380
381         /**
382          * Returns true if the passed value is a JavaScript 'primitive', a string, number or boolean.
383          * @param {Mixed} value The value to test
384          * @return {Boolean}
385          */
386         isPrimitive: function(value) {
387             var type = typeof value;
388
389             return type === 'string' || type === 'number' || type === 'boolean';
390         },
391
392         /**
393          * Returns true if the passed value is a JavaScript Function, false otherwise.
394          * @param {Mixed} value The value to test
395          * @return {Boolean}
396          * @method
397          */
398         isFunction:
399         // Safari 3.x and 4.x returns 'function' for typeof <NodeList>, hence we need to fall back to using
400         // Object.prorotype.toString (slower)
401         (typeof document !== 'undefined' && typeof document.getElementsByTagName('body') === 'function') ? function(value) {
402             return toString.call(value) === '[object Function]';
403         } : function(value) {
404             return typeof value === 'function';
405         },
406
407         /**
408          * Returns true if the passed value is a number. Returns false for non-finite numbers.
409          * @param {Mixed} value The value to test
410          * @return {Boolean}
411          */
412         isNumber: function(value) {
413             return typeof value === 'number' && isFinite(value);
414         },
415
416         /**
417          * Validates that a value is numeric.
418          * @param {Mixed} value Examples: 1, '1', '2.34'
419          * @return {Boolean} True if numeric, false otherwise
420          */
421         isNumeric: function(value) {
422             return !isNaN(parseFloat(value)) && isFinite(value);
423         },
424
425         /**
426          * Returns true if the passed value is a string.
427          * @param {Mixed} value The value to test
428          * @return {Boolean}
429          */
430         isString: function(value) {
431             return typeof value === 'string';
432         },
433
434         /**
435          * Returns true if the passed value is a boolean.
436          *
437          * @param {Mixed} value The value to test
438          * @return {Boolean}
439          */
440         isBoolean: function(value) {
441             return typeof value === 'boolean';
442         },
443
444         /**
445          * Returns true if the passed value is an HTMLElement
446          * @param {Mixed} value The value to test
447          * @return {Boolean}
448          */
449         isElement: function(value) {
450             return value ? value.nodeType === 1 : false;
451         },
452
453         /**
454          * Returns true if the passed value is a TextNode
455          * @param {Mixed} value The value to test
456          * @return {Boolean}
457          */
458         isTextNode: function(value) {
459             return value ? value.nodeName === "#text" : false;
460         },
461
462         /**
463          * Returns true if the passed value is defined.
464          * @param {Mixed} value The value to test
465          * @return {Boolean}
466          */
467         isDefined: function(value) {
468             return typeof value !== 'undefined';
469         },
470
471         /**
472          * Returns true if the passed value is iterable, false otherwise
473          * @param {Mixed} value The value to test
474          * @return {Boolean}
475          */
476         isIterable: function(value) {
477             return (value && typeof value !== 'string') ? value.length !== undefined : false;
478         }
479     });
480
481     Ext.apply(Ext, {
482
483         /**
484          * Clone almost any type of variable including array, object, DOM nodes and Date without keeping the old reference
485          * @param {Mixed} item The variable to clone
486          * @return {Mixed} clone
487          */
488         clone: function(item) {
489             if (item === null || item === undefined) {
490                 return item;
491             }
492
493             // DOM nodes
494             // TODO proxy this to Ext.Element.clone to handle automatic id attribute changing
495             // recursively
496             if (item.nodeType && item.cloneNode) {
497                 return item.cloneNode(true);
498             }
499
500             var type = toString.call(item);
501
502             // Date
503             if (type === '[object Date]') {
504                 return new Date(item.getTime());
505             }
506
507             var i, j, k, clone, key;
508
509             // Array
510             if (type === '[object Array]') {
511                 i = item.length;
512
513                 clone = [];
514
515                 while (i--) {
516                     clone[i] = Ext.clone(item[i]);
517                 }
518             }
519             // Object
520             else if (type === '[object Object]' && item.constructor === Object) {
521                 clone = {};
522
523                 for (key in item) {
524                     clone[key] = Ext.clone(item[key]);
525                 }
526
527                 if (enumerables) {
528                     for (j = enumerables.length; j--;) {
529                         k = enumerables[j];
530                         clone[k] = item[k];
531                     }
532                 }
533             }
534
535             return clone || item;
536         },
537
538         /**
539          * @private
540          * Generate a unique reference of Ext in the global scope, useful for sandboxing
541          */
542         getUniqueGlobalNamespace: function() {
543             var uniqueGlobalNamespace = this.uniqueGlobalNamespace;
544
545             if (uniqueGlobalNamespace === undefined) {
546                 var i = 0;
547
548                 do {
549                     uniqueGlobalNamespace = 'ExtBox' + (++i);
550                 } while (Ext.global[uniqueGlobalNamespace] !== undefined);
551
552                 Ext.global[uniqueGlobalNamespace] = Ext;
553                 this.uniqueGlobalNamespace = uniqueGlobalNamespace;
554             }
555
556             return uniqueGlobalNamespace;
557         },
558
559         /**
560          * @private
561          */
562         functionFactory: function() {
563             var args = Array.prototype.slice.call(arguments);
564
565             if (args.length > 0) {
566                 args[args.length - 1] = 'var Ext=window.' + this.getUniqueGlobalNamespace() + ';' +
567                     args[args.length - 1];
568             }
569
570             return Function.prototype.constructor.apply(Function.prototype, args);
571         }
572     });
573
574     /**
575      * Old alias to {@link Ext#typeOf}
576      * @deprecated 4.0.0 Use {@link Ext#typeOf} instead
577      * @method
578      * @alias Ext#typeOf
579      */
580     Ext.type = Ext.typeOf;
581
582 })();
583
584 /**
585  * @author Jacky Nguyen <jacky@sencha.com>
586  * @docauthor Jacky Nguyen <jacky@sencha.com>
587  * @class Ext.Version
588  *
589  * A utility class that wrap around a string version number and provide convenient
590  * method to perform comparison. See also: {@link Ext.Version#compare compare}. Example:
591
592     var version = new Ext.Version('1.0.2beta');
593     console.log("Version is " + version); // Version is 1.0.2beta
594
595     console.log(version.getMajor()); // 1
596     console.log(version.getMinor()); // 0
597     console.log(version.getPatch()); // 2
598     console.log(version.getBuild()); // 0
599     console.log(version.getRelease()); // beta
600
601     console.log(version.isGreaterThan('1.0.1')); // True
602     console.log(version.isGreaterThan('1.0.2alpha')); // True
603     console.log(version.isGreaterThan('1.0.2RC')); // False
604     console.log(version.isGreaterThan('1.0.2')); // False
605     console.log(version.isLessThan('1.0.2')); // True
606
607     console.log(version.match(1.0)); // True
608     console.log(version.match('1.0.2')); // True
609
610  * @markdown
611  */
612 (function() {
613
614 // Current core version
615 var version = '4.0.2', Version;
616     Ext.Version = Version = Ext.extend(Object, {
617
618         /**
619          * @param {String/Number} version The version number in the follow standard format: major[.minor[.patch[.build[release]]]]
620          * Examples: 1.0 or 1.2.3beta or 1.2.3.4RC
621          * @return {Ext.Version} this
622          */
623         constructor: function(version) {
624             var parts, releaseStartIndex;
625
626             if (version instanceof Version) {
627                 return version;
628             }
629
630             this.version = this.shortVersion = String(version).toLowerCase().replace(/_/g, '.').replace(/[\-+]/g, '');
631
632             releaseStartIndex = this.version.search(/([^\d\.])/);
633
634             if (releaseStartIndex !== -1) {
635                 this.release = this.version.substr(releaseStartIndex, version.length);
636                 this.shortVersion = this.version.substr(0, releaseStartIndex);
637             }
638
639             this.shortVersion = this.shortVersion.replace(/[^\d]/g, '');
640
641             parts = this.version.split('.');
642
643             this.major = parseInt(parts.shift() || 0, 10);
644             this.minor = parseInt(parts.shift() || 0, 10);
645             this.patch = parseInt(parts.shift() || 0, 10);
646             this.build = parseInt(parts.shift() || 0, 10);
647
648             return this;
649         },
650
651         /**
652          * Override the native toString method
653          * @private
654          * @return {String} version
655          */
656         toString: function() {
657             return this.version;
658         },
659
660         /**
661          * Override the native valueOf method
662          * @private
663          * @return {String} version
664          */
665         valueOf: function() {
666             return this.version;
667         },
668
669         /**
670          * Returns the major component value
671          * @return {Number} major
672          */
673         getMajor: function() {
674             return this.major || 0;
675         },
676
677         /**
678          * Returns the minor component value
679          * @return {Number} minor
680          */
681         getMinor: function() {
682             return this.minor || 0;
683         },
684
685         /**
686          * Returns the patch component value
687          * @return {Number} patch
688          */
689         getPatch: function() {
690             return this.patch || 0;
691         },
692
693         /**
694          * Returns the build component value
695          * @return {Number} build
696          */
697         getBuild: function() {
698             return this.build || 0;
699         },
700
701         /**
702          * Returns the release component value
703          * @return {Number} release
704          */
705         getRelease: function() {
706             return this.release || '';
707         },
708
709         /**
710          * Returns whether this version if greater than the supplied argument
711          * @param {String/Number} target The version to compare with
712          * @return {Boolean} True if this version if greater than the target, false otherwise
713          */
714         isGreaterThan: function(target) {
715             return Version.compare(this.version, target) === 1;
716         },
717
718         /**
719          * Returns whether this version if smaller than the supplied argument
720          * @param {String/Number} target The version to compare with
721          * @return {Boolean} True if this version if smaller than the target, false otherwise
722          */
723         isLessThan: function(target) {
724             return Version.compare(this.version, target) === -1;
725         },
726
727         /**
728          * Returns whether this version equals to the supplied argument
729          * @param {String/Number} target The version to compare with
730          * @return {Boolean} True if this version equals to the target, false otherwise
731          */
732         equals: function(target) {
733             return Version.compare(this.version, target) === 0;
734         },
735
736         /**
737          * Returns whether this version matches the supplied argument. Example:
738          * <pre><code>
739          * var version = new Ext.Version('1.0.2beta');
740          * console.log(version.match(1)); // True
741          * console.log(version.match(1.0)); // True
742          * console.log(version.match('1.0.2')); // True
743          * console.log(version.match('1.0.2RC')); // False
744          * </code></pre>
745          * @param {String/Number} target The version to compare with
746          * @return {Boolean} True if this version matches the target, false otherwise
747          */
748         match: function(target) {
749             target = String(target);
750             return this.version.substr(0, target.length) === target;
751         },
752
753         /**
754          * Returns this format: [major, minor, patch, build, release]. Useful for comparison
755          * @return {Array}
756          */
757         toArray: function() {
758             return [this.getMajor(), this.getMinor(), this.getPatch(), this.getBuild(), this.getRelease()];
759         },
760
761         /**
762          * Returns shortVersion version without dots and release
763          * @return {String}
764          */
765         getShortVersion: function() {
766             return this.shortVersion;
767         }
768     });
769
770     Ext.apply(Version, {
771         // @private
772         releaseValueMap: {
773             'dev': -6,
774             'alpha': -5,
775             'a': -5,
776             'beta': -4,
777             'b': -4,
778             'rc': -3,
779             '#': -2,
780             'p': -1,
781             'pl': -1
782         },
783
784         /**
785          * Converts a version component to a comparable value
786          *
787          * @static
788          * @param {Mixed} value The value to convert
789          * @return {Mixed}
790          */
791         getComponentValue: function(value) {
792             return !value ? 0 : (isNaN(value) ? this.releaseValueMap[value] || value : parseInt(value, 10));
793         },
794
795         /**
796          * Compare 2 specified versions, starting from left to right. If a part contains special version strings,
797          * they are handled in the following order:
798          * 'dev' < 'alpha' = 'a' < 'beta' = 'b' < 'RC' = 'rc' < '#' < 'pl' = 'p' < 'anything else'
799          *
800          * @static
801          * @param {String} current The current version to compare to
802          * @param {String} target The target version to compare to
803          * @return {Number} Returns -1 if the current version is smaller than the target version, 1 if greater, and 0 if they're equivalent
804          */
805         compare: function(current, target) {
806             var currentValue, targetValue, i;
807
808             current = new Version(current).toArray();
809             target = new Version(target).toArray();
810
811             for (i = 0; i < Math.max(current.length, target.length); i++) {
812                 currentValue = this.getComponentValue(current[i]);
813                 targetValue = this.getComponentValue(target[i]);
814
815                 if (currentValue < targetValue) {
816                     return -1;
817                 } else if (currentValue > targetValue) {
818                     return 1;
819                 }
820             }
821
822             return 0;
823         }
824     });
825
826     Ext.apply(Ext, {
827         /**
828          * @private
829          */
830         versions: {},
831
832         /**
833          * @private
834          */
835         lastRegisteredVersion: null,
836
837         /**
838          * Set version number for the given package name.
839          *
840          * @param {String} packageName The package name, for example: 'core', 'touch', 'extjs'
841          * @param {String/Ext.Version} version The version, for example: '1.2.3alpha', '2.4.0-dev'
842          * @return {Ext}
843          */
844         setVersion: function(packageName, version) {
845             Ext.versions[packageName] = new Version(version);
846             Ext.lastRegisteredVersion = Ext.versions[packageName];
847
848             return this;
849         },
850
851         /**
852          * Get the version number of the supplied package name; will return the last registered version
853          * (last Ext.setVersion call) if there's no package name given.
854          *
855          * @param {String} packageName (Optional) The package name, for example: 'core', 'touch', 'extjs'
856          * @return {Ext.Version} The version
857          */
858         getVersion: function(packageName) {
859             if (packageName === undefined) {
860                 return Ext.lastRegisteredVersion;
861             }
862
863             return Ext.versions[packageName];
864         },
865
866         /**
867          * Create a closure for deprecated code.
868          *
869     // This means Ext.oldMethod is only supported in 4.0.0beta and older.
870     // If Ext.getVersion('extjs') returns a version that is later than '4.0.0beta', for example '4.0.0RC',
871     // the closure will not be invoked
872     Ext.deprecate('extjs', '4.0.0beta', function() {
873         Ext.oldMethod = Ext.newMethod;
874
875         ...
876     });
877
878          * @param {String} packageName The package name
879          * @param {String} since The last version before it's deprecated
880          * @param {Function} closure The callback function to be executed with the specified version is less than the current version
881          * @param {Object} scope The execution scope (<tt>this</tt>) if the closure
882          * @markdown
883          */
884         deprecate: function(packageName, since, closure, scope) {
885             if (Version.compare(Ext.getVersion(packageName), since) < 1) {
886                 closure.call(scope);
887             }
888         }
889     }); // End Versioning
890
891     Ext.setVersion('core', version);
892
893 })();
894
895 /**
896  * @class Ext.String
897  *
898  * A collection of useful static methods to deal with strings
899  * @singleton
900  */
901
902 Ext.String = {
903     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,
904     escapeRe: /('|\\)/g,
905     formatRe: /\{(\d+)\}/g,
906     escapeRegexRe: /([-.*+?^${}()|[\]\/\\])/g,
907
908     /**
909      * Convert certain characters (&, <, >, and ') to their HTML character equivalents for literal display in web pages.
910      * @param {String} value The string to encode
911      * @return {String} The encoded text
912      * @method
913      */
914     htmlEncode: (function() {
915         var entities = {
916             '&': '&amp;',
917             '>': '&gt;',
918             '<': '&lt;',
919             '"': '&quot;'
920         }, keys = [], p, regex;
921         
922         for (p in entities) {
923             keys.push(p);
924         }
925         
926         regex = new RegExp('(' + keys.join('|') + ')', 'g');
927         
928         return function(value) {
929             return (!value) ? value : String(value).replace(regex, function(match, capture) {
930                 return entities[capture];    
931             });
932         };
933     })(),
934
935     /**
936      * Convert certain characters (&, <, >, and ') from their HTML character equivalents.
937      * @param {String} value The string to decode
938      * @return {String} The decoded text
939      * @method
940      */
941     htmlDecode: (function() {
942         var entities = {
943             '&amp;': '&',
944             '&gt;': '>',
945             '&lt;': '<',
946             '&quot;': '"'
947         }, keys = [], p, regex;
948         
949         for (p in entities) {
950             keys.push(p);
951         }
952         
953         regex = new RegExp('(' + keys.join('|') + '|&#[0-9]{1,5};' + ')', 'g');
954         
955         return function(value) {
956             return (!value) ? value : String(value).replace(regex, function(match, capture) {
957                 if (capture in entities) {
958                     return entities[capture];
959                 } else {
960                     return String.fromCharCode(parseInt(capture.substr(2), 10));
961                 }
962             });
963         };
964     })(),
965
966     /**
967      * Appends content to the query string of a URL, handling logic for whether to place
968      * a question mark or ampersand.
969      * @param {String} url The URL to append to.
970      * @param {String} string The content to append to the URL.
971      * @return (String) The resulting URL
972      */
973     urlAppend : function(url, string) {
974         if (!Ext.isEmpty(string)) {
975             return url + (url.indexOf('?') === -1 ? '?' : '&') + string;
976         }
977
978         return url;
979     },
980
981     /**
982      * Trims whitespace from either end of a string, leaving spaces within the string intact.  Example:
983      * @example
984 var s = '  foo bar  ';
985 alert('-' + s + '-');         //alerts "- foo bar -"
986 alert('-' + Ext.String.trim(s) + '-');  //alerts "-foo bar-"
987
988      * @param {String} string The string to escape
989      * @return {String} The trimmed string
990      */
991     trim: function(string) {
992         return string.replace(Ext.String.trimRegex, "");
993     },
994
995     /**
996      * Capitalize the given string
997      * @param {String} string
998      * @return {String}
999      */
1000     capitalize: function(string) {
1001         return string.charAt(0).toUpperCase() + string.substr(1);
1002     },
1003
1004     /**
1005      * Truncate a string and add an ellipsis ('...') to the end if it exceeds the specified length
1006      * @param {String} value The string to truncate
1007      * @param {Number} length The maximum length to allow before truncating
1008      * @param {Boolean} word True to try to find a common word break
1009      * @return {String} The converted text
1010      */
1011     ellipsis: function(value, len, word) {
1012         if (value && value.length > len) {
1013             if (word) {
1014                 var vs = value.substr(0, len - 2),
1015                 index = Math.max(vs.lastIndexOf(' '), vs.lastIndexOf('.'), vs.lastIndexOf('!'), vs.lastIndexOf('?'));
1016                 if (index !== -1 && index >= (len - 15)) {
1017                     return vs.substr(0, index) + "...";
1018                 }
1019             }
1020             return value.substr(0, len - 3) + "...";
1021         }
1022         return value;
1023     },
1024
1025     /**
1026      * Escapes the passed string for use in a regular expression
1027      * @param {String} string
1028      * @return {String}
1029      */
1030     escapeRegex: function(string) {
1031         return string.replace(Ext.String.escapeRegexRe, "\\$1");
1032     },
1033
1034     /**
1035      * Escapes the passed string for ' and \
1036      * @param {String} string The string to escape
1037      * @return {String} The escaped string
1038      */
1039     escape: function(string) {
1040         return string.replace(Ext.String.escapeRe, "\\$1");
1041     },
1042
1043     /**
1044      * Utility function that allows you to easily switch a string between two alternating values.  The passed value
1045      * is compared to the current string, and if they are equal, the other value that was passed in is returned.  If
1046      * they are already different, the first value passed in is returned.  Note that this method returns the new value
1047      * but does not change the current string.
1048      * <pre><code>
1049     // alternate sort directions
1050     sort = Ext.String.toggle(sort, 'ASC', 'DESC');
1051
1052     // instead of conditional logic:
1053     sort = (sort == 'ASC' ? 'DESC' : 'ASC');
1054        </code></pre>
1055      * @param {String} string The current string
1056      * @param {String} value The value to compare to the current string
1057      * @param {String} other The new value to use if the string already equals the first value passed in
1058      * @return {String} The new value
1059      */
1060     toggle: function(string, value, other) {
1061         return string === value ? other : value;
1062     },
1063
1064     /**
1065      * Pads the left side of a string with a specified character.  This is especially useful
1066      * for normalizing number and date strings.  Example usage:
1067      *
1068      * <pre><code>
1069 var s = Ext.String.leftPad('123', 5, '0');
1070 // s now contains the string: '00123'
1071        </code></pre>
1072      * @param {String} string The original string
1073      * @param {Number} size The total length of the output string
1074      * @param {String} character (optional) The character with which to pad the original string (defaults to empty string " ")
1075      * @return {String} The padded string
1076      */
1077     leftPad: function(string, size, character) {
1078         var result = String(string);
1079         character = character || " ";
1080         while (result.length < size) {
1081             result = character + result;
1082         }
1083         return result;
1084     },
1085
1086     /**
1087      * Allows you to define a tokenized string and pass an arbitrary number of arguments to replace the tokens.  Each
1088      * token must be unique, and must increment in the format {0}, {1}, etc.  Example usage:
1089      * <pre><code>
1090 var cls = 'my-class', text = 'Some text';
1091 var s = Ext.String.format('&lt;div class="{0}">{1}&lt;/div>', cls, text);
1092 // s now contains the string: '&lt;div class="my-class">Some text&lt;/div>'
1093        </code></pre>
1094      * @param {String} string The tokenized string to be formatted
1095      * @param {String} value1 The value to replace token {0}
1096      * @param {String} value2 Etc...
1097      * @return {String} The formatted string
1098      */
1099     format: function(format) {
1100         var args = Ext.Array.toArray(arguments, 1);
1101         return format.replace(Ext.String.formatRe, function(m, i) {
1102             return args[i];
1103         });
1104     }
1105 };
1106
1107 /**
1108  * @class Ext.Number
1109  *
1110  * A collection of useful static methods to deal with numbers
1111  * @singleton
1112  */
1113
1114 (function() {
1115
1116 var isToFixedBroken = (0.9).toFixed() !== '1';
1117
1118 Ext.Number = {
1119     /**
1120      * Checks whether or not the passed number is within a desired range.  If the number is already within the
1121      * range it is returned, otherwise the min or max value is returned depending on which side of the range is
1122      * exceeded. Note that this method returns the constrained value but does not change the current number.
1123      * @param {Number} number The number to check
1124      * @param {Number} min The minimum number in the range
1125      * @param {Number} max The maximum number in the range
1126      * @return {Number} The constrained value if outside the range, otherwise the current value
1127      */
1128     constrain: function(number, min, max) {
1129         number = parseFloat(number);
1130
1131         if (!isNaN(min)) {
1132             number = Math.max(number, min);
1133         }
1134         if (!isNaN(max)) {
1135             number = Math.min(number, max);
1136         }
1137         return number;
1138     },
1139
1140     /**
1141      * Snaps the passed number between stopping points based upon a passed increment value.
1142      * @param {Number} value The unsnapped value.
1143      * @param {Number} increment The increment by which the value must move.
1144      * @param {Number} minValue The minimum value to which the returned value must be constrained. Overrides the increment..
1145      * @param {Number} maxValue The maximum value to which the returned value must be constrained. Overrides the increment..
1146      * @return {Number} The value of the nearest snap target.
1147      */
1148     snap : function(value, increment, minValue, maxValue) {
1149         var newValue = value,
1150             m;
1151
1152         if (!(increment && value)) {
1153             return value;
1154         }
1155         m = value % increment;
1156         if (m !== 0) {
1157             newValue -= m;
1158             if (m * 2 >= increment) {
1159                 newValue += increment;
1160             } else if (m * 2 < -increment) {
1161                 newValue -= increment;
1162             }
1163         }
1164         return Ext.Number.constrain(newValue, minValue,  maxValue);
1165     },
1166
1167     /**
1168      * Formats a number using fixed-point notation
1169      * @param {Number} value The number to format
1170      * @param {Number} precision The number of digits to show after the decimal point
1171      */
1172     toFixed: function(value, precision) {
1173         if (isToFixedBroken) {
1174             precision = precision || 0;
1175             var pow = Math.pow(10, precision);
1176             return (Math.round(value * pow) / pow).toFixed(precision);
1177         }
1178
1179         return value.toFixed(precision);
1180     },
1181
1182     /**
1183      * Validate that a value is numeric and convert it to a number if necessary. Returns the specified default value if
1184      * it is not.
1185
1186 Ext.Number.from('1.23', 1); // returns 1.23
1187 Ext.Number.from('abc', 1); // returns 1
1188
1189      * @param {Mixed} value
1190      * @param {Number} defaultValue The value to return if the original value is non-numeric
1191      * @return {Number} value, if numeric, defaultValue otherwise
1192      */
1193     from: function(value, defaultValue) {
1194         if (isFinite(value)) {
1195             value = parseFloat(value);
1196         }
1197
1198         return !isNaN(value) ? value : defaultValue;
1199     }
1200 };
1201
1202 })();
1203
1204 /**
1205  * This method is deprecated, please use {@link Ext.Number#from Ext.Number.from} instead
1206  *
1207  * @deprecated 4.0.0 Replaced by Ext.Number.from
1208  * @member Ext
1209  * @method num
1210  */
1211 Ext.num = function() {
1212     return Ext.Number.from.apply(this, arguments);
1213 };
1214 /**
1215  * @author Jacky Nguyen <jacky@sencha.com>
1216  * @docauthor Jacky Nguyen <jacky@sencha.com>
1217  * @class Ext.Array
1218  *
1219  * A set of useful static methods to deal with arrays; provide missing methods for older browsers.
1220
1221  * @singleton
1222  * @markdown
1223  */
1224 (function() {
1225
1226     var arrayPrototype = Array.prototype,
1227         slice = arrayPrototype.slice,
1228         supportsSplice = function () {
1229             var array = [],
1230                 lengthBefore,
1231                 j = 20;
1232
1233             if (!array.splice) {
1234                 return false;
1235             }
1236
1237             // This detects a bug in IE8 splice method:
1238             // see http://social.msdn.microsoft.com/Forums/en-US/iewebdevelopment/thread/6e946d03-e09f-4b22-a4dd-cd5e276bf05a/
1239
1240             while (j--) {
1241                 array.push("A");
1242             }
1243
1244             array.splice(15, 0, "F", "F", "F", "F", "F","F","F","F","F","F","F","F","F","F","F","F","F","F","F","F","F");
1245
1246             lengthBefore = array.length; //41
1247             array.splice(13, 0, "XXX"); // add one element
1248
1249             if (lengthBefore+1 != array.length) {
1250                 return false;
1251             }
1252             // end IE8 bug
1253
1254             return true;
1255         }(),
1256         supportsForEach = 'forEach' in arrayPrototype,
1257         supportsMap = 'map' in arrayPrototype,
1258         supportsIndexOf = 'indexOf' in arrayPrototype,
1259         supportsEvery = 'every' in arrayPrototype,
1260         supportsSome = 'some' in arrayPrototype,
1261         supportsFilter = 'filter' in arrayPrototype,
1262         supportsSort = function() {
1263             var a = [1,2,3,4,5].sort(function(){ return 0; });
1264             return a[0] === 1 && a[1] === 2 && a[2] === 3 && a[3] === 4 && a[4] === 5;
1265         }(),
1266         supportsSliceOnNodeList = true,
1267         ExtArray;
1268
1269     try {
1270         // IE 6 - 8 will throw an error when using Array.prototype.slice on NodeList
1271         if (typeof document !== 'undefined') {
1272             slice.call(document.getElementsByTagName('body'));
1273         }
1274     } catch (e) {
1275         supportsSliceOnNodeList = false;
1276     }
1277
1278     function fixArrayIndex (array, index) {
1279         return (index < 0) ? Math.max(0, array.length + index)
1280                            : Math.min(array.length, index);
1281     }
1282
1283     /*
1284     Does the same work as splice, but with a slightly more convenient signature. The splice
1285     method has bugs in IE8, so this is the implementation we use on that platform.
1286
1287     The rippling of items in the array can be tricky. Consider two use cases:
1288
1289                   index=2
1290                   removeCount=2
1291                  /=====\
1292         +---+---+---+---+---+---+---+---+
1293         | 0 | 1 | 2 | 3 | 4 | 5 | 6 | 7 |
1294         +---+---+---+---+---+---+---+---+
1295                          /  \/  \/  \/  \
1296                         /   /\  /\  /\   \
1297                        /   /  \/  \/  \   +--------------------------+
1298                       /   /   /\  /\   +--------------------------+   \
1299                      /   /   /  \/  +--------------------------+   \   \
1300                     /   /   /   /+--------------------------+   \   \   \
1301                    /   /   /   /                             \   \   \   \
1302                   v   v   v   v                               v   v   v   v
1303         +---+---+---+---+---+---+       +---+---+---+---+---+---+---+---+---+
1304         | 0 | 1 | 4 | 5 | 6 | 7 |       | 0 | 1 | a | b | c | 4 | 5 | 6 | 7 |
1305         +---+---+---+---+---+---+       +---+---+---+---+---+---+---+---+---+
1306         A                               B        \=========/
1307                                                  insert=[a,b,c]
1308
1309     In case A, it is obvious that copying of [4,5,6,7] must be left-to-right so
1310     that we don't end up with [0,1,6,7,6,7]. In case B, we have the opposite; we
1311     must go right-to-left or else we would end up with [0,1,a,b,c,4,4,4,4].
1312     */
1313     function replaceSim (array, index, removeCount, insert) {
1314         var add = insert ? insert.length : 0,
1315             length = array.length,
1316             pos = fixArrayIndex(array, index);
1317
1318         // we try to use Array.push when we can for efficiency...
1319         if (pos === length) {
1320             if (add) {
1321                 array.push.apply(array, insert);
1322             }
1323         } else {
1324             var remove = Math.min(removeCount, length - pos),
1325                 tailOldPos = pos + remove,
1326                 tailNewPos = tailOldPos + add - remove,
1327                 tailCount = length - tailOldPos,
1328                 lengthAfterRemove = length - remove,
1329                 i;
1330
1331             if (tailNewPos < tailOldPos) { // case A
1332                 for (i = 0; i < tailCount; ++i) {
1333                     array[tailNewPos+i] = array[tailOldPos+i];
1334                 }
1335             } else if (tailNewPos > tailOldPos) { // case B
1336                 for (i = tailCount; i--; ) {
1337                     array[tailNewPos+i] = array[tailOldPos+i];
1338                 }
1339             } // else, add == remove (nothing to do)
1340
1341             if (add && pos === lengthAfterRemove) {
1342                 array.length = lengthAfterRemove; // truncate array
1343                 array.push.apply(array, insert);
1344             } else {
1345                 array.length = lengthAfterRemove + add; // reserves space
1346                 for (i = 0; i < add; ++i) {
1347                     array[pos+i] = insert[i];
1348                 }
1349             }
1350         }
1351
1352         return array;
1353     }
1354
1355     function replaceNative (array, index, removeCount, insert) {
1356         if (insert && insert.length) {
1357             if (index < array.length) {
1358                 array.splice.apply(array, [index, removeCount].concat(insert));
1359             } else {
1360                 array.push.apply(array, insert);
1361             }
1362         } else {
1363             array.splice(index, removeCount);
1364         }
1365         return array;
1366     }
1367
1368     function eraseSim (array, index, removeCount) {
1369         return replaceSim(array, index, removeCount);
1370     }
1371
1372     function eraseNative (array, index, removeCount) {
1373         array.splice(index, removeCount);
1374         return array;
1375     }
1376
1377     function spliceSim (array, index, removeCount) {
1378         var pos = fixArrayIndex(array, index),
1379             removed = array.slice(index, fixArrayIndex(array, pos+removeCount));
1380
1381         if (arguments.length < 4) {
1382             replaceSim(array, pos, removeCount);
1383         } else {
1384             replaceSim(array, pos, removeCount, slice.call(arguments, 3));
1385         }
1386
1387         return removed;
1388     }
1389
1390     function spliceNative (array) {
1391         return array.splice.apply(array, slice.call(arguments, 1));
1392     }
1393
1394     var erase = supportsSplice ? eraseNative : eraseSim,
1395         replace = supportsSplice ? replaceNative : replaceSim,
1396         splice = supportsSplice ? spliceNative : spliceSim;
1397
1398     // NOTE: from here on, use erase, replace or splice (not native methods)...
1399
1400     ExtArray = Ext.Array = {
1401         /**
1402          * Iterates an array or an iterable value and invoke the given callback function for each item.
1403          *
1404          *     var countries = ['Vietnam', 'Singapore', 'United States', 'Russia'];
1405          *
1406          *     Ext.Array.each(countries, function(name, index, countriesItSelf) {
1407          *         console.log(name);
1408          *     });
1409          *
1410          *     var sum = function() {
1411          *         var sum = 0;
1412          *
1413          *         Ext.Array.each(arguments, function(value) {
1414          *             sum += value;
1415          *         });
1416          *
1417          *         return sum;
1418          *     };
1419          *
1420          *     sum(1, 2, 3); // returns 6
1421          *
1422          * The iteration can be stopped by returning false in the function callback.
1423          *
1424          *     Ext.Array.each(countries, function(name, index, countriesItSelf) {
1425          *         if (name === 'Singapore') {
1426          *             return false; // break here
1427          *         }
1428          *     });
1429          *
1430          * {@link Ext#each Ext.each} is alias for {@link Ext.Array#each Ext.Array.each}
1431          *
1432          * @param {Array/NodeList/Mixed} iterable The value to be iterated. If this
1433          * argument is not iterable, the callback function is called once.
1434          * @param {Function} fn The callback function. If it returns false, the iteration stops and this method returns
1435          * the current `index`. Arguments passed to this callback function are:
1436          *
1437          * - `item` : Mixed - The item at the current `index` in the passed `array`
1438          * - `index` : Number - The current `index` within the `array`
1439          * - `allItems` : Array/NodeList/Mixed - The `array` passed as the first argument to `Ext.Array.each`
1440          *
1441          * @param {Object} scope (Optional) The scope (`this` reference) in which the specified function is executed.
1442          * @param {Boolean} reverse (Optional) Reverse the iteration order (loop from the end to the beginning)
1443          * Defaults false
1444          * @return {Boolean} See description for the `fn` parameter.
1445          */
1446         each: function(array, fn, scope, reverse) {
1447             array = ExtArray.from(array);
1448
1449             var i,
1450                 ln = array.length;
1451
1452             if (reverse !== true) {
1453                 for (i = 0; i < ln; i++) {
1454                     if (fn.call(scope || array[i], array[i], i, array) === false) {
1455                         return i;
1456                     }
1457                 }
1458             }
1459             else {
1460                 for (i = ln - 1; i > -1; i--) {
1461                     if (fn.call(scope || array[i], array[i], i, array) === false) {
1462                         return i;
1463                     }
1464                 }
1465             }
1466
1467             return true;
1468         },
1469
1470         /**
1471          * Iterates an array and invoke the given callback function for each item. Note that this will simply
1472          * delegate to the native Array.prototype.forEach method if supported.
1473          * It doesn't support stopping the iteration by returning false in the callback function like
1474          * {@link Ext.Array#each}. However, performance could be much better in modern browsers comparing with
1475          * {@link Ext.Array#each}
1476          *
1477          * @param {Array} array The array to iterate
1478          * @param {Function} fn The function callback, to be invoked these arguments:
1479          *
1480          * - `item` : Mixed - The item at the current `index` in the passed `array`
1481          * - `index` : Number - The current `index` within the `array`
1482          * - `allItems` : Array - The `array` itself which was passed as the first argument
1483          *
1484          * @param {Object} scope (Optional) The execution scope (`this`) in which the specified function is executed.
1485          */
1486         forEach: function(array, fn, scope) {
1487             if (supportsForEach) {
1488                 return array.forEach(fn, scope);
1489             }
1490
1491             var i = 0,
1492                 ln = array.length;
1493
1494             for (; i < ln; i++) {
1495                 fn.call(scope, array[i], i, array);
1496             }
1497         },
1498
1499         /**
1500          * Get the index of the provided `item` in the given `array`, a supplement for the
1501          * missing arrayPrototype.indexOf in Internet Explorer.
1502          *
1503          * @param {Array} array The array to check
1504          * @param {Mixed} item The item to look for
1505          * @param {Number} from (Optional) The index at which to begin the search
1506          * @return {Number} The index of item in the array (or -1 if it is not found)
1507          */
1508         indexOf: function(array, item, from) {
1509             if (supportsIndexOf) {
1510                 return array.indexOf(item, from);
1511             }
1512
1513             var i, length = array.length;
1514
1515             for (i = (from < 0) ? Math.max(0, length + from) : from || 0; i < length; i++) {
1516                 if (array[i] === item) {
1517                     return i;
1518                 }
1519             }
1520
1521             return -1;
1522         },
1523
1524         /**
1525          * Checks whether or not the given `array` contains the specified `item`
1526          *
1527          * @param {Array} array The array to check
1528          * @param {Mixed} item The item to look for
1529          * @return {Boolean} True if the array contains the item, false otherwise
1530          */
1531         contains: function(array, item) {
1532             if (supportsIndexOf) {
1533                 return array.indexOf(item) !== -1;
1534             }
1535
1536             var i, ln;
1537
1538             for (i = 0, ln = array.length; i < ln; i++) {
1539                 if (array[i] === item) {
1540                     return true;
1541                 }
1542             }
1543
1544             return false;
1545         },
1546
1547         /**
1548          * Converts any iterable (numeric indices and a length property) into a true array.
1549          *
1550          *     function test() {
1551          *         var args = Ext.Array.toArray(arguments),
1552          *             fromSecondToLastArgs = Ext.Array.toArray(arguments, 1);
1553          *
1554          *         alert(args.join(' '));
1555          *         alert(fromSecondToLastArgs.join(' '));
1556          *     }
1557          *
1558          *     test('just', 'testing', 'here'); // alerts 'just testing here';
1559          *                                      // alerts 'testing here';
1560          *
1561          *     Ext.Array.toArray(document.getElementsByTagName('div')); // will convert the NodeList into an array
1562          *     Ext.Array.toArray('splitted'); // returns ['s', 'p', 'l', 'i', 't', 't', 'e', 'd']
1563          *     Ext.Array.toArray('splitted', 0, 3); // returns ['s', 'p', 'l', 'i']
1564          *
1565          * {@link Ext#toArray Ext.toArray} is alias for {@link Ext.Array#toArray Ext.Array.toArray}
1566          *
1567          * @param {Mixed} iterable the iterable object to be turned into a true Array.
1568          * @param {Number} start (Optional) a zero-based index that specifies the start of extraction. Defaults to 0
1569          * @param {Number} end (Optional) a zero-based index that specifies the end of extraction. Defaults to the last
1570          * index of the iterable value
1571          * @return {Array} array
1572          */
1573         toArray: function(iterable, start, end){
1574             if (!iterable || !iterable.length) {
1575                 return [];
1576             }
1577
1578             if (typeof iterable === 'string') {
1579                 iterable = iterable.split('');
1580             }
1581
1582             if (supportsSliceOnNodeList) {
1583                 return slice.call(iterable, start || 0, end || iterable.length);
1584             }
1585
1586             var array = [],
1587                 i;
1588
1589             start = start || 0;
1590             end = end ? ((end < 0) ? iterable.length + end : end) : iterable.length;
1591
1592             for (i = start; i < end; i++) {
1593                 array.push(iterable[i]);
1594             }
1595
1596             return array;
1597         },
1598
1599         /**
1600          * Plucks the value of a property from each item in the Array. Example:
1601          *
1602          *     Ext.Array.pluck(Ext.query("p"), "className"); // [el1.className, el2.className, ..., elN.className]
1603          *
1604          * @param {Array|NodeList} array The Array of items to pluck the value from.
1605          * @param {String} propertyName The property name to pluck from each element.
1606          * @return {Array} The value from each item in the Array.
1607          */
1608         pluck: function(array, propertyName) {
1609             var ret = [],
1610                 i, ln, item;
1611
1612             for (i = 0, ln = array.length; i < ln; i++) {
1613                 item = array[i];
1614
1615                 ret.push(item[propertyName]);
1616             }
1617
1618             return ret;
1619         },
1620
1621         /**
1622          * Creates a new array with the results of calling a provided function on every element in this array.
1623          *
1624          * @param {Array} array
1625          * @param {Function} fn Callback function for each item
1626          * @param {Object} scope Callback function scope
1627          * @return {Array} results
1628          */
1629         map: function(array, fn, scope) {
1630             if (supportsMap) {
1631                 return array.map(fn, scope);
1632             }
1633
1634             var results = [],
1635                 i = 0,
1636                 len = array.length;
1637
1638             for (; i < len; i++) {
1639                 results[i] = fn.call(scope, array[i], i, array);
1640             }
1641
1642             return results;
1643         },
1644
1645         /**
1646          * Executes the specified function for each array element until the function returns a falsy value.
1647          * If such an item is found, the function will return false immediately.
1648          * Otherwise, it will return true.
1649          *
1650          * @param {Array} array
1651          * @param {Function} fn Callback function for each item
1652          * @param {Object} scope Callback function scope
1653          * @return {Boolean} True if no false value is returned by the callback function.
1654          */
1655         every: function(array, fn, scope) {
1656             if (supportsEvery) {
1657                 return array.every(fn, scope);
1658             }
1659
1660             var i = 0,
1661                 ln = array.length;
1662
1663             for (; i < ln; ++i) {
1664                 if (!fn.call(scope, array[i], i, array)) {
1665                     return false;
1666                 }
1667             }
1668
1669             return true;
1670         },
1671
1672         /**
1673          * Executes the specified function for each array element until the function returns a truthy value.
1674          * If such an item is found, the function will return true immediately. Otherwise, it will return false.
1675          *
1676          * @param {Array} array
1677          * @param {Function} fn Callback function for each item
1678          * @param {Object} scope Callback function scope
1679          * @return {Boolean} True if the callback function returns a truthy value.
1680          */
1681         some: function(array, fn, scope) {
1682             if (supportsSome) {
1683                 return array.some(fn, scope);
1684             }
1685
1686             var i = 0,
1687                 ln = array.length;
1688
1689             for (; i < ln; ++i) {
1690                 if (fn.call(scope, array[i], i, array)) {
1691                     return true;
1692                 }
1693             }
1694
1695             return false;
1696         },
1697
1698         /**
1699          * Filter through an array and remove empty item as defined in {@link Ext#isEmpty Ext.isEmpty}
1700          *
1701          * See {@link Ext.Array#filter}
1702          *
1703          * @param {Array} array
1704          * @return {Array} results
1705          */
1706         clean: function(array) {
1707             var results = [],
1708                 i = 0,
1709                 ln = array.length,
1710                 item;
1711
1712             for (; i < ln; i++) {
1713                 item = array[i];
1714
1715                 if (!Ext.isEmpty(item)) {
1716                     results.push(item);
1717                 }
1718             }
1719
1720             return results;
1721         },
1722
1723         /**
1724          * Returns a new array with unique items
1725          *
1726          * @param {Array} array
1727          * @return {Array} results
1728          */
1729         unique: function(array) {
1730             var clone = [],
1731                 i = 0,
1732                 ln = array.length,
1733                 item;
1734
1735             for (; i < ln; i++) {
1736                 item = array[i];
1737
1738                 if (ExtArray.indexOf(clone, item) === -1) {
1739                     clone.push(item);
1740                 }
1741             }
1742
1743             return clone;
1744         },
1745
1746         /**
1747          * Creates a new array with all of the elements of this array for which
1748          * the provided filtering function returns true.
1749          *
1750          * @param {Array} array
1751          * @param {Function} fn Callback function for each item
1752          * @param {Object} scope Callback function scope
1753          * @return {Array} results
1754          */
1755         filter: function(array, fn, scope) {
1756             if (supportsFilter) {
1757                 return array.filter(fn, scope);
1758             }
1759
1760             var results = [],
1761                 i = 0,
1762                 ln = array.length;
1763
1764             for (; i < ln; i++) {
1765                 if (fn.call(scope, array[i], i, array)) {
1766                     results.push(array[i]);
1767                 }
1768             }
1769
1770             return results;
1771         },
1772
1773         /**
1774          * Converts a value to an array if it's not already an array; returns:
1775          *
1776          * - An empty array if given value is `undefined` or `null`
1777          * - Itself if given value is already an array
1778          * - An array copy if given value is {@link Ext#isIterable iterable} (arguments, NodeList and alike)
1779          * - An array with one item which is the given value, otherwise
1780          *
1781          * @param {Array/Mixed} value The value to convert to an array if it's not already is an array
1782          * @param {Boolean} (Optional) newReference True to clone the given array and return a new reference if necessary,
1783          * defaults to false
1784          * @return {Array} array
1785          */
1786         from: function(value, newReference) {
1787             if (value === undefined || value === null) {
1788                 return [];
1789             }
1790
1791             if (Ext.isArray(value)) {
1792                 return (newReference) ? slice.call(value) : value;
1793             }
1794
1795             if (value && value.length !== undefined && typeof value !== 'string') {
1796                 return Ext.toArray(value);
1797             }
1798
1799             return [value];
1800         },
1801
1802         /**
1803          * Removes the specified item from the array if it exists
1804          *
1805          * @param {Array} array The array
1806          * @param {Mixed} item The item to remove
1807          * @return {Array} The passed array itself
1808          */
1809         remove: function(array, item) {
1810             var index = ExtArray.indexOf(array, item);
1811
1812             if (index !== -1) {
1813                 erase(array, index, 1);
1814             }
1815
1816             return array;
1817         },
1818
1819         /**
1820          * Push an item into the array only if the array doesn't contain it yet
1821          *
1822          * @param {Array} array The array
1823          * @param {Mixed} item The item to include
1824          */
1825         include: function(array, item) {
1826             if (!ExtArray.contains(array, item)) {
1827                 array.push(item);
1828             }
1829         },
1830
1831         /**
1832          * Clone a flat array without referencing the previous one. Note that this is different
1833          * from Ext.clone since it doesn't handle recursive cloning. It's simply a convenient, easy-to-remember method
1834          * for Array.prototype.slice.call(array)
1835          *
1836          * @param {Array} array The array
1837          * @return {Array} The clone array
1838          */
1839         clone: function(array) {
1840             return slice.call(array);
1841         },
1842
1843         /**
1844          * Merge multiple arrays into one with unique items.
1845          *
1846          * {@link Ext.Array#union} is alias for {@link Ext.Array#merge}
1847          *
1848          * @param {Array} array1
1849          * @param {Array} array2
1850          * @param {Array} etc
1851          * @return {Array} merged
1852          */
1853         merge: function() {
1854             var args = slice.call(arguments),
1855                 array = [],
1856                 i, ln;
1857
1858             for (i = 0, ln = args.length; i < ln; i++) {
1859                 array = array.concat(args[i]);
1860             }
1861
1862             return ExtArray.unique(array);
1863         },
1864
1865         /**
1866          * Merge multiple arrays into one with unique items that exist in all of the arrays.
1867          *
1868          * @param {Array} array1
1869          * @param {Array} array2
1870          * @param {Array} etc
1871          * @return {Array} intersect
1872          */
1873         intersect: function() {
1874             var intersect = [],
1875                 arrays = slice.call(arguments),
1876                 i, j, k, minArray, array, x, y, ln, arraysLn, arrayLn;
1877
1878             if (!arrays.length) {
1879                 return intersect;
1880             }
1881
1882             // Find the smallest array
1883             for (i = x = 0,ln = arrays.length; i < ln,array = arrays[i]; i++) {
1884                 if (!minArray || array.length < minArray.length) {
1885                     minArray = array;
1886                     x = i;
1887                 }
1888             }
1889
1890             minArray = ExtArray.unique(minArray);
1891             erase(arrays, x, 1);
1892
1893             // Use the smallest unique'd array as the anchor loop. If the other array(s) do contain
1894             // an item in the small array, we're likely to find it before reaching the end
1895             // of the inner loop and can terminate the search early.
1896             for (i = 0,ln = minArray.length; i < ln,x = minArray[i]; i++) {
1897                 var count = 0;
1898
1899                 for (j = 0,arraysLn = arrays.length; j < arraysLn,array = arrays[j]; j++) {
1900                     for (k = 0,arrayLn = array.length; k < arrayLn,y = array[k]; k++) {
1901                         if (x === y) {
1902                             count++;
1903                             break;
1904                         }
1905                     }
1906                 }
1907
1908                 if (count === arraysLn) {
1909                     intersect.push(x);
1910                 }
1911             }
1912
1913             return intersect;
1914         },
1915
1916         /**
1917          * Perform a set difference A-B by subtracting all items in array B from array A.
1918          *
1919          * @param {Array} arrayA
1920          * @param {Array} arrayB
1921          * @return {Array} difference
1922          */
1923         difference: function(arrayA, arrayB) {
1924             var clone = slice.call(arrayA),
1925                 ln = clone.length,
1926                 i, j, lnB;
1927
1928             for (i = 0,lnB = arrayB.length; i < lnB; i++) {
1929                 for (j = 0; j < ln; j++) {
1930                     if (clone[j] === arrayB[i]) {
1931                         erase(clone, j, 1);
1932                         j--;
1933                         ln--;
1934                     }
1935                 }
1936             }
1937
1938             return clone;
1939         },
1940
1941         /**
1942          * Returns a shallow copy of a part of an array. This is equivalent to the native
1943          * call "Array.prototype.slice.call(array, begin, end)". This is often used when "array"
1944          * is "arguments" since the arguments object does not supply a slice method but can
1945          * be the context object to Array.prototype.slice.
1946          *
1947          * @param {Array} array The array (or arguments object).
1948          * @param {Number} begin The index at which to begin. Negative values are offsets from
1949          * the end of the array.
1950          * @param {Number} end The index at which to end. The copied items do not include
1951          * end. Negative values are offsets from the end of the array. If end is omitted,
1952          * all items up to the end of the array are copied.
1953          * @return {Array} The copied piece of the array.
1954          */
1955         slice: function(array, begin, end) {
1956             return slice.call(array, begin, end);
1957         },
1958
1959         /**
1960          * Sorts the elements of an Array.
1961          * By default, this method sorts the elements alphabetically and ascending.
1962          *
1963          * @param {Array} array The array to sort.
1964          * @param {Function} sortFn (optional) The comparison function.
1965          * @return {Array} The sorted array.
1966          */
1967         sort: function(array, sortFn) {
1968             if (supportsSort) {
1969                 if (sortFn) {
1970                     return array.sort(sortFn);
1971                 } else {
1972                     return array.sort();
1973                 }
1974             }
1975
1976             var length = array.length,
1977                 i = 0,
1978                 comparison,
1979                 j, min, tmp;
1980
1981             for (; i < length; i++) {
1982                 min = i;
1983                 for (j = i + 1; j < length; j++) {
1984                     if (sortFn) {
1985                         comparison = sortFn(array[j], array[min]);
1986                         if (comparison < 0) {
1987                             min = j;
1988                         }
1989                     } else if (array[j] < array[min]) {
1990                         min = j;
1991                     }
1992                 }
1993                 if (min !== i) {
1994                     tmp = array[i];
1995                     array[i] = array[min];
1996                     array[min] = tmp;
1997                 }
1998             }
1999
2000             return array;
2001         },
2002
2003         /**
2004          * Recursively flattens into 1-d Array. Injects Arrays inline.
2005          *
2006          */
2007         flatten: function(array) {
2008             var worker = [];
2009
2010             function rFlatten(a) {
2011                 var i, ln, v;
2012
2013                 for (i = 0, ln = a.length; i < ln; i++) {
2014                     v = a[i];
2015
2016                     if (Ext.isArray(v)) {
2017                         rFlatten(v);
2018                     } else {
2019                         worker.push(v);
2020                     }
2021                 }
2022
2023                 return worker;
2024             }
2025
2026             return rFlatten(array);
2027         },
2028
2029         /**
2030          * Returns the minimum value in the Array.
2031          *
2032          * @param {Array|NodeList} array The Array from which to select the minimum value.
2033          * @param {Function} comparisonFn (optional) a function to perform the comparision which determines minimization.
2034          * If omitted the "<" operator will be used. Note: gt = 1; eq = 0; lt = -1
2035          * @return {Mixed} minValue The minimum value
2036          */
2037         min: function(array, comparisonFn) {
2038             var min = array[0],
2039                 i, ln, item;
2040
2041             for (i = 0, ln = array.length; i < ln; i++) {
2042                 item = array[i];
2043
2044                 if (comparisonFn) {
2045                     if (comparisonFn(min, item) === 1) {
2046                         min = item;
2047                     }
2048                 }
2049                 else {
2050                     if (item < min) {
2051                         min = item;
2052                     }
2053                 }
2054             }
2055
2056             return min;
2057         },
2058
2059         /**
2060          * Returns the maximum value in the Array.
2061          *
2062          * @param {Array|NodeList} array The Array from which to select the maximum value.
2063          * @param {Function} comparisonFn (optional) a function to perform the comparision which determines maximization.
2064          * If omitted the ">" operator will be used. Note: gt = 1; eq = 0; lt = -1
2065          * @return {Mixed} maxValue The maximum value
2066          */
2067         max: function(array, comparisonFn) {
2068             var max = array[0],
2069                 i, ln, item;
2070
2071             for (i = 0, ln = array.length; i < ln; i++) {
2072                 item = array[i];
2073
2074                 if (comparisonFn) {
2075                     if (comparisonFn(max, item) === -1) {
2076                         max = item;
2077                     }
2078                 }
2079                 else {
2080                     if (item > max) {
2081                         max = item;
2082                     }
2083                 }
2084             }
2085
2086             return max;
2087         },
2088
2089         /**
2090          * Calculates the mean of all items in the array.
2091          *
2092          * @param {Array} array The Array to calculate the mean value of.
2093          * @return {Number} The mean.
2094          */
2095         mean: function(array) {
2096             return array.length > 0 ? ExtArray.sum(array) / array.length : undefined;
2097         },
2098
2099         /**
2100          * Calculates the sum of all items in the given array.
2101          *
2102          * @param {Array} array The Array to calculate the sum value of.
2103          * @return {Number} The sum.
2104          */
2105         sum: function(array) {
2106             var sum = 0,
2107                 i, ln, item;
2108
2109             for (i = 0,ln = array.length; i < ln; i++) {
2110                 item = array[i];
2111
2112                 sum += item;
2113             }
2114
2115             return sum;
2116         },
2117
2118
2119         /**
2120          * Removes items from an array. This is functionally equivalent to the splice method
2121          * of Array, but works around bugs in IE8's splice method and does not copy the
2122          * removed elements in order to return them (because very often they are ignored).
2123          *
2124          * @param {Array} array The Array on which to replace.
2125          * @param {Number} index The index in the array at which to operate.
2126          * @param {Number} removeCount The number of items to remove at index.
2127          * @return {Array} The array passed.
2128          * @method
2129          */
2130         erase: erase,
2131
2132         /**
2133          * Inserts items in to an array.
2134          * 
2135          * @param {Array} array The Array on which to replace.
2136          * @param {Number} index The index in the array at which to operate.
2137          * @param {Array} items The array of items to insert at index.
2138          * @return {Array} The array passed.
2139          */
2140         insert: function (array, index, items) {
2141             return replace(array, index, 0, items);
2142         },
2143
2144         /**
2145          * Replaces items in an array. This is functionally equivalent to the splice method
2146          * of Array, but works around bugs in IE8's splice method and is often more convenient
2147          * to call because it accepts an array of items to insert rather than use a variadic
2148          * argument list.
2149          * 
2150          * @param {Array} array The Array on which to replace.
2151          * @param {Number} index The index in the array at which to operate.
2152          * @param {Number} removeCount The number of items to remove at index (can be 0).
2153          * @param {Array} insert An optional array of items to insert at index.
2154          * @return {Array} The array passed.
2155          * @method
2156          */
2157         replace: replace,
2158
2159         /**
2160          * Replaces items in an array. This is equivalent to the splice method of Array, but
2161          * works around bugs in IE8's splice method. The signature is exactly the same as the
2162          * splice method except that the array is the first argument. All arguments following
2163          * removeCount are inserted in the array at index.
2164          *
2165          * @param {Array} array The Array on which to replace.
2166          * @param {Number} index The index in the array at which to operate.
2167          * @param {Number} removeCount The number of items to remove at index (can be 0).
2168          * @return {Array} An array containing the removed items.
2169          * @method
2170          */
2171         splice: splice
2172     };
2173
2174     /**
2175      * @method
2176      * @member Ext
2177      * @alias Ext.Array#each
2178      */
2179     Ext.each = ExtArray.each;
2180
2181     /**
2182      * @method
2183      * @member Ext.Array
2184      * @alias Ext.Array#merge
2185      */
2186     ExtArray.union = ExtArray.merge;
2187
2188     /**
2189      * Old alias to {@link Ext.Array#min}
2190      * @deprecated 4.0.0 Use {@link Ext.Array#min} instead
2191      * @method
2192      * @member Ext
2193      * @alias Ext.Array#min
2194      */
2195     Ext.min = ExtArray.min;
2196
2197     /**
2198      * Old alias to {@link Ext.Array#max}
2199      * @deprecated 4.0.0 Use {@link Ext.Array#max} instead
2200      * @method
2201      * @member Ext
2202      * @alias Ext.Array#max
2203      */
2204     Ext.max = ExtArray.max;
2205
2206     /**
2207      * Old alias to {@link Ext.Array#sum}
2208      * @deprecated 4.0.0 Use {@link Ext.Array#sum} instead
2209      * @method
2210      * @member Ext
2211      * @alias Ext.Array#sum
2212      */
2213     Ext.sum = ExtArray.sum;
2214
2215     /**
2216      * Old alias to {@link Ext.Array#mean}
2217      * @deprecated 4.0.0 Use {@link Ext.Array#mean} instead
2218      * @method
2219      * @member Ext
2220      * @alias Ext.Array#mean
2221      */
2222     Ext.mean = ExtArray.mean;
2223
2224     /**
2225      * Old alias to {@link Ext.Array#flatten}
2226      * @deprecated 4.0.0 Use {@link Ext.Array#flatten} instead
2227      * @method
2228      * @member Ext
2229      * @alias Ext.Array#flatten
2230      */
2231     Ext.flatten = ExtArray.flatten;
2232
2233     /**
2234      * Old alias to {@link Ext.Array#clean}
2235      * @deprecated 4.0.0 Use {@link Ext.Array#clean} instead
2236      * @method
2237      * @member Ext
2238      * @alias Ext.Array#clean
2239      */
2240     Ext.clean = ExtArray.clean;
2241
2242     /**
2243      * Old alias to {@link Ext.Array#unique}
2244      * @deprecated 4.0.0 Use {@link Ext.Array#unique} instead
2245      * @method
2246      * @member Ext
2247      * @alias Ext.Array#unique
2248      */
2249     Ext.unique = ExtArray.unique;
2250
2251     /**
2252      * Old alias to {@link Ext.Array#pluck Ext.Array.pluck}
2253      * @deprecated 4.0.0 Use {@link Ext.Array#pluck Ext.Array.pluck} instead
2254      * @method
2255      * @member Ext
2256      * @alias Ext.Array#pluck
2257      */
2258     Ext.pluck = ExtArray.pluck;
2259
2260     /**
2261      * @method
2262      * @member Ext
2263      * @alias Ext.Array#toArray
2264      */
2265     Ext.toArray = function() {
2266         return ExtArray.toArray.apply(ExtArray, arguments);
2267     };
2268 })();
2269
2270 /**
2271  * @class Ext.Function
2272  *
2273  * A collection of useful static methods to deal with function callbacks
2274  * @singleton
2275  */
2276 Ext.Function = {
2277
2278     /**
2279      * A very commonly used method throughout the framework. It acts as a wrapper around another method
2280      * which originally accepts 2 arguments for `name` and `value`.
2281      * The wrapped function then allows "flexible" value setting of either:
2282      *
2283      * - `name` and `value` as 2 arguments
2284      * - one single object argument with multiple key - value pairs
2285      *
2286      * For example:
2287      *
2288      *     var setValue = Ext.Function.flexSetter(function(name, value) {
2289      *         this[name] = value;
2290      *     });
2291      *
2292      *     // Afterwards
2293      *     // Setting a single name - value
2294      *     setValue('name1', 'value1');
2295      *
2296      *     // Settings multiple name - value pairs
2297      *     setValue({
2298      *         name1: 'value1',
2299      *         name2: 'value2',
2300      *         name3: 'value3'
2301      *     });
2302      *
2303      * @param {Function} setter
2304      * @returns {Function} flexSetter
2305      */
2306     flexSetter: function(fn) {
2307         return function(a, b) {
2308             var k, i;
2309
2310             if (a === null) {
2311                 return this;
2312             }
2313
2314             if (typeof a !== 'string') {
2315                 for (k in a) {
2316                     if (a.hasOwnProperty(k)) {
2317                         fn.call(this, k, a[k]);
2318                     }
2319                 }
2320
2321                 if (Ext.enumerables) {
2322                     for (i = Ext.enumerables.length; i--;) {
2323                         k = Ext.enumerables[i];
2324                         if (a.hasOwnProperty(k)) {
2325                             fn.call(this, k, a[k]);
2326                         }
2327                     }
2328                 }
2329             } else {
2330                 fn.call(this, a, b);
2331             }
2332
2333             return this;
2334         };
2335     },
2336
2337     /**
2338      * Create a new function from the provided `fn`, change `this` to the provided scope, optionally
2339      * overrides arguments for the call. (Defaults to the arguments passed by the caller)
2340      *
2341      * {@link Ext#bind Ext.bind} is alias for {@link Ext.Function#bind Ext.Function.bind}
2342      *
2343      * @param {Function} fn The function to delegate.
2344      * @param {Object} scope (optional) The scope (`this` reference) in which the function is executed.
2345      * **If omitted, defaults to the browser window.**
2346      * @param {Array} args (optional) Overrides arguments for the call. (Defaults to the arguments passed by the caller)
2347      * @param {Boolean/Number} appendArgs (optional) if True args are appended to call args instead of overriding,
2348      * if a number the args are inserted at the specified position
2349      * @return {Function} The new function
2350      */
2351     bind: function(fn, scope, args, appendArgs) {
2352         var method = fn,
2353             slice = Array.prototype.slice;
2354
2355         return function() {
2356             var callArgs = args || arguments;
2357
2358             if (appendArgs === true) {
2359                 callArgs = slice.call(arguments, 0);
2360                 callArgs = callArgs.concat(args);
2361             }
2362             else if (Ext.isNumber(appendArgs)) {
2363                 callArgs = slice.call(arguments, 0); // copy arguments first
2364                 Ext.Array.insert(callArgs, appendArgs, args);
2365             }
2366
2367             return method.apply(scope || window, callArgs);
2368         };
2369     },
2370
2371     /**
2372      * Create a new function from the provided `fn`, the arguments of which are pre-set to `args`.
2373      * New arguments passed to the newly created callback when it's invoked are appended after the pre-set ones.
2374      * This is especially useful when creating callbacks.
2375      *
2376      * For example:
2377      *
2378      *     var originalFunction = function(){
2379      *         alert(Ext.Array.from(arguments).join(' '));
2380      *     };
2381      *
2382      *     var callback = Ext.Function.pass(originalFunction, ['Hello', 'World']);
2383      *
2384      *     callback(); // alerts 'Hello World'
2385      *     callback('by Me'); // alerts 'Hello World by Me'
2386      *
2387      * {@link Ext#pass Ext.pass} is alias for {@link Ext.Function#pass Ext.Function.pass}
2388      *
2389      * @param {Function} fn The original function
2390      * @param {Array} args The arguments to pass to new callback
2391      * @param {Object} scope (optional) The scope (`this` reference) in which the function is executed.
2392      * @return {Function} The new callback function
2393      */
2394     pass: function(fn, args, scope) {
2395         if (args) {
2396             args = Ext.Array.from(args);
2397         }
2398
2399         return function() {
2400             return fn.apply(scope, args.concat(Ext.Array.toArray(arguments)));
2401         };
2402     },
2403
2404     /**
2405      * Create an alias to the provided method property with name `methodName` of `object`.
2406      * Note that the execution scope will still be bound to the provided `object` itself.
2407      *
2408      * @param {Object/Function} object
2409      * @param {String} methodName
2410      * @return {Function} aliasFn
2411      */
2412     alias: function(object, methodName) {
2413         return function() {
2414             return object[methodName].apply(object, arguments);
2415         };
2416     },
2417
2418     /**
2419      * Creates an interceptor function. The passed function is called before the original one. If it returns false,
2420      * the original one is not called. The resulting function returns the results of the original function.
2421      * The passed function is called with the parameters of the original function. Example usage:
2422      *
2423      *     var sayHi = function(name){
2424      *         alert('Hi, ' + name);
2425      *     }
2426      *
2427      *     sayHi('Fred'); // alerts "Hi, Fred"
2428      *
2429      *     // create a new function that validates input without
2430      *     // directly modifying the original function:
2431      *     var sayHiToFriend = Ext.Function.createInterceptor(sayHi, function(name){
2432      *         return name == 'Brian';
2433      *     });
2434      *
2435      *     sayHiToFriend('Fred');  // no alert
2436      *     sayHiToFriend('Brian'); // alerts "Hi, Brian"
2437      *
2438      * @param {Function} origFn The original function.
2439      * @param {Function} newFn The function to call before the original
2440      * @param {Object} scope (optional) The scope (`this` reference) in which the passed function is executed.
2441      * **If omitted, defaults to the scope in which the original function is called or the browser window.**
2442      * @param {Mixed} returnValue (optional) The value to return if the passed function return false (defaults to null).
2443      * @return {Function} The new function
2444      */
2445     createInterceptor: function(origFn, newFn, scope, returnValue) {
2446         var method = origFn;
2447         if (!Ext.isFunction(newFn)) {
2448             return origFn;
2449         }
2450         else {
2451             return function() {
2452                 var me = this,
2453                     args = arguments;
2454                 newFn.target = me;
2455                 newFn.method = origFn;
2456                 return (newFn.apply(scope || me || window, args) !== false) ? origFn.apply(me || window, args) : returnValue || null;
2457             };
2458         }
2459     },
2460
2461     /**
2462      * Creates a delegate (callback) which, when called, executes after a specific delay.
2463      *
2464      * @param {Function} fn The function which will be called on a delay when the returned function is called.
2465      * Optionally, a replacement (or additional) argument list may be specified.
2466      * @param {Number} delay The number of milliseconds to defer execution by whenever called.
2467      * @param {Object} scope (optional) The scope (`this` reference) used by the function at execution time.
2468      * @param {Array} args (optional) Override arguments for the call. (Defaults to the arguments passed by the caller)
2469      * @param {Boolean/Number} appendArgs (optional) if True args are appended to call args instead of overriding,
2470      * if a number the args are inserted at the specified position.
2471      * @return {Function} A function which, when called, executes the original function after the specified delay.
2472      */
2473     createDelayed: function(fn, delay, scope, args, appendArgs) {
2474         if (scope || args) {
2475             fn = Ext.Function.bind(fn, scope, args, appendArgs);
2476         }
2477         return function() {
2478             var me = this;
2479             setTimeout(function() {
2480                 fn.apply(me, arguments);
2481             }, delay);
2482         };
2483     },
2484
2485     /**
2486      * Calls this function after the number of millseconds specified, optionally in a specific scope. Example usage:
2487      *
2488      *     var sayHi = function(name){
2489      *         alert('Hi, ' + name);
2490      *     }
2491      *
2492      *     // executes immediately:
2493      *     sayHi('Fred');
2494      *
2495      *     // executes after 2 seconds:
2496      *     Ext.Function.defer(sayHi, 2000, this, ['Fred']);
2497      *
2498      *     // this syntax is sometimes useful for deferring
2499      *     // execution of an anonymous function:
2500      *     Ext.Function.defer(function(){
2501      *         alert('Anonymous');
2502      *     }, 100);
2503      *
2504      * {@link Ext#defer Ext.defer} is alias for {@link Ext.Function#defer Ext.Function.defer}
2505      *
2506      * @param {Function} fn The function to defer.
2507      * @param {Number} millis The number of milliseconds for the setTimeout call
2508      * (if less than or equal to 0 the function is executed immediately)
2509      * @param {Object} scope (optional) The scope (`this` reference) in which the function is executed.
2510      * **If omitted, defaults to the browser window.**
2511      * @param {Array} args (optional) Overrides arguments for the call. (Defaults to the arguments passed by the caller)
2512      * @param {Boolean/Number} appendArgs (optional) if True args are appended to call args instead of overriding,
2513      * if a number the args are inserted at the specified position
2514      * @return {Number} The timeout id that can be used with clearTimeout
2515      */
2516     defer: function(fn, millis, obj, args, appendArgs) {
2517         fn = Ext.Function.bind(fn, obj, args, appendArgs);
2518         if (millis > 0) {
2519             return setTimeout(fn, millis);
2520         }
2521         fn();
2522         return 0;
2523     },
2524
2525     /**
2526      * Create a combined function call sequence of the original function + the passed function.
2527      * The resulting function returns the results of the original function.
2528      * The passed function is called with the parameters of the original function. Example usage:
2529      *
2530      *     var sayHi = function(name){
2531      *         alert('Hi, ' + name);
2532      *     }
2533      *
2534      *     sayHi('Fred'); // alerts "Hi, Fred"
2535      *
2536      *     var sayGoodbye = Ext.Function.createSequence(sayHi, function(name){
2537      *         alert('Bye, ' + name);
2538      *     });
2539      *
2540      *     sayGoodbye('Fred'); // both alerts show
2541      *
2542      * @param {Function} origFn The original function.
2543      * @param {Function} newFn The function to sequence
2544      * @param {Object} scope (optional) The scope (`this` reference) in which the passed function is executed.
2545      * If omitted, defaults to the scope in which the original function is called or the browser window.
2546      * @return {Function} The new function
2547      */
2548     createSequence: function(origFn, newFn, scope) {
2549         if (!Ext.isFunction(newFn)) {
2550             return origFn;
2551         }
2552         else {
2553             return function() {
2554                 var retval = origFn.apply(this || window, arguments);
2555                 newFn.apply(scope || this || window, arguments);
2556                 return retval;
2557             };
2558         }
2559     },
2560
2561     /**
2562      * Creates a delegate function, optionally with a bound scope which, when called, buffers
2563      * the execution of the passed function for the configured number of milliseconds.
2564      * If called again within that period, the impending invocation will be canceled, and the
2565      * timeout period will begin again.
2566      *
2567      * @param {Function} fn The function to invoke on a buffered timer.
2568      * @param {Number} buffer The number of milliseconds by which to buffer the invocation of the
2569      * function.
2570      * @param {Object} scope (optional) The scope (`this` reference) in which
2571      * the passed function is executed. If omitted, defaults to the scope specified by the caller.
2572      * @param {Array} args (optional) Override arguments for the call. Defaults to the arguments
2573      * passed by the caller.
2574      * @return {Function} A function which invokes the passed function after buffering for the specified time.
2575      */
2576     createBuffered: function(fn, buffer, scope, args) {
2577         return function(){
2578             var timerId;
2579             return function() {
2580                 var me = this;
2581                 if (timerId) {
2582                     clearInterval(timerId);
2583                     timerId = null;
2584                 }
2585                 timerId = setTimeout(function(){
2586                     fn.apply(scope || me, args || arguments);
2587                 }, buffer);
2588             };
2589         }();
2590     },
2591
2592     /**
2593      * Creates a throttled version of the passed function which, when called repeatedly and
2594      * rapidly, invokes the passed function only after a certain interval has elapsed since the
2595      * previous invocation.
2596      *
2597      * This is useful for wrapping functions which may be called repeatedly, such as
2598      * a handler of a mouse move event when the processing is expensive.
2599      *
2600      * @param {Function} fn The function to execute at a regular time interval.
2601      * @param {Number} interval The interval **in milliseconds** on which the passed function is executed.
2602      * @param {Object} scope (optional) The scope (`this` reference) in which
2603      * the passed function is executed. If omitted, defaults to the scope specified by the caller.
2604      * @returns {Function} A function which invokes the passed function at the specified interval.
2605      */
2606     createThrottled: function(fn, interval, scope) {
2607         var lastCallTime, elapsed, lastArgs, timer, execute = function() {
2608             fn.apply(scope || this, lastArgs);
2609             lastCallTime = new Date().getTime();
2610         };
2611
2612         return function() {
2613             elapsed = new Date().getTime() - lastCallTime;
2614             lastArgs = arguments;
2615
2616             clearTimeout(timer);
2617             if (!lastCallTime || (elapsed >= interval)) {
2618                 execute();
2619             } else {
2620                 timer = setTimeout(execute, interval - elapsed);
2621             }
2622         };
2623     }
2624 };
2625
2626 /**
2627  * @method
2628  * @member Ext
2629  * @alias Ext.Function#defer
2630  */
2631 Ext.defer = Ext.Function.alias(Ext.Function, 'defer');
2632
2633 /**
2634  * @method
2635  * @member Ext
2636  * @alias Ext.Function#pass
2637  */
2638 Ext.pass = Ext.Function.alias(Ext.Function, 'pass');
2639
2640 /**
2641  * @method
2642  * @member Ext
2643  * @alias Ext.Function#bind
2644  */
2645 Ext.bind = Ext.Function.alias(Ext.Function, 'bind');
2646
2647 /**
2648  * @author Jacky Nguyen <jacky@sencha.com>
2649  * @docauthor Jacky Nguyen <jacky@sencha.com>
2650  * @class Ext.Object
2651  *
2652  * A collection of useful static methods to deal with objects
2653  *
2654  * @singleton
2655  */
2656
2657 (function() {
2658
2659 var ExtObject = Ext.Object = {
2660
2661     /**
2662      * Convert a `name` - `value` pair to an array of objects with support for nested structures; useful to construct
2663      * query strings. For example:
2664
2665     var objects = Ext.Object.toQueryObjects('hobbies', ['reading', 'cooking', 'swimming']);
2666
2667     // objects then equals:
2668     [
2669         { name: 'hobbies', value: 'reading' },
2670         { name: 'hobbies', value: 'cooking' },
2671         { name: 'hobbies', value: 'swimming' },
2672     ];
2673
2674     var objects = Ext.Object.toQueryObjects('dateOfBirth', {
2675         day: 3,
2676         month: 8,
2677         year: 1987,
2678         extra: {
2679             hour: 4
2680             minute: 30
2681         }
2682     }, true); // Recursive
2683
2684     // objects then equals:
2685     [
2686         { name: 'dateOfBirth[day]', value: 3 },
2687         { name: 'dateOfBirth[month]', value: 8 },
2688         { name: 'dateOfBirth[year]', value: 1987 },
2689         { name: 'dateOfBirth[extra][hour]', value: 4 },
2690         { name: 'dateOfBirth[extra][minute]', value: 30 },
2691     ];
2692
2693      * @param {String} name
2694      * @param {Mixed} value
2695      * @param {Boolean} recursive
2696      * @markdown
2697      */
2698     toQueryObjects: function(name, value, recursive) {
2699         var self = ExtObject.toQueryObjects,
2700             objects = [],
2701             i, ln;
2702
2703         if (Ext.isArray(value)) {
2704             for (i = 0, ln = value.length; i < ln; i++) {
2705                 if (recursive) {
2706                     objects = objects.concat(self(name + '[' + i + ']', value[i], true));
2707                 }
2708                 else {
2709                     objects.push({
2710                         name: name,
2711                         value: value[i]
2712                     });
2713                 }
2714             }
2715         }
2716         else if (Ext.isObject(value)) {
2717             for (i in value) {
2718                 if (value.hasOwnProperty(i)) {
2719                     if (recursive) {
2720                         objects = objects.concat(self(name + '[' + i + ']', value[i], true));
2721                     }
2722                     else {
2723                         objects.push({
2724                             name: name,
2725                             value: value[i]
2726                         });
2727                     }
2728                 }
2729             }
2730         }
2731         else {
2732             objects.push({
2733                 name: name,
2734                 value: value
2735             });
2736         }
2737
2738         return objects;
2739     },
2740
2741     /**
2742      * Takes an object and converts it to an encoded query string
2743
2744 - Non-recursive:
2745
2746     Ext.Object.toQueryString({foo: 1, bar: 2}); // returns "foo=1&bar=2"
2747     Ext.Object.toQueryString({foo: null, bar: 2}); // returns "foo=&bar=2"
2748     Ext.Object.toQueryString({'some price': '$300'}); // returns "some%20price=%24300"
2749     Ext.Object.toQueryString({date: new Date(2011, 0, 1)}); // returns "date=%222011-01-01T00%3A00%3A00%22"
2750     Ext.Object.toQueryString({colors: ['red', 'green', 'blue']}); // returns "colors=red&colors=green&colors=blue"
2751
2752 - Recursive:
2753
2754     Ext.Object.toQueryString({
2755         username: 'Jacky',
2756         dateOfBirth: {
2757             day: 1,
2758             month: 2,
2759             year: 1911
2760         },
2761         hobbies: ['coding', 'eating', 'sleeping', ['nested', 'stuff']]
2762     }, true); // returns the following string (broken down and url-decoded for ease of reading purpose):
2763               // username=Jacky
2764               //    &dateOfBirth[day]=1&dateOfBirth[month]=2&dateOfBirth[year]=1911
2765               //    &hobbies[0]=coding&hobbies[1]=eating&hobbies[2]=sleeping&hobbies[3][0]=nested&hobbies[3][1]=stuff
2766
2767      *
2768      * @param {Object} object The object to encode
2769      * @param {Boolean} recursive (optional) Whether or not to interpret the object in recursive format.
2770      * (PHP / Ruby on Rails servers and similar). Defaults to false
2771      * @return {String} queryString
2772      * @markdown
2773      */
2774     toQueryString: function(object, recursive) {
2775         var paramObjects = [],
2776             params = [],
2777             i, j, ln, paramObject, value;
2778
2779         for (i in object) {
2780             if (object.hasOwnProperty(i)) {
2781                 paramObjects = paramObjects.concat(ExtObject.toQueryObjects(i, object[i], recursive));
2782             }
2783         }
2784
2785         for (j = 0, ln = paramObjects.length; j < ln; j++) {
2786             paramObject = paramObjects[j];
2787             value = paramObject.value;
2788
2789             if (Ext.isEmpty(value)) {
2790                 value = '';
2791             }
2792             else if (Ext.isDate(value)) {
2793                 value = Ext.Date.toString(value);
2794             }
2795
2796             params.push(encodeURIComponent(paramObject.name) + '=' + encodeURIComponent(String(value)));
2797         }
2798
2799         return params.join('&');
2800     },
2801
2802     /**
2803      * Converts a query string back into an object.
2804      *
2805 - Non-recursive:
2806
2807     Ext.Object.fromQueryString(foo=1&bar=2); // returns {foo: 1, bar: 2}
2808     Ext.Object.fromQueryString(foo=&bar=2); // returns {foo: null, bar: 2}
2809     Ext.Object.fromQueryString(some%20price=%24300); // returns {'some price': '$300'}
2810     Ext.Object.fromQueryString(colors=red&colors=green&colors=blue); // returns {colors: ['red', 'green', 'blue']}
2811
2812 - Recursive:
2813
2814     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);
2815
2816     // returns
2817     {
2818         username: 'Jacky',
2819         dateOfBirth: {
2820             day: '1',
2821             month: '2',
2822             year: '1911'
2823         },
2824         hobbies: ['coding', 'eating', 'sleeping', ['nested', 'stuff']]
2825     }
2826
2827      * @param {String} queryString The query string to decode
2828      * @param {Boolean} recursive (Optional) Whether or not to recursively decode the string. This format is supported by
2829      * PHP / Ruby on Rails servers and similar. Defaults to false
2830      * @return {Object}
2831      */
2832     fromQueryString: function(queryString, recursive) {
2833         var parts = queryString.replace(/^\?/, '').split('&'),
2834             object = {},
2835             temp, components, name, value, i, ln,
2836             part, j, subLn, matchedKeys, matchedName,
2837             keys, key, nextKey;
2838
2839         for (i = 0, ln = parts.length; i < ln; i++) {
2840             part = parts[i];
2841
2842             if (part.length > 0) {
2843                 components = part.split('=');
2844                 name = decodeURIComponent(components[0]);
2845                 value = (components[1] !== undefined) ? decodeURIComponent(components[1]) : '';
2846
2847                 if (!recursive) {
2848                     if (object.hasOwnProperty(name)) {
2849                         if (!Ext.isArray(object[name])) {
2850                             object[name] = [object[name]];
2851                         }
2852
2853                         object[name].push(value);
2854                     }
2855                     else {
2856                         object[name] = value;
2857                     }
2858                 }
2859                 else {
2860                     matchedKeys = name.match(/(\[):?([^\]]*)\]/g);
2861                     matchedName = name.match(/^([^\[]+)/);
2862
2863
2864                     name = matchedName[0];
2865                     keys = [];
2866
2867                     if (matchedKeys === null) {
2868                         object[name] = value;
2869                         continue;
2870                     }
2871
2872                     for (j = 0, subLn = matchedKeys.length; j < subLn; j++) {
2873                         key = matchedKeys[j];
2874                         key = (key.length === 2) ? '' : key.substring(1, key.length - 1);
2875                         keys.push(key);
2876                     }
2877
2878                     keys.unshift(name);
2879
2880                     temp = object;
2881
2882                     for (j = 0, subLn = keys.length; j < subLn; j++) {
2883                         key = keys[j];
2884
2885                         if (j === subLn - 1) {
2886                             if (Ext.isArray(temp) && key === '') {
2887                                 temp.push(value);
2888                             }
2889                             else {
2890                                 temp[key] = value;
2891                             }
2892                         }
2893                         else {
2894                             if (temp[key] === undefined || typeof temp[key] === 'string') {
2895                                 nextKey = keys[j+1];
2896
2897                                 temp[key] = (Ext.isNumeric(nextKey) || nextKey === '') ? [] : {};
2898                             }
2899
2900                             temp = temp[key];
2901                         }
2902                     }
2903                 }
2904             }
2905         }
2906
2907         return object;
2908     },
2909
2910     /**
2911      * Iterate through an object and invoke the given callback function for each iteration. The iteration can be stop
2912      * by returning `false` in the callback function. For example:
2913
2914     var person = {
2915         name: 'Jacky'
2916         hairColor: 'black'
2917         loves: ['food', 'sleeping', 'wife']
2918     };
2919
2920     Ext.Object.each(person, function(key, value, myself) {
2921         console.log(key + ":" + value);
2922
2923         if (key === 'hairColor') {
2924             return false; // stop the iteration
2925         }
2926     });
2927
2928      * @param {Object} object The object to iterate
2929      * @param {Function} fn The callback function. Passed arguments for each iteration are:
2930
2931 - {String} `key`
2932 - {Mixed} `value`
2933 - {Object} `object` The object itself
2934
2935      * @param {Object} scope (Optional) The execution scope (`this`) of the callback function
2936      * @markdown
2937      */
2938     each: function(object, fn, scope) {
2939         for (var property in object) {
2940             if (object.hasOwnProperty(property)) {
2941                 if (fn.call(scope || object, property, object[property], object) === false) {
2942                     return;
2943                 }
2944             }
2945         }
2946     },
2947
2948     /**
2949      * Merges any number of objects recursively without referencing them or their children.
2950
2951     var extjs = {
2952         companyName: 'Ext JS',
2953         products: ['Ext JS', 'Ext GWT', 'Ext Designer'],
2954         isSuperCool: true
2955         office: {
2956             size: 2000,
2957             location: 'Palo Alto',
2958             isFun: true
2959         }
2960     };
2961
2962     var newStuff = {
2963         companyName: 'Sencha Inc.',
2964         products: ['Ext JS', 'Ext GWT', 'Ext Designer', 'Sencha Touch', 'Sencha Animator'],
2965         office: {
2966             size: 40000,
2967             location: 'Redwood City'
2968         }
2969     };
2970
2971     var sencha = Ext.Object.merge(extjs, newStuff);
2972
2973     // extjs and sencha then equals to
2974     {
2975         companyName: 'Sencha Inc.',
2976         products: ['Ext JS', 'Ext GWT', 'Ext Designer', 'Sencha Touch', 'Sencha Animator'],
2977         isSuperCool: true
2978         office: {
2979             size: 30000,
2980             location: 'Redwood City'
2981             isFun: true
2982         }
2983     }
2984
2985      * @param {Object} object,...
2986      * @return {Object} merged The object that is created as a result of merging all the objects passed in.
2987      * @markdown
2988      */
2989     merge: function(source, key, value) {
2990         if (typeof key === 'string') {
2991             if (value && value.constructor === Object) {
2992                 if (source[key] && source[key].constructor === Object) {
2993                     ExtObject.merge(source[key], value);
2994                 }
2995                 else {
2996                     source[key] = Ext.clone(value);
2997                 }
2998             }
2999             else {
3000                 source[key] = value;
3001             }
3002
3003             return source;
3004         }
3005
3006         var i = 1,
3007             ln = arguments.length,
3008             object, property;
3009
3010         for (; i < ln; i++) {
3011             object = arguments[i];
3012
3013             for (property in object) {
3014                 if (object.hasOwnProperty(property)) {
3015                     ExtObject.merge(source, property, object[property]);
3016                 }
3017             }
3018         }
3019
3020         return source;
3021     },
3022
3023     /**
3024      * Returns the first matching key corresponding to the given value.
3025      * If no matching value is found, null is returned.
3026
3027     var person = {
3028         name: 'Jacky',
3029         loves: 'food'
3030     };
3031
3032     alert(Ext.Object.getKey(sencha, 'loves')); // alerts 'food'
3033
3034      * @param {Object} object
3035      * @param {Object} value The value to find
3036      * @markdown
3037      */
3038     getKey: function(object, value) {
3039         for (var property in object) {
3040             if (object.hasOwnProperty(property) && object[property] === value) {
3041                 return property;
3042             }
3043         }
3044
3045         return null;
3046     },
3047
3048     /**
3049      * Gets all values of the given object as an array.
3050
3051     var values = Ext.Object.getValues({
3052         name: 'Jacky',
3053         loves: 'food'
3054     }); // ['Jacky', 'food']
3055
3056      * @param {Object} object
3057      * @return {Array} An array of values from the object
3058      * @markdown
3059      */
3060     getValues: function(object) {
3061         var values = [],
3062             property;
3063
3064         for (property in object) {
3065             if (object.hasOwnProperty(property)) {
3066                 values.push(object[property]);
3067             }
3068         }
3069
3070         return values;
3071     },
3072
3073     /**
3074      * Gets all keys of the given object as an array.
3075
3076     var values = Ext.Object.getKeys({
3077         name: 'Jacky',
3078         loves: 'food'
3079     }); // ['name', 'loves']
3080
3081      * @param {Object} object
3082      * @return {Array} An array of keys from the object
3083      * @method
3084      */
3085     getKeys: ('keys' in Object.prototype) ? Object.keys : function(object) {
3086         var keys = [],
3087             property;
3088
3089         for (property in object) {
3090             if (object.hasOwnProperty(property)) {
3091                 keys.push(property);
3092             }
3093         }
3094
3095         return keys;
3096     },
3097
3098     /**
3099      * Gets the total number of this object's own properties
3100
3101     var size = Ext.Object.getSize({
3102         name: 'Jacky',
3103         loves: 'food'
3104     }); // size equals 2
3105
3106      * @param {Object} object
3107      * @return {Number} size
3108      * @markdown
3109      */
3110     getSize: function(object) {
3111         var size = 0,
3112             property;
3113
3114         for (property in object) {
3115             if (object.hasOwnProperty(property)) {
3116                 size++;
3117             }
3118         }
3119
3120         return size;
3121     }
3122 };
3123
3124
3125 /**
3126  * A convenient alias method for {@link Ext.Object#merge}
3127  *
3128  * @member Ext
3129  * @method merge
3130  */
3131 Ext.merge = Ext.Object.merge;
3132
3133 /**
3134  * A convenient alias method for {@link Ext.Object#toQueryString}
3135  *
3136  * @member Ext
3137  * @method urlEncode
3138  * @deprecated 4.0.0 Use {@link Ext.Object#toQueryString Ext.Object.toQueryString} instead
3139  */
3140 Ext.urlEncode = function() {
3141     var args = Ext.Array.from(arguments),
3142         prefix = '';
3143
3144     // Support for the old `pre` argument
3145     if ((typeof args[1] === 'string')) {
3146         prefix = args[1] + '&';
3147         args[1] = false;
3148     }
3149
3150     return prefix + Ext.Object.toQueryString.apply(Ext.Object, args);
3151 };
3152
3153 /**
3154  * A convenient alias method for {@link Ext.Object#fromQueryString}
3155  *
3156  * @member Ext
3157  * @method urlDecode
3158  * @deprecated 4.0.0 Use {@link Ext.Object#fromQueryString Ext.Object.fromQueryString} instead
3159  */
3160 Ext.urlDecode = function() {
3161     return Ext.Object.fromQueryString.apply(Ext.Object, arguments);
3162 };
3163
3164 })();
3165
3166 /**
3167  * @class Ext.Date
3168  * A set of useful static methods to deal with date
3169  * Note that if Ext.Date is required and loaded, it will copy all methods / properties to
3170  * this object for convenience
3171  *
3172  * The date parsing and formatting syntax contains a subset of
3173  * <a href="http://www.php.net/date">PHP's date() function</a>, and the formats that are
3174  * supported will provide results equivalent to their PHP versions.
3175  *
3176  * The following is a list of all currently supported formats:
3177  * <pre class="">
3178 Format  Description                                                               Example returned values
3179 ------  -----------------------------------------------------------------------   -----------------------
3180   d     Day of the month, 2 digits with leading zeros                             01 to 31
3181   D     A short textual representation of the day of the week                     Mon to Sun
3182   j     Day of the month without leading zeros                                    1 to 31
3183   l     A full textual representation of the day of the week                      Sunday to Saturday
3184   N     ISO-8601 numeric representation of the day of the week                    1 (for Monday) through 7 (for Sunday)
3185   S     English ordinal suffix for the day of the month, 2 characters             st, nd, rd or th. Works well with j
3186   w     Numeric representation of the day of the week                             0 (for Sunday) to 6 (for Saturday)
3187   z     The day of the year (starting from 0)                                     0 to 364 (365 in leap years)
3188   W     ISO-8601 week number of year, weeks starting on Monday                    01 to 53
3189   F     A full textual representation of a month, such as January or March        January to December
3190   m     Numeric representation of a month, with leading zeros                     01 to 12
3191   M     A short textual representation of a month                                 Jan to Dec
3192   n     Numeric representation of a month, without leading zeros                  1 to 12
3193   t     Number of days in the given month                                         28 to 31
3194   L     Whether it&#39;s a leap year                                                  1 if it is a leap year, 0 otherwise.
3195   o     ISO-8601 year number (identical to (Y), but if the ISO week number (W)    Examples: 1998 or 2004
3196         belongs to the previous or next year, that year is used instead)
3197   Y     A full numeric representation of a year, 4 digits                         Examples: 1999 or 2003
3198   y     A two digit representation of a year                                      Examples: 99 or 03
3199   a     Lowercase Ante meridiem and Post meridiem                                 am or pm
3200   A     Uppercase Ante meridiem and Post meridiem                                 AM or PM
3201   g     12-hour format of an hour without leading zeros                           1 to 12
3202   G     24-hour format of an hour without leading zeros                           0 to 23
3203   h     12-hour format of an hour with leading zeros                              01 to 12
3204   H     24-hour format of an hour with leading zeros                              00 to 23
3205   i     Minutes, with leading zeros                                               00 to 59
3206   s     Seconds, with leading zeros                                               00 to 59
3207   u     Decimal fraction of a second                                              Examples:
3208         (minimum 1 digit, arbitrary number of digits allowed)                     001 (i.e. 0.001s) or
3209                                                                                   100 (i.e. 0.100s) or
3210                                                                                   999 (i.e. 0.999s) or
3211                                                                                   999876543210 (i.e. 0.999876543210s)
3212   O     Difference to Greenwich time (GMT) in hours and minutes                   Example: +1030
3213   P     Difference to Greenwich time (GMT) with colon between hours and minutes   Example: -08:00
3214   T     Timezone abbreviation of the machine running the code                     Examples: EST, MDT, PDT ...
3215   Z     Timezone offset in seconds (negative if west of UTC, positive if east)    -43200 to 50400
3216   c     ISO 8601 date
3217         Notes:                                                                    Examples:
3218         1) If unspecified, the month / day defaults to the current month / day,   1991 or
3219            the time defaults to midnight, while the timezone defaults to the      1992-10 or
3220            browser's timezone. If a time is specified, it must include both hours 1993-09-20 or
3221            and minutes. The "T" delimiter, seconds, milliseconds and timezone     1994-08-19T16:20+01:00 or
3222            are optional.                                                          1995-07-18T17:21:28-02:00 or
3223         2) The decimal fraction of a second, if specified, must contain at        1996-06-17T18:22:29.98765+03:00 or
3224            least 1 digit (there is no limit to the maximum number                 1997-05-16T19:23:30,12345-0400 or
3225            of digits allowed), and may be delimited by either a '.' or a ','      1998-04-15T20:24:31.2468Z or
3226         Refer to the examples on the right for the various levels of              1999-03-14T20:24:32Z or
3227         date-time granularity which are supported, or see                         2000-02-13T21:25:33
3228         http://www.w3.org/TR/NOTE-datetime for more info.                         2001-01-12 22:26:34
3229   U     Seconds since the Unix Epoch (January 1 1970 00:00:00 GMT)                1193432466 or -2138434463
3230   MS    Microsoft AJAX serialized dates                                           \/Date(1238606590509)\/ (i.e. UTC milliseconds since epoch) or
3231                                                                                   \/Date(1238606590509+0800)\/
3232 </pre>
3233  *
3234  * Example usage (note that you must escape format specifiers with '\\' to render them as character literals):
3235  * <pre><code>
3236 // Sample date:
3237 // 'Wed Jan 10 2007 15:05:01 GMT-0600 (Central Standard Time)'
3238
3239 var dt = new Date('1/10/2007 03:05:01 PM GMT-0600');
3240 console.log(Ext.Date.format(dt, 'Y-m-d'));                          // 2007-01-10
3241 console.log(Ext.Date.format(dt, 'F j, Y, g:i a'));                  // January 10, 2007, 3:05 pm
3242 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
3243 </code></pre>
3244  *
3245  * Here are some standard date/time patterns that you might find helpful.  They
3246  * are not part of the source of Ext.Date, but to use them you can simply copy this
3247  * block of code into any script that is included after Ext.Date and they will also become
3248  * globally available on the Date object.  Feel free to add or remove patterns as needed in your code.
3249  * <pre><code>
3250 Ext.Date.patterns = {
3251     ISO8601Long:"Y-m-d H:i:s",
3252     ISO8601Short:"Y-m-d",
3253     ShortDate: "n/j/Y",
3254     LongDate: "l, F d, Y",
3255     FullDateTime: "l, F d, Y g:i:s A",
3256     MonthDay: "F d",
3257     ShortTime: "g:i A",
3258     LongTime: "g:i:s A",
3259     SortableDateTime: "Y-m-d\\TH:i:s",
3260     UniversalSortableDateTime: "Y-m-d H:i:sO",
3261     YearMonth: "F, Y"
3262 };
3263 </code></pre>
3264  *
3265  * Example usage:
3266  * <pre><code>
3267 var dt = new Date();
3268 console.log(Ext.Date.format(dt, Ext.Date.patterns.ShortDate));
3269 </code></pre>
3270  * <p>Developer-written, custom formats may be used by supplying both a formatting and a parsing function
3271  * which perform to specialized requirements. The functions are stored in {@link #parseFunctions} and {@link #formatFunctions}.</p>
3272  * @singleton
3273  */
3274
3275 /*
3276  * Most of the date-formatting functions below are the excellent work of Baron Schwartz.
3277  * (see http://www.xaprb.com/blog/2005/12/12/javascript-closures-for-runtime-efficiency/)
3278  * They generate precompiled functions from format patterns instead of parsing and
3279  * processing each pattern every time a date is formatted. These functions are available
3280  * on every Date object.
3281  */
3282
3283 (function() {
3284
3285 // create private copy of Ext's Ext.util.Format.format() method
3286 // - to remove unnecessary dependency
3287 // - to resolve namespace conflict with MS-Ajax's implementation
3288 function xf(format) {
3289     var args = Array.prototype.slice.call(arguments, 1);
3290     return format.replace(/\{(\d+)\}/g, function(m, i) {
3291         return args[i];
3292     });
3293 }
3294
3295 Ext.Date = {
3296     /**
3297      * Returns the current timestamp
3298      * @return {Date} The current timestamp
3299      * @method
3300      */
3301     now: Date.now || function() {
3302         return +new Date();
3303     },
3304
3305     /**
3306      * @private
3307      * Private for now
3308      */
3309     toString: function(date) {
3310         var pad = Ext.String.leftPad;
3311
3312         return date.getFullYear() + "-"
3313             + pad(date.getMonth() + 1, 2, '0') + "-"
3314             + pad(date.getDate(), 2, '0') + "T"
3315             + pad(date.getHours(), 2, '0') + ":"
3316             + pad(date.getMinutes(), 2, '0') + ":"
3317             + pad(date.getSeconds(), 2, '0');
3318     },
3319
3320     /**
3321      * Returns the number of milliseconds between two dates
3322      * @param {Date} dateA The first date
3323      * @param {Date} dateB (optional) The second date, defaults to now
3324      * @return {Number} The difference in milliseconds
3325      */
3326     getElapsed: function(dateA, dateB) {
3327         return Math.abs(dateA - (dateB || new Date()));
3328     },
3329
3330     /**
3331      * Global flag which determines if strict date parsing should be used.
3332      * Strict date parsing will not roll-over invalid dates, which is the
3333      * default behaviour of javascript Date objects.
3334      * (see {@link #parse} for more information)
3335      * Defaults to <tt>false</tt>.
3336      * @static
3337      * @type Boolean
3338     */
3339     useStrict: false,
3340
3341     // private
3342     formatCodeToRegex: function(character, currentGroup) {
3343         // Note: currentGroup - position in regex result array (see notes for Ext.Date.parseCodes below)
3344         var p = utilDate.parseCodes[character];
3345
3346         if (p) {
3347           p = typeof p == 'function'? p() : p;
3348           utilDate.parseCodes[character] = p; // reassign function result to prevent repeated execution
3349         }
3350
3351         return p ? Ext.applyIf({
3352           c: p.c ? xf(p.c, currentGroup || "{0}") : p.c
3353         }, p) : {
3354             g: 0,
3355             c: null,
3356             s: Ext.String.escapeRegex(character) // treat unrecognised characters as literals
3357         };
3358     },
3359
3360     /**
3361      * <p>An object hash in which each property is a date parsing function. The property name is the
3362      * format string which that function parses.</p>
3363      * <p>This object is automatically populated with date parsing functions as
3364      * date formats are requested for Ext standard formatting strings.</p>
3365      * <p>Custom parsing functions may be inserted into this object, keyed by a name which from then on
3366      * may be used as a format string to {@link #parse}.<p>
3367      * <p>Example:</p><pre><code>
3368 Ext.Date.parseFunctions['x-date-format'] = myDateParser;
3369 </code></pre>
3370      * <p>A parsing function should return a Date object, and is passed the following parameters:<div class="mdetail-params"><ul>
3371      * <li><code>date</code> : String<div class="sub-desc">The date string to parse.</div></li>
3372      * <li><code>strict</code> : Boolean<div class="sub-desc">True to validate date strings while parsing
3373      * (i.e. prevent javascript Date "rollover") (The default must be false).
3374      * Invalid date strings should return null when parsed.</div></li>
3375      * </ul></div></p>
3376      * <p>To enable Dates to also be <i>formatted</i> according to that format, a corresponding
3377      * formatting function must be placed into the {@link #formatFunctions} property.
3378      * @property parseFunctions
3379      * @static
3380      * @type Object
3381      */
3382     parseFunctions: {
3383         "MS": function(input, strict) {
3384             // note: the timezone offset is ignored since the MS Ajax server sends
3385             // a UTC milliseconds-since-Unix-epoch value (negative values are allowed)
3386             var re = new RegExp('\\/Date\\(([-+])?(\\d+)(?:[+-]\\d{4})?\\)\\/');
3387             var r = (input || '').match(re);
3388             return r? new Date(((r[1] || '') + r[2]) * 1) : null;
3389         }
3390     },
3391     parseRegexes: [],
3392
3393     /**
3394      * <p>An object hash in which each property is a date formatting function. The property name is the
3395      * format string which corresponds to the produced formatted date string.</p>
3396      * <p>This object is automatically populated with date formatting functions as
3397      * date formats are requested for Ext standard formatting strings.</p>
3398      * <p>Custom formatting functions may be inserted into this object, keyed by a name which from then on
3399      * may be used as a format string to {@link #format}. Example:</p><pre><code>
3400 Ext.Date.formatFunctions['x-date-format'] = myDateFormatter;
3401 </code></pre>
3402      * <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>
3403      * <li><code>date</code> : Date<div class="sub-desc">The Date to format.</div></li>
3404      * </ul></div></p>
3405      * <p>To enable date strings to also be <i>parsed</i> according to that format, a corresponding
3406      * parsing function must be placed into the {@link #parseFunctions} property.
3407      * @property formatFunctions
3408      * @static
3409      * @type Object
3410      */
3411     formatFunctions: {
3412         "MS": function() {
3413             // UTC milliseconds since Unix epoch (MS-AJAX serialized date format (MRSF))
3414             return '\\/Date(' + this.getTime() + ')\\/';
3415         }
3416     },
3417
3418     y2kYear : 50,
3419
3420     /**
3421      * Date interval constant
3422      * @static
3423      * @type String
3424      */
3425     MILLI : "ms",
3426
3427     /**
3428      * Date interval constant
3429      * @static
3430      * @type String
3431      */
3432     SECOND : "s",
3433
3434     /**
3435      * Date interval constant
3436      * @static
3437      * @type String
3438      */
3439     MINUTE : "mi",
3440
3441     /** Date interval constant
3442      * @static
3443      * @type String
3444      */
3445     HOUR : "h",
3446
3447     /**
3448      * Date interval constant
3449      * @static
3450      * @type String
3451      */
3452     DAY : "d",
3453
3454     /**
3455      * Date interval constant
3456      * @static
3457      * @type String
3458      */
3459     MONTH : "mo",
3460
3461     /**
3462      * Date interval constant
3463      * @static
3464      * @type String
3465      */
3466     YEAR : "y",
3467
3468     /**
3469      * <p>An object hash containing default date values used during date parsing.</p>
3470      * <p>The following properties are available:<div class="mdetail-params"><ul>
3471      * <li><code>y</code> : Number<div class="sub-desc">The default year value. (defaults to undefined)</div></li>
3472      * <li><code>m</code> : Number<div class="sub-desc">The default 1-based month value. (defaults to undefined)</div></li>
3473      * <li><code>d</code> : Number<div class="sub-desc">The default day value. (defaults to undefined)</div></li>
3474      * <li><code>h</code> : Number<div class="sub-desc">The default hour value. (defaults to undefined)</div></li>
3475      * <li><code>i</code> : Number<div class="sub-desc">The default minute value. (defaults to undefined)</div></li>
3476      * <li><code>s</code> : Number<div class="sub-desc">The default second value. (defaults to undefined)</div></li>
3477      * <li><code>ms</code> : Number<div class="sub-desc">The default millisecond value. (defaults to undefined)</div></li>
3478      * </ul></div></p>
3479      * <p>Override these properties to customize the default date values used by the {@link #parse} method.</p>
3480      * <p><b>Note: In countries which experience Daylight Saving Time (i.e. DST), the <tt>h</tt>, <tt>i</tt>, <tt>s</tt>
3481      * and <tt>ms</tt> properties may coincide with the exact time in which DST takes effect.
3482      * It is the responsiblity of the developer to account for this.</b></p>
3483      * Example Usage:
3484      * <pre><code>
3485 // set default day value to the first day of the month
3486 Ext.Date.defaults.d = 1;
3487
3488 // parse a February date string containing only year and month values.
3489 // setting the default day value to 1 prevents weird date rollover issues
3490 // when attempting to parse the following date string on, for example, March 31st 2009.
3491 Ext.Date.parse('2009-02', 'Y-m'); // returns a Date object representing February 1st 2009
3492 </code></pre>
3493      * @property defaults
3494      * @static
3495      * @type Object
3496      */
3497     defaults: {},
3498
3499     /**
3500      * An array of textual day names.
3501      * Override these values for international dates.
3502      * Example:
3503      * <pre><code>
3504 Ext.Date.dayNames = [
3505     'SundayInYourLang',
3506     'MondayInYourLang',
3507     ...
3508 ];
3509 </code></pre>
3510      * @type Array
3511      * @static
3512      */
3513     dayNames : [
3514         "Sunday",
3515         "Monday",
3516         "Tuesday",
3517         "Wednesday",
3518         "Thursday",
3519         "Friday",
3520         "Saturday"
3521     ],
3522
3523     /**
3524      * An array of textual month names.
3525      * Override these values for international dates.
3526      * Example:
3527      * <pre><code>
3528 Ext.Date.monthNames = [
3529     'JanInYourLang',
3530     'FebInYourLang',
3531     ...
3532 ];
3533 </code></pre>
3534      * @type Array
3535      * @static
3536      */
3537     monthNames : [
3538         "January",
3539         "February",
3540         "March",
3541         "April",
3542         "May",
3543         "June",
3544         "July",
3545         "August",
3546         "September",
3547         "October",
3548         "November",
3549         "December"
3550     ],
3551
3552     /**
3553      * An object hash of zero-based javascript month numbers (with short month names as keys. note: keys are case-sensitive).
3554      * Override these values for international dates.
3555      * Example:
3556      * <pre><code>
3557 Ext.Date.monthNumbers = {
3558     'ShortJanNameInYourLang':0,
3559     'ShortFebNameInYourLang':1,
3560     ...
3561 };
3562 </code></pre>
3563      * @type Object
3564      * @static
3565      */
3566     monthNumbers : {
3567         Jan:0,
3568         Feb:1,
3569         Mar:2,
3570         Apr:3,
3571         May:4,
3572         Jun:5,
3573         Jul:6,
3574         Aug:7,
3575         Sep:8,
3576         Oct:9,
3577         Nov:10,
3578         Dec:11
3579     },
3580     /**
3581      * <p>The date format string that the {@link Ext.util.Format#dateRenderer}
3582      * and {@link Ext.util.Format#date} functions use.  See {@link Ext.Date} for details.</p>
3583      * <p>This defaults to <code>m/d/Y</code>, but may be overridden in a locale file.</p>
3584      * @property defaultFormat
3585      * @static
3586      * @type String
3587      */
3588     defaultFormat : "m/d/Y",
3589     /**
3590      * Get the short month name for the given month number.
3591      * Override this function for international dates.
3592      * @param {Number} month A zero-based javascript month number.
3593      * @return {String} The short month name.
3594      * @static
3595      */
3596     getShortMonthName : function(month) {
3597         return utilDate.monthNames[month].substring(0, 3);
3598     },
3599
3600     /**
3601      * Get the short day name for the given day number.
3602      * Override this function for international dates.
3603      * @param {Number} day A zero-based javascript day number.
3604      * @return {String} The short day name.
3605      * @static
3606      */
3607     getShortDayName : function(day) {
3608         return utilDate.dayNames[day].substring(0, 3);
3609     },
3610
3611     /**
3612      * Get the zero-based javascript month number for the given short/full month name.
3613      * Override this function for international dates.
3614      * @param {String} name The short/full month name.
3615      * @return {Number} The zero-based javascript month number.
3616      * @static
3617      */
3618     getMonthNumber : function(name) {
3619         // handle camel casing for english month names (since the keys for the Ext.Date.monthNumbers hash are case sensitive)
3620         return utilDate.monthNumbers[name.substring(0, 1).toUpperCase() + name.substring(1, 3).toLowerCase()];
3621     },
3622
3623     /**
3624      * Checks if the specified format contains hour information
3625      * @param {String} format The format to check
3626      * @return {Boolean} True if the format contains hour information
3627      * @static
3628      * @method
3629      */
3630     formatContainsHourInfo : (function(){
3631         var stripEscapeRe = /(\\.)/g,
3632             hourInfoRe = /([gGhHisucUOPZ]|MS)/;
3633         return function(format){
3634             return hourInfoRe.test(format.replace(stripEscapeRe, ''));
3635         };
3636     })(),
3637
3638     /**
3639      * Checks if the specified format contains information about
3640      * anything other than the time.
3641      * @param {String} format The format to check
3642      * @return {Boolean} True if the format contains information about
3643      * date/day information.
3644      * @static
3645      * @method
3646      */
3647     formatContainsDateInfo : (function(){
3648         var stripEscapeRe = /(\\.)/g,
3649             dateInfoRe = /([djzmnYycU]|MS)/;
3650
3651         return function(format){
3652             return dateInfoRe.test(format.replace(stripEscapeRe, ''));
3653         };
3654     })(),
3655
3656     /**
3657      * The base format-code to formatting-function hashmap used by the {@link #format} method.
3658      * Formatting functions are strings (or functions which return strings) which
3659      * will return the appropriate value when evaluated in the context of the Date object
3660      * from which the {@link #format} method is called.
3661      * Add to / override these mappings for custom date formatting.
3662      * Note: Ext.Date.format() treats characters as literals if an appropriate mapping cannot be found.
3663      * Example:
3664      * <pre><code>
3665 Ext.Date.formatCodes.x = "Ext.util.Format.leftPad(this.getDate(), 2, '0')";
3666 console.log(Ext.Date.format(new Date(), 'X'); // returns the current day of the month
3667 </code></pre>
3668      * @type Object
3669      * @static
3670      */
3671     formatCodes : {
3672         d: "Ext.String.leftPad(this.getDate(), 2, '0')",
3673         D: "Ext.Date.getShortDayName(this.getDay())", // get localised short day name
3674         j: "this.getDate()",
3675         l: "Ext.Date.dayNames[this.getDay()]",
3676         N: "(this.getDay() ? this.getDay() : 7)",
3677         S: "Ext.Date.getSuffix(this)",
3678         w: "this.getDay()",
3679         z: "Ext.Date.getDayOfYear(this)",
3680         W: "Ext.String.leftPad(Ext.Date.getWeekOfYear(this), 2, '0')",
3681         F: "Ext.Date.monthNames[this.getMonth()]",
3682         m: "Ext.String.leftPad(this.getMonth() + 1, 2, '0')",
3683         M: "Ext.Date.getShortMonthName(this.getMonth())", // get localised short month name
3684         n: "(this.getMonth() + 1)",
3685         t: "Ext.Date.getDaysInMonth(this)",
3686         L: "(Ext.Date.isLeapYear(this) ? 1 : 0)",
3687         o: "(this.getFullYear() + (Ext.Date.getWeekOfYear(this) == 1 && this.getMonth() > 0 ? +1 : (Ext.Date.getWeekOfYear(this) >= 52 && this.getMonth() < 11 ? -1 : 0)))",
3688         Y: "Ext.String.leftPad(this.getFullYear(), 4, '0')",
3689         y: "('' + this.getFullYear()).substring(2, 4)",
3690         a: "(this.getHours() < 12 ? 'am' : 'pm')",
3691         A: "(this.getHours() < 12 ? 'AM' : 'PM')",
3692         g: "((this.getHours() % 12) ? this.getHours() % 12 : 12)",
3693         G: "this.getHours()",
3694         h: "Ext.String.leftPad((this.getHours() % 12) ? this.getHours() % 12 : 12, 2, '0')",
3695         H: "Ext.String.leftPad(this.getHours(), 2, '0')",
3696         i: "Ext.String.leftPad(this.getMinutes(), 2, '0')",
3697         s: "Ext.String.leftPad(this.getSeconds(), 2, '0')",
3698         u: "Ext.String.leftPad(this.getMilliseconds(), 3, '0')",
3699         O: "Ext.Date.getGMTOffset(this)",
3700         P: "Ext.Date.getGMTOffset(this, true)",
3701         T: "Ext.Date.getTimezone(this)",
3702         Z: "(this.getTimezoneOffset() * -60)",
3703
3704         c: function() { // ISO-8601 -- GMT format
3705             for (var c = "Y-m-dTH:i:sP", code = [], i = 0, l = c.length; i < l; ++i) {
3706                 var e = c.charAt(i);
3707                 code.push(e == "T" ? "'T'" : utilDate.getFormatCode(e)); // treat T as a character literal
3708             }
3709             return code.join(" + ");
3710         },
3711         /*
3712         c: function() { // ISO-8601 -- UTC format
3713             return [
3714               "this.getUTCFullYear()", "'-'",
3715               "Ext.util.Format.leftPad(this.getUTCMonth() + 1, 2, '0')", "'-'",
3716               "Ext.util.Format.leftPad(this.getUTCDate(), 2, '0')",
3717               "'T'",
3718               "Ext.util.Format.leftPad(this.getUTCHours(), 2, '0')", "':'",
3719               "Ext.util.Format.leftPad(this.getUTCMinutes(), 2, '0')", "':'",
3720               "Ext.util.Format.leftPad(this.getUTCSeconds(), 2, '0')",
3721               "'Z'"
3722             ].join(" + ");
3723         },
3724         */
3725
3726         U: "Math.round(this.getTime() / 1000)"
3727     },
3728
3729     /**
3730      * Checks if the passed Date parameters will cause a javascript Date "rollover".
3731      * @param {Number} year 4-digit year
3732      * @param {Number} month 1-based month-of-year
3733      * @param {Number} day Day of month
3734      * @param {Number} hour (optional) Hour
3735      * @param {Number} minute (optional) Minute
3736      * @param {Number} second (optional) Second
3737      * @param {Number} millisecond (optional) Millisecond
3738      * @return {Boolean} true if the passed parameters do not cause a Date "rollover", false otherwise.
3739      * @static
3740      */
3741     isValid : function(y, m, d, h, i, s, ms) {
3742         // setup defaults
3743         h = h || 0;
3744         i = i || 0;
3745         s = s || 0;
3746         ms = ms || 0;
3747
3748         // Special handling for year < 100
3749         var dt = utilDate.add(new Date(y < 100 ? 100 : y, m - 1, d, h, i, s, ms), utilDate.YEAR, y < 100 ? y - 100 : 0);
3750
3751         return y == dt.getFullYear() &&
3752             m == dt.getMonth() + 1 &&
3753             d == dt.getDate() &&
3754             h == dt.getHours() &&
3755             i == dt.getMinutes() &&
3756             s == dt.getSeconds() &&
3757             ms == dt.getMilliseconds();
3758     },
3759
3760     /**
3761      * Parses the passed string using the specified date format.
3762      * Note that this function expects normal calendar dates, meaning that months are 1-based (i.e. 1 = January).
3763      * The {@link #defaults} hash will be used for any date value (i.e. year, month, day, hour, minute, second or millisecond)
3764      * which cannot be found in the passed string. If a corresponding default date value has not been specified in the {@link #defaults} hash,
3765      * the current date's year, month, day or DST-adjusted zero-hour time value will be used instead.
3766      * Keep in mind that the input date string must precisely match the specified format string
3767      * in order for the parse operation to be successful (failed parse operations return a null value).
3768      * <p>Example:</p><pre><code>
3769 //dt = Fri May 25 2007 (current date)
3770 var dt = new Date();
3771
3772 //dt = Thu May 25 2006 (today&#39;s month/day in 2006)
3773 dt = Ext.Date.parse("2006", "Y");
3774
3775 //dt = Sun Jan 15 2006 (all date parts specified)
3776 dt = Ext.Date.parse("2006-01-15", "Y-m-d");
3777
3778 //dt = Sun Jan 15 2006 15:20:01
3779 dt = Ext.Date.parse("2006-01-15 3:20:01 PM", "Y-m-d g:i:s A");
3780
3781 // attempt to parse Sun Feb 29 2006 03:20:01 in strict mode
3782 dt = Ext.Date.parse("2006-02-29 03:20:01", "Y-m-d H:i:s", true); // returns null
3783 </code></pre>
3784      * @param {String} input The raw date string.
3785      * @param {String} format The expected date string format.
3786      * @param {Boolean} strict (optional) True to validate date strings while parsing (i.e. prevents javascript Date "rollover")
3787                         (defaults to false). Invalid date strings will return null when parsed.
3788      * @return {Date} The parsed Date.
3789      * @static
3790      */
3791     parse : function(input, format, strict) {
3792         var p = utilDate.parseFunctions;
3793         if (p[format] == null) {
3794             utilDate.createParser(format);
3795         }
3796         return p[format](input, Ext.isDefined(strict) ? strict : utilDate.useStrict);
3797     },
3798
3799     // Backwards compat
3800     parseDate: function(input, format, strict){
3801         return utilDate.parse(input, format, strict);
3802     },
3803
3804
3805     // private
3806     getFormatCode : function(character) {
3807         var f = utilDate.formatCodes[character];
3808
3809         if (f) {
3810           f = typeof f == 'function'? f() : f;
3811           utilDate.formatCodes[character] = f; // reassign function result to prevent repeated execution
3812         }
3813
3814         // note: unknown characters are treated as literals
3815         return f || ("'" + Ext.String.escape(character) + "'");
3816     },
3817
3818     // private
3819     createFormat : function(format) {
3820         var code = [],
3821             special = false,
3822             ch = '';
3823
3824         for (var i = 0; i < format.length; ++i) {
3825             ch = format.charAt(i);
3826             if (!special && ch == "\\") {
3827                 special = true;
3828             } else if (special) {
3829                 special = false;
3830                 code.push("'" + Ext.String.escape(ch) + "'");
3831             } else {
3832                 code.push(utilDate.getFormatCode(ch));
3833             }
3834         }
3835         utilDate.formatFunctions[format] = Ext.functionFactory("return " + code.join('+'));
3836     },
3837
3838     // private
3839     createParser : (function() {
3840         var code = [
3841             "var dt, y, m, d, h, i, s, ms, o, z, zz, u, v,",
3842                 "def = Ext.Date.defaults,",
3843                 "results = String(input).match(Ext.Date.parseRegexes[{0}]);", // either null, or an array of matched strings
3844
3845             "if(results){",
3846                 "{1}",
3847
3848                 "if(u != null){", // i.e. unix time is defined
3849                     "v = new Date(u * 1000);", // give top priority to UNIX time
3850                 "}else{",
3851                     // create Date object representing midnight of the current day;
3852                     // this will provide us with our date defaults
3853                     // (note: clearTime() handles Daylight Saving Time automatically)
3854                     "dt = Ext.Date.clearTime(new Date);",
3855
3856                     // date calculations (note: these calculations create a dependency on Ext.Number.from())
3857                     "y = Ext.Number.from(y, Ext.Number.from(def.y, dt.getFullYear()));",
3858                     "m = Ext.Number.from(m, Ext.Number.from(def.m - 1, dt.getMonth()));",
3859                     "d = Ext.Number.from(d, Ext.Number.from(def.d, dt.getDate()));",
3860
3861                     // time calculations (note: these calculations create a dependency on Ext.Number.from())
3862                     "h  = Ext.Number.from(h, Ext.Number.from(def.h, dt.getHours()));",
3863                     "i  = Ext.Number.from(i, Ext.Number.from(def.i, dt.getMinutes()));",
3864                     "s  = Ext.Number.from(s, Ext.Number.from(def.s, dt.getSeconds()));",
3865                     "ms = Ext.Number.from(ms, Ext.Number.from(def.ms, dt.getMilliseconds()));",
3866
3867                     "if(z >= 0 && y >= 0){",
3868                         // both the year and zero-based day of year are defined and >= 0.
3869                         // these 2 values alone provide sufficient info to create a full date object
3870
3871                         // create Date object representing January 1st for the given year
3872                         // handle years < 100 appropriately
3873                         "v = Ext.Date.add(new Date(y < 100 ? 100 : y, 0, 1, h, i, s, ms), Ext.Date.YEAR, y < 100 ? y - 100 : 0);",
3874
3875                         // then add day of year, checking for Date "rollover" if necessary
3876                         "v = !strict? v : (strict === true && (z <= 364 || (Ext.Date.isLeapYear(v) && z <= 365))? Ext.Date.add(v, Ext.Date.DAY, z) : null);",
3877                     "}else if(strict === true && !Ext.Date.isValid(y, m + 1, d, h, i, s, ms)){", // check for Date "rollover"
3878                         "v = null;", // invalid date, so return null
3879                     "}else{",
3880                         // plain old Date object
3881                         // handle years < 100 properly
3882                         "v = Ext.Date.add(new Date(y < 100 ? 100 : y, m, d, h, i, s, ms), Ext.Date.YEAR, y < 100 ? y - 100 : 0);",
3883                     "}",
3884                 "}",
3885             "}",
3886
3887             "if(v){",
3888                 // favour UTC offset over GMT offset
3889                 "if(zz != null){",
3890                     // reset to UTC, then add offset
3891                     "v = Ext.Date.add(v, Ext.Date.SECOND, -v.getTimezoneOffset() * 60 - zz);",
3892                 "}else if(o){",
3893                     // reset to GMT, then add offset
3894                     "v = Ext.Date.add(v, Ext.Date.MINUTE, -v.getTimezoneOffset() + (sn == '+'? -1 : 1) * (hr * 60 + mn));",
3895                 "}",
3896             "}",
3897
3898             "return v;"
3899         ].join('\n');
3900
3901         return function(format) {
3902             var regexNum = utilDate.parseRegexes.length,
3903                 currentGroup = 1,
3904                 calc = [],
3905                 regex = [],
3906                 special = false,
3907                 ch = "";
3908
3909             for (var i = 0; i < format.length; ++i) {
3910                 ch = format.charAt(i);
3911                 if (!special && ch == "\\") {
3912                     special = true;
3913                 } else if (special) {
3914                     special = false;
3915                     regex.push(Ext.String.escape(ch));
3916                 } else {
3917                     var obj = utilDate.formatCodeToRegex(ch, currentGroup);
3918                     currentGroup += obj.g;
3919                     regex.push(obj.s);
3920                     if (obj.g && obj.c) {
3921                         calc.push(obj.c);
3922                     }
3923                 }
3924             }
3925
3926             utilDate.parseRegexes[regexNum] = new RegExp("^" + regex.join('') + "$", 'i');
3927             utilDate.parseFunctions[format] = Ext.functionFactory("input", "strict", xf(code, regexNum, calc.join('')));
3928         };
3929     })(),
3930
3931     // private
3932     parseCodes : {
3933         /*
3934          * Notes:
3935          * g = {Number} calculation group (0 or 1. only group 1 contributes to date calculations.)
3936          * c = {String} calculation method (required for group 1. null for group 0. {0} = currentGroup - position in regex result array)
3937          * s = {String} regex pattern. all matches are stored in results[], and are accessible by the calculation mapped to 'c'
3938          */
3939         d: {
3940             g:1,
3941             c:"d = parseInt(results[{0}], 10);\n",
3942             s:"(\\d{2})" // day of month with leading zeroes (01 - 31)
3943         },
3944         j: {
3945             g:1,
3946             c:"d = parseInt(results[{0}], 10);\n",
3947             s:"(\\d{1,2})" // day of month without leading zeroes (1 - 31)
3948         },
3949         D: function() {
3950             for (var a = [], i = 0; i < 7; a.push(utilDate.getShortDayName(i)), ++i); // get localised short day names
3951             return {
3952                 g:0,
3953                 c:null,
3954                 s:"(?:" + a.join("|") +")"
3955             };
3956         },
3957         l: function() {
3958             return {
3959                 g:0,
3960                 c:null,
3961                 s:"(?:" + utilDate.dayNames.join("|") + ")"
3962             };
3963         },
3964         N: {
3965             g:0,
3966             c:null,
3967             s:"[1-7]" // ISO-8601 day number (1 (monday) - 7 (sunday))
3968         },
3969         S: {
3970             g:0,
3971             c:null,
3972             s:"(?:st|nd|rd|th)"
3973         },
3974         w: {
3975             g:0,
3976             c:null,
3977             s:"[0-6]" // javascript day number (0 (sunday) - 6 (saturday))
3978         },
3979         z: {
3980             g:1,
3981             c:"z = parseInt(results[{0}], 10);\n",
3982             s:"(\\d{1,3})" // day of the year (0 - 364 (365 in leap years))
3983         },
3984         W: {
3985             g:0,
3986             c:null,
3987             s:"(?:\\d{2})" // ISO-8601 week number (with leading zero)
3988         },
3989         F: function() {
3990             return {
3991                 g:1,
3992                 c:"m = parseInt(Ext.Date.getMonthNumber(results[{0}]), 10);\n", // get localised month number
3993                 s:"(" + utilDate.monthNames.join("|") + ")"
3994             };
3995         },
3996         M: function() {
3997             for (var a = [], i = 0; i < 12; a.push(utilDate.getShortMonthName(i)), ++i); // get localised short month names
3998             return Ext.applyIf({
3999                 s:"(" + a.join("|") + ")"
4000             }, utilDate.formatCodeToRegex("F"));
4001         },
4002         m: {
4003             g:1,
4004             c:"m = parseInt(results[{0}], 10) - 1;\n",
4005             s:"(\\d{2})" // month number with leading zeros (01 - 12)
4006         },
4007         n: {
4008             g:1,
4009             c:"m = parseInt(results[{0}], 10) - 1;\n",
4010             s:"(\\d{1,2})" // month number without leading zeros (1 - 12)
4011         },
4012         t: {
4013             g:0,
4014             c:null,
4015             s:"(?:\\d{2})" // no. of days in the month (28 - 31)
4016         },
4017         L: {
4018             g:0,
4019             c:null,
4020             s:"(?:1|0)"
4021         },
4022         o: function() {
4023             return utilDate.formatCodeToRegex("Y");
4024         },
4025         Y: {
4026             g:1,
4027             c:"y = parseInt(results[{0}], 10);\n",
4028             s:"(\\d{4})" // 4-digit year
4029         },
4030         y: {
4031             g:1,
4032             c:"var ty = parseInt(results[{0}], 10);\n"
4033                 + "y = ty > Ext.Date.y2kYear ? 1900 + ty : 2000 + ty;\n", // 2-digit year
4034             s:"(\\d{1,2})"
4035         },
4036         /*
4037          * In the am/pm parsing routines, we allow both upper and lower case
4038          * even though it doesn't exactly match the spec. It gives much more flexibility
4039          * in being able to specify case insensitive regexes.
4040          */
4041         a: {
4042             g:1,
4043             c:"if (/(am)/i.test(results[{0}])) {\n"
4044                 + "if (!h || h == 12) { h = 0; }\n"
4045                 + "} else { if (!h || h < 12) { h = (h || 0) + 12; }}",
4046             s:"(am|pm|AM|PM)"
4047         },
4048         A: {
4049             g:1,
4050             c:"if (/(am)/i.test(results[{0}])) {\n"
4051                 + "if (!h || h == 12) { h = 0; }\n"
4052                 + "} else { if (!h || h < 12) { h = (h || 0) + 12; }}",
4053             s:"(AM|PM|am|pm)"
4054         },
4055         g: function() {
4056             return utilDate.formatCodeToRegex("G");
4057         },
4058         G: {
4059             g:1,
4060             c:"h = parseInt(results[{0}], 10);\n",
4061             s:"(\\d{1,2})" // 24-hr format of an hour without leading zeroes (0 - 23)
4062         },
4063         h: function() {
4064             return utilDate.formatCodeToRegex("H");
4065         },
4066         H: {
4067             g:1,
4068             c:"h = parseInt(results[{0}], 10);\n",
4069             s:"(\\d{2})" //  24-hr format of an hour with leading zeroes (00 - 23)
4070         },
4071         i: {
4072             g:1,
4073             c:"i = parseInt(results[{0}], 10);\n",
4074             s:"(\\d{2})" // minutes with leading zeros (00 - 59)
4075         },
4076         s: {
4077             g:1,
4078             c:"s = parseInt(results[{0}], 10);\n",
4079             s:"(\\d{2})" // seconds with leading zeros (00 - 59)
4080         },
4081         u: {
4082             g:1,
4083             c:"ms = results[{0}]; ms = parseInt(ms, 10)/Math.pow(10, ms.length - 3);\n",
4084             s:"(\\d+)" // decimal fraction of a second (minimum = 1 digit, maximum = unlimited)
4085         },
4086         O: {
4087             g:1,
4088             c:[
4089                 "o = results[{0}];",
4090                 "var sn = o.substring(0,1),", // get + / - sign
4091                     "hr = o.substring(1,3)*1 + Math.floor(o.substring(3,5) / 60),", // get hours (performs minutes-to-hour conversion also, just in case)
4092                     "mn = o.substring(3,5) % 60;", // get minutes
4093                 "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
4094             ].join("\n"),
4095             s: "([+\-]\\d{4})" // GMT offset in hrs and mins
4096         },
4097         P: {
4098             g:1,
4099             c:[
4100                 "o = results[{0}];",
4101                 "var sn = o.substring(0,1),", // get + / - sign
4102                     "hr = o.substring(1,3)*1 + Math.floor(o.substring(4,6) / 60),", // get hours (performs minutes-to-hour conversion also, just in case)
4103                     "mn = o.substring(4,6) % 60;", // get minutes
4104                 "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
4105             ].join("\n"),
4106             s: "([+\-]\\d{2}:\\d{2})" // GMT offset in hrs and mins (with colon separator)
4107         },
4108         T: {
4109             g:0,
4110             c:null,
4111             s:"[A-Z]{1,4}" // timezone abbrev. may be between 1 - 4 chars
4112         },
4113         Z: {
4114             g:1,
4115             c:"zz = results[{0}] * 1;\n" // -43200 <= UTC offset <= 50400
4116                   + "zz = (-43200 <= zz && zz <= 50400)? zz : null;\n",
4117             s:"([+\-]?\\d{1,5})" // leading '+' sign is optional for UTC offset
4118         },
4119         c: function() {
4120             var calc = [],
4121                 arr = [
4122                     utilDate.formatCodeToRegex("Y", 1), // year
4123                     utilDate.formatCodeToRegex("m", 2), // month
4124                     utilDate.formatCodeToRegex("d", 3), // day
4125                     utilDate.formatCodeToRegex("h", 4), // hour
4126                     utilDate.formatCodeToRegex("i", 5), // minute
4127                     utilDate.formatCodeToRegex("s", 6), // second
4128                     {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)
4129                     {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
4130                         "if(results[8]) {", // timezone specified
4131                             "if(results[8] == 'Z'){",
4132                                 "zz = 0;", // UTC
4133                             "}else if (results[8].indexOf(':') > -1){",
4134                                 utilDate.formatCodeToRegex("P", 8).c, // timezone offset with colon separator
4135                             "}else{",
4136                                 utilDate.formatCodeToRegex("O", 8).c, // timezone offset without colon separator
4137                             "}",
4138                         "}"
4139                     ].join('\n')}
4140                 ];
4141
4142             for (var i = 0, l = arr.length; i < l; ++i) {
4143                 calc.push(arr[i].c);
4144             }
4145
4146             return {
4147                 g:1,
4148                 c:calc.join(""),
4149                 s:[
4150                     arr[0].s, // year (required)
4151                     "(?:", "-", arr[1].s, // month (optional)
4152                         "(?:", "-", arr[2].s, // day (optional)
4153                             "(?:",
4154                                 "(?:T| )?", // time delimiter -- either a "T" or a single blank space
4155                                 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
4156                                 "(?::", arr[5].s, ")?", // seconds (optional)
4157                                 "(?:(?:\\.|,)(\\d+))?", // decimal fraction of a second (e.g. ",12345" or ".98765") (optional)
4158                                 "(Z|(?:[-+]\\d{2}(?::)?\\d{2}))?", // "Z" (UTC) or "-0530" (UTC offset without colon delimiter) or "+08:00" (UTC offset with colon delimiter) (optional)
4159                             ")?",
4160                         ")?",
4161                     ")?"
4162                 ].join("")
4163             };
4164         },
4165         U: {
4166             g:1,
4167             c:"u = parseInt(results[{0}], 10);\n",
4168             s:"(-?\\d+)" // leading minus sign indicates seconds before UNIX epoch
4169         }
4170     },
4171
4172     //Old Ext.Date prototype methods.
4173     // private
4174     dateFormat: function(date, format) {
4175         return utilDate.format(date, format);
4176     },
4177
4178     /**
4179      * Formats a date given the supplied format string.
4180      * @param {Date} date The date to format
4181      * @param {String} format The format string
4182      * @return {String} The formatted date
4183      */
4184     format: function(date, format) {
4185         if (utilDate.formatFunctions[format] == null) {
4186             utilDate.createFormat(format);
4187         }
4188         var result = utilDate.formatFunctions[format].call(date);
4189         return result + '';
4190     },
4191
4192     /**
4193      * Get the timezone abbreviation of the current date (equivalent to the format specifier 'T').
4194      *
4195      * Note: The date string returned by the javascript Date object's toString() method varies
4196      * between browsers (e.g. FF vs IE) and system region settings (e.g. IE in Asia vs IE in America).
4197      * For a given date string e.g. "Thu Oct 25 2007 22:55:35 GMT+0800 (Malay Peninsula Standard Time)",
4198      * getTimezone() first tries to get the timezone abbreviation from between a pair of parentheses
4199      * (which may or may not be present), failing which it proceeds to get the timezone abbreviation
4200      * from the GMT offset portion of the date string.
4201      * @param {Date} date The date
4202      * @return {String} The abbreviated timezone name (e.g. 'CST', 'PDT', 'EDT', 'MPST' ...).
4203      */
4204     getTimezone : function(date) {
4205         // the following list shows the differences between date strings from different browsers on a WinXP SP2 machine from an Asian locale:
4206         //
4207         // Opera  : "Thu, 25 Oct 2007 22:53:45 GMT+0800" -- shortest (weirdest) date string of the lot
4208         // 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)
4209         // FF     : "Thu Oct 25 2007 22:55:35 GMT+0800 (Malay Peninsula Standard Time)" -- value in parentheses always gives the correct timezone
4210         // IE     : "Thu Oct 25 22:54:35 UTC+0800 2007" -- (Asian system setting) look for 3-4 letter timezone abbrev
4211         // IE     : "Thu Oct 25 17:06:37 PDT 2007" -- (American system setting) look for 3-4 letter timezone abbrev
4212         //
4213         // this crazy regex attempts to guess the correct timezone abbreviation despite these differences.
4214         // step 1: (?:\((.*)\) -- find timezone in parentheses
4215         // 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
4216         // step 3: remove all non uppercase characters found in step 1 and 2
4217         return date.toString().replace(/^.* (?:\((.*)\)|([A-Z]{1,4})(?:[\-+][0-9]{4})?(?: -?\d+)?)$/, "$1$2").replace(/[^A-Z]/g, "");
4218     },
4219
4220     /**
4221      * Get the offset from GMT of the current date (equivalent to the format specifier 'O').
4222      * @param {Date} date The date
4223      * @param {Boolean} colon (optional) true to separate the hours and minutes with a colon (defaults to false).
4224      * @return {String} The 4-character offset string prefixed with + or - (e.g. '-0600').
4225      */
4226     getGMTOffset : function(date, colon) {
4227         var offset = date.getTimezoneOffset();
4228         return (offset > 0 ? "-" : "+")
4229             + Ext.String.leftPad(Math.floor(Math.abs(offset) / 60), 2, "0")
4230             + (colon ? ":" : "")
4231             + Ext.String.leftPad(Math.abs(offset % 60), 2, "0");
4232     },
4233
4234     /**
4235      * Get the numeric day number of the year, adjusted for leap year.
4236      * @param {Date} date The date
4237      * @return {Number} 0 to 364 (365 in leap years).
4238      */
4239     getDayOfYear: function(date) {
4240         var num = 0,
4241             d = Ext.Date.clone(date),
4242             m = date.getMonth(),
4243             i;
4244
4245         for (i = 0, d.setDate(1), d.setMonth(0); i < m; d.setMonth(++i)) {
4246             num += utilDate.getDaysInMonth(d);
4247         }
4248         return num + date.getDate() - 1;
4249     },
4250
4251     /**
4252      * Get the numeric ISO-8601 week number of the year.
4253      * (equivalent to the format specifier 'W', but without a leading zero).
4254      * @param {Date} date The date
4255      * @return {Number} 1 to 53
4256      * @method
4257      */
4258     getWeekOfYear : (function() {
4259         // adapted from http://www.merlyn.demon.co.uk/weekcalc.htm
4260         var ms1d = 864e5, // milliseconds in a day
4261             ms7d = 7 * ms1d; // milliseconds in a week
4262
4263         return function(date) { // return a closure so constants get calculated only once
4264             var DC3 = Date.UTC(date.getFullYear(), date.getMonth(), date.getDate() + 3) / ms1d, // an Absolute Day Number
4265                 AWN = Math.floor(DC3 / 7), // an Absolute Week Number
4266                 Wyr = new Date(AWN * ms7d).getUTCFullYear();
4267
4268             return AWN - Math.floor(Date.UTC(Wyr, 0, 7) / ms7d) + 1;
4269         };
4270     })(),
4271
4272     /**
4273      * Checks if the current date falls within a leap year.
4274      * @param {Date} date The date
4275      * @return {Boolean} True if the current date falls within a leap year, false otherwise.
4276      */
4277     isLeapYear : function(date) {
4278         var year = date.getFullYear();
4279         return !!((year & 3) == 0 && (year % 100 || (year % 400 == 0 && year)));
4280     },
4281
4282     /**
4283      * Get the first day of the current month, adjusted for leap year.  The returned value
4284      * is the numeric day index within the week (0-6) which can be used in conjunction with
4285      * the {@link #monthNames} array to retrieve the textual day name.
4286      * Example:
4287      * <pre><code>
4288 var dt = new Date('1/10/2007'),
4289     firstDay = Ext.Date.getFirstDayOfMonth(dt);
4290 console.log(Ext.Date.dayNames[firstDay]); //output: 'Monday'
4291      * </code></pre>
4292      * @param {Date} date The date
4293      * @return {Number} The day number (0-6).
4294      */
4295     getFirstDayOfMonth : function(date) {
4296         var day = (date.getDay() - (date.getDate() - 1)) % 7;
4297         return (day < 0) ? (day + 7) : day;
4298     },
4299
4300     /**
4301      * Get the last day of the current month, adjusted for leap year.  The returned value
4302      * is the numeric day index within the week (0-6) which can be used in conjunction with
4303      * the {@link #monthNames} array to retrieve the textual day name.
4304      * Example:
4305      * <pre><code>
4306 var dt = new Date('1/10/2007'),
4307     lastDay = Ext.Date.getLastDayOfMonth(dt);
4308 console.log(Ext.Date.dayNames[lastDay]); //output: 'Wednesday'
4309      * </code></pre>
4310      * @param {Date} date The date
4311      * @return {Number} The day number (0-6).
4312      */
4313     getLastDayOfMonth : function(date) {
4314         return utilDate.getLastDateOfMonth(date).getDay();
4315     },
4316
4317
4318     /**
4319      * Get the date of the first day of the month in which this date resides.
4320      * @param {Date} date The date
4321      * @return {Date}
4322      */
4323     getFirstDateOfMonth : function(date) {
4324         return new Date(date.getFullYear(), date.getMonth(), 1);
4325     },
4326
4327     /**
4328      * Get the date of the last day of the month in which this date resides.
4329      * @param {Date} date The date
4330      * @return {Date}
4331      */
4332     getLastDateOfMonth : function(date) {
4333         return new Date(date.getFullYear(), date.getMonth(), utilDate.getDaysInMonth(date));
4334     },
4335
4336     /**
4337      * Get the number of days in the current month, adjusted for leap year.
4338      * @param {Date} date The date
4339      * @return {Number} The number of days in the month.
4340      * @method
4341      */
4342     getDaysInMonth: (function() {
4343         var daysInMonth = [31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31];
4344
4345         return function(date) { // return a closure for efficiency
4346             var m = date.getMonth();
4347
4348             return m == 1 && utilDate.isLeapYear(date) ? 29 : daysInMonth[m];
4349         };
4350     })(),
4351
4352     /**
4353      * Get the English ordinal suffix of the current day (equivalent to the format specifier 'S').
4354      * @param {Date} date The date
4355      * @return {String} 'st, 'nd', 'rd' or 'th'.
4356      */
4357     getSuffix : function(date) {
4358         switch (date.getDate()) {
4359             case 1:
4360             case 21:
4361             case 31:
4362                 return "st";
4363             case 2:
4364             case 22:
4365                 return "nd";
4366             case 3:
4367             case 23:
4368                 return "rd";
4369             default:
4370                 return "th";
4371         }
4372     },
4373
4374     /**
4375      * Creates and returns a new Date instance with the exact same date value as the called instance.
4376      * Dates are copied and passed by reference, so if a copied date variable is modified later, the original
4377      * variable will also be changed.  When the intention is to create a new variable that will not
4378      * modify the original instance, you should create a clone.
4379      *
4380      * Example of correctly cloning a date:
4381      * <pre><code>
4382 //wrong way:
4383 var orig = new Date('10/1/2006');
4384 var copy = orig;
4385 copy.setDate(5);
4386 console.log(orig);  //returns 'Thu Oct 05 2006'!
4387
4388 //correct way:
4389 var orig = new Date('10/1/2006'),
4390     copy = Ext.Date.clone(orig);
4391 copy.setDate(5);
4392 console.log(orig);  //returns 'Thu Oct 01 2006'
4393      * </code></pre>
4394      * @param {Date} date The date
4395      * @return {Date} The new Date instance.
4396      */
4397     clone : function(date) {
4398         return new Date(date.getTime());
4399     },
4400
4401     /**
4402      * Checks if the current date is affected by Daylight Saving Time (DST).
4403      * @param {Date} date The date
4404      * @return {Boolean} True if the current date is affected by DST.
4405      */
4406     isDST : function(date) {
4407         // adapted from http://sencha.com/forum/showthread.php?p=247172#post247172
4408         // courtesy of @geoffrey.mcgill
4409         return new Date(date.getFullYear(), 0, 1).getTimezoneOffset() != date.getTimezoneOffset();
4410     },
4411
4412     /**
4413      * Attempts to clear all time information from this Date by setting the time to midnight of the same day,
4414      * automatically adjusting for Daylight Saving Time (DST) where applicable.
4415      * (note: DST timezone information for the browser's host operating system is assumed to be up-to-date)
4416      * @param {Date} date The date
4417      * @param {Boolean} clone true to create a clone of this date, clear the time and return it (defaults to false).
4418      * @return {Date} this or the clone.
4419      */
4420     clearTime : function(date, clone) {
4421         if (clone) {
4422             return Ext.Date.clearTime(Ext.Date.clone(date));
4423         }
4424
4425         // get current date before clearing time
4426         var d = date.getDate();
4427
4428         // clear time
4429         date.setHours(0);
4430         date.setMinutes(0);
4431         date.setSeconds(0);
4432         date.setMilliseconds(0);
4433
4434         if (date.getDate() != d) { // account for DST (i.e. day of month changed when setting hour = 0)
4435             // note: DST adjustments are assumed to occur in multiples of 1 hour (this is almost always the case)
4436             // refer to http://www.timeanddate.com/time/aboutdst.html for the (rare) exceptions to this rule
4437
4438             // increment hour until cloned date == current date
4439             for (var hr = 1, c = utilDate.add(date, Ext.Date.HOUR, hr); c.getDate() != d; hr++, c = utilDate.add(date, Ext.Date.HOUR, hr));
4440
4441             date.setDate(d);
4442             date.setHours(c.getHours());
4443         }
4444
4445         return date;
4446     },
4447
4448     /**
4449      * Provides a convenient method for performing basic date arithmetic. This method
4450      * does not modify the Date instance being called - it creates and returns
4451      * a new Date instance containing the resulting date value.
4452      *
4453      * Examples:
4454      * <pre><code>
4455 // Basic usage:
4456 var dt = Ext.Date.add(new Date('10/29/2006'), Ext.Date.DAY, 5);
4457 console.log(dt); //returns 'Fri Nov 03 2006 00:00:00'
4458
4459 // Negative values will be subtracted:
4460 var dt2 = Ext.Date.add(new Date('10/1/2006'), Ext.Date.DAY, -5);
4461 console.log(dt2); //returns 'Tue Sep 26 2006 00:00:00'
4462
4463      * </code></pre>
4464      *
4465      * @param {Date} date The date to modify
4466      * @param {String} interval A valid date interval enum value.
4467      * @param {Number} value The amount to add to the current date.
4468      * @return {Date} The new Date instance.
4469      */
4470     add : function(date, interval, value) {
4471         var d = Ext.Date.clone(date),
4472             Date = Ext.Date;
4473         if (!interval || value === 0) return d;
4474
4475         switch(interval.toLowerCase()) {
4476             case Ext.Date.MILLI:
4477                 d.setMilliseconds(d.getMilliseconds() + value);
4478                 break;
4479             case Ext.Date.SECOND:
4480                 d.setSeconds(d.getSeconds() + value);
4481                 break;
4482             case Ext.Date.MINUTE:
4483                 d.setMinutes(d.getMinutes() + value);
4484                 break;
4485             case Ext.Date.HOUR:
4486                 d.setHours(d.getHours() + value);
4487                 break;
4488             case Ext.Date.DAY:
4489                 d.setDate(d.getDate() + value);
4490                 break;
4491             case Ext.Date.MONTH:
4492                 var day = date.getDate();
4493                 if (day > 28) {
4494                     day = Math.min(day, Ext.Date.getLastDateOfMonth(Ext.Date.add(Ext.Date.getFirstDateOfMonth(date), 'mo', value)).getDate());
4495                 }
4496                 d.setDate(day);
4497                 d.setMonth(date.getMonth() + value);
4498                 break;
4499             case Ext.Date.YEAR:
4500                 d.setFullYear(date.getFullYear() + value);
4501                 break;
4502         }
4503         return d;
4504     },
4505
4506     /**
4507      * Checks if a date falls on or between the given start and end dates.
4508      * @param {Date} date The date to check
4509      * @param {Date} start Start date
4510      * @param {Date} end End date
4511      * @return {Boolean} true if this date falls on or between the given start and end dates.
4512      */
4513     between : function(date, start, end) {
4514         var t = date.getTime();
4515         return start.getTime() <= t && t <= end.getTime();
4516     },
4517
4518     //Maintains compatibility with old static and prototype window.Date methods.
4519     compat: function() {
4520         var nativeDate = window.Date,
4521             p, u,
4522             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'],
4523             proto = ['dateFormat', 'format', 'getTimezone', 'getGMTOffset', 'getDayOfYear', 'getWeekOfYear', 'isLeapYear', 'getFirstDayOfMonth', 'getLastDayOfMonth', 'getDaysInMonth', 'getSuffix', 'clone', 'isDST', 'clearTime', 'add', 'between'];
4524
4525         //Append statics
4526         Ext.Array.forEach(statics, function(s) {
4527             nativeDate[s] = utilDate[s];
4528         });
4529
4530         //Append to prototype
4531         Ext.Array.forEach(proto, function(s) {
4532             nativeDate.prototype[s] = function() {
4533                 var args = Array.prototype.slice.call(arguments);
4534                 args.unshift(this);
4535                 return utilDate[s].apply(utilDate, args);
4536             };
4537         });
4538     }
4539 };
4540
4541 var utilDate = Ext.Date;
4542
4543 })();
4544
4545 /**
4546  * @author Jacky Nguyen <jacky@sencha.com>
4547  * @docauthor Jacky Nguyen <jacky@sencha.com>
4548  * @class Ext.Base
4549  *
4550  * The root of all classes created with {@link Ext#define}
4551  * All prototype and static members of this class are inherited by any other class
4552  *
4553  */
4554 (function(flexSetter) {
4555
4556 var Base = Ext.Base = function() {};
4557     Base.prototype = {
4558         $className: 'Ext.Base',
4559
4560         $class: Base,
4561
4562         /**
4563          * Get the reference to the current class from which this object was instantiated. Unlike {@link Ext.Base#statics},
4564          * `this.self` is scope-dependent and it's meant to be used for dynamic inheritance. See {@link Ext.Base#statics}
4565          * for a detailed comparison
4566          *
4567          *     Ext.define('My.Cat', {
4568          *         statics: {
4569          *             speciesName: 'Cat' // My.Cat.speciesName = 'Cat'
4570          *         },
4571          *
4572          *         constructor: function() {
4573          *             alert(this.self.speciesName); / dependent on 'this'
4574          *
4575          *             return this;
4576          *         },
4577          *
4578          *         clone: function() {
4579          *             return new this.self();
4580          *         }
4581          *     });
4582          *
4583          *
4584          *     Ext.define('My.SnowLeopard', {
4585          *         extend: 'My.Cat',
4586          *         statics: {
4587          *             speciesName: 'Snow Leopard'         // My.SnowLeopard.speciesName = 'Snow Leopard'
4588          *         }
4589          *     });
4590          *
4591          *     var cat = new My.Cat();                     // alerts 'Cat'
4592          *     var snowLeopard = new My.SnowLeopard();     // alerts 'Snow Leopard'
4593          *
4594          *     var clone = snowLeopard.clone();
4595          *     alert(Ext.getClassName(clone));             // alerts 'My.SnowLeopard'
4596          *
4597          * @type Class
4598          * @protected
4599          */
4600         self: Base,
4601
4602         // Default constructor, simply returns `this`
4603         constructor: function() {
4604             return this;
4605         },
4606
4607         /**
4608          * Initialize configuration for this class. a typical example:
4609          *
4610          *     Ext.define('My.awesome.Class', {
4611          *         // The default config
4612          *         config: {
4613          *             name: 'Awesome',
4614          *             isAwesome: true
4615          *         },
4616          *
4617          *         constructor: function(config) {
4618          *             this.initConfig(config);
4619          *
4620          *             return this;
4621          *         }
4622          *     });
4623          *
4624          *     var awesome = new My.awesome.Class({
4625          *         name: 'Super Awesome'
4626          *     });
4627          *
4628          *     alert(awesome.getName()); // 'Super Awesome'
4629          *
4630          * @protected
4631          * @param {Object} config
4632          * @return {Object} mixins The mixin prototypes as key - value pairs
4633          */
4634         initConfig: function(config) {
4635             if (!this.$configInited) {
4636                 this.config = Ext.Object.merge({}, this.config || {}, config || {});
4637
4638                 this.applyConfig(this.config);
4639
4640                 this.$configInited = true;
4641             }
4642
4643             return this;
4644         },
4645
4646         /**
4647          * @private
4648          */
4649         setConfig: function(config) {
4650             this.applyConfig(config || {});
4651
4652             return this;
4653         },
4654
4655         /**
4656          * @private
4657          */
4658         applyConfig: flexSetter(function(name, value) {
4659             var setter = 'set' + Ext.String.capitalize(name);
4660
4661             if (typeof this[setter] === 'function') {
4662                 this[setter].call(this, value);
4663             }
4664
4665             return this;
4666         }),
4667
4668         /**
4669          * Call the parent's overridden method. For example:
4670          *
4671          *     Ext.define('My.own.A', {
4672          *         constructor: function(test) {
4673          *             alert(test);
4674          *         }
4675          *     });
4676          *
4677          *     Ext.define('My.own.B', {
4678          *         extend: 'My.own.A',
4679          *
4680          *         constructor: function(test) {
4681          *             alert(test);
4682          *
4683          *             this.callParent([test + 1]);
4684          *         }
4685          *     });
4686          *
4687          *     Ext.define('My.own.C', {
4688          *         extend: 'My.own.B',
4689          *
4690          *         constructor: function() {
4691          *             alert("Going to call parent's overriden constructor...");
4692          *
4693          *             this.callParent(arguments);
4694          *         }
4695          *     });
4696          *
4697          *     var a = new My.own.A(1); // alerts '1'
4698          *     var b = new My.own.B(1); // alerts '1', then alerts '2'
4699          *     var c = new My.own.C(2); // alerts "Going to call parent's overriden constructor..."
4700          *                              // alerts '2', then alerts '3'
4701          *
4702          * @protected
4703          * @param {Array/Arguments} args The arguments, either an array or the `arguments` object
4704          * from the current method, for example: `this.callParent(arguments)`
4705          * @return {Mixed} Returns the result from the superclass' method
4706          */
4707         callParent: function(args) {
4708             var method = this.callParent.caller,
4709                 parentClass, methodName;
4710
4711             if (!method.$owner) {
4712
4713                 method = method.caller;
4714             }
4715
4716             parentClass = method.$owner.superclass;
4717             methodName = method.$name;
4718
4719
4720             return parentClass[methodName].apply(this, args || []);
4721         },
4722
4723
4724         /**
4725          * Get the reference to the class from which this object was instantiated. Note that unlike {@link Ext.Base#self},
4726          * `this.statics()` is scope-independent and it always returns the class from which it was called, regardless of what
4727          * `this` points to during run-time
4728          *
4729          *     Ext.define('My.Cat', {
4730          *         statics: {
4731          *             totalCreated: 0,
4732          *             speciesName: 'Cat' // My.Cat.speciesName = 'Cat'
4733          *         },
4734          *  
4735          *         constructor: function() {
4736          *             var statics = this.statics();
4737          *  
4738          *             alert(statics.speciesName);     // always equals to 'Cat' no matter what 'this' refers to
4739          *                                             // equivalent to: My.Cat.speciesName
4740          *  
4741          *             alert(this.self.speciesName);   // dependent on 'this'
4742          *  
4743          *             statics.totalCreated++;
4744          *  
4745          *             return this;
4746          *         },
4747          *  
4748          *         clone: function() {
4749          *             var cloned = new this.self;                      // dependent on 'this'
4750          *  
4751          *             cloned.groupName = this.statics().speciesName;   // equivalent to: My.Cat.speciesName
4752          *  
4753          *             return cloned;
4754          *         }
4755          *     });
4756          *
4757          *
4758          *     Ext.define('My.SnowLeopard', {
4759          *         extend: 'My.Cat',
4760          *  
4761          *         statics: {
4762          *             speciesName: 'Snow Leopard'     // My.SnowLeopard.speciesName = 'Snow Leopard'
4763          *         },
4764          *  
4765          *         constructor: function() {
4766          *             this.callParent();
4767          *         }
4768          *     });
4769          *
4770          *     var cat = new My.Cat();                 // alerts 'Cat', then alerts 'Cat'
4771          *
4772          *     var snowLeopard = new My.SnowLeopard(); // alerts 'Cat', then alerts 'Snow Leopard'
4773          *
4774          *     var clone = snowLeopard.clone();
4775          *     alert(Ext.getClassName(clone));         // alerts 'My.SnowLeopard'
4776          *     alert(clone.groupName);                 // alerts 'Cat'
4777          *
4778          *     alert(My.Cat.totalCreated);             // alerts 3
4779          *
4780          * @protected
4781          * @return {Class}
4782          */
4783         statics: function() {
4784             var method = this.statics.caller,
4785                 self = this.self;
4786
4787             if (!method) {
4788                 return self;
4789             }
4790
4791             return method.$owner;
4792         },
4793
4794         /**
4795          * Call the original method that was previously overridden with {@link Ext.Base#override}
4796          *
4797          *     Ext.define('My.Cat', {
4798          *         constructor: function() {
4799          *             alert("I'm a cat!");
4800          *   
4801          *             return this;
4802          *         }
4803          *     });
4804          *
4805          *     My.Cat.override({
4806          *         constructor: function() {
4807          *             alert("I'm going to be a cat!");
4808          *   
4809          *             var instance = this.callOverridden();
4810          *   
4811          *             alert("Meeeeoooowwww");
4812          *   
4813          *             return instance;
4814          *         }
4815          *     });
4816          *
4817          *     var kitty = new My.Cat(); // alerts "I'm going to be a cat!"
4818          *                               // alerts "I'm a cat!"
4819          *                               // alerts "Meeeeoooowwww"
4820          *
4821          * @param {Array/Arguments} args The arguments, either an array or the `arguments` object
4822          * @return {Mixed} Returns the result after calling the overridden method
4823          */
4824         callOverridden: function(args) {
4825             var method = this.callOverridden.caller;
4826
4827
4828             return method.$previous.apply(this, args || []);
4829         },
4830
4831         destroy: function() {}
4832     };
4833
4834     // These static properties will be copied to every newly created class with {@link Ext#define}
4835     Ext.apply(Ext.Base, {
4836         /**
4837          * Create a new instance of this Class.
4838          *
4839          *     Ext.define('My.cool.Class', {
4840          *         ...
4841          *     });
4842          *      
4843          *     My.cool.Class.create({
4844          *         someConfig: true
4845          *     });
4846          *
4847          * All parameters are passed to the constructor of the class.
4848          *
4849          * @return {Object} the created instance.
4850          * @static
4851          */
4852         create: function() {
4853             return Ext.create.apply(Ext, [this].concat(Array.prototype.slice.call(arguments, 0)));
4854         },
4855
4856         /**
4857          * @private
4858          */
4859         own: flexSetter(function(name, value) {
4860             if (typeof value === 'function') {
4861                 this.ownMethod(name, value);
4862             }
4863             else {
4864                 this.prototype[name] = value;
4865             }
4866         }),
4867
4868         /**
4869          * @private
4870          */
4871         ownMethod: function(name, fn) {
4872             var originalFn;
4873
4874             if (fn.$owner !== undefined && fn !== Ext.emptyFn) {
4875                 originalFn = fn;
4876
4877                 fn = function() {
4878                     return originalFn.apply(this, arguments);
4879                 };
4880             }
4881
4882             fn.$owner = this;
4883             fn.$name = name;
4884
4885             this.prototype[name] = fn;
4886         },
4887
4888         /**
4889          * Add / override static properties of this class.
4890          *
4891          *     Ext.define('My.cool.Class', {
4892          *         ...
4893          *     });
4894          *
4895          *     My.cool.Class.addStatics({
4896          *         someProperty: 'someValue',      // My.cool.Class.someProperty = 'someValue'
4897          *         method1: function() { ... },    // My.cool.Class.method1 = function() { ... };
4898          *         method2: function() { ... }     // My.cool.Class.method2 = function() { ... };
4899          *     });
4900          *
4901          * @param {Object} members
4902          * @return {Ext.Base} this
4903          * @static
4904          */
4905         addStatics: function(members) {
4906             for (var name in members) {
4907                 if (members.hasOwnProperty(name)) {
4908                     this[name] = members[name];
4909                 }
4910             }
4911
4912             return this;
4913         },
4914
4915         /**
4916          * Add methods / properties to the prototype of this class.
4917          *
4918          *     Ext.define('My.awesome.Cat', {
4919          *         constructor: function() {
4920          *             ...
4921          *         }
4922          *     });
4923          *
4924          *      My.awesome.Cat.implement({
4925          *          meow: function() {
4926          *             alert('Meowww...');
4927          *          }
4928          *      });
4929          *
4930          *      var kitty = new My.awesome.Cat;
4931          *      kitty.meow();
4932          *
4933          * @param {Object} members
4934          * @static
4935          */
4936         implement: function(members) {
4937             var prototype = this.prototype,
4938                 name, i, member, previous;
4939             for (name in members) {
4940                 if (members.hasOwnProperty(name)) {
4941                     member = members[name];
4942
4943                     if (typeof member === 'function') {
4944                         member.$owner = this;
4945                         member.$name = name;
4946                     }
4947
4948                     prototype[name] = member;
4949                 }
4950             }
4951
4952             if (Ext.enumerables) {
4953                 var enumerables = Ext.enumerables;
4954
4955                 for (i = enumerables.length; i--;) {
4956                     name = enumerables[i];
4957
4958                     if (members.hasOwnProperty(name)) {
4959                         member = members[name];
4960                         member.$owner = this;
4961                         member.$name = name;
4962                         prototype[name] = member;
4963                     }
4964                 }
4965             }
4966         },
4967
4968         /**
4969          * Borrow another class' members to the prototype of this class.
4970          *
4971          *     Ext.define('Bank', {
4972          *         money: '$$$',
4973          *         printMoney: function() {
4974          *             alert('$$$$$$$');
4975          *         }
4976          *     });
4977          *
4978          *     Ext.define('Thief', {
4979          *         ...
4980          *     });
4981          *
4982          *     Thief.borrow(Bank, ['money', 'printMoney']);
4983          *
4984          *     var steve = new Thief();
4985          *
4986          *     alert(steve.money); // alerts '$$$'
4987          *     steve.printMoney(); // alerts '$$$$$$$'
4988          *
4989          * @param {Ext.Base} fromClass The class to borrow members from
4990          * @param {Array/String} members The names of the members to borrow
4991          * @return {Ext.Base} this
4992          * @static
4993          * @private
4994          */
4995         borrow: function(fromClass, members) {
4996             var fromPrototype = fromClass.prototype,
4997                 i, ln, member;
4998
4999             members = Ext.Array.from(members);
5000
5001             for (i = 0, ln = members.length; i < ln; i++) {
5002                 member = members[i];
5003
5004                 this.own(member, fromPrototype[member]);
5005             }
5006
5007             return this;
5008         },
5009
5010         /**
5011          * Override prototype members of this class. Overridden methods can be invoked via
5012          * {@link Ext.Base#callOverridden}
5013          *
5014          *     Ext.define('My.Cat', {
5015          *         constructor: function() {
5016          *             alert("I'm a cat!");
5017          *
5018          *             return this;
5019          *         }
5020          *     });
5021          *
5022          *     My.Cat.override({
5023          *         constructor: function() {
5024          *             alert("I'm going to be a cat!");
5025          *
5026          *             var instance = this.callOverridden();
5027          *
5028          *             alert("Meeeeoooowwww");
5029          *
5030          *             return instance;
5031          *         }
5032          *     });
5033          *
5034          *     var kitty = new My.Cat(); // alerts "I'm going to be a cat!"
5035          *                               // alerts "I'm a cat!"
5036          *                               // alerts "Meeeeoooowwww"
5037          *
5038          * @param {Object} members
5039          * @return {Ext.Base} this
5040          * @static
5041          */
5042         override: function(members) {
5043             var prototype = this.prototype,
5044                 name, i, member, previous;
5045
5046             for (name in members) {
5047                 if (members.hasOwnProperty(name)) {
5048                     member = members[name];
5049
5050                     if (typeof member === 'function') {
5051                         if (typeof prototype[name] === 'function') {
5052                             previous = prototype[name];
5053                             member.$previous = previous;
5054                         }
5055
5056                         this.ownMethod(name, member);
5057                     }
5058                     else {
5059                         prototype[name] = member;
5060                     }
5061                 }
5062             }
5063
5064             if (Ext.enumerables) {
5065                 var enumerables = Ext.enumerables;
5066
5067                 for (i = enumerables.length; i--;) {
5068                     name = enumerables[i];
5069
5070                     if (members.hasOwnProperty(name)) {
5071                         if (prototype[name] !== undefined) {
5072                             previous = prototype[name];
5073                             members[name].$previous = previous;
5074                         }
5075
5076                         this.ownMethod(name, members[name]);
5077                     }
5078                 }
5079             }
5080
5081             return this;
5082         },
5083
5084         /**
5085          * Used internally by the mixins pre-processor
5086          * @private
5087          */
5088         mixin: flexSetter(function(name, cls) {
5089             var mixin = cls.prototype,
5090                 my = this.prototype,
5091                 i, fn;
5092
5093             for (i in mixin) {
5094                 if (mixin.hasOwnProperty(i)) {
5095                     if (my[i] === undefined) {
5096                         if (typeof mixin[i] === 'function') {
5097                             fn = mixin[i];
5098
5099                             if (fn.$owner === undefined) {
5100                                 this.ownMethod(i, fn);
5101                             }
5102                             else {
5103                                 my[i] = fn;
5104                             }
5105                         }
5106                         else {
5107                             my[i] = mixin[i];
5108                         }
5109                     }
5110                     else if (i === 'config' && my.config && mixin.config) {
5111                         Ext.Object.merge(my.config, mixin.config);
5112                     }
5113                 }
5114             }
5115
5116             if (my.mixins === undefined) {
5117                 my.mixins = {};
5118             }
5119
5120             my.mixins[name] = mixin;
5121         }),
5122
5123         /**
5124          * Get the current class' name in string format.
5125          *
5126          *     Ext.define('My.cool.Class', {
5127          *         constructor: function() {
5128          *             alert(this.self.getName()); // alerts 'My.cool.Class'
5129          *         }
5130          *     });
5131          *
5132          *     My.cool.Class.getName(); // 'My.cool.Class'
5133          *
5134          * @return {String} className
5135          */
5136         getName: function() {
5137             return Ext.getClassName(this);
5138         },
5139
5140         /**
5141          * Create aliases for existing prototype methods. Example:
5142          *
5143          *     Ext.define('My.cool.Class', {
5144          *         method1: function() { ... },
5145          *         method2: function() { ... }
5146          *     });
5147          *
5148          *     var test = new My.cool.Class();
5149          *
5150          *     My.cool.Class.createAlias({
5151          *         method3: 'method1',
5152          *         method4: 'method2'
5153          *     });
5154          *
5155          *     test.method3(); // test.method1()
5156          *
5157          *     My.cool.Class.createAlias('method5', 'method3');
5158          *
5159          *     test.method5(); // test.method3() -> test.method1()
5160          *
5161          * @param {String/Object} alias The new method name, or an object to set multiple aliases. See
5162          * {@link Ext.Function#flexSetter flexSetter}
5163          * @param {String/Object} origin The original method name
5164          * @static
5165          * @method
5166          */
5167         createAlias: flexSetter(function(alias, origin) {
5168             this.prototype[alias] = this.prototype[origin];
5169         })
5170     });
5171
5172 })(Ext.Function.flexSetter);
5173
5174 /**
5175  * @author Jacky Nguyen <jacky@sencha.com>
5176  * @docauthor Jacky Nguyen <jacky@sencha.com>
5177  * @class Ext.Class
5178  * 
5179  * Handles class creation throughout the whole framework. Note that most of the time {@link Ext#define Ext.define} should
5180  * be used instead, since it's a higher level wrapper that aliases to {@link Ext.ClassManager#create}
5181  * to enable namespacing and dynamic dependency resolution.
5182  * 
5183  * # Basic syntax: #
5184  * 
5185  *     Ext.define(className, properties);
5186  * 
5187  * in which `properties` is an object represent a collection of properties that apply to the class. See
5188  * {@link Ext.ClassManager#create} for more detailed instructions.
5189  * 
5190  *     Ext.define('Person', {
5191  *          name: 'Unknown',
5192  * 
5193  *          constructor: function(name) {
5194  *              if (name) {
5195  *                  this.name = name;
5196  *              }
5197  * 
5198  *              return this;
5199  *          },
5200  * 
5201  *          eat: function(foodType) {
5202  *              alert("I'm eating: " + foodType);
5203  * 
5204  *              return this;
5205  *          }
5206  *     });
5207  * 
5208  *     var aaron = new Person("Aaron");
5209  *     aaron.eat("Sandwich"); // alert("I'm eating: Sandwich");
5210  * 
5211  * Ext.Class has a powerful set of extensible {@link Ext.Class#registerPreprocessor pre-processors} which takes care of
5212  * everything related to class creation, including but not limited to inheritance, mixins, configuration, statics, etc.
5213  * 
5214  * # Inheritance: #
5215  * 
5216  *     Ext.define('Developer', {
5217  *          extend: 'Person',
5218  * 
5219  *          constructor: function(name, isGeek) {
5220  *              this.isGeek = isGeek;
5221  * 
5222  *              // Apply a method from the parent class' prototype
5223  *              this.callParent([name]);
5224  * 
5225  *              return this;
5226  * 
5227  *          },
5228  * 
5229  *          code: function(language) {
5230  *              alert("I'm coding in: " + language);
5231  * 
5232  *              this.eat("Bugs");
5233  * 
5234  *              return this;
5235  *          }
5236  *     });
5237  * 
5238  *     var jacky = new Developer("Jacky", true);
5239  *     jacky.code("JavaScript"); // alert("I'm coding in: JavaScript");
5240  *                               // alert("I'm eating: Bugs");
5241  * 
5242  * See {@link Ext.Base#callParent} for more details on calling superclass' methods
5243  * 
5244  * # Mixins: #
5245  * 
5246  *     Ext.define('CanPlayGuitar', {
5247  *          playGuitar: function() {
5248  *             alert("F#...G...D...A");
5249  *          }
5250  *     });
5251  * 
5252  *     Ext.define('CanComposeSongs', {
5253  *          composeSongs: function() { ... }
5254  *     });
5255  * 
5256  *     Ext.define('CanSing', {
5257  *          sing: function() {
5258  *              alert("I'm on the highway to hell...")
5259  *          }
5260  *     });
5261  * 
5262  *     Ext.define('Musician', {
5263  *          extend: 'Person',
5264  * 
5265  *          mixins: {
5266  *              canPlayGuitar: 'CanPlayGuitar',
5267  *              canComposeSongs: 'CanComposeSongs',
5268  *              canSing: 'CanSing'
5269  *          }
5270  *     })
5271  * 
5272  *     Ext.define('CoolPerson', {
5273  *          extend: 'Person',
5274  * 
5275  *          mixins: {
5276  *              canPlayGuitar: 'CanPlayGuitar',
5277  *              canSing: 'CanSing'
5278  *          },
5279  * 
5280  *          sing: function() {
5281  *              alert("Ahem....");
5282  * 
5283  *              this.mixins.canSing.sing.call(this);
5284  * 
5285  *              alert("[Playing guitar at the same time...]");
5286  * 
5287  *              this.playGuitar();
5288  *          }
5289  *     });
5290  * 
5291  *     var me = new CoolPerson("Jacky");
5292  * 
5293  *     me.sing(); // alert("Ahem...");
5294  *                // alert("I'm on the highway to hell...");
5295  *                // alert("[Playing guitar at the same time...]");
5296  *                // alert("F#...G...D...A");
5297  * 
5298  * # Config: #
5299  * 
5300  *     Ext.define('SmartPhone', {
5301  *          config: {
5302  *              hasTouchScreen: false,
5303  *              operatingSystem: 'Other',
5304  *              price: 500
5305  *          },
5306  * 
5307  *          isExpensive: false,
5308  * 
5309  *          constructor: function(config) {
5310  *              this.initConfig(config);
5311  * 
5312  *              return this;
5313  *          },
5314  * 
5315  *          applyPrice: function(price) {
5316  *              this.isExpensive = (price > 500);
5317  * 
5318  *              return price;
5319  *          },
5320  * 
5321  *          applyOperatingSystem: function(operatingSystem) {
5322  *              if (!(/^(iOS|Android|BlackBerry)$/i).test(operatingSystem)) {
5323  *                  return 'Other';
5324  *              }
5325  * 
5326  *              return operatingSystem;
5327  *          }
5328  *     });
5329  * 
5330  *     var iPhone = new SmartPhone({
5331  *          hasTouchScreen: true,
5332  *          operatingSystem: 'iOS'
5333  *     });
5334  * 
5335  *     iPhone.getPrice(); // 500;
5336  *     iPhone.getOperatingSystem(); // 'iOS'
5337  *     iPhone.getHasTouchScreen(); // true;
5338  *     iPhone.hasTouchScreen(); // true
5339  * 
5340  *     iPhone.isExpensive; // false;
5341  *     iPhone.setPrice(600);
5342  *     iPhone.getPrice(); // 600
5343  *     iPhone.isExpensive; // true;
5344  * 
5345  *     iPhone.setOperatingSystem('AlienOS');
5346  *     iPhone.getOperatingSystem(); // 'Other'
5347  * 
5348  * # Statics: #
5349  * 
5350  *     Ext.define('Computer', {
5351  *          statics: {
5352  *              factory: function(brand) {
5353  *                 // 'this' in static methods refer to the class itself
5354  *                  return new this(brand);
5355  *              }
5356  *          },
5357  * 
5358  *          constructor: function() { ... }
5359  *     });
5360  * 
5361  *     var dellComputer = Computer.factory('Dell');
5362  * 
5363  * Also see {@link Ext.Base#statics} and {@link Ext.Base#self} for more details on accessing
5364  * static properties within class methods
5365  *
5366  */
5367 (function() {
5368
5369     var Class,
5370         Base = Ext.Base,
5371         baseStaticProperties = [],
5372         baseStaticProperty;
5373
5374     for (baseStaticProperty in Base) {
5375         if (Base.hasOwnProperty(baseStaticProperty)) {
5376             baseStaticProperties.push(baseStaticProperty);
5377         }
5378     }
5379
5380     /**
5381      * @method constructor
5382      * Creates new class.
5383      * @param {Object} classData An object represent the properties of this class
5384      * @param {Function} createdFn Optional, the callback function to be executed when this class is fully created.
5385      * Note that the creation process can be asynchronous depending on the pre-processors used.
5386      * @return {Ext.Base} The newly created class
5387      */
5388     Ext.Class = Class = function(newClass, classData, onClassCreated) {
5389         if (typeof newClass !== 'function') {
5390             onClassCreated = classData;
5391             classData = newClass;
5392             newClass = function() {
5393                 return this.constructor.apply(this, arguments);
5394             };
5395         }
5396
5397         if (!classData) {
5398             classData = {};
5399         }
5400
5401         var preprocessorStack = classData.preprocessors || Class.getDefaultPreprocessors(),
5402             registeredPreprocessors = Class.getPreprocessors(),
5403             index = 0,
5404             preprocessors = [],
5405             preprocessor, preprocessors, staticPropertyName, process, i, j, ln;
5406
5407         for (i = 0, ln = baseStaticProperties.length; i < ln; i++) {
5408             staticPropertyName = baseStaticProperties[i];
5409             newClass[staticPropertyName] = Base[staticPropertyName];
5410         }
5411
5412         delete classData.preprocessors;
5413
5414         for (j = 0, ln = preprocessorStack.length; j < ln; j++) {
5415             preprocessor = preprocessorStack[j];
5416
5417             if (typeof preprocessor === 'string') {
5418                 preprocessor = registeredPreprocessors[preprocessor];
5419
5420                 if (!preprocessor.always) {
5421                     if (classData.hasOwnProperty(preprocessor.name)) {
5422                         preprocessors.push(preprocessor.fn);
5423                     }
5424                 }
5425                 else {
5426                     preprocessors.push(preprocessor.fn);
5427                 }
5428             }
5429             else {
5430                 preprocessors.push(preprocessor);
5431             }
5432         }
5433
5434         classData.onClassCreated = onClassCreated;
5435
5436         classData.onBeforeClassCreated = function(cls, data) {
5437             onClassCreated = data.onClassCreated;
5438
5439             delete data.onBeforeClassCreated;
5440             delete data.onClassCreated;
5441
5442             cls.implement(data);
5443
5444             if (onClassCreated) {
5445                 onClassCreated.call(cls, cls);
5446             }
5447         };
5448
5449         process = function(cls, data) {
5450             preprocessor = preprocessors[index++];
5451
5452             if (!preprocessor) {
5453                 data.onBeforeClassCreated.apply(this, arguments);
5454                 return;
5455             }
5456
5457             if (preprocessor.call(this, cls, data, process) !== false) {
5458                 process.apply(this, arguments);
5459             }
5460         };
5461
5462         process.call(Class, newClass, classData);
5463
5464         return newClass;
5465     };
5466
5467     Ext.apply(Class, {
5468
5469         /** @private */
5470         preprocessors: {},
5471
5472         /**
5473          * Register a new pre-processor to be used during the class creation process
5474          *
5475          * @member Ext.Class registerPreprocessor
5476          * @param {String} name The pre-processor's name
5477          * @param {Function} fn The callback function to be executed. Typical format:
5478
5479     function(cls, data, fn) {
5480         // Your code here
5481
5482         // Execute this when the processing is finished.
5483         // Asynchronous processing is perfectly ok
5484         if (fn) {
5485             fn.call(this, cls, data);
5486         }
5487     });
5488
5489          * Passed arguments for this function are:
5490          *
5491          * - `{Function} cls`: The created class
5492          * - `{Object} data`: The set of properties passed in {@link Ext.Class} constructor
5493          * - `{Function} fn`: The callback function that <b>must</b> to be executed when this pre-processor finishes,
5494          * regardless of whether the processing is synchronous or aynchronous
5495          *
5496          * @return {Ext.Class} this
5497          * @markdown
5498          */
5499         registerPreprocessor: function(name, fn, always) {
5500             this.preprocessors[name] = {
5501                 name: name,
5502                 always: always ||  false,
5503                 fn: fn
5504             };
5505
5506             return this;
5507         },
5508
5509         /**
5510          * Retrieve a pre-processor callback function by its name, which has been registered before
5511          *
5512          * @param {String} name
5513          * @return {Function} preprocessor
5514          */
5515         getPreprocessor: function(name) {
5516             return this.preprocessors[name];
5517         },
5518
5519         getPreprocessors: function() {
5520             return this.preprocessors;
5521         },
5522
5523         /**
5524          * Retrieve the array stack of default pre-processors
5525          *
5526          * @return {Function} defaultPreprocessors
5527          */
5528         getDefaultPreprocessors: function() {
5529             return this.defaultPreprocessors || [];
5530         },
5531
5532         /**
5533          * Set the default array stack of default pre-processors
5534          *
5535          * @param {Array} preprocessors
5536          * @return {Ext.Class} this
5537          */
5538         setDefaultPreprocessors: function(preprocessors) {
5539             this.defaultPreprocessors = Ext.Array.from(preprocessors);
5540
5541             return this;
5542         },
5543
5544         /**
5545          * Insert this pre-processor at a specific position in the stack, optionally relative to
5546          * any existing pre-processor. For example:
5547
5548     Ext.Class.registerPreprocessor('debug', function(cls, data, fn) {
5549         // Your code here
5550
5551         if (fn) {
5552             fn.call(this, cls, data);
5553         }
5554     }).insertDefaultPreprocessor('debug', 'last');
5555
5556          * @param {String} name The pre-processor name. Note that it needs to be registered with
5557          * {@link Ext#registerPreprocessor registerPreprocessor} before this
5558          * @param {String} offset The insertion position. Four possible values are:
5559          * 'first', 'last', or: 'before', 'after' (relative to the name provided in the third argument)
5560          * @param {String} relativeName
5561          * @return {Ext.Class} this
5562          * @markdown
5563          */
5564         setDefaultPreprocessorPosition: function(name, offset, relativeName) {
5565             var defaultPreprocessors = this.defaultPreprocessors,
5566                 index;
5567
5568             if (typeof offset === 'string') {
5569                 if (offset === 'first') {
5570                     defaultPreprocessors.unshift(name);
5571
5572                     return this;
5573                 }
5574                 else if (offset === 'last') {
5575                     defaultPreprocessors.push(name);
5576
5577                     return this;
5578                 }
5579
5580                 offset = (offset === 'after') ? 1 : -1;
5581             }
5582
5583             index = Ext.Array.indexOf(defaultPreprocessors, relativeName);
5584
5585             if (index !== -1) {
5586                 Ext.Array.splice(defaultPreprocessors, Math.max(0, index + offset), 0, name);
5587             }
5588
5589             return this;
5590         }
5591     });
5592
5593     /**
5594      * @cfg {String} extend
5595      * The parent class that this class extends. For example:
5596      *
5597      *     Ext.define('Person', {
5598      *         say: function(text) { alert(text); }
5599      *     });
5600      *
5601      *     Ext.define('Developer', {
5602      *         extend: 'Person',
5603      *         say: function(text) { this.callParent(["print "+text]); }
5604      *     });
5605      */
5606     Class.registerPreprocessor('extend', function(cls, data) {
5607         var extend = data.extend,
5608             base = Ext.Base,
5609             basePrototype = base.prototype,
5610             prototype = function() {},
5611             parent, i, k, ln, staticName, parentStatics,
5612             parentPrototype, clsPrototype;
5613
5614         if (extend && extend !== Object) {
5615             parent = extend;
5616         }
5617         else {
5618             parent = base;
5619         }
5620
5621         parentPrototype = parent.prototype;
5622
5623         prototype.prototype = parentPrototype;
5624         clsPrototype = cls.prototype = new prototype();
5625
5626         if (!('$class' in parent)) {
5627             for (i in basePrototype) {
5628                 if (!parentPrototype[i]) {
5629                     parentPrototype[i] = basePrototype[i];
5630                 }
5631             }
5632         }
5633
5634         clsPrototype.self = cls;
5635
5636         cls.superclass = clsPrototype.superclass = parentPrototype;
5637
5638         delete data.extend;
5639
5640         // Statics inheritance
5641         parentStatics = parentPrototype.$inheritableStatics;
5642
5643         if (parentStatics) {
5644             for (k = 0, ln = parentStatics.length; k < ln; k++) {
5645                 staticName = parentStatics[k];
5646
5647                 if (!cls.hasOwnProperty(staticName)) {
5648                     cls[staticName] = parent[staticName];
5649                 }
5650             }
5651         }
5652
5653         // Merge the parent class' config object without referencing it
5654         if (parentPrototype.config) {
5655             clsPrototype.config = Ext.Object.merge({}, parentPrototype.config);
5656         }
5657         else {
5658             clsPrototype.config = {};
5659         }
5660
5661         if (clsPrototype.$onExtended) {
5662             clsPrototype.$onExtended.call(cls, cls, data);
5663         }
5664
5665         if (data.onClassExtended) {
5666             clsPrototype.$onExtended = data.onClassExtended;
5667             delete data.onClassExtended;
5668         }
5669
5670     }, true);
5671
5672     /**
5673      * @cfg {Object} statics
5674      * List of static methods for this class. For example:
5675      *
5676      *     Ext.define('Computer', {
5677      *          statics: {
5678      *              factory: function(brand) {
5679      *                  // 'this' in static methods refer to the class itself
5680      *                  return new this(brand);
5681      *              }
5682      *          },
5683      *
5684      *          constructor: function() { ... }
5685      *     });
5686      *
5687      *     var dellComputer = Computer.factory('Dell');
5688      */
5689     Class.registerPreprocessor('statics', function(cls, data) {
5690         var statics = data.statics,
5691             name;
5692
5693         for (name in statics) {
5694             if (statics.hasOwnProperty(name)) {
5695                 cls[name] = statics[name];
5696             }
5697         }
5698
5699         delete data.statics;
5700     });
5701
5702     /**
5703      * @cfg {Object} inheritableStatics
5704      * List of inheritable static methods for this class.
5705      * Otherwise just like {@link #statics} but subclasses inherit these methods.
5706      */
5707     Class.registerPreprocessor('inheritableStatics', function(cls, data) {
5708         var statics = data.inheritableStatics,
5709             inheritableStatics,
5710             prototype = cls.prototype,
5711             name;
5712
5713         inheritableStatics = prototype.$inheritableStatics;
5714
5715         if (!inheritableStatics) {
5716             inheritableStatics = prototype.$inheritableStatics = [];
5717         }
5718
5719         for (name in statics) {
5720             if (statics.hasOwnProperty(name)) {
5721                 cls[name] = statics[name];
5722                 inheritableStatics.push(name);
5723             }
5724         }
5725
5726         delete data.inheritableStatics;
5727     });
5728
5729     /**
5730      * @cfg {Object} mixins
5731      * List of classes to mix into this class. For example:
5732      *
5733      *     Ext.define('CanSing', {
5734      *          sing: function() {
5735      *              alert("I'm on the highway to hell...")
5736      *          }
5737      *     });
5738      *
5739      *     Ext.define('Musician', {
5740      *          extend: 'Person',
5741      *
5742      *          mixins: {
5743      *              canSing: 'CanSing'
5744      *          }
5745      *     })
5746      */
5747     Class.registerPreprocessor('mixins', function(cls, data) {
5748         cls.mixin(data.mixins);
5749
5750         delete data.mixins;
5751     });
5752
5753     /**
5754      * @cfg {Object} config
5755      * List of configuration options with their default values, for which automatically
5756      * accessor methods are generated.  For example:
5757      *
5758      *     Ext.define('SmartPhone', {
5759      *          config: {
5760      *              hasTouchScreen: false,
5761      *              operatingSystem: 'Other',
5762      *              price: 500
5763      *          },
5764      *          constructor: function(cfg) {
5765      *              this.initConfig(cfg);
5766      *          }
5767      *     });
5768      *
5769      *     var iPhone = new SmartPhone({
5770      *          hasTouchScreen: true,
5771      *          operatingSystem: 'iOS'
5772      *     });
5773      *
5774      *     iPhone.getPrice(); // 500;
5775      *     iPhone.getOperatingSystem(); // 'iOS'
5776      *     iPhone.getHasTouchScreen(); // true;
5777      *     iPhone.hasTouchScreen(); // true
5778      */
5779     Class.registerPreprocessor('config', function(cls, data) {
5780         var prototype = cls.prototype;
5781
5782         Ext.Object.each(data.config, function(name) {
5783             var cName = name.charAt(0).toUpperCase() + name.substr(1),
5784                 pName = name,
5785                 apply = 'apply' + cName,
5786                 setter = 'set' + cName,
5787                 getter = 'get' + cName;
5788
5789             if (!(apply in prototype) && !data.hasOwnProperty(apply)) {
5790                 data[apply] = function(val) {
5791                     return val;
5792                 };
5793             }
5794
5795             if (!(setter in prototype) && !data.hasOwnProperty(setter)) {
5796                 data[setter] = function(val) {
5797                     var ret = this[apply].call(this, val, this[pName]);
5798
5799                     if (ret !== undefined) {
5800                         this[pName] = ret;
5801                     }
5802
5803                     return this;
5804                 };
5805             }
5806
5807             if (!(getter in prototype) && !data.hasOwnProperty(getter)) {
5808                 data[getter] = function() {
5809                     return this[pName];
5810                 };
5811             }
5812         });
5813
5814         Ext.Object.merge(prototype.config, data.config);
5815         delete data.config;
5816     });
5817
5818     Class.setDefaultPreprocessors(['extend', 'statics', 'inheritableStatics', 'mixins', 'config']);
5819
5820     // Backwards compatible
5821     Ext.extend = function(subclass, superclass, members) {
5822         if (arguments.length === 2 && Ext.isObject(superclass)) {
5823             members = superclass;
5824             superclass = subclass;
5825             subclass = null;
5826         }
5827
5828         var cls;
5829
5830         if (!superclass) {
5831             Ext.Error.raise("Attempting to extend from a class which has not been loaded on the page.");
5832         }
5833
5834         members.extend = superclass;
5835         members.preprocessors = ['extend', 'mixins', 'config', 'statics'];
5836
5837         if (subclass) {
5838             cls = new Class(subclass, members);
5839         }
5840         else {
5841             cls = new Class(members);
5842         }
5843
5844         cls.prototype.override = function(o) {
5845             for (var m in o) {
5846                 if (o.hasOwnProperty(m)) {
5847                     this[m] = o[m];
5848                 }
5849             }
5850         };
5851
5852         return cls;
5853     };
5854
5855 })();
5856
5857 /**
5858  * @author Jacky Nguyen <jacky@sencha.com>
5859  * @docauthor Jacky Nguyen <jacky@sencha.com>
5860  * @class Ext.ClassManager
5861  *
5862  * Ext.ClassManager manages all classes and handles mapping from string class name to
5863  * actual class objects throughout the whole framework. It is not generally accessed directly, rather through
5864  * these convenient shorthands:
5865  *
5866  * - {@link Ext#define Ext.define}
5867  * - {@link Ext#create Ext.create}
5868  * - {@link Ext#widget Ext.widget}
5869  * - {@link Ext#getClass Ext.getClass}
5870  * - {@link Ext#getClassName Ext.getClassName}
5871  *
5872  * @singleton
5873  */
5874 (function(Class, alias) {
5875
5876     var slice = Array.prototype.slice;
5877
5878     var Manager = Ext.ClassManager = {
5879
5880         /**
5881          * @property {Object} classes
5882          * All classes which were defined through the ClassManager. Keys are the
5883          * name of the classes and the values are references to the classes.
5884          * @private
5885          */
5886         classes: {},
5887
5888         /**
5889          * @private
5890          */
5891         existCache: {},
5892
5893         /**
5894          * @private
5895          */
5896         namespaceRewrites: [{
5897             from: 'Ext.',
5898             to: Ext
5899         }],
5900
5901         /**
5902          * @private
5903          */
5904         maps: {
5905             alternateToName: {},
5906             aliasToName: {},
5907             nameToAliases: {}
5908         },
5909
5910         /** @private */
5911         enableNamespaceParseCache: true,
5912
5913         /** @private */
5914         namespaceParseCache: {},
5915
5916         /** @private */
5917         instantiators: [],
5918
5919
5920         /**
5921          * Checks if a class has already been created.
5922          *
5923          * @param {String} className
5924          * @return {Boolean} exist
5925          */
5926         isCreated: function(className) {
5927             var i, ln, part, root, parts;
5928
5929
5930             if (this.classes.hasOwnProperty(className) || this.existCache.hasOwnProperty(className)) {
5931                 return true;
5932             }
5933
5934             root = Ext.global;
5935             parts = this.parseNamespace(className);
5936
5937             for (i = 0, ln = parts.length; i < ln; i++) {
5938                 part = parts[i];
5939
5940                 if (typeof part !== 'string') {
5941                     root = part;
5942                 } else {
5943                     if (!root || !root[part]) {
5944                         return false;
5945                     }
5946
5947                     root = root[part];
5948                 }
5949             }
5950
5951             Ext.Loader.historyPush(className);
5952
5953             this.existCache[className] = true;
5954
5955             return true;
5956         },
5957
5958         /**
5959          * Supports namespace rewriting
5960          * @private
5961          */
5962         parseNamespace: function(namespace) {
5963
5964             var cache = this.namespaceParseCache;
5965
5966             if (this.enableNamespaceParseCache) {
5967                 if (cache.hasOwnProperty(namespace)) {
5968                     return cache[namespace];
5969                 }
5970             }
5971
5972             var parts = [],
5973                 rewrites = this.namespaceRewrites,
5974                 rewrite, from, to, i, ln, root = Ext.global;
5975
5976             for (i = 0, ln = rewrites.length; i < ln; i++) {
5977                 rewrite = rewrites[i];
5978                 from = rewrite.from;
5979                 to = rewrite.to;
5980
5981                 if (namespace === from || namespace.substring(0, from.length) === from) {
5982                     namespace = namespace.substring(from.length);
5983
5984                     if (typeof to !== 'string') {
5985                         root = to;
5986                     } else {
5987                         parts = parts.concat(to.split('.'));
5988                     }
5989
5990                     break;
5991                 }
5992             }
5993
5994             parts.push(root);
5995
5996             parts = parts.concat(namespace.split('.'));
5997
5998             if (this.enableNamespaceParseCache) {
5999                 cache[namespace] = parts;
6000             }
6001
6002             return parts;
6003         },
6004
6005         /**
6006          * Creates a namespace and assign the `value` to the created object
6007          *
6008          *     Ext.ClassManager.setNamespace('MyCompany.pkg.Example', someObject);
6009          *
6010          *     alert(MyCompany.pkg.Example === someObject); // alerts true
6011          *
6012          * @param {String} name
6013          * @param {Mixed} value
6014          */
6015         setNamespace: function(name, value) {
6016             var root = Ext.global,
6017                 parts = this.parseNamespace(name),
6018                 leaf = parts.pop(),
6019                 i, ln, part;
6020
6021             for (i = 0, ln = parts.length; i < ln; i++) {
6022                 part = parts[i];
6023
6024                 if (typeof part !== 'string') {
6025                     root = part;
6026                 } else {
6027                     if (!root[part]) {
6028                         root[part] = {};
6029                     }
6030
6031                     root = root[part];
6032                 }
6033             }
6034
6035             root[leaf] = value;
6036
6037             return root[leaf];
6038         },
6039
6040         /**
6041          * The new Ext.ns, supports namespace rewriting
6042          * @private
6043          */
6044         createNamespaces: function() {
6045             var root = Ext.global,
6046                 parts, part, i, j, ln, subLn;
6047
6048             for (i = 0, ln = arguments.length; i < ln; i++) {
6049                 parts = this.parseNamespace(arguments[i]);
6050
6051                 for (j = 0, subLn = parts.length; j < subLn; j++) {
6052                     part = parts[j];
6053
6054                     if (typeof part !== 'string') {
6055                         root = part;
6056                     } else {
6057                         if (!root[part]) {
6058                             root[part] = {};
6059                         }
6060
6061                         root = root[part];
6062                     }
6063                 }
6064             }
6065
6066             return root;
6067         },
6068
6069         /**
6070          * Sets a name reference to a class.
6071          *
6072          * @param {String} name
6073          * @param {Object} value
6074          * @return {Ext.ClassManager} this
6075          */
6076         set: function(name, value) {
6077             var targetName = this.getName(value);
6078
6079             this.classes[name] = this.setNamespace(name, value);
6080
6081             if (targetName && targetName !== name) {
6082                 this.maps.alternateToName[name] = targetName;
6083             }
6084
6085             return this;
6086         },
6087
6088         /**
6089          * Retrieve a class by its name.
6090          *
6091          * @param {String} name
6092          * @return {Class} class
6093          */
6094         get: function(name) {
6095             if (this.classes.hasOwnProperty(name)) {
6096                 return this.classes[name];
6097             }
6098
6099             var root = Ext.global,
6100                 parts = this.parseNamespace(name),
6101                 part, i, ln;
6102
6103             for (i = 0, ln = parts.length; i < ln; i++) {
6104                 part = parts[i];
6105
6106                 if (typeof part !== 'string') {
6107                     root = part;
6108                 } else {
6109                     if (!root || !root[part]) {
6110                         return null;
6111                     }
6112
6113                     root = root[part];
6114                 }
6115             }
6116
6117             return root;
6118         },
6119
6120         /**
6121          * Register the alias for a class.
6122          *
6123          * @param {Class/String} cls a reference to a class or a className
6124          * @param {String} alias Alias to use when referring to this class
6125          */
6126         setAlias: function(cls, alias) {
6127             var aliasToNameMap = this.maps.aliasToName,
6128                 nameToAliasesMap = this.maps.nameToAliases,
6129                 className;
6130
6131             if (typeof cls === 'string') {
6132                 className = cls;
6133             } else {
6134                 className = this.getName(cls);
6135             }
6136
6137             if (alias && aliasToNameMap[alias] !== className) {
6138
6139                 aliasToNameMap[alias] = className;
6140             }
6141
6142             if (!nameToAliasesMap[className]) {
6143                 nameToAliasesMap[className] = [];
6144             }
6145
6146             if (alias) {
6147                 Ext.Array.include(nameToAliasesMap[className], alias);
6148             }
6149
6150             return this;
6151         },
6152
6153         /**
6154          * Get a reference to the class by its alias.
6155          *
6156          * @param {String} alias
6157          * @return {Class} class
6158          */
6159         getByAlias: function(alias) {
6160             return this.get(this.getNameByAlias(alias));
6161         },
6162
6163         /**
6164          * Get the name of a class by its alias.
6165          *
6166          * @param {String} alias
6167          * @return {String} className
6168          */
6169         getNameByAlias: function(alias) {
6170             return this.maps.aliasToName[alias] || '';
6171         },
6172
6173         /**
6174          * Get the name of a class by its alternate name.
6175          *
6176          * @param {String} alternate
6177          * @return {String} className
6178          */
6179         getNameByAlternate: function(alternate) {
6180             return this.maps.alternateToName[alternate] || '';
6181         },
6182
6183         /**
6184          * Get the aliases of a class by the class name
6185          *
6186          * @param {String} name
6187          * @return {Array} aliases
6188          */
6189         getAliasesByName: function(name) {
6190             return this.maps.nameToAliases[name] || [];
6191         },
6192
6193         /**
6194          * Get the name of the class by its reference or its instance.
6195          *
6196          *     Ext.ClassManager.getName(Ext.Action); // returns "Ext.Action"
6197          *
6198          * {@link Ext#getClassName Ext.getClassName} is alias for {@link Ext.ClassManager#getName Ext.ClassManager.getName}.
6199          *
6200          * @param {Class/Object} object
6201          * @return {String} className
6202          */
6203         getName: function(object) {
6204             return object && object.$className || '';
6205         },
6206
6207         /**
6208          * Get the class of the provided object; returns null if it's not an instance
6209          * of any class created with Ext.define.
6210          *
6211          *     var component = new Ext.Component();
6212          *
6213          *     Ext.ClassManager.getClass(component); // returns Ext.Component
6214          *
6215          * {@link Ext#getClass Ext.getClass} is alias for {@link Ext.ClassManager#getClass Ext.ClassManager.getClass}.
6216          *
6217          * @param {Object} object
6218          * @return {Class} class
6219          */
6220         getClass: function(object) {
6221             return object && object.self || null;
6222         },
6223
6224         /**
6225          * Defines a class.
6226          *
6227          *     Ext.ClassManager.create('My.awesome.Class', {
6228          *         someProperty: 'something',
6229          *         someMethod: function() { ... }
6230          *         ...
6231          *
6232          *     }, function() {
6233          *         alert('Created!');
6234          *         alert(this === My.awesome.Class); // alerts true
6235          *
6236          *         var myInstance = new this();
6237          *     });
6238          *
6239          * {@link Ext#define Ext.define} is alias for {@link Ext.ClassManager#create Ext.ClassManager.create}.
6240          *
6241          * @param {String} className The class name to create in string dot-namespaced format, for example:
6242          * 'My.very.awesome.Class', 'FeedViewer.plugin.CoolPager'
6243          * It is highly recommended to follow this simple convention:
6244          *
6245          * - The root and the class name are 'CamelCased'
6246          * - Everything else is lower-cased
6247          *
6248          * @param {Object} data The key - value pairs of properties to apply to this class. Property names can be of any valid
6249          * strings, except those in the reserved list below:
6250          *
6251          * - {@link Ext.Base#self self}
6252          * - {@link Ext.Class#alias alias}
6253          * - {@link Ext.Class#alternateClassName alternateClassName}
6254          * - {@link Ext.Class#config config}
6255          * - {@link Ext.Class#extend extend}
6256          * - {@link Ext.Class#inheritableStatics inheritableStatics}
6257          * - {@link Ext.Class#mixins mixins}
6258          * - {@link Ext.Class#requires requires}
6259          * - {@link Ext.Class#singleton singleton}
6260          * - {@link Ext.Class#statics statics}
6261          * - {@link Ext.Class#uses uses}
6262          *
6263          * @param {Function} createdFn Optional callback to execute after the class is created, the execution scope of which
6264          * (`this`) will be the newly created class itself.
6265          * @return {Ext.Base}
6266          */
6267         create: function(className, data, createdFn) {
6268             var manager = this;
6269
6270
6271             data.$className = className;
6272
6273             return new Class(data, function() {
6274                 var postprocessorStack = data.postprocessors || manager.defaultPostprocessors,
6275                     registeredPostprocessors = manager.postprocessors,
6276                     index = 0,
6277                     postprocessors = [],
6278                     postprocessor, postprocessors, process, i, ln;
6279
6280                 delete data.postprocessors;
6281
6282                 for (i = 0, ln = postprocessorStack.length; i < ln; i++) {
6283                     postprocessor = postprocessorStack[i];
6284
6285                     if (typeof postprocessor === 'string') {
6286                         postprocessor = registeredPostprocessors[postprocessor];
6287
6288                         if (!postprocessor.always) {
6289                             if (data[postprocessor.name] !== undefined) {
6290                                 postprocessors.push(postprocessor.fn);
6291                             }
6292                         }
6293                         else {
6294                             postprocessors.push(postprocessor.fn);
6295                         }
6296                     }
6297                     else {
6298                         postprocessors.push(postprocessor);
6299                     }
6300                 }
6301
6302                 process = function(clsName, cls, clsData) {
6303                     postprocessor = postprocessors[index++];
6304
6305                     if (!postprocessor) {
6306                         manager.set(className, cls);
6307
6308                         Ext.Loader.historyPush(className);
6309
6310                         if (createdFn) {
6311                             createdFn.call(cls, cls);
6312                         }
6313
6314                         return;
6315                     }
6316
6317                     if (postprocessor.call(this, clsName, cls, clsData, process) !== false) {
6318                         process.apply(this, arguments);
6319                     }
6320                 };
6321
6322                 process.call(manager, className, this, data);
6323             });
6324         },
6325
6326         /**
6327          * Instantiate a class by its alias.
6328          *
6329          * If {@link Ext.Loader} is {@link Ext.Loader#setConfig enabled} and the class has not been defined yet, it will
6330          * attempt to load the class via synchronous loading.
6331          *
6332          *     var window = Ext.ClassManager.instantiateByAlias('widget.window', { width: 600, height: 800, ... });
6333          *
6334          * {@link Ext#createByAlias Ext.createByAlias} is alias for {@link Ext.ClassManager#instantiateByAlias Ext.ClassManager.instantiateByAlias}.
6335          *
6336          * @param {String} alias
6337          * @param {Mixed} args,... Additional arguments after the alias will be passed to the
6338          * class constructor.
6339          * @return {Object} instance
6340          */
6341         instantiateByAlias: function() {
6342             var alias = arguments[0],
6343                 args = slice.call(arguments),
6344                 className = this.getNameByAlias(alias);
6345
6346             if (!className) {
6347                 className = this.maps.aliasToName[alias];
6348
6349
6350
6351                 Ext.syncRequire(className);
6352             }
6353
6354             args[0] = className;
6355
6356             return this.instantiate.apply(this, args);
6357         },
6358
6359         /**
6360          * Instantiate a class by either full name, alias or alternate name.
6361          *
6362          * If {@link Ext.Loader} is {@link Ext.Loader#setConfig enabled} and the class has not been defined yet, it will
6363          * attempt to load the class via synchronous loading.
6364          *
6365          * For example, all these three lines return the same result:
6366          *
6367          *     // alias
6368          *     var window = Ext.ClassManager.instantiate('widget.window', { width: 600, height: 800, ... });
6369          *
6370          *     // alternate name
6371          *     var window = Ext.ClassManager.instantiate('Ext.Window', { width: 600, height: 800, ... });
6372          *
6373          *     // full class name
6374          *     var window = Ext.ClassManager.instantiate('Ext.window.Window', { width: 600, height: 800, ... });
6375          *
6376          * {@link Ext#create Ext.create} is alias for {@link Ext.ClassManager#instantiate Ext.ClassManager.instantiate}.
6377          *
6378          * @param {String} name
6379          * @param {Mixed} args,... Additional arguments after the name will be passed to the class' constructor.
6380          * @return {Object} instance
6381          */
6382         instantiate: function() {
6383             var name = arguments[0],
6384                 args = slice.call(arguments, 1),
6385                 alias = name,
6386                 possibleName, cls;
6387
6388             if (typeof name !== 'function') {
6389
6390                 cls = this.get(name);
6391             }
6392             else {
6393                 cls = name;
6394             }
6395
6396             // No record of this class name, it's possibly an alias, so look it up
6397             if (!cls) {
6398                 possibleName = this.getNameByAlias(name);
6399
6400                 if (possibleName) {
6401                     name = possibleName;
6402
6403                     cls = this.get(name);
6404                 }
6405             }
6406
6407             // Still no record of this class name, it's possibly an alternate name, so look it up
6408             if (!cls) {
6409                 possibleName = this.getNameByAlternate(name);
6410
6411                 if (possibleName) {
6412                     name = possibleName;
6413
6414                     cls = this.get(name);
6415                 }
6416             }
6417
6418             // Still not existing at this point, try to load it via synchronous mode as the last resort
6419             if (!cls) {
6420
6421                 Ext.syncRequire(name);
6422
6423                 cls = this.get(name);
6424             }
6425
6426
6427
6428             return this.getInstantiator(args.length)(cls, args);
6429         },
6430
6431         /**
6432          * @private
6433          * @param name
6434          * @param args
6435          */
6436         dynInstantiate: function(name, args) {
6437             args = Ext.Array.from(args, true);
6438             args.unshift(name);
6439
6440             return this.instantiate.apply(this, args);
6441         },
6442
6443         /**
6444          * @private
6445          * @param length
6446          */
6447         getInstantiator: function(length) {
6448             if (!this.instantiators[length]) {
6449                 var i = length,
6450                     args = [];
6451
6452                 for (i = 0; i < length; i++) {
6453                     args.push('a['+i+']');
6454                 }
6455
6456                 this.instantiators[length] = new Function('c', 'a', 'return new c('+args.join(',')+')');
6457             }
6458
6459             return this.instantiators[length];
6460         },
6461
6462         /**
6463          * @private
6464          */
6465         postprocessors: {},
6466
6467         /**
6468          * @private
6469          */
6470         defaultPostprocessors: [],
6471
6472         /**
6473          * Register a post-processor function.
6474          *
6475          * @param {String} name
6476          * @param {Function} postprocessor
6477          */
6478         registerPostprocessor: function(name, fn, always) {
6479             this.postprocessors[name] = {
6480                 name: name,
6481                 always: always ||  false,
6482                 fn: fn
6483             };
6484
6485             return this;
6486         },
6487
6488         /**
6489          * Set the default post processors array stack which are applied to every class.
6490          *
6491          * @param {String/Array} The name of a registered post processor or an array of registered names.
6492          * @return {Ext.ClassManager} this
6493          */
6494         setDefaultPostprocessors: function(postprocessors) {
6495             this.defaultPostprocessors = Ext.Array.from(postprocessors);
6496
6497             return this;
6498         },
6499
6500         /**
6501          * Insert this post-processor at a specific position in the stack, optionally relative to
6502          * any existing post-processor
6503          *
6504          * @param {String} name The post-processor name. Note that it needs to be registered with
6505          * {@link Ext.ClassManager#registerPostprocessor} before this
6506          * @param {String} offset The insertion position. Four possible values are:
6507          * 'first', 'last', or: 'before', 'after' (relative to the name provided in the third argument)
6508          * @param {String} relativeName
6509          * @return {Ext.ClassManager} this
6510          */
6511         setDefaultPostprocessorPosition: function(name, offset, relativeName) {
6512             var defaultPostprocessors = this.defaultPostprocessors,
6513                 index;
6514
6515             if (typeof offset === 'string') {
6516                 if (offset === 'first') {
6517                     defaultPostprocessors.unshift(name);
6518
6519                     return this;
6520                 }
6521                 else if (offset === 'last') {
6522                     defaultPostprocessors.push(name);
6523
6524                     return this;
6525                 }
6526
6527                 offset = (offset === 'after') ? 1 : -1;
6528             }
6529
6530             index = Ext.Array.indexOf(defaultPostprocessors, relativeName);
6531
6532             if (index !== -1) {
6533                 Ext.Array.splice(defaultPostprocessors, Math.max(0, index + offset), 0, name);
6534             }
6535
6536             return this;
6537         },
6538
6539         /**
6540          * Converts a string expression to an array of matching class names. An expression can either refers to class aliases
6541          * or class names. Expressions support wildcards:
6542          *
6543          *     // returns ['Ext.window.Window']
6544          *     var window = Ext.ClassManager.getNamesByExpression('widget.window');
6545          *
6546          *     // returns ['widget.panel', 'widget.window', ...]
6547          *     var allWidgets = Ext.ClassManager.getNamesByExpression('widget.*');
6548          *
6549          *     // returns ['Ext.data.Store', 'Ext.data.ArrayProxy', ...]
6550          *     var allData = Ext.ClassManager.getNamesByExpression('Ext.data.*');
6551          *
6552          * @param {String} expression
6553          * @return {Array} classNames
6554          * @markdown
6555          */
6556         getNamesByExpression: function(expression) {
6557             var nameToAliasesMap = this.maps.nameToAliases,
6558                 names = [],
6559                 name, alias, aliases, possibleName, regex, i, ln;
6560
6561
6562             if (expression.indexOf('*') !== -1) {
6563                 expression = expression.replace(/\*/g, '(.*?)');
6564                 regex = new RegExp('^' + expression + '$');
6565
6566                 for (name in nameToAliasesMap) {
6567                     if (nameToAliasesMap.hasOwnProperty(name)) {
6568                         aliases = nameToAliasesMap[name];
6569
6570                         if (name.search(regex) !== -1) {
6571                             names.push(name);
6572                         }
6573                         else {
6574                             for (i = 0, ln = aliases.length; i < ln; i++) {
6575                                 alias = aliases[i];
6576
6577                                 if (alias.search(regex) !== -1) {
6578                                     names.push(name);
6579                                     break;
6580                                 }
6581                             }
6582                         }
6583                     }
6584                 }
6585
6586             } else {
6587                 possibleName = this.getNameByAlias(expression);
6588
6589                 if (possibleName) {
6590                     names.push(possibleName);
6591                 } else {
6592                     possibleName = this.getNameByAlternate(expression);
6593
6594                     if (possibleName) {
6595                         names.push(possibleName);
6596                     } else {
6597                         names.push(expression);
6598                     }
6599                 }
6600             }
6601
6602             return names;
6603         }
6604     };
6605
6606     /**
6607      * @cfg {[String]} alias
6608      * @member Ext.Class
6609      * List of short aliases for class names.  Most useful for defining xtypes for widgets:
6610      *
6611      *     Ext.define('MyApp.CoolPanel', {
6612      *         extend: 'Ext.panel.Panel',
6613      *         alias: ['widget.coolpanel'],
6614      *         title: 'Yeah!'
6615      *     });
6616      *
6617      *     // Using Ext.create
6618      *     Ext.widget('widget.coolpanel');
6619      *     // Using the shorthand for widgets and in xtypes
6620      *     Ext.widget('panel', {
6621      *         items: [
6622      *             {xtype: 'coolpanel', html: 'Foo'},
6623      *             {xtype: 'coolpanel', html: 'Bar'}
6624      *         ]
6625      *     });
6626      */
6627     Manager.registerPostprocessor('alias', function(name, cls, data) {
6628         var aliases = data.alias,
6629             widgetPrefix = 'widget.',
6630             i, ln, alias;
6631
6632         if (!(aliases instanceof Array)) {
6633             aliases = [aliases];
6634         }
6635
6636         for (i = 0, ln = aliases.length; i < ln; i++) {
6637             alias = aliases[i];
6638
6639
6640             this.setAlias(cls, alias);
6641         }
6642
6643         // This is ugly, will change to make use of parseNamespace for alias later on
6644         for (i = 0, ln = aliases.length; i < ln; i++) {
6645             alias = aliases[i];
6646
6647             if (alias.substring(0, widgetPrefix.length) === widgetPrefix) {
6648                 // Only the first alias with 'widget.' prefix will be used for xtype
6649                 cls.xtype = cls.$xtype = alias.substring(widgetPrefix.length);
6650                 break;
6651             }
6652         }
6653     });
6654
6655     /**
6656      * @cfg {Boolean} singleton
6657      * @member Ext.Class
6658      * When set to true, the class will be instanciated as singleton.  For example:
6659      *
6660      *     Ext.define('Logger', {
6661      *         singleton: true,
6662      *         log: function(msg) {
6663      *             console.log(msg);
6664      *         }
6665      *     });
6666      *
6667      *     Logger.log('Hello');
6668      */
6669     Manager.registerPostprocessor('singleton', function(name, cls, data, fn) {
6670         fn.call(this, name, new cls(), data);
6671         return false;
6672     });
6673
6674     /**
6675      * @cfg {String/[String]} alternateClassName
6676      * @member Ext.Class
6677      * Defines alternate names for this class.  For example:
6678      *
6679      *     Ext.define('Developer', {
6680      *         alternateClassName: ['Coder', 'Hacker'],
6681      *         code: function(msg) {
6682      *             alert('Typing... ' + msg);
6683      *         }
6684      *     });
6685      *
6686      *     var joe = Ext.create('Developer');
6687      *     joe.code('stackoverflow');
6688      *
6689      *     var rms = Ext.create('Hacker');
6690      *     rms.code('hack hack');
6691      */
6692     Manager.registerPostprocessor('alternateClassName', function(name, cls, data) {
6693         var alternates = data.alternateClassName,
6694             i, ln, alternate;
6695
6696         if (!(alternates instanceof Array)) {
6697             alternates = [alternates];
6698         }
6699
6700         for (i = 0, ln = alternates.length; i < ln; i++) {
6701             alternate = alternates[i];
6702
6703
6704             this.set(alternate, cls);
6705         }
6706     });
6707
6708     Manager.setDefaultPostprocessors(['alias', 'singleton', 'alternateClassName']);
6709
6710     Ext.apply(Ext, {
6711         /**
6712          * @method
6713          * @member Ext
6714          * @alias Ext.ClassManager#instantiate
6715          */
6716         create: alias(Manager, 'instantiate'),
6717
6718         /**
6719          * @private
6720          * API to be stablized
6721          *
6722          * @param {Mixed} item
6723          * @param {String} namespace
6724          */
6725         factory: function(item, namespace) {
6726             if (item instanceof Array) {
6727                 var i, ln;
6728
6729                 for (i = 0, ln = item.length; i < ln; i++) {
6730                     item[i] = Ext.factory(item[i], namespace);
6731                 }
6732
6733                 return item;
6734             }
6735
6736             var isString = (typeof item === 'string');
6737
6738             if (isString || (item instanceof Object && item.constructor === Object)) {
6739                 var name, config = {};
6740
6741                 if (isString) {
6742                     name = item;
6743                 }
6744                 else {
6745                     name = item.className;
6746                     config = item;
6747                     delete config.className;
6748                 }
6749
6750                 if (namespace !== undefined && name.indexOf(namespace) === -1) {
6751                     name = namespace + '.' + Ext.String.capitalize(name);
6752                 }
6753
6754                 return Ext.create(name, config);
6755             }
6756
6757             if (typeof item === 'function') {
6758                 return Ext.create(item);
6759             }
6760
6761             return item;
6762         },
6763
6764         /**
6765          * Convenient shorthand to create a widget by its xtype, also see {@link Ext.ClassManager#instantiateByAlias}
6766          *
6767          *     var button = Ext.widget('button'); // Equivalent to Ext.create('widget.button')
6768          *     var panel = Ext.widget('panel'); // Equivalent to Ext.create('widget.panel')
6769          *
6770          * @method
6771          * @member Ext
6772          * @param {String} name  xtype of the widget to create.
6773          * @return {Object} widget instance
6774          */
6775         widget: function(name) {
6776             var args = slice.call(arguments);
6777             args[0] = 'widget.' + name;
6778
6779             return Manager.instantiateByAlias.apply(Manager, args);
6780         },
6781
6782         /**
6783          * @method
6784          * @member Ext
6785          * @alias Ext.ClassManager#instantiateByAlias
6786          */
6787         createByAlias: alias(Manager, 'instantiateByAlias'),
6788
6789         /**
6790          * @method
6791          * @member Ext
6792          * @alias Ext.ClassManager#create
6793          */
6794         define: alias(Manager, 'create'),
6795
6796         /**
6797          * @method
6798          * @member Ext
6799          * @alias Ext.ClassManager#getName
6800          */
6801         getClassName: alias(Manager, 'getName'),
6802
6803         /**
6804          *
6805          * @param {Mixed} object
6806          */
6807         getDisplayName: function(object) {
6808             if (object.displayName) {
6809                 return object.displayName;
6810             }
6811
6812             if (object.$name && object.$class) {
6813                 return Ext.getClassName(object.$class) + '#' + object.$name;
6814             }
6815
6816             if (object.$className) {
6817                 return object.$className;
6818             }
6819
6820             return 'Anonymous';
6821         },
6822
6823         /**
6824          * @method
6825          * @member Ext
6826          * @alias Ext.ClassManager#getClass
6827          */
6828         getClass: alias(Manager, 'getClass'),
6829
6830         /**
6831          * Creates namespaces to be used for scoping variables and classes so that they are not global.
6832          * Specifying the last node of a namespace implicitly creates all other nodes. Usage:
6833          *
6834          *     Ext.namespace('Company', 'Company.data');
6835          *
6836          *     // equivalent and preferable to the above syntax
6837          *     Ext.namespace('Company.data');
6838          *
6839          *     Company.Widget = function() { ... };
6840          *
6841          *     Company.data.CustomStore = function(config) { ... };
6842          *
6843          * @method
6844          * @member Ext
6845          * @param {String} namespace1
6846          * @param {String} namespace2
6847          * @param {String} etc
6848          * @return {Object} The namespace object. (If multiple arguments are passed, this will be the last namespace created)
6849          */
6850         namespace: alias(Manager, 'createNamespaces')
6851     });
6852
6853     /**
6854      * Old name for {@link Ext#widget}.
6855      * @deprecated 4.0.0 Use {@link Ext#widget} instead.
6856      * @method
6857      * @member Ext
6858      * @alias Ext#widget
6859      */
6860     Ext.createWidget = Ext.widget;
6861
6862     /**
6863      * Convenient alias for {@link Ext#namespace Ext.namespace}
6864      * @method
6865      * @member Ext
6866      * @alias Ext#namespace
6867      */
6868     Ext.ns = Ext.namespace;
6869
6870     Class.registerPreprocessor('className', function(cls, data) {
6871         if (data.$className) {
6872             cls.$className = data.$className;
6873         }
6874     }, true);
6875
6876     Class.setDefaultPreprocessorPosition('className', 'first');
6877
6878 })(Ext.Class, Ext.Function.alias);
6879
6880 /**
6881  * @class Ext.Loader
6882  * @singleton
6883  * @author Jacky Nguyen <jacky@sencha.com>
6884  * @docauthor Jacky Nguyen <jacky@sencha.com>
6885  *
6886  * Ext.Loader is the heart of the new dynamic dependency loading capability in Ext JS 4+. It is most commonly used
6887  * via the {@link Ext#require} shorthand. Ext.Loader supports both asynchronous and synchronous loading
6888  * approaches, and leverage their advantages for the best development flow. We'll discuss about the pros and cons
6889  * of each approach:
6890  *
6891  * # Asynchronous Loading
6892  *
6893  * - *Advantages:*
6894  *       + Cross-domain
6895  *       + No web server needed: you can run the application via the file system protocol
6896  *     (i.e: `file://path/to/your/index.html`)
6897  *       + Best possible debugging experience: error messages come with the exact file name and line number
6898  *
6899  * - *Disadvantages:*
6900  *       + Dependencies need to be specified before-hand
6901  *
6902  * ### Method 1: Explicitly include what you need:
6903  *
6904  *     // Syntax
6905  *     Ext.require({String/Array} expressions);
6906  *
6907  *     // Example: Single alias
6908  *     Ext.require('widget.window');
6909  *
6910  *     // Example: Single class name
6911  *     Ext.require('Ext.window.Window');
6912  *
6913  *     // Example: Multiple aliases / class names mix
6914  *     Ext.require(['widget.window', 'layout.border', 'Ext.data.Connection']);
6915  *
6916  *     // Wildcards
6917  *     Ext.require(['widget.*', 'layout.*', 'Ext.data.*']);
6918  *
6919  * ### Method 2: Explicitly exclude what you don't need:
6920  *
6921  *     // Syntax: Note that it must be in this chaining format.
6922  *     Ext.exclude({String/Array} expressions)
6923  *        .require({String/Array} expressions);
6924  *
6925  *     // Include everything except Ext.data.*
6926  *     Ext.exclude('Ext.data.*').require('*'); 
6927  *
6928  *     // Include all widgets except widget.checkbox*,
6929  *     // which will match widget.checkbox, widget.checkboxfield, widget.checkboxgroup, etc.
6930  *     Ext.exclude('widget.checkbox*').require('widget.*');
6931  *
6932  * # Synchronous Loading on Demand
6933  *
6934  * - *Advantages:*
6935  *       + There's no need to specify dependencies before-hand, which is always the convenience of including
6936  *     ext-all.js before
6937  *
6938  * - *Disadvantages:*
6939  *       + Not as good debugging experience since file name won't be shown (except in Firebug at the moment)
6940  *       + Must be from the same domain due to XHR restriction
6941  *       + Need a web server, same reason as above
6942  *
6943  * There's one simple rule to follow: Instantiate everything with Ext.create instead of the `new` keyword
6944  *
6945  *     Ext.create('widget.window', { ... }); // Instead of new Ext.window.Window({...});
6946  *
6947  *     Ext.create('Ext.window.Window', {}); // Same as above, using full class name instead of alias
6948  *
6949  *     Ext.widget('window', {}); // Same as above, all you need is the traditional `xtype`
6950  *
6951  * Behind the scene, {@link Ext.ClassManager} will automatically check whether the given class name / alias has already
6952  * existed on the page. If it's not, Ext.Loader will immediately switch itself to synchronous mode and automatic load
6953  * the given class and all its dependencies.
6954  *
6955  * # Hybrid Loading - The Best of Both Worlds
6956  *
6957  * It has all the advantages combined from asynchronous and synchronous loading. The development flow is simple:
6958  *
6959  * ### Step 1: Start writing your application using synchronous approach.
6960  * 
6961  * Ext.Loader will automatically fetch all dependencies on demand as they're needed during run-time. For example:
6962  *
6963  *     Ext.onReady(function(){
6964  *         var window = Ext.createWidget('window', {
6965  *             width: 500,
6966  *             height: 300,
6967  *             layout: {
6968  *                 type: 'border',
6969  *                 padding: 5
6970  *             },
6971  *             title: 'Hello Dialog',
6972  *             items: [{
6973  *                 title: 'Navigation',
6974  *                 collapsible: true,
6975  *                 region: 'west',
6976  *                 width: 200,
6977  *                 html: 'Hello',
6978  *                 split: true
6979  *             }, {
6980  *                 title: 'TabPanel',
6981  *                 region: 'center'
6982  *             }]
6983  *         });
6984  *
6985  *         window.show();
6986  *     })
6987  *
6988  * ### Step 2: Along the way, when you need better debugging ability, watch the console for warnings like these:
6989  *
6990  *     [Ext.Loader] Synchronously loading 'Ext.window.Window'; consider adding Ext.require('Ext.window.Window') before your application's code ClassManager.js:432
6991  *     [Ext.Loader] Synchronously loading 'Ext.layout.container.Border'; consider adding Ext.require('Ext.layout.container.Border') before your application's code
6992  *
6993  * Simply copy and paste the suggested code above `Ext.onReady`, e.g.:
6994  *
6995  *     Ext.require('Ext.window.Window');
6996  *     Ext.require('Ext.layout.container.Border');
6997  *
6998  *     Ext.onReady(...);
6999  *
7000  * Everything should now load via asynchronous mode.
7001  *
7002  * # Deployment
7003  *
7004  * It's important to note that dynamic loading should only be used during development on your local machines.
7005  * During production, all dependencies should be combined into one single JavaScript file. Ext.Loader makes
7006  * the whole process of transitioning from / to between development / maintenance and production as easy as
7007  * possible. Internally {@link Ext.Loader#history Ext.Loader.history} maintains the list of all dependencies
7008  * your application needs in the exact loading sequence. It's as simple as concatenating all files in this
7009  * array into one, then include it on top of your application.
7010  *
7011  * This process will be automated with Sencha Command, to be released and documented towards Ext JS 4 Final.
7012  */
7013 (function(Manager, Class, flexSetter, alias) {
7014
7015     var
7016         dependencyProperties = ['extend', 'mixins', 'requires'],
7017         Loader;
7018
7019     Loader = Ext.Loader = {
7020         /**
7021          * @private
7022          */
7023         documentHead: typeof document !== 'undefined' && (document.head || document.getElementsByTagName('head')[0]),
7024
7025         /**
7026          * Flag indicating whether there are still files being loaded
7027          * @private
7028          */
7029         isLoading: false,
7030
7031         /**
7032          * Maintain the queue for all dependencies. Each item in the array is an object of the format:
7033          * {
7034          *      requires: [...], // The required classes for this queue item
7035          *      callback: function() { ... } // The function to execute when all classes specified in requires exist
7036          * }
7037          * @private
7038          */
7039         queue: [],
7040
7041         /**
7042          * Maintain the list of files that have already been handled so that they never get double-loaded
7043          * @private
7044          */
7045         isFileLoaded: {},
7046
7047         /**
7048          * Maintain the list of listeners to execute when all required scripts are fully loaded
7049          * @private
7050          */
7051         readyListeners: [],
7052
7053         /**
7054          * Contains optional dependencies to be loaded last
7055          * @private
7056          */
7057         optionalRequires: [],
7058
7059         /**
7060          * Map of fully qualified class names to an array of dependent classes.
7061          * @private
7062          */
7063         requiresMap: {},
7064
7065         /**
7066          * @private
7067          */
7068         numPendingFiles: 0,
7069
7070         /**
7071          * @private
7072          */
7073         numLoadedFiles: 0,
7074
7075         /** @private */
7076         hasFileLoadError: false,
7077
7078         /**
7079          * @private
7080          */
7081         classNameToFilePathMap: {},
7082
7083         /**
7084          * @property {[String]} history
7085          * An array of class names to keep track of the dependency loading order.
7086          * This is not guaranteed to be the same everytime due to the asynchronous nature of the Loader.
7087          */
7088         history: [],
7089
7090         /**
7091          * Configuration
7092          * @private
7093          */
7094         config: {
7095             /**
7096              * @cfg {Boolean} enabled
7097              * Whether or not to enable the dynamic dependency loading feature Defaults to false
7098              */
7099             enabled: false,
7100
7101             /**
7102              * @cfg {Boolean} disableCaching
7103              * Appends current timestamp to script files to prevent caching Defaults to true
7104              */
7105             disableCaching: true,
7106
7107             /**
7108              * @cfg {String} disableCachingParam
7109              * The get parameter name for the cache buster's timestamp. Defaults to '_dc'
7110              */
7111             disableCachingParam: '_dc',
7112
7113             /**
7114              * @cfg {Object} paths
7115              * The mapping from namespaces to file paths
7116              *
7117              *     {
7118              *         'Ext': '.', // This is set by default, Ext.layout.container.Container will be
7119              *                     // loaded from ./layout/Container.js
7120              *
7121              *         'My': './src/my_own_folder' // My.layout.Container will be loaded from
7122              *                                     // ./src/my_own_folder/layout/Container.js
7123              *     }
7124              *
7125              * Note that all relative paths are relative to the current HTML document.
7126              * If not being specified, for example, `Other.awesome.Class`
7127              * will simply be loaded from `./Other/awesome/Class.js`
7128              */
7129             paths: {
7130                 'Ext': '.'
7131             }
7132         },
7133
7134         /**
7135          * Set the configuration for the loader. This should be called right after ext-core.js
7136          * (or ext-core-debug.js) is included in the page, e.g.:
7137          *
7138          *     <script type="text/javascript" src="ext-core-debug.js"></script>
7139          *     <script type="text/javascript">
7140          *       Ext.Loader.setConfig({
7141          *           enabled: true,
7142          *           paths: {
7143          *               'My': 'my_own_path'
7144          *           }
7145          *       });
7146          *     <script>
7147          *     <script type="text/javascript">
7148          *       Ext.require(...);
7149          *
7150          *       Ext.onReady(function() {
7151          *           // application code here
7152          *       });
7153          *     </script>
7154          *
7155          * Refer to config options of {@link Ext.Loader} for the list of possible properties.
7156          *
7157          * @param {String/Object} name  Name of the value to override, or a config object to override multiple values.
7158          * @param {Object} value  (optional) The new value to set, needed if first parameter is String.
7159          * @return {Ext.Loader} this
7160          */
7161         setConfig: function(name, value) {
7162             if (Ext.isObject(name) && arguments.length === 1) {
7163                 Ext.Object.merge(this.config, name);
7164             }
7165             else {
7166                 this.config[name] = (Ext.isObject(value)) ? Ext.Object.merge(this.config[name], value) : value;
7167             }
7168
7169             return this;
7170         },
7171
7172         /**
7173          * Get the config value corresponding to the specified name.
7174          * If no name is given, will return the config object.
7175          * @param {String} name The config property name
7176          * @return {Object/Mixed}
7177          */
7178         getConfig: function(name) {
7179             if (name) {
7180                 return this.config[name];
7181             }
7182
7183             return this.config;
7184         },
7185
7186         /**
7187          * Sets the path of a namespace. For Example:
7188          *
7189          *     Ext.Loader.setPath('Ext', '.');
7190          *
7191          * @param {String/Object} name See {@link Ext.Function#flexSetter flexSetter}
7192          * @param {String} path See {@link Ext.Function#flexSetter flexSetter}
7193          * @return {Ext.Loader} this
7194          * @method
7195          */
7196         setPath: flexSetter(function(name, path) {
7197             this.config.paths[name] = path;
7198
7199             return this;
7200         }),
7201
7202         /**
7203          * Translates a className to a file path by adding the the proper prefix and converting the .'s to /'s.
7204          * For example:
7205          *
7206          *     Ext.Loader.setPath('My', '/path/to/My');
7207          *
7208          *     alert(Ext.Loader.getPath('My.awesome.Class')); // alerts '/path/to/My/awesome/Class.js'
7209          *
7210          * Note that the deeper namespace levels, if explicitly set, are always resolved first. For example:
7211          *
7212          *     Ext.Loader.setPath({
7213          *         'My': '/path/to/lib',
7214          *         'My.awesome': '/other/path/for/awesome/stuff',
7215          *         'My.awesome.more': '/more/awesome/path'
7216          *     });
7217          *
7218          *     alert(Ext.Loader.getPath('My.awesome.Class')); // alerts '/other/path/for/awesome/stuff/Class.js'
7219          *
7220          *     alert(Ext.Loader.getPath('My.awesome.more.Class')); // alerts '/more/awesome/path/Class.js'
7221          *
7222          *     alert(Ext.Loader.getPath('My.cool.Class')); // alerts '/path/to/lib/cool/Class.js'
7223          *
7224          *     alert(Ext.Loader.getPath('Unknown.strange.Stuff')); // alerts 'Unknown/strange/Stuff.js'
7225          *
7226          * @param {String} className
7227          * @return {String} path
7228          */
7229         getPath: function(className) {
7230             var path = '',
7231                 paths = this.config.paths,
7232                 prefix = this.getPrefix(className);
7233
7234             if (prefix.length > 0) {
7235                 if (prefix === className) {
7236                     return paths[prefix];
7237                 }
7238
7239                 path = paths[prefix];
7240                 className = className.substring(prefix.length + 1);
7241             }
7242
7243             if (path.length > 0) {
7244                 path += '/';
7245             }
7246
7247             return path.replace(/\/\.\//g, '/') + className.replace(/\./g, "/") + '.js';
7248         },
7249
7250         /**
7251          * @private
7252          * @param {String} className
7253          */
7254         getPrefix: function(className) {
7255             var paths = this.config.paths,
7256                 prefix, deepestPrefix = '';
7257
7258             if (paths.hasOwnProperty(className)) {
7259                 return className;
7260             }
7261
7262             for (prefix in paths) {
7263                 if (paths.hasOwnProperty(prefix) && prefix + '.' === className.substring(0, prefix.length + 1)) {
7264                     if (prefix.length > deepestPrefix.length) {
7265                         deepestPrefix = prefix;
7266                     }
7267                 }
7268             }
7269
7270             return deepestPrefix;
7271         },
7272
7273         /**
7274          * Refresh all items in the queue. If all dependencies for an item exist during looping,
7275          * it will execute the callback and call refreshQueue again. Triggers onReady when the queue is
7276          * empty
7277          * @private
7278          */
7279         refreshQueue: function() {
7280             var ln = this.queue.length,
7281                 i, item, j, requires;
7282
7283             if (ln === 0) {
7284                 this.triggerReady();
7285                 return;
7286             }
7287
7288             for (i = 0; i < ln; i++) {
7289                 item = this.queue[i];
7290
7291                 if (item) {
7292                     requires = item.requires;
7293
7294                     // Don't bother checking when the number of files loaded
7295                     // is still less than the array length
7296                     if (requires.length > this.numLoadedFiles) {
7297                         continue;
7298                     }
7299
7300                     j = 0;
7301
7302                     do {
7303                         if (Manager.isCreated(requires[j])) {
7304                             // Take out from the queue
7305                             Ext.Array.erase(requires, j, 1);
7306                         }
7307                         else {
7308                             j++;
7309                         }
7310                     } while (j < requires.length);
7311
7312                     if (item.requires.length === 0) {
7313                         Ext.Array.erase(this.queue, i, 1);
7314                         item.callback.call(item.scope);
7315                         this.refreshQueue();
7316                         break;
7317                     }
7318                 }
7319             }
7320
7321             return this;
7322         },
7323
7324         /**
7325          * Inject a script element to document's head, call onLoad and onError accordingly
7326          * @private
7327          */
7328         injectScriptElement: function(url, onLoad, onError, scope) {
7329             var script = document.createElement('script'),
7330                 me = this,
7331                 onLoadFn = function() {
7332                     me.cleanupScriptElement(script);
7333                     onLoad.call(scope);
7334                 },
7335                 onErrorFn = function() {
7336                     me.cleanupScriptElement(script);
7337                     onError.call(scope);
7338                 };
7339
7340             script.type = 'text/javascript';
7341             script.src = url;
7342             script.onload = onLoadFn;
7343             script.onerror = onErrorFn;
7344             script.onreadystatechange = function() {
7345                 if (this.readyState === 'loaded' || this.readyState === 'complete') {
7346                     onLoadFn();
7347                 }
7348             };
7349
7350             this.documentHead.appendChild(script);
7351
7352             return script;
7353         },
7354
7355         /**
7356          * @private
7357          */
7358         cleanupScriptElement: function(script) {
7359             script.onload = null;
7360             script.onreadystatechange = null;
7361             script.onerror = null;
7362
7363             return this;
7364         },
7365
7366         /**
7367          * Load a script file, supports both asynchronous and synchronous approaches
7368          *
7369          * @param {String} url
7370          * @param {Function} onLoad
7371          * @param {Scope} scope
7372          * @param {Boolean} synchronous
7373          * @private
7374          */
7375         loadScriptFile: function(url, onLoad, onError, scope, synchronous) {
7376             var me = this,
7377                 noCacheUrl = url + (this.getConfig('disableCaching') ? ('?' + this.getConfig('disableCachingParam') + '=' + Ext.Date.now()) : ''),
7378                 fileName = url.split('/').pop(),
7379                 isCrossOriginRestricted = false,
7380                 xhr, status, onScriptError;
7381
7382             scope = scope || this;
7383
7384             this.isLoading = true;
7385
7386             if (!synchronous) {
7387                 onScriptError = function() {
7388                     onError.call(scope, "Failed loading '" + url + "', please verify that the file exists", synchronous);
7389                 };
7390
7391                 if (!Ext.isReady && Ext.onDocumentReady) {
7392                     Ext.onDocumentReady(function() {
7393                         me.injectScriptElement(noCacheUrl, onLoad, onScriptError, scope);
7394                     });
7395                 }
7396                 else {
7397                     this.injectScriptElement(noCacheUrl, onLoad, onScriptError, scope);
7398                 }
7399             }
7400             else {
7401                 if (typeof XMLHttpRequest !== 'undefined') {
7402                     xhr = new XMLHttpRequest();
7403                 } else {
7404                     xhr = new ActiveXObject('Microsoft.XMLHTTP');
7405                 }
7406
7407                 try {
7408                     xhr.open('GET', noCacheUrl, false);
7409                     xhr.send(null);
7410                 } catch (e) {
7411                     isCrossOriginRestricted = true;
7412                 }
7413
7414                 status = (xhr.status === 1223) ? 204 : xhr.status;
7415
7416                 if (!isCrossOriginRestricted) {
7417                     isCrossOriginRestricted = (status === 0);
7418                 }
7419
7420                 if (isCrossOriginRestricted
7421                 ) {
7422                     onError.call(this, "Failed loading synchronously via XHR: '" + url + "'; It's likely that the file is either " +
7423                                        "being loaded from a different domain or from the local file system whereby cross origin " +
7424                                        "requests are not allowed due to security reasons. Use asynchronous loading with " +
7425                                        "Ext.require instead.", synchronous);
7426                 }
7427                 else if (status >= 200 && status < 300
7428                 ) {
7429                     // Firebug friendly, file names are still shown even though they're eval'ed code
7430                     new Function(xhr.responseText + "\n//@ sourceURL=" + fileName)();
7431
7432                     onLoad.call(scope);
7433                 }
7434                 else {
7435                     onError.call(this, "Failed loading synchronously via XHR: '" + url + "'; please " +
7436                                        "verify that the file exists. " +
7437                                        "XHR status code: " + status, synchronous);
7438                 }
7439
7440                 // Prevent potential IE memory leak
7441                 xhr = null;
7442             }
7443         },
7444
7445         /**
7446          * Explicitly exclude files from being loaded. Useful when used in conjunction with a broad include expression.
7447          * Can be chained with more `require` and `exclude` methods, e.g.:
7448          *
7449          *     Ext.exclude('Ext.data.*').require('*');
7450          *
7451          *     Ext.exclude('widget.button*').require('widget.*');
7452          *
7453          * {@link Ext#exclude Ext.exclude} is alias for {@link Ext.Loader#exclude Ext.Loader.exclude} for convenience.
7454          *
7455          * @param {String/[String]} excludes
7456          * @return {Object} object contains `require` method for chaining
7457          */
7458         exclude: function(excludes) {
7459             var me = this;
7460
7461             return {
7462                 require: function(expressions, fn, scope) {
7463                     return me.require(expressions, fn, scope, excludes);
7464                 },
7465
7466                 syncRequire: function(expressions, fn, scope) {
7467                     return me.syncRequire(expressions, fn, scope, excludes);
7468                 }
7469             };
7470         },
7471
7472         /**
7473          * Synchronously loads all classes by the given names and all their direct dependencies;
7474          * optionally executes the given callback function when finishes, within the optional scope.
7475          *
7476          * {@link Ext#syncRequire Ext.syncRequire} is alias for {@link Ext.Loader#syncRequire Ext.Loader.syncRequire} for convenience.
7477          *
7478          * @param {String/[String]} expressions Can either be a string or an array of string
7479          * @param {Function} fn (Optional) The callback function
7480          * @param {Object} scope (Optional) The execution scope (`this`) of the callback function
7481          * @param {String/[String]} excludes (Optional) Classes to be excluded, useful when being used with expressions
7482          */
7483         syncRequire: function() {
7484             this.syncModeEnabled = true;
7485             this.require.apply(this, arguments);
7486             this.refreshQueue();
7487             this.syncModeEnabled = false;
7488         },
7489
7490         /**
7491          * Loads all classes by the given names and all their direct dependencies;
7492          * optionally executes the given callback function when finishes, within the optional scope.
7493          *
7494          * {@link Ext#require Ext.require} is alias for {@link Ext.Loader#require Ext.Loader.require} for convenience.
7495          *
7496          * @param {String/[String]} expressions Can either be a string or an array of string
7497          * @param {Function} fn (Optional) The callback function
7498          * @param {Object} scope (Optional) The execution scope (`this`) of the callback function
7499          * @param {String/[String]} excludes (Optional) Classes to be excluded, useful when being used with expressions
7500          */
7501         require: function(expressions, fn, scope, excludes) {
7502             var filePath, expression, exclude, className, excluded = {},
7503                 excludedClassNames = [],
7504                 possibleClassNames = [],
7505                 possibleClassName, classNames = [],
7506                 i, j, ln, subLn;
7507
7508             expressions = Ext.Array.from(expressions);
7509             excludes = Ext.Array.from(excludes);
7510
7511             fn = fn || Ext.emptyFn;
7512
7513             scope = scope || Ext.global;
7514
7515             for (i = 0, ln = excludes.length; i < ln; i++) {
7516                 exclude = excludes[i];
7517
7518                 if (typeof exclude === 'string' && exclude.length > 0) {
7519                     excludedClassNames = Manager.getNamesByExpression(exclude);
7520
7521                     for (j = 0, subLn = excludedClassNames.length; j < subLn; j++) {
7522                         excluded[excludedClassNames[j]] = true;
7523                     }
7524                 }
7525             }
7526
7527             for (i = 0, ln = expressions.length; i < ln; i++) {
7528                 expression = expressions[i];
7529
7530                 if (typeof expression === 'string' && expression.length > 0) {
7531                     possibleClassNames = Manager.getNamesByExpression(expression);
7532
7533                     for (j = 0, subLn = possibleClassNames.length; j < subLn; j++) {
7534                         possibleClassName = possibleClassNames[j];
7535
7536                         if (!excluded.hasOwnProperty(possibleClassName) && !Manager.isCreated(possibleClassName)) {
7537                             Ext.Array.include(classNames, possibleClassName);
7538                         }
7539                     }
7540                 }
7541             }
7542
7543             // If the dynamic dependency feature is not being used, throw an error
7544             // if the dependencies are not defined
7545             if (!this.config.enabled) {
7546                 if (classNames.length > 0) {
7547                     Ext.Error.raise({
7548                         sourceClass: "Ext.Loader",
7549                         sourceMethod: "require",
7550                         msg: "Ext.Loader is not enabled, so dependencies cannot be resolved dynamically. " +
7551                              "Missing required class" + ((classNames.length > 1) ? "es" : "") + ": " + classNames.join(', ')
7552                     });
7553                 }
7554             }
7555
7556             if (classNames.length === 0) {
7557                 fn.call(scope);
7558                 return this;
7559             }
7560
7561             this.queue.push({
7562                 requires: classNames,
7563                 callback: fn,
7564                 scope: scope
7565             });
7566
7567             classNames = classNames.slice();
7568
7569             for (i = 0, ln = classNames.length; i < ln; i++) {
7570                 className = classNames[i];
7571
7572                 if (!this.isFileLoaded.hasOwnProperty(className)) {
7573                     this.isFileLoaded[className] = false;
7574
7575                     filePath = this.getPath(className);
7576
7577                     this.classNameToFilePathMap[className] = filePath;
7578
7579                     this.numPendingFiles++;
7580
7581                     this.loadScriptFile(
7582                         filePath,
7583                         Ext.Function.pass(this.onFileLoaded, [className, filePath], this),
7584                         Ext.Function.pass(this.onFileLoadError, [className, filePath]),
7585                         this,
7586                         this.syncModeEnabled
7587                     );
7588                 }
7589             }
7590
7591             return this;
7592         },
7593
7594         /**
7595          * @private
7596          * @param {String} className
7597          * @param {String} filePath
7598          */
7599         onFileLoaded: function(className, filePath) {
7600             this.numLoadedFiles++;
7601
7602             this.isFileLoaded[className] = true;
7603
7604             this.numPendingFiles--;
7605
7606             if (this.numPendingFiles === 0) {
7607                 this.refreshQueue();
7608             }
7609
7610
7611         },
7612
7613         /**
7614          * @private
7615          */
7616         onFileLoadError: function(className, filePath, errorMessage, isSynchronous) {
7617             this.numPendingFiles--;
7618             this.hasFileLoadError = true;
7619
7620         },
7621
7622         /**
7623          * @private
7624          */
7625         addOptionalRequires: function(requires) {
7626             var optionalRequires = this.optionalRequires,
7627                 i, ln, require;
7628
7629             requires = Ext.Array.from(requires);
7630
7631             for (i = 0, ln = requires.length; i < ln; i++) {
7632                 require = requires[i];
7633
7634                 Ext.Array.include(optionalRequires, require);
7635             }
7636
7637             return this;
7638         },
7639
7640         /**
7641          * @private
7642          */
7643         triggerReady: function(force) {
7644             var readyListeners = this.readyListeners,
7645                 optionalRequires, listener;
7646
7647             if (this.isLoading || force) {
7648                 this.isLoading = false;
7649
7650                 if (this.optionalRequires.length) {
7651                     // Clone then empty the array to eliminate potential recursive loop issue
7652                     optionalRequires = Ext.Array.clone(this.optionalRequires);
7653
7654                     // Empty the original array
7655                     this.optionalRequires.length = 0;
7656
7657                     this.require(optionalRequires, Ext.Function.pass(this.triggerReady, [true], this), this);
7658                     return this;
7659                 }
7660
7661                 while (readyListeners.length) {
7662                     listener = readyListeners.shift();
7663                     listener.fn.call(listener.scope);
7664
7665                     if (this.isLoading) {
7666                         return this;
7667                     }
7668                 }
7669             }
7670
7671             return this;
7672         },
7673
7674         /**
7675          * Adds new listener to be executed when all required scripts are fully loaded.
7676          *
7677          * @param {Function} fn The function callback to be executed
7678          * @param {Object} scope The execution scope (`this`) of the callback function
7679          * @param {Boolean} withDomReady Whether or not to wait for document dom ready as well
7680          */
7681         onReady: function(fn, scope, withDomReady, options) {
7682             var oldFn;
7683
7684             if (withDomReady !== false && Ext.onDocumentReady) {
7685                 oldFn = fn;
7686
7687                 fn = function() {
7688                     Ext.onDocumentReady(oldFn, scope, options);
7689                 };
7690             }
7691
7692             if (!this.isLoading) {
7693                 fn.call(scope);
7694             }
7695             else {
7696                 this.readyListeners.push({
7697                     fn: fn,
7698                     scope: scope
7699                 });
7700             }
7701         },
7702
7703         /**
7704          * @private
7705          * @param {String} className
7706          */
7707         historyPush: function(className) {
7708             if (className && this.isFileLoaded.hasOwnProperty(className)) {
7709                 Ext.Array.include(this.history, className);
7710             }
7711
7712             return this;
7713         }
7714     };
7715
7716     /**
7717      * @member Ext
7718      * @method require
7719      * @alias Ext.Loader#require
7720      */
7721     Ext.require = alias(Loader, 'require');
7722
7723     /**
7724      * @member Ext
7725      * @method syncRequire
7726      * @alias Ext.Loader#syncRequire
7727      */
7728     Ext.syncRequire = alias(Loader, 'syncRequire');
7729
7730     /**
7731      * @member Ext
7732      * @method exclude
7733      * @alias Ext.Loader#exclude
7734      */
7735     Ext.exclude = alias(Loader, 'exclude');
7736
7737     /**
7738      * @member Ext
7739      * @method onReady
7740      * @alias Ext.Loader#onReady
7741      */
7742     Ext.onReady = function(fn, scope, options) {
7743         Loader.onReady(fn, scope, true, options);
7744     };
7745
7746     /**
7747      * @cfg {[String]} requires
7748      * @member Ext.Class
7749      * List of classes that have to be loaded before instanciating this class.
7750      * For example:
7751      *
7752      *     Ext.define('Mother', {
7753      *         requires: ['Child'],
7754      *         giveBirth: function() {
7755      *             // we can be sure that child class is available.
7756      *             return new Child();
7757      *         }
7758      *     });
7759      */
7760     Class.registerPreprocessor('loader', function(cls, data, continueFn) {
7761         var me = this,
7762             dependencies = [],
7763             className = Manager.getName(cls),
7764             i, j, ln, subLn, value, propertyName, propertyValue;
7765
7766         /*
7767         Basically loop through the dependencyProperties, look for string class names and push
7768         them into a stack, regardless of whether the property's value is a string, array or object. For example:
7769         {
7770               extend: 'Ext.MyClass',
7771               requires: ['Ext.some.OtherClass'],
7772               mixins: {
7773                   observable: 'Ext.util.Observable';
7774               }
7775         }
7776         which will later be transformed into:
7777         {
7778               extend: Ext.MyClass,
7779               requires: [Ext.some.OtherClass],
7780               mixins: {
7781                   observable: Ext.util.Observable;
7782               }
7783         }
7784         */
7785
7786         for (i = 0, ln = dependencyProperties.length; i < ln; i++) {
7787             propertyName = dependencyProperties[i];
7788
7789             if (data.hasOwnProperty(propertyName)) {
7790                 propertyValue = data[propertyName];
7791
7792                 if (typeof propertyValue === 'string') {
7793                     dependencies.push(propertyValue);
7794                 }
7795                 else if (propertyValue instanceof Array) {
7796                     for (j = 0, subLn = propertyValue.length; j < subLn; j++) {
7797                         value = propertyValue[j];
7798
7799                         if (typeof value === 'string') {
7800                             dependencies.push(value);
7801                         }
7802                     }
7803                 }
7804                 else {
7805                     for (j in propertyValue) {
7806                         if (propertyValue.hasOwnProperty(j)) {
7807                             value = propertyValue[j];
7808
7809                             if (typeof value === 'string') {
7810                                 dependencies.push(value);
7811                             }
7812                         }
7813                     }
7814                 }
7815             }
7816         }
7817
7818         if (dependencies.length === 0) {
7819 //            Loader.historyPush(className);
7820             return;
7821         }
7822
7823
7824         Loader.require(dependencies, function() {
7825             for (i = 0, ln = dependencyProperties.length; i < ln; i++) {
7826                 propertyName = dependencyProperties[i];
7827
7828                 if (data.hasOwnProperty(propertyName)) {
7829                     propertyValue = data[propertyName];
7830
7831                     if (typeof propertyValue === 'string') {
7832                         data[propertyName] = Manager.get(propertyValue);
7833                     }
7834                     else if (propertyValue instanceof Array) {
7835                         for (j = 0, subLn = propertyValue.length; j < subLn; j++) {
7836                             value = propertyValue[j];
7837
7838                             if (typeof value === 'string') {
7839                                 data[propertyName][j] = Manager.get(value);
7840                             }
7841                         }
7842                     }
7843                     else {
7844                         for (var k in propertyValue) {
7845                             if (propertyValue.hasOwnProperty(k)) {
7846                                 value = propertyValue[k];
7847
7848                                 if (typeof value === 'string') {
7849                                     data[propertyName][k] = Manager.get(value);
7850                                 }
7851                             }
7852                         }
7853                     }
7854                 }
7855             }
7856
7857             continueFn.call(me, cls, data);
7858         });
7859
7860         return false;
7861     }, true);
7862
7863     Class.setDefaultPreprocessorPosition('loader', 'after', 'className');
7864
7865     /**
7866      * @cfg {[String]} uses
7867      * @member Ext.Class
7868      * List of classes to load together with this class.  These aren't neccessarily loaded before
7869      * this class is instanciated. For example:
7870      *
7871      *     Ext.define('Mother', {
7872      *         uses: ['Child'],
7873      *         giveBirth: function() {
7874      *             // This code might, or might not work:
7875      *             // return new Child();
7876      *
7877      *             // Instead use Ext.create() to load the class at the spot if not loaded already:
7878      *             return Ext.create('Child');
7879      *         }
7880      *     });
7881      */
7882     Manager.registerPostprocessor('uses', function(name, cls, data) {
7883         var uses = Ext.Array.from(data.uses),
7884             items = [],
7885             i, ln, item;
7886
7887         for (i = 0, ln = uses.length; i < ln; i++) {
7888             item = uses[i];
7889
7890             if (typeof item === 'string') {
7891                 items.push(item);
7892             }
7893         }
7894
7895         Loader.addOptionalRequires(items);
7896     });
7897
7898     Manager.setDefaultPostprocessorPosition('uses', 'last');
7899
7900 })(Ext.ClassManager, Ext.Class, Ext.Function.flexSetter, Ext.Function.alias);
7901
7902 /**
7903  * @class Ext.Error
7904  * @private
7905  * @extends Error
7906
7907 A wrapper class for the native JavaScript Error object that adds a few useful capabilities for handling
7908 errors in an Ext application. When you use Ext.Error to {@link #raise} an error from within any class that
7909 uses the Ext 4 class system, the Error class can automatically add the source class and method from which
7910 the error was raised. It also includes logic to automatically log the eroor to the console, if available,
7911 with additional metadata about the error. In all cases, the error will always be thrown at the end so that
7912 execution will halt.
7913
7914 Ext.Error also offers a global error {@link #handle handling} method that can be overridden in order to
7915 handle application-wide errors in a single spot. You can optionally {@link #ignore} errors altogether,
7916 although in a real application it's usually a better idea to override the handling function and perform
7917 logging or some other method of reporting the errors in a way that is meaningful to the application.
7918
7919 At its simplest you can simply raise an error as a simple string from within any code:
7920
7921 #Example usage:#
7922
7923     Ext.Error.raise('Something bad happened!');
7924
7925 If raised from plain JavaScript code, the error will be logged to the console (if available) and the message
7926 displayed. In most cases however you'll be raising errors from within a class, and it may often be useful to add
7927 additional metadata about the error being raised.  The {@link #raise} method can also take a config object.
7928 In this form the `msg` attribute becomes the error description, and any other data added to the config gets
7929 added to the error object and, if the console is available, logged to the console for inspection.
7930
7931 #Example usage:#
7932
7933     Ext.define('Ext.Foo', {
7934         doSomething: function(option){
7935             if (someCondition === false) {
7936                 Ext.Error.raise({
7937                     msg: 'You cannot do that!',
7938                     option: option,   // whatever was passed into the method
7939                     'error code': 100 // other arbitrary info
7940                 });
7941             }
7942         }
7943     });
7944
7945 If a console is available (that supports the `console.dir` function) you'll see console output like:
7946
7947     An error was raised with the following data:
7948     option:         Object { foo: "bar"}
7949         foo:        "bar"
7950     error code:     100
7951     msg:            "You cannot do that!"
7952     sourceClass:   "Ext.Foo"
7953     sourceMethod:  "doSomething"
7954
7955     uncaught exception: You cannot do that!
7956
7957 As you can see, the error will report exactly where it was raised and will include as much information as the
7958 raising code can usefully provide.
7959
7960 If you want to handle all application errors globally you can simply override the static {@link #handle} method
7961 and provide whatever handling logic you need. If the method returns true then the error is considered handled
7962 and will not be thrown to the browser. If anything but true is returned then the error will be thrown normally.
7963
7964 #Example usage:#
7965
7966     Ext.Error.handle = function(err) {
7967         if (err.someProperty == 'NotReallyAnError') {
7968             // maybe log something to the application here if applicable
7969             return true;
7970         }
7971         // any non-true return value (including none) will cause the error to be thrown
7972     }
7973
7974  * Create a new Error object
7975  * @param {Object} config The config object
7976  * @markdown
7977  * @author Brian Moeskau <brian@sencha.com>
7978  * @docauthor Brian Moeskau <brian@sencha.com>
7979  */
7980 Ext.Error = Ext.extend(Error, {
7981     statics: {
7982         /**
7983          * @property ignore
7984 Static flag that can be used to globally disable error reporting to the browser if set to true
7985 (defaults to false). Note that if you ignore Ext errors it's likely that some other code may fail
7986 and throw a native JavaScript error thereafter, so use with caution. In most cases it will probably
7987 be preferable to supply a custom error {@link #handle handling} function instead.
7988
7989 #Example usage:#
7990
7991     Ext.Error.ignore = true;
7992
7993          * @markdown
7994          * @static
7995          */
7996         ignore: false,
7997
7998         /**
7999          * @property notify
8000 Static flag that can be used to globally control error notification to the user. Unlike
8001 Ex.Error.ignore, this does not effect exceptions. They are still thrown. This value can be
8002 set to false to disable the alert notification (default is true for IE6 and IE7).
8003
8004 Only the first error will generate an alert. Internally this flag is set to false when the
8005 first error occurs prior to displaying the alert.
8006
8007 This flag is not used in a release build.
8008
8009 #Example usage:#
8010
8011     Ext.Error.notify = false;
8012
8013          * @markdown
8014          * @static
8015          */
8016         //notify: Ext.isIE6 || Ext.isIE7,
8017
8018         /**
8019 Raise an error that can include additional data and supports automatic console logging if available.
8020 You can pass a string error message or an object with the `msg` attribute which will be used as the
8021 error message. The object can contain any other name-value attributes (or objects) to be logged
8022 along with the error.
8023
8024 Note that after displaying the error message a JavaScript error will ultimately be thrown so that
8025 execution will halt.
8026
8027 #Example usage:#
8028
8029     Ext.Error.raise('A simple string error message');
8030
8031     // or...
8032
8033     Ext.define('Ext.Foo', {
8034         doSomething: function(option){
8035             if (someCondition === false) {
8036                 Ext.Error.raise({
8037                     msg: 'You cannot do that!',
8038                     option: option,   // whatever was passed into the method
8039                     'error code': 100 // other arbitrary info
8040                 });
8041             }
8042         }
8043     });
8044          * @param {String/Object} err The error message string, or an object containing the
8045          * attribute "msg" that will be used as the error message. Any other data included in
8046          * the object will also be logged to the browser console, if available.
8047          * @static
8048          * @markdown
8049          */
8050         raise: function(err){
8051             err = err || {};
8052             if (Ext.isString(err)) {
8053                 err = { msg: err };
8054             }
8055
8056             var method = this.raise.caller;
8057
8058             if (method) {
8059                 if (method.$name) {
8060                     err.sourceMethod = method.$name;
8061                 }
8062                 if (method.$owner) {
8063                     err.sourceClass = method.$owner.$className;
8064                 }
8065             }
8066
8067             if (Ext.Error.handle(err) !== true) {
8068                 var msg = Ext.Error.prototype.toString.call(err);
8069
8070                 Ext.log({
8071                     msg: msg,
8072                     level: 'error',
8073                     dump: err,
8074                     stack: true
8075                 });
8076
8077                 throw new Ext.Error(err);
8078             }
8079         },
8080
8081         /**
8082 Globally handle any Ext errors that may be raised, optionally providing custom logic to
8083 handle different errors individually. Return true from the function to bypass throwing the
8084 error to the browser, otherwise the error will be thrown and execution will halt.
8085
8086 #Example usage:#
8087
8088     Ext.Error.handle = function(err) {
8089         if (err.someProperty == 'NotReallyAnError') {
8090             // maybe log something to the application here if applicable
8091             return true;
8092         }
8093         // any non-true return value (including none) will cause the error to be thrown
8094     }
8095
8096          * @param {Ext.Error} err The Ext.Error object being raised. It will contain any attributes
8097          * that were originally raised with it, plus properties about the method and class from which
8098          * the error originated (if raised from a class that uses the Ext 4 class system).
8099          * @static
8100          * @markdown
8101          */
8102         handle: function(){
8103             return Ext.Error.ignore;
8104         }
8105     },
8106
8107     // This is the standard property that is the name of the constructor.
8108     name: 'Ext.Error',
8109
8110     /**
8111      * @param {String/Object} config The error message string, or an object containing the
8112      * attribute "msg" that will be used as the error message. Any other data included in
8113      * the object will be applied to the error instance and logged to the browser console, if available.
8114      */
8115     constructor: function(config){
8116         if (Ext.isString(config)) {
8117             config = { msg: config };
8118         }
8119
8120         var me = this;
8121
8122         Ext.apply(me, config);
8123
8124         me.message = me.message || me.msg; // 'message' is standard ('msg' is non-standard)
8125         // note: the above does not work in old WebKit (me.message is readonly) (Safari 4)
8126     },
8127
8128     /**
8129 Provides a custom string representation of the error object. This is an override of the base JavaScript
8130 `Object.toString` method, which is useful so that when logged to the browser console, an error object will
8131 be displayed with a useful message instead of `[object Object]`, the default `toString` result.
8132
8133 The default implementation will include the error message along with the raising class and method, if available,
8134 but this can be overridden with a custom implementation either at the prototype level (for all errors) or on
8135 a particular error instance, if you want to provide a custom description that will show up in the console.
8136      * @markdown
8137      * @return {String} The error message. If raised from within the Ext 4 class system, the error message
8138      * will also include the raising class and method names, if available.
8139      */
8140     toString: function(){
8141         var me = this,
8142             className = me.className ? me.className  : '',
8143             methodName = me.methodName ? '.' + me.methodName + '(): ' : '',
8144             msg = me.msg || '(No description provided)';
8145
8146         return className + methodName + msg;
8147     }
8148 });
8149
8150 /*
8151  * This mechanism is used to notify the user of the first error encountered on the page. This
8152  * was previously internal to Ext.Error.raise and is a desirable feature since errors often
8153  * slip silently under the radar. It cannot live in Ext.Error.raise since there are times
8154  * where exceptions are handled in a try/catch.
8155  */
8156
8157
8158
8159 /*
8160
8161 This file is part of Ext JS 4
8162
8163 Copyright (c) 2011 Sencha Inc
8164
8165 Contact:  http://www.sencha.com/contact
8166
8167 GNU General Public License Usage
8168 This file may be used under the terms of the GNU General Public License version 3.0 as published by the Free Software Foundation and appearing in the file LICENSE included in the packaging of this file.  Please review the following information to ensure the GNU General Public License version 3.0 requirements will be met: http://www.gnu.org/copyleft/gpl.html.
8169
8170 If you are unsure which license is appropriate for your use, please contact the sales department at http://www.sencha.com/contact.
8171
8172 */
8173 /**
8174  * @class Ext.JSON
8175  * Modified version of Douglas Crockford"s json.js that doesn"t
8176  * mess with the Object prototype
8177  * http://www.json.org/js.html
8178  * @singleton
8179  */
8180 Ext.JSON = new(function() {
8181     var useHasOwn = !! {}.hasOwnProperty,
8182     isNative = function() {
8183         var useNative = null;
8184
8185         return function() {
8186             if (useNative === null) {
8187                 useNative = Ext.USE_NATIVE_JSON && window.JSON && JSON.toString() == '[object JSON]';
8188             }
8189
8190             return useNative;
8191         };
8192     }(),
8193     pad = function(n) {
8194         return n < 10 ? "0" + n : n;
8195     },
8196     doDecode = function(json) {
8197         return eval("(" + json + ')');
8198     },
8199     doEncode = function(o) {
8200         if (!Ext.isDefined(o) || o === null) {
8201             return "null";
8202         } else if (Ext.isArray(o)) {
8203             return encodeArray(o);
8204         } else if (Ext.isDate(o)) {
8205             return Ext.JSON.encodeDate(o);
8206         } else if (Ext.isString(o)) {
8207             return encodeString(o);
8208         } else if (typeof o == "number") {
8209             //don't use isNumber here, since finite checks happen inside isNumber
8210             return isFinite(o) ? String(o) : "null";
8211         } else if (Ext.isBoolean(o)) {
8212             return String(o);
8213         } else if (Ext.isObject(o)) {
8214             return encodeObject(o);
8215         } else if (typeof o === "function") {
8216             return "null";
8217         }
8218         return 'undefined';
8219     },
8220     m = {
8221         "\b": '\\b',
8222         "\t": '\\t',
8223         "\n": '\\n',
8224         "\f": '\\f',
8225         "\r": '\\r',
8226         '"': '\\"',
8227         "\\": '\\\\',
8228         '\x0b': '\\u000b' //ie doesn't handle \v
8229     },
8230     charToReplace = /[\\\"\x00-\x1f\x7f-\uffff]/g,
8231     encodeString = function(s) {
8232         return '"' + s.replace(charToReplace, function(a) {
8233             var c = m[a];
8234             return typeof c === 'string' ? c : '\\u' + ('0000' + a.charCodeAt(0).toString(16)).slice(-4);
8235         }) + '"';
8236     },
8237     encodeArray = function(o) {
8238         var a = ["[", ""],
8239         // Note empty string in case there are no serializable members.
8240         len = o.length,
8241         i;
8242         for (i = 0; i < len; i += 1) {
8243             a.push(doEncode(o[i]), ',');
8244         }
8245         // Overwrite trailing comma (or empty string)
8246         a[a.length - 1] = ']';
8247         return a.join("");
8248     },
8249     encodeObject = function(o) {
8250         var a = ["{", ""],
8251         // Note empty string in case there are no serializable members.
8252         i;
8253         for (i in o) {
8254             if (!useHasOwn || o.hasOwnProperty(i)) {
8255                 a.push(doEncode(i), ":", doEncode(o[i]), ',');
8256             }
8257         }
8258         // Overwrite trailing comma (or empty string)
8259         a[a.length - 1] = '}';
8260         return a.join("");
8261     };
8262
8263     /**
8264      * <p>Encodes a Date. This returns the actual string which is inserted into the JSON string as the literal expression.
8265      * <b>The returned value includes enclosing double quotation marks.</b></p>
8266      * <p>The default return format is "yyyy-mm-ddThh:mm:ss".</p>
8267      * <p>To override this:</p><pre><code>
8268      Ext.JSON.encodeDate = function(d) {
8269      return d.format('"Y-m-d"');
8270      };
8271      </code></pre>
8272      * @param {Date} d The Date to encode
8273      * @return {String} The string literal to use in a JSON string.
8274      */
8275     this.encodeDate = function(o) {
8276         return '"' + o.getFullYear() + "-" 
8277         + pad(o.getMonth() + 1) + "-"
8278         + pad(o.getDate()) + "T"
8279         + pad(o.getHours()) + ":"
8280         + pad(o.getMinutes()) + ":"
8281         + pad(o.getSeconds()) + '"';
8282     };
8283
8284     /**
8285      * Encodes an Object, Array or other value
8286      * @param {Mixed} o The variable to encode
8287      * @return {String} The JSON string
8288      */
8289     this.encode = function() {
8290         var ec;
8291         return function(o) {
8292             if (!ec) {
8293                 // setup encoding function on first access
8294                 ec = isNative() ? JSON.stringify : doEncode;
8295             }
8296             return ec(o);
8297         };
8298     }();
8299
8300
8301     /**
8302      * Decodes (parses) a JSON string to an object. If the JSON is invalid, this function throws a SyntaxError unless the safe option is set.
8303      * @param {String} json The JSON string
8304      * @param {Boolean} safe (optional) Whether to return null or throw an exception if the JSON is invalid.
8305      * @return {Object} The resulting object
8306      */
8307     this.decode = function() {
8308         var dc;
8309         return function(json, safe) {
8310             if (!dc) {
8311                 // setup decoding function on first access
8312                 dc = isNative() ? JSON.parse : doDecode;
8313             }
8314             try {
8315                 return dc(json);
8316             } catch (e) {
8317                 if (safe === true) {
8318                     return null;
8319                 }
8320                 Ext.Error.raise({
8321                     sourceClass: "Ext.JSON",
8322                     sourceMethod: "decode",
8323                     msg: "You're trying to decode an invalid JSON String: " + json
8324                 });
8325             }
8326         };
8327     }();
8328
8329 })();
8330 /**
8331  * Shorthand for {@link Ext.JSON#encode}
8332  * @param {Mixed} o The variable to encode
8333  * @return {String} The JSON string
8334  * @member Ext
8335  * @method encode
8336  */
8337 Ext.encode = Ext.JSON.encode;
8338 /**
8339  * Shorthand for {@link Ext.JSON#decode}
8340  * @param {String} json The JSON string
8341  * @param {Boolean} safe (optional) Whether to return null or throw an exception if the JSON is invalid.
8342  * @return {Object} The resulting object
8343  * @member Ext
8344  * @method decode
8345  */
8346 Ext.decode = Ext.JSON.decode;
8347
8348
8349 /**
8350  * @class Ext
8351
8352  The Ext namespace (global object) encapsulates all classes, singletons, and utility methods provided by Sencha's libraries.</p>
8353  Most user interface Components are at a lower level of nesting in the namespace, but many common utility functions are provided
8354  as direct properties of the Ext namespace.
8355
8356  Also many frequently used methods from other classes are provided as shortcuts within the Ext namespace.
8357  For example {@link Ext#getCmp Ext.getCmp} aliases {@link Ext.ComponentManager#get Ext.ComponentManager.get}.
8358
8359  Many applications are initiated with {@link Ext#onReady Ext.onReady} which is called once the DOM is ready.
8360  This ensures all scripts have been loaded, preventing dependency issues. For example
8361
8362      Ext.onReady(function(){
8363          new Ext.Component({
8364              renderTo: document.body,
8365              html: 'DOM ready!'
8366          });
8367      });
8368
8369 For more information about how to use the Ext classes, see
8370
8371 - <a href="http://www.sencha.com/learn/">The Learning Center</a>
8372 - <a href="http://www.sencha.com/learn/Ext_FAQ">The FAQ</a>
8373 - <a href="http://www.sencha.com/forum/">The forums</a>
8374
8375  * @singleton
8376  * @markdown
8377  */
8378 Ext.apply(Ext, {
8379     userAgent: navigator.userAgent.toLowerCase(),
8380     cache: {},
8381     idSeed: 1000,
8382     BLANK_IMAGE_URL : 'data:image/gif;base64,R0lGODlhAQABAID/AMDAwAAAACH5BAEAAAAALAAAAAABAAEAAAICRAEAOw==',
8383     isStrict: document.compatMode == "CSS1Compat",
8384     windowId: 'ext-window',
8385     documentId: 'ext-document',
8386
8387     /**
8388      * True when the document is fully initialized and ready for action
8389      * @type Boolean
8390      */
8391     isReady: false,
8392
8393     /**
8394      * True to automatically uncache orphaned Ext.core.Elements periodically (defaults to true)
8395      * @type Boolean
8396      */
8397     enableGarbageCollector: true,
8398
8399     /**
8400      * True to automatically purge event listeners during garbageCollection (defaults to true).
8401      * @type Boolean
8402      */
8403     enableListenerCollection: true,
8404
8405     /**
8406      * Generates unique ids. If the element already has an id, it is unchanged
8407      * @param {Mixed} el (optional) The element to generate an id for
8408      * @param {String} prefix (optional) Id prefix (defaults "ext-gen")
8409      * @return {String} The generated Id.
8410      */
8411     id: function(el, prefix) {
8412         var me = this,
8413             sandboxPrefix = '';
8414         el = Ext.getDom(el, true) || {};
8415         if (el === document) {
8416             el.id = me.documentId;
8417         }
8418         else if (el === window) {
8419             el.id = me.windowId;
8420         }
8421         if (!el.id) {
8422             if (me.isSandboxed) {
8423                 if (!me.uniqueGlobalNamespace) {
8424                     me.getUniqueGlobalNamespace();
8425                 }
8426                 sandboxPrefix = me.uniqueGlobalNamespace + '-';
8427             }
8428             el.id = sandboxPrefix + (prefix || "ext-gen") + (++Ext.idSeed);
8429         }
8430         return el.id;
8431     },
8432
8433     /**
8434      * Returns the current document body as an {@link Ext.core.Element}.
8435      * @return Ext.core.Element The document body
8436      */
8437     getBody: function() {
8438         return Ext.get(document.body || false);
8439     },
8440
8441     /**
8442      * Returns the current document head as an {@link Ext.core.Element}.
8443      * @return Ext.core.Element The document head
8444      * @method
8445      */
8446     getHead: function() {
8447         var head;
8448
8449         return function() {
8450             if (head == undefined) {
8451                 head = Ext.get(document.getElementsByTagName("head")[0]);
8452             }
8453
8454             return head;
8455         };
8456     }(),
8457
8458     /**
8459      * Returns the current HTML document object as an {@link Ext.core.Element}.
8460      * @return Ext.core.Element The document
8461      */
8462     getDoc: function() {
8463         return Ext.get(document);
8464     },
8465
8466     /**
8467      * This is shorthand reference to {@link Ext.ComponentManager#get}.
8468      * Looks up an existing {@link Ext.Component Component} by {@link Ext.Component#id id}
8469      * @param {String} id The component {@link Ext.Component#id id}
8470      * @return Ext.Component The Component, <tt>undefined</tt> if not found, or <tt>null</tt> if a
8471      * Class was found.
8472     */
8473     getCmp: function(id) {
8474         return Ext.ComponentManager.get(id);
8475     },
8476
8477     /**
8478      * Returns the current orientation of the mobile device
8479      * @return {String} Either 'portrait' or 'landscape'
8480      */
8481     getOrientation: function() {
8482         return window.innerHeight > window.innerWidth ? 'portrait' : 'landscape';
8483     },
8484
8485     /**
8486      * Attempts to destroy any objects passed to it by removing all event listeners, removing them from the
8487      * DOM (if applicable) and calling their destroy functions (if available).  This method is primarily
8488      * intended for arguments of type {@link Ext.core.Element} and {@link Ext.Component}, but any subclass of
8489      * {@link Ext.util.Observable} can be passed in.  Any number of elements and/or components can be
8490      * passed into this function in a single call as separate arguments.
8491      * @param {Mixed} arg1 An {@link Ext.core.Element}, {@link Ext.Component}, or an Array of either of these to destroy
8492      * @param {Mixed} arg2 (optional)
8493      * @param {Mixed} etc... (optional)
8494      */
8495     destroy: function() {
8496         var ln = arguments.length,
8497         i, arg;
8498
8499         for (i = 0; i < ln; i++) {
8500             arg = arguments[i];
8501             if (arg) {
8502                 if (Ext.isArray(arg)) {
8503                     this.destroy.apply(this, arg);
8504                 }
8505                 else if (Ext.isFunction(arg.destroy)) {
8506                     arg.destroy();
8507                 }
8508                 else if (arg.dom) {
8509                     arg.remove();
8510                 }
8511             }
8512         }
8513     },
8514
8515     /**
8516      * Execute a callback function in a particular scope. If no function is passed the call is ignored.
8517      * 
8518      * For example, these lines are equivalent:
8519      * 
8520      *     Ext.callback(myFunc, this, [arg1, arg2]);
8521      *     Ext.isFunction(myFunc) && myFunc.apply(this, [arg1, arg2]);
8522      * 
8523      * @param {Function} callback The callback to execute
8524      * @param {Object} scope (optional) The scope to execute in
8525      * @param {Array} args (optional) The arguments to pass to the function
8526      * @param {Number} delay (optional) Pass a number to delay the call by a number of milliseconds.
8527      */
8528     callback: function(callback, scope, args, delay){
8529         if(Ext.isFunction(callback)){
8530             args = args || [];
8531             scope = scope || window;
8532             if (delay) {
8533                 Ext.defer(callback, delay, scope, args);
8534             } else {
8535                 callback.apply(scope, args);
8536             }
8537         }
8538     },
8539
8540     /**
8541      * Convert certain characters (&, <, >, and ') to their HTML character equivalents for literal display in web pages.
8542      * @param {String} value The string to encode
8543      * @return {String} The encoded text
8544      */
8545     htmlEncode : function(value) {
8546         return Ext.String.htmlEncode(value);
8547     },
8548
8549     /**
8550      * Convert certain characters (&, <, >, and ') from their HTML character equivalents.
8551      * @param {String} value The string to decode
8552      * @return {String} The decoded text
8553      */
8554     htmlDecode : function(value) {
8555          return Ext.String.htmlDecode(value);
8556     },
8557
8558     /**
8559      * Appends content to the query string of a URL, handling logic for whether to place
8560      * a question mark or ampersand.
8561      * @param {String} url The URL to append to.
8562      * @param {String} s The content to append to the URL.
8563      * @return (String) The resulting URL
8564      */
8565     urlAppend : function(url, s) {
8566         if (!Ext.isEmpty(s)) {
8567             return url + (url.indexOf('?') === -1 ? '?' : '&') + s;
8568         }
8569         return url;
8570     }
8571 });
8572
8573
8574 Ext.ns = Ext.namespace;
8575
8576 // for old browsers
8577 window.undefined = window.undefined;
8578
8579 /**
8580  * @class Ext
8581  * Ext core utilities and functions.
8582  * @singleton
8583  */
8584 (function(){
8585     var check = function(regex){
8586             return regex.test(Ext.userAgent);
8587         },
8588         docMode = document.documentMode,
8589         isOpera = check(/opera/),
8590         isOpera10_5 = isOpera && check(/version\/10\.5/),
8591         isChrome = check(/\bchrome\b/),
8592         isWebKit = check(/webkit/),
8593         isSafari = !isChrome && check(/safari/),
8594         isSafari2 = isSafari && check(/applewebkit\/4/), // unique to Safari 2
8595         isSafari3 = isSafari && check(/version\/3/),
8596         isSafari4 = isSafari && check(/version\/4/),
8597         isIE = !isOpera && check(/msie/),
8598         isIE7 = isIE && (check(/msie 7/) || docMode == 7),
8599         isIE8 = isIE && (check(/msie 8/) && docMode != 7 && docMode != 9 || docMode == 8),
8600         isIE9 = isIE && (check(/msie 9/) && docMode != 7 && docMode != 8 || docMode == 9),
8601         isIE6 = isIE && check(/msie 6/),
8602         isGecko = !isWebKit && check(/gecko/),
8603         isGecko3 = isGecko && check(/rv:1\.9/),
8604         isGecko4 = isGecko && check(/rv:2\.0/),
8605         isFF3_0 = isGecko3 && check(/rv:1\.9\.0/),
8606         isFF3_5 = isGecko3 && check(/rv:1\.9\.1/),
8607         isFF3_6 = isGecko3 && check(/rv:1\.9\.2/),
8608         isWindows = check(/windows|win32/),
8609         isMac = check(/macintosh|mac os x/),
8610         isLinux = check(/linux/),
8611         scrollbarSize = null,
8612         webKitVersion = isWebKit && (/webkit\/(\d+\.\d+)/.exec(Ext.userAgent));
8613
8614     // remove css image flicker
8615     try {
8616         document.execCommand("BackgroundImageCache", false, true);
8617     } catch(e) {}
8618
8619     Ext.setVersion('extjs', '4.0.2');
8620     Ext.apply(Ext, {
8621         /**
8622          * URL to a blank file used by Ext when in secure mode for iframe src and onReady src to prevent
8623          * the IE insecure content warning (<tt>'about:blank'</tt>, except for IE in secure mode, which is <tt>'javascript:""'</tt>).
8624          * @type String
8625          */
8626         SSL_SECURE_URL : Ext.isSecure && isIE ? 'javascript:""' : 'about:blank',
8627
8628         /**
8629          * True if the {@link Ext.fx.Anim} Class is available
8630          * @type Boolean
8631          * @property enableFx
8632          */
8633
8634         /**
8635          * True to scope the reset CSS to be just applied to Ext components. Note that this wraps root containers
8636          * with an additional element. Also remember that when you turn on this option, you have to use ext-all-scoped {
8637          * unless you use the bootstrap.js to load your javascript, in which case it will be handled for you.
8638          * @type Boolean
8639          */
8640         scopeResetCSS : Ext.buildSettings.scopeResetCSS,
8641
8642         /**
8643          * EXPERIMENTAL - True to cascade listener removal to child elements when an element is removed.
8644          * Currently not optimized for performance.
8645          * @type Boolean
8646          */
8647         enableNestedListenerRemoval : false,
8648
8649         /**
8650          * Indicates whether to use native browser parsing for JSON methods.
8651          * This option is ignored if the browser does not support native JSON methods.
8652          * <b>Note: Native JSON methods will not work with objects that have functions.
8653          * Also, property names must be quoted, otherwise the data will not parse.</b> (Defaults to false)
8654          * @type Boolean
8655          */
8656         USE_NATIVE_JSON : false,
8657
8658         /**
8659          * Return the dom node for the passed String (id), dom node, or Ext.core.Element.
8660          * Optional 'strict' flag is needed for IE since it can return 'name' and
8661          * 'id' elements by using getElementById.
8662          * Here are some examples:
8663          * <pre><code>
8664 // gets dom node based on id
8665 var elDom = Ext.getDom('elId');
8666 // gets dom node based on the dom node
8667 var elDom1 = Ext.getDom(elDom);
8668
8669 // If we don&#39;t know if we are working with an
8670 // Ext.core.Element or a dom node use Ext.getDom
8671 function(el){
8672     var dom = Ext.getDom(el);
8673     // do something with the dom node
8674 }
8675          * </code></pre>
8676          * <b>Note</b>: the dom node to be found actually needs to exist (be rendered, etc)
8677          * when this method is called to be successful.
8678          * @param {Mixed} el
8679          * @return HTMLElement
8680          */
8681         getDom : function(el, strict) {
8682             if (!el || !document) {
8683                 return null;
8684             }
8685             if (el.dom) {
8686                 return el.dom;
8687             } else {
8688                 if (typeof el == 'string') {
8689                     var e = document.getElementById(el);
8690                     // IE returns elements with the 'name' and 'id' attribute.
8691                     // we do a strict check to return the element with only the id attribute
8692                     if (e && isIE && strict) {
8693                         if (el == e.getAttribute('id')) {
8694                             return e;
8695                         } else {
8696                             return null;
8697                         }
8698                     }
8699                     return e;
8700                 } else {
8701                     return el;
8702                 }
8703             }
8704         },
8705
8706         /**
8707          * Removes a DOM node from the document.
8708          * <p>Removes this element from the document, removes all DOM event listeners, and deletes the cache reference.
8709          * All DOM event listeners are removed from this element. If {@link Ext#enableNestedListenerRemoval Ext.enableNestedListenerRemoval} is
8710          * <code>true</code>, then DOM event listeners are also removed from all child nodes. The body node
8711          * will be ignored if passed in.</p>
8712          * @param {HTMLElement} node The node to remove
8713          * @method
8714          */
8715         removeNode : isIE6 || isIE7 ? function() {
8716             var d;
8717             return function(n){
8718                 if(n && n.tagName != 'BODY'){
8719                     (Ext.enableNestedListenerRemoval) ? Ext.EventManager.purgeElement(n) : Ext.EventManager.removeAll(n);
8720                     d = d || document.createElement('div');
8721                     d.appendChild(n);
8722                     d.innerHTML = '';
8723                     delete Ext.cache[n.id];
8724                 }
8725             };
8726         }() : function(n) {
8727             if (n && n.parentNode && n.tagName != 'BODY') {
8728                 (Ext.enableNestedListenerRemoval) ? Ext.EventManager.purgeElement(n) : Ext.EventManager.removeAll(n);
8729                 n.parentNode.removeChild(n);
8730                 delete Ext.cache[n.id];
8731             }
8732         },
8733
8734         /**
8735          * True if the detected browser is Opera.
8736          * @type Boolean
8737          */
8738         isOpera : isOpera,
8739
8740         /**
8741          * True if the detected browser is Opera 10.5x.
8742          * @type Boolean
8743          */
8744         isOpera10_5 : isOpera10_5,
8745
8746         /**
8747          * True if the detected browser uses WebKit.
8748          * @type Boolean
8749          */
8750         isWebKit : isWebKit,
8751
8752         /**
8753          * True if the detected browser is Chrome.
8754          * @type Boolean
8755          */
8756         isChrome : isChrome,
8757
8758         /**
8759          * True if the detected browser is Safari.
8760          * @type Boolean
8761          */
8762         isSafari : isSafari,
8763
8764         /**
8765          * True if the detected browser is Safari 3.x.
8766          * @type Boolean
8767          */
8768         isSafari3 : isSafari3,
8769
8770         /**
8771          * True if the detected browser is Safari 4.x.
8772          * @type Boolean
8773          */
8774         isSafari4 : isSafari4,
8775
8776         /**
8777          * True if the detected browser is Safari 2.x.
8778          * @type Boolean
8779          */
8780         isSafari2 : isSafari2,
8781
8782         /**
8783          * True if the detected browser is Internet Explorer.
8784          * @type Boolean
8785          */
8786         isIE : isIE,
8787
8788         /**
8789          * True if the detected browser is Internet Explorer 6.x.
8790          * @type Boolean
8791          */
8792         isIE6 : isIE6,
8793
8794         /**
8795          * True if the detected browser is Internet Explorer 7.x.
8796          * @type Boolean
8797          */
8798         isIE7 : isIE7,
8799
8800         /**
8801          * True if the detected browser is Internet Explorer 8.x.
8802          * @type Boolean
8803          */
8804         isIE8 : isIE8,
8805
8806         /**
8807          * True if the detected browser is Internet Explorer 9.x.
8808          * @type Boolean
8809          */
8810         isIE9 : isIE9,
8811
8812         /**
8813          * True if the detected browser uses the Gecko layout engine (e.g. Mozilla, Firefox).
8814          * @type Boolean
8815          */
8816         isGecko : isGecko,
8817
8818         /**
8819          * True if the detected browser uses a Gecko 1.9+ layout engine (e.g. Firefox 3.x).
8820          * @type Boolean
8821          */
8822         isGecko3 : isGecko3,
8823
8824         /**
8825          * True if the detected browser uses a Gecko 2.0+ layout engine (e.g. Firefox 4.x).
8826          * @type Boolean
8827          */
8828         isGecko4 : isGecko4,
8829
8830         /**
8831          * True if the detected browser uses FireFox 3.0
8832          * @type Boolean
8833          */
8834
8835         isFF3_0 : isFF3_0,
8836         /**
8837          * True if the detected browser uses FireFox 3.5
8838          * @type Boolean
8839          */
8840
8841         isFF3_5 : isFF3_5,
8842         /**
8843          * True if the detected browser uses FireFox 3.6
8844          * @type Boolean
8845          */
8846         isFF3_6 : isFF3_6,
8847
8848         /**
8849          * True if the detected platform is Linux.
8850          * @type Boolean
8851          */
8852         isLinux : isLinux,
8853
8854         /**
8855          * True if the detected platform is Windows.
8856          * @type Boolean
8857          */
8858         isWindows : isWindows,
8859
8860         /**
8861          * True if the detected platform is Mac OS.
8862          * @type Boolean
8863          */
8864         isMac : isMac,
8865
8866         /**
8867          * The current version of WebKit (-1 if the browser does not use WebKit).
8868          * @type Float
8869          */
8870         webKitVersion: webKitVersion ? parseFloat(webKitVersion[1]) : -1,
8871
8872         /**
8873          * URL to a 1x1 transparent gif image used by Ext to create inline icons with CSS background images.
8874          * In older versions of IE, this defaults to "http://sencha.com/s.gif" and you should change this to a URL on your server.
8875          * For other browsers it uses an inline data URL.
8876          * @type String
8877          */
8878         BLANK_IMAGE_URL : (isIE6 || isIE7) ? 'http:/' + '/www.sencha.com/s.gif' : 'data:image/gif;base64,R0lGODlhAQABAID/AMDAwAAAACH5BAEAAAAALAAAAAABAAEAAAICRAEAOw==',
8879
8880         /**
8881          * <p>Utility method for returning a default value if the passed value is empty.</p>
8882          * <p>The value is deemed to be empty if it is<div class="mdetail-params"><ul>
8883          * <li>null</li>
8884          * <li>undefined</li>
8885          * <li>an empty array</li>
8886          * <li>a zero length string (Unless the <tt>allowBlank</tt> parameter is <tt>true</tt>)</li>
8887          * </ul></div>
8888          * @param {Mixed} value The value to test
8889          * @param {Mixed} defaultValue The value to return if the original value is empty
8890          * @param {Boolean} allowBlank (optional) true to allow zero length strings to qualify as non-empty (defaults to false)
8891          * @return {Mixed} value, if non-empty, else defaultValue
8892          * @deprecated 4.0.0 Use {@link Ext#valueFrom} instead
8893          */
8894         value : function(v, defaultValue, allowBlank){
8895             return Ext.isEmpty(v, allowBlank) ? defaultValue : v;
8896         },
8897
8898         /**
8899          * Escapes the passed string for use in a regular expression
8900          * @param {String} str
8901          * @return {String}
8902          * @deprecated 4.0.0 Use {@link Ext.String#escapeRegex} instead
8903          */
8904         escapeRe : function(s) {
8905             return s.replace(/([-.*+?^${}()|[\]\/\\])/g, "\\$1");
8906         },
8907
8908         /**
8909          * Applies event listeners to elements by selectors when the document is ready.
8910          * The event name is specified with an <tt>&#64;</tt> suffix.
8911          * <pre><code>
8912 Ext.addBehaviors({
8913     // add a listener for click on all anchors in element with id foo
8914     '#foo a&#64;click' : function(e, t){
8915         // do something
8916     },
8917
8918     // add the same listener to multiple selectors (separated by comma BEFORE the &#64;)
8919     '#foo a, #bar span.some-class&#64;mouseover' : function(){
8920         // do something
8921     }
8922 });
8923          * </code></pre>
8924          * @param {Object} obj The list of behaviors to apply
8925          */
8926         addBehaviors : function(o){
8927             if(!Ext.isReady){
8928                 Ext.onReady(function(){
8929                     Ext.addBehaviors(o);
8930                 });
8931             } else {
8932                 var cache = {}, // simple cache for applying multiple behaviors to same selector does query multiple times
8933                     parts,
8934                     b,
8935                     s;
8936                 for (b in o) {
8937                     if ((parts = b.split('@'))[1]) { // for Object prototype breakers
8938                         s = parts[0];
8939                         if(!cache[s]){
8940                             cache[s] = Ext.select(s);
8941                         }
8942                         cache[s].on(parts[1], o[b]);
8943                     }
8944                 }
8945                 cache = null;
8946             }
8947         },
8948
8949         /**
8950          * Returns the size of the browser scrollbars. This can differ depending on
8951          * operating system settings, such as the theme or font size.
8952          * @param {Boolean} force (optional) true to force a recalculation of the value.
8953          * @return {Object} An object containing the width of a vertical scrollbar and the
8954          * height of a horizontal scrollbar.
8955          */
8956         getScrollbarSize: function (force) {
8957             if(!Ext.isReady){
8958                 return 0;
8959             }
8960
8961             if(force === true || scrollbarSize === null){
8962                 // BrowserBug: IE9
8963                 // When IE9 positions an element offscreen via offsets, the offsetWidth is
8964                 // inaccurately reported. For IE9 only, we render on screen before removing.
8965                 var cssClass = Ext.isIE9 ? '' : Ext.baseCSSPrefix + 'hide-offsets',
8966                     // Append our div, do our calculation and then remove it
8967                     div = Ext.getBody().createChild('<div class="' + cssClass + '" style="width:100px;height:50px;overflow:hidden;"><div style="height:200px;"></div></div>'),
8968                     child = div.child('div', true),
8969                     w1 = child.offsetWidth;
8970
8971                 div.setStyle('overflow', (Ext.isWebKit || Ext.isGecko) ? 'auto' : 'scroll');
8972
8973                 var w2 = child.offsetWidth, width = w1 - w2;
8974                 div.remove();
8975
8976                 // We assume width == height for now. TODO: is this always true?
8977                 scrollbarSize = { width: width, height: width };
8978             }
8979
8980             return scrollbarSize;
8981         },
8982
8983         /**
8984          * Utility method for getting the width of the browser's vertical scrollbar. This
8985          * can differ depending on operating system settings, such as the theme or font size.
8986          *
8987          * This method is deprected in favor of {@link #getScrollbarSize}.
8988          *
8989          * @param {Boolean} force (optional) true to force a recalculation of the value.
8990          * @return {Number} The width of a vertical scrollbar.
8991          * @deprecated
8992          */
8993         getScrollBarWidth: function(force){
8994             var size = Ext.getScrollbarSize(force);
8995             return size.width + 2; // legacy fudge factor
8996         },
8997
8998         /**
8999          * Copies a set of named properties fom the source object to the destination object.
9000          *
9001          * Example:
9002          *
9003          *     ImageComponent = Ext.extend(Ext.Component, {
9004          *         initComponent: function() {
9005          *             this.autoEl = { tag: 'img' };
9006          *             MyComponent.superclass.initComponent.apply(this, arguments);
9007          *             this.initialBox = Ext.copyTo({}, this.initialConfig, 'x,y,width,height');
9008          *         }
9009          *     });
9010          *
9011          * Important note: To borrow class prototype methods, use {@link Ext.Base#borrow} instead.
9012          *
9013          * @param {Object} dest The destination object.
9014          * @param {Object} source The source object.
9015          * @param {Array/String} names Either an Array of property names, or a comma-delimited list
9016          * of property names to copy.
9017          * @param {Boolean} usePrototypeKeys (Optional) Defaults to false. Pass true to copy keys off of the prototype as well as the instance.
9018          * @return {Object} The modified object.
9019          */
9020         copyTo : function(dest, source, names, usePrototypeKeys){
9021             if(typeof names == 'string'){
9022                 names = names.split(/[,;\s]/);
9023             }
9024             Ext.each(names, function(name){
9025                 if(usePrototypeKeys || source.hasOwnProperty(name)){
9026                     dest[name] = source[name];
9027                 }
9028             }, this);
9029             return dest;
9030         },
9031
9032         /**
9033          * Attempts to destroy and then remove a set of named properties of the passed object.
9034          * @param {Object} o The object (most likely a Component) who's properties you wish to destroy.
9035          * @param {Mixed} arg1 The name of the property to destroy and remove from the object.
9036          * @param {Mixed} etc... More property names to destroy and remove.
9037          */
9038         destroyMembers : function(o){
9039             for (var i = 1, a = arguments, len = a.length; i < len; i++) {
9040                 Ext.destroy(o[a[i]]);
9041                 delete o[a[i]];
9042             }
9043         },
9044
9045         /**
9046          * Logs a message. If a console is present it will be used. On Opera, the method
9047          * "opera.postError" is called. In other cases, the message is logged to an array
9048          * "Ext.log.out". An attached debugger can watch this array and view the log. The
9049          * log buffer is limited to a maximum of "Ext.log.max" entries (defaults to 100).
9050          *
9051          * If additional parameters are passed, they are joined and appended to the message.
9052          * 
9053          * This method does nothing in a release build.
9054          *
9055          * @param {String|Object} message The message to log or an options object with any
9056          * of the following properties:
9057          *
9058          *  - `msg`: The message to log (required).
9059          *  - `level`: One of: "error", "warn", "info" or "log" (the default is "log").
9060          *  - `dump`: An object to dump to the log as part of the message.
9061          *  - `stack`: True to include a stack trace in the log.
9062          * @markdown
9063          */
9064         log : function (message) {
9065         },
9066
9067         /**
9068          * Partitions the set into two sets: a true set and a false set.
9069          * Example:
9070          * Example2:
9071          * <pre><code>
9072 // Example 1:
9073 Ext.partition([true, false, true, true, false]); // [[true, true, true], [false, false]]
9074
9075 // Example 2:
9076 Ext.partition(
9077     Ext.query("p"),
9078     function(val){
9079         return val.className == "class1"
9080     }
9081 );
9082 // true are those paragraph elements with a className of "class1",
9083 // false set are those that do not have that className.
9084          * </code></pre>
9085          * @param {Array|NodeList} arr The array to partition
9086          * @param {Function} truth (optional) a function to determine truth.  If this is omitted the element
9087          * itself must be able to be evaluated for its truthfulness.
9088          * @return {Array} [array of truish values, array of falsy values]
9089          * @deprecated 4.0.0 Will be removed in the next major version
9090          */
9091         partition : function(arr, truth){
9092             var ret = [[],[]];
9093             Ext.each(arr, function(v, i, a) {
9094                 ret[ (truth && truth(v, i, a)) || (!truth && v) ? 0 : 1].push(v);
9095             });
9096             return ret;
9097         },
9098
9099         /**
9100          * Invokes a method on each item in an Array.
9101          * <pre><code>
9102 // Example:
9103 Ext.invoke(Ext.query("p"), "getAttribute", "id");
9104 // [el1.getAttribute("id"), el2.getAttribute("id"), ..., elN.getAttribute("id")]
9105          * </code></pre>
9106          * @param {Array|NodeList} arr The Array of items to invoke the method on.
9107          * @param {String} methodName The method name to invoke.
9108          * @param {...*} args Arguments to send into the method invocation.
9109          * @return {Array} The results of invoking the method on each item in the array.
9110          * @deprecated 4.0.0 Will be removed in the next major version
9111          */
9112         invoke : function(arr, methodName){
9113             var ret = [],
9114                 args = Array.prototype.slice.call(arguments, 2);
9115             Ext.each(arr, function(v,i) {
9116                 if (v && typeof v[methodName] == 'function') {
9117                     ret.push(v[methodName].apply(v, args));
9118                 } else {
9119                     ret.push(undefined);
9120                 }
9121             });
9122             return ret;
9123         },
9124
9125         /**
9126          * <p>Zips N sets together.</p>
9127          * <pre><code>
9128 // Example 1:
9129 Ext.zip([1,2,3],[4,5,6]); // [[1,4],[2,5],[3,6]]
9130 // Example 2:
9131 Ext.zip(
9132     [ "+", "-", "+"],
9133     [  12,  10,  22],
9134     [  43,  15,  96],
9135     function(a, b, c){
9136         return "$" + a + "" + b + "." + c
9137     }
9138 ); // ["$+12.43", "$-10.15", "$+22.96"]
9139          * </code></pre>
9140          * @param {Arrays|NodeLists} arr This argument may be repeated. Array(s) to contribute values.
9141          * @param {Function} zipper (optional) The last item in the argument list. This will drive how the items are zipped together.
9142          * @return {Array} The zipped set.
9143          * @deprecated 4.0.0 Will be removed in the next major version
9144          */
9145         zip : function(){
9146             var parts = Ext.partition(arguments, function( val ){ return typeof val != 'function'; }),
9147                 arrs = parts[0],
9148                 fn = parts[1][0],
9149                 len = Ext.max(Ext.pluck(arrs, "length")),
9150                 ret = [];
9151
9152             for (var i = 0; i < len; i++) {
9153                 ret[i] = [];
9154                 if(fn){
9155                     ret[i] = fn.apply(fn, Ext.pluck(arrs, i));
9156                 }else{
9157                     for (var j = 0, aLen = arrs.length; j < aLen; j++){
9158                         ret[i].push( arrs[j][i] );
9159                     }
9160                 }
9161             }
9162             return ret;
9163         },
9164
9165         /**
9166          * Turns an array into a sentence, joined by a specified connector - e.g.:
9167          * Ext.toSentence(['Adama', 'Tigh', 'Roslin']); //'Adama, Tigh and Roslin'
9168          * Ext.toSentence(['Adama', 'Tigh', 'Roslin'], 'or'); //'Adama, Tigh or Roslin'
9169          * @param {Array} items The array to create a sentence from
9170          * @param {String} connector The string to use to connect the last two words. Usually 'and' or 'or' - defaults to 'and'.
9171          * @return {String} The sentence string
9172          * @deprecated 4.0.0 Will be removed in the next major version
9173          */
9174         toSentence: function(items, connector) {
9175             var length = items.length;
9176
9177             if (length <= 1) {
9178                 return items[0];
9179             } else {
9180                 var head = items.slice(0, length - 1),
9181                     tail = items[length - 1];
9182
9183                 return Ext.util.Format.format("{0} {1} {2}", head.join(", "), connector || 'and', tail);
9184             }
9185         },
9186
9187         /**
9188          * By default, Ext intelligently decides whether floating elements should be shimmed. If you are using flash,
9189          * you may want to set this to true.
9190          * @type Boolean
9191          */
9192         useShims: isIE6
9193     });
9194 })();
9195
9196 /**
9197  * Loads Ext.app.Application class and starts it up with given configuration after the page is ready.
9198  *
9199  * See Ext.app.Application for details.
9200  *
9201  * @param {Object} config
9202  */
9203 Ext.application = function(config) {
9204     Ext.require('Ext.app.Application');
9205
9206     Ext.onReady(function() {
9207         Ext.create('Ext.app.Application', config);
9208     });
9209 };
9210
9211 /**
9212  * @class Ext.util.Format
9213
9214 This class is a centralized place for formatting functions inside the library. It includes
9215 functions to format various different types of data, such as text, dates and numeric values.
9216
9217 __Localization__
9218 This class contains several options for localization. These can be set once the library has loaded,
9219 all calls to the functions from that point will use the locale settings that were specified.
9220 Options include:
9221 - thousandSeparator
9222 - decimalSeparator
9223 - currenyPrecision
9224 - currencySign
9225 - currencyAtEnd
9226 This class also uses the default date format defined here: {@link Ext.Date#defaultFormat}.
9227
9228 __Using with renderers__
9229 There are two helper functions that return a new function that can be used in conjunction with 
9230 grid renderers:
9231
9232     columns: [{
9233         dataIndex: 'date',
9234         renderer: Ext.util.Format.dateRenderer('Y-m-d')
9235     }, {
9236         dataIndex: 'time',
9237         renderer: Ext.util.Format.numberRenderer('0.000')
9238     }]
9239     
9240 Functions that only take a single argument can also be passed directly:
9241     columns: [{
9242         dataIndex: 'cost',
9243         renderer: Ext.util.Format.usMoney
9244     }, {
9245         dataIndex: 'productCode',
9246         renderer: Ext.util.Format.uppercase
9247     }]
9248     
9249 __Using with XTemplates__
9250 XTemplates can also directly use Ext.util.Format functions:
9251
9252     new Ext.XTemplate([
9253         'Date: {startDate:date("Y-m-d")}',
9254         'Cost: {cost:usMoney}'
9255     ]);
9256
9257  * @markdown
9258  * @singleton
9259  */
9260 (function() {
9261     Ext.ns('Ext.util');
9262
9263     Ext.util.Format = {};
9264     var UtilFormat     = Ext.util.Format,
9265         stripTagsRE    = /<\/?[^>]+>/gi,
9266         stripScriptsRe = /(?:<script.*?>)((\n|\r|.)*?)(?:<\/script>)/ig,
9267         nl2brRe        = /\r?\n/g,
9268
9269         // A RegExp to remove from a number format string, all characters except digits and '.'
9270         formatCleanRe  = /[^\d\.]/g,
9271
9272         // A RegExp to remove from a number format string, all characters except digits and the local decimal separator.
9273         // Created on first use. The local decimal separator character must be initialized for this to be created.
9274         I18NFormatCleanRe;
9275
9276     Ext.apply(UtilFormat, {
9277         /**
9278          * @type String
9279          * @property thousandSeparator
9280          * <p>The character that the {@link #number} function uses as a thousand separator.</p>
9281          * <p>This defaults to <code>,</code>, but may be overridden in a locale file.</p>
9282          */
9283         thousandSeparator: ',',
9284
9285         /**
9286          * @type String
9287          * @property decimalSeparator
9288          * <p>The character that the {@link #number} function uses as a decimal point.</p>
9289          * <p>This defaults to <code>.</code>, but may be overridden in a locale file.</p>
9290          */
9291         decimalSeparator: '.',
9292
9293         /**
9294          * @type Number
9295          * @property currencyPrecision
9296          * <p>The number of decimal places that the {@link #currency} function displays.</p>
9297          * <p>This defaults to <code>2</code>, but may be overridden in a locale file.</p>
9298          */
9299         currencyPrecision: 2,
9300
9301         /**
9302          * @type String
9303          * @property currencySign
9304          * <p>The currency sign that the {@link #currency} function displays.</p>
9305          * <p>This defaults to <code>$</code>, but may be overridden in a locale file.</p>
9306          */
9307         currencySign: '$',
9308
9309         /**
9310          * @type Boolean
9311          * @property currencyAtEnd
9312          * <p>This may be set to <code>true</code> to make the {@link #currency} function
9313          * append the currency sign to the formatted value.</p>
9314          * <p>This defaults to <code>false</code>, but may be overridden in a locale file.</p>
9315          */
9316         currencyAtEnd: false,
9317
9318         /**
9319          * Checks a reference and converts it to empty string if it is undefined
9320          * @param {Mixed} value Reference to check
9321          * @return {Mixed} Empty string if converted, otherwise the original value
9322          */
9323         undef : function(value) {
9324             return value !== undefined ? value : "";
9325         },
9326
9327         /**
9328          * Checks a reference and converts it to the default value if it's empty
9329          * @param {Mixed} value Reference to check
9330          * @param {String} defaultValue The value to insert of it's undefined (defaults to "")
9331          * @return {String}
9332          */
9333         defaultValue : function(value, defaultValue) {
9334             return value !== undefined && value !== '' ? value : defaultValue;
9335         },
9336
9337         /**
9338          * Returns a substring from within an original string
9339          * @param {String} value The original text
9340          * @param {Number} start The start index of the substring
9341          * @param {Number} length The length of the substring
9342          * @return {String} The substring
9343          */
9344         substr : function(value, start, length) {
9345             return String(value).substr(start, length);
9346         },
9347
9348         /**
9349          * Converts a string to all lower case letters
9350          * @param {String} value The text to convert
9351          * @return {String} The converted text
9352          */
9353         lowercase : function(value) {
9354             return String(value).toLowerCase();
9355         },
9356
9357         /**
9358          * Converts a string to all upper case letters
9359          * @param {String} value The text to convert
9360          * @return {String} The converted text
9361          */
9362         uppercase : function(value) {
9363             return String(value).toUpperCase();
9364         },
9365
9366         /**
9367          * Format a number as US currency
9368          * @param {Number/String} value The numeric value to format
9369          * @return {String} The formatted currency string
9370          */
9371         usMoney : function(v) {
9372             return UtilFormat.currency(v, '$', 2);
9373         },
9374
9375         /**
9376          * Format a number as a currency
9377          * @param {Number/String} value The numeric value to format
9378          * @param {String} sign The currency sign to use (defaults to {@link #currencySign})
9379          * @param {Number} decimals The number of decimals to use for the currency (defaults to {@link #currencyPrecision})
9380          * @param {Boolean} end True if the currency sign should be at the end of the string (defaults to {@link #currencyAtEnd})
9381          * @return {String} The formatted currency string
9382          */
9383         currency: function(v, currencySign, decimals, end) {
9384             var negativeSign = '',
9385                 format = ",0",
9386                 i = 0;
9387             v = v - 0;
9388             if (v < 0) {
9389                 v = -v;
9390                 negativeSign = '-';
9391             }
9392             decimals = decimals || UtilFormat.currencyPrecision;
9393             format += format + (decimals > 0 ? '.' : '');
9394             for (; i < decimals; i++) {
9395                 format += '0';
9396             }
9397             v = UtilFormat.number(v, format); 
9398             if ((end || UtilFormat.currencyAtEnd) === true) {
9399                 return Ext.String.format("{0}{1}{2}", negativeSign, v, currencySign || UtilFormat.currencySign);
9400             } else {
9401                 return Ext.String.format("{0}{1}{2}", negativeSign, currencySign || UtilFormat.currencySign, v);
9402             }
9403         },
9404
9405         /**
9406          * Formats the passed date using the specified format pattern.
9407          * @param {String/Date} value The value to format. If a string is passed, it is converted to a Date by the Javascript
9408          * Date object's <a href="http://www.w3schools.com/jsref/jsref_parse.asp">parse()</a> method.
9409          * @param {String} format (Optional) Any valid date format string. Defaults to {@link Ext.Date#defaultFormat}.
9410          * @return {String} The formatted date string.
9411          */
9412         date: function(v, format) {
9413             if (!v) {
9414                 return "";
9415             }
9416             if (!Ext.isDate(v)) {
9417                 v = new Date(Date.parse(v));
9418             }
9419             return Ext.Date.dateFormat(v, format || Ext.Date.defaultFormat);
9420         },
9421
9422         /**
9423          * Returns a date rendering function that can be reused to apply a date format multiple times efficiently
9424          * @param {String} format Any valid date format string. Defaults to {@link Ext.Date#defaultFormat}.
9425          * @return {Function} The date formatting function
9426          */
9427         dateRenderer : function(format) {
9428             return function(v) {
9429                 return UtilFormat.date(v, format);
9430             };
9431         },
9432
9433         /**
9434          * Strips all HTML tags
9435          * @param {Mixed} value The text from which to strip tags
9436          * @return {String} The stripped text
9437          */
9438         stripTags : function(v) {
9439             return !v ? v : String(v).replace(stripTagsRE, "");
9440         },
9441
9442         /**
9443          * Strips all script tags
9444          * @param {Mixed} value The text from which to strip script tags
9445          * @return {String} The stripped text
9446          */
9447         stripScripts : function(v) {
9448             return !v ? v : String(v).replace(stripScriptsRe, "");
9449         },
9450
9451         /**
9452          * Simple format for a file size (xxx bytes, xxx KB, xxx MB)
9453          * @param {Number/String} size The numeric value to format
9454          * @return {String} The formatted file size
9455          */
9456         fileSize : function(size) {
9457             if (size < 1024) {
9458                 return size + " bytes";
9459             } else if (size < 1048576) {
9460                 return (Math.round(((size*10) / 1024))/10) + " KB";
9461             } else {
9462                 return (Math.round(((size*10) / 1048576))/10) + " MB";
9463             }
9464         },
9465
9466         /**
9467          * It does simple math for use in a template, for example:<pre><code>
9468          * var tpl = new Ext.Template('{value} * 10 = {value:math("* 10")}');
9469          * </code></pre>
9470          * @return {Function} A function that operates on the passed value.
9471          * @method
9472          */
9473         math : function(){
9474             var fns = {};
9475
9476             return function(v, a){
9477                 if (!fns[a]) {
9478                     fns[a] = Ext.functionFactory('v', 'return v ' + a + ';');
9479                 }
9480                 return fns[a](v);
9481             };
9482         }(),
9483
9484         /**
9485          * Rounds the passed number to the required decimal precision.
9486          * @param {Number/String} value The numeric value to round.
9487          * @param {Number} precision The number of decimal places to which to round the first parameter's value.
9488          * @return {Number} The rounded value.
9489          */
9490         round : function(value, precision) {
9491             var result = Number(value);
9492             if (typeof precision == 'number') {
9493                 precision = Math.pow(10, precision);
9494                 result = Math.round(value * precision) / precision;
9495             }
9496             return result;
9497         },
9498
9499         /**
9500          * <p>Formats the passed number according to the passed format string.</p>
9501          * <p>The number of digits after the decimal separator character specifies the number of
9502          * decimal places in the resulting string. The <u>local-specific</u> decimal character is used in the result.</p>
9503          * <p>The <i>presence</i> of a thousand separator character in the format string specifies that
9504          * the <u>locale-specific</u> thousand separator (if any) is inserted separating thousand groups.</p>
9505          * <p>By default, "," is expected as the thousand separator, and "." is expected as the decimal separator.</p>
9506          * <p><b>New to Ext4</b></p>
9507          * <p>Locale-specific characters are always used in the formatted output when inserting
9508          * thousand and decimal separators.</p>
9509          * <p>The format string must specify separator characters according to US/UK conventions ("," as the
9510          * thousand separator, and "." as the decimal separator)</p>
9511          * <p>To allow specification of format strings according to local conventions for separator characters, add
9512          * the string <code>/i</code> to the end of the format string.</p>
9513          * <div style="margin-left:40px">examples (123456.789):
9514          * <div style="margin-left:10px">
9515          * 0 - (123456) show only digits, no precision<br>
9516          * 0.00 - (123456.78) show only digits, 2 precision<br>
9517          * 0.0000 - (123456.7890) show only digits, 4 precision<br>
9518          * 0,000 - (123,456) show comma and digits, no precision<br>
9519          * 0,000.00 - (123,456.78) show comma and digits, 2 precision<br>
9520          * 0,0.00 - (123,456.78) shortcut method, show comma and digits, 2 precision<br>
9521          * To allow specification of the formatting string using UK/US grouping characters (,) and decimal (.) for international numbers, add /i to the end.
9522          * For example: 0.000,00/i
9523          * </div></div>
9524          * @param {Number} v The number to format.
9525          * @param {String} format The way you would like to format this text.
9526          * @return {String} The formatted number.
9527          */
9528         number: function(v, formatString) {
9529             if (!formatString) {
9530                 return v;
9531             }
9532             v = Ext.Number.from(v, NaN);
9533             if (isNaN(v)) {
9534                 return '';
9535             }
9536             var comma = UtilFormat.thousandSeparator,
9537                 dec   = UtilFormat.decimalSeparator,
9538                 i18n  = false,
9539                 neg   = v < 0,
9540                 hasComma,
9541                 psplit;
9542
9543             v = Math.abs(v);
9544
9545             // The "/i" suffix allows caller to use a locale-specific formatting string.
9546             // Clean the format string by removing all but numerals and the decimal separator.
9547             // Then split the format string into pre and post decimal segments according to *what* the
9548             // decimal separator is. If they are specifying "/i", they are using the local convention in the format string.
9549             if (formatString.substr(formatString.length - 2) == '/i') {
9550                 if (!I18NFormatCleanRe) {
9551                     I18NFormatCleanRe = new RegExp('[^\\d\\' + UtilFormat.decimalSeparator + ']','g');
9552                 }
9553                 formatString = formatString.substr(0, formatString.length - 2);
9554                 i18n   = true;
9555                 hasComma = formatString.indexOf(comma) != -1;
9556                 psplit = formatString.replace(I18NFormatCleanRe, '').split(dec);
9557             } else {
9558                 hasComma = formatString.indexOf(',') != -1;
9559                 psplit = formatString.replace(formatCleanRe, '').split('.');
9560             }
9561
9562             if (1 < psplit.length) {
9563                 v = v.toFixed(psplit[1].length);
9564             } else if(2 < psplit.length) {
9565             } else {
9566                 v = v.toFixed(0);
9567             }
9568
9569             var fnum = v.toString();
9570
9571             psplit = fnum.split('.');
9572
9573             if (hasComma) {
9574                 var cnum = psplit[0],
9575                     parr = [],
9576                     j    = cnum.length,
9577                     m    = Math.floor(j / 3),
9578                     n    = cnum.length % 3 || 3,
9579                     i;
9580
9581                 for (i = 0; i < j; i += n) {
9582                     if (i !== 0) {
9583                         n = 3;
9584                     }
9585
9586                     parr[parr.length] = cnum.substr(i, n);
9587                     m -= 1;
9588                 }
9589                 fnum = parr.join(comma);
9590                 if (psplit[1]) {
9591                     fnum += dec + psplit[1];
9592                 }
9593             } else {
9594                 if (psplit[1]) {
9595                     fnum = psplit[0] + dec + psplit[1];
9596                 }
9597             }
9598             
9599             if (neg) {
9600                 /*
9601                  * Edge case. If we have a very small negative number it will get rounded to 0,
9602                  * however the initial check at the top will still report as negative. Replace
9603                  * everything but 1-9 and check if the string is empty to determine a 0 value.
9604                  */
9605                 neg = fnum.replace(/[^1-9]/g, '') !== '';
9606             }
9607
9608             return (neg ? '-' : '') + formatString.replace(/[\d,?\.?]+/, fnum);
9609         },
9610
9611         /**
9612          * Returns a number rendering function that can be reused to apply a number format multiple times efficiently
9613          * @param {String} format Any valid number format string for {@link #number}
9614          * @return {Function} The number formatting function
9615          */
9616         numberRenderer : function(format) {
9617             return function(v) {
9618                 return UtilFormat.number(v, format);
9619             };
9620         },
9621
9622         /**
9623          * Selectively do a plural form of a word based on a numeric value. For example, in a template,
9624          * {commentCount:plural("Comment")}  would result in "1 Comment" if commentCount was 1 or would be "x Comments"
9625          * if the value is 0 or greater than 1.
9626          * @param {Number} value The value to compare against
9627          * @param {String} singular The singular form of the word
9628          * @param {String} plural (optional) The plural form of the word (defaults to the singular with an "s")
9629          */
9630         plural : function(v, s, p) {
9631             return v +' ' + (v == 1 ? s : (p ? p : s+'s'));
9632         },
9633
9634         /**
9635          * Converts newline characters to the HTML tag &lt;br/>
9636          * @param {String} The string value to format.
9637          * @return {String} The string with embedded &lt;br/> tags in place of newlines.
9638          */
9639         nl2br : function(v) {
9640             return Ext.isEmpty(v) ? '' : v.replace(nl2brRe, '<br/>');
9641         },
9642
9643         /**
9644          * Capitalize the given string. See {@link Ext.String#capitalize}.
9645          * @method
9646          */
9647         capitalize: Ext.String.capitalize,
9648
9649         /**
9650          * Truncate a string and add an ellipsis ('...') to the end if it exceeds the specified length.
9651          * See {@link Ext.String#ellipsis}.
9652          * @method
9653          */
9654         ellipsis: Ext.String.ellipsis,
9655
9656         /**
9657          * Formats to a string. See {@link Ext.String#format}
9658          * @method
9659          */
9660         format: Ext.String.format,
9661
9662         /**
9663          * Convert certain characters (&, <, >, and ') from their HTML character equivalents.
9664          * See {@link Ext.String#htmlDecode}.
9665          * @method
9666          */
9667         htmlDecode: Ext.String.htmlDecode,
9668
9669         /**
9670          * Convert certain characters (&, <, >, and ') to their HTML character equivalents for literal display in web pages.
9671          * See {@link Ext.String#htmlEncode}.
9672          * @method
9673          */
9674         htmlEncode: Ext.String.htmlEncode,
9675
9676         /**
9677          * Adds left padding to a string. See {@link Ext.String#leftPad}
9678          * @method
9679          */
9680         leftPad: Ext.String.leftPad,
9681
9682         /**
9683          * Trims any whitespace from either side of a string. See {@link Ext.String#trim}.
9684          * @method
9685          */
9686         trim : Ext.String.trim,
9687
9688         /**
9689          * Parses a number or string representing margin sizes into an object. Supports CSS-style margin declarations
9690          * (e.g. 10, "10", "10 10", "10 10 10" and "10 10 10 10" are all valid options and would return the same result)
9691          * @param {Number|String} v The encoded margins
9692          * @return {Object} An object with margin sizes for top, right, bottom and left
9693          */
9694         parseBox : function(box) {
9695             if (Ext.isNumber(box)) {
9696                 box = box.toString();
9697             }
9698             var parts  = box.split(' '),
9699                 ln = parts.length;
9700
9701             if (ln == 1) {
9702                 parts[1] = parts[2] = parts[3] = parts[0];
9703             }
9704             else if (ln == 2) {
9705                 parts[2] = parts[0];
9706                 parts[3] = parts[1];
9707             }
9708             else if (ln == 3) {
9709                 parts[3] = parts[1];
9710             }
9711
9712             return {
9713                 top   :parseInt(parts[0], 10) || 0,
9714                 right :parseInt(parts[1], 10) || 0,
9715                 bottom:parseInt(parts[2], 10) || 0,
9716                 left  :parseInt(parts[3], 10) || 0
9717             };
9718         },
9719
9720         /**
9721          * Escapes the passed string for use in a regular expression
9722          * @param {String} str
9723          * @return {String}
9724          */
9725         escapeRegex : function(s) {
9726             return s.replace(/([\-.*+?\^${}()|\[\]\/\\])/g, "\\$1");
9727         }
9728     });
9729 })();
9730
9731 /**
9732  * @class Ext.util.TaskRunner
9733  * Provides the ability to execute one or more arbitrary tasks in a multithreaded
9734  * manner.  Generally, you can use the singleton {@link Ext.TaskManager} instead, but
9735  * if needed, you can create separate instances of TaskRunner.  Any number of
9736  * separate tasks can be started at any time and will run independently of each
9737  * other. Example usage:
9738  * <pre><code>
9739 // Start a simple clock task that updates a div once per second
9740 var updateClock = function(){
9741     Ext.fly('clock').update(new Date().format('g:i:s A'));
9742
9743 var task = {
9744     run: updateClock,
9745     interval: 1000 //1 second
9746 }
9747 var runner = new Ext.util.TaskRunner();
9748 runner.start(task);
9749
9750 // equivalent using TaskManager
9751 Ext.TaskManager.start({
9752     run: updateClock,
9753     interval: 1000
9754 });
9755
9756  * </code></pre>
9757  * <p>See the {@link #start} method for details about how to configure a task object.</p>
9758  * Also see {@link Ext.util.DelayedTask}. 
9759  * 
9760  * @constructor
9761  * @param {Number} interval (optional) The minimum precision in milliseconds supported by this TaskRunner instance
9762  * (defaults to 10)
9763  */
9764 Ext.ns('Ext.util');
9765
9766 Ext.util.TaskRunner = function(interval) {
9767     interval = interval || 10;
9768     var tasks = [],
9769     removeQueue = [],
9770     id = 0,
9771     running = false,
9772
9773     // private
9774     stopThread = function() {
9775         running = false;
9776         clearInterval(id);
9777         id = 0;
9778     },
9779
9780     // private
9781     startThread = function() {
9782         if (!running) {
9783             running = true;
9784             id = setInterval(runTasks, interval);
9785         }
9786     },
9787
9788     // private
9789     removeTask = function(t) {
9790         removeQueue.push(t);
9791         if (t.onStop) {
9792             t.onStop.apply(t.scope || t);
9793         }
9794     },
9795
9796     // private
9797     runTasks = function() {
9798         var rqLen = removeQueue.length,
9799             now = new Date().getTime(),
9800             i;
9801
9802         if (rqLen > 0) {
9803             for (i = 0; i < rqLen; i++) {
9804                 Ext.Array.remove(tasks, removeQueue[i]);
9805             }
9806             removeQueue = [];
9807             if (tasks.length < 1) {
9808                 stopThread();
9809                 return;
9810             }
9811         }
9812         i = 0;
9813         var t,
9814             itime,
9815             rt,
9816             len = tasks.length;
9817         for (; i < len; ++i) {
9818             t = tasks[i];
9819             itime = now - t.taskRunTime;
9820             if (t.interval <= itime) {
9821                 rt = t.run.apply(t.scope || t, t.args || [++t.taskRunCount]);
9822                 t.taskRunTime = now;
9823                 if (rt === false || t.taskRunCount === t.repeat) {
9824                     removeTask(t);
9825                     return;
9826                 }
9827             }
9828             if (t.duration && t.duration <= (now - t.taskStartTime)) {
9829                 removeTask(t);
9830             }
9831         }
9832     };
9833
9834     /**
9835      * Starts a new task.
9836      * @method start
9837      * @param {Object} task <p>A config object that supports the following properties:<ul>
9838      * <li><code>run</code> : Function<div class="sub-desc"><p>The function to execute each time the task is invoked. The
9839      * function will be called at each interval and passed the <code>args</code> argument if specified, and the
9840      * current invocation count if not.</p>
9841      * <p>If a particular scope (<code>this</code> reference) is required, be sure to specify it using the <code>scope</code> argument.</p>
9842      * <p>Return <code>false</code> from this function to terminate the task.</p></div></li>
9843      * <li><code>interval</code> : Number<div class="sub-desc">The frequency in milliseconds with which the task
9844      * should be invoked.</div></li>
9845      * <li><code>args</code> : Array<div class="sub-desc">(optional) An array of arguments to be passed to the function
9846      * specified by <code>run</code>. If not specified, the current invocation count is passed.</div></li>
9847      * <li><code>scope</code> : Object<div class="sub-desc">(optional) The scope (<tt>this</tt> reference) in which to execute the
9848      * <code>run</code> function. Defaults to the task config object.</div></li>
9849      * <li><code>duration</code> : Number<div class="sub-desc">(optional) The length of time in milliseconds to invoke
9850      * the task before stopping automatically (defaults to indefinite).</div></li>
9851      * <li><code>repeat</code> : Number<div class="sub-desc">(optional) The number of times to invoke the task before
9852      * stopping automatically (defaults to indefinite).</div></li>
9853      * </ul></p>
9854      * <p>Before each invocation, Ext injects the property <code>taskRunCount</code> into the task object so
9855      * that calculations based on the repeat count can be performed.</p>
9856      * @return {Object} The task
9857      */
9858     this.start = function(task) {
9859         tasks.push(task);
9860         task.taskStartTime = new Date().getTime();
9861         task.taskRunTime = 0;
9862         task.taskRunCount = 0;
9863         startThread();
9864         return task;
9865     };
9866
9867     /**
9868      * Stops an existing running task.
9869      * @method stop
9870      * @param {Object} task The task to stop
9871      * @return {Object} The task
9872      */
9873     this.stop = function(task) {
9874         removeTask(task);
9875         return task;
9876     };
9877
9878     /**
9879      * Stops all tasks that are currently running.
9880      * @method stopAll
9881      */
9882     this.stopAll = function() {
9883         stopThread();
9884         for (var i = 0, len = tasks.length; i < len; i++) {
9885             if (tasks[i].onStop) {
9886                 tasks[i].onStop();
9887             }
9888         }
9889         tasks = [];
9890         removeQueue = [];
9891     };
9892 };
9893
9894 /**
9895  * @class Ext.TaskManager
9896  * @extends Ext.util.TaskRunner
9897  * A static {@link Ext.util.TaskRunner} instance that can be used to start and stop arbitrary tasks.  See
9898  * {@link Ext.util.TaskRunner} for supported methods and task config properties.
9899  * <pre><code>
9900 // Start a simple clock task that updates a div once per second
9901 var task = {
9902     run: function(){
9903         Ext.fly('clock').update(new Date().format('g:i:s A'));
9904     },
9905     interval: 1000 //1 second
9906 }
9907 Ext.TaskManager.start(task);
9908 </code></pre>
9909  * <p>See the {@link #start} method for details about how to configure a task object.</p>
9910  * @singleton
9911  */
9912 Ext.TaskManager = Ext.create('Ext.util.TaskRunner');
9913 /**
9914  * @class Ext.is
9915  * 
9916  * Determines information about the current platform the application is running on.
9917  * 
9918  * @singleton
9919  */
9920 Ext.is = {
9921     init : function(navigator) {
9922         var platforms = this.platforms,
9923             ln = platforms.length,
9924             i, platform;
9925
9926         navigator = navigator || window.navigator;
9927
9928         for (i = 0; i < ln; i++) {
9929             platform = platforms[i];
9930             this[platform.identity] = platform.regex.test(navigator[platform.property]);
9931         }
9932
9933         /**
9934          * @property Desktop True if the browser is running on a desktop machine
9935          * @type {Boolean}
9936          */
9937         this.Desktop = this.Mac || this.Windows || (this.Linux && !this.Android);
9938         /**
9939          * @property Tablet True if the browser is running on a tablet (iPad)
9940          */
9941         this.Tablet = this.iPad;
9942         /**
9943          * @property Phone True if the browser is running on a phone.
9944          * @type {Boolean}
9945          */
9946         this.Phone = !this.Desktop && !this.Tablet;
9947         /**
9948          * @property iOS True if the browser is running on iOS
9949          * @type {Boolean}
9950          */
9951         this.iOS = this.iPhone || this.iPad || this.iPod;
9952         
9953         /**
9954          * @property Standalone Detects when application has been saved to homescreen.
9955          * @type {Boolean}
9956          */
9957         this.Standalone = !!window.navigator.standalone;
9958     },
9959     
9960     /**
9961      * @property iPhone True when the browser is running on a iPhone
9962      * @type {Boolean}
9963      */
9964     platforms: [{
9965         property: 'platform',
9966         regex: /iPhone/i,
9967         identity: 'iPhone'
9968     },
9969     
9970     /**
9971      * @property iPod True when the browser is running on a iPod
9972      * @type {Boolean}
9973      */
9974     {
9975         property: 'platform',
9976         regex: /iPod/i,
9977         identity: 'iPod'
9978     },
9979     
9980     /**
9981      * @property iPad True when the browser is running on a iPad
9982      * @type {Boolean}
9983      */
9984     {
9985         property: 'userAgent',
9986         regex: /iPad/i,
9987         identity: 'iPad'
9988     },
9989     
9990     /**
9991      * @property Blackberry True when the browser is running on a Blackberry
9992      * @type {Boolean}
9993      */
9994     {
9995         property: 'userAgent',
9996         regex: /Blackberry/i,
9997         identity: 'Blackberry'
9998     },
9999     
10000     /**
10001      * @property Android True when the browser is running on an Android device
10002      * @type {Boolean}
10003      */
10004     {
10005         property: 'userAgent',
10006         regex: /Android/i,
10007         identity: 'Android'
10008     },
10009     
10010     /**
10011      * @property Mac True when the browser is running on a Mac
10012      * @type {Boolean}
10013      */
10014     {
10015         property: 'platform',
10016         regex: /Mac/i,
10017         identity: 'Mac'
10018     },
10019     
10020     /**
10021      * @property Windows True when the browser is running on Windows
10022      * @type {Boolean}
10023      */
10024     {
10025         property: 'platform',
10026         regex: /Win/i,
10027         identity: 'Windows'
10028     },
10029     
10030     /**
10031      * @property Linux True when the browser is running on Linux
10032      * @type {Boolean}
10033      */
10034     {
10035         property: 'platform',
10036         regex: /Linux/i,
10037         identity: 'Linux'
10038     }]
10039 };
10040
10041 Ext.is.init();
10042
10043 /**
10044  * @class Ext.supports
10045  *
10046  * Determines information about features are supported in the current environment
10047  * 
10048  * @singleton
10049  */
10050 Ext.supports = {
10051     init : function() {
10052         var doc = document,
10053             div = doc.createElement('div'),
10054             tests = this.tests,
10055             ln = tests.length,
10056             i, test;
10057
10058         div.innerHTML = [
10059             '<div style="height:30px;width:50px;">',
10060                 '<div style="height:20px;width:20px;"></div>',
10061             '</div>',
10062             '<div style="width: 200px; height: 200px; position: relative; padding: 5px;">',
10063                 '<div style="position: absolute; top: 0; left: 0; width: 100%; height: 100%;"></div>',
10064             '</div>',
10065             '<div style="float:left; background-color:transparent;"></div>'
10066         ].join('');
10067
10068         doc.body.appendChild(div);
10069
10070         for (i = 0; i < ln; i++) {
10071             test = tests[i];
10072             this[test.identity] = test.fn.call(this, doc, div);
10073         }
10074
10075         doc.body.removeChild(div);
10076     },
10077
10078     /**
10079      * @property CSS3BoxShadow True if document environment supports the CSS3 box-shadow style.
10080      * @type {Boolean}
10081      */
10082     CSS3BoxShadow: Ext.isDefined(document.documentElement.style.boxShadow),
10083
10084     /**
10085      * @property ClassList True if document environment supports the HTML5 classList API.
10086      * @type {Boolean}
10087      */
10088     ClassList: !!document.documentElement.classList,
10089
10090     /**
10091      * @property OrientationChange True if the device supports orientation change
10092      * @type {Boolean}
10093      */
10094     OrientationChange: ((typeof window.orientation != 'undefined') && ('onorientationchange' in window)),
10095     
10096     /**
10097      * @property DeviceMotion True if the device supports device motion (acceleration and rotation rate)
10098      * @type {Boolean}
10099      */
10100     DeviceMotion: ('ondevicemotion' in window),
10101     
10102     /**
10103      * @property Touch True if the device supports touch
10104      * @type {Boolean}
10105      */
10106     // is.Desktop is needed due to the bug in Chrome 5.0.375, Safari 3.1.2
10107     // and Safari 4.0 (they all have 'ontouchstart' in the window object).
10108     Touch: ('ontouchstart' in window) && (!Ext.is.Desktop),
10109
10110     tests: [
10111         /**
10112          * @property Transitions True if the device supports CSS3 Transitions
10113          * @type {Boolean}
10114          */
10115         {
10116             identity: 'Transitions',
10117             fn: function(doc, div) {
10118                 var prefix = [
10119                         'webkit',
10120                         'Moz',
10121                         'o',
10122                         'ms',
10123                         'khtml'
10124                     ],
10125                     TE = 'TransitionEnd',
10126                     transitionEndName = [
10127                         prefix[0] + TE,
10128                         'transitionend', //Moz bucks the prefixing convention
10129                         prefix[2] + TE,
10130                         prefix[3] + TE,
10131                         prefix[4] + TE
10132                     ],
10133                     ln = prefix.length,
10134                     i = 0,
10135                     out = false;
10136                 div = Ext.get(div);
10137                 for (; i < ln; i++) {
10138                     if (div.getStyle(prefix[i] + "TransitionProperty")) {
10139                         Ext.supports.CSS3Prefix = prefix[i];
10140                         Ext.supports.CSS3TransitionEnd = transitionEndName[i];
10141                         out = true;
10142                         break;
10143                     }
10144                 }
10145                 return out;
10146             }
10147         },
10148         
10149         /**
10150          * @property RightMargin True if the device supports right margin.
10151          * See https://bugs.webkit.org/show_bug.cgi?id=13343 for why this is needed.
10152          * @type {Boolean}
10153          */
10154         {
10155             identity: 'RightMargin',
10156             fn: function(doc, div) {
10157                 var view = doc.defaultView;
10158                 return !(view && view.getComputedStyle(div.firstChild.firstChild, null).marginRight != '0px');
10159             }
10160         },
10161
10162         /**
10163          * @property DisplayChangeInputSelectionBug True if INPUT elements lose their
10164          * selection when their display style is changed. Essentially, if a text input
10165          * has focus and its display style is changed, the I-beam disappears.
10166          * 
10167          * This bug is encountered due to the work around in place for the {@link #RightMargin}
10168          * bug. This has been observed in Safari 4.0.4 and older, and appears to be fixed
10169          * in Safari 5. It's not clear if Safari 4.1 has the bug, but it has the same WebKit
10170          * version number as Safari 5 (according to http://unixpapa.com/js/gecko.html).
10171          */
10172         {
10173             identity: 'DisplayChangeInputSelectionBug',
10174             fn: function() {
10175                 var webKitVersion = Ext.webKitVersion;
10176                 // WebKit but older than Safari 5 or Chrome 6:
10177                 return 0 < webKitVersion && webKitVersion < 533;
10178             }
10179         },
10180
10181         /**
10182          * @property DisplayChangeTextAreaSelectionBug True if TEXTAREA elements lose their
10183          * selection when their display style is changed. Essentially, if a text area has
10184          * focus and its display style is changed, the I-beam disappears.
10185          *
10186          * This bug is encountered due to the work around in place for the {@link #RightMargin}
10187          * bug. This has been observed in Chrome 10 and Safari 5 and older, and appears to
10188          * be fixed in Chrome 11.
10189          */
10190         {
10191             identity: 'DisplayChangeTextAreaSelectionBug',
10192             fn: function() {
10193                 var webKitVersion = Ext.webKitVersion;
10194
10195                 /*
10196                 Has bug w/textarea:
10197
10198                 (Chrome) Mozilla/5.0 (Macintosh; U; Intel Mac OS X 10_6_7; en-US)
10199                             AppleWebKit/534.16 (KHTML, like Gecko) Chrome/10.0.648.127
10200                             Safari/534.16
10201                 (Safari) Mozilla/5.0 (Macintosh; U; Intel Mac OS X 10_6_7; en-us)
10202                             AppleWebKit/533.21.1 (KHTML, like Gecko) Version/5.0.5
10203                             Safari/533.21.1
10204
10205                 No bug:
10206
10207                 (Chrome) Mozilla/5.0 (Macintosh; Intel Mac OS X 10_6_7)
10208                             AppleWebKit/534.24 (KHTML, like Gecko) Chrome/11.0.696.57
10209                             Safari/534.24
10210                 */
10211                 return 0 < webKitVersion && webKitVersion < 534.24;
10212             }
10213         },
10214
10215         /**
10216          * @property TransparentColor True if the device supports transparent color
10217          * @type {Boolean}
10218          */
10219         {
10220             identity: 'TransparentColor',
10221             fn: function(doc, div, view) {
10222                 view = doc.defaultView;
10223                 return !(view && view.getComputedStyle(div.lastChild, null).backgroundColor != 'transparent');
10224             }
10225         },
10226
10227         /**
10228          * @property ComputedStyle True if the browser supports document.defaultView.getComputedStyle()
10229          * @type {Boolean}
10230          */
10231         {
10232             identity: 'ComputedStyle',
10233             fn: function(doc, div, view) {
10234                 view = doc.defaultView;
10235                 return view && view.getComputedStyle;
10236             }
10237         },
10238         
10239         /**
10240          * @property SVG True if the device supports SVG
10241          * @type {Boolean}
10242          */
10243         {
10244             identity: 'Svg',
10245             fn: function(doc) {
10246                 return !!doc.createElementNS && !!doc.createElementNS( "http:/" + "/www.w3.org/2000/svg", "svg").createSVGRect;
10247             }
10248         },
10249     
10250         /**
10251          * @property Canvas True if the device supports Canvas
10252          * @type {Boolean}
10253          */
10254         {
10255             identity: 'Canvas',
10256             fn: function(doc) {
10257                 return !!doc.createElement('canvas').getContext;
10258             }
10259         },
10260         
10261         /**
10262          * @property VML True if the device supports VML
10263          * @type {Boolean}
10264          */
10265         {
10266             identity: 'Vml',
10267             fn: function(doc) {
10268                 var d = doc.createElement("div");
10269                 d.innerHTML = "<!--[if vml]><br><br><![endif]-->";
10270                 return (d.childNodes.length == 2);
10271             }
10272         },
10273         
10274         /**
10275          * @property Float True if the device supports CSS float
10276          * @type {Boolean}
10277          */
10278         {
10279             identity: 'Float',
10280             fn: function(doc, div) {
10281                 return !!div.lastChild.style.cssFloat;
10282             }
10283         },
10284         
10285         /**
10286          * @property AudioTag True if the device supports the HTML5 audio tag
10287          * @type {Boolean}
10288          */
10289         {
10290             identity: 'AudioTag',
10291             fn: function(doc) {
10292                 return !!doc.createElement('audio').canPlayType;
10293             }
10294         },
10295         
10296         /**
10297          * @property History True if the device supports HTML5 history
10298          * @type {Boolean}
10299          */
10300         {
10301             identity: 'History',
10302             fn: function() {
10303                 return !!(window.history && history.pushState);
10304             }
10305         },
10306         
10307         /**
10308          * @property CSS3DTransform True if the device supports CSS3DTransform
10309          * @type {Boolean}
10310          */
10311         {
10312             identity: 'CSS3DTransform',
10313             fn: function() {
10314                 return (typeof WebKitCSSMatrix != 'undefined' && new WebKitCSSMatrix().hasOwnProperty('m41'));
10315             }
10316         },
10317
10318                 /**
10319          * @property CSS3LinearGradient True if the device supports CSS3 linear gradients
10320          * @type {Boolean}
10321          */
10322         {
10323             identity: 'CSS3LinearGradient',
10324             fn: function(doc, div) {
10325                 var property = 'background-image:',
10326                     webkit   = '-webkit-gradient(linear, left top, right bottom, from(black), to(white))',
10327                     w3c      = 'linear-gradient(left top, black, white)',
10328                     moz      = '-moz-' + w3c,
10329                     options  = [property + webkit, property + w3c, property + moz];
10330                 
10331                 div.style.cssText = options.join(';');
10332                 
10333                 return ("" + div.style.backgroundImage).indexOf('gradient') !== -1;
10334             }
10335         },
10336         
10337         /**
10338          * @property CSS3BorderRadius True if the device supports CSS3 border radius
10339          * @type {Boolean}
10340          */
10341         {
10342             identity: 'CSS3BorderRadius',
10343             fn: function(doc, div) {
10344                 var domPrefixes = ['borderRadius', 'BorderRadius', 'MozBorderRadius', 'WebkitBorderRadius', 'OBorderRadius', 'KhtmlBorderRadius'],
10345                     pass = false,
10346                     i;
10347                 for (i = 0; i < domPrefixes.length; i++) {
10348                     if (document.body.style[domPrefixes[i]] !== undefined) {
10349                         return true;
10350                     }
10351                 }
10352                 return pass;
10353             }
10354         },
10355         
10356         /**
10357          * @property GeoLocation True if the device supports GeoLocation
10358          * @type {Boolean}
10359          */
10360         {
10361             identity: 'GeoLocation',
10362             fn: function() {
10363                 return (typeof navigator != 'undefined' && typeof navigator.geolocation != 'undefined') || (typeof google != 'undefined' && typeof google.gears != 'undefined');
10364             }
10365         },
10366         /**
10367          * @property MouseEnterLeave True if the browser supports mouseenter and mouseleave events
10368          * @type {Boolean}
10369          */
10370         {
10371             identity: 'MouseEnterLeave',
10372             fn: function(doc, div){
10373                 return ('onmouseenter' in div && 'onmouseleave' in div);
10374             }
10375         },
10376         /**
10377          * @property MouseWheel True if the browser supports the mousewheel event
10378          * @type {Boolean}
10379          */
10380         {
10381             identity: 'MouseWheel',
10382             fn: function(doc, div) {
10383                 return ('onmousewheel' in div);
10384             }
10385         },
10386         /**
10387          * @property Opacity True if the browser supports normal css opacity
10388          * @type {Boolean}
10389          */
10390         {
10391             identity: 'Opacity',
10392             fn: function(doc, div){
10393                 // Not a strict equal comparison in case opacity can be converted to a number.
10394                 if (Ext.isIE6 || Ext.isIE7 || Ext.isIE8) {
10395                     return false;
10396                 }
10397                 div.firstChild.style.cssText = 'opacity:0.73';
10398                 return div.firstChild.style.opacity == '0.73';
10399             }
10400         },
10401         /**
10402          * @property Placeholder True if the browser supports the HTML5 placeholder attribute on inputs
10403          * @type {Boolean}
10404          */
10405         {
10406             identity: 'Placeholder',
10407             fn: function(doc) {
10408                 return 'placeholder' in doc.createElement('input');
10409             }
10410         },
10411         
10412         /**
10413          * @property Direct2DBug True if when asking for an element's dimension via offsetWidth or offsetHeight, 
10414          * getBoundingClientRect, etc. the browser returns the subpixel width rounded to the nearest pixel.
10415          * @type {Boolean}
10416          */
10417         {
10418             identity: 'Direct2DBug',
10419             fn: function() {
10420                 return Ext.isString(document.body.style.msTransformOrigin);
10421             }
10422         },
10423         /**
10424          * @property BoundingClientRect True if the browser supports the getBoundingClientRect method on elements
10425          * @type {Boolean}
10426          */
10427         {
10428             identity: 'BoundingClientRect',
10429             fn: function(doc, div) {
10430                 return Ext.isFunction(div.getBoundingClientRect);
10431             }
10432         },
10433         {
10434             identity: 'IncludePaddingInWidthCalculation',
10435             fn: function(doc, div){
10436                 var el = Ext.get(div.childNodes[1].firstChild);
10437                 return el.getWidth() == 210;
10438             }
10439         },
10440         {
10441             identity: 'IncludePaddingInHeightCalculation',
10442             fn: function(doc, div){
10443                 var el = Ext.get(div.childNodes[1].firstChild);
10444                 return el.getHeight() == 210;
10445             }
10446         },
10447         
10448         /**
10449          * @property ArraySort True if the Array sort native method isn't bugged.
10450          * @type {Boolean}
10451          */
10452         {
10453             identity: 'ArraySort',
10454             fn: function() {
10455                 var a = [1,2,3,4,5].sort(function(){ return 0; });
10456                 return a[0] === 1 && a[1] === 2 && a[2] === 3 && a[3] === 4 && a[4] === 5;
10457             }
10458         },
10459         /**
10460          * @property Range True if browser support document.createRange native method.
10461          * @type {Boolean}
10462          */
10463         {
10464             identity: 'Range',
10465             fn: function() {
10466                 return !!document.createRange;
10467             }
10468         },
10469         /**
10470          * @property CreateContextualFragment True if browser support CreateContextualFragment range native methods.
10471          * @type {Boolean}
10472          */
10473         {
10474             identity: 'CreateContextualFragment',
10475             fn: function() {
10476                 var range = Ext.supports.Range ? document.createRange() : false;
10477                 
10478                 return range && !!range.createContextualFragment;
10479             }
10480         },
10481
10482         /**
10483          * @property WindowOnError True if browser supports window.onerror.
10484          * @type {Boolean}
10485          */
10486         {
10487             identity: 'WindowOnError',
10488             fn: function () {
10489                 // sadly, we cannot feature detect this...
10490                 return Ext.isIE || Ext.isGecko || Ext.webKitVersion >= 534.16; // Chrome 10+
10491             }
10492         }
10493     ]
10494 };
10495
10496
10497
10498 /*
10499
10500 This file is part of Ext JS 4
10501
10502 Copyright (c) 2011 Sencha Inc
10503
10504 Contact:  http://www.sencha.com/contact
10505
10506 GNU General Public License Usage
10507 This file may be used under the terms of the GNU General Public License version 3.0 as published by the Free Software Foundation and appearing in the file LICENSE included in the packaging of this file.  Please review the following information to ensure the GNU General Public License version 3.0 requirements will be met: http://www.gnu.org/copyleft/gpl.html.
10508
10509 If you are unsure which license is appropriate for your use, please contact the sales department at http://www.sencha.com/contact.
10510
10511 */
10512 /**
10513  * @class Ext.core.DomHelper
10514  * <p>The DomHelper class provides a layer of abstraction from DOM and transparently supports creating
10515  * elements via DOM or using HTML fragments. It also has the ability to create HTML fragment templates
10516  * from your DOM building code.</p>
10517  *
10518  * <p><b><u>DomHelper element specification object</u></b></p>
10519  * <p>A specification object is used when creating elements. Attributes of this object
10520  * are assumed to be element attributes, except for 4 special attributes:
10521  * <div class="mdetail-params"><ul>
10522  * <li><b><tt>tag</tt></b> : <div class="sub-desc">The tag name of the element</div></li>
10523  * <li><b><tt>children</tt></b> : or <tt>cn</tt><div class="sub-desc">An array of the
10524  * same kind of element definition objects to be created and appended. These can be nested
10525  * as deep as you want.</div></li>
10526  * <li><b><tt>cls</tt></b> : <div class="sub-desc">The class attribute of the element.
10527  * This will end up being either the "class" attribute on a HTML fragment or className
10528  * for a DOM node, depending on whether DomHelper is using fragments or DOM.</div></li>
10529  * <li><b><tt>html</tt></b> : <div class="sub-desc">The innerHTML for the element</div></li>
10530  * </ul></div></p>
10531  * <p><b>NOTE:</b> For other arbitrary attributes, the value will currently <b>not</b> be automatically
10532  * HTML-escaped prior to building the element's HTML string. This means that if your attribute value
10533  * contains special characters that would not normally be allowed in a double-quoted attribute value,
10534  * you <b>must</b> manually HTML-encode it beforehand (see {@link Ext.String#htmlEncode}) or risk
10535  * malformed HTML being created. This behavior may change in a future release.</p>
10536  *
10537  * <p><b><u>Insertion methods</u></b></p>
10538  * <p>Commonly used insertion methods:
10539  * <div class="mdetail-params"><ul>
10540  * <li><b><tt>{@link #append}</tt></b> : <div class="sub-desc"></div></li>
10541  * <li><b><tt>{@link #insertBefore}</tt></b> : <div class="sub-desc"></div></li>
10542  * <li><b><tt>{@link #insertAfter}</tt></b> : <div class="sub-desc"></div></li>
10543  * <li><b><tt>{@link #overwrite}</tt></b> : <div class="sub-desc"></div></li>
10544  * <li><b><tt>{@link #createTemplate}</tt></b> : <div class="sub-desc"></div></li>
10545  * <li><b><tt>{@link #insertHtml}</tt></b> : <div class="sub-desc"></div></li>
10546  * </ul></div></p>
10547  *
10548  * <p><b><u>Example</u></b></p>
10549  * <p>This is an example, where an unordered list with 3 children items is appended to an existing
10550  * element with id <tt>'my-div'</tt>:<br>
10551  <pre><code>
10552 var dh = Ext.core.DomHelper; // create shorthand alias
10553 // specification object
10554 var spec = {
10555     id: 'my-ul',
10556     tag: 'ul',
10557     cls: 'my-list',
10558     // append children after creating
10559     children: [     // may also specify 'cn' instead of 'children'
10560         {tag: 'li', id: 'item0', html: 'List Item 0'},
10561         {tag: 'li', id: 'item1', html: 'List Item 1'},
10562         {tag: 'li', id: 'item2', html: 'List Item 2'}
10563     ]
10564 };
10565 var list = dh.append(
10566     'my-div', // the context element 'my-div' can either be the id or the actual node
10567     spec      // the specification object
10568 );
10569  </code></pre></p>
10570  * <p>Element creation specification parameters in this class may also be passed as an Array of
10571  * specification objects. This can be used to insert multiple sibling nodes into an existing
10572  * container very efficiently. For example, to add more list items to the example above:<pre><code>
10573 dh.append('my-ul', [
10574     {tag: 'li', id: 'item3', html: 'List Item 3'},
10575     {tag: 'li', id: 'item4', html: 'List Item 4'}
10576 ]);
10577  * </code></pre></p>
10578  *
10579  * <p><b><u>Templating</u></b></p>
10580  * <p>The real power is in the built-in templating. Instead of creating or appending any elements,
10581  * <tt>{@link #createTemplate}</tt> returns a Template object which can be used over and over to
10582  * insert new elements. Revisiting the example above, we could utilize templating this time:
10583  * <pre><code>
10584 // create the node
10585 var list = dh.append('my-div', {tag: 'ul', cls: 'my-list'});
10586 // get template
10587 var tpl = dh.createTemplate({tag: 'li', id: 'item{0}', html: 'List Item {0}'});
10588
10589 for(var i = 0; i < 5, i++){
10590     tpl.append(list, [i]); // use template to append to the actual node
10591 }
10592  * </code></pre></p>
10593  * <p>An example using a template:<pre><code>
10594 var html = '<a id="{0}" href="{1}" class="nav">{2}</a>';
10595
10596 var tpl = new Ext.core.DomHelper.createTemplate(html);
10597 tpl.append('blog-roll', ['link1', 'http://www.edspencer.net/', "Ed&#39;s Site"]);
10598 tpl.append('blog-roll', ['link2', 'http://www.dustindiaz.com/', "Dustin&#39;s Site"]);
10599  * </code></pre></p>
10600  *
10601  * <p>The same example using named parameters:<pre><code>
10602 var html = '<a id="{id}" href="{url}" class="nav">{text}</a>';
10603
10604 var tpl = new Ext.core.DomHelper.createTemplate(html);
10605 tpl.append('blog-roll', {
10606     id: 'link1',
10607     url: 'http://www.edspencer.net/',
10608     text: "Ed&#39;s Site"
10609 });
10610 tpl.append('blog-roll', {
10611     id: 'link2',
10612     url: 'http://www.dustindiaz.com/',
10613     text: "Dustin&#39;s Site"
10614 });
10615  * </code></pre></p>
10616  *
10617  * <p><b><u>Compiling Templates</u></b></p>
10618  * <p>Templates are applied using regular expressions. The performance is great, but if
10619  * you are adding a bunch of DOM elements using the same template, you can increase
10620  * performance even further by {@link Ext.Template#compile "compiling"} the template.
10621  * The way "{@link Ext.Template#compile compile()}" works is the template is parsed and
10622  * broken up at the different variable points and a dynamic function is created and eval'ed.
10623  * The generated function performs string concatenation of these parts and the passed
10624  * variables instead of using regular expressions.
10625  * <pre><code>
10626 var html = '<a id="{id}" href="{url}" class="nav">{text}</a>';
10627
10628 var tpl = new Ext.core.DomHelper.createTemplate(html);
10629 tpl.compile();
10630
10631 //... use template like normal
10632  * </code></pre></p>
10633  *
10634  * <p><b><u>Performance Boost</u></b></p>
10635  * <p>DomHelper will transparently create HTML fragments when it can. Using HTML fragments instead
10636  * of DOM can significantly boost performance.</p>
10637  * <p>Element creation specification parameters may also be strings. If {@link #useDom} is <tt>false</tt>,
10638  * then the string is used as innerHTML. If {@link #useDom} is <tt>true</tt>, a string specification
10639  * results in the creation of a text node. Usage:</p>
10640  * <pre><code>
10641 Ext.core.DomHelper.useDom = true; // force it to use DOM; reduces performance
10642  * </code></pre>
10643  * @singleton
10644  */
10645 Ext.ns('Ext.core');
10646 Ext.core.DomHelper = function(){
10647     var tempTableEl = null,
10648         emptyTags = /^(?:br|frame|hr|img|input|link|meta|range|spacer|wbr|area|param|col)$/i,
10649         tableRe = /^table|tbody|tr|td$/i,
10650         confRe = /tag|children|cn|html$/i,
10651         tableElRe = /td|tr|tbody/i,
10652         endRe = /end/i,
10653         pub,
10654         // kill repeat to save bytes
10655         afterbegin = 'afterbegin',
10656         afterend = 'afterend',
10657         beforebegin = 'beforebegin',
10658         beforeend = 'beforeend',
10659         ts = '<table>',
10660         te = '</table>',
10661         tbs = ts+'<tbody>',
10662         tbe = '</tbody>'+te,
10663         trs = tbs + '<tr>',
10664         tre = '</tr>'+tbe;
10665
10666     // private
10667     function doInsert(el, o, returnElement, pos, sibling, append){
10668         el = Ext.getDom(el);
10669         var newNode;
10670         if (pub.useDom) {
10671             newNode = createDom(o, null);
10672             if (append) {
10673                 el.appendChild(newNode);
10674             } else {
10675                 (sibling == 'firstChild' ? el : el.parentNode).insertBefore(newNode, el[sibling] || el);
10676             }
10677         } else {
10678             newNode = Ext.core.DomHelper.insertHtml(pos, el, Ext.core.DomHelper.createHtml(o));
10679         }
10680         return returnElement ? Ext.get(newNode, true) : newNode;
10681     }
10682     
10683     function createDom(o, parentNode){
10684         var el,
10685             doc = document,
10686             useSet,
10687             attr,
10688             val,
10689             cn;
10690
10691         if (Ext.isArray(o)) {                       // Allow Arrays of siblings to be inserted
10692             el = doc.createDocumentFragment(); // in one shot using a DocumentFragment
10693             for (var i = 0, l = o.length; i < l; i++) {
10694                 createDom(o[i], el);
10695             }
10696         } else if (typeof o == 'string') {         // Allow a string as a child spec.
10697             el = doc.createTextNode(o);
10698         } else {
10699             el = doc.createElement( o.tag || 'div' );
10700             useSet = !!el.setAttribute; // In IE some elements don't have setAttribute
10701             for (attr in o) {
10702                 if(!confRe.test(attr)){
10703                     val = o[attr];
10704                     if(attr == 'cls'){
10705                         el.className = val;
10706                     }else{
10707                         if(useSet){
10708                             el.setAttribute(attr, val);
10709                         }else{
10710                             el[attr] = val;
10711                         }
10712                     }
10713                 }
10714             }
10715             Ext.core.DomHelper.applyStyles(el, o.style);
10716
10717             if ((cn = o.children || o.cn)) {
10718                 createDom(cn, el);
10719             } else if (o.html) {
10720                 el.innerHTML = o.html;
10721             }
10722         }
10723         if(parentNode){
10724            parentNode.appendChild(el);
10725         }
10726         return el;
10727     }
10728
10729     // build as innerHTML where available
10730     function createHtml(o){
10731         var b = '',
10732             attr,
10733             val,
10734             key,
10735             cn,
10736             i;
10737
10738         if(typeof o == "string"){
10739             b = o;
10740         } else if (Ext.isArray(o)) {
10741             for (i=0; i < o.length; i++) {
10742                 if(o[i]) {
10743                     b += createHtml(o[i]);
10744                 }
10745             }
10746         } else {
10747             b += '<' + (o.tag = o.tag || 'div');
10748             for (attr in o) {
10749                 val = o[attr];
10750                 if(!confRe.test(attr)){
10751                     if (typeof val == "object") {
10752                         b += ' ' + attr + '="';
10753                         for (key in val) {
10754                             b += key + ':' + val[key] + ';';
10755                         }
10756                         b += '"';
10757                     }else{
10758                         b += ' ' + ({cls : 'class', htmlFor : 'for'}[attr] || attr) + '="' + val + '"';
10759                     }
10760                 }
10761             }
10762             // Now either just close the tag or try to add children and close the tag.
10763             if (emptyTags.test(o.tag)) {
10764                 b += '/>';
10765             } else {
10766                 b += '>';
10767                 if ((cn = o.children || o.cn)) {
10768                     b += createHtml(cn);
10769                 } else if(o.html){
10770                     b += o.html;
10771                 }
10772                 b += '</' + o.tag + '>';
10773             }
10774         }
10775         return b;
10776     }
10777
10778     function ieTable(depth, s, h, e){
10779         tempTableEl.innerHTML = [s, h, e].join('');
10780         var i = -1,
10781             el = tempTableEl,
10782             ns;
10783         while(++i < depth){
10784             el = el.firstChild;
10785         }
10786 //      If the result is multiple siblings, then encapsulate them into one fragment.
10787         ns = el.nextSibling;
10788         if (ns){
10789             var df = document.createDocumentFragment();
10790             while(el){
10791                 ns = el.nextSibling;
10792                 df.appendChild(el);
10793                 el = ns;
10794             }
10795             el = df;
10796         }
10797         return el;
10798     }
10799
10800     /**
10801      * @ignore
10802      * Nasty code for IE's broken table implementation
10803      */
10804     function insertIntoTable(tag, where, el, html) {
10805         var node,
10806             before;
10807
10808         tempTableEl = tempTableEl || document.createElement('div');
10809
10810         if(tag == 'td' && (where == afterbegin || where == beforeend) ||
10811            !tableElRe.test(tag) && (where == beforebegin || where == afterend)) {
10812             return null;
10813         }
10814         before = where == beforebegin ? el :
10815                  where == afterend ? el.nextSibling :
10816                  where == afterbegin ? el.firstChild : null;
10817
10818         if (where == beforebegin || where == afterend) {
10819             el = el.parentNode;
10820         }
10821
10822         if (tag == 'td' || (tag == 'tr' && (where == beforeend || where == afterbegin))) {
10823             node = ieTable(4, trs, html, tre);
10824         } else if ((tag == 'tbody' && (where == beforeend || where == afterbegin)) ||
10825                    (tag == 'tr' && (where == beforebegin || where == afterend))) {
10826             node = ieTable(3, tbs, html, tbe);
10827         } else {
10828             node = ieTable(2, ts, html, te);
10829         }
10830         el.insertBefore(node, before);
10831         return node;
10832     }
10833     
10834     /**
10835      * @ignore
10836      * Fix for IE9 createContextualFragment missing method
10837      */   
10838     function createContextualFragment(html){
10839         var div = document.createElement("div"),
10840             fragment = document.createDocumentFragment(),
10841             i = 0,
10842             length, childNodes;
10843         
10844         div.innerHTML = html;
10845         childNodes = div.childNodes;
10846         length = childNodes.length;
10847
10848         for (; i < length; i++) {
10849             fragment.appendChild(childNodes[i].cloneNode(true));
10850         }
10851
10852         return fragment;
10853     }
10854     
10855     pub = {
10856         /**
10857          * Returns the markup for the passed Element(s) config.
10858          * @param {Object} o The DOM object spec (and children)
10859          * @return {String}
10860          */
10861         markup : function(o){
10862             return createHtml(o);
10863         },
10864
10865         /**
10866          * Applies a style specification to an element.
10867          * @param {String/HTMLElement} el The element to apply styles to
10868          * @param {String/Object/Function} styles A style specification string e.g. 'width:100px', or object in the form {width:'100px'}, or
10869          * a function which returns such a specification.
10870          */
10871         applyStyles : function(el, styles){
10872             if (styles) {
10873                 el = Ext.fly(el);
10874                 if (typeof styles == "function") {
10875                     styles = styles.call();
10876                 }
10877                 if (typeof styles == "string") {
10878                     styles = Ext.core.Element.parseStyles(styles);
10879                 }
10880                 if (typeof styles == "object") {
10881                     el.setStyle(styles);
10882                 }
10883             }
10884         },
10885
10886         /**
10887          * Inserts an HTML fragment into the DOM.
10888          * @param {String} where Where to insert the html in relation to el - beforeBegin, afterBegin, beforeEnd, afterEnd.
10889          * @param {HTMLElement/TextNode} el The context element
10890          * @param {String} html The HTML fragment
10891          * @return {HTMLElement} The new node
10892          */
10893         insertHtml : function(where, el, html){
10894             var hash = {},
10895                 hashVal,
10896                 range,
10897                 rangeEl,
10898                 setStart,
10899                 frag,
10900                 rs;
10901
10902             where = where.toLowerCase();
10903             // add these here because they are used in both branches of the condition.
10904             hash[beforebegin] = ['BeforeBegin', 'previousSibling'];
10905             hash[afterend] = ['AfterEnd', 'nextSibling'];
10906             
10907             // if IE and context element is an HTMLElement
10908             if (el.insertAdjacentHTML) {
10909                 if(tableRe.test(el.tagName) && (rs = insertIntoTable(el.tagName.toLowerCase(), where, el, html))){
10910                     return rs;
10911                 }
10912                 
10913                 // add these two to the hash.
10914                 hash[afterbegin] = ['AfterBegin', 'firstChild'];
10915                 hash[beforeend] = ['BeforeEnd', 'lastChild'];
10916                 if ((hashVal = hash[where])) {
10917                     el.insertAdjacentHTML(hashVal[0], html);
10918                     return el[hashVal[1]];
10919                 }
10920             // if (not IE and context element is an HTMLElement) or TextNode
10921             } else {
10922                 // we cannot insert anything inside a textnode so...
10923                 if (Ext.isTextNode(el)) {
10924                     where = where === 'afterbegin' ? 'beforebegin' : where; 
10925                     where = where === 'beforeend' ? 'afterend' : where;
10926                 }
10927                 range = Ext.supports.CreateContextualFragment ? el.ownerDocument.createRange() : undefined;
10928                 setStart = 'setStart' + (endRe.test(where) ? 'After' : 'Before');
10929                 if (hash[where]) {
10930                     if (range) {
10931                         range[setStart](el);
10932                         frag = range.createContextualFragment(html);
10933                     } else {
10934                         frag = createContextualFragment(html);
10935                     }
10936                     el.parentNode.insertBefore(frag, where == beforebegin ? el : el.nextSibling);
10937                     return el[(where == beforebegin ? 'previous' : 'next') + 'Sibling'];
10938                 } else {
10939                     rangeEl = (where == afterbegin ? 'first' : 'last') + 'Child';
10940                     if (el.firstChild) {
10941                         if (range) {
10942                             range[setStart](el[rangeEl]);
10943                             frag = range.createContextualFragment(html);
10944                         } else {
10945                             frag = createContextualFragment(html);
10946                         }
10947                         
10948                         if(where == afterbegin){
10949                             el.insertBefore(frag, el.firstChild);
10950                         }else{
10951                             el.appendChild(frag);
10952                         }
10953                     } else {
10954                         el.innerHTML = html;
10955                     }
10956                     return el[rangeEl];
10957                 }
10958             }
10959         },
10960
10961         /**
10962          * Creates new DOM element(s) and inserts them before el.
10963          * @param {Mixed} el The context element
10964          * @param {Object/String} o The DOM object spec (and children) or raw HTML blob
10965          * @param {Boolean} returnElement (optional) true to return a Ext.core.Element
10966          * @return {HTMLElement/Ext.core.Element} The new node
10967          */
10968         insertBefore : function(el, o, returnElement){
10969             return doInsert(el, o, returnElement, beforebegin);
10970         },
10971
10972         /**
10973          * Creates new DOM element(s) and inserts them after el.
10974          * @param {Mixed} el The context element
10975          * @param {Object} o The DOM object spec (and children)
10976          * @param {Boolean} returnElement (optional) true to return a Ext.core.Element
10977          * @return {HTMLElement/Ext.core.Element} The new node
10978          */
10979         insertAfter : function(el, o, returnElement){
10980             return doInsert(el, o, returnElement, afterend, 'nextSibling');
10981         },
10982
10983         /**
10984          * Creates new DOM element(s) and inserts them as the first child of el.
10985          * @param {Mixed} el The context element
10986          * @param {Object/String} o The DOM object spec (and children) or raw HTML blob
10987          * @param {Boolean} returnElement (optional) true to return a Ext.core.Element
10988          * @return {HTMLElement/Ext.core.Element} The new node
10989          */
10990         insertFirst : function(el, o, returnElement){
10991             return doInsert(el, o, returnElement, afterbegin, 'firstChild');
10992         },
10993
10994         /**
10995          * Creates new DOM element(s) and appends them to el.
10996          * @param {Mixed} el The context element
10997          * @param {Object/String} o The DOM object spec (and children) or raw HTML blob
10998          * @param {Boolean} returnElement (optional) true to return a Ext.core.Element
10999          * @return {HTMLElement/Ext.core.Element} The new node
11000          */
11001         append : function(el, o, returnElement){
11002             return doInsert(el, o, returnElement, beforeend, '', true);
11003         },
11004
11005         /**
11006          * Creates new DOM element(s) and overwrites the contents of el with them.
11007          * @param {Mixed} el The context element
11008          * @param {Object/String} o The DOM object spec (and children) or raw HTML blob
11009          * @param {Boolean} returnElement (optional) true to return a Ext.core.Element
11010          * @return {HTMLElement/Ext.core.Element} The new node
11011          */
11012         overwrite : function(el, o, returnElement){
11013             el = Ext.getDom(el);
11014             el.innerHTML = createHtml(o);
11015             return returnElement ? Ext.get(el.firstChild) : el.firstChild;
11016         },
11017
11018         createHtml : createHtml,
11019         
11020         /**
11021          * Creates new DOM element(s) without inserting them to the document.
11022          * @param {Object/String} o The DOM object spec (and children) or raw HTML blob
11023          * @return {HTMLElement} The new uninserted node
11024          * @method
11025          */
11026         createDom: createDom,
11027         
11028         /** True to force the use of DOM instead of html fragments @type Boolean */
11029         useDom : false,
11030         
11031         /**
11032          * Creates a new Ext.Template from the DOM object spec.
11033          * @param {Object} o The DOM object spec (and children)
11034          * @return {Ext.Template} The new template
11035          */
11036         createTemplate : function(o){
11037             var html = Ext.core.DomHelper.createHtml(o);
11038             return Ext.create('Ext.Template', html);
11039         }
11040     };
11041     return pub;
11042 }();
11043
11044 /*
11045  * This is code is also distributed under MIT license for use
11046  * with jQuery and prototype JavaScript libraries.
11047  */
11048 /**
11049  * @class Ext.DomQuery
11050 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).
11051 <p>
11052 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>
11053
11054 <p>
11055 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.
11056 </p>
11057 <h4>Element Selectors:</h4>
11058 <ul class="list">
11059     <li> <b>*</b> any element</li>
11060     <li> <b>E</b> an element with the tag E</li>
11061     <li> <b>E F</b> All descendent elements of E that have the tag F</li>
11062     <li> <b>E > F</b> or <b>E/F</b> all direct children elements of E that have the tag F</li>
11063     <li> <b>E + F</b> all elements with the tag F that are immediately preceded by an element with the tag E</li>
11064     <li> <b>E ~ F</b> all elements with the tag F that are preceded by a sibling element with the tag E</li>
11065 </ul>
11066 <h4>Attribute Selectors:</h4>
11067 <p>The use of &#64; and quotes are optional. For example, div[&#64;foo='bar'] is also a valid attribute selector.</p>
11068 <ul class="list">
11069     <li> <b>E[foo]</b> has an attribute "foo"</li>
11070     <li> <b>E[foo=bar]</b> has an attribute "foo" that equals "bar"</li>
11071     <li> <b>E[foo^=bar]</b> has an attribute "foo" that starts with "bar"</li>
11072     <li> <b>E[foo$=bar]</b> has an attribute "foo" that ends with "bar"</li>
11073     <li> <b>E[foo*=bar]</b> has an attribute "foo" that contains the substring "bar"</li>
11074     <li> <b>E[foo%=2]</b> has an attribute "foo" that is evenly divisible by 2</li>
11075     <li> <b>E[foo!=bar]</b> attribute "foo" does not equal "bar"</li>
11076 </ul>
11077 <h4>Pseudo Classes:</h4>
11078 <ul class="list">
11079     <li> <b>E:first-child</b> E is the first child of its parent</li>
11080     <li> <b>E:last-child</b> E is the last child of its parent</li>
11081     <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>
11082     <li> <b>E:nth-child(odd)</b> E is an odd child of its parent</li>
11083     <li> <b>E:nth-child(even)</b> E is an even child of its parent</li>
11084     <li> <b>E:only-child</b> E is the only child of its parent</li>
11085     <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>
11086     <li> <b>E:first</b> the first E in the resultset</li>
11087     <li> <b>E:last</b> the last E in the resultset</li>
11088     <li> <b>E:nth(<i>n</i>)</b> the <i>n</i>th E in the resultset (1 based)</li>
11089     <li> <b>E:odd</b> shortcut for :nth-child(odd)</li>
11090     <li> <b>E:even</b> shortcut for :nth-child(even)</li>
11091     <li> <b>E:contains(foo)</b> E's innerHTML contains the substring "foo"</li>
11092     <li> <b>E:nodeValue(foo)</b> E contains a textNode with a nodeValue that equals "foo"</li>
11093     <li> <b>E:not(S)</b> an E element that does not match simple selector S</li>
11094     <li> <b>E:has(S)</b> an E element that has a descendent that matches simple selector S</li>
11095     <li> <b>E:next(S)</b> an E element whose next sibling matches simple selector S</li>
11096     <li> <b>E:prev(S)</b> an E element whose previous sibling matches simple selector S</li>
11097     <li> <b>E:any(S1|S2|S2)</b> an E element which matches any of the simple selectors S1, S2 or S3//\\</li>
11098 </ul>
11099 <h4>CSS Value Selectors:</h4>
11100 <ul class="list">
11101     <li> <b>E{display=none}</b> css value "display" that equals "none"</li>
11102     <li> <b>E{display^=none}</b> css value "display" that starts with "none"</li>
11103     <li> <b>E{display$=none}</b> css value "display" that ends with "none"</li>
11104     <li> <b>E{display*=none}</b> css value "display" that contains the substring "none"</li>
11105     <li> <b>E{display%=2}</b> css value "display" that is evenly divisible by 2</li>
11106     <li> <b>E{display!=none}</b> css value "display" that does not equal "none"</li>
11107 </ul>
11108  * @singleton
11109  */
11110 Ext.ns('Ext.core');
11111
11112 Ext.core.DomQuery = Ext.DomQuery = function(){
11113     var cache = {},
11114         simpleCache = {},
11115         valueCache = {},
11116         nonSpace = /\S/,
11117         trimRe = /^\s+|\s+$/g,
11118         tplRe = /\{(\d+)\}/g,
11119         modeRe = /^(\s?[\/>+~]\s?|\s|$)/,
11120         tagTokenRe = /^(#)?([\w-\*]+)/,
11121         nthRe = /(\d*)n\+?(\d*)/,
11122         nthRe2 = /\D/,
11123         // This is for IE MSXML which does not support expandos.
11124     // IE runs the same speed using setAttribute, however FF slows way down
11125     // and Safari completely fails so they need to continue to use expandos.
11126     isIE = window.ActiveXObject ? true : false,
11127     key = 30803;
11128
11129     // this eval is stop the compressor from
11130     // renaming the variable to something shorter
11131     eval("var batch = 30803;");
11132
11133     // Retrieve the child node from a particular
11134     // parent at the specified index.
11135     function child(parent, index){
11136         var i = 0,
11137             n = parent.firstChild;
11138         while(n){
11139             if(n.nodeType == 1){
11140                if(++i == index){
11141                    return n;
11142                }
11143             }
11144             n = n.nextSibling;
11145         }
11146         return null;
11147     }
11148
11149     // retrieve the next element node
11150     function next(n){
11151         while((n = n.nextSibling) && n.nodeType != 1);
11152         return n;
11153     }
11154
11155     // retrieve the previous element node
11156     function prev(n){
11157         while((n = n.previousSibling) && n.nodeType != 1);
11158         return n;
11159     }
11160
11161     // Mark each child node with a nodeIndex skipping and
11162     // removing empty text nodes.
11163     function children(parent){
11164         var n = parent.firstChild,
11165         nodeIndex = -1,
11166         nextNode;
11167         while(n){
11168             nextNode = n.nextSibling;
11169             // clean worthless empty nodes.
11170             if(n.nodeType == 3 && !nonSpace.test(n.nodeValue)){
11171             parent.removeChild(n);
11172             }else{
11173             // add an expando nodeIndex
11174             n.nodeIndex = ++nodeIndex;
11175             }
11176             n = nextNode;
11177         }
11178         return this;
11179     }
11180
11181
11182     // nodeSet - array of nodes
11183     // cls - CSS Class
11184     function byClassName(nodeSet, cls){
11185         if(!cls){
11186             return nodeSet;
11187         }
11188         var result = [], ri = -1;
11189         for(var i = 0, ci; ci = nodeSet[i]; i++){
11190             if((' '+ci.className+' ').indexOf(cls) != -1){
11191                 result[++ri] = ci;
11192             }
11193         }
11194         return result;
11195     };
11196
11197     function attrValue(n, attr){
11198         // if its an array, use the first node.
11199         if(!n.tagName && typeof n.length != "undefined"){
11200             n = n[0];
11201         }
11202         if(!n){
11203             return null;
11204         }
11205
11206         if(attr == "for"){
11207             return n.htmlFor;
11208         }
11209         if(attr == "class" || attr == "className"){
11210             return n.className;
11211         }
11212         return n.getAttribute(attr) || n[attr];
11213
11214     };
11215
11216
11217     // ns - nodes
11218     // mode - false, /, >, +, ~
11219     // tagName - defaults to "*"
11220     function getNodes(ns, mode, tagName){
11221         var result = [], ri = -1, cs;
11222         if(!ns){
11223             return result;
11224         }
11225         tagName = tagName || "*";
11226         // convert to array
11227         if(typeof ns.getElementsByTagName != "undefined"){
11228             ns = [ns];
11229         }
11230
11231         // no mode specified, grab all elements by tagName
11232         // at any depth
11233         if(!mode){
11234             for(var i = 0, ni; ni = ns[i]; i++){
11235                 cs = ni.getElementsByTagName(tagName);
11236                 for(var j = 0, ci; ci = cs[j]; j++){
11237                     result[++ri] = ci;
11238                 }
11239             }
11240         // Direct Child mode (/ or >)
11241         // E > F or E/F all direct children elements of E that have the tag
11242         } else if(mode == "/" || mode == ">"){
11243             var utag = tagName.toUpperCase();
11244             for(var i = 0, ni, cn; ni = ns[i]; i++){
11245                 cn = ni.childNodes;
11246                 for(var j = 0, cj; cj = cn[j]; j++){
11247                     if(cj.nodeName == utag || cj.nodeName == tagName  || tagName == '*'){
11248                         result[++ri] = cj;
11249                     }
11250                 }
11251             }
11252         // Immediately Preceding mode (+)
11253         // E + F all elements with the tag F that are immediately preceded by an element with the tag E
11254         }else if(mode == "+"){
11255             var utag = tagName.toUpperCase();
11256             for(var i = 0, n; n = ns[i]; i++){
11257                 while((n = n.nextSibling) && n.nodeType != 1);
11258                 if(n && (n.nodeName == utag || n.nodeName == tagName || tagName == '*')){
11259                     result[++ri] = n;
11260                 }
11261             }
11262         // Sibling mode (~)
11263         // E ~ F all elements with the tag F that are preceded by a sibling element with the tag E
11264         }else if(mode == "~"){
11265             var utag = tagName.toUpperCase();
11266             for(var i = 0, n; n = ns[i]; i++){
11267                 while((n = n.nextSibling)){
11268                     if (n.nodeName == utag || n.nodeName == tagName || tagName == '*'){
11269                         result[++ri] = n;
11270                     }
11271                 }
11272             }
11273         }
11274         return result;
11275     }
11276
11277     function concat(a, b){
11278         if(b.slice){
11279             return a.concat(b);
11280         }
11281         for(var i = 0, l = b.length; i < l; i++){
11282             a[a.length] = b[i];
11283         }
11284         return a;
11285     }
11286
11287     function byTag(cs, tagName){
11288         if(cs.tagName || cs == document){
11289             cs = [cs];
11290         }
11291         if(!tagName){
11292             return cs;
11293         }
11294         var result = [], ri = -1;
11295         tagName = tagName.toLowerCase();
11296         for(var i = 0, ci; ci = cs[i]; i++){
11297             if(ci.nodeType == 1 && ci.tagName.toLowerCase() == tagName){
11298                 result[++ri] = ci;
11299             }
11300         }
11301         return result;
11302     }
11303
11304     function byId(cs, id){
11305         if(cs.tagName || cs == document){
11306             cs = [cs];
11307         }
11308         if(!id){
11309             return cs;
11310         }
11311         var result = [], ri = -1;
11312         for(var i = 0, ci; ci = cs[i]; i++){
11313             if(ci && ci.id == id){
11314                 result[++ri] = ci;
11315                 return result;
11316             }
11317         }
11318         return result;
11319     }
11320
11321     // operators are =, !=, ^=, $=, *=, %=, |= and ~=
11322     // custom can be "{"
11323     function byAttribute(cs, attr, value, op, custom){
11324         var result = [],
11325             ri = -1,
11326             useGetStyle = custom == "{",
11327             fn = Ext.DomQuery.operators[op],
11328             a,
11329             xml,
11330             hasXml;
11331
11332         for(var i = 0, ci; ci = cs[i]; i++){
11333             // skip non-element nodes.
11334             if(ci.nodeType != 1){
11335                 continue;
11336             }
11337             // only need to do this for the first node
11338             if(!hasXml){
11339                 xml = Ext.DomQuery.isXml(ci);
11340                 hasXml = true;
11341             }
11342
11343             // we only need to change the property names if we're dealing with html nodes, not XML
11344             if(!xml){
11345                 if(useGetStyle){
11346                     a = Ext.DomQuery.getStyle(ci, attr);
11347                 } else if (attr == "class" || attr == "className"){
11348                     a = ci.className;
11349                 } else if (attr == "for"){
11350                     a = ci.htmlFor;
11351                 } else if (attr == "href"){
11352                     // getAttribute href bug
11353                     // http://www.glennjones.net/Post/809/getAttributehrefbug.htm
11354                     a = ci.getAttribute("href", 2);
11355                 } else{
11356                     a = ci.getAttribute(attr);
11357                 }
11358             }else{
11359                 a = ci.getAttribute(attr);
11360             }
11361             if((fn && fn(a, value)) || (!fn && a)){
11362                 result[++ri] = ci;
11363             }
11364         }
11365         return result;
11366     }
11367
11368     function byPseudo(cs, name, value){
11369         return Ext.DomQuery.pseudos[name](cs, value);
11370     }
11371
11372     function nodupIEXml(cs){
11373         var d = ++key,
11374             r;
11375         cs[0].setAttribute("_nodup", d);
11376         r = [cs[0]];
11377         for(var i = 1, len = cs.length; i < len; i++){
11378             var c = cs[i];
11379             if(!c.getAttribute("_nodup") != d){
11380                 c.setAttribute("_nodup", d);
11381                 r[r.length] = c;
11382             }
11383         }
11384         for(var i = 0, len = cs.length; i < len; i++){
11385             cs[i].removeAttribute("_nodup");
11386         }
11387         return r;
11388     }
11389
11390     function nodup(cs){
11391         if(!cs){
11392             return [];
11393         }
11394         var len = cs.length, c, i, r = cs, cj, ri = -1;
11395         if(!len || typeof cs.nodeType != "undefined" || len == 1){
11396             return cs;
11397         }
11398         if(isIE && typeof cs[0].selectSingleNode != "undefined"){
11399             return nodupIEXml(cs);
11400         }
11401         var d = ++key;
11402         cs[0]._nodup = d;
11403         for(i = 1; c = cs[i]; i++){
11404             if(c._nodup != d){
11405                 c._nodup = d;
11406             }else{
11407                 r = [];
11408                 for(var j = 0; j < i; j++){
11409                     r[++ri] = cs[j];
11410                 }
11411                 for(j = i+1; cj = cs[j]; j++){
11412                     if(cj._nodup != d){
11413                         cj._nodup = d;
11414                         r[++ri] = cj;
11415                     }
11416                 }
11417                 return r;
11418             }
11419         }
11420         return r;
11421     }
11422
11423     function quickDiffIEXml(c1, c2){
11424         var d = ++key,
11425             r = [];
11426         for(var i = 0, len = c1.length; i < len; i++){
11427             c1[i].setAttribute("_qdiff", d);
11428         }
11429         for(var i = 0, len = c2.length; i < len; i++){
11430             if(c2[i].getAttribute("_qdiff") != d){
11431                 r[r.length] = c2[i];
11432             }
11433         }
11434         for(var i = 0, len = c1.length; i < len; i++){
11435            c1[i].removeAttribute("_qdiff");
11436         }
11437         return r;
11438     }
11439
11440     function quickDiff(c1, c2){
11441         var len1 = c1.length,
11442             d = ++key,
11443             r = [];
11444         if(!len1){
11445             return c2;
11446         }
11447         if(isIE && typeof c1[0].selectSingleNode != "undefined"){
11448             return quickDiffIEXml(c1, c2);
11449         }
11450         for(var i = 0; i < len1; i++){
11451             c1[i]._qdiff = d;
11452         }
11453         for(var i = 0, len = c2.length; i < len; i++){
11454             if(c2[i]._qdiff != d){
11455                 r[r.length] = c2[i];
11456             }
11457         }
11458         return r;
11459     }
11460
11461     function quickId(ns, mode, root, id){
11462         if(ns == root){
11463            var d = root.ownerDocument || root;
11464            return d.getElementById(id);
11465         }
11466         ns = getNodes(ns, mode, "*");
11467         return byId(ns, id);
11468     }
11469
11470     return {
11471         getStyle : function(el, name){
11472             return Ext.fly(el).getStyle(name);
11473         },
11474         /**
11475          * Compiles a selector/xpath query into a reusable function. The returned function
11476          * takes one parameter "root" (optional), which is the context node from where the query should start.
11477          * @param {String} selector The selector/xpath query
11478          * @param {String} type (optional) Either "select" (the default) or "simple" for a simple selector match
11479          * @return {Function}
11480          */
11481         compile : function(path, type){
11482             type = type || "select";
11483
11484             // setup fn preamble
11485             var fn = ["var f = function(root){\n var mode; ++batch; var n = root || document;\n"],
11486                 mode,
11487                 lastPath,
11488                 matchers = Ext.DomQuery.matchers,
11489                 matchersLn = matchers.length,
11490                 modeMatch,
11491                 // accept leading mode switch
11492                 lmode = path.match(modeRe);
11493
11494             if(lmode && lmode[1]){
11495                 fn[fn.length] = 'mode="'+lmode[1].replace(trimRe, "")+'";';
11496                 path = path.replace(lmode[1], "");
11497             }
11498
11499             // strip leading slashes
11500             while(path.substr(0, 1)=="/"){
11501                 path = path.substr(1);
11502             }
11503
11504             while(path && lastPath != path){
11505                 lastPath = path;
11506                 var tokenMatch = path.match(tagTokenRe);
11507                 if(type == "select"){
11508                     if(tokenMatch){
11509                         // ID Selector
11510                         if(tokenMatch[1] == "#"){
11511                             fn[fn.length] = 'n = quickId(n, mode, root, "'+tokenMatch[2]+'");';
11512                         }else{
11513                             fn[fn.length] = 'n = getNodes(n, mode, "'+tokenMatch[2]+'");';
11514                         }
11515                         path = path.replace(tokenMatch[0], "");
11516                     }else if(path.substr(0, 1) != '@'){
11517                         fn[fn.length] = 'n = getNodes(n, mode, "*");';
11518                     }
11519                 // type of "simple"
11520                 }else{
11521                     if(tokenMatch){
11522                         if(tokenMatch[1] == "#"){
11523                             fn[fn.length] = 'n = byId(n, "'+tokenMatch[2]+'");';
11524                         }else{
11525                             fn[fn.length] = 'n = byTag(n, "'+tokenMatch[2]+'");';
11526                         }
11527                         path = path.replace(tokenMatch[0], "");
11528                     }
11529                 }
11530                 while(!(modeMatch = path.match(modeRe))){
11531                     var matched = false;
11532                     for(var j = 0; j < matchersLn; j++){
11533                         var t = matchers[j];
11534                         var m = path.match(t.re);
11535                         if(m){
11536                             fn[fn.length] = t.select.replace(tplRe, function(x, i){
11537                                 return m[i];
11538                             });
11539                             path = path.replace(m[0], "");
11540                             matched = true;
11541                             break;
11542                         }
11543                     }
11544                     // prevent infinite loop on bad selector
11545                     if(!matched){
11546                     }
11547                 }
11548                 if(modeMatch[1]){
11549                     fn[fn.length] = 'mode="'+modeMatch[1].replace(trimRe, "")+'";';
11550                     path = path.replace(modeMatch[1], "");
11551                 }
11552             }
11553             // close fn out
11554             fn[fn.length] = "return nodup(n);\n}";
11555
11556             // eval fn and return it
11557             eval(fn.join(""));
11558             return f;
11559         },
11560
11561         /**
11562          * Selects an array of DOM nodes using JavaScript-only implementation.
11563          *
11564          * Use {@link #select} to take advantage of browsers built-in support for CSS selectors.
11565          *
11566          * @param {String} selector The selector/xpath query (can be a comma separated list of selectors)
11567          * @param {Node/String} root (optional) The start of the query (defaults to document).
11568          * @return {Array} An Array of DOM elements which match the selector. If there are
11569          * no matches, and empty Array is returned.
11570          */
11571         jsSelect: function(path, root, type){
11572             // set root to doc if not specified.
11573             root = root || document;
11574
11575             if(typeof root == "string"){
11576                 root = document.getElementById(root);
11577             }
11578             var paths = path.split(","),
11579                 results = [];
11580
11581             // loop over each selector
11582             for(var i = 0, len = paths.length; i < len; i++){
11583                 var subPath = paths[i].replace(trimRe, "");
11584                 // compile and place in cache
11585                 if(!cache[subPath]){
11586                     cache[subPath] = Ext.DomQuery.compile(subPath);
11587                     if(!cache[subPath]){
11588                     }
11589                 }
11590                 var result = cache[subPath](root);
11591                 if(result && result != document){
11592                     results = results.concat(result);
11593                 }
11594             }
11595
11596             // if there were multiple selectors, make sure dups
11597             // are eliminated
11598             if(paths.length > 1){
11599                 return nodup(results);
11600             }
11601             return results;
11602         },
11603
11604         isXml: function(el) {
11605             var docEl = (el ? el.ownerDocument || el : 0).documentElement;
11606             return docEl ? docEl.nodeName !== "HTML" : false;
11607         },
11608
11609         /**
11610          * Selects an array of DOM nodes by CSS/XPath selector.
11611          *
11612          * Uses [document.querySelectorAll][0] if browser supports that, otherwise falls back to
11613          * {@link #jsSelect} to do the work.
11614          * 
11615          * Aliased as {@link Ext#query}.
11616          * 
11617          * [0]: https://developer.mozilla.org/en/DOM/document.querySelectorAll
11618          *
11619          * @param {String} path The selector/xpath query
11620          * @param {Node} root (optional) The start of the query (defaults to document).
11621          * @return {Array} An array of DOM elements (not a NodeList as returned by `querySelectorAll`).
11622          * Empty array when no matches.
11623          * @method
11624          */
11625         select : document.querySelectorAll ? function(path, root, type) {
11626             root = root || document;
11627             if (!Ext.DomQuery.isXml(root)) {
11628             try {
11629                 var cs = root.querySelectorAll(path);
11630                 return Ext.Array.toArray(cs);
11631             }
11632             catch (ex) {}
11633             }
11634             return Ext.DomQuery.jsSelect.call(this, path, root, type);
11635         } : function(path, root, type) {
11636             return Ext.DomQuery.jsSelect.call(this, path, root, type);
11637         },
11638
11639         /**
11640          * Selects a single element.
11641          * @param {String} selector The selector/xpath query
11642          * @param {Node} root (optional) The start of the query (defaults to document).
11643          * @return {Element} The DOM element which matched the selector.
11644          */
11645         selectNode : function(path, root){
11646             return Ext.DomQuery.select(path, root)[0];
11647         },
11648
11649         /**
11650          * Selects the value of a node, optionally replacing null with the defaultValue.
11651          * @param {String} selector The selector/xpath query
11652          * @param {Node} root (optional) The start of the query (defaults to document).
11653          * @param {String} defaultValue
11654          * @return {String}
11655          */
11656         selectValue : function(path, root, defaultValue){
11657             path = path.replace(trimRe, "");
11658             if(!valueCache[path]){
11659                 valueCache[path] = Ext.DomQuery.compile(path, "select");
11660             }
11661             var n = valueCache[path](root), v;
11662             n = n[0] ? n[0] : n;
11663
11664             // overcome a limitation of maximum textnode size
11665             // Rumored to potentially crash IE6 but has not been confirmed.
11666             // http://reference.sitepoint.com/javascript/Node/normalize
11667             // https://developer.mozilla.org/En/DOM/Node.normalize
11668             if (typeof n.normalize == 'function') n.normalize();
11669
11670             v = (n && n.firstChild ? n.firstChild.nodeValue : null);
11671             return ((v === null||v === undefined||v==='') ? defaultValue : v);
11672         },
11673
11674         /**
11675          * Selects the value of a node, parsing integers and floats. Returns the defaultValue, or 0 if none is specified.
11676          * @param {String} selector The selector/xpath query
11677          * @param {Node} root (optional) The start of the query (defaults to document).
11678          * @param {Number} defaultValue
11679          * @return {Number}
11680          */
11681         selectNumber : function(path, root, defaultValue){
11682             var v = Ext.DomQuery.selectValue(path, root, defaultValue || 0);
11683             return parseFloat(v);
11684         },
11685
11686         /**
11687          * Returns true if the passed element(s) match the passed simple selector (e.g. div.some-class or span:first-child)
11688          * @param {String/HTMLElement/Array} el An element id, element or array of elements
11689          * @param {String} selector The simple selector to test
11690          * @return {Boolean}
11691          */
11692         is : function(el, ss){
11693             if(typeof el == "string"){
11694                 el = document.getElementById(el);
11695             }
11696             var isArray = Ext.isArray(el),
11697                 result = Ext.DomQuery.filter(isArray ? el : [el], ss);
11698             return isArray ? (result.length == el.length) : (result.length > 0);
11699         },
11700
11701         /**
11702          * Filters an array of elements to only include matches of a simple selector (e.g. div.some-class or span:first-child)
11703          * @param {Array} el An array of elements to filter
11704          * @param {String} selector The simple selector to test
11705          * @param {Boolean} nonMatches If true, it returns the elements that DON'T match
11706          * the selector instead of the ones that match
11707          * @return {Array} An Array of DOM elements which match the selector. If there are
11708          * no matches, and empty Array is returned.
11709          */
11710         filter : function(els, ss, nonMatches){
11711             ss = ss.replace(trimRe, "");
11712             if(!simpleCache[ss]){
11713                 simpleCache[ss] = Ext.DomQuery.compile(ss, "simple");
11714             }
11715             var result = simpleCache[ss](els);
11716             return nonMatches ? quickDiff(result, els) : result;
11717         },
11718
11719         /**
11720          * Collection of matching regular expressions and code snippets.
11721          * Each capture group within () will be replace the {} in the select
11722          * statement as specified by their index.
11723          */
11724         matchers : [{
11725                 re: /^\.([\w-]+)/,
11726                 select: 'n = byClassName(n, " {1} ");'
11727             }, {
11728                 re: /^\:([\w-]+)(?:\(((?:[^\s>\/]*|.*?))\))?/,
11729                 select: 'n = byPseudo(n, "{1}", "{2}");'
11730             },{
11731                 re: /^(?:([\[\{])(?:@)?([\w-]+)\s?(?:(=|.=)\s?['"]?(.*?)["']?)?[\]\}])/,
11732                 select: 'n = byAttribute(n, "{2}", "{4}", "{3}", "{1}");'
11733             }, {
11734                 re: /^#([\w-]+)/,
11735                 select: 'n = byId(n, "{1}");'
11736             },{
11737                 re: /^@([\w-]+)/,
11738                 select: 'return {firstChild:{nodeValue:attrValue(n, "{1}")}};'
11739             }
11740         ],
11741
11742         /**
11743          * Collection of operator comparison functions. The default operators are =, !=, ^=, $=, *=, %=, |= and ~=.
11744          * 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;.
11745          */
11746         operators : {
11747             "=" : function(a, v){
11748                 return a == v;
11749             },
11750             "!=" : function(a, v){
11751                 return a != v;
11752             },
11753             "^=" : function(a, v){
11754                 return a && a.substr(0, v.length) == v;
11755             },
11756             "$=" : function(a, v){
11757                 return a && a.substr(a.length-v.length) == v;
11758             },
11759             "*=" : function(a, v){
11760                 return a && a.indexOf(v) !== -1;
11761             },
11762             "%=" : function(a, v){
11763                 return (a % v) == 0;
11764             },
11765             "|=" : function(a, v){
11766                 return a && (a == v || a.substr(0, v.length+1) == v+'-');
11767             },
11768             "~=" : function(a, v){
11769                 return a && (' '+a+' ').indexOf(' '+v+' ') != -1;
11770             }
11771         },
11772
11773         /**
11774 Object hash of "pseudo class" filter functions which are used when filtering selections. 
11775 Each function is passed two parameters:
11776
11777 - **c** : Array
11778     An Array of DOM elements to filter.
11779     
11780 - **v** : String
11781     The argument (if any) supplied in the selector.
11782
11783 A filter function returns an Array of DOM elements which conform to the pseudo class.
11784 In addition to the provided pseudo classes listed above such as `first-child` and `nth-child`,
11785 developers may add additional, custom psuedo class filters to select elements according to application-specific requirements.
11786
11787 For example, to filter `a` elements to only return links to __external__ resources:
11788
11789     Ext.DomQuery.pseudos.external = function(c, v){
11790         var r = [], ri = -1;
11791         for(var i = 0, ci; ci = c[i]; i++){
11792             // Include in result set only if it's a link to an external resource
11793             if(ci.hostname != location.hostname){
11794                 r[++ri] = ci;
11795             }
11796         }
11797         return r;
11798     };
11799
11800 Then external links could be gathered with the following statement:
11801
11802     var externalLinks = Ext.select("a:external");
11803
11804         * @markdown
11805         */
11806         pseudos : {
11807             "first-child" : function(c){
11808                 var r = [], ri = -1, n;
11809                 for(var i = 0, ci; ci = n = c[i]; i++){
11810                     while((n = n.previousSibling) && n.nodeType != 1);
11811                     if(!n){
11812                         r[++ri] = ci;
11813                     }
11814                 }
11815                 return r;
11816             },
11817
11818             "last-child" : function(c){
11819                 var r = [], ri = -1, n;
11820                 for(var i = 0, ci; ci = n = c[i]; i++){
11821                     while((n = n.nextSibling) && n.nodeType != 1);
11822                     if(!n){
11823                         r[++ri] = ci;
11824                     }
11825                 }
11826                 return r;
11827             },
11828
11829             "nth-child" : function(c, a) {
11830                 var r = [], ri = -1,
11831                     m = nthRe.exec(a == "even" && "2n" || a == "odd" && "2n+1" || !nthRe2.test(a) && "n+" + a || a),
11832                     f = (m[1] || 1) - 0, l = m[2] - 0;
11833                 for(var i = 0, n; n = c[i]; i++){
11834                     var pn = n.parentNode;
11835                     if (batch != pn._batch) {
11836                         var j = 0;
11837                         for(var cn = pn.firstChild; cn; cn = cn.nextSibling){
11838                             if(cn.nodeType == 1){
11839                                cn.nodeIndex = ++j;
11840                             }
11841                         }
11842                         pn._batch = batch;
11843                     }
11844                     if (f == 1) {
11845                         if (l == 0 || n.nodeIndex == l){
11846                             r[++ri] = n;
11847                         }
11848                     } else if ((n.nodeIndex + l) % f == 0){
11849                         r[++ri] = n;
11850                     }
11851                 }
11852
11853                 return r;
11854             },
11855
11856             "only-child" : function(c){
11857                 var r = [], ri = -1;;
11858                 for(var i = 0, ci; ci = c[i]; i++){
11859                     if(!prev(ci) && !next(ci)){
11860                         r[++ri] = ci;
11861                     }
11862                 }
11863                 return r;
11864             },
11865
11866             "empty" : function(c){
11867                 var r = [], ri = -1;
11868                 for(var i = 0, ci; ci = c[i]; i++){
11869                     var cns = ci.childNodes, j = 0, cn, empty = true;
11870                     while(cn = cns[j]){
11871                         ++j;
11872                         if(cn.nodeType == 1 || cn.nodeType == 3){
11873                             empty = false;
11874                             break;
11875                         }
11876                     }
11877                     if(empty){
11878                         r[++ri] = ci;
11879                     }
11880                 }
11881                 return r;
11882             },
11883
11884             "contains" : function(c, v){
11885                 var r = [], ri = -1;
11886                 for(var i = 0, ci; ci = c[i]; i++){
11887                     if((ci.textContent||ci.innerText||'').indexOf(v) != -1){
11888                         r[++ri] = ci;
11889                     }
11890                 }
11891                 return r;
11892             },
11893
11894             "nodeValue" : function(c, v){
11895                 var r = [], ri = -1;
11896                 for(var i = 0, ci; ci = c[i]; i++){
11897                     if(ci.firstChild && ci.firstChild.nodeValue == v){
11898                         r[++ri] = ci;
11899                     }
11900                 }
11901                 return r;
11902             },
11903
11904             "checked" : function(c){
11905                 var r = [], ri = -1;
11906                 for(var i = 0, ci; ci = c[i]; i++){
11907                     if(ci.checked == true){
11908                         r[++ri] = ci;
11909                     }
11910                 }
11911                 return r;
11912             },
11913
11914             "not" : function(c, ss){
11915                 return Ext.DomQuery.filter(c, ss, true);
11916             },
11917
11918             "any" : function(c, selectors){
11919                 var ss = selectors.split('|'),
11920                     r = [], ri = -1, s;
11921                 for(var i = 0, ci; ci = c[i]; i++){
11922                     for(var j = 0; s = ss[j]; j++){
11923                         if(Ext.DomQuery.is(ci, s)){
11924                             r[++ri] = ci;
11925                             break;
11926                         }
11927                     }
11928                 }
11929                 return r;
11930             },
11931
11932             "odd" : function(c){
11933                 return this["nth-child"](c, "odd");
11934             },
11935
11936             "even" : function(c){
11937                 return this["nth-child"](c, "even");
11938             },
11939
11940             "nth" : function(c, a){
11941                 return c[a-1] || [];
11942             },
11943
11944             "first" : function(c){
11945                 return c[0] || [];
11946             },
11947
11948             "last" : function(c){
11949                 return c[c.length-1] || [];
11950             },
11951
11952             "has" : function(c, ss){
11953                 var s = Ext.DomQuery.select,
11954                     r = [], ri = -1;
11955                 for(var i = 0, ci; ci = c[i]; i++){
11956                     if(s(ss, ci).length > 0){
11957                         r[++ri] = ci;
11958                     }
11959                 }
11960                 return r;
11961             },
11962
11963             "next" : function(c, ss){
11964                 var is = Ext.DomQuery.is,
11965                     r = [], ri = -1;
11966                 for(var i = 0, ci; ci = c[i]; i++){
11967                     var n = next(ci);
11968                     if(n && is(n, ss)){
11969                         r[++ri] = ci;
11970                     }
11971                 }
11972                 return r;
11973             },
11974
11975             "prev" : function(c, ss){
11976                 var is = Ext.DomQuery.is,
11977                     r = [], ri = -1;
11978                 for(var i = 0, ci; ci = c[i]; i++){
11979                     var n = prev(ci);
11980                     if(n && is(n, ss)){
11981                         r[++ri] = ci;
11982                     }
11983                 }
11984                 return r;
11985             }
11986         }
11987     };
11988 }();
11989
11990 /**
11991  * Selects an array of DOM nodes by CSS/XPath selector. Shorthand of {@link Ext.DomQuery#select}
11992  * @param {String} path The selector/xpath query
11993  * @param {Node} root (optional) The start of the query (defaults to document).
11994  * @return {Array}
11995  * @member Ext
11996  * @method query
11997  */
11998 Ext.query = Ext.DomQuery.select;
11999
12000 /**
12001  * @class Ext.core.Element
12002  * <p>Encapsulates a DOM element, adding simple DOM manipulation facilities, normalizing for browser differences.</p>
12003  * <p>All instances of this class inherit the methods of {@link Ext.fx.Anim} making visual effects easily available to all DOM elements.</p>
12004  * <p>Note that the events documented in this class are not Ext events, they encapsulate browser events. To
12005  * access the underlying browser event, see {@link Ext.EventObject#browserEvent}. Some older
12006  * browsers may not support the full range of events. Which events are supported is beyond the control of ExtJs.</p>
12007  * Usage:<br>
12008 <pre><code>
12009 // by id
12010 var el = Ext.get("my-div");
12011
12012 // by DOM element reference
12013 var el = Ext.get(myDivElement);
12014 </code></pre>
12015  * <b>Animations</b><br />
12016  * <p>When an element is manipulated, by default there is no animation.</p>
12017  * <pre><code>
12018 var el = Ext.get("my-div");
12019
12020 // no animation
12021 el.setWidth(100);
12022  * </code></pre>
12023  * <p>Many of the functions for manipulating an element have an optional "animate" parameter.  This
12024  * parameter can be specified as boolean (<tt>true</tt>) for default animation effects.</p>
12025  * <pre><code>
12026 // default animation
12027 el.setWidth(100, true);
12028  * </code></pre>
12029  *
12030  * <p>To configure the effects, an object literal with animation options to use as the Element animation
12031  * configuration object can also be specified. Note that the supported Element animation configuration
12032  * options are a subset of the {@link Ext.fx.Anim} animation options specific to Fx effects.  The supported
12033  * Element animation configuration options are:</p>
12034 <pre>
12035 Option    Default   Description
12036 --------- --------  ---------------------------------------------
12037 {@link Ext.fx.Anim#duration duration}  .35       The duration of the animation in seconds
12038 {@link Ext.fx.Anim#easing easing}    easeOut   The easing method
12039 {@link Ext.fx.Anim#callback callback}  none      A function to execute when the anim completes
12040 {@link Ext.fx.Anim#scope scope}     this      The scope (this) of the callback function
12041 </pre>
12042  *
12043  * <pre><code>
12044 // Element animation options object
12045 var opt = {
12046     {@link Ext.fx.Anim#duration duration}: 1,
12047     {@link Ext.fx.Anim#easing easing}: 'elasticIn',
12048     {@link Ext.fx.Anim#callback callback}: this.foo,
12049     {@link Ext.fx.Anim#scope scope}: this
12050 };
12051 // animation with some options set
12052 el.setWidth(100, opt);
12053  * </code></pre>
12054  * <p>The Element animation object being used for the animation will be set on the options
12055  * object as "anim", which allows you to stop or manipulate the animation. Here is an example:</p>
12056  * <pre><code>
12057 // using the "anim" property to get the Anim object
12058 if(opt.anim.isAnimated()){
12059     opt.anim.stop();
12060 }
12061  * </code></pre>
12062  * <p>Also see the <tt>{@link #animate}</tt> method for another animation technique.</p>
12063  * <p><b> Composite (Collections of) Elements</b></p>
12064  * <p>For working with collections of Elements, see {@link Ext.CompositeElement}</p>
12065  * @constructor Create a new Element directly.
12066  * @param {String/HTMLElement} element
12067  * @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).
12068  */
12069  (function() {
12070     var DOC = document,
12071         EC = Ext.cache;
12072
12073     Ext.Element = Ext.core.Element = function(element, forceNew) {
12074         var dom = typeof element == "string" ? DOC.getElementById(element) : element,
12075         id;
12076
12077         if (!dom) {
12078             return null;
12079         }
12080
12081         id = dom.id;
12082
12083         if (!forceNew && id && EC[id]) {
12084             // element object already exists
12085             return EC[id].el;
12086         }
12087
12088         /**
12089      * The DOM element
12090      * @type HTMLElement
12091      */
12092         this.dom = dom;
12093
12094         /**
12095      * The DOM element ID
12096      * @type String
12097      */
12098         this.id = id || Ext.id(dom);
12099     };
12100
12101     var DH = Ext.core.DomHelper,
12102     El = Ext.core.Element;
12103
12104
12105     El.prototype = {
12106         /**
12107      * Sets the passed attributes as attributes of this element (a style attribute can be a string, object or function)
12108      * @param {Object} o The object with the attributes
12109      * @param {Boolean} useSet (optional) false to override the default setAttribute to use expandos.
12110      * @return {Ext.core.Element} this
12111      */
12112         set: function(o, useSet) {
12113             var el = this.dom,
12114                 attr,
12115                 val;
12116             useSet = (useSet !== false) && !!el.setAttribute;
12117
12118             for (attr in o) {
12119                 if (o.hasOwnProperty(attr)) {
12120                     val = o[attr];
12121                     if (attr == 'style') {
12122                         DH.applyStyles(el, val);
12123                     } else if (attr == 'cls') {
12124                         el.className = val;
12125                     } else if (useSet) {
12126                         el.setAttribute(attr, val);
12127                     } else {
12128                         el[attr] = val;
12129                     }
12130                 }
12131             }
12132             return this;
12133         },
12134
12135         //  Mouse events
12136         /**
12137      * @event click
12138      * Fires when a mouse click is detected within the element.
12139      * @param {Ext.EventObject} e The {@link Ext.EventObject} encapsulating the DOM event.
12140      * @param {HtmlElement} t The target of the event.
12141      * @param {Object} o The options configuration passed to the {@link #addListener} call.
12142      */
12143         /**
12144      * @event contextmenu
12145      * Fires when a right click is detected within the element.
12146      * @param {Ext.EventObject} e The {@link Ext.EventObject} encapsulating the DOM event.
12147      * @param {HtmlElement} t The target of the event.
12148      * @param {Object} o The options configuration passed to the {@link #addListener} call.
12149      */
12150         /**
12151      * @event dblclick
12152      * Fires when a mouse double click is detected within the element.
12153      * @param {Ext.EventObject} e The {@link Ext.EventObject} encapsulating the DOM event.
12154      * @param {HtmlElement} t The target of the event.
12155      * @param {Object} o The options configuration passed to the {@link #addListener} call.
12156      */
12157         /**
12158      * @event mousedown
12159      * Fires when a mousedown is detected within the element.
12160      * @param {Ext.EventObject} e The {@link Ext.EventObject} encapsulating the DOM event.
12161      * @param {HtmlElement} t The target of the event.
12162      * @param {Object} o The options configuration passed to the {@link #addListener} call.
12163      */
12164         /**
12165      * @event mouseup
12166      * Fires when a mouseup is detected within the element.
12167      * @param {Ext.EventObject} e The {@link Ext.EventObject} encapsulating the DOM event.
12168      * @param {HtmlElement} t The target of the event.
12169      * @param {Object} o The options configuration passed to the {@link #addListener} call.
12170      */
12171         /**
12172      * @event mouseover
12173      * Fires when a mouseover is detected within the element.
12174      * @param {Ext.EventObject} e The {@link Ext.EventObject} encapsulating the DOM event.
12175      * @param {HtmlElement} t The target of the event.
12176      * @param {Object} o The options configuration passed to the {@link #addListener} call.
12177      */
12178         /**
12179      * @event mousemove
12180      * Fires when a mousemove is detected with the element.
12181      * @param {Ext.EventObject} e The {@link Ext.EventObject} encapsulating the DOM event.
12182      * @param {HtmlElement} t The target of the event.
12183      * @param {Object} o The options configuration passed to the {@link #addListener} call.
12184      */
12185         /**
12186      * @event mouseout
12187      * Fires when a mouseout is detected with the element.
12188      * @param {Ext.EventObject} e The {@link Ext.EventObject} encapsulating the DOM event.
12189      * @param {HtmlElement} t The target of the event.
12190      * @param {Object} o The options configuration passed to the {@link #addListener} call.
12191      */
12192         /**
12193      * @event mouseenter
12194      * Fires when the mouse enters the element.
12195      * @param {Ext.EventObject} e The {@link Ext.EventObject} encapsulating the DOM event.
12196      * @param {HtmlElement} t The target of the event.
12197      * @param {Object} o The options configuration passed to the {@link #addListener} call.
12198      */
12199         /**
12200      * @event mouseleave
12201      * Fires when the mouse leaves the element.
12202      * @param {Ext.EventObject} e The {@link Ext.EventObject} encapsulating the DOM event.
12203      * @param {HtmlElement} t The target of the event.
12204      * @param {Object} o The options configuration passed to the {@link #addListener} call.
12205      */
12206
12207         //  Keyboard events
12208         /**
12209      * @event keypress
12210      * Fires when a keypress is detected within the element.
12211      * @param {Ext.EventObject} e The {@link Ext.EventObject} encapsulating the DOM event.
12212      * @param {HtmlElement} t The target of the event.
12213      * @param {Object} o The options configuration passed to the {@link #addListener} call.
12214      */
12215         /**
12216      * @event keydown
12217      * Fires when a keydown is detected within the element.
12218      * @param {Ext.EventObject} e The {@link Ext.EventObject} encapsulating the DOM event.
12219      * @param {HtmlElement} t The target of the event.
12220      * @param {Object} o The options configuration passed to the {@link #addListener} call.
12221      */
12222         /**
12223      * @event keyup
12224      * Fires when a keyup is detected within the element.
12225      * @param {Ext.EventObject} e The {@link Ext.EventObject} encapsulating the DOM event.
12226      * @param {HtmlElement} t The target of the event.
12227      * @param {Object} o The options configuration passed to the {@link #addListener} call.
12228      */
12229
12230
12231         //  HTML frame/object events
12232         /**
12233      * @event load
12234      * Fires when the user agent finishes loading all content within the element. Only supported by window, frames, objects and images.
12235      * @param {Ext.EventObject} e The {@link Ext.EventObject} encapsulating the DOM event.
12236      * @param {HtmlElement} t The target of the event.
12237      * @param {Object} o The options configuration passed to the {@link #addListener} call.
12238      */
12239         /**
12240      * @event unload
12241      * 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.
12242      * @param {Ext.EventObject} e The {@link Ext.EventObject} encapsulating the DOM event.
12243      * @param {HtmlElement} t The target of the event.
12244      * @param {Object} o The options configuration passed to the {@link #addListener} call.
12245      */
12246         /**
12247      * @event abort
12248      * Fires when an object/image is stopped from loading before completely loaded.
12249      * @param {Ext.EventObject} e The {@link Ext.EventObject} encapsulating the DOM event.
12250      * @param {HtmlElement} t The target of the event.
12251      * @param {Object} o The options configuration passed to the {@link #addListener} call.
12252      */
12253         /**
12254      * @event error
12255      * Fires when an object/image/frame cannot be loaded properly.
12256      * @param {Ext.EventObject} e The {@link Ext.EventObject} encapsulating the DOM event.
12257      * @param {HtmlElement} t The target of the event.
12258      * @param {Object} o The options configuration passed to the {@link #addListener} call.
12259      */
12260         /**
12261      * @event resize
12262      * Fires when a document view is resized.
12263      * @param {Ext.EventObject} e The {@link Ext.EventObject} encapsulating the DOM event.
12264      * @param {HtmlElement} t The target of the event.
12265      * @param {Object} o The options configuration passed to the {@link #addListener} call.
12266      */
12267         /**
12268      * @event scroll
12269      * Fires when a document view is scrolled.
12270      * @param {Ext.EventObject} e The {@link Ext.EventObject} encapsulating the DOM event.
12271      * @param {HtmlElement} t The target of the event.
12272      * @param {Object} o The options configuration passed to the {@link #addListener} call.
12273      */
12274
12275         //  Form events
12276         /**
12277      * @event select
12278      * Fires when a user selects some text in a text field, including input and textarea.
12279      * @param {Ext.EventObject} e The {@link Ext.EventObject} encapsulating the DOM event.
12280      * @param {HtmlElement} t The target of the event.
12281      * @param {Object} o The options configuration passed to the {@link #addListener} call.
12282      */
12283         /**
12284      * @event change
12285      * Fires when a control loses the input focus and its value has been modified since gaining focus.
12286      * @param {Ext.EventObject} e The {@link Ext.EventObject} encapsulating the DOM event.
12287      * @param {HtmlElement} t The target of the event.
12288      * @param {Object} o The options configuration passed to the {@link #addListener} call.
12289      */
12290         /**
12291      * @event submit
12292      * Fires when a form is submitted.
12293      * @param {Ext.EventObject} e The {@link Ext.EventObject} encapsulating the DOM event.
12294      * @param {HtmlElement} t The target of the event.
12295      * @param {Object} o The options configuration passed to the {@link #addListener} call.
12296      */
12297         /**
12298      * @event reset
12299      * Fires when a form is reset.
12300      * @param {Ext.EventObject} e The {@link Ext.EventObject} encapsulating the DOM event.
12301      * @param {HtmlElement} t The target of the event.
12302      * @param {Object} o The options configuration passed to the {@link #addListener} call.
12303      */
12304         /**
12305      * @event focus
12306      * Fires when an element receives focus either via the pointing device or by tab navigation.
12307      * @param {Ext.EventObject} e The {@link Ext.EventObject} encapsulating the DOM event.
12308      * @param {HtmlElement} t The target of the event.
12309      * @param {Object} o The options configuration passed to the {@link #addListener} call.
12310      */
12311         /**
12312      * @event blur
12313      * Fires when an element loses focus either via the pointing device or by tabbing navigation.
12314      * @param {Ext.EventObject} e The {@link Ext.EventObject} encapsulating the DOM event.
12315      * @param {HtmlElement} t The target of the event.
12316      * @param {Object} o The options configuration passed to the {@link #addListener} call.
12317      */
12318
12319         //  User Interface events
12320         /**
12321      * @event DOMFocusIn
12322      * Where supported. Similar to HTML focus event, but can be applied to any focusable element.
12323      * @param {Ext.EventObject} e The {@link Ext.EventObject} encapsulating the DOM event.
12324      * @param {HtmlElement} t The target of the event.
12325      * @param {Object} o The options configuration passed to the {@link #addListener} call.
12326      */
12327         /**
12328      * @event DOMFocusOut
12329      * Where supported. Similar to HTML blur event, but can be applied to any focusable element.
12330      * @param {Ext.EventObject} e The {@link Ext.EventObject} encapsulating the DOM event.
12331      * @param {HtmlElement} t The target of the event.
12332      * @param {Object} o The options configuration passed to the {@link #addListener} call.
12333      */
12334         /**
12335      * @event DOMActivate
12336      * Where supported. Fires when an element is activated, for instance, through a mouse click or a keypress.
12337      * @param {Ext.EventObject} e The {@link Ext.EventObject} encapsulating the DOM event.
12338      * @param {HtmlElement} t The target of the event.
12339      * @param {Object} o The options configuration passed to the {@link #addListener} call.
12340      */
12341
12342         //  DOM Mutation events
12343         /**
12344      * @event DOMSubtreeModified
12345      * Where supported. Fires when the subtree is modified.
12346      * @param {Ext.EventObject} e The {@link Ext.EventObject} encapsulating the DOM event.
12347      * @param {HtmlElement} t The target of the event.
12348      * @param {Object} o The options configuration passed to the {@link #addListener} call.
12349      */
12350         /**
12351      * @event DOMNodeInserted
12352      * Where supported. Fires when a node has been added as a child of another node.
12353      * @param {Ext.EventObject} e The {@link Ext.EventObject} encapsulating the DOM event.
12354      * @param {HtmlElement} t The target of the event.
12355      * @param {Object} o The options configuration passed to the {@link #addListener} call.
12356      */
12357         /**
12358      * @event DOMNodeRemoved
12359      * Where supported. Fires when a descendant node of the element is removed.
12360      * @param {Ext.EventObject} e The {@link Ext.EventObject} encapsulating the DOM event.
12361      * @param {HtmlElement} t The target of the event.
12362      * @param {Object} o The options configuration passed to the {@link #addListener} call.
12363      */
12364         /**
12365      * @event DOMNodeRemovedFromDocument
12366      * Where supported. Fires when a node is being removed from a document.
12367      * @param {Ext.EventObject} e The {@link Ext.EventObject} encapsulating the DOM event.
12368      * @param {HtmlElement} t The target of the event.
12369      * @param {Object} o The options configuration passed to the {@link #addListener} call.
12370      */
12371         /**
12372      * @event DOMNodeInsertedIntoDocument
12373      * Where supported. Fires when a node is being inserted into a document.
12374      * @param {Ext.EventObject} e The {@link Ext.EventObject} encapsulating the DOM event.
12375      * @param {HtmlElement} t The target of the event.
12376      * @param {Object} o The options configuration passed to the {@link #addListener} call.
12377      */
12378         /**
12379      * @event DOMAttrModified
12380      * Where supported. Fires when an attribute has been modified.
12381      * @param {Ext.EventObject} e The {@link Ext.EventObject} encapsulating the DOM event.
12382      * @param {HtmlElement} t The target of the event.
12383      * @param {Object} o The options configuration passed to the {@link #addListener} call.
12384      */
12385         /**
12386      * @event DOMCharacterDataModified
12387      * Where supported. Fires when the character data has been modified.
12388      * @param {Ext.EventObject} e The {@link Ext.EventObject} encapsulating the DOM event.
12389      * @param {HtmlElement} t The target of the event.
12390      * @param {Object} o The options configuration passed to the {@link #addListener} call.
12391      */
12392
12393         /**
12394      * The default unit to append to CSS values where a unit isn't provided (defaults to px).
12395      * @type String
12396      */
12397         defaultUnit: "px",
12398
12399         /**
12400      * Returns true if this element matches the passed simple selector (e.g. div.some-class or span:first-child)
12401      * @param {String} selector The simple selector to test
12402      * @return {Boolean} True if this element matches the selector, else false
12403      */
12404         is: function(simpleSelector) {
12405             return Ext.DomQuery.is(this.dom, simpleSelector);
12406         },
12407
12408         /**
12409      * Tries to focus the element. Any exceptions are caught and ignored.
12410      * @param {Number} defer (optional) Milliseconds to defer the focus
12411      * @return {Ext.core.Element} this
12412      */
12413         focus: function(defer,
12414                         /* private */
12415                         dom) {
12416             var me = this;
12417             dom = dom || me.dom;
12418             try {
12419                 if (Number(defer)) {
12420                     Ext.defer(me.focus, defer, null, [null, dom]);
12421                 } else {
12422                     dom.focus();
12423                 }
12424             } catch(e) {}
12425             return me;
12426         },
12427
12428         /**
12429      * Tries to blur the element. Any exceptions are caught and ignored.
12430      * @return {Ext.core.Element} this
12431      */
12432         blur: function() {
12433             try {
12434                 this.dom.blur();
12435             } catch(e) {}
12436             return this;
12437         },
12438
12439         /**
12440      * Returns the value of the "value" attribute
12441      * @param {Boolean} asNumber true to parse the value as a number
12442      * @return {String/Number}
12443      */
12444         getValue: function(asNumber) {
12445             var val = this.dom.value;
12446             return asNumber ? parseInt(val, 10) : val;
12447         },
12448
12449         /**
12450      * Appends an event handler to this element.  The shorthand version {@link #on} is equivalent.
12451      * @param {String} eventName The name of event to handle.
12452      * @param {Function} fn The handler function the event invokes. This function is passed
12453      * the following parameters:<ul>
12454      * <li><b>evt</b> : EventObject<div class="sub-desc">The {@link Ext.EventObject EventObject} describing the event.</div></li>
12455      * <li><b>el</b> : HtmlElement<div class="sub-desc">The DOM element which was the target of the event.
12456      * Note that this may be filtered by using the <tt>delegate</tt> option.</div></li>
12457      * <li><b>o</b> : Object<div class="sub-desc">The options object from the addListener call.</div></li>
12458      * </ul>
12459      * @param {Object} scope (optional) The scope (<code><b>this</b></code> reference) in which the handler function is executed.
12460      * <b>If omitted, defaults to this Element.</b>.
12461      * @param {Object} options (optional) An object containing handler configuration properties.
12462      * This may contain any of the following properties:<ul>
12463      * <li><b>scope</b> Object : <div class="sub-desc">The scope (<code><b>this</b></code> reference) in which the handler function is executed.
12464      * <b>If omitted, defaults to this Element.</b></div></li>
12465      * <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>
12466      * <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>
12467      * <li><b>preventDefault</b> Boolean: <div class="sub-desc">True to prevent the default action</div></li>
12468      * <li><b>stopPropagation</b> Boolean: <div class="sub-desc">True to prevent event propagation</div></li>
12469      * <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>
12470      * <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>
12471      * <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>
12472      * <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>
12473      * <li><b>buffer</b> Number: <div class="sub-desc">Causes the handler to be scheduled to run in an {@link Ext.util.DelayedTask} delayed
12474      * by the specified number of milliseconds. If the event fires again within that time, the original
12475      * handler is <em>not</em> invoked, but the new handler is scheduled in its place.</div></li>
12476      * </ul><br>
12477      * <p>
12478      * <b>Combining Options</b><br>
12479      * In the following examples, the shorthand form {@link #on} is used rather than the more verbose
12480      * addListener.  The two are equivalent.  Using the options argument, it is possible to combine different
12481      * types of listeners:<br>
12482      * <br>
12483      * A delayed, one-time listener that auto stops the event and adds a custom argument (forumId) to the
12484      * options object. The options object is available as the third parameter in the handler function.<div style="margin: 5px 20px 20px;">
12485      * Code:<pre><code>
12486 el.on('click', this.onClick, this, {
12487     single: true,
12488     delay: 100,
12489     stopEvent : true,
12490     forumId: 4
12491 });</code></pre></p>
12492      * <p>
12493      * <b>Attaching multiple handlers in 1 call</b><br>
12494      * The method also allows for a single argument to be passed which is a config object containing properties
12495      * which specify multiple handlers.</p>
12496      * <p>
12497      * Code:<pre><code>
12498 el.on({
12499     'click' : {
12500         fn: this.onClick,
12501         scope: this,
12502         delay: 100
12503     },
12504     'mouseover' : {
12505         fn: this.onMouseOver,
12506         scope: this
12507     },
12508     'mouseout' : {
12509         fn: this.onMouseOut,
12510         scope: this
12511     }
12512 });</code></pre>
12513      * <p>
12514      * Or a shorthand syntax:<br>
12515      * Code:<pre><code></p>
12516 el.on({
12517     'click' : this.onClick,
12518     'mouseover' : this.onMouseOver,
12519     'mouseout' : this.onMouseOut,
12520     scope: this
12521 });
12522      * </code></pre></p>
12523      * <p><b>delegate</b></p>
12524      * <p>This is a configuration option that you can pass along when registering a handler for
12525      * an event to assist with event delegation. Event delegation is a technique that is used to
12526      * reduce memory consumption and prevent exposure to memory-leaks. By registering an event
12527      * for a container element as opposed to each element within a container. By setting this
12528      * configuration option to a simple selector, the target element will be filtered to look for
12529      * a descendant of the target.
12530      * For example:<pre><code>
12531 // using this markup:
12532 &lt;div id='elId'>
12533     &lt;p id='p1'>paragraph one&lt;/p>
12534     &lt;p id='p2' class='clickable'>paragraph two&lt;/p>
12535     &lt;p id='p3'>paragraph three&lt;/p>
12536 &lt;/div>
12537 // utilize event delegation to registering just one handler on the container element:
12538 el = Ext.get('elId');
12539 el.on(
12540     'click',
12541     function(e,t) {
12542         // handle click
12543         console.info(t.id); // 'p2'
12544     },
12545     this,
12546     {
12547         // filter the target element to be a descendant with the class 'clickable'
12548         delegate: '.clickable'
12549     }
12550 );
12551      * </code></pre></p>
12552      * @return {Ext.core.Element} this
12553      */
12554         addListener: function(eventName, fn, scope, options) {
12555             Ext.EventManager.on(this.dom, eventName, fn, scope || this, options);
12556             return this;
12557         },
12558
12559         /**
12560      * Removes an event handler from this element.  The shorthand version {@link #un} is equivalent.
12561      * <b>Note</b>: if a <i>scope</i> was explicitly specified when {@link #addListener adding} the
12562      * listener, the same scope must be specified here.
12563      * Example:
12564      * <pre><code>
12565 el.removeListener('click', this.handlerFn);
12566 // or
12567 el.un('click', this.handlerFn);
12568 </code></pre>
12569      * @param {String} eventName The name of the event from which to remove the handler.
12570      * @param {Function} fn The handler function to remove. <b>This must be a reference to the function passed into the {@link #addListener} call.</b>
12571      * @param {Object} scope If a scope (<b><code>this</code></b> reference) was specified when the listener was added,
12572      * then this must refer to the same object.
12573      * @return {Ext.core.Element} this
12574      */
12575         removeListener: function(eventName, fn, scope) {
12576             Ext.EventManager.un(this.dom, eventName, fn, scope || this);
12577             return this;
12578         },
12579
12580         /**
12581      * Removes all previous added listeners from this element
12582      * @return {Ext.core.Element} this
12583      */
12584         removeAllListeners: function() {
12585             Ext.EventManager.removeAll(this.dom);
12586             return this;
12587         },
12588
12589         /**
12590          * Recursively removes all previous added listeners from this element and its children
12591          * @return {Ext.core.Element} this
12592          */
12593         purgeAllListeners: function() {
12594             Ext.EventManager.purgeElement(this);
12595             return this;
12596         },
12597
12598         /**
12599          * @private Test if size has a unit, otherwise appends the passed unit string, or the default for this Element.
12600          * @param size {Mixed} The size to set
12601          * @param units {String} The units to append to a numeric size value
12602          */
12603         addUnits: function(size, units) {
12604
12605             // Most common case first: Size is set to a number
12606             if (Ext.isNumber(size)) {
12607                 return size + (units || this.defaultUnit || 'px');
12608             }
12609
12610             // Size set to a value which means "auto"
12611             if (size === "" || size == "auto" || size === undefined || size === null) {
12612                 return size || '';
12613             }
12614
12615             // Otherwise, warn if it's not a valid CSS measurement
12616             if (!unitPattern.test(size)) {
12617                 return size || '';
12618             }
12619             return size;
12620         },
12621
12622         /**
12623          * Tests various css rules/browsers to determine if this element uses a border box
12624          * @return {Boolean}
12625          */
12626         isBorderBox: function() {
12627             return Ext.isBorderBox || noBoxAdjust[(this.dom.tagName || "").toLowerCase()];
12628         },
12629
12630         /**
12631          * <p>Removes this element's dom reference.  Note that event and cache removal is handled at {@link Ext#removeNode Ext.removeNode}</p>
12632          */
12633         remove: function() {
12634             var me = this,
12635             dom = me.dom;
12636
12637             if (dom) {
12638                 delete me.dom;
12639                 Ext.removeNode(dom);
12640             }
12641         },
12642
12643         /**
12644          * Sets up event handlers to call the passed functions when the mouse is moved into and out of the Element.
12645          * @param {Function} overFn The function to call when the mouse enters the Element.
12646          * @param {Function} outFn The function to call when the mouse leaves the Element.
12647          * @param {Object} scope (optional) The scope (<code>this</code> reference) in which the functions are executed. Defaults to the Element's DOM element.
12648          * @param {Object} options (optional) Options for the listener. See {@link Ext.util.Observable#addListener the <tt>options</tt> parameter}.
12649          * @return {Ext.core.Element} this
12650          */
12651         hover: function(overFn, outFn, scope, options) {
12652             var me = this;
12653             me.on('mouseenter', overFn, scope || me.dom, options);
12654             me.on('mouseleave', outFn, scope || me.dom, options);
12655             return me;
12656         },
12657
12658         /**
12659          * Returns true if this element is an ancestor of the passed element
12660          * @param {HTMLElement/String} el The element to check
12661          * @return {Boolean} True if this element is an ancestor of el, else false
12662          */
12663         contains: function(el) {
12664             return ! el ? false: Ext.core.Element.isAncestor(this.dom, el.dom ? el.dom: el);
12665         },
12666
12667         /**
12668          * Returns the value of a namespaced attribute from the element's underlying DOM node.
12669          * @param {String} namespace The namespace in which to look for the attribute
12670          * @param {String} name The attribute name
12671          * @return {String} The attribute value
12672          * @deprecated
12673          */
12674         getAttributeNS: function(ns, name) {
12675             return this.getAttribute(name, ns);
12676         },
12677
12678         /**
12679          * Returns the value of an attribute from the element's underlying DOM node.
12680          * @param {String} name The attribute name
12681          * @param {String} namespace (optional) The namespace in which to look for the attribute
12682          * @return {String} The attribute value
12683          * @method
12684          */
12685         getAttribute: (Ext.isIE && !(Ext.isIE9 && document.documentMode === 9)) ?
12686         function(name, ns) {
12687             var d = this.dom,
12688             type;
12689             if(ns) {
12690                 type = typeof d[ns + ":" + name];
12691                 if (type != 'undefined' && type != 'unknown') {
12692                     return d[ns + ":" + name] || null;
12693                 }
12694                 return null;
12695             }
12696             if (name === "for") {
12697                 name = "htmlFor";
12698             }
12699             return d[name] || null;
12700         }: function(name, ns) {
12701             var d = this.dom;
12702             if (ns) {
12703                return d.getAttributeNS(ns, name) || d.getAttribute(ns + ":" + name);
12704             }
12705             return  d.getAttribute(name) || d[name] || null;
12706         },
12707
12708         /**
12709          * Update the innerHTML of this element
12710          * @param {String} html The new HTML
12711          * @return {Ext.core.Element} this
12712          */
12713         update: function(html) {
12714             if (this.dom) {
12715                 this.dom.innerHTML = html;
12716             }
12717             return this;
12718         }
12719     };
12720
12721     var ep = El.prototype;
12722
12723     El.addMethods = function(o) {
12724         Ext.apply(ep, o);
12725     };
12726
12727     /**
12728      * Appends an event handler (shorthand for {@link #addListener}).
12729      * @param {String} eventName The name of event to handle.
12730      * @param {Function} fn The handler function the event invokes.
12731      * @param {Object} scope (optional) The scope (<code>this</code> reference) in which the handler function is executed.
12732      * @param {Object} options (optional) An object containing standard {@link #addListener} options
12733      * @member Ext.core.Element
12734      * @method on
12735      */
12736     ep.on = ep.addListener;
12737
12738     /**
12739      * Removes an event handler from this element (see {@link #removeListener} for additional notes).
12740      * @param {String} eventName The name of the event from which to remove the handler.
12741      * @param {Function} fn The handler function to remove. <b>This must be a reference to the function passed into the {@link #addListener} call.</b>
12742      * @param {Object} scope If a scope (<b><code>this</code></b> reference) was specified when the listener was added,
12743      * then this must refer to the same object.
12744      * @return {Ext.core.Element} this
12745      * @member Ext.core.Element
12746      * @method un
12747      */
12748     ep.un = ep.removeListener;
12749
12750     /**
12751      * Removes all previous added listeners from this element
12752      * @return {Ext.core.Element} this
12753      * @member Ext.core.Element
12754      * @method clearListeners
12755      */
12756     ep.clearListeners = ep.removeAllListeners;
12757
12758     /**
12759      * Removes this element's dom reference.  Note that event and cache removal is handled at {@link Ext#removeNode Ext.removeNode}.
12760      * Alias to {@link #remove}.
12761      * @member Ext.core.Element
12762      * @method destroy
12763      */
12764     ep.destroy = ep.remove;
12765
12766     /**
12767      * true to automatically adjust width and height settings for box-model issues (default to true)
12768      */
12769     ep.autoBoxAdjust = true;
12770
12771     // private
12772     var unitPattern = /\d+(px|em|%|en|ex|pt|in|cm|mm|pc)$/i,
12773     docEl;
12774
12775     /**
12776      * Retrieves Ext.core.Element objects.
12777      * <p><b>This method does not retrieve {@link Ext.Component Component}s.</b> This method
12778      * retrieves Ext.core.Element objects which encapsulate DOM elements. To retrieve a Component by
12779      * its ID, use {@link Ext.ComponentManager#get}.</p>
12780      * <p>Uses simple caching to consistently return the same object. Automatically fixes if an
12781      * object was recreated with the same id via AJAX or DOM.</p>
12782      * @param {Mixed} el The id of the node, a DOM Node or an existing Element.
12783      * @return {Element} The Element object (or null if no matching element was found)
12784      * @static
12785      * @member Ext.core.Element
12786      * @method get
12787      */
12788     El.get = function(el) {
12789         var ex,
12790         elm,
12791         id;
12792         if (!el) {
12793             return null;
12794         }
12795         if (typeof el == "string") {
12796             // element id
12797             if (! (elm = DOC.getElementById(el))) {
12798                 return null;
12799             }
12800             if (EC[el] && EC[el].el) {
12801                 ex = EC[el].el;
12802                 ex.dom = elm;
12803             } else {
12804                 ex = El.addToCache(new El(elm));
12805             }
12806             return ex;
12807         } else if (el.tagName) {
12808             // dom element
12809             if (! (id = el.id)) {
12810                 id = Ext.id(el);
12811             }
12812             if (EC[id] && EC[id].el) {
12813                 ex = EC[id].el;
12814                 ex.dom = el;
12815             } else {
12816                 ex = El.addToCache(new El(el));
12817             }
12818             return ex;
12819         } else if (el instanceof El) {
12820             if (el != docEl) {
12821                 // refresh dom element in case no longer valid,
12822                 // catch case where it hasn't been appended
12823                 // If an el instance is passed, don't pass to getElementById without some kind of id
12824                 if (Ext.isIE && (el.id == undefined || el.id == '')) {
12825                     el.dom = el.dom;
12826                 } else {
12827                     el.dom = DOC.getElementById(el.id) || el.dom;
12828                 }
12829             }
12830             return el;
12831         } else if (el.isComposite) {
12832             return el;
12833         } else if (Ext.isArray(el)) {
12834             return El.select(el);
12835         } else if (el == DOC) {
12836             // create a bogus element object representing the document object
12837             if (!docEl) {
12838                 var f = function() {};
12839                 f.prototype = El.prototype;
12840                 docEl = new f();
12841                 docEl.dom = DOC;
12842             }
12843             return docEl;
12844         }
12845         return null;
12846     };
12847
12848     El.addToCache = function(el, id) {
12849         if (el) {
12850             id = id || el.id;
12851             EC[id] = {
12852                 el: el,
12853                 data: {},
12854                 events: {}
12855             };
12856         }
12857         return el;
12858     };
12859
12860     // private method for getting and setting element data
12861     El.data = function(el, key, value) {
12862         el = El.get(el);
12863         if (!el) {
12864             return null;
12865         }
12866         var c = EC[el.id].data;
12867         if (arguments.length == 2) {
12868             return c[key];
12869         } else {
12870             return (c[key] = value);
12871         }
12872     };
12873
12874     // private
12875     // Garbage collection - uncache elements/purge listeners on orphaned elements
12876     // so we don't hold a reference and cause the browser to retain them
12877     function garbageCollect() {
12878         if (!Ext.enableGarbageCollector) {
12879             clearInterval(El.collectorThreadId);
12880         } else {
12881             var eid,
12882             el,
12883             d,
12884             o;
12885
12886             for (eid in EC) {
12887                 if (!EC.hasOwnProperty(eid)) {
12888                     continue;
12889                 }
12890                 o = EC[eid];
12891                 if (o.skipGarbageCollection) {
12892                     continue;
12893                 }
12894                 el = o.el;
12895                 d = el.dom;
12896                 // -------------------------------------------------------
12897                 // Determining what is garbage:
12898                 // -------------------------------------------------------
12899                 // !d
12900                 // dom node is null, definitely garbage
12901                 // -------------------------------------------------------
12902                 // !d.parentNode
12903                 // no parentNode == direct orphan, definitely garbage
12904                 // -------------------------------------------------------
12905                 // !d.offsetParent && !document.getElementById(eid)
12906                 // display none elements have no offsetParent so we will
12907                 // also try to look it up by it's id. However, check
12908                 // offsetParent first so we don't do unneeded lookups.
12909                 // This enables collection of elements that are not orphans
12910                 // directly, but somewhere up the line they have an orphan
12911                 // parent.
12912                 // -------------------------------------------------------
12913                 if (!d || !d.parentNode || (!d.offsetParent && !DOC.getElementById(eid))) {
12914                     if (d && Ext.enableListenerCollection) {
12915                         Ext.EventManager.removeAll(d);
12916                     }
12917                     delete EC[eid];
12918                 }
12919             }
12920             // Cleanup IE Object leaks
12921             if (Ext.isIE) {
12922                 var t = {};
12923                 for (eid in EC) {
12924                     if (!EC.hasOwnProperty(eid)) {
12925                         continue;
12926                     }
12927                     t[eid] = EC[eid];
12928                 }
12929                 EC = Ext.cache = t;
12930             }
12931         }
12932     }
12933     El.collectorThreadId = setInterval(garbageCollect, 30000);
12934
12935     var flyFn = function() {};
12936     flyFn.prototype = El.prototype;
12937
12938     // dom is optional
12939     El.Flyweight = function(dom) {
12940         this.dom = dom;
12941     };
12942
12943     El.Flyweight.prototype = new flyFn();
12944     El.Flyweight.prototype.isFlyweight = true;
12945     El._flyweights = {};
12946
12947     /**
12948      * <p>Gets the globally shared flyweight Element, with the passed node as the active element. Do not store a reference to this element -
12949      * the dom node can be overwritten by other code. Shorthand of {@link Ext.core.Element#fly}</p>
12950      * <p>Use this to make one-time references to DOM elements which are not going to be accessed again either by
12951      * application code, or by Ext's classes. If accessing an element which will be processed regularly, then {@link Ext#get Ext.get}
12952      * will be more appropriate to take advantage of the caching provided by the Ext.core.Element class.</p>
12953      * @param {String/HTMLElement} el The dom node or id
12954      * @param {String} named (optional) Allows for creation of named reusable flyweights to prevent conflicts
12955      * (e.g. internally Ext uses "_global")
12956      * @return {Element} The shared Element object (or null if no matching element was found)
12957      * @member Ext.core.Element
12958      * @method fly
12959      */
12960     El.fly = function(el, named) {
12961         var ret = null;
12962         named = named || '_global';
12963         el = Ext.getDom(el);
12964         if (el) {
12965             (El._flyweights[named] = El._flyweights[named] || new El.Flyweight()).dom = el;
12966             ret = El._flyweights[named];
12967         }
12968         return ret;
12969     };
12970
12971     /**
12972      * Retrieves Ext.core.Element objects.
12973      * <p><b>This method does not retrieve {@link Ext.Component Component}s.</b> This method
12974      * retrieves Ext.core.Element objects which encapsulate DOM elements. To retrieve a Component by
12975      * its ID, use {@link Ext.ComponentManager#get}.</p>
12976      * <p>Uses simple caching to consistently return the same object. Automatically fixes if an
12977      * object was recreated with the same id via AJAX or DOM.</p>
12978      * Shorthand of {@link Ext.core.Element#get}
12979      * @param {Mixed} el The id of the node, a DOM Node or an existing Element.
12980      * @return {Element} The Element object (or null if no matching element was found)
12981      * @member Ext
12982      * @method get
12983      */
12984     Ext.get = El.get;
12985
12986     /**
12987      * <p>Gets the globally shared flyweight Element, with the passed node as the active element. Do not store a reference to this element -
12988      * the dom node can be overwritten by other code. Shorthand of {@link Ext.core.Element#fly}</p>
12989      * <p>Use this to make one-time references to DOM elements which are not going to be accessed again either by
12990      * application code, or by Ext's classes. If accessing an element which will be processed regularly, then {@link Ext#get Ext.get}
12991      * will be more appropriate to take advantage of the caching provided by the Ext.core.Element class.</p>
12992      * @param {String/HTMLElement} el The dom node or id
12993      * @param {String} named (optional) Allows for creation of named reusable flyweights to prevent conflicts
12994      * (e.g. internally Ext uses "_global")
12995      * @return {Element} The shared Element object (or null if no matching element was found)
12996      * @member Ext
12997      * @method fly
12998      */
12999     Ext.fly = El.fly;
13000
13001     // speedy lookup for elements never to box adjust
13002     var noBoxAdjust = Ext.isStrict ? {
13003         select: 1
13004     }: {
13005         input: 1,
13006         select: 1,
13007         textarea: 1
13008     };
13009     if (Ext.isIE || Ext.isGecko) {
13010         noBoxAdjust['button'] = 1;
13011     }
13012 })();
13013
13014 /**
13015  * @class Ext.core.Element
13016  */
13017 Ext.core.Element.addMethods({
13018     /**
13019      * 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)
13020      * @param {String} selector The simple selector to test
13021      * @param {Number/Mixed} maxDepth (optional) The max depth to search as a number or element (defaults to 50 || document.body)
13022      * @param {Boolean} returnEl (optional) True to return a Ext.core.Element object instead of DOM node
13023      * @return {HTMLElement} The matching DOM node (or null if no match was found)
13024      */
13025     findParent : function(simpleSelector, maxDepth, returnEl) {
13026         var p = this.dom,
13027             b = document.body,
13028             depth = 0,
13029             stopEl;
13030
13031         maxDepth = maxDepth || 50;
13032         if (isNaN(maxDepth)) {
13033             stopEl = Ext.getDom(maxDepth);
13034             maxDepth = Number.MAX_VALUE;
13035         }
13036         while (p && p.nodeType == 1 && depth < maxDepth && p != b && p != stopEl) {
13037             if (Ext.DomQuery.is(p, simpleSelector)) {
13038                 return returnEl ? Ext.get(p) : p;
13039             }
13040             depth++;
13041             p = p.parentNode;
13042         }
13043         return null;
13044     },
13045     
13046     /**
13047      * Looks at parent nodes for a match of the passed simple selector (e.g. div.some-class or span:first-child)
13048      * @param {String} selector The simple selector to test
13049      * @param {Number/Mixed} maxDepth (optional) The max depth to
13050             search as a number or element (defaults to 10 || document.body)
13051      * @param {Boolean} returnEl (optional) True to return a Ext.core.Element object instead of DOM node
13052      * @return {HTMLElement} The matching DOM node (or null if no match was found)
13053      */
13054     findParentNode : function(simpleSelector, maxDepth, returnEl) {
13055         var p = Ext.fly(this.dom.parentNode, '_internal');
13056         return p ? p.findParent(simpleSelector, maxDepth, returnEl) : null;
13057     },
13058
13059     /**
13060      * Walks up the dom looking for a parent node that matches the passed simple selector (e.g. div.some-class or span:first-child).
13061      * This is a shortcut for findParentNode() that always returns an Ext.core.Element.
13062      * @param {String} selector The simple selector to test
13063      * @param {Number/Mixed} maxDepth (optional) The max depth to
13064             search as a number or element (defaults to 10 || document.body)
13065      * @return {Ext.core.Element} The matching DOM node (or null if no match was found)
13066      */
13067     up : function(simpleSelector, maxDepth) {
13068         return this.findParentNode(simpleSelector, maxDepth, true);
13069     },
13070
13071     /**
13072      * Creates a {@link Ext.CompositeElement} for child nodes based on the passed CSS selector (the selector should not contain an id).
13073      * @param {String} selector The CSS selector
13074      * @return {CompositeElement/CompositeElement} The composite element
13075      */
13076     select : function(selector) {
13077         return Ext.core.Element.select(selector, false,  this.dom);
13078     },
13079
13080     /**
13081      * Selects child nodes based on the passed CSS selector (the selector should not contain an id).
13082      * @param {String} selector The CSS selector
13083      * @return {Array} An array of the matched nodes
13084      */
13085     query : function(selector) {
13086         return Ext.DomQuery.select(selector, this.dom);
13087     },
13088
13089     /**
13090      * Selects a single child at any depth below this element based on the passed CSS selector (the selector should not contain an id).
13091      * @param {String} selector The CSS selector
13092      * @param {Boolean} returnDom (optional) True to return the DOM node instead of Ext.core.Element (defaults to false)
13093      * @return {HTMLElement/Ext.core.Element} The child Ext.core.Element (or DOM node if returnDom = true)
13094      */
13095     down : function(selector, returnDom) {
13096         var n = Ext.DomQuery.selectNode(selector, this.dom);
13097         return returnDom ? n : Ext.get(n);
13098     },
13099
13100     /**
13101      * Selects a single *direct* child based on the passed CSS selector (the selector should not contain an id).
13102      * @param {String} selector The CSS selector
13103      * @param {Boolean} returnDom (optional) True to return the DOM node instead of Ext.core.Element (defaults to false)
13104      * @return {HTMLElement/Ext.core.Element} The child Ext.core.Element (or DOM node if returnDom = true)
13105      */
13106     child : function(selector, returnDom) {
13107         var node,
13108             me = this,
13109             id;
13110         id = Ext.get(me).id;
13111         // Escape . or :
13112         id = id.replace(/[\.:]/g, "\\$0");
13113         node = Ext.DomQuery.selectNode('#' + id + " > " + selector, me.dom);
13114         return returnDom ? node : Ext.get(node);
13115     },
13116
13117      /**
13118      * Gets the parent node for this element, optionally chaining up trying to match a selector
13119      * @param {String} selector (optional) Find a parent node that matches the passed simple selector
13120      * @param {Boolean} returnDom (optional) True to return a raw dom node instead of an Ext.core.Element
13121      * @return {Ext.core.Element/HTMLElement} The parent node or null
13122      */
13123     parent : function(selector, returnDom) {
13124         return this.matchNode('parentNode', 'parentNode', selector, returnDom);
13125     },
13126
13127      /**
13128      * Gets the next sibling, skipping text nodes
13129      * @param {String} selector (optional) Find the next sibling that matches the passed simple selector
13130      * @param {Boolean} returnDom (optional) True to return a raw dom node instead of an Ext.core.Element
13131      * @return {Ext.core.Element/HTMLElement} The next sibling or null
13132      */
13133     next : function(selector, returnDom) {
13134         return this.matchNode('nextSibling', 'nextSibling', selector, returnDom);
13135     },
13136
13137     /**
13138      * Gets the previous sibling, skipping text nodes
13139      * @param {String} selector (optional) Find the previous sibling that matches the passed simple selector
13140      * @param {Boolean} returnDom (optional) True to return a raw dom node instead of an Ext.core.Element
13141      * @return {Ext.core.Element/HTMLElement} The previous sibling or null
13142      */
13143     prev : function(selector, returnDom) {
13144         return this.matchNode('previousSibling', 'previousSibling', selector, returnDom);
13145     },
13146
13147
13148     /**
13149      * Gets the first child, skipping text nodes
13150      * @param {String} selector (optional) Find the next sibling that matches the passed simple selector
13151      * @param {Boolean} returnDom (optional) True to return a raw dom node instead of an Ext.core.Element
13152      * @return {Ext.core.Element/HTMLElement} The first child or null
13153      */
13154     first : function(selector, returnDom) {
13155         return this.matchNode('nextSibling', 'firstChild', selector, returnDom);
13156     },
13157
13158     /**
13159      * Gets the last child, skipping text nodes
13160      * @param {String} selector (optional) Find the previous sibling that matches the passed simple selector
13161      * @param {Boolean} returnDom (optional) True to return a raw dom node instead of an Ext.core.Element
13162      * @return {Ext.core.Element/HTMLElement} The last child or null
13163      */
13164     last : function(selector, returnDom) {
13165         return this.matchNode('previousSibling', 'lastChild', selector, returnDom);
13166     },
13167
13168     matchNode : function(dir, start, selector, returnDom) {
13169         if (!this.dom) {
13170             return null;
13171         }
13172         
13173         var n = this.dom[start];
13174         while (n) {
13175             if (n.nodeType == 1 && (!selector || Ext.DomQuery.is(n, selector))) {
13176                 return !returnDom ? Ext.get(n) : n;
13177             }
13178             n = n[dir];
13179         }
13180         return null;
13181     }
13182 });
13183
13184 /**
13185  * @class Ext.core.Element
13186  */
13187 Ext.core.Element.addMethods({
13188     /**
13189      * Appends the passed element(s) to this element
13190      * @param {String/HTMLElement/Array/Element/CompositeElement} el
13191      * @return {Ext.core.Element} this
13192      */
13193     appendChild : function(el) {
13194         return Ext.get(el).appendTo(this);
13195     },
13196
13197     /**
13198      * Appends this element to the passed element
13199      * @param {Mixed} el The new parent element
13200      * @return {Ext.core.Element} this
13201      */
13202     appendTo : function(el) {
13203         Ext.getDom(el).appendChild(this.dom);
13204         return this;
13205     },
13206
13207     /**
13208      * Inserts this element before the passed element in the DOM
13209      * @param {Mixed} el The element before which this element will be inserted
13210      * @return {Ext.core.Element} this
13211      */
13212     insertBefore : function(el) {
13213         el = Ext.getDom(el);
13214         el.parentNode.insertBefore(this.dom, el);
13215         return this;
13216     },
13217
13218     /**
13219      * Inserts this element after the passed element in the DOM
13220      * @param {Mixed} el The element to insert after
13221      * @return {Ext.core.Element} this
13222      */
13223     insertAfter : function(el) {
13224         el = Ext.getDom(el);
13225         el.parentNode.insertBefore(this.dom, el.nextSibling);
13226         return this;
13227     },
13228
13229     /**
13230      * Inserts (or creates) an element (or DomHelper config) as the first child of this element
13231      * @param {Mixed/Object} el The id or element to insert or a DomHelper config to create and insert
13232      * @return {Ext.core.Element} The new child
13233      */
13234     insertFirst : function(el, returnDom) {
13235         el = el || {};
13236         if (el.nodeType || el.dom || typeof el == 'string') { // element
13237             el = Ext.getDom(el);
13238             this.dom.insertBefore(el, this.dom.firstChild);
13239             return !returnDom ? Ext.get(el) : el;
13240         }
13241         else { // dh config
13242             return this.createChild(el, this.dom.firstChild, returnDom);
13243         }
13244     },
13245
13246     /**
13247      * Inserts (or creates) the passed element (or DomHelper config) as a sibling of this element
13248      * @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.
13249      * @param {String} where (optional) 'before' or 'after' defaults to before
13250      * @param {Boolean} returnDom (optional) True to return the .;ll;l,raw DOM element instead of Ext.core.Element
13251      * @return {Ext.core.Element} The inserted Element. If an array is passed, the last inserted element is returned.
13252      */
13253     insertSibling: function(el, where, returnDom){
13254         var me = this, rt,
13255         isAfter = (where || 'before').toLowerCase() == 'after',
13256         insertEl;
13257
13258         if(Ext.isArray(el)){
13259             insertEl = me;
13260             Ext.each(el, function(e) {
13261                 rt = Ext.fly(insertEl, '_internal').insertSibling(e, where, returnDom);
13262                 if(isAfter){
13263                     insertEl = rt;
13264                 }
13265             });
13266             return rt;
13267         }
13268
13269         el = el || {};
13270
13271         if(el.nodeType || el.dom){
13272             rt = me.dom.parentNode.insertBefore(Ext.getDom(el), isAfter ? me.dom.nextSibling : me.dom);
13273             if (!returnDom) {
13274                 rt = Ext.get(rt);
13275             }
13276         }else{
13277             if (isAfter && !me.dom.nextSibling) {
13278                 rt = Ext.core.DomHelper.append(me.dom.parentNode, el, !returnDom);
13279             } else {
13280                 rt = Ext.core.DomHelper[isAfter ? 'insertAfter' : 'insertBefore'](me.dom, el, !returnDom);
13281             }
13282         }
13283         return rt;
13284     },
13285
13286     /**
13287      * Replaces the passed element with this element
13288      * @param {Mixed} el The element to replace
13289      * @return {Ext.core.Element} this
13290      */
13291     replace : function(el) {
13292         el = Ext.get(el);
13293         this.insertBefore(el);
13294         el.remove();
13295         return this;
13296     },
13297     
13298     /**
13299      * Replaces this element with the passed element
13300      * @param {Mixed/Object} el The new element or a DomHelper config of an element to create
13301      * @return {Ext.core.Element} this
13302      */
13303     replaceWith: function(el){
13304         var me = this;
13305             
13306         if(el.nodeType || el.dom || typeof el == 'string'){
13307             el = Ext.get(el);
13308             me.dom.parentNode.insertBefore(el, me.dom);
13309         }else{
13310             el = Ext.core.DomHelper.insertBefore(me.dom, el);
13311         }
13312         
13313         delete Ext.cache[me.id];
13314         Ext.removeNode(me.dom);      
13315         me.id = Ext.id(me.dom = el);
13316         Ext.core.Element.addToCache(me.isFlyweight ? new Ext.core.Element(me.dom) : me);     
13317         return me;
13318     },
13319     
13320     /**
13321      * Creates the passed DomHelper config and appends it to this element or optionally inserts it before the passed child element.
13322      * @param {Object} config DomHelper element config object.  If no tag is specified (e.g., {tag:'input'}) then a div will be
13323      * automatically generated with the specified attributes.
13324      * @param {HTMLElement} insertBefore (optional) a child element of this element
13325      * @param {Boolean} returnDom (optional) true to return the dom node instead of creating an Element
13326      * @return {Ext.core.Element} The new child element
13327      */
13328     createChild : function(config, insertBefore, returnDom) {
13329         config = config || {tag:'div'};
13330         if (insertBefore) {
13331             return Ext.core.DomHelper.insertBefore(insertBefore, config, returnDom !== true);
13332         }
13333         else {
13334             return Ext.core.DomHelper[!this.dom.firstChild ? 'insertFirst' : 'append'](this.dom, config,  returnDom !== true);
13335         }
13336     },
13337
13338     /**
13339      * Creates and wraps this element with another element
13340      * @param {Object} config (optional) DomHelper element config object for the wrapper element or null for an empty div
13341      * @param {Boolean} returnDom (optional) True to return the raw DOM element instead of Ext.core.Element
13342      * @return {HTMLElement/Element} The newly created wrapper element
13343      */
13344     wrap : function(config, returnDom) {
13345         var newEl = Ext.core.DomHelper.insertBefore(this.dom, config || {tag: "div"}, !returnDom),
13346             d = newEl.dom || newEl;
13347
13348         d.appendChild(this.dom);
13349         return newEl;
13350     },
13351
13352     /**
13353      * Inserts an html fragment into this element
13354      * @param {String} where Where to insert the html in relation to this element - beforeBegin, afterBegin, beforeEnd, afterEnd.
13355      * @param {String} html The HTML fragment
13356      * @param {Boolean} returnEl (optional) True to return an Ext.core.Element (defaults to false)
13357      * @return {HTMLElement/Ext.core.Element} The inserted node (or nearest related if more than 1 inserted)
13358      */
13359     insertHtml : function(where, html, returnEl) {
13360         var el = Ext.core.DomHelper.insertHtml(where, this.dom, html);
13361         return returnEl ? Ext.get(el) : el;
13362     }
13363 });
13364
13365 /**
13366  * @class Ext.core.Element
13367  */
13368 (function(){
13369     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>';
13370     // local style camelizing for speed
13371     var supports = Ext.supports,
13372         view = document.defaultView,
13373         opacityRe = /alpha\(opacity=(.*)\)/i,
13374         trimRe = /^\s+|\s+$/g,
13375         spacesRe = /\s+/,
13376         wordsRe = /\w/g,
13377         adjustDirect2DTableRe = /table-row|table-.*-group/,
13378         INTERNAL = '_internal',
13379         PADDING = 'padding',
13380         MARGIN = 'margin',
13381         BORDER = 'border',
13382         LEFT = '-left',
13383         RIGHT = '-right',
13384         TOP = '-top',
13385         BOTTOM = '-bottom',
13386         WIDTH = '-width',
13387         MATH = Math,
13388         HIDDEN = 'hidden',
13389         ISCLIPPED = 'isClipped',
13390         OVERFLOW = 'overflow',
13391         OVERFLOWX = 'overflow-x',
13392         OVERFLOWY = 'overflow-y',
13393         ORIGINALCLIP = 'originalClip',
13394         // special markup used throughout Ext when box wrapping elements
13395         borders = {l: BORDER + LEFT + WIDTH, r: BORDER + RIGHT + WIDTH, t: BORDER + TOP + WIDTH, b: BORDER + BOTTOM + WIDTH},
13396         paddings = {l: PADDING + LEFT, r: PADDING + RIGHT, t: PADDING + TOP, b: PADDING + BOTTOM},
13397         margins = {l: MARGIN + LEFT, r: MARGIN + RIGHT, t: MARGIN + TOP, b: MARGIN + BOTTOM},
13398         data = Ext.core.Element.data;
13399
13400     Ext.override(Ext.core.Element, {
13401         
13402         /**
13403          * TODO: Look at this
13404          */
13405         // private  ==> used by Fx
13406         adjustWidth : function(width) {
13407             var me = this,
13408                 isNum = (typeof width == 'number');
13409                 
13410             if(isNum && me.autoBoxAdjust && !me.isBorderBox()){
13411                width -= (me.getBorderWidth("lr") + me.getPadding("lr"));
13412             }
13413             return (isNum && width < 0) ? 0 : width;
13414         },
13415
13416         // private   ==> used by Fx
13417         adjustHeight : function(height) {
13418             var me = this,
13419                 isNum = (typeof height == "number");
13420                 
13421             if(isNum && me.autoBoxAdjust && !me.isBorderBox()){
13422                height -= (me.getBorderWidth("tb") + me.getPadding("tb"));
13423             }
13424             return (isNum && height < 0) ? 0 : height;
13425         },
13426
13427
13428         /**
13429          * Adds one or more CSS classes to the element. Duplicate classes are automatically filtered out.
13430          * @param {String/Array} className The CSS classes to add separated by space, or an array of classes
13431          * @return {Ext.core.Element} this
13432          */
13433         addCls : function(className){
13434             var me = this,
13435                 cls = [],
13436                 space = ((me.dom.className.replace(trimRe, '') == '') ? "" : " "),
13437                 i, len, v;
13438             if (className === undefined) {
13439                 return me;
13440             }
13441             // Separate case is for speed
13442             if (Object.prototype.toString.call(className) !== '[object Array]') {
13443                 if (typeof className === 'string') {
13444                     className = className.replace(trimRe, '').split(spacesRe);
13445                     if (className.length === 1) {
13446                         className = className[0];
13447                         if (!me.hasCls(className)) {
13448                             me.dom.className += space + className;
13449                         }
13450                     } else {
13451                         this.addCls(className);
13452                     }
13453                 }
13454             } else {
13455                 for (i = 0, len = className.length; i < len; i++) {
13456                     v = className[i];
13457                     if (typeof v == 'string' && (' ' + me.dom.className + ' ').indexOf(' ' + v + ' ') == -1) {
13458                         cls.push(v);
13459                     }
13460                 }
13461                 if (cls.length) {
13462                     me.dom.className += space + cls.join(" ");
13463                 }
13464             }
13465             return me;
13466         },
13467
13468         /**
13469          * Removes one or more CSS classes from the element.
13470          * @param {String/Array} className The CSS classes to remove separated by space, or an array of classes
13471          * @return {Ext.core.Element} this
13472          */
13473         removeCls : function(className){
13474             var me = this,
13475                 i, idx, len, cls, elClasses;
13476             if (className === undefined) {
13477                 return me;
13478             }
13479             if (Object.prototype.toString.call(className) !== '[object Array]') {
13480                 className = className.replace(trimRe, '').split(spacesRe);
13481             }
13482             if (me.dom && me.dom.className) {
13483                 elClasses = me.dom.className.replace(trimRe, '').split(spacesRe);
13484                 for (i = 0, len = className.length; i < len; i++) {
13485                     cls = className[i];
13486                     if (typeof cls == 'string') {
13487                         cls = cls.replace(trimRe, '');
13488                         idx = Ext.Array.indexOf(elClasses, cls);
13489                         if (idx != -1) {
13490                             Ext.Array.erase(elClasses, idx, 1);
13491                         }
13492                     }
13493                 }
13494                 me.dom.className = elClasses.join(" ");
13495             }
13496             return me;
13497         },
13498
13499         /**
13500          * Adds one or more CSS classes to this element and removes the same class(es) from all siblings.
13501          * @param {String/Array} className The CSS class to add, or an array of classes
13502          * @return {Ext.core.Element} this
13503          */
13504         radioCls : function(className){
13505             var cn = this.dom.parentNode.childNodes,
13506                 v, i, len;
13507             className = Ext.isArray(className) ? className : [className];
13508             for (i = 0, len = cn.length; i < len; i++) {
13509                 v = cn[i];
13510                 if (v && v.nodeType == 1) {
13511                     Ext.fly(v, '_internal').removeCls(className);
13512                 }
13513             }
13514             return this.addCls(className);
13515         },
13516
13517         /**
13518          * Toggles the specified CSS class on this element (removes it if it already exists, otherwise adds it).
13519          * @param {String} className The CSS class to toggle
13520          * @return {Ext.core.Element} this
13521          * @method
13522          */
13523         toggleCls : Ext.supports.ClassList ?
13524             function(className) {
13525                 this.dom.classList.toggle(Ext.String.trim(className));
13526                 return this;
13527             } :
13528             function(className) {
13529                 return this.hasCls(className) ? this.removeCls(className) : this.addCls(className);
13530             },
13531
13532         /**
13533          * Checks if the specified CSS class exists on this element's DOM node.
13534          * @param {String} className The CSS class to check for
13535          * @return {Boolean} True if the class exists, else false
13536          * @method
13537          */
13538         hasCls : Ext.supports.ClassList ?
13539             function(className) {
13540                 if (!className) {
13541                     return false;
13542                 }
13543                 className = className.split(spacesRe);
13544                 var ln = className.length,
13545                     i = 0;
13546                 for (; i < ln; i++) {
13547                     if (className[i] && this.dom.classList.contains(className[i])) {
13548                         return true;
13549                     }
13550                 }
13551                 return false;
13552             } :
13553             function(className){
13554                 return className && (' ' + this.dom.className + ' ').indexOf(' ' + className + ' ') != -1;
13555             },
13556
13557         /**
13558          * Replaces a CSS class on the element with another.  If the old name does not exist, the new name will simply be added.
13559          * @param {String} oldClassName The CSS class to replace
13560          * @param {String} newClassName The replacement CSS class
13561          * @return {Ext.core.Element} this
13562          */
13563         replaceCls : function(oldClassName, newClassName){
13564             return this.removeCls(oldClassName).addCls(newClassName);
13565         },
13566
13567         isStyle : function(style, val) {
13568             return this.getStyle(style) == val;
13569         },
13570
13571         /**
13572          * Normalizes currentStyle and computedStyle.
13573          * @param {String} property The style property whose value is returned.
13574          * @return {String} The current value of the style property for this element.
13575          * @method
13576          */
13577         getStyle : function(){
13578             return view && view.getComputedStyle ?
13579                 function(prop){
13580                     var el = this.dom,
13581                         v, cs, out, display, cleaner;
13582
13583                     if(el == document){
13584                         return null;
13585                     }
13586                     prop = Ext.core.Element.normalize(prop);
13587                     out = (v = el.style[prop]) ? v :
13588                            (cs = view.getComputedStyle(el, "")) ? cs[prop] : null;
13589                            
13590                     // Ignore cases when the margin is correctly reported as 0, the bug only shows
13591                     // numbers larger.
13592                     if(prop == 'marginRight' && out != '0px' && !supports.RightMargin){
13593                         cleaner = Ext.core.Element.getRightMarginFixCleaner(el);
13594                         display = this.getStyle('display');
13595                         el.style.display = 'inline-block';
13596                         out = view.getComputedStyle(el, '').marginRight;
13597                         el.style.display = display;
13598                         cleaner();
13599                     }
13600                     
13601                     if(prop == 'backgroundColor' && out == 'rgba(0, 0, 0, 0)' && !supports.TransparentColor){
13602                         out = 'transparent';
13603                     }
13604                     return out;
13605                 } :
13606                 function(prop){
13607                     var el = this.dom,
13608                         m, cs;
13609
13610                     if (el == document) {
13611                         return null;
13612                     }
13613                     
13614                     if (prop == 'opacity') {
13615                         if (el.style.filter.match) {
13616                             m = el.style.filter.match(opacityRe);
13617                             if(m){
13618                                 var fv = parseFloat(m[1]);
13619                                 if(!isNaN(fv)){
13620                                     return fv ? fv / 100 : 0;
13621                                 }
13622                             }
13623                         }
13624                         return 1;
13625                     }
13626                     prop = Ext.core.Element.normalize(prop);
13627                     return el.style[prop] || ((cs = el.currentStyle) ? cs[prop] : null);
13628                 };
13629         }(),
13630
13631         /**
13632          * Return the CSS color for the specified CSS attribute. rgb, 3 digit (like #fff) and valid values
13633          * are convert to standard 6 digit hex color.
13634          * @param {String} attr The css attribute
13635          * @param {String} defaultValue The default value to use when a valid color isn't found
13636          * @param {String} prefix (optional) defaults to #. Use an empty string when working with
13637          * color anims.
13638          */
13639         getColor : function(attr, defaultValue, prefix){
13640             var v = this.getStyle(attr),
13641                 color = prefix || prefix === '' ? prefix : '#',
13642                 h;
13643
13644             if(!v || (/transparent|inherit/.test(v))) {
13645                 return defaultValue;
13646             }
13647             if(/^r/.test(v)){
13648                 Ext.each(v.slice(4, v.length -1).split(','), function(s){
13649                     h = parseInt(s, 10);
13650                     color += (h < 16 ? '0' : '') + h.toString(16);
13651                 });
13652             }else{
13653                 v = v.replace('#', '');
13654                 color += v.length == 3 ? v.replace(/^(\w)(\w)(\w)$/, '$1$1$2$2$3$3') : v;
13655             }
13656             return(color.length > 5 ? color.toLowerCase() : defaultValue);
13657         },
13658
13659         /**
13660          * Wrapper for setting style properties, also takes single object parameter of multiple styles.
13661          * @param {String/Object} property The style property to be set, or an object of multiple styles.
13662          * @param {String} value (optional) The value to apply to the given property, or null if an object was passed.
13663          * @return {Ext.core.Element} this
13664          */
13665         setStyle : function(prop, value){
13666             var me = this,
13667                 tmp, style;
13668
13669             if (!me.dom) {
13670                 return me;
13671             }
13672             if (typeof prop === 'string') {
13673                 tmp = {};
13674                 tmp[prop] = value;
13675                 prop = tmp;
13676             }
13677             for (style in prop) {
13678                 if (prop.hasOwnProperty(style)) {
13679                     value = Ext.value(prop[style], '');
13680                     if (style == 'opacity') {
13681                         me.setOpacity(value);
13682                     }
13683                     else {
13684                         me.dom.style[Ext.core.Element.normalize(style)] = value;
13685                     }
13686                 }
13687             }
13688             return me;
13689         },
13690
13691         /**
13692          * Set the opacity of the element
13693          * @param {Float} opacity The new opacity. 0 = transparent, .5 = 50% visibile, 1 = fully visible, etc
13694          * @param {Boolean/Object} animate (optional) a standard Element animation config object or <tt>true</tt> for
13695          * the default animation (<tt>{duration: .35, easing: 'easeIn'}</tt>)
13696          * @return {Ext.core.Element} this
13697          */
13698         setOpacity: function(opacity, animate) {
13699             var me = this,
13700                 dom = me.dom,
13701                 val,
13702                 style;
13703
13704             if (!me.dom) {
13705                 return me;
13706             }
13707
13708             style = me.dom.style;
13709
13710             if (!animate || !me.anim) {
13711                 if (!Ext.supports.Opacity) {
13712                     opacity = opacity < 1 ? 'alpha(opacity=' + opacity * 100 + ')': '';
13713                     val = style.filter.replace(opacityRe, '').replace(trimRe, '');
13714
13715                     style.zoom = 1;
13716                     style.filter = val + (val.length > 0 ? ' ': '') + opacity;
13717                 }
13718                 else {
13719                     style.opacity = opacity;
13720                 }
13721             }
13722             else {
13723                 if (!Ext.isObject(animate)) {
13724                     animate = {
13725                         duration: 350,
13726                         easing: 'ease-in'
13727                     };
13728                 }
13729                 me.animate(Ext.applyIf({
13730                     to: {
13731                         opacity: opacity
13732                     }
13733                 },
13734                 animate));
13735             }
13736             return me;
13737         },
13738
13739
13740         /**
13741          * Clears any opacity settings from this element. Required in some cases for IE.
13742          * @return {Ext.core.Element} this
13743          */
13744         clearOpacity : function(){
13745             var style = this.dom.style;
13746             if(!Ext.supports.Opacity){
13747                 if(!Ext.isEmpty(style.filter)){
13748                     style.filter = style.filter.replace(opacityRe, '').replace(trimRe, '');
13749                 }
13750             }else{
13751                 style.opacity = style['-moz-opacity'] = style['-khtml-opacity'] = '';
13752             }
13753             return this;
13754         },
13755         
13756         /**
13757          * @private
13758          * Returns 1 if the browser returns the subpixel dimension rounded to the lowest pixel.
13759          * @return {Number} 0 or 1 
13760          */
13761         adjustDirect2DDimension: function(dimension) {
13762             var me = this,
13763                 dom = me.dom,
13764                 display = me.getStyle('display'),
13765                 inlineDisplay = dom.style['display'],
13766                 inlinePosition = dom.style['position'],
13767                 originIndex = dimension === 'width' ? 0 : 1,
13768                 floating;
13769                 
13770             if (display === 'inline') {
13771                 dom.style['display'] = 'inline-block';
13772             }
13773
13774             dom.style['position'] = display.match(adjustDirect2DTableRe) ? 'absolute' : 'static';
13775
13776             // floating will contain digits that appears after the decimal point
13777             // if height or width are set to auto we fallback to msTransformOrigin calculation
13778             floating = (parseFloat(me.getStyle(dimension)) || parseFloat(dom.currentStyle.msTransformOrigin.split(' ')[originIndex]) * 2) % 1;
13779             
13780             dom.style['position'] = inlinePosition;
13781             
13782             if (display === 'inline') {
13783                 dom.style['display'] = inlineDisplay;
13784             }
13785
13786             return floating;
13787         },
13788         
13789         /**
13790          * Returns the offset height of the element
13791          * @param {Boolean} contentHeight (optional) true to get the height minus borders and padding
13792          * @return {Number} The element's height
13793          */
13794         getHeight: function(contentHeight, preciseHeight) {
13795             var me = this,
13796                 dom = me.dom,
13797                 hidden = Ext.isIE && me.isStyle('display', 'none'),
13798                 height, overflow, style, floating;
13799
13800             // IE Quirks mode acts more like a max-size measurement unless overflow is hidden during measurement.
13801             // We will put the overflow back to it's original value when we are done measuring.
13802             if (Ext.isIEQuirks) {
13803                 style = dom.style;
13804                 overflow = style.overflow;
13805                 me.setStyle({ overflow: 'hidden'});
13806             }
13807
13808             height = dom.offsetHeight;
13809
13810             height = MATH.max(height, hidden ? 0 : dom.clientHeight) || 0;
13811
13812             // IE9 Direct2D dimension rounding bug
13813             if (!hidden && Ext.supports.Direct2DBug) {
13814                 floating = me.adjustDirect2DDimension('height');
13815                 if (preciseHeight) {
13816                     height += floating;
13817                 }
13818                 else if (floating > 0 && floating < 0.5) {
13819                     height++;
13820                 }
13821             }
13822
13823             if (contentHeight) {
13824                 height -= (me.getBorderWidth("tb") + me.getPadding("tb"));
13825             }
13826
13827             if (Ext.isIEQuirks) {
13828                 me.setStyle({ overflow: overflow});
13829             }
13830
13831             if (height < 0) {
13832                 height = 0;
13833             }
13834             return height;
13835         },
13836                 
13837         /**
13838          * Returns the offset width of the element
13839          * @param {Boolean} contentWidth (optional) true to get the width minus borders and padding
13840          * @return {Number} The element's width
13841          */
13842         getWidth: function(contentWidth, preciseWidth) {
13843             var me = this,
13844                 dom = me.dom,
13845                 hidden = Ext.isIE && me.isStyle('display', 'none'),
13846                 rect, width, overflow, style, floating, parentPosition;
13847
13848             // IE Quirks mode acts more like a max-size measurement unless overflow is hidden during measurement.
13849             // We will put the overflow back to it's original value when we are done measuring.
13850             if (Ext.isIEQuirks) {
13851                 style = dom.style;
13852                 overflow = style.overflow;
13853                 me.setStyle({overflow: 'hidden'});
13854             }
13855             
13856             // Fix Opera 10.5x width calculation issues 
13857             if (Ext.isOpera10_5) {
13858                 if (dom.parentNode.currentStyle.position === 'relative') {
13859                     parentPosition = dom.parentNode.style.position;
13860                     dom.parentNode.style.position = 'static';
13861                     width = dom.offsetWidth;
13862                     dom.parentNode.style.position = parentPosition;
13863                 }
13864                 width = Math.max(width || 0, dom.offsetWidth);
13865             
13866             // Gecko will in some cases report an offsetWidth that is actually less than the width of the
13867             // text contents, because it measures fonts with sub-pixel precision but rounds the calculated
13868             // value down. Using getBoundingClientRect instead of offsetWidth allows us to get the precise
13869             // subpixel measurements so we can force them to always be rounded up. See
13870             // https://bugzilla.mozilla.org/show_bug.cgi?id=458617
13871             } else if (Ext.supports.BoundingClientRect) {
13872                 rect = dom.getBoundingClientRect();
13873                 width = rect.right - rect.left;
13874                 width = preciseWidth ? width : Math.ceil(width);
13875             } else {
13876                 width = dom.offsetWidth;
13877             }
13878
13879             width = MATH.max(width, hidden ? 0 : dom.clientWidth) || 0;
13880
13881             // IE9 Direct2D dimension rounding bug
13882             if (!hidden && Ext.supports.Direct2DBug) {
13883                 floating = me.adjustDirect2DDimension('width');
13884                 if (preciseWidth) {
13885                     width += floating;
13886                 }
13887                 else if (floating > 0 && floating < 0.5) {
13888                     width++;
13889                 }
13890             }
13891             
13892             if (contentWidth) {
13893                 width -= (me.getBorderWidth("lr") + me.getPadding("lr"));
13894             }
13895             
13896             if (Ext.isIEQuirks) {
13897                 me.setStyle({ overflow: overflow});
13898             }
13899
13900             if (width < 0) {
13901                 width = 0;
13902             }
13903             return width;
13904         },
13905
13906         /**
13907          * Set the width of this Element.
13908          * @param {Mixed} width The new width. This may be one of:<div class="mdetail-params"><ul>
13909          * <li>A Number specifying the new width in this Element's {@link #defaultUnit}s (by default, pixels).</li>
13910          * <li>A String used to set the CSS width style. Animation may <b>not</b> be used.
13911          * </ul></div>
13912          * @param {Boolean/Object} animate (optional) true for the default animation or a standard Element animation config object
13913          * @return {Ext.core.Element} this
13914          */
13915         setWidth : function(width, animate){
13916             var me = this;
13917             width = me.adjustWidth(width);
13918             if (!animate || !me.anim) {
13919                 me.dom.style.width = me.addUnits(width);
13920             }
13921             else {
13922                 if (!Ext.isObject(animate)) {
13923                     animate = {};
13924                 }
13925                 me.animate(Ext.applyIf({
13926                     to: {
13927                         width: width
13928                     }
13929                 }, animate));
13930             }
13931             return me;
13932         },
13933
13934         /**
13935          * Set the height of this Element.
13936          * <pre><code>
13937 // change the height to 200px and animate with default configuration
13938 Ext.fly('elementId').setHeight(200, true);
13939
13940 // change the height to 150px and animate with a custom configuration
13941 Ext.fly('elId').setHeight(150, {
13942     duration : .5, // animation will have a duration of .5 seconds
13943     // will change the content to "finished"
13944     callback: function(){ this.{@link #update}("finished"); }
13945 });
13946          * </code></pre>
13947          * @param {Mixed} height The new height. This may be one of:<div class="mdetail-params"><ul>
13948          * <li>A Number specifying the new height in this Element's {@link #defaultUnit}s (by default, pixels.)</li>
13949          * <li>A String used to set the CSS height style. Animation may <b>not</b> be used.</li>
13950          * </ul></div>
13951          * @param {Boolean/Object} animate (optional) true for the default animation or a standard Element animation config object
13952          * @return {Ext.core.Element} this
13953          */
13954          setHeight : function(height, animate){
13955             var me = this;
13956             height = me.adjustHeight(height);
13957             if (!animate || !me.anim) {
13958                 me.dom.style.height = me.addUnits(height);
13959             }
13960             else {
13961                 if (!Ext.isObject(animate)) {
13962                     animate = {};
13963                 }
13964                 me.animate(Ext.applyIf({
13965                     to: {
13966                         height: height
13967                     }
13968                 }, animate));
13969             }
13970             return me;
13971         },
13972
13973         /**
13974          * Gets the width of the border(s) for the specified side(s)
13975          * @param {String} side Can be t, l, r, b or any combination of those to add multiple values. For example,
13976          * passing <tt>'lr'</tt> would get the border <b><u>l</u></b>eft width + the border <b><u>r</u></b>ight width.
13977          * @return {Number} The width of the sides passed added together
13978          */
13979         getBorderWidth : function(side){
13980             return this.addStyles(side, borders);
13981         },
13982
13983         /**
13984          * Gets the width of the padding(s) for the specified side(s)
13985          * @param {String} side Can be t, l, r, b or any combination of those to add multiple values. For example,
13986          * passing <tt>'lr'</tt> would get the padding <b><u>l</u></b>eft + the padding <b><u>r</u></b>ight.
13987          * @return {Number} The padding of the sides passed added together
13988          */
13989         getPadding : function(side){
13990             return this.addStyles(side, paddings);
13991         },
13992
13993         /**
13994          *  Store the current overflow setting and clip overflow on the element - use <tt>{@link #unclip}</tt> to remove
13995          * @return {Ext.core.Element} this
13996          */
13997         clip : function(){
13998             var me = this,
13999                 dom = me.dom;
14000
14001             if(!data(dom, ISCLIPPED)){
14002                 data(dom, ISCLIPPED, true);
14003                 data(dom, ORIGINALCLIP, {
14004                     o: me.getStyle(OVERFLOW),
14005                     x: me.getStyle(OVERFLOWX),
14006                     y: me.getStyle(OVERFLOWY)
14007                 });
14008                 me.setStyle(OVERFLOW, HIDDEN);
14009                 me.setStyle(OVERFLOWX, HIDDEN);
14010                 me.setStyle(OVERFLOWY, HIDDEN);
14011             }
14012             return me;
14013         },
14014
14015         /**
14016          *  Return clipping (overflow) to original clipping before <tt>{@link #clip}</tt> was called
14017          * @return {Ext.core.Element} this
14018          */
14019         unclip : function(){
14020             var me = this,
14021                 dom = me.dom,
14022                 clip;
14023
14024             if(data(dom, ISCLIPPED)){
14025                 data(dom, ISCLIPPED, false);
14026                 clip = data(dom, ORIGINALCLIP);
14027                 if(o.o){
14028                     me.setStyle(OVERFLOW, o.o);
14029                 }
14030                 if(o.x){
14031                     me.setStyle(OVERFLOWX, o.x);
14032                 }
14033                 if(o.y){
14034                     me.setStyle(OVERFLOWY, o.y);
14035                 }
14036             }
14037             return me;
14038         },
14039
14040         // private
14041         addStyles : function(sides, styles){
14042             var totalSize = 0,
14043                 sidesArr = sides.match(wordsRe),
14044                 i = 0,
14045                 len = sidesArr.length,
14046                 side, size;
14047             for (; i < len; i++) {
14048                 side = sidesArr[i];
14049                 size = side && parseInt(this.getStyle(styles[side]), 10);
14050                 if (size) {
14051                     totalSize += MATH.abs(size);
14052                 }
14053             }
14054             return totalSize;
14055         },
14056
14057         margins : margins,
14058         
14059         /**
14060          * More flexible version of {@link #setStyle} for setting style properties.
14061          * @param {String/Object/Function} styles A style specification string, e.g. "width:100px", or object in the form {width:"100px"}, or
14062          * a function which returns such a specification.
14063          * @return {Ext.core.Element} this
14064          */
14065         applyStyles : function(style){
14066             Ext.core.DomHelper.applyStyles(this.dom, style);
14067             return this;
14068         },
14069
14070         /**
14071          * Returns an object with properties matching the styles requested.
14072          * For example, el.getStyles('color', 'font-size', 'width') might return
14073          * {'color': '#FFFFFF', 'font-size': '13px', 'width': '100px'}.
14074          * @param {String} style1 A style name
14075          * @param {String} style2 A style name
14076          * @param {String} etc.
14077          * @return {Object} The style object
14078          */
14079         getStyles : function(){
14080             var styles = {},
14081                 len = arguments.length,
14082                 i = 0, style;
14083                 
14084             for(; i < len; ++i) {
14085                 style = arguments[i];
14086                 styles[style] = this.getStyle(style);
14087             }
14088             return styles;
14089         },
14090
14091        /**
14092         * <p>Wraps the specified element with a special 9 element markup/CSS block that renders by default as
14093         * a gray container with a gradient background, rounded corners and a 4-way shadow.</p>
14094         * <p>This special markup is used throughout Ext when box wrapping elements ({@link Ext.button.Button},
14095         * {@link Ext.panel.Panel} when <tt>{@link Ext.panel.Panel#frame frame=true}</tt>, {@link Ext.window.Window}).  The markup
14096         * is of this form:</p>
14097         * <pre><code>
14098     Ext.core.Element.boxMarkup =
14099     &#39;&lt;div class="{0}-tl">&lt;div class="{0}-tr">&lt;div class="{0}-tc">&lt;/div>&lt;/div>&lt;/div>
14100      &lt;div class="{0}-ml">&lt;div class="{0}-mr">&lt;div class="{0}-mc">&lt;/div>&lt;/div>&lt;/div>
14101      &lt;div class="{0}-bl">&lt;div class="{0}-br">&lt;div class="{0}-bc">&lt;/div>&lt;/div>&lt;/div>&#39;;
14102         * </code></pre>
14103         * <p>Example usage:</p>
14104         * <pre><code>
14105     // Basic box wrap
14106     Ext.get("foo").boxWrap();
14107
14108     // You can also add a custom class and use CSS inheritance rules to customize the box look.
14109     // 'x-box-blue' is a built-in alternative -- look at the related CSS definitions as an example
14110     // for how to create a custom box wrap style.
14111     Ext.get("foo").boxWrap().addCls("x-box-blue");
14112         * </code></pre>
14113         * @param {String} class (optional) A base CSS class to apply to the containing wrapper element
14114         * (defaults to <tt>'x-box'</tt>). Note that there are a number of CSS rules that are dependent on
14115         * this name to make the overall effect work, so if you supply an alternate base class, make sure you
14116         * also supply all of the necessary rules.
14117         * @return {Ext.core.Element} The outermost wrapping element of the created box structure.
14118         */
14119         boxWrap : function(cls){
14120             cls = cls || Ext.baseCSSPrefix + 'box';
14121             var el = Ext.get(this.insertHtml("beforeBegin", "<div class='" + cls + "'>" + Ext.String.format(Ext.core.Element.boxMarkup, cls) + "</div>"));
14122             Ext.DomQuery.selectNode('.' + cls + '-mc', el.dom).appendChild(this.dom);
14123             return el;
14124         },
14125
14126         /**
14127          * Set the size of this Element. If animation is true, both width and height will be animated concurrently.
14128          * @param {Mixed} width The new width. This may be one of:<div class="mdetail-params"><ul>
14129          * <li>A Number specifying the new width in this Element's {@link #defaultUnit}s (by default, pixels).</li>
14130          * <li>A String used to set the CSS width style. Animation may <b>not</b> be used.
14131          * <li>A size object in the format <code>{width: widthValue, height: heightValue}</code>.</li>
14132          * </ul></div>
14133          * @param {Mixed} height The new height. This may be one of:<div class="mdetail-params"><ul>
14134          * <li>A Number specifying the new height in this Element's {@link #defaultUnit}s (by default, pixels).</li>
14135          * <li>A String used to set the CSS height style. Animation may <b>not</b> be used.</li>
14136          * </ul></div>
14137          * @param {Boolean/Object} animate (optional) true for the default animation or a standard Element animation config object
14138          * @return {Ext.core.Element} this
14139          */
14140         setSize : function(width, height, animate){
14141             var me = this;
14142             if (Ext.isObject(width)) { // in case of object from getSize()
14143                 animate = height;
14144                 height = width.height;
14145                 width = width.width;
14146             }
14147             width = me.adjustWidth(width);
14148             height = me.adjustHeight(height);
14149             if(!animate || !me.anim){
14150                 me.dom.style.width = me.addUnits(width);
14151                 me.dom.style.height = me.addUnits(height);
14152             }
14153             else {
14154                 if (animate === true) {
14155                     animate = {};
14156                 }
14157                 me.animate(Ext.applyIf({
14158                     to: {
14159                         width: width,
14160                         height: height
14161                     }
14162                 }, animate));
14163             }
14164             return me;
14165         },
14166
14167         /**
14168          * Returns either the offsetHeight or the height of this element based on CSS height adjusted by padding or borders
14169          * when needed to simulate offsetHeight when offsets aren't available. This may not work on display:none elements
14170          * if a height has not been set using CSS.
14171          * @return {Number}
14172          */
14173         getComputedHeight : function(){
14174             var me = this,
14175                 h = Math.max(me.dom.offsetHeight, me.dom.clientHeight);
14176             if(!h){
14177                 h = parseFloat(me.getStyle('height')) || 0;
14178                 if(!me.isBorderBox()){
14179                     h += me.getFrameWidth('tb');
14180                 }
14181             }
14182             return h;
14183         },
14184
14185         /**
14186          * Returns either the offsetWidth or the width of this element based on CSS width adjusted by padding or borders
14187          * when needed to simulate offsetWidth when offsets aren't available. This may not work on display:none elements
14188          * if a width has not been set using CSS.
14189          * @return {Number}
14190          */
14191         getComputedWidth : function(){
14192             var me = this,
14193                 w = Math.max(me.dom.offsetWidth, me.dom.clientWidth);
14194                 
14195             if(!w){
14196                 w = parseFloat(me.getStyle('width')) || 0;
14197                 if(!me.isBorderBox()){
14198                     w += me.getFrameWidth('lr');
14199                 }
14200             }
14201             return w;
14202         },
14203
14204         /**
14205          * Returns the sum width of the padding and borders for the passed "sides". See getBorderWidth()
14206          for more information about the sides.
14207          * @param {String} sides
14208          * @return {Number}
14209          */
14210         getFrameWidth : function(sides, onlyContentBox){
14211             return onlyContentBox && this.isBorderBox() ? 0 : (this.getPadding(sides) + this.getBorderWidth(sides));
14212         },
14213
14214         /**
14215          * Sets up event handlers to add and remove a css class when the mouse is over this element
14216          * @param {String} className
14217          * @return {Ext.core.Element} this
14218          */
14219         addClsOnOver : function(className){
14220             var dom = this.dom;
14221             this.hover(
14222                 function(){
14223                     Ext.fly(dom, INTERNAL).addCls(className);
14224                 },
14225                 function(){
14226                     Ext.fly(dom, INTERNAL).removeCls(className);
14227                 }
14228             );
14229             return this;
14230         },
14231
14232         /**
14233          * Sets up event handlers to add and remove a css class when this element has the focus
14234          * @param {String} className
14235          * @return {Ext.core.Element} this
14236          */
14237         addClsOnFocus : function(className){
14238             var me = this,
14239                 dom = me.dom;
14240             me.on("focus", function(){
14241                 Ext.fly(dom, INTERNAL).addCls(className);
14242             });
14243             me.on("blur", function(){
14244                 Ext.fly(dom, INTERNAL).removeCls(className);
14245             });
14246             return me;
14247         },
14248
14249         /**
14250          * 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)
14251          * @param {String} className
14252          * @return {Ext.core.Element} this
14253          */
14254         addClsOnClick : function(className){
14255             var dom = this.dom;
14256             this.on("mousedown", function(){
14257                 Ext.fly(dom, INTERNAL).addCls(className);
14258                 var d = Ext.getDoc(),
14259                     fn = function(){
14260                         Ext.fly(dom, INTERNAL).removeCls(className);
14261                         d.removeListener("mouseup", fn);
14262                     };
14263                 d.on("mouseup", fn);
14264             });
14265             return this;
14266         },
14267
14268         /**
14269          * <p>Returns the dimensions of the element available to lay content out in.<p>
14270          * <p>If the element (or any ancestor element) has CSS style <code>display : none</code>, the dimensions will be zero.</p>
14271          * example:<pre><code>
14272         var vpSize = Ext.getBody().getViewSize();
14273
14274         // all Windows created afterwards will have a default value of 90% height and 95% width
14275         Ext.Window.override({
14276             width: vpSize.width * 0.9,
14277             height: vpSize.height * 0.95
14278         });
14279         // To handle window resizing you would have to hook onto onWindowResize.
14280         * </code></pre>
14281         *
14282         * getViewSize utilizes clientHeight/clientWidth which excludes sizing of scrollbars.
14283         * To obtain the size including scrollbars, use getStyleSize
14284         *
14285         * Sizing of the document body is handled at the adapter level which handles special cases for IE and strict modes, etc.
14286         */
14287
14288         getViewSize : function(){
14289             var me = this,
14290                 dom = me.dom,
14291                 isDoc = (dom == Ext.getDoc().dom || dom == Ext.getBody().dom),
14292                 style, overflow, ret;
14293
14294             // If the body, use static methods
14295             if (isDoc) {
14296                 ret = {
14297                     width : Ext.core.Element.getViewWidth(),
14298                     height : Ext.core.Element.getViewHeight()
14299                 };
14300
14301             // Else use clientHeight/clientWidth
14302             }
14303             else {
14304                 // IE 6 & IE Quirks mode acts more like a max-size measurement unless overflow is hidden during measurement.
14305                 // We will put the overflow back to it's original value when we are done measuring.
14306                 if (Ext.isIE6 || Ext.isIEQuirks) {
14307                     style = dom.style;
14308                     overflow = style.overflow;
14309                     me.setStyle({ overflow: 'hidden'});
14310                 }
14311                 ret = {
14312                     width : dom.clientWidth,
14313                     height : dom.clientHeight
14314                 };
14315                 if (Ext.isIE6 || Ext.isIEQuirks) {
14316                     me.setStyle({ overflow: overflow });
14317                 }
14318             }
14319             return ret;
14320         },
14321
14322         /**
14323         * <p>Returns the dimensions of the element available to lay content out in.<p>
14324         *
14325         * getStyleSize utilizes prefers style sizing if present, otherwise it chooses the larger of offsetHeight/clientHeight and offsetWidth/clientWidth.
14326         * To obtain the size excluding scrollbars, use getViewSize
14327         *
14328         * Sizing of the document body is handled at the adapter level which handles special cases for IE and strict modes, etc.
14329         */
14330
14331         getStyleSize : function(){
14332             var me = this,
14333                 doc = document,
14334                 d = this.dom,
14335                 isDoc = (d == doc || d == doc.body),
14336                 s = d.style,
14337                 w, h;
14338
14339             // If the body, use static methods
14340             if (isDoc) {
14341                 return {
14342                     width : Ext.core.Element.getViewWidth(),
14343                     height : Ext.core.Element.getViewHeight()
14344                 };
14345             }
14346             // Use Styles if they are set
14347             if(s.width && s.width != 'auto'){
14348                 w = parseFloat(s.width);
14349                 if(me.isBorderBox()){
14350                    w -= me.getFrameWidth('lr');
14351                 }
14352             }
14353             // Use Styles if they are set
14354             if(s.height && s.height != 'auto'){
14355                 h = parseFloat(s.height);
14356                 if(me.isBorderBox()){
14357                    h -= me.getFrameWidth('tb');
14358                 }
14359             }
14360             // Use getWidth/getHeight if style not set.
14361             return {width: w || me.getWidth(true), height: h || me.getHeight(true)};
14362         },
14363
14364         /**
14365          * Returns the size of the element.
14366          * @param {Boolean} contentSize (optional) true to get the width/size minus borders and padding
14367          * @return {Object} An object containing the element's size {width: (element width), height: (element height)}
14368          */
14369         getSize : function(contentSize){
14370             return {width: this.getWidth(contentSize), height: this.getHeight(contentSize)};
14371         },
14372
14373         /**
14374          * Forces the browser to repaint this element
14375          * @return {Ext.core.Element} this
14376          */
14377         repaint : function(){
14378             var dom = this.dom;
14379             this.addCls(Ext.baseCSSPrefix + 'repaint');
14380             setTimeout(function(){
14381                 Ext.fly(dom).removeCls(Ext.baseCSSPrefix + 'repaint');
14382             }, 1);
14383             return this;
14384         },
14385
14386         /**
14387          * Disables text selection for this element (normalized across browsers)
14388          * @return {Ext.core.Element} this
14389          */
14390         unselectable : function(){
14391             var me = this;
14392             me.dom.unselectable = "on";
14393
14394             me.swallowEvent("selectstart", true);
14395             me.applyStyles("-moz-user-select:none;-khtml-user-select:none;");
14396             me.addCls(Ext.baseCSSPrefix + 'unselectable');
14397             
14398             return me;
14399         },
14400
14401         /**
14402          * Returns an object with properties top, left, right and bottom representing the margins of this element unless sides is passed,
14403          * then it returns the calculated width of the sides (see getPadding)
14404          * @param {String} sides (optional) Any combination of l, r, t, b to get the sum of those sides
14405          * @return {Object/Number}
14406          */
14407         getMargin : function(side){
14408             var me = this,
14409                 hash = {t:"top", l:"left", r:"right", b: "bottom"},
14410                 o = {},
14411                 key;
14412
14413             if (!side) {
14414                 for (key in me.margins){
14415                     o[hash[key]] = parseFloat(me.getStyle(me.margins[key])) || 0;
14416                 }
14417                 return o;
14418             } else {
14419                 return me.addStyles.call(me, side, me.margins);
14420             }
14421         }
14422     });
14423 })();
14424 /**
14425  * @class Ext.core.Element
14426  */
14427 /**
14428  * Visibility mode constant for use with {@link #setVisibilityMode}. Use visibility to hide element
14429  * @static
14430  * @type Number
14431  */
14432 Ext.core.Element.VISIBILITY = 1;
14433 /**
14434  * Visibility mode constant for use with {@link #setVisibilityMode}. Use display to hide element
14435  * @static
14436  * @type Number
14437  */
14438 Ext.core.Element.DISPLAY = 2;
14439
14440 /**
14441  * Visibility mode constant for use with {@link #setVisibilityMode}. Use offsets (x and y positioning offscreen)
14442  * to hide element.
14443  * @static
14444  * @type Number
14445  */
14446 Ext.core.Element.OFFSETS = 3;
14447
14448
14449 Ext.core.Element.ASCLASS = 4;
14450
14451 /**
14452  * Defaults to 'x-hide-nosize'
14453  * @static
14454  * @type String
14455  */
14456 Ext.core.Element.visibilityCls = Ext.baseCSSPrefix + 'hide-nosize';
14457
14458 Ext.core.Element.addMethods(function(){
14459     var El = Ext.core.Element,
14460         OPACITY = "opacity",
14461         VISIBILITY = "visibility",
14462         DISPLAY = "display",
14463         HIDDEN = "hidden",
14464         OFFSETS = "offsets",
14465         ASCLASS = "asclass",
14466         NONE = "none",
14467         NOSIZE = 'nosize',
14468         ORIGINALDISPLAY = 'originalDisplay',
14469         VISMODE = 'visibilityMode',
14470         ISVISIBLE = 'isVisible',
14471         data = El.data,
14472         getDisplay = function(dom){
14473             var d = data(dom, ORIGINALDISPLAY);
14474             if(d === undefined){
14475                 data(dom, ORIGINALDISPLAY, d = '');
14476             }
14477             return d;
14478         },
14479         getVisMode = function(dom){
14480             var m = data(dom, VISMODE);
14481             if(m === undefined){
14482                 data(dom, VISMODE, m = 1);
14483             }
14484             return m;
14485         };
14486
14487     return {
14488         /**
14489          * The element's default display mode  (defaults to "")
14490          * @type String
14491          */
14492         originalDisplay : "",
14493         visibilityMode : 1,
14494
14495         /**
14496          * Sets the element's visibility mode. When setVisible() is called it
14497          * will use this to determine whether to set the visibility or the display property.
14498          * @param {Number} visMode Ext.core.Element.VISIBILITY or Ext.core.Element.DISPLAY
14499          * @return {Ext.core.Element} this
14500          */
14501         setVisibilityMode : function(visMode){
14502             data(this.dom, VISMODE, visMode);
14503             return this;
14504         },
14505
14506         /**
14507          * Checks whether the element is currently visible using both visibility and display properties.
14508          * @return {Boolean} True if the element is currently visible, else false
14509          */
14510         isVisible : function() {
14511             var me = this,
14512                 dom = me.dom,
14513                 visible = data(dom, ISVISIBLE);
14514
14515             if(typeof visible == 'boolean'){ //return the cached value if registered
14516                 return visible;
14517             }
14518             //Determine the current state based on display states
14519             visible = !me.isStyle(VISIBILITY, HIDDEN) &&
14520                       !me.isStyle(DISPLAY, NONE) &&
14521                       !((getVisMode(dom) == El.ASCLASS) && me.hasCls(me.visibilityCls || El.visibilityCls));
14522
14523             data(dom, ISVISIBLE, visible);
14524             return visible;
14525         },
14526
14527         /**
14528          * Sets the visibility of the element (see details). If the visibilityMode is set to Element.DISPLAY, it will use
14529          * the display property to hide the element, otherwise it uses visibility. The default is to hide and show using the visibility property.
14530          * @param {Boolean} visible Whether the element is visible
14531          * @param {Boolean/Object} animate (optional) True for the default animation, or a standard Element animation config object
14532          * @return {Ext.core.Element} this
14533          */
14534         setVisible : function(visible, animate){
14535             var me = this, isDisplay, isVisibility, isOffsets, isNosize,
14536                 dom = me.dom,
14537                 visMode = getVisMode(dom);
14538
14539
14540             // hideMode string override
14541             if (typeof animate == 'string'){
14542                 switch (animate) {
14543                     case DISPLAY:
14544                         visMode = El.DISPLAY;
14545                         break;
14546                     case VISIBILITY:
14547                         visMode = El.VISIBILITY;
14548                         break;
14549                     case OFFSETS:
14550                         visMode = El.OFFSETS;
14551                         break;
14552                     case NOSIZE:
14553                     case ASCLASS:
14554                         visMode = El.ASCLASS;
14555                         break;
14556                 }
14557                 me.setVisibilityMode(visMode);
14558                 animate = false;
14559             }
14560
14561             if (!animate || !me.anim) {
14562                 if(visMode == El.ASCLASS ){
14563
14564                     me[visible?'removeCls':'addCls'](me.visibilityCls || El.visibilityCls);
14565
14566                 } else if (visMode == El.DISPLAY){
14567
14568                     return me.setDisplayed(visible);
14569
14570                 } else if (visMode == El.OFFSETS){
14571
14572                     if (!visible){
14573                         // Remember position for restoring, if we are not already hidden by offsets.
14574                         if (!me.hideModeStyles) {
14575                             me.hideModeStyles = {
14576                                 position: me.getStyle('position'),
14577                                 top: me.getStyle('top'),
14578                                 left: me.getStyle('left')
14579                             };
14580                         }
14581                         me.applyStyles({position: 'absolute', top: '-10000px', left: '-10000px'});
14582                     }
14583
14584                     // Only "restore" as position if we have actually been hidden using offsets.
14585                     // Calling setVisible(true) on a positioned element should not reposition it.
14586                     else if (me.hideModeStyles) {
14587                         me.applyStyles(me.hideModeStyles || {position: '', top: '', left: ''});
14588                         delete me.hideModeStyles;
14589                     }
14590
14591                 }else{
14592                     me.fixDisplay();
14593                     // Show by clearing visibility style. Explicitly setting to "visible" overrides parent visibility setting.
14594                     dom.style.visibility = visible ? '' : HIDDEN;
14595                 }
14596             }else{
14597                 // closure for composites
14598                 if(visible){
14599                     me.setOpacity(0.01);
14600                     me.setVisible(true);
14601                 }
14602                 if (!Ext.isObject(animate)) {
14603                     animate = {
14604                         duration: 350,
14605                         easing: 'ease-in'
14606                     };
14607                 }
14608                 me.animate(Ext.applyIf({
14609                     callback: function() {
14610                         visible || me.setVisible(false).setOpacity(1);
14611                     },
14612                     to: {
14613                         opacity: (visible) ? 1 : 0
14614                     }
14615                 }, animate));
14616             }
14617             data(dom, ISVISIBLE, visible);  //set logical visibility state
14618             return me;
14619         },
14620
14621
14622         /**
14623          * @private
14624          * Determine if the Element has a relevant height and width available based
14625          * upon current logical visibility state
14626          */
14627         hasMetrics  : function(){
14628             var dom = this.dom;
14629             return this.isVisible() || (getVisMode(dom) == El.OFFSETS) || (getVisMode(dom) == El.VISIBILITY);
14630         },
14631
14632         /**
14633          * Toggles the element's visibility or display, depending on visibility mode.
14634          * @param {Boolean/Object} animate (optional) True for the default animation, or a standard Element animation config object
14635          * @return {Ext.core.Element} this
14636          */
14637         toggle : function(animate){
14638             var me = this;
14639             me.setVisible(!me.isVisible(), me.anim(animate));
14640             return me;
14641         },
14642
14643         /**
14644          * Sets the CSS display property. Uses originalDisplay if the specified value is a boolean true.
14645          * @param {Mixed} value Boolean value to display the element using its default display, or a string to set the display directly.
14646          * @return {Ext.core.Element} this
14647          */
14648         setDisplayed : function(value) {
14649             if(typeof value == "boolean"){
14650                value = value ? getDisplay(this.dom) : NONE;
14651             }
14652             this.setStyle(DISPLAY, value);
14653             return this;
14654         },
14655
14656         // private
14657         fixDisplay : function(){
14658             var me = this;
14659             if (me.isStyle(DISPLAY, NONE)) {
14660                 me.setStyle(VISIBILITY, HIDDEN);
14661                 me.setStyle(DISPLAY, getDisplay(this.dom)); // first try reverting to default
14662                 if (me.isStyle(DISPLAY, NONE)) { // if that fails, default to block
14663                     me.setStyle(DISPLAY, "block");
14664                 }
14665             }
14666         },
14667
14668         /**
14669          * Hide this element - Uses display mode to determine whether to use "display" or "visibility". See {@link #setVisible}.
14670          * @param {Boolean/Object} animate (optional) true for the default animation or a standard Element animation config object
14671          * @return {Ext.core.Element} this
14672          */
14673         hide : function(animate){
14674             // hideMode override
14675             if (typeof animate == 'string'){
14676                 this.setVisible(false, animate);
14677                 return this;
14678             }
14679             this.setVisible(false, this.anim(animate));
14680             return this;
14681         },
14682
14683         /**
14684         * Show this element - Uses display mode to determine whether to use "display" or "visibility". See {@link #setVisible}.
14685         * @param {Boolean/Object} animate (optional) true for the default animation or a standard Element animation config object
14686          * @return {Ext.core.Element} this
14687          */
14688         show : function(animate){
14689             // hideMode override
14690             if (typeof animate == 'string'){
14691                 this.setVisible(true, animate);
14692                 return this;
14693             }
14694             this.setVisible(true, this.anim(animate));
14695             return this;
14696         }
14697     };
14698 }());
14699 /**
14700  * @class Ext.core.Element
14701  */
14702 Ext.applyIf(Ext.core.Element.prototype, {
14703     // @private override base Ext.util.Animate mixin for animate for backwards compatibility
14704     animate: function(config) {
14705         var me = this;
14706         if (!me.id) {
14707             me = Ext.get(me.dom);
14708         }
14709         if (Ext.fx.Manager.hasFxBlock(me.id)) {
14710             return me;
14711         }
14712         Ext.fx.Manager.queueFx(Ext.create('Ext.fx.Anim', me.anim(config)));
14713         return this;
14714     },
14715
14716     // @private override base Ext.util.Animate mixin for animate for backwards compatibility
14717     anim: function(config) {
14718         if (!Ext.isObject(config)) {
14719             return (config) ? {} : false;
14720         }
14721
14722         var me = this,
14723             duration = config.duration || Ext.fx.Anim.prototype.duration,
14724             easing = config.easing || 'ease',
14725             animConfig;
14726
14727         if (config.stopAnimation) {
14728             me.stopAnimation();
14729         }
14730
14731         Ext.applyIf(config, Ext.fx.Manager.getFxDefaults(me.id));
14732
14733         // Clear any 'paused' defaults.
14734         Ext.fx.Manager.setFxDefaults(me.id, {
14735             delay: 0
14736         });
14737
14738         animConfig = {
14739             target: me,
14740             remove: config.remove,
14741             alternate: config.alternate || false,
14742             duration: duration,
14743             easing: easing,
14744             callback: config.callback,
14745             listeners: config.listeners,
14746             iterations: config.iterations || 1,
14747             scope: config.scope,
14748             block: config.block,
14749             concurrent: config.concurrent,
14750             delay: config.delay || 0,
14751             paused: true,
14752             keyframes: config.keyframes,
14753             from: config.from || {},
14754             to: Ext.apply({}, config)
14755         };
14756         Ext.apply(animConfig.to, config.to);
14757
14758         // Anim API properties - backward compat
14759         delete animConfig.to.to;
14760         delete animConfig.to.from;
14761         delete animConfig.to.remove;
14762         delete animConfig.to.alternate;
14763         delete animConfig.to.keyframes;
14764         delete animConfig.to.iterations;
14765         delete animConfig.to.listeners;
14766         delete animConfig.to.target;
14767         delete animConfig.to.paused;
14768         delete animConfig.to.callback;
14769         delete animConfig.to.scope;
14770         delete animConfig.to.duration;
14771         delete animConfig.to.easing;
14772         delete animConfig.to.concurrent;
14773         delete animConfig.to.block;
14774         delete animConfig.to.stopAnimation;
14775         delete animConfig.to.delay;
14776         return animConfig;
14777     },
14778
14779     /**
14780      * Slides the element into view.  An anchor point can be optionally passed to set the point of
14781      * origin for the slide effect.  This function automatically handles wrapping the element with
14782      * a fixed-size container if needed.  See the Fx class overview for valid anchor point options.
14783      * Usage:
14784      *<pre><code>
14785 // default: slide the element in from the top
14786 el.slideIn();
14787
14788 // custom: slide the element in from the right with a 2-second duration
14789 el.slideIn('r', { duration: 2 });
14790
14791 // common config options shown with default values
14792 el.slideIn('t', {
14793     easing: 'easeOut',
14794     duration: 500
14795 });
14796 </code></pre>
14797      * @param {String} anchor (optional) One of the valid Fx anchor positions (defaults to top: 't')
14798      * @param {Object} options (optional) Object literal with any of the Fx config options
14799      * @return {Ext.core.Element} The Element
14800      */
14801     slideIn: function(anchor, obj, slideOut) { 
14802         var me = this,
14803             elStyle = me.dom.style,
14804             beforeAnim, wrapAnim;
14805
14806         anchor = anchor || "t";
14807         obj = obj || {};
14808
14809         beforeAnim = function() {
14810             var animScope = this,
14811                 listeners = obj.listeners,
14812                 box, position, restoreSize, wrap, anim;
14813
14814             if (!slideOut) {
14815                 me.fixDisplay();
14816             }
14817
14818             box = me.getBox();
14819             if ((anchor == 't' || anchor == 'b') && box.height == 0) {
14820                 box.height = me.dom.scrollHeight;
14821             }
14822             else if ((anchor == 'l' || anchor == 'r') && box.width == 0) {
14823                 box.width = me.dom.scrollWidth;
14824             }
14825             
14826             position = me.getPositioning();
14827             me.setSize(box.width, box.height);
14828
14829             wrap = me.wrap({
14830                 style: {
14831                     visibility: slideOut ? 'visible' : 'hidden'
14832                 }
14833             });
14834             wrap.setPositioning(position);
14835             if (wrap.isStyle('position', 'static')) {
14836                 wrap.position('relative');
14837             }
14838             me.clearPositioning('auto');
14839             wrap.clip();
14840
14841             // This element is temporarily positioned absolute within its wrapper.
14842             // Restore to its default, CSS-inherited visibility setting.
14843             // We cannot explicitly poke visibility:visible into its style because that overrides the visibility of the wrap.
14844             me.setStyle({
14845                 visibility: '',
14846                 position: 'absolute'
14847             });
14848             if (slideOut) {
14849                 wrap.setSize(box.width, box.height);
14850             }
14851
14852             switch (anchor) {
14853                 case 't':
14854                     anim = {
14855                         from: {
14856                             width: box.width + 'px',
14857                             height: '0px'
14858                         },
14859                         to: {
14860                             width: box.width + 'px',
14861                             height: box.height + 'px'
14862                         }
14863                     };
14864                     elStyle.bottom = '0px';
14865                     break;
14866                 case 'l':
14867                     anim = {
14868                         from: {
14869                             width: '0px',
14870                             height: box.height + 'px'
14871                         },
14872                         to: {
14873                             width: box.width + 'px',
14874                             height: box.height + 'px'
14875                         }
14876                     };
14877                     elStyle.right = '0px';
14878                     break;
14879                 case 'r':
14880                     anim = {
14881                         from: {
14882                             x: box.x + box.width,
14883                             width: '0px',
14884                             height: box.height + 'px'
14885                         },
14886                         to: {
14887                             x: box.x,
14888                             width: box.width + 'px',
14889                             height: box.height + 'px'
14890                         }
14891                     };
14892                     break;
14893                 case 'b':
14894                     anim = {
14895                         from: {
14896                             y: box.y + box.height,
14897                             width: box.width + 'px',
14898                             height: '0px'
14899                         },
14900                         to: {
14901                             y: box.y,
14902                             width: box.width + 'px',
14903                             height: box.height + 'px'
14904                         }
14905                     };
14906                     break;
14907                 case 'tl':
14908                     anim = {
14909                         from: {
14910                             x: box.x,
14911                             y: box.y,
14912                             width: '0px',
14913                             height: '0px'
14914                         },
14915                         to: {
14916                             width: box.width + 'px',
14917                             height: box.height + 'px'
14918                         }
14919                     };
14920                     elStyle.bottom = '0px';
14921                     elStyle.right = '0px';
14922                     break;
14923                 case 'bl':
14924                     anim = {
14925                         from: {
14926                             x: box.x + box.width,
14927                             width: '0px',
14928                             height: '0px'
14929                         },
14930                         to: {
14931                             x: box.x,
14932                             width: box.width + 'px',
14933                             height: box.height + 'px'
14934                         }
14935                     };
14936                     elStyle.right = '0px';
14937                     break;
14938                 case 'br':
14939                     anim = {
14940                         from: {
14941                             x: box.x + box.width,
14942                             y: box.y + box.height,
14943                             width: '0px',
14944                             height: '0px'
14945                         },
14946                         to: {
14947                             x: box.x,
14948                             y: box.y,
14949                             width: box.width + 'px',
14950                             height: box.height + 'px'
14951                         }
14952                     };
14953                     break;
14954                 case 'tr':
14955                     anim = {
14956                         from: {
14957                             y: box.y + box.height,
14958                             width: '0px',
14959                             height: '0px'
14960                         },
14961                         to: {
14962                             y: box.y,
14963                             width: box.width + 'px',
14964                             height: box.height + 'px'
14965                         }
14966                     };
14967                     elStyle.bottom = '0px';
14968                     break;
14969             }
14970
14971             wrap.show();
14972             wrapAnim = Ext.apply({}, obj);
14973             delete wrapAnim.listeners;
14974             wrapAnim = Ext.create('Ext.fx.Anim', Ext.applyIf(wrapAnim, {
14975                 target: wrap,
14976                 duration: 500,
14977                 easing: 'ease-out',
14978                 from: slideOut ? anim.to : anim.from,
14979                 to: slideOut ? anim.from : anim.to
14980             }));
14981
14982             // In the absence of a callback, this listener MUST be added first
14983             wrapAnim.on('afteranimate', function() {
14984                 if (slideOut) {
14985                     me.setPositioning(position);
14986                     if (obj.useDisplay) {
14987                         me.setDisplayed(false);
14988                     } else {
14989                         me.hide();   
14990                     }
14991                 }
14992                 else {
14993                     me.clearPositioning();
14994                     me.setPositioning(position);
14995                 }
14996                 if (wrap.dom) {
14997                     wrap.dom.parentNode.insertBefore(me.dom, wrap.dom); 
14998                     wrap.remove();
14999                 }
15000                 me.setSize(box.width, box.height);
15001                 animScope.end();
15002             });
15003             // Add configured listeners after
15004             if (listeners) {
15005                 wrapAnim.on(listeners);
15006             }
15007         };
15008
15009         me.animate({
15010             duration: obj.duration ? obj.duration * 2 : 1000,
15011             listeners: {
15012                 beforeanimate: {
15013                     fn: beforeAnim
15014                 },
15015                 afteranimate: {
15016                     fn: function() {
15017                         if (wrapAnim && wrapAnim.running) {
15018                             wrapAnim.end();
15019                         }
15020                     }
15021                 }
15022             }
15023         });
15024         return me;
15025     },
15026
15027     
15028     /**
15029      * Slides the element out of view.  An anchor point can be optionally passed to set the end point
15030      * for the slide effect.  When the effect is completed, the element will be hidden (visibility = 
15031      * 'hidden') but block elements will still take up space in the document.  The element must be removed
15032      * from the DOM using the 'remove' config option if desired.  This function automatically handles 
15033      * wrapping the element with a fixed-size container if needed.  See the Fx class overview for valid anchor point options.
15034      * Usage:
15035      *<pre><code>
15036 // default: slide the element out to the top
15037 el.slideOut();
15038
15039 // custom: slide the element out to the right with a 2-second duration
15040 el.slideOut('r', { duration: 2 });
15041
15042 // common config options shown with default values
15043 el.slideOut('t', {
15044     easing: 'easeOut',
15045     duration: 500,
15046     remove: false,
15047     useDisplay: false
15048 });
15049 </code></pre>
15050      * @param {String} anchor (optional) One of the valid Fx anchor positions (defaults to top: 't')
15051      * @param {Object} options (optional) Object literal with any of the Fx config options
15052      * @return {Ext.core.Element} The Element
15053      */
15054     slideOut: function(anchor, o) {
15055         return this.slideIn(anchor, o, true);
15056     },
15057
15058     /**
15059      * Fades the element out while slowly expanding it in all directions.  When the effect is completed, the 
15060      * element will be hidden (visibility = 'hidden') but block elements will still take up space in the document.
15061      * Usage:
15062      *<pre><code>
15063 // default
15064 el.puff();
15065
15066 // common config options shown with default values
15067 el.puff({
15068     easing: 'easeOut',
15069     duration: 500,
15070     useDisplay: false
15071 });
15072 </code></pre>
15073      * @param {Object} options (optional) Object literal with any of the Fx config options
15074      * @return {Ext.core.Element} The Element
15075      */
15076
15077     puff: function(obj) {
15078         var me = this,
15079             beforeAnim;
15080         obj = Ext.applyIf(obj || {}, {
15081             easing: 'ease-out',
15082             duration: 500,
15083             useDisplay: false
15084         });
15085
15086         beforeAnim = function() {
15087             me.clearOpacity();
15088             me.show();
15089
15090             var box = me.getBox(),
15091                 fontSize = me.getStyle('fontSize'),
15092                 position = me.getPositioning();
15093             this.to = {
15094                 width: box.width * 2,
15095                 height: box.height * 2,
15096                 x: box.x - (box.width / 2),
15097                 y: box.y - (box.height /2),
15098                 opacity: 0,
15099                 fontSize: '200%'
15100             };
15101             this.on('afteranimate',function() {
15102                 if (me.dom) {
15103                     if (obj.useDisplay) {
15104                         me.setDisplayed(false);
15105                     } else {
15106                         me.hide();
15107                     }
15108                     me.clearOpacity();  
15109                     me.setPositioning(position);
15110                     me.setStyle({fontSize: fontSize});
15111                 }
15112             });
15113         };
15114
15115         me.animate({
15116             duration: obj.duration,
15117             easing: obj.easing,
15118             listeners: {
15119                 beforeanimate: {
15120                     fn: beforeAnim
15121                 }
15122             }
15123         });
15124         return me;
15125     },
15126
15127     /**
15128      * Blinks the element as if it was clicked and then collapses on its center (similar to switching off a television).
15129      * When the effect is completed, the element will be hidden (visibility = 'hidden') but block elements will still 
15130      * take up space in the document. The element must be removed from the DOM using the 'remove' config option if desired.
15131      * Usage:
15132      *<pre><code>
15133 // default
15134 el.switchOff();
15135
15136 // all config options shown with default values
15137 el.switchOff({
15138     easing: 'easeIn',
15139     duration: .3,
15140     remove: false,
15141     useDisplay: false
15142 });
15143 </code></pre>
15144      * @param {Object} options (optional) Object literal with any of the Fx config options
15145      * @return {Ext.core.Element} The Element
15146      */
15147     switchOff: function(obj) {
15148         var me = this,
15149             beforeAnim;
15150         
15151         obj = Ext.applyIf(obj || {}, {
15152             easing: 'ease-in',
15153             duration: 500,
15154             remove: false,
15155             useDisplay: false
15156         });
15157
15158         beforeAnim = function() {
15159             var animScope = this,
15160                 size = me.getSize(),
15161                 xy = me.getXY(),
15162                 keyframe, position;
15163             me.clearOpacity();
15164             me.clip();
15165             position = me.getPositioning();
15166
15167             keyframe = Ext.create('Ext.fx.Animator', {
15168                 target: me,
15169                 duration: obj.duration,
15170                 easing: obj.easing,
15171                 keyframes: {
15172                     33: {
15173                         opacity: 0.3
15174                     },
15175                     66: {
15176                         height: 1,
15177                         y: xy[1] + size.height / 2
15178                     },
15179                     100: {
15180                         width: 1,
15181                         x: xy[0] + size.width / 2
15182                     }
15183                 }
15184             });
15185             keyframe.on('afteranimate', function() {
15186                 if (obj.useDisplay) {
15187                     me.setDisplayed(false);
15188                 } else {
15189                     me.hide();
15190                 }  
15191                 me.clearOpacity();
15192                 me.setPositioning(position);
15193                 me.setSize(size);
15194                 animScope.end();
15195             });
15196         };
15197         me.animate({
15198             duration: (obj.duration * 2),
15199             listeners: {
15200                 beforeanimate: {
15201                     fn: beforeAnim
15202                 }
15203             }
15204         });
15205         return me;
15206     },
15207
15208    /**
15209     * Shows a ripple of exploding, attenuating borders to draw attention to an Element.
15210     * Usage:
15211 <pre><code>
15212 // default: a single light blue ripple
15213 el.frame();
15214
15215 // custom: 3 red ripples lasting 3 seconds total
15216 el.frame("#ff0000", 3, { duration: 3 });
15217
15218 // common config options shown with default values
15219 el.frame("#C3DAF9", 1, {
15220     duration: 1 //duration of each individual ripple.
15221     // Note: Easing is not configurable and will be ignored if included
15222 });
15223 </code></pre>
15224     * @param {String} color (optional) The color of the border.  Should be a 6 char hex color without the leading # (defaults to light blue: 'C3DAF9').
15225     * @param {Number} count (optional) The number of ripples to display (defaults to 1)
15226     * @param {Object} options (optional) Object literal with any of the Fx config options
15227     * @return {Ext.core.Element} The Element
15228     */
15229     frame : function(color, count, obj){
15230         var me = this,
15231             beforeAnim;
15232
15233         color = color || '#C3DAF9';
15234         count = count || 1;
15235         obj = obj || {};
15236
15237         beforeAnim = function() {
15238             me.show();
15239             var animScope = this,
15240                 box = me.getBox(),
15241                 proxy = Ext.getBody().createChild({
15242                     style: {
15243                         position : 'absolute',
15244                         'pointer-events': 'none',
15245                         'z-index': 35000,
15246                         border : '0px solid ' + color
15247                     }
15248                 }),
15249                 proxyAnim;
15250             proxyAnim = Ext.create('Ext.fx.Anim', {
15251                 target: proxy,
15252                 duration: obj.duration || 1000,
15253                 iterations: count,
15254                 from: {
15255                     top: box.y,
15256                     left: box.x,
15257                     borderWidth: 0,
15258                     opacity: 1,
15259                     height: box.height,
15260                     width: box.width
15261                 },
15262                 to: {
15263                     top: box.y - 20,
15264                     left: box.x - 20,
15265                     borderWidth: 10,
15266                     opacity: 0,
15267                     height: box.height + 40,
15268                     width: box.width + 40
15269                 }
15270             });
15271             proxyAnim.on('afteranimate', function() {
15272                 proxy.remove();
15273                 animScope.end();
15274             });
15275         };
15276
15277         me.animate({
15278             duration: (obj.duration * 2) || 2000,
15279             listeners: {
15280                 beforeanimate: {
15281                     fn: beforeAnim
15282                 }
15283             }
15284         });
15285         return me;
15286     },
15287
15288     /**
15289      * Slides the element while fading it out of view.  An anchor point can be optionally passed to set the 
15290      * ending point of the effect.
15291      * Usage:
15292      *<pre><code>
15293 // default: slide the element downward while fading out
15294 el.ghost();
15295
15296 // custom: slide the element out to the right with a 2-second duration
15297 el.ghost('r', { duration: 2 });
15298
15299 // common config options shown with default values
15300 el.ghost('b', {
15301     easing: 'easeOut',
15302     duration: 500
15303 });
15304 </code></pre>
15305      * @param {String} anchor (optional) One of the valid Fx anchor positions (defaults to bottom: 'b')
15306      * @param {Object} options (optional) Object literal with any of the Fx config options
15307      * @return {Ext.core.Element} The Element
15308      */
15309     ghost: function(anchor, obj) {
15310         var me = this,
15311             beforeAnim;
15312
15313         anchor = anchor || "b";
15314         beforeAnim = function() {
15315             var width = me.getWidth(),
15316                 height = me.getHeight(),
15317                 xy = me.getXY(),
15318                 position = me.getPositioning(),
15319                 to = {
15320                     opacity: 0
15321                 };
15322             switch (anchor) {
15323                 case 't':
15324                     to.y = xy[1] - height;
15325                     break;
15326                 case 'l':
15327                     to.x = xy[0] - width;
15328                     break;
15329                 case 'r':
15330                     to.x = xy[0] + width;
15331                     break;
15332                 case 'b':
15333                     to.y = xy[1] + height;
15334                     break;
15335                 case 'tl':
15336                     to.x = xy[0] - width;
15337                     to.y = xy[1] - height;
15338                     break;
15339                 case 'bl':
15340                     to.x = xy[0] - width;
15341                     to.y = xy[1] + height;
15342                     break;
15343                 case 'br':
15344                     to.x = xy[0] + width;
15345                     to.y = xy[1] + height;
15346                     break;
15347                 case 'tr':
15348                     to.x = xy[0] + width;
15349                     to.y = xy[1] - height;
15350                     break;
15351             }
15352             this.to = to;
15353             this.on('afteranimate', function () {
15354                 if (me.dom) {
15355                     me.hide();
15356                     me.clearOpacity();
15357                     me.setPositioning(position);
15358                 }
15359             });
15360         };
15361
15362         me.animate(Ext.applyIf(obj || {}, {
15363             duration: 500,
15364             easing: 'ease-out',
15365             listeners: {
15366                 beforeanimate: {
15367                     fn: beforeAnim
15368                 }
15369             }
15370         }));
15371         return me;
15372     },
15373
15374     /**
15375      * Highlights the Element by setting a color (applies to the background-color by default, but can be
15376      * changed using the "attr" config option) and then fading back to the original color. If no original
15377      * color is available, you should provide the "endColor" config option which will be cleared after the animation.
15378      * Usage:
15379 <pre><code>
15380 // default: highlight background to yellow
15381 el.highlight();
15382
15383 // custom: highlight foreground text to blue for 2 seconds
15384 el.highlight("0000ff", { attr: 'color', duration: 2 });
15385
15386 // common config options shown with default values
15387 el.highlight("ffff9c", {
15388     attr: "backgroundColor", //can be any valid CSS property (attribute) that supports a color value
15389     endColor: (current color) or "ffffff",
15390     easing: 'easeIn',
15391     duration: 1000
15392 });
15393 </code></pre>
15394      * @param {String} color (optional) The highlight color. Should be a 6 char hex color without the leading # (defaults to yellow: 'ffff9c')
15395      * @param {Object} options (optional) Object literal with any of the Fx config options
15396      * @return {Ext.core.Element} The Element
15397      */ 
15398     highlight: function(color, o) {
15399         var me = this,
15400             dom = me.dom,
15401             from = {},
15402             restore, to, attr, lns, event, fn;
15403
15404         o = o || {};
15405         lns = o.listeners || {};
15406         attr = o.attr || 'backgroundColor';
15407         from[attr] = color || 'ffff9c';
15408         
15409         if (!o.to) {
15410             to = {};
15411             to[attr] = o.endColor || me.getColor(attr, 'ffffff', '');
15412         }
15413         else {
15414             to = o.to;
15415         }
15416         
15417         // Don't apply directly on lns, since we reference it in our own callbacks below
15418         o.listeners = Ext.apply(Ext.apply({}, lns), {
15419             beforeanimate: function() {
15420                 restore = dom.style[attr];
15421                 me.clearOpacity();
15422                 me.show();
15423                 
15424                 event = lns.beforeanimate;
15425                 if (event) {
15426                     fn = event.fn || event;
15427                     return fn.apply(event.scope || lns.scope || window, arguments);
15428                 }
15429             },
15430             afteranimate: function() {
15431                 if (dom) {
15432                     dom.style[attr] = restore;
15433                 }
15434                 
15435                 event = lns.afteranimate;
15436                 if (event) {
15437                     fn = event.fn || event;
15438                     fn.apply(event.scope || lns.scope || window, arguments);
15439                 }
15440             }
15441         });
15442
15443         me.animate(Ext.apply({}, o, {
15444             duration: 1000,
15445             easing: 'ease-in',
15446             from: from,
15447             to: to
15448         }));
15449         return me;
15450     },
15451
15452    /**
15453     * @deprecated 4.0
15454     * Creates a pause before any subsequent queued effects begin.  If there are
15455     * no effects queued after the pause it will have no effect.
15456     * Usage:
15457 <pre><code>
15458 el.pause(1);
15459 </code></pre>
15460     * @param {Number} seconds The length of time to pause (in seconds)
15461     * @return {Ext.Element} The Element
15462     */
15463     pause: function(ms) {
15464         var me = this;
15465         Ext.fx.Manager.setFxDefaults(me.id, {
15466             delay: ms
15467         });
15468         return me;
15469     },
15470
15471    /**
15472     * Fade an element in (from transparent to opaque).  The ending opacity can be specified
15473     * using the <tt>{@link #endOpacity}</tt> config option.
15474     * Usage:
15475 <pre><code>
15476 // default: fade in from opacity 0 to 100%
15477 el.fadeIn();
15478
15479 // custom: fade in from opacity 0 to 75% over 2 seconds
15480 el.fadeIn({ endOpacity: .75, duration: 2});
15481
15482 // common config options shown with default values
15483 el.fadeIn({
15484     endOpacity: 1, //can be any value between 0 and 1 (e.g. .5)
15485     easing: 'easeOut',
15486     duration: 500
15487 });
15488 </code></pre>
15489     * @param {Object} options (optional) Object literal with any of the Fx config options
15490     * @return {Ext.Element} The Element
15491     */
15492     fadeIn: function(o) {
15493         this.animate(Ext.apply({}, o, {
15494             opacity: 1
15495         }));
15496         return this;
15497     },
15498
15499    /**
15500     * Fade an element out (from opaque to transparent).  The ending opacity can be specified
15501     * using the <tt>{@link #endOpacity}</tt> config option.  Note that IE may require
15502     * <tt>{@link #useDisplay}:true</tt> in order to redisplay correctly.
15503     * Usage:
15504 <pre><code>
15505 // default: fade out from the element's current opacity to 0
15506 el.fadeOut();
15507
15508 // custom: fade out from the element's current opacity to 25% over 2 seconds
15509 el.fadeOut({ endOpacity: .25, duration: 2});
15510
15511 // common config options shown with default values
15512 el.fadeOut({
15513     endOpacity: 0, //can be any value between 0 and 1 (e.g. .5)
15514     easing: 'easeOut',
15515     duration: 500,
15516     remove: false,
15517     useDisplay: false
15518 });
15519 </code></pre>
15520     * @param {Object} options (optional) Object literal with any of the Fx config options
15521     * @return {Ext.Element} The Element
15522     */
15523     fadeOut: function(o) {
15524         this.animate(Ext.apply({}, o, {
15525             opacity: 0
15526         }));
15527         return this;
15528     },
15529
15530    /**
15531     * @deprecated 4.0
15532     * Animates the transition of an element's dimensions from a starting height/width
15533     * to an ending height/width.  This method is a convenience implementation of {@link #shift}.
15534     * Usage:
15535 <pre><code>
15536 // change height and width to 100x100 pixels
15537 el.scale(100, 100);
15538
15539 // common config options shown with default values.  The height and width will default to
15540 // the element&#39;s existing values if passed as null.
15541 el.scale(
15542     [element&#39;s width],
15543     [element&#39;s height], {
15544         easing: 'easeOut',
15545         duration: .35
15546     }
15547 );
15548 </code></pre>
15549     * @param {Number} width  The new width (pass undefined to keep the original width)
15550     * @param {Number} height  The new height (pass undefined to keep the original height)
15551     * @param {Object} options (optional) Object literal with any of the Fx config options
15552     * @return {Ext.Element} The Element
15553     */
15554     scale: function(w, h, o) {
15555         this.animate(Ext.apply({}, o, {
15556             width: w,
15557             height: h
15558         }));
15559         return this;
15560     },
15561
15562    /**
15563     * @deprecated 4.0
15564     * Animates the transition of any combination of an element's dimensions, xy position and/or opacity.
15565     * Any of these properties not specified in the config object will not be changed.  This effect 
15566     * requires that at least one new dimension, position or opacity setting must be passed in on
15567     * the config object in order for the function to have any effect.
15568     * Usage:
15569 <pre><code>
15570 // slide the element horizontally to x position 200 while changing the height and opacity
15571 el.shift({ x: 200, height: 50, opacity: .8 });
15572
15573 // common config options shown with default values.
15574 el.shift({
15575     width: [element&#39;s width],
15576     height: [element&#39;s height],
15577     x: [element&#39;s x position],
15578     y: [element&#39;s y position],
15579     opacity: [element&#39;s opacity],
15580     easing: 'easeOut',
15581     duration: .35
15582 });
15583 </code></pre>
15584     * @param {Object} options  Object literal with any of the Fx config options
15585     * @return {Ext.Element} The Element
15586     */
15587     shift: function(config) {
15588         this.animate(config);
15589         return this;
15590     }
15591 });
15592
15593 /**
15594  * @class Ext.core.Element
15595  */
15596 Ext.applyIf(Ext.core.Element, {
15597     unitRe: /\d+(px|em|%|en|ex|pt|in|cm|mm|pc)$/i,
15598     camelRe: /(-[a-z])/gi,
15599     opacityRe: /alpha\(opacity=(.*)\)/i,
15600     cssRe: /([a-z0-9-]+)\s*:\s*([^;\s]+(?:\s*[^;\s]+)*);?/gi,
15601     propertyCache: {},
15602     defaultUnit : "px",
15603     borders: {l: 'border-left-width', r: 'border-right-width', t: 'border-top-width', b: 'border-bottom-width'},
15604     paddings: {l: 'padding-left', r: 'padding-right', t: 'padding-top', b: 'padding-bottom'},
15605     margins: {l: 'margin-left', r: 'margin-right', t: 'margin-top', b: 'margin-bottom'},
15606
15607     // Reference the prototype's version of the method. Signatures are identical.
15608     addUnits : Ext.core.Element.prototype.addUnits,
15609
15610     /**
15611      * Parses a number or string representing margin sizes into an object. Supports CSS-style margin declarations
15612      * (e.g. 10, "10", "10 10", "10 10 10" and "10 10 10 10" are all valid options and would return the same result)
15613      * @static
15614      * @param {Number|String} box The encoded margins
15615      * @return {Object} An object with margin sizes for top, right, bottom and left
15616      */
15617     parseBox : function(box) {
15618         if (Ext.isObject(box)) {
15619             return {
15620                 top: box.top || 0,
15621                 right: box.right || 0,
15622                 bottom: box.bottom || 0,
15623                 left: box.left || 0
15624             };
15625         } else {
15626             if (typeof box != 'string') {
15627                 box = box.toString();
15628             }
15629             var parts  = box.split(' '),
15630                 ln = parts.length;
15631     
15632             if (ln == 1) {
15633                 parts[1] = parts[2] = parts[3] = parts[0];
15634             }
15635             else if (ln == 2) {
15636                 parts[2] = parts[0];
15637                 parts[3] = parts[1];
15638             }
15639             else if (ln == 3) {
15640                 parts[3] = parts[1];
15641             }
15642     
15643             return {
15644                 top   :parseFloat(parts[0]) || 0,
15645                 right :parseFloat(parts[1]) || 0,
15646                 bottom:parseFloat(parts[2]) || 0,
15647                 left  :parseFloat(parts[3]) || 0
15648             };
15649         }
15650         
15651     },
15652     
15653     /**
15654      * Parses a number or string representing margin sizes into an object. Supports CSS-style margin declarations
15655      * (e.g. 10, "10", "10 10", "10 10 10" and "10 10 10 10" are all valid options and would return the same result)
15656      * @static
15657      * @param {Number|String} box The encoded margins
15658      * @param {String} units The type of units to add
15659      * @return {String} An string with unitized (px if units is not specified) metrics for top, right, bottom and left
15660      */
15661     unitizeBox : function(box, units) {
15662         var A = this.addUnits,
15663             B = this.parseBox(box);
15664             
15665         return A(B.top, units) + ' ' +
15666                A(B.right, units) + ' ' +
15667                A(B.bottom, units) + ' ' +
15668                A(B.left, units);
15669         
15670     },
15671
15672     // private
15673     camelReplaceFn : function(m, a) {
15674         return a.charAt(1).toUpperCase();
15675     },
15676
15677     /**
15678      * Normalizes CSS property keys from dash delimited to camel case JavaScript Syntax.
15679      * For example:
15680      * <ul>
15681      *  <li>border-width -> borderWidth</li>
15682      *  <li>padding-top -> paddingTop</li>
15683      * </ul>
15684      * @static
15685      * @param {String} prop The property to normalize
15686      * @return {String} The normalized string
15687      */
15688     normalize : function(prop) {
15689         if (prop == 'float') {
15690             prop = Ext.supports.Float ? 'cssFloat' : 'styleFloat';
15691         }
15692         return this.propertyCache[prop] || (this.propertyCache[prop] = prop.replace(this.camelRe, this.camelReplaceFn));
15693     },
15694
15695     /**
15696      * Retrieves the document height
15697      * @static
15698      * @return {Number} documentHeight
15699      */
15700     getDocumentHeight: function() {
15701         return Math.max(!Ext.isStrict ? document.body.scrollHeight : document.documentElement.scrollHeight, this.getViewportHeight());
15702     },
15703
15704     /**
15705      * Retrieves the document width
15706      * @static
15707      * @return {Number} documentWidth
15708      */
15709     getDocumentWidth: function() {
15710         return Math.max(!Ext.isStrict ? document.body.scrollWidth : document.documentElement.scrollWidth, this.getViewportWidth());
15711     },
15712
15713     /**
15714      * Retrieves the viewport height of the window.
15715      * @static
15716      * @return {Number} viewportHeight
15717      */
15718     getViewportHeight: function(){
15719         return window.innerHeight;
15720     },
15721
15722     /**
15723      * Retrieves the viewport width of the window.
15724      * @static
15725      * @return {Number} viewportWidth
15726      */
15727     getViewportWidth : function() {
15728         return window.innerWidth;
15729     },
15730
15731     /**
15732      * Retrieves the viewport size of the window.
15733      * @static
15734      * @return {Object} object containing width and height properties
15735      */
15736     getViewSize : function() {
15737         return {
15738             width: window.innerWidth,
15739             height: window.innerHeight
15740         };
15741     },
15742
15743     /**
15744      * Retrieves the current orientation of the window. This is calculated by
15745      * determing if the height is greater than the width.
15746      * @static
15747      * @return {String} Orientation of window: 'portrait' or 'landscape'
15748      */
15749     getOrientation : function() {
15750         if (Ext.supports.OrientationChange) {
15751             return (window.orientation == 0) ? 'portrait' : 'landscape';
15752         }
15753         
15754         return (window.innerHeight > window.innerWidth) ? 'portrait' : 'landscape';
15755     },
15756
15757     /** 
15758      * Returns the top Element that is located at the passed coordinates
15759      * @static
15760      * @param {Number} x The x coordinate
15761      * @param {Number} x The y coordinate
15762      * @return {String} The found Element
15763      */
15764     fromPoint: function(x, y) {
15765         return Ext.get(document.elementFromPoint(x, y));
15766     },
15767     
15768     /**
15769      * Converts a CSS string into an object with a property for each style.
15770      * <p>
15771      * The sample code below would return an object with 2 properties, one
15772      * for background-color and one for color.</p>
15773      * <pre><code>
15774 var css = 'background-color: red;color: blue; ';
15775 console.log(Ext.core.Element.parseStyles(css));
15776      * </code></pre>
15777      * @static
15778      * @param {String} styles A CSS string
15779      * @return {Object} styles
15780      */
15781     parseStyles: function(styles){
15782         var out = {},
15783             cssRe = this.cssRe,
15784             matches;
15785             
15786         if (styles) {
15787             // Since we're using the g flag on the regex, we need to set the lastIndex.
15788             // This automatically happens on some implementations, but not others, see:
15789             // http://stackoverflow.com/questions/2645273/javascript-regular-expression-literal-persists-between-function-calls
15790             // http://blog.stevenlevithan.com/archives/fixing-javascript-regexp
15791             cssRe.lastIndex = 0;
15792             while ((matches = cssRe.exec(styles))) {
15793                 out[matches[1]] = matches[2];
15794             }
15795         }
15796         return out;
15797     }
15798 });
15799
15800 /**
15801  * @class Ext.CompositeElementLite
15802  * <p>This class encapsulates a <i>collection</i> of DOM elements, providing methods to filter
15803  * members, or to perform collective actions upon the whole set.</p>
15804  * <p>Although they are not listed, this class supports all of the methods of {@link Ext.core.Element} and
15805  * {@link Ext.fx.Anim}. The methods from these classes will be performed on all the elements in this collection.</p>
15806  * Example:<pre><code>
15807 var els = Ext.select("#some-el div.some-class");
15808 // or select directly from an existing element
15809 var el = Ext.get('some-el');
15810 el.select('div.some-class');
15811
15812 els.setWidth(100); // all elements become 100 width
15813 els.hide(true); // all elements fade out and hide
15814 // or
15815 els.setWidth(100).hide(true);
15816 </code></pre>
15817  */
15818 Ext.CompositeElementLite = function(els, root){
15819     /**
15820      * <p>The Array of DOM elements which this CompositeElement encapsulates. Read-only.</p>
15821      * <p>This will not <i>usually</i> be accessed in developers' code, but developers wishing
15822      * to augment the capabilities of the CompositeElementLite class may use it when adding
15823      * methods to the class.</p>
15824      * <p>For example to add the <code>nextAll</code> method to the class to <b>add</b> all
15825      * following siblings of selected elements, the code would be</p><code><pre>
15826 Ext.override(Ext.CompositeElementLite, {
15827     nextAll: function() {
15828         var els = this.elements, i, l = els.length, n, r = [], ri = -1;
15829
15830 //      Loop through all elements in this Composite, accumulating
15831 //      an Array of all siblings.
15832         for (i = 0; i < l; i++) {
15833             for (n = els[i].nextSibling; n; n = n.nextSibling) {
15834                 r[++ri] = n;
15835             }
15836         }
15837
15838 //      Add all found siblings to this Composite
15839         return this.add(r);
15840     }
15841 });</pre></code>
15842      * @type Array
15843      * @property elements
15844      */
15845     this.elements = [];
15846     this.add(els, root);
15847     this.el = new Ext.core.Element.Flyweight();
15848 };
15849
15850 Ext.CompositeElementLite.prototype = {
15851     isComposite: true,
15852
15853     // private
15854     getElement : function(el){
15855         // Set the shared flyweight dom property to the current element
15856         var e = this.el;
15857         e.dom = el;
15858         e.id = el.id;
15859         return e;
15860     },
15861
15862     // private
15863     transformElement : function(el){
15864         return Ext.getDom(el);
15865     },
15866
15867     /**
15868      * Returns the number of elements in this Composite.
15869      * @return Number
15870      */
15871     getCount : function(){
15872         return this.elements.length;
15873     },
15874     /**
15875      * Adds elements to this Composite object.
15876      * @param {Mixed} els Either an Array of DOM elements to add, or another Composite object who's elements should be added.
15877      * @return {CompositeElement} This Composite object.
15878      */
15879     add : function(els, root){
15880         var me = this,
15881             elements = me.elements;
15882         if(!els){
15883             return this;
15884         }
15885         if(typeof els == "string"){
15886             els = Ext.core.Element.selectorFunction(els, root);
15887         }else if(els.isComposite){
15888             els = els.elements;
15889         }else if(!Ext.isIterable(els)){
15890             els = [els];
15891         }
15892
15893         for(var i = 0, len = els.length; i < len; ++i){
15894             elements.push(me.transformElement(els[i]));
15895         }
15896         return me;
15897     },
15898
15899     invoke : function(fn, args){
15900         var me = this,
15901             els = me.elements,
15902             len = els.length,
15903             e,
15904             i;
15905
15906         for(i = 0; i < len; i++) {
15907             e = els[i];
15908             if(e){
15909                 Ext.core.Element.prototype[fn].apply(me.getElement(e), args);
15910             }
15911         }
15912         return me;
15913     },
15914     /**
15915      * Returns a flyweight Element of the dom element object at the specified index
15916      * @param {Number} index
15917      * @return {Ext.core.Element}
15918      */
15919     item : function(index){
15920         var me = this,
15921             el = me.elements[index],
15922             out = null;
15923
15924         if(el){
15925             out = me.getElement(el);
15926         }
15927         return out;
15928     },
15929
15930     // fixes scope with flyweight
15931     addListener : function(eventName, handler, scope, opt){
15932         var els = this.elements,
15933             len = els.length,
15934             i, e;
15935
15936         for(i = 0; i<len; i++) {
15937             e = els[i];
15938             if(e) {
15939                 Ext.EventManager.on(e, eventName, handler, scope || e, opt);
15940             }
15941         }
15942         return this;
15943     },
15944     /**
15945      * <p>Calls the passed function for each element in this composite.</p>
15946      * @param {Function} fn The function to call. The function is passed the following parameters:<ul>
15947      * <li><b>el</b> : Element<div class="sub-desc">The current Element in the iteration.
15948      * <b>This is the flyweight (shared) Ext.core.Element instance, so if you require a
15949      * a reference to the dom node, use el.dom.</b></div></li>
15950      * <li><b>c</b> : Composite<div class="sub-desc">This Composite object.</div></li>
15951      * <li><b>idx</b> : Number<div class="sub-desc">The zero-based index in the iteration.</div></li>
15952      * </ul>
15953      * @param {Object} scope (optional) The scope (<i>this</i> reference) in which the function is executed. (defaults to the Element)
15954      * @return {CompositeElement} this
15955      */
15956     each : function(fn, scope){
15957         var me = this,
15958             els = me.elements,
15959             len = els.length,
15960             i, e;
15961
15962         for(i = 0; i<len; i++) {
15963             e = els[i];
15964             if(e){
15965                 e = this.getElement(e);
15966                 if(fn.call(scope || e, e, me, i) === false){
15967                     break;
15968                 }
15969             }
15970         }
15971         return me;
15972     },
15973
15974     /**
15975     * Clears this Composite and adds the elements passed.
15976     * @param {Mixed} els Either an array of DOM elements, or another Composite from which to fill this Composite.
15977     * @return {CompositeElement} this
15978     */
15979     fill : function(els){
15980         var me = this;
15981         me.elements = [];
15982         me.add(els);
15983         return me;
15984     },
15985
15986     /**
15987      * Filters this composite to only elements that match the passed selector.
15988      * @param {String/Function} selector A string CSS selector or a comparison function.
15989      * The comparison function will be called with the following arguments:<ul>
15990      * <li><code>el</code> : Ext.core.Element<div class="sub-desc">The current DOM element.</div></li>
15991      * <li><code>index</code> : Number<div class="sub-desc">The current index within the collection.</div></li>
15992      * </ul>
15993      * @return {CompositeElement} this
15994      */
15995     filter : function(selector){
15996         var els = [],
15997             me = this,
15998             fn = Ext.isFunction(selector) ? selector
15999                 : function(el){
16000                     return el.is(selector);
16001                 };
16002
16003         me.each(function(el, self, i) {
16004             if (fn(el, i) !== false) {
16005                 els[els.length] = me.transformElement(el);
16006             }
16007         });
16008         
16009         me.elements = els;
16010         return me;
16011     },
16012
16013     /**
16014      * Find the index of the passed element within the composite collection.
16015      * @param el {Mixed} The id of an element, or an Ext.core.Element, or an HtmlElement to find within the composite collection.
16016      * @return Number The index of the passed Ext.core.Element in the composite collection, or -1 if not found.
16017      */
16018     indexOf : function(el){
16019         return Ext.Array.indexOf(this.elements, this.transformElement(el));
16020     },
16021
16022     /**
16023     * Replaces the specified element with the passed element.
16024     * @param {Mixed} el The id of an element, the Element itself, the index of the element in this composite
16025     * to replace.
16026     * @param {Mixed} replacement The id of an element or the Element itself.
16027     * @param {Boolean} domReplace (Optional) True to remove and replace the element in the document too.
16028     * @return {CompositeElement} this
16029     */
16030     replaceElement : function(el, replacement, domReplace){
16031         var index = !isNaN(el) ? el : this.indexOf(el),
16032             d;
16033         if(index > -1){
16034             replacement = Ext.getDom(replacement);
16035             if(domReplace){
16036                 d = this.elements[index];
16037                 d.parentNode.insertBefore(replacement, d);
16038                 Ext.removeNode(d);
16039             }
16040             Ext.Array.splice(this.elements, index, 1, replacement);
16041         }
16042         return this;
16043     },
16044
16045     /**
16046      * Removes all elements.
16047      */
16048     clear : function(){
16049         this.elements = [];
16050     }
16051 };
16052
16053 Ext.CompositeElementLite.prototype.on = Ext.CompositeElementLite.prototype.addListener;
16054
16055 /**
16056  * @private
16057  * Copies all of the functions from Ext.core.Element's prototype onto CompositeElementLite's prototype.
16058  * This is called twice - once immediately below, and once again after additional Ext.core.Element
16059  * are added in Ext JS
16060  */
16061 Ext.CompositeElementLite.importElementMethods = function() {
16062     var fnName,
16063         ElProto = Ext.core.Element.prototype,
16064         CelProto = Ext.CompositeElementLite.prototype;
16065
16066     for (fnName in ElProto) {
16067         if (typeof ElProto[fnName] == 'function'){
16068             (function(fnName) {
16069                 CelProto[fnName] = CelProto[fnName] || function() {
16070                     return this.invoke(fnName, arguments);
16071                 };
16072             }).call(CelProto, fnName);
16073
16074         }
16075     }
16076 };
16077
16078 Ext.CompositeElementLite.importElementMethods();
16079
16080 if(Ext.DomQuery){
16081     Ext.core.Element.selectorFunction = Ext.DomQuery.select;
16082 }
16083
16084 /**
16085  * Selects elements based on the passed CSS selector to enable {@link Ext.core.Element Element} methods
16086  * to be applied to many related elements in one statement through the returned {@link Ext.CompositeElement CompositeElement} or
16087  * {@link Ext.CompositeElementLite CompositeElementLite} object.
16088  * @param {String/Array} selector The CSS selector or an array of elements
16089  * @param {HTMLElement/String} root (optional) The root element of the query or id of the root
16090  * @return {CompositeElementLite/CompositeElement}
16091  * @member Ext.core.Element
16092  * @method select
16093  */
16094 Ext.core.Element.select = function(selector, root){
16095     var els;
16096     if(typeof selector == "string"){
16097         els = Ext.core.Element.selectorFunction(selector, root);
16098     }else if(selector.length !== undefined){
16099         els = selector;
16100     }else{
16101     }
16102     return new Ext.CompositeElementLite(els);
16103 };
16104 /**
16105  * Selects elements based on the passed CSS selector to enable {@link Ext.core.Element Element} methods
16106  * to be applied to many related elements in one statement through the returned {@link Ext.CompositeElement CompositeElement} or
16107  * {@link Ext.CompositeElementLite CompositeElementLite} object.
16108  * @param {String/Array} selector The CSS selector or an array of elements
16109  * @param {HTMLElement/String} root (optional) The root element of the query or id of the root
16110  * @return {CompositeElementLite/CompositeElement}
16111  * @member Ext
16112  * @method select
16113  */
16114 Ext.select = Ext.core.Element.select;
16115
16116 /**
16117  * @class Ext.util.DelayedTask
16118  * 
16119  * The DelayedTask class provides a convenient way to "buffer" the execution of a method,
16120  * performing setTimeout where a new timeout cancels the old timeout. When called, the
16121  * task will wait the specified time period before executing. If durng that time period,
16122  * the task is called again, the original call will be cancelled. This continues so that
16123  * the function is only called a single time for each iteration.
16124  * 
16125  * This method is especially useful for things like detecting whether a user has finished
16126  * typing in a text field. An example would be performing validation on a keypress. You can
16127  * use this class to buffer the keypress events for a certain number of milliseconds, and
16128  * perform only if they stop for that amount of time.  
16129  * 
16130  * ## Usage
16131  * 
16132  *     var task = new Ext.util.DelayedTask(function(){
16133  *         alert(Ext.getDom('myInputField').value.length);
16134  *     });
16135  *     
16136  *     // Wait 500ms before calling our function. If the user presses another key
16137  *     // during that 500ms, it will be cancelled and we'll wait another 500ms.
16138  *     Ext.get('myInputField').on('keypress', function(){
16139  *         task.{@link #delay}(500);
16140  *     });
16141  * 
16142  * Note that we are using a DelayedTask here to illustrate a point. The configuration
16143  * option `buffer` for {@link Ext.util.Observable#addListener addListener/on} will
16144  * also setup a delayed task for you to buffer events.
16145  * 
16146  * @constructor The parameters to this constructor serve as defaults and are not required.
16147  * @param {Function} fn (optional) The default function to call.
16148  * @param {Object} scope (optional) The default scope (The <code><b>this</b></code> reference) in which the
16149  * function is called. If not specified, <code>this</code> will refer to the browser window.
16150  * @param {Array} args (optional) The default Array of arguments.
16151  */
16152 Ext.util.DelayedTask = function(fn, scope, args) {
16153     var me = this,
16154         id,
16155         call = function() {
16156             clearInterval(id);
16157             id = null;
16158             fn.apply(scope, args || []);
16159         };
16160
16161     /**
16162      * Cancels any pending timeout and queues a new one
16163      * @param {Number} delay The milliseconds to delay
16164      * @param {Function} newFn (optional) Overrides function passed to constructor
16165      * @param {Object} newScope (optional) Overrides scope passed to constructor. Remember that if no scope
16166      * is specified, <code>this</code> will refer to the browser window.
16167      * @param {Array} newArgs (optional) Overrides args passed to constructor
16168      */
16169     this.delay = function(delay, newFn, newScope, newArgs) {
16170         me.cancel();
16171         fn = newFn || fn;
16172         scope = newScope || scope;
16173         args = newArgs || args;
16174         id = setInterval(call, delay);
16175     };
16176
16177     /**
16178      * Cancel the last queued timeout
16179      */
16180     this.cancel = function(){
16181         if (id) {
16182             clearInterval(id);
16183             id = null;
16184         }
16185     };
16186 };
16187 Ext.require('Ext.util.DelayedTask', function() {
16188
16189     Ext.util.Event = Ext.extend(Object, (function() {
16190         function createBuffered(handler, listener, o, scope) {
16191             listener.task = new Ext.util.DelayedTask();
16192             return function() {
16193                 listener.task.delay(o.buffer, handler, scope, Ext.Array.toArray(arguments));
16194             };
16195         }
16196
16197         function createDelayed(handler, listener, o, scope) {
16198             return function() {
16199                 var task = new Ext.util.DelayedTask();
16200                 if (!listener.tasks) {
16201                     listener.tasks = [];
16202                 }
16203                 listener.tasks.push(task);
16204                 task.delay(o.delay || 10, handler, scope, Ext.Array.toArray(arguments));
16205             };
16206         }
16207
16208         function createSingle(handler, listener, o, scope) {
16209             return function() {
16210                 listener.ev.removeListener(listener.fn, scope);
16211                 return handler.apply(scope, arguments);
16212             };
16213         }
16214
16215         return {
16216             isEvent: true,
16217
16218             constructor: function(observable, name) {
16219                 this.name = name;
16220                 this.observable = observable;
16221                 this.listeners = [];
16222             },
16223
16224             addListener: function(fn, scope, options) {
16225                 var me = this,
16226                     listener;
16227                     scope = scope || me.observable;
16228
16229
16230                 if (!me.isListening(fn, scope)) {
16231                     listener = me.createListener(fn, scope, options);
16232                     if (me.firing) {
16233                         // if we are currently firing this event, don't disturb the listener loop
16234                         me.listeners = me.listeners.slice(0);
16235                     }
16236                     me.listeners.push(listener);
16237                 }
16238             },
16239
16240             createListener: function(fn, scope, o) {
16241                 o = o || {};
16242                 scope = scope || this.observable;
16243
16244                 var listener = {
16245                         fn: fn,
16246                         scope: scope,
16247                         o: o,
16248                         ev: this
16249                     },
16250                     handler = fn;
16251
16252                 // The order is important. The 'single' wrapper must be wrapped by the 'buffer' and 'delayed' wrapper
16253                 // because the event removal that the single listener does destroys the listener's DelayedTask(s)
16254                 if (o.single) {
16255                     handler = createSingle(handler, listener, o, scope);
16256                 }
16257                 if (o.delay) {
16258                     handler = createDelayed(handler, listener, o, scope);
16259                 }
16260                 if (o.buffer) {
16261                     handler = createBuffered(handler, listener, o, scope);
16262                 }
16263
16264                 listener.fireFn = handler;
16265                 return listener;
16266             },
16267
16268             findListener: function(fn, scope) {
16269                 var listeners = this.listeners,
16270                 i = listeners.length,
16271                 listener,
16272                 s;
16273
16274                 while (i--) {
16275                     listener = listeners[i];
16276                     if (listener) {
16277                         s = listener.scope;
16278                         if (listener.fn == fn && (s == scope || s == this.observable)) {
16279                             return i;
16280                         }
16281                     }
16282                 }
16283
16284                 return - 1;
16285             },
16286
16287             isListening: function(fn, scope) {
16288                 return this.findListener(fn, scope) !== -1;
16289             },
16290
16291             removeListener: function(fn, scope) {
16292                 var me = this,
16293                     index,
16294                     listener,
16295                     k;
16296                 index = me.findListener(fn, scope);
16297                 if (index != -1) {
16298                     listener = me.listeners[index];
16299
16300                     if (me.firing) {
16301                         me.listeners = me.listeners.slice(0);
16302                     }
16303
16304                     // cancel and remove a buffered handler that hasn't fired yet
16305                     if (listener.task) {
16306                         listener.task.cancel();
16307                         delete listener.task;
16308                     }
16309
16310                     // cancel and remove all delayed handlers that haven't fired yet
16311                     k = listener.tasks && listener.tasks.length;
16312                     if (k) {
16313                         while (k--) {
16314                             listener.tasks[k].cancel();
16315                         }
16316                         delete listener.tasks;
16317                     }
16318
16319                     // remove this listener from the listeners array
16320                     Ext.Array.erase(me.listeners, index, 1);
16321                     return true;
16322                 }
16323
16324                 return false;
16325             },
16326
16327             // Iterate to stop any buffered/delayed events
16328             clearListeners: function() {
16329                 var listeners = this.listeners,
16330                     i = listeners.length;
16331
16332                 while (i--) {
16333                     this.removeListener(listeners[i].fn, listeners[i].scope);
16334                 }
16335             },
16336
16337             fire: function() {
16338                 var me = this,
16339                     listeners = me.listeners,
16340                     count = listeners.length,
16341                     i,
16342                     args,
16343                     listener;
16344
16345                 if (count > 0) {
16346                     me.firing = true;
16347                     for (i = 0; i < count; i++) {
16348                         listener = listeners[i];
16349                         args = arguments.length ? Array.prototype.slice.call(arguments, 0) : [];
16350                         if (listener.o) {
16351                             args.push(listener.o);
16352                         }
16353                         if (listener && listener.fireFn.apply(listener.scope || me.observable, args) === false) {
16354                             return (me.firing = false);
16355                         }
16356                     }
16357                 }
16358                 me.firing = false;
16359                 return true;
16360             }
16361         };
16362     })());
16363 });
16364
16365 /**
16366  * @class Ext.EventManager
16367  * Registers event handlers that want to receive a normalized EventObject instead of the standard browser event and provides
16368  * several useful events directly.
16369  * See {@link Ext.EventObject} for more details on normalized event objects.
16370  * @singleton
16371  */
16372 Ext.EventManager = {
16373
16374     // --------------------- onReady ---------------------
16375
16376     /**
16377      * Check if we have bound our global onReady listener
16378      * @private
16379      */
16380     hasBoundOnReady: false,
16381
16382     /**
16383      * Check if fireDocReady has been called
16384      * @private
16385      */
16386     hasFiredReady: false,
16387
16388     /**
16389      * Timer for the document ready event in old IE versions
16390      * @private
16391      */
16392     readyTimeout: null,
16393
16394     /**
16395      * Checks if we have bound an onreadystatechange event
16396      * @private
16397      */
16398     hasOnReadyStateChange: false,
16399
16400     /**
16401      * Holds references to any onReady functions
16402      * @private
16403      */
16404     readyEvent: new Ext.util.Event(),
16405
16406     /**
16407      * Check the ready state for old IE versions
16408      * @private
16409      * @return {Boolean} True if the document is ready
16410      */
16411     checkReadyState: function(){
16412         var me = Ext.EventManager;
16413
16414         if(window.attachEvent){
16415             // See here for reference: http://javascript.nwbox.com/IEContentLoaded/
16416             if (window != top) {
16417                 return false;
16418             }
16419             try{
16420                 document.documentElement.doScroll('left');
16421             }catch(e){
16422                 return false;
16423             }
16424             me.fireDocReady();
16425             return true;
16426         }
16427         if (document.readyState == 'complete') {
16428             me.fireDocReady();
16429             return true;
16430         }
16431         me.readyTimeout = setTimeout(arguments.callee, 2);
16432         return false;
16433     },
16434
16435     /**
16436      * Binds the appropriate browser event for checking if the DOM has loaded.
16437      * @private
16438      */
16439     bindReadyEvent: function(){
16440         var me = Ext.EventManager;
16441         if (me.hasBoundOnReady) {
16442             return;
16443         }
16444
16445         if (document.addEventListener) {
16446             document.addEventListener('DOMContentLoaded', me.fireDocReady, false);
16447             // fallback, load will ~always~ fire
16448             window.addEventListener('load', me.fireDocReady, false);
16449         } else {
16450             // check if the document is ready, this will also kick off the scroll checking timer
16451             if (!me.checkReadyState()) {
16452                 document.attachEvent('onreadystatechange', me.checkReadyState);
16453                 me.hasOnReadyStateChange = true;
16454             }
16455             // fallback, onload will ~always~ fire
16456             window.attachEvent('onload', me.fireDocReady, false);
16457         }
16458         me.hasBoundOnReady = true;
16459     },
16460
16461     /**
16462      * We know the document is loaded, so trigger any onReady events.
16463      * @private
16464      */
16465     fireDocReady: function(){
16466         var me = Ext.EventManager;
16467
16468         // only unbind these events once
16469         if (!me.hasFiredReady) {
16470             me.hasFiredReady = true;
16471
16472             if (document.addEventListener) {
16473                 document.removeEventListener('DOMContentLoaded', me.fireDocReady, false);
16474                 window.removeEventListener('load', me.fireDocReady, false);
16475             } else {
16476                 if (me.readyTimeout !== null) {
16477                     clearTimeout(me.readyTimeout);
16478                 }
16479                 if (me.hasOnReadyStateChange) {
16480                     document.detachEvent('onreadystatechange', me.checkReadyState);
16481                 }
16482                 window.detachEvent('onload', me.fireDocReady);
16483             }
16484             Ext.supports.init();
16485         }
16486         if (!Ext.isReady) {
16487             Ext.isReady = true;
16488             me.onWindowUnload();
16489             me.readyEvent.fire();
16490         }
16491     },
16492
16493     /**
16494      * Adds a listener to be notified when the document is ready (before onload and before images are loaded). Can be
16495      * accessed shorthanded as Ext.onReady().
16496      * @param {Function} fn The method the event invokes.
16497      * @param {Object} scope (optional) The scope (<code>this</code> reference) in which the handler function executes. Defaults to the browser window.
16498      * @param {boolean} options (optional) Options object as passed to {@link Ext.core.Element#addListener}.
16499      */
16500     onDocumentReady: function(fn, scope, options){
16501         options = options || {};
16502         var me = Ext.EventManager,
16503             readyEvent = me.readyEvent;
16504
16505         // force single to be true so our event is only ever fired once.
16506         options.single = true;
16507
16508         // Document already loaded, let's just fire it
16509         if (Ext.isReady) {
16510             readyEvent.addListener(fn, scope, options);
16511             readyEvent.fire();
16512         } else {
16513             options.delay = options.delay || 1;
16514             readyEvent.addListener(fn, scope, options);
16515             me.bindReadyEvent();
16516         }
16517     },
16518
16519
16520     // --------------------- event binding ---------------------
16521
16522     /**
16523      * Contains a list of all document mouse downs, so we can ensure they fire even when stopEvent is called.
16524      * @private
16525      */
16526     stoppedMouseDownEvent: new Ext.util.Event(),
16527
16528     /**
16529      * Options to parse for the 4th argument to addListener.
16530      * @private
16531      */
16532     propRe: /^(?:scope|delay|buffer|single|stopEvent|preventDefault|stopPropagation|normalized|args|delegate|freezeEvent)$/,
16533
16534     /**
16535      * Get the id of the element. If one has not been assigned, automatically assign it.
16536      * @param {Mixed} element The element to get the id for.
16537      * @return {String} id
16538      */
16539     getId : function(element) {
16540         var skipGarbageCollection = false,
16541             id;
16542     
16543         element = Ext.getDom(element);
16544     
16545         if (element === document || element === window) {
16546             id = element === document ? Ext.documentId : Ext.windowId;
16547         }
16548         else {
16549             id = Ext.id(element);
16550         }
16551         // skip garbage collection for special elements (window, document, iframes)
16552         if (element && (element.getElementById || element.navigator)) {
16553             skipGarbageCollection = true;
16554         }
16555     
16556         if (!Ext.cache[id]){
16557             Ext.core.Element.addToCache(new Ext.core.Element(element), id);
16558             if (skipGarbageCollection) {
16559                 Ext.cache[id].skipGarbageCollection = true;
16560             }
16561         }
16562         return id;
16563     },
16564
16565     /**
16566      * Convert a "config style" listener into a set of flat arguments so they can be passed to addListener
16567      * @private
16568      * @param {Object} element The element the event is for
16569      * @param {Object} event The event configuration
16570      * @param {Object} isRemove True if a removal should be performed, otherwise an add will be done.
16571      */
16572     prepareListenerConfig: function(element, config, isRemove){
16573         var me = this,
16574             propRe = me.propRe,
16575             key, value, args;
16576
16577         // loop over all the keys in the object
16578         for (key in config) {
16579             if (config.hasOwnProperty(key)) {
16580                 // if the key is something else then an event option
16581                 if (!propRe.test(key)) {
16582                     value = config[key];
16583                     // if the value is a function it must be something like click: function(){}, scope: this
16584                     // which means that there might be multiple event listeners with shared options
16585                     if (Ext.isFunction(value)) {
16586                         // shared options
16587                         args = [element, key, value, config.scope, config];
16588                     } else {
16589                         // if its not a function, it must be an object like click: {fn: function(){}, scope: this}
16590                         args = [element, key, value.fn, value.scope, value];
16591                     }
16592
16593                     if (isRemove === true) {
16594                         me.removeListener.apply(this, args);
16595                     } else {
16596                         me.addListener.apply(me, args);
16597                     }
16598                 }
16599             }
16600         }
16601     },
16602
16603     /**
16604      * Normalize cross browser event differences
16605      * @private
16606      * @param {Object} eventName The event name
16607      * @param {Object} fn The function to execute
16608      * @return {Object} The new event name/function
16609      */
16610     normalizeEvent: function(eventName, fn){
16611         if (/mouseenter|mouseleave/.test(eventName) && !Ext.supports.MouseEnterLeave) {
16612             if (fn) {
16613                 fn = Ext.Function.createInterceptor(fn, this.contains, this);
16614             }
16615             eventName = eventName == 'mouseenter' ? 'mouseover' : 'mouseout';
16616         } else if (eventName == 'mousewheel' && !Ext.supports.MouseWheel && !Ext.isOpera){
16617             eventName = 'DOMMouseScroll';
16618         }
16619         return {
16620             eventName: eventName,
16621             fn: fn
16622         };
16623     },
16624
16625     /**
16626      * Checks whether the event's relatedTarget is contained inside (or <b>is</b>) the element.
16627      * @private
16628      * @param {Object} event
16629      */
16630     contains: function(event){
16631         var parent = event.browserEvent.currentTarget,
16632             child = this.getRelatedTarget(event);
16633
16634         if (parent && parent.firstChild) {
16635             while (child) {
16636                 if (child === parent) {
16637                     return false;
16638                 }
16639                 child = child.parentNode;
16640                 if (child && (child.nodeType != 1)) {
16641                     child = null;
16642                 }
16643             }
16644         }
16645         return true;
16646     },
16647
16648     /**
16649     * Appends an event handler to an element.  The shorthand version {@link #on} is equivalent.  Typically you will
16650     * use {@link Ext.core.Element#addListener} directly on an Element in favor of calling this version.
16651     * @param {String/HTMLElement} el The html element or id to assign the event handler to.
16652     * @param {String} eventName The name of the event to listen for.
16653     * @param {Function} handler The handler function the event invokes. This function is passed
16654     * the following parameters:<ul>
16655     * <li>evt : EventObject<div class="sub-desc">The {@link Ext.EventObject EventObject} describing the event.</div></li>
16656     * <li>t : Element<div class="sub-desc">The {@link Ext.core.Element Element} which was the target of the event.
16657     * Note that this may be filtered by using the <tt>delegate</tt> option.</div></li>
16658     * <li>o : Object<div class="sub-desc">The options object from the addListener call.</div></li>
16659     * </ul>
16660     * @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>.
16661     * @param {Object} options (optional) An object containing handler configuration properties.
16662     * This may contain any of the following properties:<ul>
16663     * <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>
16664     * <li>delegate : String<div class="sub-desc">A simple selector to filter the target or look for a descendant of the target</div></li>
16665     * <li>stopEvent : Boolean<div class="sub-desc">True to stop the event. That is stop propagation, and prevent the default action.</div></li>
16666     * <li>preventDefault : Boolean<div class="sub-desc">True to prevent the default action</div></li>
16667     * <li>stopPropagation : Boolean<div class="sub-desc">True to prevent event propagation</div></li>
16668     * <li>normalized : Boolean<div class="sub-desc">False to pass a browser event to the handler function instead of an Ext.EventObject</div></li>
16669     * <li>delay : Number<div class="sub-desc">The number of milliseconds to delay the invocation of the handler after te event fires.</div></li>
16670     * <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>
16671     * <li>buffer : Number<div class="sub-desc">Causes the handler to be scheduled to run in an {@link Ext.util.DelayedTask} delayed
16672     * by the specified number of milliseconds. If the event fires again within that time, the original
16673     * handler is <em>not</em> invoked, but the new handler is scheduled in its place.</div></li>
16674     * <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>
16675     * </ul><br>
16676     * <p>See {@link Ext.core.Element#addListener} for examples of how to use these options.</p>
16677     */
16678     addListener: function(element, eventName, fn, scope, options){
16679         // Check if we've been passed a "config style" event.
16680         if (typeof eventName !== 'string') {
16681             this.prepareListenerConfig(element, eventName);
16682             return;
16683         }
16684
16685         var dom = Ext.getDom(element),
16686             bind,
16687             wrap;
16688
16689
16690         // create the wrapper function
16691         options = options || {};
16692
16693         bind = this.normalizeEvent(eventName, fn);
16694         wrap = this.createListenerWrap(dom, eventName, bind.fn, scope, options);
16695
16696
16697         if (dom.attachEvent) {
16698             dom.attachEvent('on' + bind.eventName, wrap);
16699         } else {
16700             dom.addEventListener(bind.eventName, wrap, options.capture || false);
16701         }
16702
16703         if (dom == document && eventName == 'mousedown') {
16704             this.stoppedMouseDownEvent.addListener(wrap);
16705         }
16706
16707         // add all required data into the event cache
16708         this.getEventListenerCache(dom, eventName).push({
16709             fn: fn,
16710             wrap: wrap,
16711             scope: scope
16712         });
16713     },
16714
16715     /**
16716     * Removes an event handler from an element.  The shorthand version {@link #un} is equivalent.  Typically
16717     * you will use {@link Ext.core.Element#removeListener} directly on an Element in favor of calling this version.
16718     * @param {String/HTMLElement} el The id or html element from which to remove the listener.
16719     * @param {String} eventName The name of the event.
16720     * @param {Function} fn The handler function to remove. <b>This must be a reference to the function passed into the {@link #addListener} call.</b>
16721     * @param {Object} scope If a scope (<b><code>this</code></b> reference) was specified when the listener was added,
16722     * then this must refer to the same object.
16723     */
16724     removeListener : function(element, eventName, fn, scope) {
16725         // handle our listener config object syntax
16726         if (typeof eventName !== 'string') {
16727             this.prepareListenerConfig(element, eventName, true);
16728             return;
16729         }
16730
16731         var dom = Ext.getDom(element),
16732             cache = this.getEventListenerCache(dom, eventName),
16733             bindName = this.normalizeEvent(eventName).eventName,
16734             i = cache.length, j,
16735             listener, wrap, tasks;
16736
16737
16738         while (i--) {
16739             listener = cache[i];
16740
16741             if (listener && (!fn || listener.fn == fn) && (!scope || listener.scope === scope)) {
16742                 wrap = listener.wrap;
16743
16744                 // clear buffered calls
16745                 if (wrap.task) {
16746                     clearTimeout(wrap.task);
16747                     delete wrap.task;
16748                 }
16749
16750                 // clear delayed calls
16751                 j = wrap.tasks && wrap.tasks.length;
16752                 if (j) {
16753                     while (j--) {
16754                         clearTimeout(wrap.tasks[j]);
16755                     }
16756                     delete wrap.tasks;
16757                 }
16758
16759                 if (dom.detachEvent) {
16760                     dom.detachEvent('on' + bindName, wrap);
16761                 } else {
16762                     dom.removeEventListener(bindName, wrap, false);
16763                 }
16764
16765                 if (wrap && dom == document && eventName == 'mousedown') {
16766                     this.stoppedMouseDownEvent.removeListener(wrap);
16767                 }
16768
16769                 // remove listener from cache
16770                 Ext.Array.erase(cache, i, 1);
16771             }
16772         }
16773     },
16774
16775     /**
16776     * Removes all event handers from an element.  Typically you will use {@link Ext.core.Element#removeAllListeners}
16777     * directly on an Element in favor of calling this version.
16778     * @param {String/HTMLElement} el The id or html element from which to remove all event handlers.
16779     */
16780     removeAll : function(element){
16781         var dom = Ext.getDom(element),
16782             cache, ev;
16783         if (!dom) {
16784             return;
16785         }
16786         cache = this.getElementEventCache(dom);
16787
16788         for (ev in cache) {
16789             if (cache.hasOwnProperty(ev)) {
16790                 this.removeListener(dom, ev);
16791             }
16792         }
16793         Ext.cache[dom.id].events = {};
16794     },
16795
16796     /**
16797      * Recursively removes all previous added listeners from an element and its children. Typically you will use {@link Ext.core.Element#purgeAllListeners}
16798      * directly on an Element in favor of calling this version.
16799      * @param {String/HTMLElement} el The id or html element from which to remove all event handlers.
16800      * @param {String} eventName (optional) The name of the event.
16801      */
16802     purgeElement : function(element, eventName) {
16803         var dom = Ext.getDom(element),
16804             i = 0, len;
16805
16806         if(eventName) {
16807             this.removeListener(dom, eventName);
16808         }
16809         else {
16810             this.removeAll(dom);
16811         }
16812
16813         if(dom && dom.childNodes) {
16814             for(len = element.childNodes.length; i < len; i++) {
16815                 this.purgeElement(element.childNodes[i], eventName);
16816             }
16817         }
16818     },
16819
16820     /**
16821      * Create the wrapper function for the event
16822      * @private
16823      * @param {HTMLElement} dom The dom element
16824      * @param {String} ename The event name
16825      * @param {Function} fn The function to execute
16826      * @param {Object} scope The scope to execute callback in
16827      * @param {Object} options The options
16828      * @return {Function} the wrapper function
16829      */
16830     createListenerWrap : function(dom, ename, fn, scope, options) {
16831         options = options || {};
16832
16833         var f, gen;
16834
16835         return function wrap(e, args) {
16836             // Compile the implementation upon first firing
16837             if (!gen) {
16838                 f = ['if(!Ext) {return;}'];
16839
16840                 if(options.buffer || options.delay || options.freezeEvent) {
16841                     f.push('e = new Ext.EventObjectImpl(e, ' + (options.freezeEvent ? 'true' : 'false' ) + ');');
16842                 } else {
16843                     f.push('e = Ext.EventObject.setEvent(e);');
16844                 }
16845
16846                 if (options.delegate) {
16847                     f.push('var t = e.getTarget("' + options.delegate + '", this);');
16848                     f.push('if(!t) {return;}');
16849                 } else {
16850                     f.push('var t = e.target;');
16851                 }
16852
16853                 if (options.target) {
16854                     f.push('if(e.target !== options.target) {return;}');
16855                 }
16856
16857                 if(options.stopEvent) {
16858                     f.push('e.stopEvent();');
16859                 } else {
16860                     if(options.preventDefault) {
16861                         f.push('e.preventDefault();');
16862                     }
16863                     if(options.stopPropagation) {
16864                         f.push('e.stopPropagation();');
16865                     }
16866                 }
16867
16868                 if(options.normalized === false) {
16869                     f.push('e = e.browserEvent;');
16870                 }
16871
16872                 if(options.buffer) {
16873                     f.push('(wrap.task && clearTimeout(wrap.task));');
16874                     f.push('wrap.task = setTimeout(function(){');
16875                 }
16876
16877                 if(options.delay) {
16878                     f.push('wrap.tasks = wrap.tasks || [];');
16879                     f.push('wrap.tasks.push(setTimeout(function(){');
16880                 }
16881
16882                 // finally call the actual handler fn
16883                 f.push('fn.call(scope || dom, e, t, options);');
16884
16885                 if(options.single) {
16886                     f.push('Ext.EventManager.removeListener(dom, ename, fn, scope);');
16887                 }
16888
16889                 if(options.delay) {
16890                     f.push('}, ' + options.delay + '));');
16891                 }
16892
16893                 if(options.buffer) {
16894                     f.push('}, ' + options.buffer + ');');
16895                 }
16896
16897                 gen = Ext.functionFactory('e', 'options', 'fn', 'scope', 'ename', 'dom', 'wrap', 'args', f.join('\n'));
16898             }
16899
16900             gen.call(dom, e, options, fn, scope, ename, dom, wrap, args);
16901         };
16902     },
16903
16904     /**
16905      * Get the event cache for a particular element for a particular event
16906      * @private
16907      * @param {HTMLElement} element The element
16908      * @param {Object} eventName The event name
16909      * @return {Array} The events for the element
16910      */
16911     getEventListenerCache : function(element, eventName) {
16912         if (!element) {
16913             return [];
16914         }
16915         
16916         var eventCache = this.getElementEventCache(element);
16917         return eventCache[eventName] || (eventCache[eventName] = []);
16918     },
16919
16920     /**
16921      * Gets the event cache for the object
16922      * @private
16923      * @param {HTMLElement} element The element
16924      * @return {Object} The event cache for the object
16925      */
16926     getElementEventCache : function(element) {
16927         if (!element) {
16928             return {};
16929         }
16930         var elementCache = Ext.cache[this.getId(element)];
16931         return elementCache.events || (elementCache.events = {});
16932     },
16933
16934     // --------------------- utility methods ---------------------
16935     mouseLeaveRe: /(mouseout|mouseleave)/,
16936     mouseEnterRe: /(mouseover|mouseenter)/,
16937
16938     /**
16939      * Stop the event (preventDefault and stopPropagation)
16940      * @param {Event} The event to stop
16941      */
16942     stopEvent: function(event) {
16943         this.stopPropagation(event);
16944         this.preventDefault(event);
16945     },
16946
16947     /**
16948      * Cancels bubbling of the event.
16949      * @param {Event} The event to stop bubbling.
16950      */
16951     stopPropagation: function(event) {
16952         event = event.browserEvent || event;
16953         if (event.stopPropagation) {
16954             event.stopPropagation();
16955         } else {
16956             event.cancelBubble = true;
16957         }
16958     },
16959
16960     /**
16961      * Prevents the browsers default handling of the event.
16962      * @param {Event} The event to prevent the default
16963      */
16964     preventDefault: function(event) {
16965         event = event.browserEvent || event;
16966         if (event.preventDefault) {
16967             event.preventDefault();
16968         } else {
16969             event.returnValue = false;
16970             // Some keys events require setting the keyCode to -1 to be prevented
16971             try {
16972               // all ctrl + X and F1 -> F12
16973               if (event.ctrlKey || event.keyCode > 111 && event.keyCode < 124) {
16974                   event.keyCode = -1;
16975               }
16976             } catch (e) {
16977                 // see this outdated document http://support.microsoft.com/kb/934364/en-us for more info
16978             }
16979         }
16980     },
16981
16982     /**
16983      * Gets the related target from the event.
16984      * @param {Object} event The event
16985      * @return {HTMLElement} The related target.
16986      */
16987     getRelatedTarget: function(event) {
16988         event = event.browserEvent || event;
16989         var target = event.relatedTarget;
16990         if (!target) {
16991             if (this.mouseLeaveRe.test(event.type)) {
16992                 target = event.toElement;
16993             } else if (this.mouseEnterRe.test(event.type)) {
16994                 target = event.fromElement;
16995             }
16996         }
16997         return this.resolveTextNode(target);
16998     },
16999
17000     /**
17001      * Gets the x coordinate from the event
17002      * @param {Object} event The event
17003      * @return {Number} The x coordinate
17004      */
17005     getPageX: function(event) {
17006         return this.getXY(event)[0];
17007     },
17008
17009     /**
17010      * Gets the y coordinate from the event
17011      * @param {Object} event The event
17012      * @return {Number} The y coordinate
17013      */
17014     getPageY: function(event) {
17015         return this.getXY(event)[1];
17016     },
17017
17018     /**
17019      * Gets the x & ycoordinate from the event
17020      * @param {Object} event The event
17021      * @return {Array} The x/y coordinate
17022      */
17023     getPageXY: function(event) {
17024         event = event.browserEvent || event;
17025         var x = event.pageX,
17026             y = event.pageY,
17027             doc = document.documentElement,
17028             body = document.body;
17029
17030         // pageX/pageY not available (undefined, not null), use clientX/clientY instead
17031         if (!x && x !== 0) {
17032             x = event.clientX + (doc && doc.scrollLeft || body && body.scrollLeft || 0) - (doc && doc.clientLeft || body && body.clientLeft || 0);
17033             y = event.clientY + (doc && doc.scrollTop  || body && body.scrollTop  || 0) - (doc && doc.clientTop  || body && body.clientTop  || 0);
17034         }
17035         return [x, y];
17036     },
17037
17038     /**
17039      * Gets the target of the event.
17040      * @param {Object} event The event
17041      * @return {HTMLElement} target
17042      */
17043     getTarget: function(event) {
17044         event = event.browserEvent || event;
17045         return this.resolveTextNode(event.target || event.srcElement);
17046     },
17047
17048     /**
17049      * Resolve any text nodes accounting for browser differences.
17050      * @private
17051      * @param {HTMLElement} node The node
17052      * @return {HTMLElement} The resolved node
17053      */
17054     // 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.
17055     resolveTextNode: Ext.isGecko ?
17056         function(node) {
17057             if (!node) {
17058                 return;
17059             }
17060             // work around firefox bug, https://bugzilla.mozilla.org/show_bug.cgi?id=101197
17061             var s = HTMLElement.prototype.toString.call(node);
17062             if (s == '[xpconnect wrapped native prototype]' || s == '[object XULElement]') {
17063                 return;
17064             }
17065                 return node.nodeType == 3 ? node.parentNode: node;
17066             }: function(node) {
17067                 return node && node.nodeType == 3 ? node.parentNode: node;
17068             },
17069
17070     // --------------------- custom event binding ---------------------
17071
17072     // Keep track of the current width/height
17073     curWidth: 0,
17074     curHeight: 0,
17075
17076     /**
17077      * Adds a listener to be notified when the browser window is resized and provides resize event buffering (100 milliseconds),
17078      * passes new viewport width and height to handlers.
17079      * @param {Function} fn      The handler function the window resize event invokes.
17080      * @param {Object}   scope   The scope (<code>this</code> reference) in which the handler function executes. Defaults to the browser window.
17081      * @param {boolean}  options Options object as passed to {@link Ext.core.Element#addListener}
17082      */
17083     onWindowResize: function(fn, scope, options){
17084         var resize = this.resizeEvent;
17085         if(!resize){
17086             this.resizeEvent = resize = new Ext.util.Event();
17087             this.on(window, 'resize', this.fireResize, this, {buffer: 100});
17088         }
17089         resize.addListener(fn, scope, options);
17090     },
17091
17092     /**
17093      * Fire the resize event.
17094      * @private
17095      */
17096     fireResize: function(){
17097         var me = this,
17098             w = Ext.core.Element.getViewWidth(),
17099             h = Ext.core.Element.getViewHeight();
17100
17101          //whacky problem in IE where the resize event will sometimes fire even though the w/h are the same.
17102          if(me.curHeight != h || me.curWidth != w){
17103              me.curHeight = h;
17104              me.curWidth = w;
17105              me.resizeEvent.fire(w, h);
17106          }
17107     },
17108
17109     /**
17110      * Removes the passed window resize listener.
17111      * @param {Function} fn        The method the event invokes
17112      * @param {Object}   scope    The scope of handler
17113      */
17114     removeResizeListener: function(fn, scope){
17115         if (this.resizeEvent) {
17116             this.resizeEvent.removeListener(fn, scope);
17117         }
17118     },
17119
17120     onWindowUnload: function() {
17121         var unload = this.unloadEvent;
17122         if (!unload) {
17123             this.unloadEvent = unload = new Ext.util.Event();
17124             this.addListener(window, 'unload', this.fireUnload, this);
17125         }
17126     },
17127
17128     /**
17129      * Fires the unload event for items bound with onWindowUnload
17130      * @private
17131      */
17132     fireUnload: function() {
17133         // wrap in a try catch, could have some problems during unload
17134         try {
17135             this.removeUnloadListener();
17136             // Work around FF3 remembering the last scroll position when refreshing the grid and then losing grid view
17137             if (Ext.isGecko3) {
17138                 var gridviews = Ext.ComponentQuery.query('gridview'),
17139                     i = 0,
17140                     ln = gridviews.length;
17141                 for (; i < ln; i++) {
17142                     gridviews[i].scrollToTop();
17143                 }
17144             }
17145             // Purge all elements in the cache
17146             var el,
17147                 cache = Ext.cache;
17148             for (el in cache) {
17149                 if (cache.hasOwnProperty(el)) {
17150                     Ext.EventManager.removeAll(el);
17151                 }
17152             }
17153         } catch(e) {
17154         }
17155     },
17156
17157     /**
17158      * Removes the passed window unload listener.
17159      * @param {Function} fn        The method the event invokes
17160      * @param {Object}   scope    The scope of handler
17161      */
17162     removeUnloadListener: function(){
17163         if (this.unloadEvent) {
17164             this.removeListener(window, 'unload', this.fireUnload);
17165         }
17166     },
17167
17168     /**
17169      * note 1: IE fires ONLY the keydown event on specialkey autorepeat
17170      * note 2: Safari < 3.1, Gecko (Mac/Linux) & Opera fire only the keypress event on specialkey autorepeat
17171      * (research done by @Jan Wolter at http://unixpapa.com/js/key.html)
17172      * @private
17173      */
17174     useKeyDown: Ext.isWebKit ?
17175                    parseInt(navigator.userAgent.match(/AppleWebKit\/(\d+)/)[1], 10) >= 525 :
17176                    !((Ext.isGecko && !Ext.isWindows) || Ext.isOpera),
17177
17178     /**
17179      * Indicates which event to use for getting key presses.
17180      * @return {String} The appropriate event name.
17181      */
17182     getKeyEvent: function(){
17183         return this.useKeyDown ? 'keydown' : 'keypress';
17184     }
17185 };
17186
17187 /**
17188  * Alias for {@link Ext.Loader#onReady Ext.Loader.onReady} with withDomReady set to true
17189  * @member Ext
17190  * @method onReady
17191  */
17192 Ext.onReady = function(fn, scope, options) {
17193     Ext.Loader.onReady(fn, scope, true, options);
17194 };
17195
17196 /**
17197  * Alias for {@link Ext.EventManager#onDocumentReady Ext.EventManager.onDocumentReady}
17198  * @member Ext
17199  * @method onDocumentReady
17200  */
17201 Ext.onDocumentReady = Ext.EventManager.onDocumentReady;
17202
17203 /**
17204  * Alias for {@link Ext.EventManager#addListener Ext.EventManager.addListener}
17205  * @member Ext.EventManager
17206  * @method on
17207  */
17208 Ext.EventManager.on = Ext.EventManager.addListener;
17209
17210 /**
17211  * Alias for {@link Ext.EventManager#removeListener Ext.EventManager.removeListener}
17212  * @member Ext.EventManager
17213  * @method un
17214  */
17215 Ext.EventManager.un = Ext.EventManager.removeListener;
17216
17217 (function(){
17218     var initExtCss = function() {
17219         // find the body element
17220         var bd = document.body || document.getElementsByTagName('body')[0],
17221             baseCSSPrefix = Ext.baseCSSPrefix,
17222             cls = [baseCSSPrefix + 'body'],
17223             htmlCls = [],
17224             html;
17225
17226         if (!bd) {
17227             return false;
17228         }
17229
17230         html = bd.parentNode;
17231
17232         //Let's keep this human readable!
17233         if (Ext.isIE) {
17234             cls.push(baseCSSPrefix + 'ie');
17235         }
17236         if (Ext.isIE6) {
17237             cls.push(baseCSSPrefix + 'ie6');
17238         }
17239         if (Ext.isIE7) {
17240             cls.push(baseCSSPrefix + 'ie7');
17241         }
17242         if (Ext.isIE8) {
17243             cls.push(baseCSSPrefix + 'ie8');
17244         }
17245         if (Ext.isIE9) {
17246             cls.push(baseCSSPrefix + 'ie9');
17247         }
17248         if (Ext.isGecko) {
17249             cls.push(baseCSSPrefix + 'gecko');
17250         }
17251         if (Ext.isGecko3) {
17252             cls.push(baseCSSPrefix + 'gecko3');
17253         }
17254         if (Ext.isGecko4) {
17255             cls.push(baseCSSPrefix + 'gecko4');
17256         }
17257         if (Ext.isOpera) {
17258             cls.push(baseCSSPrefix + 'opera');
17259         }
17260         if (Ext.isWebKit) {
17261             cls.push(baseCSSPrefix + 'webkit');
17262         }
17263         if (Ext.isSafari) {
17264             cls.push(baseCSSPrefix + 'safari');
17265         }
17266         if (Ext.isSafari2) {
17267             cls.push(baseCSSPrefix + 'safari2');
17268         }
17269         if (Ext.isSafari3) {
17270             cls.push(baseCSSPrefix + 'safari3');
17271         }
17272         if (Ext.isSafari4) {
17273             cls.push(baseCSSPrefix + 'safari4');
17274         }
17275         if (Ext.isChrome) {
17276             cls.push(baseCSSPrefix + 'chrome');
17277         }
17278         if (Ext.isMac) {
17279             cls.push(baseCSSPrefix + 'mac');
17280         }
17281         if (Ext.isLinux) {
17282             cls.push(baseCSSPrefix + 'linux');
17283         }
17284         if (!Ext.supports.CSS3BorderRadius) {
17285             cls.push(baseCSSPrefix + 'nbr');
17286         }
17287         if (!Ext.supports.CSS3LinearGradient) {
17288             cls.push(baseCSSPrefix + 'nlg');
17289         }
17290         if (!Ext.scopeResetCSS) {
17291             cls.push(baseCSSPrefix + 'reset');
17292         }
17293
17294         // add to the parent to allow for selectors x-strict x-border-box, also set the isBorderBox property correctly
17295         if (html) {
17296             if (Ext.isStrict && (Ext.isIE6 || Ext.isIE7)) {
17297                 Ext.isBorderBox = false;
17298             }
17299             else {
17300                 Ext.isBorderBox = true;
17301             }
17302
17303             htmlCls.push(baseCSSPrefix + (Ext.isBorderBox ? 'border-box' : 'strict'));
17304             if (!Ext.isStrict) {
17305                 htmlCls.push(baseCSSPrefix + 'quirks');
17306                 if (Ext.isIE && !Ext.isStrict) {
17307                     Ext.isIEQuirks = true;
17308                 }
17309             }
17310             Ext.fly(html, '_internal').addCls(htmlCls);
17311         }
17312
17313         Ext.fly(bd, '_internal').addCls(cls);
17314         return true;
17315     };
17316
17317     Ext.onReady(initExtCss);
17318 })();
17319
17320 /**
17321  * @class Ext.EventObject
17322
17323 Just as {@link Ext.core.Element} wraps around a native DOM node, Ext.EventObject
17324 wraps the browser's native event-object normalizing cross-browser differences,
17325 such as which mouse button is clicked, keys pressed, mechanisms to stop
17326 event-propagation along with a method to prevent default actions from taking place.
17327
17328 For example:
17329
17330     function handleClick(e, t){ // e is not a standard event object, it is a Ext.EventObject
17331         e.preventDefault();
17332         var target = e.getTarget(); // same as t (the target HTMLElement)
17333         ...
17334     }
17335
17336     var myDiv = {@link Ext#get Ext.get}("myDiv");  // get reference to an {@link Ext.core.Element}
17337     myDiv.on(         // 'on' is shorthand for addListener
17338         "click",      // perform an action on click of myDiv
17339         handleClick   // reference to the action handler
17340     );
17341
17342     // other methods to do the same:
17343     Ext.EventManager.on("myDiv", 'click', handleClick);
17344     Ext.EventManager.addListener("myDiv", 'click', handleClick);
17345
17346  * @singleton
17347  * @markdown
17348  */
17349 Ext.define('Ext.EventObjectImpl', {
17350     uses: ['Ext.util.Point'],
17351
17352     /** Key constant @type Number */
17353     BACKSPACE: 8,
17354     /** Key constant @type Number */
17355     TAB: 9,
17356     /** Key constant @type Number */
17357     NUM_CENTER: 12,
17358     /** Key constant @type Number */
17359     ENTER: 13,
17360     /** Key constant @type Number */
17361     RETURN: 13,
17362     /** Key constant @type Number */
17363     SHIFT: 16,
17364     /** Key constant @type Number */
17365     CTRL: 17,
17366     /** Key constant @type Number */
17367     ALT: 18,
17368     /** Key constant @type Number */
17369     PAUSE: 19,
17370     /** Key constant @type Number */
17371     CAPS_LOCK: 20,
17372     /** Key constant @type Number */
17373     ESC: 27,
17374     /** Key constant @type Number */
17375     SPACE: 32,
17376     /** Key constant @type Number */
17377     PAGE_UP: 33,
17378     /** Key constant @type Number */
17379     PAGE_DOWN: 34,
17380     /** Key constant @type Number */
17381     END: 35,
17382     /** Key constant @type Number */
17383     HOME: 36,
17384     /** Key constant @type Number */
17385     LEFT: 37,
17386     /** Key constant @type Number */
17387     UP: 38,
17388     /** Key constant @type Number */
17389     RIGHT: 39,
17390     /** Key constant @type Number */
17391     DOWN: 40,
17392     /** Key constant @type Number */
17393     PRINT_SCREEN: 44,
17394     /** Key constant @type Number */
17395     INSERT: 45,
17396     /** Key constant @type Number */
17397     DELETE: 46,
17398     /** Key constant @type Number */
17399     ZERO: 48,
17400     /** Key constant @type Number */
17401     ONE: 49,
17402     /** Key constant @type Number */
17403     TWO: 50,
17404     /** Key constant @type Number */
17405     THREE: 51,
17406     /** Key constant @type Number */
17407     FOUR: 52,
17408     /** Key constant @type Number */
17409     FIVE: 53,
17410     /** Key constant @type Number */
17411     SIX: 54,
17412     /** Key constant @type Number */
17413     SEVEN: 55,
17414     /** Key constant @type Number */
17415     EIGHT: 56,
17416     /** Key constant @type Number */
17417     NINE: 57,
17418     /** Key constant @type Number */
17419     A: 65,
17420     /** Key constant @type Number */
17421     B: 66,
17422     /** Key constant @type Number */
17423     C: 67,
17424     /** Key constant @type Number */
17425     D: 68,
17426     /** Key constant @type Number */
17427     E: 69,
17428     /** Key constant @type Number */
17429     F: 70,
17430     /** Key constant @type Number */
17431     G: 71,
17432     /** Key constant @type Number */
17433     H: 72,
17434     /** Key constant @type Number */
17435     I: 73,
17436     /** Key constant @type Number */
17437     J: 74,
17438     /** Key constant @type Number */
17439     K: 75,
17440     /** Key constant @type Number */
17441     L: 76,
17442     /** Key constant @type Number */
17443     M: 77,
17444     /** Key constant @type Number */
17445     N: 78,
17446     /** Key constant @type Number */
17447     O: 79,
17448     /** Key constant @type Number */
17449     P: 80,
17450     /** Key constant @type Number */
17451     Q: 81,
17452     /** Key constant @type Number */
17453     R: 82,
17454     /** Key constant @type Number */
17455     S: 83,
17456     /** Key constant @type Number */
17457     T: 84,
17458     /** Key constant @type Number */
17459     U: 85,
17460     /** Key constant @type Number */
17461     V: 86,
17462     /** Key constant @type Number */
17463     W: 87,
17464     /** Key constant @type Number */
17465     X: 88,
17466     /** Key constant @type Number */
17467     Y: 89,
17468     /** Key constant @type Number */
17469     Z: 90,
17470     /** Key constant @type Number */
17471     CONTEXT_MENU: 93,
17472     /** Key constant @type Number */
17473     NUM_ZERO: 96,
17474     /** Key constant @type Number */
17475     NUM_ONE: 97,
17476     /** Key constant @type Number */
17477     NUM_TWO: 98,
17478     /** Key constant @type Number */
17479     NUM_THREE: 99,
17480     /** Key constant @type Number */
17481     NUM_FOUR: 100,
17482     /** Key constant @type Number */
17483     NUM_FIVE: 101,
17484     /** Key constant @type Number */
17485     NUM_SIX: 102,
17486     /** Key constant @type Number */
17487     NUM_SEVEN: 103,
17488     /** Key constant @type Number */
17489     NUM_EIGHT: 104,
17490     /** Key constant @type Number */
17491     NUM_NINE: 105,
17492     /** Key constant @type Number */
17493     NUM_MULTIPLY: 106,
17494     /** Key constant @type Number */
17495     NUM_PLUS: 107,
17496     /** Key constant @type Number */
17497     NUM_MINUS: 109,
17498     /** Key constant @type Number */
17499     NUM_PERIOD: 110,
17500     /** Key constant @type Number */
17501     NUM_DIVISION: 111,
17502     /** Key constant @type Number */
17503     F1: 112,
17504     /** Key constant @type Number */
17505     F2: 113,
17506     /** Key constant @type Number */
17507     F3: 114,
17508     /** Key constant @type Number */
17509     F4: 115,
17510     /** Key constant @type Number */
17511     F5: 116,
17512     /** Key constant @type Number */
17513     F6: 117,
17514     /** Key constant @type Number */
17515     F7: 118,
17516     /** Key constant @type Number */
17517     F8: 119,
17518     /** Key constant @type Number */
17519     F9: 120,
17520     /** Key constant @type Number */
17521     F10: 121,
17522     /** Key constant @type Number */
17523     F11: 122,
17524     /** Key constant @type Number */
17525     F12: 123,
17526     /**
17527      * The mouse wheel delta scaling factor. This value depends on browser version and OS and
17528      * attempts to produce a similar scrolling experience across all platforms and browsers.
17529      * 
17530      * To change this value:
17531      * 
17532      *      Ext.EventObjectImpl.prototype.WHEEL_SCALE = 72;
17533      * 
17534      * @type Number
17535      * @markdown
17536      */
17537     WHEEL_SCALE: (function () {
17538         var scale;
17539
17540         if (Ext.isGecko) {
17541             // Firefox uses 3 on all platforms
17542             scale = 3;
17543         } else if (Ext.isMac) {
17544             // Continuous scrolling devices have momentum and produce much more scroll than
17545             // discrete devices on the same OS and browser. To make things exciting, Safari
17546             // (and not Chrome) changed from small values to 120 (like IE).
17547
17548             if (Ext.isSafari && Ext.webKitVersion >= 532.0) {
17549                 // Safari changed the scrolling factor to match IE (for details see
17550                 // https://bugs.webkit.org/show_bug.cgi?id=24368). The WebKit version where this
17551                 // change was introduced was 532.0
17552                 //      Detailed discussion:
17553                 //      https://bugs.webkit.org/show_bug.cgi?id=29601
17554                 //      http://trac.webkit.org/browser/trunk/WebKit/chromium/src/mac/WebInputEventFactory.mm#L1063
17555                 scale = 120;
17556             } else {
17557                 // MS optical wheel mouse produces multiples of 12 which is close enough
17558                 // to help tame the speed of the continuous mice...
17559                 scale = 12;
17560             }
17561
17562             // Momentum scrolling produces very fast scrolling, so increase the scale factor
17563             // to help produce similar results cross platform. This could be even larger and
17564             // it would help those mice, but other mice would become almost unusable as a
17565             // result (since we cannot tell which device type is in use).
17566             scale *= 3;
17567         } else {
17568             // IE, Opera and other Windows browsers use 120.
17569             scale = 120;
17570         }
17571
17572         return scale;
17573     })(),
17574
17575     /**
17576      * Simple click regex
17577      * @private
17578      */
17579     clickRe: /(dbl)?click/,
17580     // safari keypress events for special keys return bad keycodes
17581     safariKeys: {
17582         3: 13, // enter
17583         63234: 37, // left
17584         63235: 39, // right
17585         63232: 38, // up
17586         63233: 40, // down
17587         63276: 33, // page up
17588         63277: 34, // page down
17589         63272: 46, // delete
17590         63273: 36, // home
17591         63275: 35 // end
17592     },
17593     // normalize button clicks, don't see any way to feature detect this.
17594     btnMap: Ext.isIE ? {
17595         1: 0,
17596         4: 1,
17597         2: 2
17598     } : {
17599         0: 0,
17600         1: 1,
17601         2: 2
17602     },
17603
17604     constructor: function(event, freezeEvent){
17605         if (event) {
17606             this.setEvent(event.browserEvent || event, freezeEvent);
17607         }
17608     },
17609
17610     setEvent: function(event, freezeEvent){
17611         var me = this, button, options;
17612
17613         if (event == me || (event && event.browserEvent)) { // already wrapped
17614             return event;
17615         }
17616         me.browserEvent = event;
17617         if (event) {
17618             // normalize buttons
17619             button = event.button ? me.btnMap[event.button] : (event.which ? event.which - 1 : -1);
17620             if (me.clickRe.test(event.type) && button == -1) {
17621                 button = 0;
17622             }
17623             options = {
17624                 type: event.type,
17625                 button: button,
17626                 shiftKey: event.shiftKey,
17627                 // mac metaKey behaves like ctrlKey
17628                 ctrlKey: event.ctrlKey || event.metaKey || false,
17629                 altKey: event.altKey,
17630                 // in getKey these will be normalized for the mac
17631                 keyCode: event.keyCode,
17632                 charCode: event.charCode,
17633                 // cache the targets for the delayed and or buffered events
17634                 target: Ext.EventManager.getTarget(event),
17635                 relatedTarget: Ext.EventManager.getRelatedTarget(event),
17636                 currentTarget: event.currentTarget,
17637                 xy: (freezeEvent ? me.getXY() : null)
17638             };
17639         } else {
17640             options = {
17641                 button: -1,
17642                 shiftKey: false,
17643                 ctrlKey: false,
17644                 altKey: false,
17645                 keyCode: 0,
17646                 charCode: 0,
17647                 target: null,
17648                 xy: [0, 0]
17649             };
17650         }
17651         Ext.apply(me, options);
17652         return me;
17653     },
17654
17655     /**
17656      * Stop the event (preventDefault and stopPropagation)
17657      */
17658     stopEvent: function(){
17659         this.stopPropagation();
17660         this.preventDefault();
17661     },
17662
17663     /**
17664      * Prevents the browsers default handling of the event.
17665      */
17666     preventDefault: function(){
17667         if (this.browserEvent) {
17668             Ext.EventManager.preventDefault(this.browserEvent);
17669         }
17670     },
17671
17672     /**
17673      * Cancels bubbling of the event.
17674      */
17675     stopPropagation: function(){
17676         var browserEvent = this.browserEvent;
17677
17678         if (browserEvent) {
17679             if (browserEvent.type == 'mousedown') {
17680                 Ext.EventManager.stoppedMouseDownEvent.fire(this);
17681             }
17682             Ext.EventManager.stopPropagation(browserEvent);
17683         }
17684     },
17685
17686     /**
17687      * Gets the character code for the event.
17688      * @return {Number}
17689      */
17690     getCharCode: function(){
17691         return this.charCode || this.keyCode;
17692     },
17693
17694     /**
17695      * Returns a normalized keyCode for the event.
17696      * @return {Number} The key code
17697      */
17698     getKey: function(){
17699         return this.normalizeKey(this.keyCode || this.charCode);
17700     },
17701
17702     /**
17703      * Normalize key codes across browsers
17704      * @private
17705      * @param {Number} key The key code
17706      * @return {Number} The normalized code
17707      */
17708     normalizeKey: function(key){
17709         // can't feature detect this
17710         return Ext.isWebKit ? (this.safariKeys[key] || key) : key;
17711     },
17712
17713     /**
17714      * Gets the x coordinate of the event.
17715      * @return {Number}
17716      * @deprecated 4.0 Replaced by {@link #getX}
17717      */
17718     getPageX: function(){
17719         return this.getX();
17720     },
17721
17722     /**
17723      * Gets the y coordinate of the event.
17724      * @return {Number}
17725      * @deprecated 4.0 Replaced by {@link #getY}
17726      */
17727     getPageY: function(){
17728         return this.getY();
17729     },
17730     
17731     /**
17732      * Gets the x coordinate of the event.
17733      * @return {Number}
17734      */
17735     getX: function() {
17736         return this.getXY()[0];
17737     },    
17738     
17739     /**
17740      * Gets the y coordinate of the event.
17741      * @return {Number}
17742      */
17743     getY: function() {
17744         return this.getXY()[1];
17745     },
17746         
17747     /**
17748      * Gets the page coordinates of the event.
17749      * @return {Array} The xy values like [x, y]
17750      */
17751     getXY: function() {
17752         if (!this.xy) {
17753             // same for XY
17754             this.xy = Ext.EventManager.getPageXY(this.browserEvent);
17755         }
17756         return this.xy;
17757     },
17758
17759     /**
17760      * Gets the target for the event.
17761      * @param {String} selector (optional) A simple selector to filter the target or look for an ancestor of the target
17762      * @param {Number/Mixed} maxDepth (optional) The max depth to search as a number or element (defaults to 10 || document.body)
17763      * @param {Boolean} returnEl (optional) True to return a Ext.core.Element object instead of DOM node
17764      * @return {HTMLelement}
17765      */
17766     getTarget : function(selector, maxDepth, returnEl){
17767         if (selector) {
17768             return Ext.fly(this.target).findParent(selector, maxDepth, returnEl);
17769         }
17770         return returnEl ? Ext.get(this.target) : this.target;
17771     },
17772
17773     /**
17774      * Gets the related target.
17775      * @param {String} selector (optional) A simple selector to filter the target or look for an ancestor of the target
17776      * @param {Number/Mixed} maxDepth (optional) The max depth to search as a number or element (defaults to 10 || document.body)
17777      * @param {Boolean} returnEl (optional) True to return a Ext.core.Element object instead of DOM node
17778      * @return {HTMLElement}
17779      */
17780     getRelatedTarget : function(selector, maxDepth, returnEl){
17781         if (selector) {
17782             return Ext.fly(this.relatedTarget).findParent(selector, maxDepth, returnEl);
17783         }
17784         return returnEl ? Ext.get(this.relatedTarget) : this.relatedTarget;
17785     },
17786
17787     /**
17788      * Correctly scales a given wheel delta.
17789      * @param {Number} delta The delta value.
17790      */
17791     correctWheelDelta : function (delta) {
17792         var scale = this.WHEEL_SCALE,
17793             ret = Math.round(delta / scale + 0.5);
17794
17795         if (!ret && delta) {
17796             ret = (delta < 0) ? -1 : 1; // don't allow non-zero deltas to go to zero!
17797         }
17798
17799         return ret;
17800     },
17801
17802     /**
17803      * Returns the mouse wheel deltas for this event.
17804      * @return {Object} An object with "x" and "y" properties holding the mouse wheel deltas.
17805      */
17806     getWheelDeltas : function () {
17807         var me = this,
17808             event = me.browserEvent,
17809             dx = 0, dy = 0; // the deltas
17810
17811         if (Ext.isDefined(event.wheelDeltaX)) { // WebKit has both dimensions
17812             dx = event.wheelDeltaX;
17813             dy = event.wheelDeltaY;
17814         } else if (event.wheelDelta) { // old WebKit and IE
17815             dy = event.wheelDelta;
17816         } else if (event.detail) { // Gecko
17817             dy = -event.detail; // gecko is backwards
17818
17819             // Gecko sometimes returns really big values if the user changes settings to
17820             // scroll a whole page per scroll
17821             if (dy > 100) {
17822                 dy = 3;
17823             } else if (dy < -100) {
17824                 dy = -3;
17825             }
17826
17827             // Firefox 3.1 adds an axis field to the event to indicate direction of
17828             // scroll.  See https://developer.mozilla.org/en/Gecko-Specific_DOM_Events
17829             if (Ext.isDefined(event.axis) && event.axis === event.HORIZONTAL_AXIS) {
17830                 dx = dy;
17831                 dy = 0;
17832             }
17833         }
17834
17835         return {
17836             x: me.correctWheelDelta(dx),
17837             y: me.correctWheelDelta(dy)
17838         };
17839     },
17840
17841     /**
17842      * Normalizes mouse wheel y-delta across browsers. To get x-delta information, use
17843      * {@link #getWheelDeltas} instead.
17844      * @return {Number} The mouse wheel y-delta
17845      */
17846     getWheelDelta : function(){
17847         var deltas = this.getWheelDeltas();
17848
17849         return deltas.y;
17850     },
17851
17852     /**
17853     * 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.
17854     * Example usage:<pre><code>
17855 // Handle click on any child of an element
17856 Ext.getBody().on('click', function(e){
17857     if(e.within('some-el')){
17858         alert('Clicked on a child of some-el!');
17859     }
17860 });
17861
17862 // Handle click directly on an element, ignoring clicks on child nodes
17863 Ext.getBody().on('click', function(e,t){
17864     if((t.id == 'some-el') && !e.within(t, true)){
17865         alert('Clicked directly on some-el!');
17866     }
17867 });
17868 </code></pre>
17869      * @param {Mixed} el The id, DOM element or Ext.core.Element to check
17870      * @param {Boolean} related (optional) true to test if the related target is within el instead of the target
17871      * @param {Boolean} allowEl {optional} true to also check if the passed element is the target or related target
17872      * @return {Boolean}
17873      */
17874     within : function(el, related, allowEl){
17875         if(el){
17876             var t = related ? this.getRelatedTarget() : this.getTarget(),
17877                 result;
17878
17879             if (t) {
17880                 result = Ext.fly(el).contains(t);
17881                 if (!result && allowEl) {
17882                     result = t == Ext.getDom(el);
17883                 }
17884                 return result;
17885             }
17886         }
17887         return false;
17888     },
17889
17890     /**
17891      * Checks if the key pressed was a "navigation" key
17892      * @return {Boolean} True if the press is a navigation keypress
17893      */
17894     isNavKeyPress : function(){
17895         var me = this,
17896             k = this.normalizeKey(me.keyCode);
17897
17898        return (k >= 33 && k <= 40) ||  // Page Up/Down, End, Home, Left, Up, Right, Down
17899        k == me.RETURN ||
17900        k == me.TAB ||
17901        k == me.ESC;
17902     },
17903
17904     /**
17905      * Checks if the key pressed was a "special" key
17906      * @return {Boolean} True if the press is a special keypress
17907      */
17908     isSpecialKey : function(){
17909         var k = this.normalizeKey(this.keyCode);
17910         return (this.type == 'keypress' && this.ctrlKey) ||
17911         this.isNavKeyPress() ||
17912         (k == this.BACKSPACE) || // Backspace
17913         (k >= 16 && k <= 20) || // Shift, Ctrl, Alt, Pause, Caps Lock
17914         (k >= 44 && k <= 46);   // Print Screen, Insert, Delete
17915     },
17916
17917     /**
17918      * Returns a point object that consists of the object coordinates.
17919      * @return {Ext.util.Point} point
17920      */
17921     getPoint : function(){
17922         var xy = this.getXY();
17923         return Ext.create('Ext.util.Point', xy[0], xy[1]);
17924     },
17925
17926    /**
17927     * Returns true if the control, meta, shift or alt key was pressed during this event.
17928     * @return {Boolean}
17929     */
17930     hasModifier : function(){
17931         return this.ctrlKey || this.altKey || this.shiftKey || this.metaKey;
17932     },
17933
17934     /**
17935      * Injects a DOM event using the data in this object and (optionally) a new target.
17936      * This is a low-level technique and not likely to be used by application code. The
17937      * currently supported event types are:
17938      * <p><b>HTMLEvents</b></p>
17939      * <ul>
17940      * <li>load</li>
17941      * <li>unload</li>
17942      * <li>select</li>
17943      * <li>change</li>
17944      * <li>submit</li>
17945      * <li>reset</li>
17946      * <li>resize</li>
17947      * <li>scroll</li>
17948      * </ul>
17949      * <p><b>MouseEvents</b></p>
17950      * <ul>
17951      * <li>click</li>
17952      * <li>dblclick</li>
17953      * <li>mousedown</li>
17954      * <li>mouseup</li>
17955      * <li>mouseover</li>
17956      * <li>mousemove</li>
17957      * <li>mouseout</li>
17958      * </ul>
17959      * <p><b>UIEvents</b></p>
17960      * <ul>
17961      * <li>focusin</li>
17962      * <li>focusout</li>
17963      * <li>activate</li>
17964      * <li>focus</li>
17965      * <li>blur</li>
17966      * </ul>
17967      * @param {Element/HTMLElement} target If specified, the target for the event. This
17968      * is likely to be used when relaying a DOM event. If not specified, {@link #getTarget}
17969      * is used to determine the target.
17970      */
17971     injectEvent: function () {
17972         var API,
17973             dispatchers = {}; // keyed by event type (e.g., 'mousedown')
17974
17975         // Good reference: http://developer.yahoo.com/yui/docs/UserAction.js.html
17976
17977         // IE9 has createEvent, but this code causes major problems with htmleditor (it
17978         // blocks all mouse events and maybe more). TODO
17979
17980         if (!Ext.isIE && document.createEvent) { // if (DOM compliant)
17981             API = {
17982                 createHtmlEvent: function (doc, type, bubbles, cancelable) {
17983                     var event = doc.createEvent('HTMLEvents');
17984
17985                     event.initEvent(type, bubbles, cancelable);
17986                     return event;
17987                 },
17988
17989                 createMouseEvent: function (doc, type, bubbles, cancelable, detail,
17990                                             clientX, clientY, ctrlKey, altKey, shiftKey, metaKey,
17991                                             button, relatedTarget) {
17992                     var event = doc.createEvent('MouseEvents'),
17993                         view = doc.defaultView || window;
17994
17995                     if (event.initMouseEvent) {
17996                         event.initMouseEvent(type, bubbles, cancelable, view, detail,
17997                                     clientX, clientY, clientX, clientY, ctrlKey, altKey,
17998                                     shiftKey, metaKey, button, relatedTarget);
17999                     } else { // old Safari
18000                         event = doc.createEvent('UIEvents');
18001                         event.initEvent(type, bubbles, cancelable);
18002                         event.view = view;
18003                         event.detail = detail;
18004                         event.screenX = clientX;
18005                         event.screenY = clientY;
18006                         event.clientX = clientX;
18007                         event.clientY = clientY;
18008                         event.ctrlKey = ctrlKey;
18009                         event.altKey = altKey;
18010                         event.metaKey = metaKey;
18011                         event.shiftKey = shiftKey;
18012                         event.button = button;
18013                         event.relatedTarget = relatedTarget;
18014                     }
18015
18016                     return event;
18017                 },
18018
18019                 createUIEvent: function (doc, type, bubbles, cancelable, detail) {
18020                     var event = doc.createEvent('UIEvents'),
18021                         view = doc.defaultView || window;
18022
18023                     event.initUIEvent(type, bubbles, cancelable, view, detail);
18024                     return event;
18025                 },
18026
18027                 fireEvent: function (target, type, event) {
18028                     target.dispatchEvent(event);
18029                 },
18030
18031                 fixTarget: function (target) {
18032                     // Safari3 doesn't have window.dispatchEvent()
18033                     if (target == window && !target.dispatchEvent) {
18034                         return document;
18035                     }
18036
18037                     return target;
18038                 }
18039             };
18040         } else if (document.createEventObject) { // else if (IE)
18041             var crazyIEButtons = { 0: 1, 1: 4, 2: 2 };
18042
18043             API = {
18044                 createHtmlEvent: function (doc, type, bubbles, cancelable) {
18045                     var event = doc.createEventObject();
18046                     event.bubbles = bubbles;
18047                     event.cancelable = cancelable;
18048                     return event;
18049                 },
18050
18051                 createMouseEvent: function (doc, type, bubbles, cancelable, detail,
18052                                             clientX, clientY, ctrlKey, altKey, shiftKey, metaKey,
18053                                             button, relatedTarget) {
18054                     var event = doc.createEventObject();
18055                     event.bubbles = bubbles;
18056                     event.cancelable = cancelable;
18057                     event.detail = detail;
18058                     event.screenX = clientX;
18059                     event.screenY = clientY;
18060                     event.clientX = clientX;
18061                     event.clientY = clientY;
18062                     event.ctrlKey = ctrlKey;
18063                     event.altKey = altKey;
18064                     event.shiftKey = shiftKey;
18065                     event.metaKey = metaKey;
18066                     event.button = crazyIEButtons[button] || button;
18067                     event.relatedTarget = relatedTarget; // cannot assign to/fromElement
18068                     return event;
18069                 },
18070
18071                 createUIEvent: function (doc, type, bubbles, cancelable, detail) {
18072                     var event = doc.createEventObject();
18073                     event.bubbles = bubbles;
18074                     event.cancelable = cancelable;
18075                     return event;
18076                 },
18077
18078                 fireEvent: function (target, type, event) {
18079                     target.fireEvent('on' + type, event);
18080                 },
18081
18082                 fixTarget: function (target) {
18083                     if (target == document) {
18084                         // IE6,IE7 thinks window==document and doesn't have window.fireEvent()
18085                         // IE6,IE7 cannot properly call document.fireEvent()
18086                         return document.documentElement;
18087                     }
18088
18089                     return target;
18090                 }
18091             };
18092         }
18093
18094         //----------------
18095         // HTMLEvents
18096
18097         Ext.Object.each({
18098                 load:   [false, false],
18099                 unload: [false, false],
18100                 select: [true, false],
18101                 change: [true, false],
18102                 submit: [true, true],
18103                 reset:  [true, false],
18104                 resize: [true, false],
18105                 scroll: [true, false]
18106             },
18107             function (name, value) {
18108                 var bubbles = value[0], cancelable = value[1];
18109                 dispatchers[name] = function (targetEl, srcEvent) {
18110                     var e = API.createHtmlEvent(name, bubbles, cancelable);
18111                     API.fireEvent(targetEl, name, e);
18112                 };
18113             });
18114
18115         //----------------
18116         // MouseEvents
18117
18118         function createMouseEventDispatcher (type, detail) {
18119             var cancelable = (type != 'mousemove');
18120             return function (targetEl, srcEvent) {
18121                 var xy = srcEvent.getXY(),
18122                     e = API.createMouseEvent(targetEl.ownerDocument, type, true, cancelable,
18123                                 detail, xy[0], xy[1], srcEvent.ctrlKey, srcEvent.altKey,
18124                                 srcEvent.shiftKey, srcEvent.metaKey, srcEvent.button,
18125                                 srcEvent.relatedTarget);
18126                 API.fireEvent(targetEl, type, e);
18127             };
18128         }
18129
18130         Ext.each(['click', 'dblclick', 'mousedown', 'mouseup', 'mouseover', 'mousemove', 'mouseout'],
18131             function (eventName) {
18132                 dispatchers[eventName] = createMouseEventDispatcher(eventName, 1);
18133             });
18134
18135         //----------------
18136         // UIEvents
18137
18138         Ext.Object.each({
18139                 focusin:  [true, false],
18140                 focusout: [true, false],
18141                 activate: [true, true],
18142                 focus:    [false, false],
18143                 blur:     [false, false]
18144             },
18145             function (name, value) {
18146                 var bubbles = value[0], cancelable = value[1];
18147                 dispatchers[name] = function (targetEl, srcEvent) {
18148                     var e = API.createUIEvent(targetEl.ownerDocument, name, bubbles, cancelable, 1);
18149                     API.fireEvent(targetEl, name, e);
18150                 };
18151             });
18152
18153         //---------
18154         if (!API) {
18155             // not even sure what ancient browsers fall into this category...
18156
18157             dispatchers = {}; // never mind all those we just built :P
18158
18159             API = {
18160                 fixTarget: function (t) {
18161                     return t;
18162                 }
18163             };
18164         }
18165
18166         function cannotInject (target, srcEvent) {
18167         }
18168
18169         return function (target) {
18170             var me = this,
18171                 dispatcher = dispatchers[me.type] || cannotInject,
18172                 t = target ? (target.dom || target) : me.getTarget();
18173
18174             t = API.fixTarget(t);
18175             dispatcher(t, me);
18176         };
18177     }() // call to produce method
18178
18179 }, function() {
18180
18181 Ext.EventObject = new Ext.EventObjectImpl();
18182
18183 });
18184
18185
18186 /**
18187  * @class Ext.core.Element
18188  */
18189 (function(){
18190     var doc = document,
18191         activeElement = null,
18192         isCSS1 = doc.compatMode == "CSS1Compat",
18193         ELEMENT = Ext.core.Element,
18194         fly = function(el){
18195             if (!_fly) {
18196                 _fly = new Ext.core.Element.Flyweight();
18197             }
18198             _fly.dom = el;
18199             return _fly;
18200         }, _fly;
18201
18202     // If the browser does not support document.activeElement we need some assistance.
18203     // This covers old Safari 3.2 (4.0 added activeElement along with just about all
18204     // other browsers). We need this support to handle issues with old Safari.
18205     if (!('activeElement' in doc) && doc.addEventListener) {
18206         doc.addEventListener('focus',
18207             function (ev) {
18208                 if (ev && ev.target) {
18209                     activeElement = (ev.target == doc) ? null : ev.target;
18210                 }
18211             }, true);
18212     }
18213
18214     /*
18215      * Helper function to create the function that will restore the selection.
18216      */
18217     function makeSelectionRestoreFn (activeEl, start, end) {
18218         return function () {
18219             activeEl.selectionStart = start;
18220             activeEl.selectionEnd = end;
18221         };
18222     }
18223
18224     Ext.apply(ELEMENT, {
18225         isAncestor : function(p, c) {
18226             var ret = false;
18227
18228             p = Ext.getDom(p);
18229             c = Ext.getDom(c);
18230             if (p && c) {
18231                 if (p.contains) {
18232                     return p.contains(c);
18233                 } else if (p.compareDocumentPosition) {
18234                     return !!(p.compareDocumentPosition(c) & 16);
18235                 } else {
18236                     while ((c = c.parentNode)) {
18237                         ret = c == p || ret;
18238                     }
18239                 }
18240             }
18241             return ret;
18242         },
18243
18244         /**
18245          * Returns the active element in the DOM. If the browser supports activeElement
18246          * on the document, this is returned. If not, the focus is tracked and the active
18247          * element is maintained internally.
18248          * @return {HTMLElement} The active (focused) element in the document.
18249          */
18250         getActiveElement: function () {
18251             return doc.activeElement || activeElement;
18252         },
18253
18254         /**
18255          * Creates a function to call to clean up problems with the work-around for the
18256          * WebKit RightMargin bug. The work-around is to add "display: 'inline-block'" to
18257          * the element before calling getComputedStyle and then to restore its original
18258          * display value. The problem with this is that it corrupts the selection of an
18259          * INPUT or TEXTAREA element (as in the "I-beam" goes away but ths focus remains).
18260          * To cleanup after this, we need to capture the selection of any such element and
18261          * then restore it after we have restored the display style.
18262          *
18263          * @param target {Element} The top-most element being adjusted.
18264          * @private
18265          */
18266         getRightMarginFixCleaner: function (target) {
18267             var supports = Ext.supports,
18268                 hasInputBug = supports.DisplayChangeInputSelectionBug,
18269                 hasTextAreaBug = supports.DisplayChangeTextAreaSelectionBug;
18270
18271             if (hasInputBug || hasTextAreaBug) {
18272                 var activeEl = doc.activeElement || activeElement, // save a call
18273                     tag = activeEl && activeEl.tagName,
18274                     start,
18275                     end;
18276
18277                 if ((hasTextAreaBug && tag == 'TEXTAREA') ||
18278                     (hasInputBug && tag == 'INPUT' && activeEl.type == 'text')) {
18279                     if (ELEMENT.isAncestor(target, activeEl)) {
18280                         start = activeEl.selectionStart;
18281                         end = activeEl.selectionEnd;
18282
18283                         if (Ext.isNumber(start) && Ext.isNumber(end)) { // to be safe...
18284                             // We don't create the raw closure here inline because that
18285                             // will be costly even if we don't want to return it (nested
18286                             // function decls and exprs are often instantiated on entry
18287                             // regardless of whether execution ever reaches them):
18288                             return makeSelectionRestoreFn(activeEl, start, end);
18289                         }
18290                     }
18291                 }
18292             }
18293
18294             return Ext.emptyFn; // avoid special cases, just return a nop
18295         },
18296
18297         getViewWidth : function(full) {
18298             return full ? ELEMENT.getDocumentWidth() : ELEMENT.getViewportWidth();
18299         },
18300
18301         getViewHeight : function(full) {
18302             return full ? ELEMENT.getDocumentHeight() : ELEMENT.getViewportHeight();
18303         },
18304
18305         getDocumentHeight: function() {
18306             return Math.max(!isCSS1 ? doc.body.scrollHeight : doc.documentElement.scrollHeight, ELEMENT.getViewportHeight());
18307         },
18308
18309         getDocumentWidth: function() {
18310             return Math.max(!isCSS1 ? doc.body.scrollWidth : doc.documentElement.scrollWidth, ELEMENT.getViewportWidth());
18311         },
18312
18313         getViewportHeight: function(){
18314             return Ext.isIE ?
18315                    (Ext.isStrict ? doc.documentElement.clientHeight : doc.body.clientHeight) :
18316                    self.innerHeight;
18317         },
18318
18319         getViewportWidth : function() {
18320             return (!Ext.isStrict && !Ext.isOpera) ? doc.body.clientWidth :
18321                    Ext.isIE ? doc.documentElement.clientWidth : self.innerWidth;
18322         },
18323
18324         getY : function(el) {
18325             return ELEMENT.getXY(el)[1];
18326         },
18327
18328         getX : function(el) {
18329             return ELEMENT.getXY(el)[0];
18330         },
18331
18332         getXY : function(el) {
18333             var p,
18334                 pe,
18335                 b,
18336                 bt,
18337                 bl,
18338                 dbd,
18339                 x = 0,
18340                 y = 0,
18341                 scroll,
18342                 hasAbsolute,
18343                 bd = (doc.body || doc.documentElement),
18344                 ret = [0,0];
18345
18346             el = Ext.getDom(el);
18347
18348             if(el != bd){
18349                 hasAbsolute = fly(el).isStyle("position", "absolute");
18350
18351                 if (el.getBoundingClientRect) {
18352                     b = el.getBoundingClientRect();
18353                     scroll = fly(document).getScroll();
18354                     ret = [Math.round(b.left + scroll.left), Math.round(b.top + scroll.top)];
18355                 } else {
18356                     p = el;
18357
18358                     while (p) {
18359                         pe = fly(p);
18360                         x += p.offsetLeft;
18361                         y += p.offsetTop;
18362
18363                         hasAbsolute = hasAbsolute || pe.isStyle("position", "absolute");
18364
18365                         if (Ext.isGecko) {
18366                             y += bt = parseInt(pe.getStyle("borderTopWidth"), 10) || 0;
18367                             x += bl = parseInt(pe.getStyle("borderLeftWidth"), 10) || 0;
18368
18369                             if (p != el && !pe.isStyle('overflow','visible')) {
18370                                 x += bl;
18371                                 y += bt;
18372                             }
18373                         }
18374                         p = p.offsetParent;
18375                     }
18376
18377                     if (Ext.isSafari && hasAbsolute) {
18378                         x -= bd.offsetLeft;
18379                         y -= bd.offsetTop;
18380                     }
18381
18382                     if (Ext.isGecko && !hasAbsolute) {
18383                         dbd = fly(bd);
18384                         x += parseInt(dbd.getStyle("borderLeftWidth"), 10) || 0;
18385                         y += parseInt(dbd.getStyle("borderTopWidth"), 10) || 0;
18386                     }
18387
18388                     p = el.parentNode;
18389                     while (p && p != bd) {
18390                         if (!Ext.isOpera || (p.tagName != 'TR' && !fly(p).isStyle("display", "inline"))) {
18391                             x -= p.scrollLeft;
18392                             y -= p.scrollTop;
18393                         }
18394                         p = p.parentNode;
18395                     }
18396                     ret = [x,y];
18397                 }
18398             }
18399             return ret;
18400         },
18401
18402         setXY : function(el, xy) {
18403             (el = Ext.fly(el, '_setXY')).position();
18404
18405             var pts = el.translatePoints(xy),
18406                 style = el.dom.style,
18407                 pos;
18408
18409             for (pos in pts) {
18410                 if (!isNaN(pts[pos])) {
18411                     style[pos] = pts[pos] + "px";
18412                 }
18413             }
18414         },
18415
18416         setX : function(el, x) {
18417             ELEMENT.setXY(el, [x, false]);
18418         },
18419
18420         setY : function(el, y) {
18421             ELEMENT.setXY(el, [false, y]);
18422         },
18423
18424         /**
18425          * Serializes a DOM form into a url encoded string
18426          * @param {Object} form The form
18427          * @return {String} The url encoded form
18428          */
18429         serializeForm: function(form) {
18430             var fElements = form.elements || (document.forms[form] || Ext.getDom(form)).elements,
18431                 hasSubmit = false,
18432                 encoder = encodeURIComponent,
18433                 name,
18434                 data = '',
18435                 type,
18436                 hasValue;
18437
18438             Ext.each(fElements, function(element){
18439                 name = element.name;
18440                 type = element.type;
18441
18442                 if (!element.disabled && name) {
18443                     if (/select-(one|multiple)/i.test(type)) {
18444                         Ext.each(element.options, function(opt){
18445                             if (opt.selected) {
18446                                 hasValue = opt.hasAttribute ? opt.hasAttribute('value') : opt.getAttributeNode('value').specified;
18447                                 data += Ext.String.format("{0}={1}&", encoder(name), encoder(hasValue ? opt.value : opt.text));
18448                             }
18449                         });
18450                     } else if (!(/file|undefined|reset|button/i.test(type))) {
18451                         if (!(/radio|checkbox/i.test(type) && !element.checked) && !(type == 'submit' && hasSubmit)) {
18452                             data += encoder(name) + '=' + encoder(element.value) + '&';
18453                             hasSubmit = /submit/i.test(type);
18454                         }
18455                     }
18456                 }
18457             });
18458             return data.substr(0, data.length - 1);
18459         }
18460     });
18461 })();
18462
18463 /**
18464  * @class Ext.core.Element
18465  */
18466
18467 Ext.core.Element.addMethods({
18468
18469     /**
18470      * Monitors this Element for the mouse leaving. Calls the function after the specified delay only if
18471      * the mouse was not moved back into the Element within the delay. If the mouse <i>was</i> moved
18472      * back in, the function is not called.
18473      * @param {Number} delay The delay <b>in milliseconds</b> to wait for possible mouse re-entry before calling the handler function.
18474      * @param {Function} handler The function to call if the mouse remains outside of this Element for the specified time.
18475      * @param {Object} scope The scope (<code>this</code> reference) in which the handler function executes. Defaults to this Element.
18476      * @return {Object} The listeners object which was added to this element so that monitoring can be stopped. Example usage:</pre><code>
18477 // Hide the menu if the mouse moves out for 250ms or more
18478 this.mouseLeaveMonitor = this.menuEl.monitorMouseLeave(250, this.hideMenu, this);
18479
18480 ...
18481 // Remove mouseleave monitor on menu destroy
18482 this.menuEl.un(this.mouseLeaveMonitor);
18483 </code></pre>
18484      */
18485     monitorMouseLeave: function(delay, handler, scope) {
18486         var me = this,
18487             timer,
18488             listeners = {
18489                 mouseleave: function(e) {
18490                     timer = setTimeout(Ext.Function.bind(handler, scope||me, [e]), delay);
18491                 },
18492                 mouseenter: function() {
18493                     clearTimeout(timer);
18494                 },
18495                 freezeEvent: true
18496             };
18497
18498         me.on(listeners);
18499         return listeners;
18500     },
18501
18502     /**
18503      * Stops the specified event(s) from bubbling and optionally prevents the default action
18504      * @param {String/Array} eventName an event / array of events to stop from bubbling
18505      * @param {Boolean} preventDefault (optional) true to prevent the default action too
18506      * @return {Ext.core.Element} this
18507      */
18508     swallowEvent : function(eventName, preventDefault) {
18509         var me = this;
18510         function fn(e) {
18511             e.stopPropagation();
18512             if (preventDefault) {
18513                 e.preventDefault();
18514             }
18515         }
18516         
18517         if (Ext.isArray(eventName)) {
18518             Ext.each(eventName, function(e) {
18519                  me.on(e, fn);
18520             });
18521             return me;
18522         }
18523         me.on(eventName, fn);
18524         return me;
18525     },
18526
18527     /**
18528      * Create an event handler on this element such that when the event fires and is handled by this element,
18529      * it will be relayed to another object (i.e., fired again as if it originated from that object instead).
18530      * @param {String} eventName The type of event to relay
18531      * @param {Object} object Any object that extends {@link Ext.util.Observable} that will provide the context
18532      * for firing the relayed event
18533      */
18534     relayEvent : function(eventName, observable) {
18535         this.on(eventName, function(e) {
18536             observable.fireEvent(eventName, e);
18537         });
18538     },
18539
18540     /**
18541      * Removes Empty, or whitespace filled text nodes. Combines adjacent text nodes.
18542      * @param {Boolean} forceReclean (optional) By default the element
18543      * keeps track if it has been cleaned already so
18544      * you can call this over and over. However, if you update the element and
18545      * need to force a reclean, you can pass true.
18546      */
18547     clean : function(forceReclean) {
18548         var me  = this,
18549             dom = me.dom,
18550             n   = dom.firstChild,
18551             nx,
18552             ni  = -1;
18553
18554         if (Ext.core.Element.data(dom, 'isCleaned') && forceReclean !== true) {
18555             return me;
18556         }
18557
18558         while (n) {
18559             nx = n.nextSibling;
18560             if (n.nodeType == 3) {
18561                 // Remove empty/whitespace text nodes
18562                 if (!(/\S/.test(n.nodeValue))) {
18563                     dom.removeChild(n);
18564                 // Combine adjacent text nodes
18565                 } else if (nx && nx.nodeType == 3) {
18566                     n.appendData(Ext.String.trim(nx.data));
18567                     dom.removeChild(nx);
18568                     nx = n.nextSibling;
18569                     n.nodeIndex = ++ni;
18570                 }
18571             } else {
18572                 // Recursively clean
18573                 Ext.fly(n).clean();
18574                 n.nodeIndex = ++ni;
18575             }
18576             n = nx;
18577         }
18578
18579         Ext.core.Element.data(dom, 'isCleaned', true);
18580         return me;
18581     },
18582
18583     /**
18584      * Direct access to the Ext.ElementLoader {@link Ext.ElementLoader#load} method. The method takes the same object
18585      * parameter as {@link Ext.ElementLoader#load}
18586      * @return {Ext.core.Element} this
18587      */
18588     load : function(options) {
18589         this.getLoader().load(options);
18590         return this;
18591     },
18592
18593     /**
18594     * Gets this element's {@link Ext.ElementLoader ElementLoader}
18595     * @return {Ext.ElementLoader} The loader
18596     */
18597     getLoader : function() {
18598         var dom = this.dom,
18599             data = Ext.core.Element.data,
18600             loader = data(dom, 'loader');
18601             
18602         if (!loader) {
18603             loader = Ext.create('Ext.ElementLoader', {
18604                 target: this
18605             });
18606             data(dom, 'loader', loader);
18607         }
18608         return loader;
18609     },
18610
18611     /**
18612     * Update the innerHTML of this element, optionally searching for and processing scripts
18613     * @param {String} html The new HTML
18614     * @param {Boolean} loadScripts (optional) True to look for and process scripts (defaults to false)
18615     * @param {Function} callback (optional) For async script loading you can be notified when the update completes
18616     * @return {Ext.core.Element} this
18617      */
18618     update : function(html, loadScripts, callback) {
18619         var me = this,
18620             id,
18621             dom,
18622             interval;
18623             
18624         if (!me.dom) {
18625             return me;
18626         }
18627         html = html || '';
18628         dom = me.dom;
18629
18630         if (loadScripts !== true) {
18631             dom.innerHTML = html;
18632             Ext.callback(callback, me);
18633             return me;
18634         }
18635
18636         id  = Ext.id();
18637         html += '<span id="' + id + '"></span>';
18638
18639         interval = setInterval(function(){
18640             if (!document.getElementById(id)) {
18641                 return false;    
18642             }
18643             clearInterval(interval);
18644             var DOC    = document,
18645                 hd     = DOC.getElementsByTagName("head")[0],
18646                 re     = /(?:<script([^>]*)?>)((\n|\r|.)*?)(?:<\/script>)/ig,
18647                 srcRe  = /\ssrc=([\'\"])(.*?)\1/i,
18648                 typeRe = /\stype=([\'\"])(.*?)\1/i,
18649                 match,
18650                 attrs,
18651                 srcMatch,
18652                 typeMatch,
18653                 el,
18654                 s;
18655
18656             while ((match = re.exec(html))) {
18657                 attrs = match[1];
18658                 srcMatch = attrs ? attrs.match(srcRe) : false;
18659                 if (srcMatch && srcMatch[2]) {
18660                    s = DOC.createElement("script");
18661                    s.src = srcMatch[2];
18662                    typeMatch = attrs.match(typeRe);
18663                    if (typeMatch && typeMatch[2]) {
18664                        s.type = typeMatch[2];
18665                    }
18666                    hd.appendChild(s);
18667                 } else if (match[2] && match[2].length > 0) {
18668                     if (window.execScript) {
18669                        window.execScript(match[2]);
18670                     } else {
18671                        window.eval(match[2]);
18672                     }
18673                 }
18674             }
18675             
18676             el = DOC.getElementById(id);
18677             if (el) {
18678                 Ext.removeNode(el);
18679             }
18680             Ext.callback(callback, me);
18681         }, 20);
18682         dom.innerHTML = html.replace(/(?:<script.*?>)((\n|\r|.)*?)(?:<\/script>)/ig, '');
18683         return me;
18684     },
18685
18686     // inherit docs, overridden so we can add removeAnchor
18687     removeAllListeners : function() {
18688         this.removeAnchor();
18689         Ext.EventManager.removeAll(this.dom);
18690         return this;
18691     },
18692
18693     /**
18694      * Creates a proxy element of this element
18695      * @param {String/Object} config The class name of the proxy element or a DomHelper config object
18696      * @param {String/HTMLElement} renderTo (optional) The element or element id to render the proxy to (defaults to document.body)
18697      * @param {Boolean} matchBox (optional) True to align and size the proxy to this element now (defaults to false)
18698      * @return {Ext.core.Element} The new proxy element
18699      */
18700     createProxy : function(config, renderTo, matchBox) {
18701         config = (typeof config == 'object') ? config : {tag : "div", cls: config};
18702
18703         var me = this,
18704             proxy = renderTo ? Ext.core.DomHelper.append(renderTo, config, true) :
18705                                Ext.core.DomHelper.insertBefore(me.dom, config, true);
18706
18707         proxy.setVisibilityMode(Ext.core.Element.DISPLAY);
18708         proxy.hide();
18709         if (matchBox && me.setBox && me.getBox) { // check to make sure Element.position.js is loaded
18710            proxy.setBox(me.getBox());
18711         }
18712         return proxy;
18713     }
18714 });
18715 Ext.core.Element.prototype.clearListeners = Ext.core.Element.prototype.removeAllListeners;
18716
18717 /**
18718  * @class Ext.core.Element
18719  */
18720 Ext.core.Element.addMethods({
18721     /**
18722      * Gets the x,y coordinates specified by the anchor position on the element.
18723      * @param {String} anchor (optional) The specified anchor position (defaults to "c").  See {@link #alignTo}
18724      * for details on supported anchor positions.
18725      * @param {Boolean} local (optional) True to get the local (element top/left-relative) anchor position instead
18726      * of page coordinates
18727      * @param {Object} size (optional) An object containing the size to use for calculating anchor position
18728      * {width: (target width), height: (target height)} (defaults to the element's current size)
18729      * @return {Array} [x, y] An array containing the element's x and y coordinates
18730      */
18731     getAnchorXY : function(anchor, local, s){
18732         //Passing a different size is useful for pre-calculating anchors,
18733         //especially for anchored animations that change the el size.
18734         anchor = (anchor || "tl").toLowerCase();
18735         s = s || {};
18736
18737         var me = this,
18738             vp = me.dom == document.body || me.dom == document,
18739             w = s.width || vp ? Ext.core.Element.getViewWidth() : me.getWidth(),
18740             h = s.height || vp ? Ext.core.Element.getViewHeight() : me.getHeight(),
18741             xy,
18742             r = Math.round,
18743             o = me.getXY(),
18744             scroll = me.getScroll(),
18745             extraX = vp ? scroll.left : !local ? o[0] : 0,
18746             extraY = vp ? scroll.top : !local ? o[1] : 0,
18747             hash = {
18748                 c  : [r(w * 0.5), r(h * 0.5)],
18749                 t  : [r(w * 0.5), 0],
18750                 l  : [0, r(h * 0.5)],
18751                 r  : [w, r(h * 0.5)],
18752                 b  : [r(w * 0.5), h],
18753                 tl : [0, 0],
18754                 bl : [0, h],
18755                 br : [w, h],
18756                 tr : [w, 0]
18757             };
18758
18759         xy = hash[anchor];
18760         return [xy[0] + extraX, xy[1] + extraY];
18761     },
18762
18763     /**
18764      * Anchors an element to another element and realigns it when the window is resized.
18765      * @param {Mixed} element The element to align to.
18766      * @param {String} position The position to align to.
18767      * @param {Array} offsets (optional) Offset the positioning by [x, y]
18768      * @param {Boolean/Object} animate (optional) True for the default animation or a standard Element animation config object
18769      * @param {Boolean/Number} monitorScroll (optional) True to monitor body scroll and reposition. If this parameter
18770      * is a number, it is used as the buffer delay (defaults to 50ms).
18771      * @param {Function} callback The function to call after the animation finishes
18772      * @return {Ext.core.Element} this
18773      */
18774     anchorTo : function(el, alignment, offsets, animate, monitorScroll, callback){
18775         var me = this,
18776             dom = me.dom,
18777             scroll = !Ext.isEmpty(monitorScroll),
18778             action = function(){
18779                 Ext.fly(dom).alignTo(el, alignment, offsets, animate);
18780                 Ext.callback(callback, Ext.fly(dom));
18781             },
18782             anchor = this.getAnchor();
18783
18784         // previous listener anchor, remove it
18785         this.removeAnchor();
18786         Ext.apply(anchor, {
18787             fn: action,
18788             scroll: scroll
18789         });
18790
18791         Ext.EventManager.onWindowResize(action, null);
18792
18793         if(scroll){
18794             Ext.EventManager.on(window, 'scroll', action, null,
18795                 {buffer: !isNaN(monitorScroll) ? monitorScroll : 50});
18796         }
18797         action.call(me); // align immediately
18798         return me;
18799     },
18800
18801     /**
18802      * Remove any anchor to this element. See {@link #anchorTo}.
18803      * @return {Ext.core.Element} this
18804      */
18805     removeAnchor : function(){
18806         var me = this,
18807             anchor = this.getAnchor();
18808
18809         if(anchor && anchor.fn){
18810             Ext.EventManager.removeResizeListener(anchor.fn);
18811             if(anchor.scroll){
18812                 Ext.EventManager.un(window, 'scroll', anchor.fn);
18813             }
18814             delete anchor.fn;
18815         }
18816         return me;
18817     },
18818
18819     // private
18820     getAnchor : function(){
18821         var data = Ext.core.Element.data,
18822             dom = this.dom;
18823             if (!dom) {
18824                 return;
18825             }
18826             var anchor = data(dom, '_anchor');
18827
18828         if(!anchor){
18829             anchor = data(dom, '_anchor', {});
18830         }
18831         return anchor;
18832     },
18833
18834     getAlignVector: function(el, spec, offset) {
18835         var me = this,
18836             side = {t:"top", l:"left", r:"right", b: "bottom"},
18837             thisRegion = me.getRegion(),
18838             elRegion;
18839
18840         el = Ext.get(el);
18841         if(!el || !el.dom){
18842         }
18843
18844         elRegion = el.getRegion();
18845     },
18846
18847     /**
18848      * Gets the x,y coordinates to align this element with another element. See {@link #alignTo} for more info on the
18849      * supported position values.
18850      * @param {Mixed} element The element to align to.
18851      * @param {String} position (optional, defaults to "tl-bl?") The position to align to.
18852      * @param {Array} offsets (optional) Offset the positioning by [x, y]
18853      * @return {Array} [x, y]
18854      */
18855     getAlignToXY : function(el, p, o){
18856         el = Ext.get(el);
18857
18858         if(!el || !el.dom){
18859         }
18860
18861         o = o || [0,0];
18862         p = (!p || p == "?" ? "tl-bl?" : (!(/-/).test(p) && p !== "" ? "tl-" + p : p || "tl-bl")).toLowerCase();
18863
18864         var me = this,
18865             d = me.dom,
18866             a1,
18867             a2,
18868             x,
18869             y,
18870             //constrain the aligned el to viewport if necessary
18871             w,
18872             h,
18873             r,
18874             dw = Ext.core.Element.getViewWidth() -10, // 10px of margin for ie
18875             dh = Ext.core.Element.getViewHeight()-10, // 10px of margin for ie
18876             p1y,
18877             p1x,
18878             p2y,
18879             p2x,
18880             swapY,
18881             swapX,
18882             doc = document,
18883             docElement = doc.documentElement,
18884             docBody = doc.body,
18885             scrollX = (docElement.scrollLeft || docBody.scrollLeft || 0)+5,
18886             scrollY = (docElement.scrollTop || docBody.scrollTop || 0)+5,
18887             c = false, //constrain to viewport
18888             p1 = "",
18889             p2 = "",
18890             m = p.match(/^([a-z]+)-([a-z]+)(\?)?$/);
18891
18892         if(!m){
18893         }
18894
18895         p1 = m[1];
18896         p2 = m[2];
18897         c = !!m[3];
18898
18899         //Subtract the aligned el's internal xy from the target's offset xy
18900         //plus custom offset to get the aligned el's new offset xy
18901         a1 = me.getAnchorXY(p1, true);
18902         a2 = el.getAnchorXY(p2, false);
18903
18904         x = a2[0] - a1[0] + o[0];
18905         y = a2[1] - a1[1] + o[1];
18906
18907         if(c){
18908            w = me.getWidth();
18909            h = me.getHeight();
18910            r = el.getRegion();
18911            //If we are at a viewport boundary and the aligned el is anchored on a target border that is
18912            //perpendicular to the vp border, allow the aligned el to slide on that border,
18913            //otherwise swap the aligned el to the opposite border of the target.
18914            p1y = p1.charAt(0);
18915            p1x = p1.charAt(p1.length-1);
18916            p2y = p2.charAt(0);
18917            p2x = p2.charAt(p2.length-1);
18918            swapY = ((p1y=="t" && p2y=="b") || (p1y=="b" && p2y=="t"));
18919            swapX = ((p1x=="r" && p2x=="l") || (p1x=="l" && p2x=="r"));
18920
18921
18922            if (x + w > dw + scrollX) {
18923                 x = swapX ? r.left-w : dw+scrollX-w;
18924            }
18925            if (x < scrollX) {
18926                x = swapX ? r.right : scrollX;
18927            }
18928            if (y + h > dh + scrollY) {
18929                 y = swapY ? r.top-h : dh+scrollY-h;
18930             }
18931            if (y < scrollY){
18932                y = swapY ? r.bottom : scrollY;
18933            }
18934         }
18935         return [x,y];
18936     },
18937
18938     /**
18939      * Aligns this element with another element relative to the specified anchor points. If the other element is the
18940      * document it aligns it to the viewport.
18941      * The position parameter is optional, and can be specified in any one of the following formats:
18942      * <ul>
18943      *   <li><b>Blank</b>: Defaults to aligning the element's top-left corner to the target's bottom-left corner ("tl-bl").</li>
18944      *   <li><b>One anchor (deprecated)</b>: The passed anchor position is used as the target element's anchor point.
18945      *       The element being aligned will position its top-left corner (tl) to that point.  <i>This method has been
18946      *       deprecated in favor of the newer two anchor syntax below</i>.</li>
18947      *   <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
18948      *       element's anchor point, and the second value is used as the target's anchor point.</li>
18949      * </ul>
18950      * In addition to the anchor points, the position parameter also supports the "?" character.  If "?" is passed at the end of
18951      * the position string, the element will attempt to align as specified, but the position will be adjusted to constrain to
18952      * the viewport if necessary.  Note that the element being aligned might be swapped to align to a different position than
18953      * that specified in order to enforce the viewport constraints.
18954      * Following are all of the supported anchor positions:
18955 <pre>
18956 Value  Description
18957 -----  -----------------------------
18958 tl     The top left corner (default)
18959 t      The center of the top edge
18960 tr     The top right corner
18961 l      The center of the left edge
18962 c      In the center of the element
18963 r      The center of the right edge
18964 bl     The bottom left corner
18965 b      The center of the bottom edge
18966 br     The bottom right corner
18967 </pre>
18968 Example Usage:
18969 <pre><code>
18970 // align el to other-el using the default positioning ("tl-bl", non-constrained)
18971 el.alignTo("other-el");
18972
18973 // align the top left corner of el with the top right corner of other-el (constrained to viewport)
18974 el.alignTo("other-el", "tr?");
18975
18976 // align the bottom right corner of el with the center left edge of other-el
18977 el.alignTo("other-el", "br-l?");
18978
18979 // align the center of el with the bottom left corner of other-el and
18980 // adjust the x position by -6 pixels (and the y position by 0)
18981 el.alignTo("other-el", "c-bl", [-6, 0]);
18982 </code></pre>
18983      * @param {Mixed} element The element to align to.
18984      * @param {String} position (optional, defaults to "tl-bl?") The position to align to.
18985      * @param {Array} offsets (optional) Offset the positioning by [x, y]
18986      * @param {Boolean/Object} animate (optional) true for the default animation or a standard Element animation config object
18987      * @return {Ext.core.Element} this
18988      */
18989     alignTo : function(element, position, offsets, animate){
18990         var me = this;
18991         return me.setXY(me.getAlignToXY(element, position, offsets),
18992                         me.anim && !!animate ? me.anim(animate) : false);
18993     },
18994
18995     // private ==>  used outside of core
18996     adjustForConstraints : function(xy, parent) {
18997         var vector = this.getConstrainVector(parent, xy);
18998         if (vector) {
18999             xy[0] += vector[0];
19000             xy[1] += vector[1];
19001         }
19002         return xy;
19003     },
19004
19005     /**
19006      * <p>Returns the <code>[X, Y]</code> vector by which this element must be translated to make a best attempt
19007      * to constrain within the passed constraint. Returns <code>false</code> is this element does not need to be moved.</p>
19008      * <p>Priority is given to constraining the top and left within the constraint.</p>
19009      * <p>The constraint may either be an existing element into which this element is to be constrained, or
19010      * an {@link Ext.util.Region Region} into which this element is to be constrained.</p>
19011      * @param constrainTo {Mixed} The Element or {@link Ext.util.Region Region} into which this element is to be constrained.
19012      * @param proposedPosition {Array} A proposed <code>[X, Y]</code> position to test for validity and to produce a vector for instead
19013      * of using this Element's current position;
19014      * @returns {Array} <b>If</b> this element <i>needs</i> to be translated, an <code>[X, Y]</code>
19015      * vector by which this element must be translated. Otherwise, <code>false</code>.
19016      */
19017     getConstrainVector: function(constrainTo, proposedPosition) {
19018         if (!(constrainTo instanceof Ext.util.Region)) {
19019             constrainTo = Ext.get(constrainTo).getViewRegion();
19020         }
19021         var thisRegion = this.getRegion(),
19022             vector = [0, 0],
19023             shadowSize = this.shadow && this.shadow.offset,
19024             overflowed = false;
19025
19026         // Shift this region to occupy the proposed position
19027         if (proposedPosition) {
19028             thisRegion.translateBy(proposedPosition[0] - thisRegion.x, proposedPosition[1] - thisRegion.y);
19029         }
19030
19031         // Reduce the constrain region to allow for shadow
19032         // TODO: Rewrite the Shadow class. When that's done, get the extra for each side from the Shadow.
19033         if (shadowSize) {
19034             constrainTo.adjust(0, -shadowSize, -shadowSize, shadowSize);
19035         }
19036
19037         // Constrain the X coordinate by however much this Element overflows
19038         if (thisRegion.right > constrainTo.right) {
19039             overflowed = true;
19040             vector[0] = (constrainTo.right - thisRegion.right);    // overflowed the right
19041         }
19042         if (thisRegion.left + vector[0] < constrainTo.left) {
19043             overflowed = true;
19044             vector[0] = (constrainTo.left - thisRegion.left);      // overflowed the left
19045         }
19046
19047         // Constrain the Y coordinate by however much this Element overflows
19048         if (thisRegion.bottom > constrainTo.bottom) {
19049             overflowed = true;
19050             vector[1] = (constrainTo.bottom - thisRegion.bottom);  // overflowed the bottom
19051         }
19052         if (thisRegion.top + vector[1] < constrainTo.top) {
19053             overflowed = true;
19054             vector[1] = (constrainTo.top - thisRegion.top);        // overflowed the top
19055         }
19056         return overflowed ? vector : false;
19057     },
19058
19059     /**
19060     * Calculates the x, y to center this element on the screen
19061     * @return {Array} The x, y values [x, y]
19062     */
19063     getCenterXY : function(){
19064         return this.getAlignToXY(document, 'c-c');
19065     },
19066
19067     /**
19068     * Centers the Element in either the viewport, or another Element.
19069     * @param {Mixed} centerIn (optional) The element in which to center the element.
19070     */
19071     center : function(centerIn){
19072         return this.alignTo(centerIn || document, 'c-c');
19073     }
19074 });
19075
19076 /**
19077  * @class Ext.core.Element
19078  */
19079 (function(){
19080
19081 var ELEMENT = Ext.core.Element,
19082     LEFT = "left",
19083     RIGHT = "right",
19084     TOP = "top",
19085     BOTTOM = "bottom",
19086     POSITION = "position",
19087     STATIC = "static",
19088     RELATIVE = "relative",
19089     AUTO = "auto",
19090     ZINDEX = "z-index";
19091
19092 Ext.override(Ext.core.Element, {
19093     /**
19094       * 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).
19095       * @return {Number} The X position of the element
19096       */
19097     getX : function(){
19098         return ELEMENT.getX(this.dom);
19099     },
19100
19101     /**
19102       * 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).
19103       * @return {Number} The Y position of the element
19104       */
19105     getY : function(){
19106         return ELEMENT.getY(this.dom);
19107     },
19108
19109     /**
19110       * 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).
19111       * @return {Array} The XY position of the element
19112       */
19113     getXY : function(){
19114         return ELEMENT.getXY(this.dom);
19115     },
19116
19117     /**
19118       * 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.
19119       * @param {Mixed} element The element to get the offsets from.
19120       * @return {Array} The XY page offsets (e.g. [100, -200])
19121       */
19122     getOffsetsTo : function(el){
19123         var o = this.getXY(),
19124             e = Ext.fly(el, '_internal').getXY();
19125         return [o[0]-e[0],o[1]-e[1]];
19126     },
19127
19128     /**
19129      * 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).
19130      * @param {Number} The X position of the element
19131      * @param {Boolean/Object} animate (optional) True for the default animation, or a standard Element animation config object
19132      * @return {Ext.core.Element} this
19133      */
19134     setX : function(x, animate){
19135         return this.setXY([x, this.getY()], animate);
19136     },
19137
19138     /**
19139      * 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).
19140      * @param {Number} The Y position of the element
19141      * @param {Boolean/Object} animate (optional) True for the default animation, or a standard Element animation config object
19142      * @return {Ext.core.Element} this
19143      */
19144     setY : function(y, animate){
19145         return this.setXY([this.getX(), y], animate);
19146     },
19147
19148     /**
19149      * Sets the element's left position directly using CSS style (instead of {@link #setX}).
19150      * @param {String} left The left CSS property value
19151      * @return {Ext.core.Element} this
19152      */
19153     setLeft : function(left){
19154         this.setStyle(LEFT, this.addUnits(left));
19155         return this;
19156     },
19157
19158     /**
19159      * Sets the element's top position directly using CSS style (instead of {@link #setY}).
19160      * @param {String} top The top CSS property value
19161      * @return {Ext.core.Element} this
19162      */
19163     setTop : function(top){
19164         this.setStyle(TOP, this.addUnits(top));
19165         return this;
19166     },
19167
19168     /**
19169      * Sets the element's CSS right style.
19170      * @param {String} right The right CSS property value
19171      * @return {Ext.core.Element} this
19172      */
19173     setRight : function(right){
19174         this.setStyle(RIGHT, this.addUnits(right));
19175         return this;
19176     },
19177
19178     /**
19179      * Sets the element's CSS bottom style.
19180      * @param {String} bottom The bottom CSS property value
19181      * @return {Ext.core.Element} this
19182      */
19183     setBottom : function(bottom){
19184         this.setStyle(BOTTOM, this.addUnits(bottom));
19185         return this;
19186     },
19187
19188     /**
19189      * Sets the position of the element in page coordinates, regardless of how the element is positioned.
19190      * The element must be part of the DOM tree to have page coordinates (display:none or elements not appended return false).
19191      * @param {Array} pos Contains X & Y [x, y] values for new position (coordinates are page-based)
19192      * @param {Boolean/Object} animate (optional) True for the default animation, or a standard Element animation config object
19193      * @return {Ext.core.Element} this
19194      */
19195     setXY: function(pos, animate) {
19196         var me = this;
19197         if (!animate || !me.anim) {
19198             ELEMENT.setXY(me.dom, pos);
19199         }
19200         else {
19201             if (!Ext.isObject(animate)) {
19202                 animate = {};
19203             }
19204             me.animate(Ext.applyIf({ to: { x: pos[0], y: pos[1] } }, animate));
19205         }
19206         return me;
19207     },
19208
19209     /**
19210      * Sets the position of the element in page coordinates, regardless of how the element is positioned.
19211      * The element must be part of the DOM tree to have page coordinates (display:none or elements not appended return false).
19212      * @param {Number} x X value for new position (coordinates are page-based)
19213      * @param {Number} y Y value for new position (coordinates are page-based)
19214      * @param {Boolean/Object} animate (optional) True for the default animation, or a standard Element animation config object
19215      * @return {Ext.core.Element} this
19216      */
19217     setLocation : function(x, y, animate){
19218         return this.setXY([x, y], animate);
19219     },
19220
19221     /**
19222      * Sets the position of the element in page coordinates, regardless of how the element is positioned.
19223      * The element must be part of the DOM tree to have page coordinates (display:none or elements not appended return false).
19224      * @param {Number} x X value for new position (coordinates are page-based)
19225      * @param {Number} y Y value for new position (coordinates are page-based)
19226      * @param {Boolean/Object} animate (optional) True for the default animation, or a standard Element animation config object
19227      * @return {Ext.core.Element} this
19228      */
19229     moveTo : function(x, y, animate){
19230         return this.setXY([x, y], animate);
19231     },
19232
19233     /**
19234      * Gets the left X coordinate
19235      * @param {Boolean} local True to get the local css position instead of page coordinate
19236      * @return {Number}
19237      */
19238     getLeft : function(local){
19239         return !local ? this.getX() : parseInt(this.getStyle(LEFT), 10) || 0;
19240     },
19241
19242     /**
19243      * Gets the right X coordinate of the element (element X position + element width)
19244      * @param {Boolean} local True to get the local css position instead of page coordinate
19245      * @return {Number}
19246      */
19247     getRight : function(local){
19248         var me = this;
19249         return !local ? me.getX() + me.getWidth() : (me.getLeft(true) + me.getWidth()) || 0;
19250     },
19251
19252     /**
19253      * Gets the top Y coordinate
19254      * @param {Boolean} local True to get the local css position instead of page coordinate
19255      * @return {Number}
19256      */
19257     getTop : function(local) {
19258         return !local ? this.getY() : parseInt(this.getStyle(TOP), 10) || 0;
19259     },
19260
19261     /**
19262      * Gets the bottom Y coordinate of the element (element Y position + element height)
19263      * @param {Boolean} local True to get the local css position instead of page coordinate
19264      * @return {Number}
19265      */
19266     getBottom : function(local){
19267         var me = this;
19268         return !local ? me.getY() + me.getHeight() : (me.getTop(true) + me.getHeight()) || 0;
19269     },
19270
19271     /**
19272     * Initializes positioning on this element. If a desired position is not passed, it will make the
19273     * the element positioned relative IF it is not already positioned.
19274     * @param {String} pos (optional) Positioning to use "relative", "absolute" or "fixed"
19275     * @param {Number} zIndex (optional) The zIndex to apply
19276     * @param {Number} x (optional) Set the page X position
19277     * @param {Number} y (optional) Set the page Y position
19278     */
19279     position : function(pos, zIndex, x, y) {
19280         var me = this;
19281
19282         if (!pos && me.isStyle(POSITION, STATIC)){
19283             me.setStyle(POSITION, RELATIVE);
19284         } else if(pos) {
19285             me.setStyle(POSITION, pos);
19286         }
19287         if (zIndex){
19288             me.setStyle(ZINDEX, zIndex);
19289         }
19290         if (x || y) {
19291             me.setXY([x || false, y || false]);
19292         }
19293     },
19294
19295     /**
19296     * Clear positioning back to the default when the document was loaded
19297     * @param {String} value (optional) The value to use for the left,right,top,bottom, defaults to '' (empty string). You could use 'auto'.
19298     * @return {Ext.core.Element} this
19299      */
19300     clearPositioning : function(value){
19301         value = value || '';
19302         this.setStyle({
19303             left : value,
19304             right : value,
19305             top : value,
19306             bottom : value,
19307             "z-index" : "",
19308             position : STATIC
19309         });
19310         return this;
19311     },
19312
19313     /**
19314     * Gets an object with all CSS positioning properties. Useful along with setPostioning to get
19315     * snapshot before performing an update and then restoring the element.
19316     * @return {Object}
19317     */
19318     getPositioning : function(){
19319         var l = this.getStyle(LEFT);
19320         var t = this.getStyle(TOP);
19321         return {
19322             "position" : this.getStyle(POSITION),
19323             "left" : l,
19324             "right" : l ? "" : this.getStyle(RIGHT),
19325             "top" : t,
19326             "bottom" : t ? "" : this.getStyle(BOTTOM),
19327             "z-index" : this.getStyle(ZINDEX)
19328         };
19329     },
19330
19331     /**
19332     * Set positioning with an object returned by getPositioning().
19333     * @param {Object} posCfg
19334     * @return {Ext.core.Element} this
19335      */
19336     setPositioning : function(pc){
19337         var me = this,
19338             style = me.dom.style;
19339
19340         me.setStyle(pc);
19341
19342         if(pc.right == AUTO){
19343             style.right = "";
19344         }
19345         if(pc.bottom == AUTO){
19346             style.bottom = "";
19347         }
19348
19349         return me;
19350     },
19351
19352     /**
19353      * Translates the passed page coordinates into left/top css values for this element
19354      * @param {Number/Array} x The page x or an array containing [x, y]
19355      * @param {Number} y (optional) The page y, required if x is not an array
19356      * @return {Object} An object with left and top properties. e.g. {left: (value), top: (value)}
19357      */
19358     translatePoints: function(x, y) {
19359         if (Ext.isArray(x)) {
19360              y = x[1];
19361              x = x[0];
19362         }
19363         var me = this,
19364             relative = me.isStyle(POSITION, RELATIVE),
19365             o = me.getXY(),
19366             left = parseInt(me.getStyle(LEFT), 10),
19367             top = parseInt(me.getStyle(TOP), 10);
19368
19369         if (!Ext.isNumber(left)) {
19370             left = relative ? 0 : me.dom.offsetLeft;
19371         }
19372         if (!Ext.isNumber(top)) {
19373             top = relative ? 0 : me.dom.offsetTop;
19374         }
19375         left = (Ext.isNumber(x)) ? x - o[0] + left : undefined;
19376         top = (Ext.isNumber(y)) ? y - o[1] + top : undefined;
19377         return {
19378             left: left,
19379             top: top
19380         };
19381     },
19382
19383     /**
19384      * 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.
19385      * @param {Object} box The box to fill {x, y, width, height}
19386      * @param {Boolean} adjust (optional) Whether to adjust for box-model issues automatically
19387      * @param {Boolean/Object} animate (optional) true for the default animation or a standard Element animation config object
19388      * @return {Ext.core.Element} this
19389      */
19390     setBox: function(box, adjust, animate) {
19391         var me = this,
19392             w = box.width,
19393             h = box.height;
19394         if ((adjust && !me.autoBoxAdjust) && !me.isBorderBox()) {
19395             w -= (me.getBorderWidth("lr") + me.getPadding("lr"));
19396             h -= (me.getBorderWidth("tb") + me.getPadding("tb"));
19397         }
19398         me.setBounds(box.x, box.y, w, h, animate);
19399         return me;
19400     },
19401
19402     /**
19403      * Return an object defining the area of this Element which can be passed to {@link #setBox} to
19404      * set another Element's size/location to match this element.
19405      * @param {Boolean} contentBox (optional) If true a box for the content of the element is returned.
19406      * @param {Boolean} local (optional) If true the element's left and top are returned instead of page x/y.
19407      * @return {Object} box An object in the format<pre><code>
19408 {
19409     x: &lt;Element's X position>,
19410     y: &lt;Element's Y position>,
19411     width: &lt;Element's width>,
19412     height: &lt;Element's height>,
19413     bottom: &lt;Element's lower bound>,
19414     right: &lt;Element's rightmost bound>
19415 }
19416 </code></pre>
19417      * The returned object may also be addressed as an Array where index 0 contains the X position
19418      * and index 1 contains the Y position. So the result may also be used for {@link #setXY}
19419      */
19420     getBox: function(contentBox, local) {
19421         var me = this,
19422             xy,
19423             left,
19424             top,
19425             getBorderWidth = me.getBorderWidth,
19426             getPadding = me.getPadding,
19427             l, r, t, b, w, h, bx;
19428         if (!local) {
19429             xy = me.getXY();
19430         } else {
19431             left = parseInt(me.getStyle("left"), 10) || 0;
19432             top = parseInt(me.getStyle("top"), 10) || 0;
19433             xy = [left, top];
19434         }
19435         w = me.getWidth();
19436         h = me.getHeight();
19437         if (!contentBox) {
19438             bx = {
19439                 x: xy[0],
19440                 y: xy[1],
19441                 0: xy[0],
19442                 1: xy[1],
19443                 width: w,
19444                 height: h
19445             };
19446         } else {
19447             l = getBorderWidth.call(me, "l") + getPadding.call(me, "l");
19448             r = getBorderWidth.call(me, "r") + getPadding.call(me, "r");
19449             t = getBorderWidth.call(me, "t") + getPadding.call(me, "t");
19450             b = getBorderWidth.call(me, "b") + getPadding.call(me, "b");
19451             bx = {
19452                 x: xy[0] + l,
19453                 y: xy[1] + t,
19454                 0: xy[0] + l,
19455                 1: xy[1] + t,
19456                 width: w - (l + r),
19457                 height: h - (t + b)
19458             };
19459         }
19460         bx.right = bx.x + bx.width;
19461         bx.bottom = bx.y + bx.height;
19462         return bx;
19463     },
19464
19465     /**
19466      * Move this element relative to its current position.
19467      * @param {String} direction Possible values are: "l" (or "left"), "r" (or "right"), "t" (or "top", or "up"), "b" (or "bottom", or "down").
19468      * @param {Number} distance How far to move the element in pixels
19469      * @param {Boolean/Object} animate (optional) true for the default animation or a standard Element animation config object
19470      * @return {Ext.core.Element} this
19471      */
19472     move: function(direction, distance, animate) {
19473         var me = this,
19474             xy = me.getXY(),
19475             x = xy[0],
19476             y = xy[1],
19477             left = [x - distance, y],
19478             right = [x + distance, y],
19479             top = [x, y - distance],
19480             bottom = [x, y + distance],
19481             hash = {
19482                 l: left,
19483                 left: left,
19484                 r: right,
19485                 right: right,
19486                 t: top,
19487                 top: top,
19488                 up: top,
19489                 b: bottom,
19490                 bottom: bottom,
19491                 down: bottom
19492             };
19493
19494         direction = direction.toLowerCase();
19495         me.moveTo(hash[direction][0], hash[direction][1], animate);
19496     },
19497
19498     /**
19499      * Quick set left and top adding default units
19500      * @param {String} left The left CSS property value
19501      * @param {String} top The top CSS property value
19502      * @return {Ext.core.Element} this
19503      */
19504     setLeftTop: function(left, top) {
19505         var me = this,
19506             style = me.dom.style;
19507         style.left = me.addUnits(left);
19508         style.top = me.addUnits(top);
19509         return me;
19510     },
19511
19512     /**
19513      * Returns the region of this element.
19514      * The element must be part of the DOM tree to have a region (display:none or elements not appended return false).
19515      * @return {Region} A Ext.util.Region containing "top, left, bottom, right" member data.
19516      */
19517     getRegion: function() {
19518         return this.getPageBox(true);
19519     },
19520
19521     /**
19522      * Returns the <b>content</b> region of this element. That is the region within the borders and padding.
19523      * @return {Region} A Ext.util.Region containing "top, left, bottom, right" member data.
19524      */
19525     getViewRegion: function() {
19526         var me = this,
19527             isBody = me.dom === document.body,
19528             scroll, pos, top, left, width, height;
19529             
19530         // For the body we want to do some special logic
19531         if (isBody) {
19532             scroll = me.getScroll();
19533             left = scroll.left;
19534             top = scroll.top;
19535             width = Ext.core.Element.getViewportWidth();
19536             height = Ext.core.Element.getViewportHeight();
19537         }
19538         else {
19539             pos = me.getXY();
19540             left = pos[0] + me.getBorderWidth('l') + me.getPadding('l');
19541             top = pos[1] + me.getBorderWidth('t') + me.getPadding('t');
19542             width = me.getWidth(true);
19543             height = me.getHeight(true);
19544         }
19545
19546         return Ext.create('Ext.util.Region', top, left + width, top + height, left);
19547     },
19548
19549     /**
19550      * Return an object defining the area of this Element which can be passed to {@link #setBox} to
19551      * set another Element's size/location to match this element.
19552      * @param {Boolean} asRegion(optional) If true an Ext.util.Region will be returned
19553      * @return {Object} box An object in the format<pre><code>
19554 {
19555     x: &lt;Element's X position>,
19556     y: &lt;Element's Y position>,
19557     width: &lt;Element's width>,
19558     height: &lt;Element's height>,
19559     bottom: &lt;Element's lower bound>,
19560     right: &lt;Element's rightmost bound>
19561 }
19562 </code></pre>
19563      * The returned object may also be addressed as an Array where index 0 contains the X position
19564      * and index 1 contains the Y position. So the result may also be used for {@link #setXY}
19565      */
19566     getPageBox : function(getRegion) {
19567         var me = this,
19568             el = me.dom,
19569             isDoc = el === document.body,
19570             w = isDoc ? Ext.core.Element.getViewWidth()  : el.offsetWidth,
19571             h = isDoc ? Ext.core.Element.getViewHeight() : el.offsetHeight,
19572             xy = me.getXY(),
19573             t = xy[1],
19574             r = xy[0] + w,
19575             b = xy[1] + h,
19576             l = xy[0];
19577
19578         if (getRegion) {
19579             return Ext.create('Ext.util.Region', t, r, b, l);
19580         }
19581         else {
19582             return {
19583                 left: l,
19584                 top: t,
19585                 width: w,
19586                 height: h,
19587                 right: r,
19588                 bottom: b
19589             };
19590         }
19591     },
19592
19593     /**
19594      * Sets the element's position and size in one shot. If animation is true then width, height, x and y will be animated concurrently.
19595      * @param {Number} x X value for new position (coordinates are page-based)
19596      * @param {Number} y Y value for new position (coordinates are page-based)
19597      * @param {Mixed} width The new width. This may be one of:<div class="mdetail-params"><ul>
19598      * <li>A Number specifying the new width in this Element's {@link #defaultUnit}s (by default, pixels)</li>
19599      * <li>A String used to set the CSS width style. Animation may <b>not</b> be used.
19600      * </ul></div>
19601      * @param {Mixed} height The new height. This may be one of:<div class="mdetail-params"><ul>
19602      * <li>A Number specifying the new height in this Element's {@link #defaultUnit}s (by default, pixels)</li>
19603      * <li>A String used to set the CSS height style. Animation may <b>not</b> be used.</li>
19604      * </ul></div>
19605      * @param {Boolean/Object} animate (optional) true for the default animation or a standard Element animation config object
19606      * @return {Ext.core.Element} this
19607      */
19608     setBounds: function(x, y, width, height, animate) {
19609         var me = this;
19610         if (!animate || !me.anim) {
19611             me.setSize(width, height);
19612             me.setLocation(x, y);
19613         } else {
19614             if (!Ext.isObject(animate)) {
19615                 animate = {};
19616             }
19617             me.animate(Ext.applyIf({
19618                 to: {
19619                     x: x,
19620                     y: y,
19621                     width: me.adjustWidth(width),
19622                     height: me.adjustHeight(height)
19623                 }
19624             }, animate));
19625         }
19626         return me;
19627     },
19628
19629     /**
19630      * Sets the element's position and size the specified region. If animation is true then width, height, x and y will be animated concurrently.
19631      * @param {Ext.util.Region} region The region to fill
19632      * @param {Boolean/Object} animate (optional) true for the default animation or a standard Element animation config object
19633      * @return {Ext.core.Element} this
19634      */
19635     setRegion: function(region, animate) {
19636         return this.setBounds(region.left, region.top, region.right - region.left, region.bottom - region.top, animate);
19637     }
19638 });
19639 })();
19640
19641 /**
19642  * @class Ext.core.Element
19643  */
19644 Ext.override(Ext.core.Element, {
19645     /**
19646      * Returns true if this element is scrollable.
19647      * @return {Boolean}
19648      */
19649     isScrollable : function(){
19650         var dom = this.dom;
19651         return dom.scrollHeight > dom.clientHeight || dom.scrollWidth > dom.clientWidth;
19652     },
19653
19654     /**
19655      * Returns the current scroll position of the element.
19656      * @return {Object} An object containing the scroll position in the format {left: (scrollLeft), top: (scrollTop)}
19657      */
19658     getScroll : function() {
19659         var d = this.dom, 
19660             doc = document,
19661             body = doc.body,
19662             docElement = doc.documentElement,
19663             l,
19664             t,
19665             ret;
19666
19667         if (d == doc || d == body) {
19668             if (Ext.isIE && Ext.isStrict) {
19669                 l = docElement.scrollLeft; 
19670                 t = docElement.scrollTop;
19671             } else {
19672                 l = window.pageXOffset;
19673                 t = window.pageYOffset;
19674             }
19675             ret = {
19676                 left: l || (body ? body.scrollLeft : 0), 
19677                 top : t || (body ? body.scrollTop : 0)
19678             };
19679         } else {
19680             ret = {
19681                 left: d.scrollLeft, 
19682                 top : d.scrollTop
19683             };
19684         }
19685         
19686         return ret;
19687     },
19688     
19689     /**
19690      * 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().
19691      * @param {String} side Either "left" for scrollLeft values or "top" for scrollTop values.
19692      * @param {Number} value The new scroll value
19693      * @param {Boolean/Object} animate (optional) true for the default animation or a standard Element animation config object
19694      * @return {Element} this
19695      */
19696     scrollTo : function(side, value, animate) {
19697         //check if we're scrolling top or left
19698         var top = /top/i.test(side),
19699             me = this,
19700             dom = me.dom,
19701             obj = {},
19702             prop;
19703         if (!animate || !me.anim) {
19704             // just setting the value, so grab the direction
19705             prop = 'scroll' + (top ? 'Top' : 'Left');
19706             dom[prop] = value;
19707         }
19708         else {
19709             if (!Ext.isObject(animate)) {
19710                 animate = {};
19711             }
19712             obj['scroll' + (top ? 'Top' : 'Left')] = value;
19713             me.animate(Ext.applyIf({
19714                 to: obj
19715             }, animate));
19716         }
19717         return me;
19718     },
19719
19720     /**
19721      * Scrolls this element into view within the passed container.
19722      * @param {Mixed} container (optional) The container element to scroll (defaults to document.body).  Should be a
19723      * string (id), dom node, or Ext.core.Element.
19724      * @param {Boolean} hscroll (optional) False to disable horizontal scroll (defaults to true)
19725      * @return {Ext.core.Element} this
19726      */
19727     scrollIntoView : function(container, hscroll) {
19728         container = Ext.getDom(container) || Ext.getBody().dom;
19729         var el = this.dom,
19730             offsets = this.getOffsetsTo(container),
19731             // el's box
19732             left = offsets[0] + container.scrollLeft,
19733             top = offsets[1] + container.scrollTop,
19734             bottom = top + el.offsetHeight,
19735             right = left + el.offsetWidth,
19736             // ct's box
19737             ctClientHeight = container.clientHeight,
19738             ctScrollTop = parseInt(container.scrollTop, 10),
19739             ctScrollLeft = parseInt(container.scrollLeft, 10),
19740             ctBottom = ctScrollTop + ctClientHeight,
19741             ctRight = ctScrollLeft + container.clientWidth;
19742
19743         if (el.offsetHeight > ctClientHeight || top < ctScrollTop) {
19744             container.scrollTop = top;
19745         } else if (bottom > ctBottom) {
19746             container.scrollTop = bottom - ctClientHeight;
19747         }
19748         // corrects IE, other browsers will ignore
19749         container.scrollTop = container.scrollTop;
19750
19751         if (hscroll !== false) {
19752             if (el.offsetWidth > container.clientWidth || left < ctScrollLeft) {
19753                 container.scrollLeft = left;
19754             }
19755             else if (right > ctRight) {
19756                 container.scrollLeft = right - container.clientWidth;
19757             }
19758             container.scrollLeft = container.scrollLeft;
19759         }
19760         return this;
19761     },
19762
19763     // private
19764     scrollChildIntoView : function(child, hscroll) {
19765         Ext.fly(child, '_scrollChildIntoView').scrollIntoView(this, hscroll);
19766     },
19767
19768     /**
19769      * Scrolls this element the specified direction. Does bounds checking to make sure the scroll is
19770      * within this element's scrollable range.
19771      * @param {String} direction Possible values are: "l" (or "left"), "r" (or "right"), "t" (or "top", or "up"), "b" (or "bottom", or "down").
19772      * @param {Number} distance How far to scroll the element in pixels
19773      * @param {Boolean/Object} animate (optional) true for the default animation or a standard Element animation config object
19774      * @return {Boolean} Returns true if a scroll was triggered or false if the element
19775      * was scrolled as far as it could go.
19776      */
19777      scroll : function(direction, distance, animate) {
19778         if (!this.isScrollable()) {
19779             return false;
19780         }
19781         var el = this.dom,
19782             l = el.scrollLeft, t = el.scrollTop,
19783             w = el.scrollWidth, h = el.scrollHeight,
19784             cw = el.clientWidth, ch = el.clientHeight,
19785             scrolled = false, v,
19786             hash = {
19787                 l: Math.min(l + distance, w-cw),
19788                 r: v = Math.max(l - distance, 0),
19789                 t: Math.max(t - distance, 0),
19790                 b: Math.min(t + distance, h-ch)
19791             };
19792             hash.d = hash.b;
19793             hash.u = hash.t;
19794
19795         direction = direction.substr(0, 1);
19796         if ((v = hash[direction]) > -1) {
19797             scrolled = true;
19798             this.scrollTo(direction == 'l' || direction == 'r' ? 'left' : 'top', v, this.anim(animate));
19799         }
19800         return scrolled;
19801     }
19802 });
19803 /**
19804  * @class Ext.core.Element
19805  */
19806 Ext.core.Element.addMethods(
19807     function() {
19808         var VISIBILITY      = "visibility",
19809             DISPLAY         = "display",
19810             HIDDEN          = "hidden",
19811             NONE            = "none",
19812             XMASKED         = Ext.baseCSSPrefix + "masked",
19813             XMASKEDRELATIVE = Ext.baseCSSPrefix + "masked-relative",
19814             data            = Ext.core.Element.data;
19815
19816         return {
19817             /**
19818              * Checks whether the element is currently visible using both visibility and display properties.
19819              * @param {Boolean} deep (optional) True to walk the dom and see if parent elements are hidden (defaults to false)
19820              * @return {Boolean} True if the element is currently visible, else false
19821              */
19822             isVisible : function(deep) {
19823                 var vis = !this.isStyle(VISIBILITY, HIDDEN) && !this.isStyle(DISPLAY, NONE),
19824                     p   = this.dom.parentNode;
19825
19826                 if (deep !== true || !vis) {
19827                     return vis;
19828                 }
19829
19830                 while (p && !(/^body/i.test(p.tagName))) {
19831                     if (!Ext.fly(p, '_isVisible').isVisible()) {
19832                         return false;
19833                     }
19834                     p = p.parentNode;
19835                 }
19836                 return true;
19837             },
19838
19839             /**
19840              * Returns true if display is not "none"
19841              * @return {Boolean}
19842              */
19843             isDisplayed : function() {
19844                 return !this.isStyle(DISPLAY, NONE);
19845             },
19846
19847             /**
19848              * Convenience method for setVisibilityMode(Element.DISPLAY)
19849              * @param {String} display (optional) What to set display to when visible
19850              * @return {Ext.core.Element} this
19851              */
19852             enableDisplayMode : function(display) {
19853                 this.setVisibilityMode(Ext.core.Element.DISPLAY);
19854
19855                 if (!Ext.isEmpty(display)) {
19856                     data(this.dom, 'originalDisplay', display);
19857                 }
19858
19859                 return this;
19860             },
19861
19862             /**
19863              * Puts a mask over this element to disable user interaction. Requires core.css.
19864              * This method can only be applied to elements which accept child nodes.
19865              * @param {String} msg (optional) A message to display in the mask
19866              * @param {String} msgCls (optional) A css class to apply to the msg element
19867              * @return {Element} The mask element
19868              */
19869             mask : function(msg, msgCls) {
19870                 var me  = this,
19871                     dom = me.dom,
19872                     setExpression = dom.style.setExpression,
19873                     dh  = Ext.core.DomHelper,
19874                     EXTELMASKMSG = Ext.baseCSSPrefix + "mask-msg",
19875                     el,
19876                     mask;
19877
19878                 if (!(/^body/i.test(dom.tagName) && me.getStyle('position') == 'static')) {
19879                     me.addCls(XMASKEDRELATIVE);
19880                 }
19881                 el = data(dom, 'maskMsg');
19882                 if (el) {
19883                     el.remove();
19884                 }
19885                 el = data(dom, 'mask');
19886                 if (el) {
19887                     el.remove();
19888                 }
19889
19890                 mask = dh.append(dom, {cls : Ext.baseCSSPrefix + "mask"}, true);
19891                 data(dom, 'mask', mask);
19892
19893                 me.addCls(XMASKED);
19894                 mask.setDisplayed(true);
19895
19896                 if (typeof msg == 'string') {
19897                     var mm = dh.append(dom, {cls : EXTELMASKMSG, cn:{tag:'div'}}, true);
19898                     data(dom, 'maskMsg', mm);
19899                     mm.dom.className = msgCls ? EXTELMASKMSG + " " + msgCls : EXTELMASKMSG;
19900                     mm.dom.firstChild.innerHTML = msg;
19901                     mm.setDisplayed(true);
19902                     mm.center(me);
19903                 }
19904                 // NOTE: CSS expressions are resource intensive and to be used only as a last resort
19905                 // These expressions are removed as soon as they are no longer necessary - in the unmask method.
19906                 // In normal use cases an element will be masked for a limited period of time.
19907                 // Fix for https://sencha.jira.com/browse/EXTJSIV-19.
19908                 // IE6 strict mode and IE6-9 quirks mode takes off left+right padding when calculating width!
19909                 if (!Ext.supports.IncludePaddingInWidthCalculation && setExpression) {
19910                     mask.dom.style.setExpression('width', 'this.parentNode.offsetWidth + "px"');
19911                 }
19912
19913                 // Some versions and modes of IE subtract top+bottom padding when calculating height.
19914                 // Different versions from those which make the same error for width!
19915                 if (!Ext.supports.IncludePaddingInHeightCalculation && setExpression) {
19916                     mask.dom.style.setExpression('height', 'this.parentNode.offsetHeight + "px"');
19917                 }
19918                 // ie will not expand full height automatically
19919                 else if (Ext.isIE && !(Ext.isIE7 && Ext.isStrict) && me.getStyle('height') == 'auto') {
19920                     mask.setSize(undefined, me.getHeight());
19921                 }
19922                 return mask;
19923             },
19924
19925             /**
19926              * Removes a previously applied mask.
19927              */
19928             unmask : function() {
19929                 var me      = this,
19930                     dom     = me.dom,
19931                     mask    = data(dom, 'mask'),
19932                     maskMsg = data(dom, 'maskMsg');
19933
19934                 if (mask) {
19935                     // Remove resource-intensive CSS expressions as soon as they are not required.
19936                     if (mask.dom.style.clearExpression) {
19937                         mask.dom.style.clearExpression('width');
19938                         mask.dom.style.clearExpression('height');
19939                     }
19940                     if (maskMsg) {
19941                         maskMsg.remove();
19942                         data(dom, 'maskMsg', undefined);
19943                     }
19944
19945                     mask.remove();
19946                     data(dom, 'mask', undefined);
19947                     me.removeCls([XMASKED, XMASKEDRELATIVE]);
19948                 }
19949             },
19950             /**
19951              * Returns true if this element is masked. Also re-centers any displayed message within the mask.
19952              * @return {Boolean}
19953              */
19954             isMasked : function() {
19955                 var me = this,
19956                     mask = data(me.dom, 'mask'),
19957                     maskMsg = data(me.dom, 'maskMsg');
19958
19959                 if (mask && mask.isVisible()) {
19960                     if (maskMsg) {
19961                         maskMsg.center(me);
19962                     }
19963                     return true;
19964                 }
19965                 return false;
19966             },
19967
19968             /**
19969              * Creates an iframe shim for this element to keep selects and other windowed objects from
19970              * showing through.
19971              * @return {Ext.core.Element} The new shim element
19972              */
19973             createShim : function() {
19974                 var el = document.createElement('iframe'),
19975                     shim;
19976
19977                 el.frameBorder = '0';
19978                 el.className = Ext.baseCSSPrefix + 'shim';
19979                 el.src = Ext.SSL_SECURE_URL;
19980                 shim = Ext.get(this.dom.parentNode.insertBefore(el, this.dom));
19981                 shim.autoBoxAdjust = false;
19982                 return shim;
19983             }
19984         };
19985     }()
19986 );
19987 /**
19988  * @class Ext.core.Element
19989  */
19990 Ext.core.Element.addMethods({
19991     /**
19992      * Convenience method for constructing a KeyMap
19993      * @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:
19994      * <code>{key: (number or array), shift: (true/false), ctrl: (true/false), alt: (true/false)}</code>
19995      * @param {Function} fn The function to call
19996      * @param {Object} scope (optional) The scope (<code>this</code> reference) in which the specified function is executed. Defaults to this Element.
19997      * @return {Ext.util.KeyMap} The KeyMap created
19998      */
19999     addKeyListener : function(key, fn, scope){
20000         var config;
20001         if(typeof key != 'object' || Ext.isArray(key)){
20002             config = {
20003                 key: key,
20004                 fn: fn,
20005                 scope: scope
20006             };
20007         }else{
20008             config = {
20009                 key : key.key,
20010                 shift : key.shift,
20011                 ctrl : key.ctrl,
20012                 alt : key.alt,
20013                 fn: fn,
20014                 scope: scope
20015             };
20016         }
20017         return Ext.create('Ext.util.KeyMap', this, config);
20018     },
20019
20020     /**
20021      * Creates a KeyMap for this element
20022      * @param {Object} config The KeyMap config. See {@link Ext.util.KeyMap} for more details
20023      * @return {Ext.util.KeyMap} The KeyMap created
20024      */
20025     addKeyMap : function(config){
20026         return Ext.create('Ext.util.KeyMap', this, config);
20027     }
20028 });
20029
20030 //Import the newly-added Ext.core.Element functions into CompositeElementLite. We call this here because
20031 //Element.keys.js is the last extra Ext.core.Element include in the ext-all.js build
20032 Ext.CompositeElementLite.importElementMethods();
20033
20034 /**
20035  * @class Ext.CompositeElementLite
20036  */
20037 Ext.apply(Ext.CompositeElementLite.prototype, {
20038     addElements : function(els, root){
20039         if(!els){
20040             return this;
20041         }
20042         if(typeof els == "string"){
20043             els = Ext.core.Element.selectorFunction(els, root);
20044         }
20045         var yels = this.elements;
20046         Ext.each(els, function(e) {
20047             yels.push(Ext.get(e));
20048         });
20049         return this;
20050     },
20051
20052     /**
20053      * Returns the first Element
20054      * @return {Ext.core.Element}
20055      */
20056     first : function(){
20057         return this.item(0);
20058     },
20059
20060     /**
20061      * Returns the last Element
20062      * @return {Ext.core.Element}
20063      */
20064     last : function(){
20065         return this.item(this.getCount()-1);
20066     },
20067
20068     /**
20069      * Returns true if this composite contains the passed element
20070      * @param el {Mixed} The id of an element, or an Ext.core.Element, or an HtmlElement to find within the composite collection.
20071      * @return Boolean
20072      */
20073     contains : function(el){
20074         return this.indexOf(el) != -1;
20075     },
20076
20077     /**
20078     * Removes the specified element(s).
20079     * @param {Mixed} el The id of an element, the Element itself, the index of the element in this composite
20080     * or an array of any of those.
20081     * @param {Boolean} removeDom (optional) True to also remove the element from the document
20082     * @return {CompositeElement} this
20083     */
20084     removeElement : function(keys, removeDom){
20085         var me = this,
20086             els = this.elements,
20087             el;
20088         Ext.each(keys, function(val){
20089             if ((el = (els[val] || els[val = me.indexOf(val)]))) {
20090                 if(removeDom){
20091                     if(el.dom){
20092                         el.remove();
20093                     }else{
20094                         Ext.removeNode(el);
20095                     }
20096                 }
20097                 Ext.Array.erase(els, val, 1);
20098             }
20099         });
20100         return this;
20101     }
20102 });
20103
20104 /**
20105  * @class Ext.CompositeElement
20106  * @extends Ext.CompositeElementLite
20107  * <p>This class encapsulates a <i>collection</i> of DOM elements, providing methods to filter
20108  * members, or to perform collective actions upon the whole set.</p>
20109  * <p>Although they are not listed, this class supports all of the methods of {@link Ext.core.Element} and
20110  * {@link Ext.fx.Anim}. The methods from these classes will be performed on all the elements in this collection.</p>
20111  * <p>All methods return <i>this</i> and can be chained.</p>
20112  * Usage:
20113 <pre><code>
20114 var els = Ext.select("#some-el div.some-class", true);
20115 // or select directly from an existing element
20116 var el = Ext.get('some-el');
20117 el.select('div.some-class', true);
20118
20119 els.setWidth(100); // all elements become 100 width
20120 els.hide(true); // all elements fade out and hide
20121 // or
20122 els.setWidth(100).hide(true);
20123 </code></pre>
20124  */
20125 Ext.CompositeElement = Ext.extend(Ext.CompositeElementLite, {
20126     
20127     constructor : function(els, root){
20128         this.elements = [];
20129         this.add(els, root);
20130     },
20131     
20132     // private
20133     getElement : function(el){
20134         // In this case just return it, since we already have a reference to it
20135         return el;
20136     },
20137     
20138     // private
20139     transformElement : function(el){
20140         return Ext.get(el);
20141     }
20142
20143     /**
20144     * Adds elements to this composite.
20145     * @param {String/Array} els A string CSS selector, an array of elements or an element
20146     * @return {CompositeElement} this
20147     */
20148
20149     /**
20150      * Returns the Element object at the specified index
20151      * @param {Number} index
20152      * @return {Ext.core.Element}
20153      */
20154
20155     /**
20156      * Iterates each `element` in this `composite` calling the supplied function using {@link Ext#each Ext.each}.
20157      * @param {Function} fn 
20158
20159 The function to be called with each
20160 `element`. If the supplied function returns <tt>false</tt>,
20161 iteration stops. This function is called with the following arguments:
20162
20163 - `element` : __Ext.core.Element++
20164     The element at the current `index` in the `composite`
20165     
20166 - `composite` : __Object__ 
20167     This composite.
20168
20169 - `index` : __Number__ 
20170     The current index within the `composite`
20171
20172      * @param {Object} scope (optional) The scope (<code>this</code> reference) in which the specified function is executed.
20173      * Defaults to the <code>element</code> at the current <code>index</code>
20174      * within the composite.
20175      * @return {CompositeElement} this
20176      * @markdown
20177      */
20178 });
20179
20180 /**
20181  * Selects elements based on the passed CSS selector to enable {@link Ext.core.Element Element} methods
20182  * to be applied to many related elements in one statement through the returned {@link Ext.CompositeElement CompositeElement} or
20183  * {@link Ext.CompositeElementLite CompositeElementLite} object.
20184  * @param {String/Array} selector The CSS selector or an array of elements
20185  * @param {Boolean} unique (optional) true to create a unique Ext.core.Element for each element (defaults to a shared flyweight object)
20186  * @param {HTMLElement/String} root (optional) The root element of the query or id of the root
20187  * @return {CompositeElementLite/CompositeElement}
20188  * @member Ext.core.Element
20189  * @method select
20190  */
20191 Ext.core.Element.select = function(selector, unique, root){
20192     var els;
20193     if(typeof selector == "string"){
20194         els = Ext.core.Element.selectorFunction(selector, root);
20195     }else if(selector.length !== undefined){
20196         els = selector;
20197     }else{
20198     }
20199     return (unique === true) ? new Ext.CompositeElement(els) : new Ext.CompositeElementLite(els);
20200 };
20201
20202 /**
20203  * Selects elements based on the passed CSS selector to enable {@link Ext.core.Element Element} methods
20204  * to be applied to many related elements in one statement through the returned {@link Ext.CompositeElement CompositeElement} or
20205  * {@link Ext.CompositeElementLite CompositeElementLite} object.
20206  * @param {String/Array} selector The CSS selector or an array of elements
20207  * @param {Boolean} unique (optional) true to create a unique Ext.core.Element for each element (defaults to a shared flyweight object)
20208  * @param {HTMLElement/String} root (optional) The root element of the query or id of the root
20209  * @return {CompositeElementLite/CompositeElement}
20210  * @member Ext
20211  * @method select
20212  */
20213 Ext.select = Ext.core.Element.select;
20214
20215
20216