/ext-4.0.7/builds/ext-foundation-dev.js
JavaScript | 8848 lines | 5299 code | 741 blank | 2808 comment | 557 complexity | 1d768b28a5617b02c3abcaf2ee7d8efa MD5 | raw file
Large files files are truncated, but you can click here to view the full file
1/*
2
3This file is part of Ext JS 4
4
5Copyright (c) 2011 Sencha Inc
6
7Contact: http://www.sencha.com/contact
8
9GNU General Public License Usage
10This 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
12If you are unsure which license is appropriate for your use, please contact the sales department at http://www.sencha.com/contact.
13
14*/
15/**
16 * @class Ext
17 * @singleton
18 */
19(function() {
20 var global = this,
21 objectPrototype = Object.prototype,
22 toString = objectPrototype.toString,
23 enumerables = true,
24 enumerablesTest = { toString: 1 },
25 i;
26
27 if (typeof Ext === 'undefined') {
28 global.Ext = {};
29 }
30
31 Ext.global = global;
32
33 for (i in enumerablesTest) {
34 enumerables = null;
35 }
36
37 if (enumerables) {
38 enumerables = ['hasOwnProperty', 'valueOf', 'isPrototypeOf', 'propertyIsEnumerable',
39 'toLocaleString', 'toString', 'constructor'];
40 }
41
42 /**
43 * An array containing extra enumerables for old browsers
44 * @property {String[]}
45 */
46 Ext.enumerables = enumerables;
47
48 /**
49 * Copies all the properties of config to the specified object.
50 * Note that if recursive merging and cloning without referencing the original objects / arrays is needed, use
51 * {@link Ext.Object#merge} instead.
52 * @param {Object} object The receiver of the properties
53 * @param {Object} config The source of the properties
54 * @param {Object} defaults A different object that will also be applied for default values
55 * @return {Object} returns obj
56 */
57 Ext.apply = function(object, config, defaults) {
58 if (defaults) {
59 Ext.apply(object, defaults);
60 }
61
62 if (object && config && typeof config === 'object') {
63 var i, j, k;
64
65 for (i in config) {
66 object[i] = config[i];
67 }
68
69 if (enumerables) {
70 for (j = enumerables.length; j--;) {
71 k = enumerables[j];
72 if (config.hasOwnProperty(k)) {
73 object[k] = config[k];
74 }
75 }
76 }
77 }
78
79 return object;
80 };
81
82 Ext.buildSettings = Ext.apply({
83 baseCSSPrefix: 'x-',
84 scopeResetCSS: false
85 }, Ext.buildSettings || {});
86
87 Ext.apply(Ext, {
88 /**
89 * A reusable empty function
90 */
91 emptyFn: function() {},
92
93 baseCSSPrefix: Ext.buildSettings.baseCSSPrefix,
94
95 /**
96 * Copies all the properties of config to object if they don't already exist.
97 * @param {Object} object The receiver of the properties
98 * @param {Object} config The source of the properties
99 * @return {Object} returns obj
100 */
101 applyIf: function(object, config) {
102 var property;
103
104 if (object) {
105 for (property in config) {
106 if (object[property] === undefined) {
107 object[property] = config[property];
108 }
109 }
110 }
111
112 return object;
113 },
114
115 /**
116 * Iterates either an array or an object. This method delegates to
117 * {@link Ext.Array#each Ext.Array.each} if the given value is iterable, and {@link Ext.Object#each Ext.Object.each} otherwise.
118 *
119 * @param {Object/Array} object The object or array to be iterated.
120 * @param {Function} fn The function to be called for each iteration. See and {@link Ext.Array#each Ext.Array.each} and
121 * {@link Ext.Object#each Ext.Object.each} for detailed lists of arguments passed to this function depending on the given object
122 * type that is being iterated.
123 * @param {Object} scope (Optional) The scope (`this` reference) in which the specified function is executed.
124 * Defaults to the object being iterated itself.
125 * @markdown
126 */
127 iterate: function(object, fn, scope) {
128 if (Ext.isEmpty(object)) {
129 return;
130 }
131
132 if (scope === undefined) {
133 scope = object;
134 }
135
136 if (Ext.isIterable(object)) {
137 Ext.Array.each.call(Ext.Array, object, fn, scope);
138 }
139 else {
140 Ext.Object.each.call(Ext.Object, object, fn, scope);
141 }
142 }
143 });
144
145 Ext.apply(Ext, {
146
147 /**
148 * This method deprecated. Use {@link Ext#define Ext.define} instead.
149 * @method
150 * @param {Function} superclass
151 * @param {Object} overrides
152 * @return {Function} The subclass constructor from the <tt>overrides</tt> parameter, or a generated one if not provided.
153 * @deprecated 4.0.0 Use {@link Ext#define Ext.define} instead
154 */
155 extend: function() {
156 // inline overrides
157 var objectConstructor = objectPrototype.constructor,
158 inlineOverrides = function(o) {
159 for (var m in o) {
160 if (!o.hasOwnProperty(m)) {
161 continue;
162 }
163 this[m] = o[m];
164 }
165 };
166
167 return function(subclass, superclass, overrides) {
168 // First we check if the user passed in just the superClass with overrides
169 if (Ext.isObject(superclass)) {
170 overrides = superclass;
171 superclass = subclass;
172 subclass = overrides.constructor !== objectConstructor ? overrides.constructor : function() {
173 superclass.apply(this, arguments);
174 };
175 }
176
177 if (!superclass) {
178 Ext.Error.raise({
179 sourceClass: 'Ext',
180 sourceMethod: 'extend',
181 msg: 'Attempting to extend from a class which has not been loaded on the page.'
182 });
183 }
184
185 // We create a new temporary class
186 var F = function() {},
187 subclassProto, superclassProto = superclass.prototype;
188
189 F.prototype = superclassProto;
190 subclassProto = subclass.prototype = new F();
191 subclassProto.constructor = subclass;
192 subclass.superclass = superclassProto;
193
194 if (superclassProto.constructor === objectConstructor) {
195 superclassProto.constructor = superclass;
196 }
197
198 subclass.override = function(overrides) {
199 Ext.override(subclass, overrides);
200 };
201
202 subclassProto.override = inlineOverrides;
203 subclassProto.proto = subclassProto;
204
205 subclass.override(overrides);
206 subclass.extend = function(o) {
207 return Ext.extend(subclass, o);
208 };
209
210 return subclass;
211 };
212 }(),
213
214 /**
215 * Proxy to {@link Ext.Base#override}. Please refer {@link Ext.Base#override} for further details.
216
217 Ext.define('My.cool.Class', {
218 sayHi: function() {
219 alert('Hi!');
220 }
221 }
222
223 Ext.override(My.cool.Class, {
224 sayHi: function() {
225 alert('About to say...');
226
227 this.callOverridden();
228 }
229 });
230
231 var cool = new My.cool.Class();
232 cool.sayHi(); // alerts 'About to say...'
233 // alerts 'Hi!'
234
235 * Please note that `this.callOverridden()` only works if the class was previously
236 * created with {@link Ext#define)
237 *
238 * @param {Object} cls The class to override
239 * @param {Object} overrides The list of functions to add to origClass. This should be specified as an object literal
240 * containing one or more methods.
241 * @method override
242 * @markdown
243 */
244 override: function(cls, overrides) {
245 if (cls.prototype.$className) {
246 return cls.override(overrides);
247 }
248 else {
249 Ext.apply(cls.prototype, overrides);
250 }
251 }
252 });
253
254 // A full set of static methods to do type checking
255 Ext.apply(Ext, {
256
257 /**
258 * Returns the given value itself if it's not empty, as described in {@link Ext#isEmpty}; returns the default
259 * value (second argument) otherwise.
260 *
261 * @param {Object} value The value to test
262 * @param {Object} defaultValue The value to return if the original value is empty
263 * @param {Boolean} allowBlank (optional) true to allow zero length strings to qualify as non-empty (defaults to false)
264 * @return {Object} value, if non-empty, else defaultValue
265 */
266 valueFrom: function(value, defaultValue, allowBlank){
267 return Ext.isEmpty(value, allowBlank) ? defaultValue : value;
268 },
269
270 /**
271 * Returns the type of the given variable in string format. List of possible values are:
272 *
273 * - `undefined`: If the given value is `undefined`
274 * - `null`: If the given value is `null`
275 * - `string`: If the given value is a string
276 * - `number`: If the given value is a number
277 * - `boolean`: If the given value is a boolean value
278 * - `date`: If the given value is a `Date` object
279 * - `function`: If the given value is a function reference
280 * - `object`: If the given value is an object
281 * - `array`: If the given value is an array
282 * - `regexp`: If the given value is a regular expression
283 * - `element`: If the given value is a DOM Element
284 * - `textnode`: If the given value is a DOM text node and contains something other than whitespace
285 * - `whitespace`: If the given value is a DOM text node and contains only whitespace
286 *
287 * @param {Object} value
288 * @return {String}
289 * @markdown
290 */
291 typeOf: function(value) {
292 if (value === null) {
293 return 'null';
294 }
295
296 var type = typeof value;
297
298 if (type === 'undefined' || type === 'string' || type === 'number' || type === 'boolean') {
299 return type;
300 }
301
302 var typeToString = toString.call(value);
303
304 switch(typeToString) {
305 case '[object Array]':
306 return 'array';
307 case '[object Date]':
308 return 'date';
309 case '[object Boolean]':
310 return 'boolean';
311 case '[object Number]':
312 return 'number';
313 case '[object RegExp]':
314 return 'regexp';
315 }
316
317 if (type === 'function') {
318 return 'function';
319 }
320
321 if (type === 'object') {
322 if (value.nodeType !== undefined) {
323 if (value.nodeType === 3) {
324 return (/\S/).test(value.nodeValue) ? 'textnode' : 'whitespace';
325 }
326 else {
327 return 'element';
328 }
329 }
330
331 return 'object';
332 }
333
334 Ext.Error.raise({
335 sourceClass: 'Ext',
336 sourceMethod: 'typeOf',
337 msg: 'Failed to determine the type of the specified value "' + value + '". This is most likely a bug.'
338 });
339 },
340
341 /**
342 * Returns true if the passed value is empty, false otherwise. The value is deemed to be empty if it is either:
343 *
344 * - `null`
345 * - `undefined`
346 * - a zero-length array
347 * - a zero-length string (Unless the `allowEmptyString` parameter is set to `true`)
348 *
349 * @param {Object} value The value to test
350 * @param {Boolean} allowEmptyString (optional) true to allow empty strings (defaults to false)
351 * @return {Boolean}
352 * @markdown
353 */
354 isEmpty: function(value, allowEmptyString) {
355 return (value === null) || (value === undefined) || (!allowEmptyString ? value === '' : false) || (Ext.isArray(value) && value.length === 0);
356 },
357
358 /**
359 * Returns true if the passed value is a JavaScript Array, false otherwise.
360 *
361 * @param {Object} target The target to test
362 * @return {Boolean}
363 * @method
364 */
365 isArray: ('isArray' in Array) ? Array.isArray : function(value) {
366 return toString.call(value) === '[object Array]';
367 },
368
369 /**
370 * Returns true if the passed value is a JavaScript Date object, false otherwise.
371 * @param {Object} object The object to test
372 * @return {Boolean}
373 */
374 isDate: function(value) {
375 return toString.call(value) === '[object Date]';
376 },
377
378 /**
379 * Returns true if the passed value is a JavaScript Object, false otherwise.
380 * @param {Object} value The value to test
381 * @return {Boolean}
382 * @method
383 */
384 isObject: (toString.call(null) === '[object Object]') ?
385 function(value) {
386 // check ownerDocument here as well to exclude DOM nodes
387 return value !== null && value !== undefined && toString.call(value) === '[object Object]' && value.ownerDocument === undefined;
388 } :
389 function(value) {
390 return toString.call(value) === '[object Object]';
391 },
392
393 /**
394 * Returns true if the passed value is a JavaScript 'primitive', a string, number or boolean.
395 * @param {Object} value The value to test
396 * @return {Boolean}
397 */
398 isPrimitive: function(value) {
399 var type = typeof value;
400
401 return type === 'string' || type === 'number' || type === 'boolean';
402 },
403
404 /**
405 * Returns true if the passed value is a JavaScript Function, false otherwise.
406 * @param {Object} value The value to test
407 * @return {Boolean}
408 * @method
409 */
410 isFunction:
411 // Safari 3.x and 4.x returns 'function' for typeof <NodeList>, hence we need to fall back to using
412 // Object.prorotype.toString (slower)
413 (typeof document !== 'undefined' && typeof document.getElementsByTagName('body') === 'function') ? function(value) {
414 return toString.call(value) === '[object Function]';
415 } : function(value) {
416 return typeof value === 'function';
417 },
418
419 /**
420 * Returns true if the passed value is a number. Returns false for non-finite numbers.
421 * @param {Object} value The value to test
422 * @return {Boolean}
423 */
424 isNumber: function(value) {
425 return typeof value === 'number' && isFinite(value);
426 },
427
428 /**
429 * Validates that a value is numeric.
430 * @param {Object} value Examples: 1, '1', '2.34'
431 * @return {Boolean} True if numeric, false otherwise
432 */
433 isNumeric: function(value) {
434 return !isNaN(parseFloat(value)) && isFinite(value);
435 },
436
437 /**
438 * Returns true if the passed value is a string.
439 * @param {Object} value The value to test
440 * @return {Boolean}
441 */
442 isString: function(value) {
443 return typeof value === 'string';
444 },
445
446 /**
447 * Returns true if the passed value is a boolean.
448 *
449 * @param {Object} value The value to test
450 * @return {Boolean}
451 */
452 isBoolean: function(value) {
453 return typeof value === 'boolean';
454 },
455
456 /**
457 * Returns true if the passed value is an HTMLElement
458 * @param {Object} value The value to test
459 * @return {Boolean}
460 */
461 isElement: function(value) {
462 return value ? value.nodeType === 1 : false;
463 },
464
465 /**
466 * Returns true if the passed value is a TextNode
467 * @param {Object} value The value to test
468 * @return {Boolean}
469 */
470 isTextNode: function(value) {
471 return value ? value.nodeName === "#text" : false;
472 },
473
474 /**
475 * Returns true if the passed value is defined.
476 * @param {Object} value The value to test
477 * @return {Boolean}
478 */
479 isDefined: function(value) {
480 return typeof value !== 'undefined';
481 },
482
483 /**
484 * Returns true if the passed value is iterable, false otherwise
485 * @param {Object} value The value to test
486 * @return {Boolean}
487 */
488 isIterable: function(value) {
489 return (value && typeof value !== 'string') ? value.length !== undefined : false;
490 }
491 });
492
493 Ext.apply(Ext, {
494
495 /**
496 * Clone almost any type of variable including array, object, DOM nodes and Date without keeping the old reference
497 * @param {Object} item The variable to clone
498 * @return {Object} clone
499 */
500 clone: function(item) {
501 if (item === null || item === undefined) {
502 return item;
503 }
504
505 // DOM nodes
506 // TODO proxy this to Ext.Element.clone to handle automatic id attribute changing
507 // recursively
508 if (item.nodeType && item.cloneNode) {
509 return item.cloneNode(true);
510 }
511
512 var type = toString.call(item);
513
514 // Date
515 if (type === '[object Date]') {
516 return new Date(item.getTime());
517 }
518
519 var i, j, k, clone, key;
520
521 // Array
522 if (type === '[object Array]') {
523 i = item.length;
524
525 clone = [];
526
527 while (i--) {
528 clone[i] = Ext.clone(item[i]);
529 }
530 }
531 // Object
532 else if (type === '[object Object]' && item.constructor === Object) {
533 clone = {};
534
535 for (key in item) {
536 clone[key] = Ext.clone(item[key]);
537 }
538
539 if (enumerables) {
540 for (j = enumerables.length; j--;) {
541 k = enumerables[j];
542 clone[k] = item[k];
543 }
544 }
545 }
546
547 return clone || item;
548 },
549
550 /**
551 * @private
552 * Generate a unique reference of Ext in the global scope, useful for sandboxing
553 */
554 getUniqueGlobalNamespace: function() {
555 var uniqueGlobalNamespace = this.uniqueGlobalNamespace;
556
557 if (uniqueGlobalNamespace === undefined) {
558 var i = 0;
559
560 do {
561 uniqueGlobalNamespace = 'ExtBox' + (++i);
562 } while (Ext.global[uniqueGlobalNamespace] !== undefined);
563
564 Ext.global[uniqueGlobalNamespace] = Ext;
565 this.uniqueGlobalNamespace = uniqueGlobalNamespace;
566 }
567
568 return uniqueGlobalNamespace;
569 },
570
571 /**
572 * @private
573 */
574 functionFactory: function() {
575 var args = Array.prototype.slice.call(arguments);
576
577 if (args.length > 0) {
578 args[args.length - 1] = 'var Ext=window.' + this.getUniqueGlobalNamespace() + ';' +
579 args[args.length - 1];
580 }
581
582 return Function.prototype.constructor.apply(Function.prototype, args);
583 }
584 });
585
586 /**
587 * Old alias to {@link Ext#typeOf}
588 * @deprecated 4.0.0 Use {@link Ext#typeOf} instead
589 * @method
590 * @alias Ext#typeOf
591 */
592 Ext.type = Ext.typeOf;
593
594})();
595
596/**
597 * @author Jacky Nguyen <jacky@sencha.com>
598 * @docauthor Jacky Nguyen <jacky@sencha.com>
599 * @class Ext.Version
600 *
601 * A utility class that wrap around a string version number and provide convenient
602 * method to perform comparison. See also: {@link Ext.Version#compare compare}. Example:
603
604 var version = new Ext.Version('1.0.2beta');
605 console.log("Version is " + version); // Version is 1.0.2beta
606
607 console.log(version.getMajor()); // 1
608 console.log(version.getMinor()); // 0
609 console.log(version.getPatch()); // 2
610 console.log(version.getBuild()); // 0
611 console.log(version.getRelease()); // beta
612
613 console.log(version.isGreaterThan('1.0.1')); // True
614 console.log(version.isGreaterThan('1.0.2alpha')); // True
615 console.log(version.isGreaterThan('1.0.2RC')); // False
616 console.log(version.isGreaterThan('1.0.2')); // False
617 console.log(version.isLessThan('1.0.2')); // True
618
619 console.log(version.match(1.0)); // True
620 console.log(version.match('1.0.2')); // True
621
622 * @markdown
623 */
624(function() {
625
626// Current core version
627var version = '4.0.7', Version;
628 Ext.Version = Version = Ext.extend(Object, {
629
630 /**
631 * @param {String/Number} version The version number in the follow standard format: major[.minor[.patch[.build[release]]]]
632 * Examples: 1.0 or 1.2.3beta or 1.2.3.4RC
633 * @return {Ext.Version} this
634 */
635 constructor: function(version) {
636 var parts, releaseStartIndex;
637
638 if (version instanceof Version) {
639 return version;
640 }
641
642 this.version = this.shortVersion = String(version).toLowerCase().replace(/_/g, '.').replace(/[\-+]/g, '');
643
644 releaseStartIndex = this.version.search(/([^\d\.])/);
645
646 if (releaseStartIndex !== -1) {
647 this.release = this.version.substr(releaseStartIndex, version.length);
648 this.shortVersion = this.version.substr(0, releaseStartIndex);
649 }
650
651 this.shortVersion = this.shortVersion.replace(/[^\d]/g, '');
652
653 parts = this.version.split('.');
654
655 this.major = parseInt(parts.shift() || 0, 10);
656 this.minor = parseInt(parts.shift() || 0, 10);
657 this.patch = parseInt(parts.shift() || 0, 10);
658 this.build = parseInt(parts.shift() || 0, 10);
659
660 return this;
661 },
662
663 /**
664 * Override the native toString method
665 * @private
666 * @return {String} version
667 */
668 toString: function() {
669 return this.version;
670 },
671
672 /**
673 * Override the native valueOf method
674 * @private
675 * @return {String} version
676 */
677 valueOf: function() {
678 return this.version;
679 },
680
681 /**
682 * Returns the major component value
683 * @return {Number} major
684 */
685 getMajor: function() {
686 return this.major || 0;
687 },
688
689 /**
690 * Returns the minor component value
691 * @return {Number} minor
692 */
693 getMinor: function() {
694 return this.minor || 0;
695 },
696
697 /**
698 * Returns the patch component value
699 * @return {Number} patch
700 */
701 getPatch: function() {
702 return this.patch || 0;
703 },
704
705 /**
706 * Returns the build component value
707 * @return {Number} build
708 */
709 getBuild: function() {
710 return this.build || 0;
711 },
712
713 /**
714 * Returns the release component value
715 * @return {Number} release
716 */
717 getRelease: function() {
718 return this.release || '';
719 },
720
721 /**
722 * Returns whether this version if greater than the supplied argument
723 * @param {String/Number} target The version to compare with
724 * @return {Boolean} True if this version if greater than the target, false otherwise
725 */
726 isGreaterThan: function(target) {
727 return Version.compare(this.version, target) === 1;
728 },
729
730 /**
731 * Returns whether this version if smaller than the supplied argument
732 * @param {String/Number} target The version to compare with
733 * @return {Boolean} True if this version if smaller than the target, false otherwise
734 */
735 isLessThan: function(target) {
736 return Version.compare(this.version, target) === -1;
737 },
738
739 /**
740 * Returns whether this version equals to the supplied argument
741 * @param {String/Number} target The version to compare with
742 * @return {Boolean} True if this version equals to the target, false otherwise
743 */
744 equals: function(target) {
745 return Version.compare(this.version, target) === 0;
746 },
747
748 /**
749 * Returns whether this version matches the supplied argument. Example:
750 * <pre><code>
751 * var version = new Ext.Version('1.0.2beta');
752 * console.log(version.match(1)); // True
753 * console.log(version.match(1.0)); // True
754 * console.log(version.match('1.0.2')); // True
755 * console.log(version.match('1.0.2RC')); // False
756 * </code></pre>
757 * @param {String/Number} target The version to compare with
758 * @return {Boolean} True if this version matches the target, false otherwise
759 */
760 match: function(target) {
761 target = String(target);
762 return this.version.substr(0, target.length) === target;
763 },
764
765 /**
766 * Returns this format: [major, minor, patch, build, release]. Useful for comparison
767 * @return {Number[]}
768 */
769 toArray: function() {
770 return [this.getMajor(), this.getMinor(), this.getPatch(), this.getBuild(), this.getRelease()];
771 },
772
773 /**
774 * Returns shortVersion version without dots and release
775 * @return {String}
776 */
777 getShortVersion: function() {
778 return this.shortVersion;
779 }
780 });
781
782 Ext.apply(Version, {
783 // @private
784 releaseValueMap: {
785 'dev': -6,
786 'alpha': -5,
787 'a': -5,
788 'beta': -4,
789 'b': -4,
790 'rc': -3,
791 '#': -2,
792 'p': -1,
793 'pl': -1
794 },
795
796 /**
797 * Converts a version component to a comparable value
798 *
799 * @static
800 * @param {Object} value The value to convert
801 * @return {Object}
802 */
803 getComponentValue: function(value) {
804 return !value ? 0 : (isNaN(value) ? this.releaseValueMap[value] || value : parseInt(value, 10));
805 },
806
807 /**
808 * Compare 2 specified versions, starting from left to right. If a part contains special version strings,
809 * they are handled in the following order:
810 * 'dev' < 'alpha' = 'a' < 'beta' = 'b' < 'RC' = 'rc' < '#' < 'pl' = 'p' < 'anything else'
811 *
812 * @static
813 * @param {String} current The current version to compare to
814 * @param {String} target The target version to compare to
815 * @return {Number} Returns -1 if the current version is smaller than the target version, 1 if greater, and 0 if they're equivalent
816 */
817 compare: function(current, target) {
818 var currentValue, targetValue, i;
819
820 current = new Version(current).toArray();
821 target = new Version(target).toArray();
822
823 for (i = 0; i < Math.max(current.length, target.length); i++) {
824 currentValue = this.getComponentValue(current[i]);
825 targetValue = this.getComponentValue(target[i]);
826
827 if (currentValue < targetValue) {
828 return -1;
829 } else if (currentValue > targetValue) {
830 return 1;
831 }
832 }
833
834 return 0;
835 }
836 });
837
838 Ext.apply(Ext, {
839 /**
840 * @private
841 */
842 versions: {},
843
844 /**
845 * @private
846 */
847 lastRegisteredVersion: null,
848
849 /**
850 * Set version number for the given package name.
851 *
852 * @param {String} packageName The package name, for example: 'core', 'touch', 'extjs'
853 * @param {String/Ext.Version} version The version, for example: '1.2.3alpha', '2.4.0-dev'
854 * @return {Ext}
855 */
856 setVersion: function(packageName, version) {
857 Ext.versions[packageName] = new Version(version);
858 Ext.lastRegisteredVersion = Ext.versions[packageName];
859
860 return this;
861 },
862
863 /**
864 * Get the version number of the supplied package name; will return the last registered version
865 * (last Ext.setVersion call) if there's no package name given.
866 *
867 * @param {String} packageName (Optional) The package name, for example: 'core', 'touch', 'extjs'
868 * @return {Ext.Version} The version
869 */
870 getVersion: function(packageName) {
871 if (packageName === undefined) {
872 return Ext.lastRegisteredVersion;
873 }
874
875 return Ext.versions[packageName];
876 },
877
878 /**
879 * Create a closure for deprecated code.
880 *
881 // This means Ext.oldMethod is only supported in 4.0.0beta and older.
882 // If Ext.getVersion('extjs') returns a version that is later than '4.0.0beta', for example '4.0.0RC',
883 // the closure will not be invoked
884 Ext.deprecate('extjs', '4.0.0beta', function() {
885 Ext.oldMethod = Ext.newMethod;
886
887 ...
888 });
889
890 * @param {String} packageName The package name
891 * @param {String} since The last version before it's deprecated
892 * @param {Function} closure The callback function to be executed with the specified version is less than the current version
893 * @param {Object} scope The execution scope (<tt>this</tt>) if the closure
894 * @markdown
895 */
896 deprecate: function(packageName, since, closure, scope) {
897 if (Version.compare(Ext.getVersion(packageName), since) < 1) {
898 closure.call(scope);
899 }
900 }
901 }); // End Versioning
902
903 Ext.setVersion('core', version);
904
905})();
906
907/**
908 * @class Ext.String
909 *
910 * A collection of useful static methods to deal with strings
911 * @singleton
912 */
913
914Ext.String = {
915 trimRegex: /^[\x09\x0a\x0b\x0c\x0d\x20\xa0\u1680\u180e\u2000\u2001\u2002\u2003\u2004\u2005\u2006\u2007\u2008\u2009\u200a\u2028\u2029\u202f\u205f\u3000]+|[\x09\x0a\x0b\x0c\x0d\x20\xa0\u1680\u180e\u2000\u2001\u2002\u2003\u2004\u2005\u2006\u2007\u2008\u2009\u200a\u2028\u2029\u202f\u205f\u3000]+$/g,
916 escapeRe: /('|\\)/g,
917 formatRe: /\{(\d+)\}/g,
918 escapeRegexRe: /([-.*+?^${}()|[\]\/\\])/g,
919
920 /**
921 * Convert certain characters (&, <, >, and ") to their HTML character equivalents for literal display in web pages.
922 * @param {String} value The string to encode
923 * @return {String} The encoded text
924 * @method
925 */
926 htmlEncode: (function() {
927 var entities = {
928 '&': '&',
929 '>': '>',
930 '<': '<',
931 '"': '"'
932 }, keys = [], p, regex;
933
934 for (p in entities) {
935 keys.push(p);
936 }
937
938 regex = new RegExp('(' + keys.join('|') + ')', 'g');
939
940 return function(value) {
941 return (!value) ? value : String(value).replace(regex, function(match, capture) {
942 return entities[capture];
943 });
944 };
945 })(),
946
947 /**
948 * Convert certain characters (&, <, >, and ") from their HTML character equivalents.
949 * @param {String} value The string to decode
950 * @return {String} The decoded text
951 * @method
952 */
953 htmlDecode: (function() {
954 var entities = {
955 '&': '&',
956 '>': '>',
957 '<': '<',
958 '"': '"'
959 }, keys = [], p, regex;
960
961 for (p in entities) {
962 keys.push(p);
963 }
964
965 regex = new RegExp('(' + keys.join('|') + '|&#[0-9]{1,5};' + ')', 'g');
966
967 return function(value) {
968 return (!value) ? value : String(value).replace(regex, function(match, capture) {
969 if (capture in entities) {
970 return entities[capture];
971 } else {
972 return String.fromCharCode(parseInt(capture.substr(2), 10));
973 }
974 });
975 };
976 })(),
977
978 /**
979 * Appends content to the query string of a URL, handling logic for whether to place
980 * a question mark or ampersand.
981 * @param {String} url The URL to append to.
982 * @param {String} string The content to append to the URL.
983 * @return (String) The resulting URL
984 */
985 urlAppend : function(url, string) {
986 if (!Ext.isEmpty(string)) {
987 return url + (url.indexOf('?') === -1 ? '?' : '&') + string;
988 }
989
990 return url;
991 },
992
993 /**
994 * Trims whitespace from either end of a string, leaving spaces within the string intact. Example:
995 * @example
996var s = ' foo bar ';
997alert('-' + s + '-'); //alerts "- foo bar -"
998alert('-' + Ext.String.trim(s) + '-'); //alerts "-foo bar-"
999
1000 * @param {String} string The string to escape
1001 * @return {String} The trimmed string
1002 */
1003 trim: function(string) {
1004 return string.replace(Ext.String.trimRegex, "");
1005 },
1006
1007 /**
1008 * Capitalize the given string
1009 * @param {String} string
1010 * @return {String}
1011 */
1012 capitalize: function(string) {
1013 return string.charAt(0).toUpperCase() + string.substr(1);
1014 },
1015
1016 /**
1017 * Truncate a string and add an ellipsis ('...') to the end if it exceeds the specified length
1018 * @param {String} value The string to truncate
1019 * @param {Number} length The maximum length to allow before truncating
1020 * @param {Boolean} word True to try to find a common word break
1021 * @return {String} The converted text
1022 */
1023 ellipsis: function(value, len, word) {
1024 if (value && value.length > len) {
1025 if (word) {
1026 var vs = value.substr(0, len - 2),
1027 index = Math.max(vs.lastIndexOf(' '), vs.lastIndexOf('.'), vs.lastIndexOf('!'), vs.lastIndexOf('?'));
1028 if (index !== -1 && index >= (len - 15)) {
1029 return vs.substr(0, index) + "...";
1030 }
1031 }
1032 return value.substr(0, len - 3) + "...";
1033 }
1034 return value;
1035 },
1036
1037 /**
1038 * Escapes the passed string for use in a regular expression
1039 * @param {String} string
1040 * @return {String}
1041 */
1042 escapeRegex: function(string) {
1043 return string.replace(Ext.String.escapeRegexRe, "\\$1");
1044 },
1045
1046 /**
1047 * Escapes the passed string for ' and \
1048 * @param {String} string The string to escape
1049 * @return {String} The escaped string
1050 */
1051 escape: function(string) {
1052 return string.replace(Ext.String.escapeRe, "\\$1");
1053 },
1054
1055 /**
1056 * Utility function that allows you to easily switch a string between two alternating values. The passed value
1057 * is compared to the current string, and if they are equal, the other value that was passed in is returned. If
1058 * they are already different, the first value passed in is returned. Note that this method returns the new value
1059 * but does not change the current string.
1060 * <pre><code>
1061 // alternate sort directions
1062 sort = Ext.String.toggle(sort, 'ASC', 'DESC');
1063
1064 // instead of conditional logic:
1065 sort = (sort == 'ASC' ? 'DESC' : 'ASC');
1066 </code></pre>
1067 * @param {String} string The current string
1068 * @param {String} value The value to compare to the current string
1069 * @param {String} other The new value to use if the string already equals the first value passed in
1070 * @return {String} The new value
1071 */
1072 toggle: function(string, value, other) {
1073 return string === value ? other : value;
1074 },
1075
1076 /**
1077 * Pads the left side of a string with a specified character. This is especially useful
1078 * for normalizing number and date strings. Example usage:
1079 *
1080 * <pre><code>
1081var s = Ext.String.leftPad('123', 5, '0');
1082// s now contains the string: '00123'
1083 </code></pre>
1084 * @param {String} string The original string
1085 * @param {Number} size The total length of the output string
1086 * @param {String} character (optional) The character with which to pad the original string (defaults to empty string " ")
1087 * @return {String} The padded string
1088 */
1089 leftPad: function(string, size, character) {
1090 var result = String(string);
1091 character = character || " ";
1092 while (result.length < size) {
1093 result = character + result;
1094 }
1095 return result;
1096 },
1097
1098 /**
1099 * Allows you to define a tokenized string and pass an arbitrary number of arguments to replace the tokens. Each
1100 * token must be unique, and must increment in the format {0}, {1}, etc. Example usage:
1101 * <pre><code>
1102var cls = 'my-class', text = 'Some text';
1103var s = Ext.String.format('<div class="{0}">{1}</div>', cls, text);
1104// s now contains the string: '<div class="my-class">Some text</div>'
1105 </code></pre>
1106 * @param {String} string The tokenized string to be formatted
1107 * @param {String} value1 The value to replace token {0}
1108 * @param {String} value2 Etc...
1109 * @return {String} The formatted string
1110 */
1111 format: function(format) {
1112 var args = Ext.Array.toArray(arguments, 1);
1113 return format.replace(Ext.String.formatRe, function(m, i) {
1114 return args[i];
1115 });
1116 },
1117
1118 /**
1119 * Returns a string with a specified number of repititions a given string pattern.
1120 * The pattern be separated by a different string.
1121 *
1122 * var s = Ext.String.repeat('---', 4); // = '------------'
1123 * var t = Ext.String.repeat('--', 3, '/'); // = '--/--/--'
1124 *
1125 * @param {String} pattern The pattern to repeat.
1126 * @param {Number} count The number of times to repeat the pattern (may be 0).
1127 * @param {String} sep An option string to separate each pattern.
1128 */
1129 repeat: function(pattern, count, sep) {
1130 for (var buf = [], i = count; i--; ) {
1131 buf.push(pattern);
1132 }
1133 return buf.join(sep || '');
1134 }
1135};
1136
1137/**
1138 * @class Ext.Number
1139 *
1140 * A collection of useful static methods to deal with numbers
1141 * @singleton
1142 */
1143
1144(function() {
1145
1146var isToFixedBroken = (0.9).toFixed() !== '1';
1147
1148Ext.Number = {
1149 /**
1150 * Checks whether or not the passed number is within a desired range. If the number is already within the
1151 * range it is returned, otherwise the min or max value is returned depending on which side of the range is
1152 * exceeded. Note that this method returns the constrained value but does not change the current number.
1153 * @param {Number} number The number to check
1154 * @param {Number} min The minimum number in the range
1155 * @param {Number} max The maximum number in the range
1156 * @return {Number} The constrained value if outside the range, otherwise the current value
1157 */
1158 constrain: function(number, min, max) {
1159 number = parseFloat(number);
1160
1161 if (!isNaN(min)) {
1162 number = Math.max(number, min);
1163 }
1164 if (!isNaN(max)) {
1165 number = Math.min(number, max);
1166 }
1167 return number;
1168 },
1169
1170 /**
1171 * Snaps the passed number between stopping points based upon a passed increment value.
1172 * @param {Number} value The unsnapped value.
1173 * @param {Number} increment The increment by which the value must move.
1174 * @param {Number} minValue The minimum value to which the returned value must be constrained. Overrides the increment..
1175 * @param {Number} maxValue The maximum value to which the returned value must be constrained. Overrides the increment..
1176 * @return {Number} The value of the nearest snap target.
1177 */
1178 snap : function(value, increment, minValue, maxValue) {
1179 var newValue = value,
1180 m;
1181
1182 if (!(increment && value)) {
1183 return value;
1184 }
1185 m = value % increment;
1186 if (m !== 0) {
1187 newValue -= m;
1188 if (m * 2 >= increment) {
1189 newValue += increment;
1190 } else if (m * 2 < -increment) {
1191 newValue -= increment;
1192 }
1193 }
1194 return Ext.Number.constrain(newValue, minValue, maxValue);
1195 },
1196
1197 /**
1198 * Formats a number using fixed-point notation
1199 * @param {Number} value The number to format
1200 * @param {Number} precision The number of digits to show after the decimal point
1201 */
1202 toFixed: function(value, precision) {
1203 if (isToFixedBroken) {
1204 precision = precision || 0;
1205 var pow = Math.pow(10, precision);
1206 return (Math.round(value * pow) / pow).toFixed(precision);
1207 }
1208
1209 return value.toFixed(precision);
1210 },
1211
1212 /**
1213 * Validate that a value is numeric and convert it to a number if necessary. Returns the specified default value if
1214 * it is not.
1215
1216Ext.Number.from('1.23', 1); // returns 1.23
1217Ext.Number.from('abc', 1); // returns 1
1218
1219 * @param {Object} value
1220 * @param {Number} defaultValue The value to return if the original value is non-numeric
1221 * @return {Number} value, if numeric, defaultValue otherwise
1222 */
1223 from: function(value, defaultValue) {
1224 if (isFinite(value)) {
1225 value = parseFloat(value);
1226 }
1227
1228 return !isNaN(value) ? value : defaultValue;
1229 }
1230};
1231
1232})();
1233
1234/**
1235 * @deprecated 4.0.0 Please use {@link Ext.Number#from} instead.
1236 * @member Ext
1237 * @method num
1238 * @alias Ext.Number#from
1239 */
1240Ext.num = function() {
1241 return Ext.Number.from.apply(this, arguments);
1242};
1243/**
1244 * @class Ext.Array
1245 * @singleton
1246 * @author Jacky Nguyen <jacky@sencha.com>
1247 * @docauthor Jacky Nguyen <jacky@sencha.com>
1248 *
1249 * A set of useful static methods to deal with arrays; provide missing methods for older browsers.
1250 */
1251(function() {
1252
1253 var arrayPrototype = Array.prototype,
1254 slice = arrayPrototype.slice,
1255 supportsSplice = function () {
1256 var array = [],
1257 lengthBefore,
1258 j = 20;
1259
1260 if (!array.splice) {
1261 return false;
1262 }
1263
1264 // This detects a bug in IE8 splice method:
1265 // see http://social.msdn.microsoft.com/Forums/en-US/iewebdevelopment/thread/6e946d03-e09f-4b22-a4dd-cd5e276bf05a/
1266
1267 while (j--) {
1268 array.push("A");
1269 }
1270
1271 array.splice(15, 0, "F", "F", "F", "F", "F","F","F","F","F","F","F","F","F","F","F","F","F","F","F","F","F");
1272
1273 lengthBefore = array.length; //41
1274 array.splice(13, 0, "XXX"); // add one element
1275
1276 if (lengthBefore+1 != array.length) {
1277 return false;
1278 }
1279 // end IE8 bug
1280
1281 return true;
1282 }(),
1283 supportsForEach = 'forEach' in arrayPrototype,
1284 supportsMap = 'map' in arrayPrototype,
1285 supportsIndexOf = 'indexOf' in arrayPrototype,
1286 supportsEvery = 'every' in arrayPrototype,
1287 supportsSome = 'some' in arrayPrototype,
1288 supportsFilter = 'filter' in arrayPrototype,
1289 supportsSort = function() {
1290 var a = [1,2,3,4,5].sort(function(){ return 0; });
1291 return a[0] === 1 && a[1] === 2 && a[2] === 3 && a[3] === 4 && a[4] === 5;
1292 }(),
1293 supportsSliceOnNodeList = true,
1294 ExtArray;
1295
1296 try {
1297 // IE 6 - 8 will throw an error when using Array.prototype.slice on NodeList
1298 if (typeof document !== 'undefined') {
1299 slice.call(document.getElementsByTagName('body'));
1300 }
1301 } catch (e) {
1302 supportsSliceOnNodeList = false;
1303 }
1304
1305 function fixArrayIndex (array, index) {
1306 return (index < 0) ? Math.max(0, array.length + index)
1307 : Math.min(array.length, index);
1308 }
1309
1310 /*
1311 Does the same work as splice, but with a slightly more convenient signature. The splice
1312 method has bugs in IE8, so this is the implementation we use on that platform.
1313
1314 The rippling of items in the array can be tricky. Consider two use cases:
1315
1316 index=2
1317 removeCount=2
1318 /=====\
1319 +---+---+---+---+---+---+---+---+
1320 | 0 | 1 | 2 | 3 | 4 | 5 | 6 | 7 |
1321 +---+---+---+---+---+---+---+---+
1322 / \/ \/ \/ \
1323 / /\ /\ /\ \
1324 / / \/ \/ \ +--------------------------+
1325 / / /\ /\ +--------------------------+ \
1326 / / / \/ +--------------------------+ \ \
1327 / / / /+--------------------------+ \ \ \
1328 / / / / \ \ \ \
1329 v v v v v v v v
1330 +---+---+---+---+---+---+ +---+---+---+---+---+---+---+---+---+
1331 | 0 | 1 | 4 | 5 | 6 | 7 | | 0 | 1 | a | b | c | 4 | 5 | 6 | 7 |
1332 +---+---+---+---+---+---+ +---+---+---+---+---+---+---+---+---+
1333 A B \=========/
1334 insert=[a,b,c]
1335
1336 In case A, it is obvious that copying of [4,5,6,7] must be left-to-right so
1337 that we don't end up with [0,1,6,7,6,7]. In case B, we have the opposite; we
1338 must go right-to-left or else we would end up with [0,1,a,b,c,4,4,4,4].
1339 */
1340 function replaceSim (array, index, removeCount, insert) {
1341 var add = insert ? insert.length : 0,
1342 length = array.length,
1343 pos = fixArrayIndex(array, index);
1344
1345 // we try to use Array.push when we can for efficiency...
1346 if (pos === length) {
1347 if (add) {
1348 array.push.apply(array, insert);
1349 }
1350 } else {
1351 var remove = Math.min(removeCount, length - pos),
1352 tailOldPos = pos + remove,
1353 tailNewPos = tailOldPos + add - remove,
1354 tailCount = length - tailOldPos,
1355 lengthAfterRemove = length - remove,
1356 i;
1357
1358 if (tailNewPos < tailOldPos) { // case A
1359 for (i = 0; i < tailCount; ++i) {
1360 array[tailNewPos+i] = array[tailOldPos+i];
1361 }
1362 } else if (tailNewPos > tailOldPos) { // case B
1363 for (i = tailCount; i--; ) {
1364 array[tailNewPos+i] = array[tailOldPos+i];
1365 }
1366 } // else, add == remove (nothing to do)
1367
1368 if (add && pos === lengthAfterRemove) {
1369 array.length = lengthAfterRemove; // truncate array
1370 array.push.apply(array, insert);
1371 } else {
1372 array.length = lengthAfterRemove + add; // reserves space
1373 for (i = 0; i < add; ++i) {
1374 array[pos+i] = insert[i];
1375 }
1376 }
1377 }
1378
1379 return array;
1380 }
1381
1382 function replaceNative (array, index, removeCount, insert) {
1383 if (insert && insert.length) {
1384 if (index < array.length) {
1385 array.splice.apply(array, [index, removeCount].concat(insert));
1386 } else {
1387 array.push.apply(array, insert);
1388 }
1389 } else {
1390 array.splice(index, removeCount);
1391 }
1392 return array;
1393 }
1394
1395 function eraseSim (array, index, removeCount) {
1396 return replaceSim(array, index, removeCount);
1397 }
1398
1399 function eraseNative (array, index, removeCount) {
1400 array.splice(index, removeCount);
1401 return array;
1402 }
1403
1404 function spliceSim (array, index, removeCount) {
1405 var pos = fixArrayIndex(array, index),
1406 removed = array.slice(index, fixArrayIndex(array, pos+removeCount));
1407
1408 if (arguments.length < 4) {
1409 replaceSim(array, pos, removeCount);
1410 } else {
1411 replaceSim(array, pos, removeCount, slice.call(arguments, 3));
1412 }
1413
1414 return removed;
1415 }
1416
1417 function spliceNative (array) {
1418 return array.splice.apply(array, slice.call(arguments, 1));
1419 }
1420
1421 var erase = supportsSplice ? eraseNative : eraseSim,
1422 replace = supportsSplice ? replaceNative : replaceSim,
1423 splice = supportsSplice ? spliceNative : spliceSim;
1424
1425 // NOTE: from here on, use erase, replace or splice (not native methods)...
1426
1427 ExtArray = Ext.Array = {
1428 /**
1429 * Iterates an array or an iterable value and invoke the given callback function for each item.
1430 *
1431 * var countries = ['Vietnam', 'Singapore', 'United States', 'Russia'];
1432 *
1433 * Ext.Array.each(countries, function(name, index, countriesItSelf) {
1434 * console.log(name);
1435 * });
1436 *
1437 * var sum = function() {
1438 * var sum = 0;
1439 *
1440 * Ext.Array.each(arguments, function(value) {
1441 * sum += value;
1442 * });
1443 *
1444 * return sum;
1445 * };
1446 *
1447 * sum(1, 2, 3); // returns 6
1448 *
1449 * The iteration can be stopped by returning false in the function callback.
1450 *
1451 * Ext.Array.each(countries, function(name, index, countriesItSelf) {
1452 * if (name === 'Singapore') {
1453 * return false; // break here
1454 * }
1455 * });
1456 *
1457 * {@link Ext#each Ext.each} is alias for {@link Ext.Array#each Ext…
Large files files are truncated, but you can click here to view the full file