3 This file is part of Ext JS 4
5 Copyright (c) 2011 Sencha Inc
7 Contact: http://www.sencha.com/contact
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.
12 If you are unsure which license is appropriate for your use, please contact the sales department at http://www.sencha.com/contact.
21 objectPrototype = Object.prototype,
22 toString = objectPrototype.toString,
24 enumerablesTest = { toString: 1 },
27 if (typeof Ext === 'undefined') {
33 for (i in enumerablesTest) {
38 enumerables = ['hasOwnProperty', 'valueOf', 'isPrototypeOf', 'propertyIsEnumerable',
39 'toLocaleString', 'toString', 'constructor'];
43 * An array containing extra enumerables for old browsers
44 * @property {String[]}
46 Ext.enumerables = enumerables;
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
57 Ext.apply = function(object, config, defaults) {
59 Ext.apply(object, defaults);
62 if (object && config && typeof config === 'object') {
66 object[i] = config[i];
70 for (j = enumerables.length; j--;) {
72 if (config.hasOwnProperty(k)) {
73 object[k] = config[k];
82 Ext.buildSettings = Ext.apply({
85 }, Ext.buildSettings || {});
89 * A reusable empty function
91 emptyFn: function() {},
93 baseCSSPrefix: Ext.buildSettings.baseCSSPrefix,
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
101 applyIf: function(object, config) {
105 for (property in config) {
106 if (object[property] === undefined) {
107 object[property] = config[property];
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.
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.
127 iterate: function(object, fn, scope) {
128 if (Ext.isEmpty(object)) {
132 if (scope === undefined) {
136 if (Ext.isIterable(object)) {
137 Ext.Array.each.call(Ext.Array, object, fn, scope);
140 Ext.Object.each.call(Ext.Object, object, fn, scope);
148 * This method deprecated. Use {@link Ext#define Ext.define} instead.
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
157 var objectConstructor = objectPrototype.constructor,
158 inlineOverrides = function(o) {
160 if (!o.hasOwnProperty(m)) {
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);
181 sourceMethod: 'extend',
182 msg: 'Attempting to extend from a class which has not been loaded on the page.'
187 // We create a new temporary class
188 var F = function() {},
189 subclassProto, superclassProto = superclass.prototype;
191 F.prototype = superclassProto;
192 subclassProto = subclass.prototype = new F();
193 subclassProto.constructor = subclass;
194 subclass.superclass = superclassProto;
196 if (superclassProto.constructor === objectConstructor) {
197 superclassProto.constructor = superclass;
200 subclass.override = function(overrides) {
201 Ext.override(subclass, overrides);
204 subclassProto.override = inlineOverrides;
205 subclassProto.proto = subclassProto;
207 subclass.override(overrides);
208 subclass.extend = function(o) {
209 return Ext.extend(subclass, o);
217 * Proxy to {@link Ext.Base#override}. Please refer {@link Ext.Base#override} for further details.
219 Ext.define('My.cool.Class', {
225 Ext.override(My.cool.Class, {
227 alert('About to say...');
229 this.callOverridden();
233 var cool = new My.cool.Class();
234 cool.sayHi(); // alerts 'About to say...'
237 * Please note that `this.callOverridden()` only works if the class was previously
238 * created with {@link Ext#define)
240 * @param {Object} cls The class to override
241 * @param {Object} overrides The list of functions to add to origClass. This should be specified as an object literal
242 * containing one or more methods.
246 override: function(cls, overrides) {
247 if (cls.prototype.$className) {
248 return cls.override(overrides);
251 Ext.apply(cls.prototype, overrides);
256 // A full set of static methods to do type checking
260 * Returns the given value itself if it's not empty, as described in {@link Ext#isEmpty}; returns the default
261 * value (second argument) otherwise.
263 * @param {Object} value The value to test
264 * @param {Object} defaultValue The value to return if the original value is empty
265 * @param {Boolean} allowBlank (optional) true to allow zero length strings to qualify as non-empty (defaults to false)
266 * @return {Object} value, if non-empty, else defaultValue
268 valueFrom: function(value, defaultValue, allowBlank){
269 return Ext.isEmpty(value, allowBlank) ? defaultValue : value;
273 * Returns the type of the given variable in string format. List of possible values are:
275 * - `undefined`: If the given value is `undefined`
276 * - `null`: If the given value is `null`
277 * - `string`: If the given value is a string
278 * - `number`: If the given value is a number
279 * - `boolean`: If the given value is a boolean value
280 * - `date`: If the given value is a `Date` object
281 * - `function`: If the given value is a function reference
282 * - `object`: If the given value is an object
283 * - `array`: If the given value is an array
284 * - `regexp`: If the given value is a regular expression
285 * - `element`: If the given value is a DOM Element
286 * - `textnode`: If the given value is a DOM text node and contains something other than whitespace
287 * - `whitespace`: If the given value is a DOM text node and contains only whitespace
289 * @param {Object} value
293 typeOf: function(value) {
294 if (value === null) {
298 var type = typeof value;
300 if (type === 'undefined' || type === 'string' || type === 'number' || type === 'boolean') {
304 var typeToString = toString.call(value);
306 switch(typeToString) {
307 case '[object Array]':
309 case '[object Date]':
311 case '[object Boolean]':
313 case '[object Number]':
315 case '[object RegExp]':
319 if (type === 'function') {
323 if (type === 'object') {
324 if (value.nodeType !== undefined) {
325 if (value.nodeType === 3) {
326 return (/\S/).test(value.nodeValue) ? 'textnode' : 'whitespace';
339 sourceMethod: 'typeOf',
340 msg: 'Failed to determine the type of the specified value "' + value + '". This is most likely a bug.'
346 * Returns true if the passed value is empty, false otherwise. The value is deemed to be empty if it is either:
350 * - a zero-length array
351 * - a zero-length string (Unless the `allowEmptyString` parameter is set to `true`)
353 * @param {Object} value The value to test
354 * @param {Boolean} allowEmptyString (optional) true to allow empty strings (defaults to false)
358 isEmpty: function(value, allowEmptyString) {
359 return (value === null) || (value === undefined) || (!allowEmptyString ? value === '' : false) || (Ext.isArray(value) && value.length === 0);
363 * Returns true if the passed value is a JavaScript Array, false otherwise.
365 * @param {Object} target The target to test
369 isArray: ('isArray' in Array) ? Array.isArray : function(value) {
370 return toString.call(value) === '[object Array]';
374 * Returns true if the passed value is a JavaScript Date object, false otherwise.
375 * @param {Object} object The object to test
378 isDate: function(value) {
379 return toString.call(value) === '[object Date]';
383 * Returns true if the passed value is a JavaScript Object, false otherwise.
384 * @param {Object} value The value to test
388 isObject: (toString.call(null) === '[object Object]') ?
390 // check ownerDocument here as well to exclude DOM nodes
391 return value !== null && value !== undefined && toString.call(value) === '[object Object]' && value.ownerDocument === undefined;
394 return toString.call(value) === '[object Object]';
398 * Returns true if the passed value is a JavaScript 'primitive', a string, number or boolean.
399 * @param {Object} value The value to test
402 isPrimitive: function(value) {
403 var type = typeof value;
405 return type === 'string' || type === 'number' || type === 'boolean';
409 * Returns true if the passed value is a JavaScript Function, false otherwise.
410 * @param {Object} value The value to test
415 // Safari 3.x and 4.x returns 'function' for typeof <NodeList>, hence we need to fall back to using
416 // Object.prorotype.toString (slower)
417 (typeof document !== 'undefined' && typeof document.getElementsByTagName('body') === 'function') ? function(value) {
418 return toString.call(value) === '[object Function]';
419 } : function(value) {
420 return typeof value === 'function';
424 * Returns true if the passed value is a number. Returns false for non-finite numbers.
425 * @param {Object} value The value to test
428 isNumber: function(value) {
429 return typeof value === 'number' && isFinite(value);
433 * Validates that a value is numeric.
434 * @param {Object} value Examples: 1, '1', '2.34'
435 * @return {Boolean} True if numeric, false otherwise
437 isNumeric: function(value) {
438 return !isNaN(parseFloat(value)) && isFinite(value);
442 * Returns true if the passed value is a string.
443 * @param {Object} value The value to test
446 isString: function(value) {
447 return typeof value === 'string';
451 * Returns true if the passed value is a boolean.
453 * @param {Object} value The value to test
456 isBoolean: function(value) {
457 return typeof value === 'boolean';
461 * Returns true if the passed value is an HTMLElement
462 * @param {Object} value The value to test
465 isElement: function(value) {
466 return value ? value.nodeType === 1 : false;
470 * Returns true if the passed value is a TextNode
471 * @param {Object} value The value to test
474 isTextNode: function(value) {
475 return value ? value.nodeName === "#text" : false;
479 * Returns true if the passed value is defined.
480 * @param {Object} value The value to test
483 isDefined: function(value) {
484 return typeof value !== 'undefined';
488 * Returns true if the passed value is iterable, false otherwise
489 * @param {Object} value The value to test
492 isIterable: function(value) {
493 return (value && typeof value !== 'string') ? value.length !== undefined : false;
500 * Clone almost any type of variable including array, object, DOM nodes and Date without keeping the old reference
501 * @param {Object} item The variable to clone
502 * @return {Object} clone
504 clone: function(item) {
505 if (item === null || item === undefined) {
510 // TODO proxy this to Ext.Element.clone to handle automatic id attribute changing
512 if (item.nodeType && item.cloneNode) {
513 return item.cloneNode(true);
516 var type = toString.call(item);
519 if (type === '[object Date]') {
520 return new Date(item.getTime());
523 var i, j, k, clone, key;
526 if (type === '[object Array]') {
532 clone[i] = Ext.clone(item[i]);
536 else if (type === '[object Object]' && item.constructor === Object) {
540 clone[key] = Ext.clone(item[key]);
544 for (j = enumerables.length; j--;) {
551 return clone || item;
556 * Generate a unique reference of Ext in the global scope, useful for sandboxing
558 getUniqueGlobalNamespace: function() {
559 var uniqueGlobalNamespace = this.uniqueGlobalNamespace;
561 if (uniqueGlobalNamespace === undefined) {
565 uniqueGlobalNamespace = 'ExtBox' + (++i);
566 } while (Ext.global[uniqueGlobalNamespace] !== undefined);
568 Ext.global[uniqueGlobalNamespace] = Ext;
569 this.uniqueGlobalNamespace = uniqueGlobalNamespace;
572 return uniqueGlobalNamespace;
578 functionFactory: function() {
579 var args = Array.prototype.slice.call(arguments);
581 if (args.length > 0) {
582 args[args.length - 1] = 'var Ext=window.' + this.getUniqueGlobalNamespace() + ';' +
583 args[args.length - 1];
586 return Function.prototype.constructor.apply(Function.prototype, args);
591 * Old alias to {@link Ext#typeOf}
592 * @deprecated 4.0.0 Use {@link Ext#typeOf} instead
596 Ext.type = Ext.typeOf;