PageRenderTime 39ms CodeModel.GetById 15ms app.highlight 19ms RepoModel.GetById 0ms app.codeStats 1ms

/ext-4.1.0_b3/src/core/src/Ext.js

https://bitbucket.org/srogerf/javascript
JavaScript | 656 lines | 340 code | 87 blank | 229 comment | 79 complexity | c0bafa206e26aa97c2ea39efa3048a99 MD5 | raw file
  1/**
  2 * @class Ext
  3 * @singleton
  4 */
  5var Ext = Ext || {};
  6Ext._startTime = new Date().getTime();
  7(function() {
  8    var global = this,
  9        objectPrototype = Object.prototype,
 10        toString = objectPrototype.toString,
 11        enumerables = true,
 12        enumerablesTest = { toString: 1 },
 13        emptyFn = function(){},
 14        i;
 15
 16    Ext.global = global;
 17
 18    for (i in enumerablesTest) {
 19        enumerables = null;
 20    }
 21
 22    if (enumerables) {
 23        enumerables = ['hasOwnProperty', 'valueOf', 'isPrototypeOf', 'propertyIsEnumerable',
 24                       'toLocaleString', 'toString', 'constructor'];
 25    }
 26
 27    /**
 28     * An array containing extra enumerables for old browsers
 29     * @property {String[]}
 30     */
 31    Ext.enumerables = enumerables;
 32
 33    /**
 34     * Copies all the properties of config to the specified object.
 35     * Note that if recursive merging and cloning without referencing the original objects / arrays is needed, use
 36     * {@link Ext.Object#merge} instead.
 37     * @param {Object} object The receiver of the properties
 38     * @param {Object} config The source of the properties
 39     * @param {Object} defaults A different object that will also be applied for default values
 40     * @return {Object} returns obj
 41     */
 42    Ext.apply = function(object, config, defaults) {
 43        if (defaults) {
 44            Ext.apply(object, defaults);
 45        }
 46
 47        if (object && config && typeof config === 'object') {
 48            var i, j, k;
 49
 50            for (i in config) {
 51                object[i] = config[i];
 52            }
 53
 54            if (enumerables) {
 55                for (j = enumerables.length; j--;) {
 56                    k = enumerables[j];
 57                    if (config.hasOwnProperty(k)) {
 58                        object[k] = config[k];
 59                    }
 60                }
 61            }
 62        }
 63
 64        return object;
 65    };
 66
 67    Ext.buildSettings = Ext.apply({
 68        baseCSSPrefix: 'x-',
 69        scopeResetCSS: false
 70    }, Ext.buildSettings || {});
 71
 72    Ext.apply(Ext, {
 73
 74        /**
 75         * @property {String} [name='Ext']
 76         * <p>The name of the property in the global namespace (The <code>window</code> in browser environments) which refers to the current instance of Ext.</p>
 77         * <p>This is usually <code>"Ext"</code>, but if a sandboxed build of ExtJS is being used, this will be an alternative name.</p>
 78         * <p>If code is being generated for use by <code>eval</code> or to create a <code>new Function</code>, and the global instance
 79         * of Ext must be referenced, this is the name that should be built into the code.</p>
 80         */
 81        name: Ext.sandboxName || 'Ext',
 82
 83        /**
 84         * A reusable empty function
 85         */
 86        emptyFn: emptyFn,
 87
 88        /**
 89         * A zero length string which will pass a truth test. Useful for passing to methods
 90         * which use a truth test to reject <i>falsy</i> values where a string value must be cleared.
 91         */
 92        emptyString: new String(),
 93
 94        baseCSSPrefix: Ext.buildSettings.baseCSSPrefix,
 95
 96        /**
 97         * Copies all the properties of config to object if they don't already exist.
 98         * @param {Object} object The receiver of the properties
 99         * @param {Object} config The source of the properties
100         * @return {Object} returns obj
101         */
102        applyIf: function(object, config) {
103            var property;
104
105            if (object) {
106                for (property in config) {
107                    if (object[property] === undefined) {
108                        object[property] = config[property];
109                    }
110                }
111            }
112
113            return object;
114        },
115
116        /**
117         * Iterates either an array or an object. This method delegates to
118         * {@link Ext.Array#each Ext.Array.each} if the given value is iterable, and {@link Ext.Object#each Ext.Object.each} otherwise.
119         *
120         * @param {Object/Array} object The object or array to be iterated.
121         * @param {Function} fn The function to be called for each iteration. See and {@link Ext.Array#each Ext.Array.each} and
122         * {@link Ext.Object#each Ext.Object.each} for detailed lists of arguments passed to this function depending on the given object
123         * type that is being iterated.
124         * @param {Object} scope (Optional) The scope (`this` reference) in which the specified function is executed.
125         * Defaults to the object being iterated itself.
126         * @markdown
127         */
128        iterate: function(object, fn, scope) {
129            if (Ext.isEmpty(object)) {
130                return;
131            }
132
133            if (scope === undefined) {
134                scope = object;
135            }
136
137            if (Ext.isIterable(object)) {
138                Ext.Array.each.call(Ext.Array, object, fn, scope);
139            }
140            else {
141                Ext.Object.each.call(Ext.Object, object, fn, scope);
142            }
143        }
144    });
145
146    Ext.apply(Ext, {
147
148        /**
149         * This method deprecated. Use {@link Ext#define Ext.define} instead.
150         * @method
151         * @param {Function} superclass
152         * @param {Object} overrides
153         * @return {Function} The subclass constructor from the <tt>overrides</tt> parameter, or a generated one if not provided.
154         * @deprecated 4.0.0 Use {@link Ext#define Ext.define} instead
155         */
156        extend: function() {
157            // inline overrides
158            var objectConstructor = objectPrototype.constructor,
159                inlineOverrides = function(o) {
160                for (var m in o) {
161                    if (!o.hasOwnProperty(m)) {
162                        continue;
163                    }
164                    this[m] = o[m];
165                }
166            };
167
168            return function(subclass, superclass, overrides) {
169                // First we check if the user passed in just the superClass with overrides
170                if (Ext.isObject(superclass)) {
171                    overrides = superclass;
172                    superclass = subclass;
173                    subclass = overrides.constructor !== objectConstructor ? overrides.constructor : function() {
174                        superclass.apply(this, arguments);
175                    };
176                }
177
178                //<debug>
179                if (!superclass) {
180                    Ext.Error.raise({
181                        sourceClass: 'Ext',
182                        sourceMethod: 'extend',
183                        msg: 'Attempting to extend from a class which has not been loaded on the page.'
184                    });
185                }
186                //</debug>
187
188                // We create a new temporary class
189                var F = function() {},
190                    subclassProto, superclassProto = superclass.prototype;
191
192                F.prototype = superclassProto;
193                subclassProto = subclass.prototype = new F();
194                subclassProto.constructor = subclass;
195                subclass.superclass = superclassProto;
196
197                if (superclassProto.constructor === objectConstructor) {
198                    superclassProto.constructor = superclass;
199                }
200
201                subclass.override = function(overrides) {
202                    Ext.override(subclass, overrides);
203                };
204
205                subclassProto.override = inlineOverrides;
206                subclassProto.proto = subclassProto;
207
208                subclass.override(overrides);
209                subclass.extend = function(o) {
210                    return Ext.extend(subclass, o);
211                };
212
213                return subclass;
214            };
215        }(),
216
217        /**
218         * Proxy to {@link Ext.Base#override}. Please refer {@link Ext.Base#override} for further details.
219         *
220         * @param {Object} cls The class to override
221         * @param {Object} overrides The properties to add to origClass. This should be specified as an object literal
222         * containing one or more properties.
223         * @method override
224         * @markdown
225         * @deprecated 4.1.0 Use {@link Ext#define Ext.define} instead
226         */
227        override: function(cls, overrides) {
228            if (cls.$isClass) {
229                return cls.override(overrides);
230            }
231            else {
232                Ext.apply(cls.prototype, overrides);
233            }
234        }
235    });
236
237    // A full set of static methods to do type checking
238    Ext.apply(Ext, {
239
240        /**
241         * Returns the given value itself if it's not empty, as described in {@link Ext#isEmpty}; returns the default
242         * value (second argument) otherwise.
243         *
244         * @param {Object} value The value to test
245         * @param {Object} defaultValue The value to return if the original value is empty
246         * @param {Boolean} allowBlank (optional) true to allow zero length strings to qualify as non-empty (defaults to false)
247         * @return {Object} value, if non-empty, else defaultValue
248         */
249        valueFrom: function(value, defaultValue, allowBlank){
250            return Ext.isEmpty(value, allowBlank) ? defaultValue : value;
251        },
252
253        /**
254         * Returns the type of the given variable in string format. List of possible values are:
255         *
256         * - `undefined`: If the given value is `undefined`
257         * - `null`: If the given value is `null`
258         * - `string`: If the given value is a string
259         * - `number`: If the given value is a number
260         * - `boolean`: If the given value is a boolean value
261         * - `date`: If the given value is a `Date` object
262         * - `function`: If the given value is a function reference
263         * - `object`: If the given value is an object
264         * - `array`: If the given value is an array
265         * - `regexp`: If the given value is a regular expression
266         * - `element`: If the given value is a DOM Element
267         * - `textnode`: If the given value is a DOM text node and contains something other than whitespace
268         * - `whitespace`: If the given value is a DOM text node and contains only whitespace
269         *
270         * @param {Object} value
271         * @return {String}
272         * @markdown
273         */
274        typeOf: function(value) {
275            if (value === null) {
276                return 'null';
277            }
278
279            var type = typeof value;
280
281            if (type === 'undefined' || type === 'string' || type === 'number' || type === 'boolean') {
282                return type;
283            }
284
285            var typeToString = toString.call(value);
286
287            switch(typeToString) {
288                case '[object Array]':
289                    return 'array';
290                case '[object Date]':
291                    return 'date';
292                case '[object Boolean]':
293                    return 'boolean';
294                case '[object Number]':
295                    return 'number';
296                case '[object RegExp]':
297                    return 'regexp';
298            }
299
300            if (type === 'function') {
301                return 'function';
302            }
303
304            if (type === 'object') {
305                if (value.nodeType !== undefined) {
306                    if (value.nodeType === 3) {
307                        return (/\S/).test(value.nodeValue) ? 'textnode' : 'whitespace';
308                    }
309                    else {
310                        return 'element';
311                    }
312                }
313
314                return 'object';
315            }
316
317            //<debug error>
318            Ext.Error.raise({
319                sourceClass: 'Ext',
320                sourceMethod: 'typeOf',
321                msg: 'Failed to determine the type of the specified value "' + value + '". This is most likely a bug.'
322            });
323            //</debug>
324        },
325
326        /**
327         * Returns true if the passed value is empty, false otherwise. The value is deemed to be empty if it is either:
328         *
329         * - `null`
330         * - `undefined`
331         * - a zero-length array
332         * - a zero-length string (Unless the `allowEmptyString` parameter is set to `true`)
333         *
334         * @param {Object} value The value to test
335         * @param {Boolean} allowEmptyString (optional) true to allow empty strings (defaults to false)
336         * @return {Boolean}
337         * @markdown
338         */
339        isEmpty: function(value, allowEmptyString) {
340            return (value === null) || (value === undefined) || (!allowEmptyString ? value === '' : false) || (Ext.isArray(value) && value.length === 0);
341        },
342
343        /**
344         * Returns true if the passed value is a JavaScript Array, false otherwise.
345         *
346         * @param {Object} target The target to test
347         * @return {Boolean}
348         * @method
349         */
350        isArray: ('isArray' in Array) ? Array.isArray : function(value) {
351            return toString.call(value) === '[object Array]';
352        },
353
354        /**
355         * Returns true if the passed value is a JavaScript Date object, false otherwise.
356         * @param {Object} object The object to test
357         * @return {Boolean}
358         */
359        isDate: function(value) {
360            return toString.call(value) === '[object Date]';
361        },
362
363        /**
364         * Returns true if the passed value is a JavaScript Object, false otherwise.
365         * @param {Object} value The value to test
366         * @return {Boolean}
367         * @method
368         */
369        isObject: (toString.call(null) === '[object Object]') ?
370        function(value) {
371            // check ownerDocument here as well to exclude DOM nodes
372            return value !== null && value !== undefined && toString.call(value) === '[object Object]' && value.ownerDocument === undefined;
373        } :
374        function(value) {
375            return toString.call(value) === '[object Object]';
376        },
377
378        /**
379         * @private
380         */
381        isSimpleObject: function(value) {
382            return value instanceof Object && value.constructor === Object;
383        },
384        /**
385         * Returns true if the passed value is a JavaScript 'primitive', a string, number or boolean.
386         * @param {Object} value The value to test
387         * @return {Boolean}
388         */
389        isPrimitive: function(value) {
390            var type = typeof value;
391
392            return type === 'string' || type === 'number' || type === 'boolean';
393        },
394
395        /**
396         * Returns true if the passed value is a JavaScript Function, false otherwise.
397         * @param {Object} value The value to test
398         * @return {Boolean}
399         * @method
400         */
401        isFunction:
402        // Safari 3.x and 4.x returns 'function' for typeof <NodeList>, hence we need to fall back to using
403        // Object.prototype.toString (slower)
404        (typeof document !== 'undefined' && typeof document.getElementsByTagName('body') === 'function') ? function(value) {
405            return toString.call(value) === '[object Function]';
406        } : function(value) {
407            return typeof value === 'function';
408        },
409
410        /**
411         * Returns true if the passed value is a number. Returns false for non-finite numbers.
412         * @param {Object} value The value to test
413         * @return {Boolean}
414         */
415        isNumber: function(value) {
416            return typeof value === 'number' && isFinite(value);
417        },
418
419        /**
420         * Validates that a value is numeric.
421         * @param {Object} value Examples: 1, '1', '2.34'
422         * @return {Boolean} True if numeric, false otherwise
423         */
424        isNumeric: function(value) {
425            return !isNaN(parseFloat(value)) && isFinite(value);
426        },
427
428        /**
429         * Returns true if the passed value is a string.
430         * @param {Object} value The value to test
431         * @return {Boolean}
432         */
433        isString: function(value) {
434            return typeof value === 'string';
435        },
436
437        /**
438         * Returns true if the passed value is a boolean.
439         *
440         * @param {Object} value The value to test
441         * @return {Boolean}
442         */
443        isBoolean: function(value) {
444            return typeof value === 'boolean';
445        },
446
447        /**
448         * Returns true if the passed value is an HTMLElement
449         * @param {Object} value The value to test
450         * @return {Boolean}
451         */
452        isElement: function(value) {
453            return value ? value.nodeType === 1 : false;
454        },
455
456        /**
457         * Returns true if the passed value is a TextNode
458         * @param {Object} value The value to test
459         * @return {Boolean}
460         */
461        isTextNode: function(value) {
462            return value ? value.nodeName === "#text" : false;
463        },
464
465        /**
466         * Returns true if the passed value is defined.
467         * @param {Object} value The value to test
468         * @return {Boolean}
469         */
470        isDefined: function(value) {
471            return typeof value !== 'undefined';
472        },
473
474        /**
475         * Returns true if the passed value is iterable, false otherwise
476         * @param {Object} value The value to test
477         * @return {Boolean}
478         */
479        isIterable: function(value) {
480            var type = typeof value,
481                checkLength = false;
482            if (value && type != 'string') {
483                // Functions have a length property, so we need to filter them out
484                if (type == 'function') {
485                    // In Safari, NodeList/HTMLCollection both return "function" when using typeof, so we need
486                    // to explicitly check them here.
487                    if (Ext.isSafari) {
488                        checkLength = value instanceof NodeList || value instanceof HTMLCollection;
489                    }
490                } else {
491                    checkLength = true;
492                }
493            }
494            return checkLength ? value.length !== undefined : false;
495        }
496    });
497
498    Ext.apply(Ext, {
499
500        /**
501         * Clone almost any type of variable including array, object, DOM nodes and Date without keeping the old reference
502         * @param {Object} item The variable to clone
503         * @return {Object} clone
504         */
505        clone: function(item) {
506            if (item === null || item === undefined) {
507                return item;
508            }
509
510            // DOM nodes
511            // TODO proxy this to Ext.Element.clone to handle automatic id attribute changing
512            // recursively
513            if (item.nodeType && item.cloneNode) {
514                return item.cloneNode(true);
515            }
516
517            var type = toString.call(item);
518
519            // Date
520            if (type === '[object Date]') {
521                return new Date(item.getTime());
522            }
523
524            var i, j, k, clone, key;
525
526            // Array
527            if (type === '[object Array]') {
528                i = item.length;
529
530                clone = [];
531
532                while (i--) {
533                    clone[i] = Ext.clone(item[i]);
534                }
535            }
536            // Object
537            else if (type === '[object Object]' && item.constructor === Object) {
538                clone = {};
539
540                for (key in item) {
541                    clone[key] = Ext.clone(item[key]);
542                }
543
544                if (enumerables) {
545                    for (j = enumerables.length; j--;) {
546                        k = enumerables[j];
547                        clone[k] = item[k];
548                    }
549                }
550            }
551
552            return clone || item;
553        },
554
555        /**
556         * @private
557         * Generate a unique reference of Ext in the global scope, useful for sandboxing
558         */
559        getUniqueGlobalNamespace: function() {
560            var uniqueGlobalNamespace = this.uniqueGlobalNamespace;
561
562            if (uniqueGlobalNamespace === undefined) {
563                var i = 0;
564
565                do {
566                    uniqueGlobalNamespace = 'ExtBox' + (++i);
567                } while (Ext.global[uniqueGlobalNamespace] !== undefined);
568
569                Ext.global[uniqueGlobalNamespace] = Ext;
570                this.uniqueGlobalNamespace = uniqueGlobalNamespace;
571            }
572
573            return uniqueGlobalNamespace;
574        },
575        
576        /**
577         * @private
578         */
579        functionFactoryCache: {},
580        
581        cacheableFunctionFactory: function() {
582            var me = this,
583                args = Array.prototype.slice.call(arguments),
584                cache = me.functionFactoryCache,
585                idx, fn, ln;
586                
587             if (Ext.isSandboxed) {
588                ln = args.length;
589                if (ln > 0) {
590                    ln--;
591                    args[ln] = 'var Ext=window.' + Ext.name + ';' + args[ln];
592                }
593            }
594            idx = args.join('');
595            fn = cache[idx];
596            if (!fn) {
597                fn = Function.prototype.constructor.apply(Function.prototype, args);
598                
599                cache[idx] = fn;
600            }
601            return fn;
602        },
603        
604        functionFactory: function() {
605            var me = this,
606                args = Array.prototype.slice.call(arguments),
607                ln;
608                
609            if (Ext.isSandboxed) {
610                ln = args.length;
611                if (ln > 0) {
612                    ln--;
613                    args[ln] = 'var Ext=window.' + Ext.name + ';' + args[ln];
614                }
615            }
616     
617            return Function.prototype.constructor.apply(Function.prototype, args);
618        },
619
620        /**
621         * @property
622         * @private
623         */
624        globalEval: ('execScript' in global) ? function(code) {
625            global.execScript(code)
626        } : function(code) {
627            (function(){
628                eval(code);
629            })();
630        },
631
632        /**
633         * @private
634         * @property
635         */
636        Logger: {
637            verbose: emptyFn,
638            log: emptyFn,
639            info: emptyFn,
640            warn: emptyFn,
641            error: function(message) {
642                throw new Error(message);
643            },
644            deprecate: emptyFn
645        }
646    });
647
648    /**
649     * Old alias to {@link Ext#typeOf}
650     * @deprecated 4.0.0 Use {@link Ext#typeOf} instead
651     * @method
652     * @inheritdoc Ext#typeOf
653     */
654    Ext.type = Ext.typeOf;
655
656})();