Upgrade to ExtJS 4.0.7 - Released 10/19/2011
[extjs.git] / src / core / src / class / Base.js
index 468d0cf..3c0de32 100644 (file)
@@ -1,11 +1,26 @@
+/*
+
+This file is part of Ext JS 4
+
+Copyright (c) 2011 Sencha Inc
+
+Contact:  http://www.sencha.com/contact
+
+GNU General Public License Usage
+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.
+
+If you are unsure which license is appropriate for your use, please contact the sales department at http://www.sencha.com/contact.
+
+*/
 /**
  * @author Jacky Nguyen <jacky@sencha.com>
  * @docauthor Jacky Nguyen <jacky@sencha.com>
  * @class Ext.Base
  *
 /**
  * @author Jacky Nguyen <jacky@sencha.com>
  * @docauthor Jacky Nguyen <jacky@sencha.com>
  * @class Ext.Base
  *
- * The root of all classes created with {@link Ext#define}
- * All prototype and static members of this class are inherited by any other class
+ * The root of all classes created with {@link Ext#define}.
  *
  *
+ * Ext.Base is the building block of all Ext classes. All classes in Ext inherit from Ext.Base.
+ * All prototype and static members of this class are inherited by all other classes.
  */
 (function(flexSetter) {
 
  */
 (function(flexSetter) {
 
@@ -50,23 +65,17 @@ var Base = Ext.Base = function() {};
          *     var clone = snowLeopard.clone();
          *     alert(Ext.getClassName(clone));             // alerts 'My.SnowLeopard'
          *
          *     var clone = snowLeopard.clone();
          *     alert(Ext.getClassName(clone));             // alerts 'My.SnowLeopard'
          *
-         * @type Class
+         * @type Ext.Class
          * @protected
          * @protected
-         * @markdown
          */
         self: Base,
 
          */
         self: Base,
 
-        /**
-         * Default constructor, simply returns `this`
-         *
-         * @constructor
-         * @protected
-         * @return {Object} this
-         */
+        // Default constructor, simply returns `this`
         constructor: function() {
             return this;
         },
 
         constructor: function() {
             return this;
         },
 
+        //<feature classSystem.config>
         /**
          * Initialize configuration for this class. a typical example:
          *
         /**
          * Initialize configuration for this class. a typical example:
          *
@@ -93,7 +102,6 @@ var Base = Ext.Base = function() {};
          * @protected
          * @param {Object} config
          * @return {Object} mixins The mixin prototypes as key - value pairs
          * @protected
          * @param {Object} config
          * @return {Object} mixins The mixin prototypes as key - value pairs
-         * @markdown
          */
         initConfig: function(config) {
             if (!this.$configInited) {
          */
         initConfig: function(config) {
             if (!this.$configInited) {
@@ -128,6 +136,7 @@ var Base = Ext.Base = function() {};
 
             return this;
         }),
 
             return this;
         }),
+        //</feature>
 
         /**
          * Call the parent's overridden method. For example:
 
         /**
          * Call the parent's overridden method. For example:
@@ -166,8 +175,7 @@ var Base = Ext.Base = function() {};
          * @protected
          * @param {Array/Arguments} args The arguments, either an array or the `arguments` object
          * from the current method, for example: `this.callParent(arguments)`
          * @protected
          * @param {Array/Arguments} args The arguments, either an array or the `arguments` object
          * from the current method, for example: `this.callParent(arguments)`
-         * @return {Mixed} Returns the result from the superclass' method
-         * @markdown
+         * @return {Object} Returns the result from the superclass' method
          */
         callParent: function(args) {
             var method = this.callParent.caller,
          */
         callParent: function(args) {
             var method = this.callParent.caller,
@@ -215,25 +223,25 @@ var Base = Ext.Base = function() {};
          *             totalCreated: 0,
          *             speciesName: 'Cat' // My.Cat.speciesName = 'Cat'
          *         },
          *             totalCreated: 0,
          *             speciesName: 'Cat' // My.Cat.speciesName = 'Cat'
          *         },
-         *  
+         *
          *         constructor: function() {
          *             var statics = this.statics();
          *         constructor: function() {
          *             var statics = this.statics();
-         *  
+         *
          *             alert(statics.speciesName);     // always equals to 'Cat' no matter what 'this' refers to
          *                                             // equivalent to: My.Cat.speciesName
          *             alert(statics.speciesName);     // always equals to 'Cat' no matter what 'this' refers to
          *                                             // equivalent to: My.Cat.speciesName
-         *  
+         *
          *             alert(this.self.speciesName);   // dependent on 'this'
          *             alert(this.self.speciesName);   // dependent on 'this'
-         *  
+         *
          *             statics.totalCreated++;
          *             statics.totalCreated++;
-         *  
+         *
          *             return this;
          *         },
          *             return this;
          *         },
-         *  
+         *
          *         clone: function() {
          *             var cloned = new this.self;                      // dependent on 'this'
          *         clone: function() {
          *             var cloned = new this.self;                      // dependent on 'this'
-         *  
+         *
          *             cloned.groupName = this.statics().speciesName;   // equivalent to: My.Cat.speciesName
          *             cloned.groupName = this.statics().speciesName;   // equivalent to: My.Cat.speciesName
-         *  
+         *
          *             return cloned;
          *         }
          *     });
          *             return cloned;
          *         }
          *     });
@@ -241,11 +249,11 @@ var Base = Ext.Base = function() {};
          *
          *     Ext.define('My.SnowLeopard', {
          *         extend: 'My.Cat',
          *
          *     Ext.define('My.SnowLeopard', {
          *         extend: 'My.Cat',
-         *  
+         *
          *         statics: {
          *             speciesName: 'Snow Leopard'     // My.SnowLeopard.speciesName = 'Snow Leopard'
          *         },
          *         statics: {
          *             speciesName: 'Snow Leopard'     // My.SnowLeopard.speciesName = 'Snow Leopard'
          *         },
-         *  
+         *
          *         constructor: function() {
          *             this.callParent();
          *         }
          *         constructor: function() {
          *             this.callParent();
          *         }
@@ -262,8 +270,7 @@ var Base = Ext.Base = function() {};
          *     alert(My.Cat.totalCreated);             // alerts 3
          *
          * @protected
          *     alert(My.Cat.totalCreated);             // alerts 3
          *
          * @protected
-         * @return {Class}
-         * @markdown
+         * @return {Ext.Class}
          */
         statics: function() {
             var method = this.statics.caller,
          */
         statics: function() {
             var method = this.statics.caller,
@@ -282,7 +289,7 @@ var Base = Ext.Base = function() {};
          *     Ext.define('My.Cat', {
          *         constructor: function() {
          *             alert("I'm a cat!");
          *     Ext.define('My.Cat', {
          *         constructor: function() {
          *             alert("I'm a cat!");
-         *   
+         *
          *             return this;
          *         }
          *     });
          *             return this;
          *         }
          *     });
@@ -290,11 +297,11 @@ var Base = Ext.Base = function() {};
          *     My.Cat.override({
          *         constructor: function() {
          *             alert("I'm going to be a cat!");
          *     My.Cat.override({
          *         constructor: function() {
          *             alert("I'm going to be a cat!");
-         *   
+         *
          *             var instance = this.callOverridden();
          *             var instance = this.callOverridden();
-         *   
+         *
          *             alert("Meeeeoooowwww");
          *             alert("Meeeeoooowwww");
-         *   
+         *
          *             return instance;
          *         }
          *     });
          *             return instance;
          *         }
          *     });
@@ -304,8 +311,8 @@ var Base = Ext.Base = function() {};
          *                               // alerts "Meeeeoooowwww"
          *
          * @param {Array/Arguments} args The arguments, either an array or the `arguments` object
          *                               // alerts "Meeeeoooowwww"
          *
          * @param {Array/Arguments} args The arguments, either an array or the `arguments` object
-         * @return {Mixed} Returns the result after calling the overridden method
-         * @markdown
+         * @return {Object} Returns the result after calling the overridden method
+         * @protected
          */
         callOverridden: function(args) {
             var method = this.callOverridden.caller;
          */
         callOverridden: function(args) {
             var method = this.callOverridden.caller;
@@ -343,15 +350,16 @@ var Base = Ext.Base = function() {};
          *     Ext.define('My.cool.Class', {
          *         ...
          *     });
          *     Ext.define('My.cool.Class', {
          *         ...
          *     });
-         *      
+         *
          *     My.cool.Class.create({
          *         someConfig: true
          *     });
          *
          *     My.cool.Class.create({
          *         someConfig: true
          *     });
          *
-         * @property create
+         * All parameters are passed to the constructor of the class.
+         *
+         * @return {Object} the created instance.
          * @static
          * @static
-         * @type Function
-         * @markdown
+         * @inheritable
          */
         create: function() {
             return Ext.create.apply(Ext, [this].concat(Array.prototype.slice.call(arguments, 0)));
          */
         create: function() {
             return Ext.create.apply(Ext, [this].concat(Array.prototype.slice.call(arguments, 0)));
@@ -359,23 +367,25 @@ var Base = Ext.Base = function() {};
 
         /**
          * @private
 
         /**
          * @private
+         * @inheritable
          */
          */
-        own: flexSetter(function(name, value) {
-            if (typeof value === 'function') {
+        own: function(name, value) {
+            if (typeof value == 'function') {
                 this.ownMethod(name, value);
             }
             else {
                 this.prototype[name] = value;
             }
                 this.ownMethod(name, value);
             }
             else {
                 this.prototype[name] = value;
             }
-        }),
+        },
 
         /**
          * @private
 
         /**
          * @private
+         * @inheritable
          */
         ownMethod: function(name, fn) {
             var originalFn;
 
          */
         ownMethod: function(name, fn) {
             var originalFn;
 
-            if (fn.$owner !== undefined && fn !== Ext.emptyFn) {
+            if (typeof fn.$owner !== 'undefined' && fn !== Ext.emptyFn) {
                 originalFn = fn;
 
                 fn = function() {
                 originalFn = fn;
 
                 fn = function() {
@@ -409,11 +419,10 @@ var Base = Ext.Base = function() {};
          *         method2: function() { ... }     // My.cool.Class.method2 = function() { ... };
          *     });
          *
          *         method2: function() { ... }     // My.cool.Class.method2 = function() { ... };
          *     });
          *
-         * @property addStatics
-         * @static
-         * @type Function
          * @param {Object} members
          * @param {Object} members
-         * @markdown
+         * @return {Ext.Base} this
+         * @static
+         * @inheritable
          */
         addStatics: function(members) {
             for (var name in members) {
          */
         addStatics: function(members) {
             for (var name in members) {
@@ -425,6 +434,48 @@ var Base = Ext.Base = function() {};
             return this;
         },
 
             return this;
         },
 
+        /**
+         * @private
+         * @param {Object} members
+         */
+        addInheritableStatics: function(members) {
+            var inheritableStatics,
+                hasInheritableStatics,
+                prototype = this.prototype,
+                name, member;
+
+            inheritableStatics = prototype.$inheritableStatics;
+            hasInheritableStatics = prototype.$hasInheritableStatics;
+
+            if (!inheritableStatics) {
+                inheritableStatics = prototype.$inheritableStatics = [];
+                hasInheritableStatics = prototype.$hasInheritableStatics = {};
+            }
+
+            //<debug>
+            var className = Ext.getClassName(this);
+            //</debug>
+
+            for (name in members) {
+                if (members.hasOwnProperty(name)) {
+                    member = members[name];
+                    //<debug>
+                    if (typeof member == 'function') {
+                        member.displayName = className + '.' + name;
+                    }
+                    //</debug>
+                    this[name] = member;
+
+                    if (!hasInheritableStatics[name]) {
+                        hasInheritableStatics[name] = true;
+                        inheritableStatics.push(name);
+                    }
+                }
+            }
+
+            return this;
+        },
+
         /**
          * Add methods / properties to the prototype of this class.
          *
         /**
          * Add methods / properties to the prototype of this class.
          *
@@ -443,15 +494,14 @@ var Base = Ext.Base = function() {};
          *      var kitty = new My.awesome.Cat;
          *      kitty.meow();
          *
          *      var kitty = new My.awesome.Cat;
          *      kitty.meow();
          *
-         * @property implement
-         * @static
-         * @type Function
          * @param {Object} members
          * @param {Object} members
-         * @markdown
+         * @static
+         * @inheritable
          */
         implement: function(members) {
             var prototype = this.prototype,
          */
         implement: function(members) {
             var prototype = this.prototype,
-                name, i, member, previous;
+                enumerables = Ext.enumerables,
+                name, i, member;
             //<debug>
             var className = Ext.getClassName(this);
             //</debug>
             //<debug>
             var className = Ext.getClassName(this);
             //</debug>
@@ -473,9 +523,7 @@ var Base = Ext.Base = function() {};
                 }
             }
 
                 }
             }
 
-            if (Ext.enumerables) {
-                var enumerables = Ext.enumerables;
-
+            if (enumerables) {
                 for (i = enumerables.length; i--;) {
                     name = enumerables[i];
 
                 for (i = enumerables.length; i--;) {
                     name = enumerables[i];
 
@@ -510,13 +558,11 @@ var Base = Ext.Base = function() {};
          *     alert(steve.money); // alerts '$$$'
          *     steve.printMoney(); // alerts '$$$$$$$'
          *
          *     alert(steve.money); // alerts '$$$'
          *     steve.printMoney(); // alerts '$$$$$$$'
          *
-         * @property borrow
-         * @static
-         * @type Function
          * @param {Ext.Base} fromClass The class to borrow members from
          * @param {Ext.Base} fromClass The class to borrow members from
-         * @param {Array/String} members The names of the members to borrow
+         * @param {String/String[]} members The names of the members to borrow
          * @return {Ext.Base} this
          * @return {Ext.Base} this
-         * @markdown
+         * @static
+         * @inheritable
          */
         borrow: function(fromClass, members) {
             var fromPrototype = fromClass.prototype,
          */
         borrow: function(fromClass, members) {
             var fromPrototype = fromClass.prototype,
@@ -561,17 +607,35 @@ var Base = Ext.Base = function() {};
          *                               // alerts "I'm a cat!"
          *                               // alerts "Meeeeoooowwww"
          *
          *                               // alerts "I'm a cat!"
          *                               // alerts "Meeeeoooowwww"
          *
-         * @property override
-         * @static
-         * @type Function
          * @param {Object} members
          * @return {Ext.Base} this
          * @param {Object} members
          * @return {Ext.Base} this
-         * @markdown
+         * @static
+         * @inheritable
          */
         override: function(members) {
             var prototype = this.prototype,
          */
         override: function(members) {
             var prototype = this.prototype,
+                enumerables = Ext.enumerables,
                 name, i, member, previous;
 
                 name, i, member, previous;
 
+            if (arguments.length === 2) {
+                name = members;
+                member = arguments[1];
+
+                if (typeof member == 'function') {
+                    if (typeof prototype[name] == 'function') {
+                        previous = prototype[name];
+                        member.$previous = previous;
+                    }
+
+                    this.ownMethod(name, member);
+                }
+                else {
+                    prototype[name] = member;
+                }
+
+                return this;
+            }
+
             for (name in members) {
                 if (members.hasOwnProperty(name)) {
                     member = members[name];
             for (name in members) {
                 if (members.hasOwnProperty(name)) {
                     member = members[name];
@@ -590,14 +654,12 @@ var Base = Ext.Base = function() {};
                 }
             }
 
                 }
             }
 
-            if (Ext.enumerables) {
-                var enumerables = Ext.enumerables;
-
+            if (enumerables) {
                 for (i = enumerables.length; i--;) {
                     name = enumerables[i];
 
                     if (members.hasOwnProperty(name)) {
                 for (i = enumerables.length; i--;) {
                     name = enumerables[i];
 
                     if (members.hasOwnProperty(name)) {
-                        if (prototype[name] !== undefined) {
+                        if (typeof prototype[name] !== 'undefined') {
                             previous = prototype[name];
                             members[name].$previous = previous;
                         }
                             previous = prototype[name];
                             members[name].$previous = previous;
                         }
@@ -610,44 +672,58 @@ var Base = Ext.Base = function() {};
             return this;
         },
 
             return this;
         },
 
+        //<feature classSystem.mixins>
         /**
          * Used internally by the mixins pre-processor
          * @private
         /**
          * Used internally by the mixins pre-processor
          * @private
+         * @inheritable
          */
          */
-        mixin: flexSetter(function(name, cls) {
+        mixin: function(name, cls) {
             var mixin = cls.prototype,
                 my = this.prototype,
             var mixin = cls.prototype,
                 my = this.prototype,
-                i, fn;
+                key, fn;
 
 
-            for (i in mixin) {
-                if (mixin.hasOwnProperty(i)) {
-                    if (my[i] === undefined) {
-                        if (typeof mixin[i] === 'function') {
-                            fn = mixin[i];
+            for (key in mixin) {
+                if (mixin.hasOwnProperty(key)) {
+                    if (typeof my[key] === 'undefined' && key !== 'mixins' && key !== 'mixinId') {
+                        if (typeof mixin[key] === 'function') {
+                            fn = mixin[key];
 
 
-                            if (fn.$owner === undefined) {
-                                this.ownMethod(i, fn);
+                            if (typeof fn.$owner === 'undefined') {
+                                this.ownMethod(key, fn);
                             }
                             else {
                             }
                             else {
-                                my[i] = fn;
+                                my[key] = fn;
                             }
                         }
                         else {
                             }
                         }
                         else {
-                            my[i] = mixin[i];
+                            my[key] = mixin[key];
                         }
                     }
                         }
                     }
-                    else if (i === 'config' && my.config && mixin.config) {
+                    //<feature classSystem.config>
+                    else if (key === 'config' && my.config && mixin.config) {
                         Ext.Object.merge(my.config, mixin.config);
                     }
                         Ext.Object.merge(my.config, mixin.config);
                     }
+                    //</feature>
                 }
             }
 
                 }
             }
 
-            if (my.mixins === undefined) {
-                my.mixins = {};
+            if (typeof mixin.onClassMixedIn !== 'undefined') {
+                mixin.onClassMixedIn.call(cls, this);
+            }
+
+            if (!my.hasOwnProperty('mixins')) {
+                if ('mixins' in my) {
+                    my.mixins = Ext.Object.merge({}, my.mixins);
+                }
+                else {
+                    my.mixins = {};
+                }
             }
 
             my.mixins[name] = mixin;
             }
 
             my.mixins[name] = mixin;
-        }),
+        },
+        //</feature>
 
         /**
          * Get the current class' name in string format.
 
         /**
          * Get the current class' name in string format.
@@ -661,7 +737,8 @@ var Base = Ext.Base = function() {};
          *     My.cool.Class.getName(); // 'My.cool.Class'
          *
          * @return {String} className
          *     My.cool.Class.getName(); // 'My.cool.Class'
          *
          * @return {String} className
-         * @markdown
+         * @static
+         * @inheritable
          */
         getName: function() {
             return Ext.getClassName(this);
          */
         getName: function() {
             return Ext.getClassName(this);
@@ -688,17 +765,19 @@ var Base = Ext.Base = function() {};
          *
          *     test.method5(); // test.method3() -> test.method1()
          *
          *
          *     test.method5(); // test.method3() -> test.method1()
          *
-         * @property createAlias
-         * @static
-         * @type Function
          * @param {String/Object} alias The new method name, or an object to set multiple aliases. See
          * {@link Ext.Function#flexSetter flexSetter}
          * @param {String/Object} origin The original method name
          * @param {String/Object} alias The new method name, or an object to set multiple aliases. See
          * {@link Ext.Function#flexSetter flexSetter}
          * @param {String/Object} origin The original method name
-         * @markdown
+         * @static
+         * @inheritable
+         * @method
          */
         createAlias: flexSetter(function(alias, origin) {
          */
         createAlias: flexSetter(function(alias, origin) {
-            this.prototype[alias] = this.prototype[origin];
+            this.prototype[alias] = function() {
+                return this[origin].apply(this, arguments);
+            }
         })
     });
 
 })(Ext.Function.flexSetter);
         })
     });
 
 })(Ext.Function.flexSetter);
+