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.
16 * @author Jacky Nguyen <jacky@sencha.com>
17 * @docauthor Jacky Nguyen <jacky@sencha.com>
20 * The root of all classes created with {@link Ext#define}.
22 * Ext.Base is the building block of all Ext classes. All classes in Ext inherit from Ext.Base.
23 * All prototype and static members of this class are inherited by all other classes.
25 (function(flexSetter) {
27 var Base = Ext.Base = function() {};
29 $className: 'Ext.Base',
34 * Get the reference to the current class from which this object was instantiated. Unlike {@link Ext.Base#statics},
35 * `this.self` is scope-dependent and it's meant to be used for dynamic inheritance. See {@link Ext.Base#statics}
36 * for a detailed comparison
38 * Ext.define('My.Cat', {
40 * speciesName: 'Cat' // My.Cat.speciesName = 'Cat'
43 * constructor: function() {
44 * alert(this.self.speciesName); / dependent on 'this'
50 * return new this.self();
55 * Ext.define('My.SnowLeopard', {
58 * speciesName: 'Snow Leopard' // My.SnowLeopard.speciesName = 'Snow Leopard'
62 * var cat = new My.Cat(); // alerts 'Cat'
63 * var snowLeopard = new My.SnowLeopard(); // alerts 'Snow Leopard'
65 * var clone = snowLeopard.clone();
66 * alert(Ext.getClassName(clone)); // alerts 'My.SnowLeopard'
73 // Default constructor, simply returns `this`
74 constructor: function() {
78 //<feature classSystem.config>
80 * Initialize configuration for this class. a typical example:
82 * Ext.define('My.awesome.Class', {
83 * // The default config
89 * constructor: function(config) {
90 * this.initConfig(config);
96 * var awesome = new My.awesome.Class({
97 * name: 'Super Awesome'
100 * alert(awesome.getName()); // 'Super Awesome'
103 * @param {Object} config
104 * @return {Object} mixins The mixin prototypes as key - value pairs
106 initConfig: function(config) {
107 if (!this.$configInited) {
108 this.config = Ext.Object.merge({}, this.config || {}, config || {});
110 this.applyConfig(this.config);
112 this.$configInited = true;
121 setConfig: function(config) {
122 this.applyConfig(config || {});
130 applyConfig: flexSetter(function(name, value) {
131 var setter = 'set' + Ext.String.capitalize(name);
133 if (typeof this[setter] === 'function') {
134 this[setter].call(this, value);
142 * Call the parent's overridden method. For example:
144 * Ext.define('My.own.A', {
145 * constructor: function(test) {
150 * Ext.define('My.own.B', {
151 * extend: 'My.own.A',
153 * constructor: function(test) {
156 * this.callParent([test + 1]);
160 * Ext.define('My.own.C', {
161 * extend: 'My.own.B',
163 * constructor: function() {
164 * alert("Going to call parent's overriden constructor...");
166 * this.callParent(arguments);
170 * var a = new My.own.A(1); // alerts '1'
171 * var b = new My.own.B(1); // alerts '1', then alerts '2'
172 * var c = new My.own.C(2); // alerts "Going to call parent's overriden constructor..."
173 * // alerts '2', then alerts '3'
176 * @param {Array/Arguments} args The arguments, either an array or the `arguments` object
177 * from the current method, for example: `this.callParent(arguments)`
178 * @return {Object} Returns the result from the superclass' method
180 callParent: function(args) {
181 var method = this.callParent.caller,
182 parentClass, methodName;
184 if (!method.$owner) {
186 if (!method.caller) {
188 sourceClass: Ext.getClassName(this),
189 sourceMethod: "callParent",
190 msg: "Attempting to call a protected method from the public scope, which is not allowed"
195 method = method.caller;
198 parentClass = method.$owner.superclass;
199 methodName = method.$name;
202 if (!(methodName in parentClass)) {
204 sourceClass: Ext.getClassName(this),
205 sourceMethod: methodName,
206 msg: "this.callParent() was called but there's no such method (" + methodName +
207 ") found in the parent class (" + (Ext.getClassName(parentClass) || 'Object') + ")"
212 return parentClass[methodName].apply(this, args || []);
217 * Get the reference to the class from which this object was instantiated. Note that unlike {@link Ext.Base#self},
218 * `this.statics()` is scope-independent and it always returns the class from which it was called, regardless of what
219 * `this` points to during run-time
221 * Ext.define('My.Cat', {
224 * speciesName: 'Cat' // My.Cat.speciesName = 'Cat'
227 * constructor: function() {
228 * var statics = this.statics();
230 * alert(statics.speciesName); // always equals to 'Cat' no matter what 'this' refers to
231 * // equivalent to: My.Cat.speciesName
233 * alert(this.self.speciesName); // dependent on 'this'
235 * statics.totalCreated++;
240 * clone: function() {
241 * var cloned = new this.self; // dependent on 'this'
243 * cloned.groupName = this.statics().speciesName; // equivalent to: My.Cat.speciesName
250 * Ext.define('My.SnowLeopard', {
254 * speciesName: 'Snow Leopard' // My.SnowLeopard.speciesName = 'Snow Leopard'
257 * constructor: function() {
262 * var cat = new My.Cat(); // alerts 'Cat', then alerts 'Cat'
264 * var snowLeopard = new My.SnowLeopard(); // alerts 'Cat', then alerts 'Snow Leopard'
266 * var clone = snowLeopard.clone();
267 * alert(Ext.getClassName(clone)); // alerts 'My.SnowLeopard'
268 * alert(clone.groupName); // alerts 'Cat'
270 * alert(My.Cat.totalCreated); // alerts 3
273 * @return {Ext.Class}
275 statics: function() {
276 var method = this.statics.caller,
283 return method.$owner;
287 * Call the original method that was previously overridden with {@link Ext.Base#override}
289 * Ext.define('My.Cat', {
290 * constructor: function() {
291 * alert("I'm a cat!");
298 * constructor: function() {
299 * alert("I'm going to be a cat!");
301 * var instance = this.callOverridden();
303 * alert("Meeeeoooowwww");
309 * var kitty = new My.Cat(); // alerts "I'm going to be a cat!"
310 * // alerts "I'm a cat!"
311 * // alerts "Meeeeoooowwww"
313 * @param {Array/Arguments} args The arguments, either an array or the `arguments` object
314 * @return {Object} Returns the result after calling the overridden method
317 callOverridden: function(args) {
318 var method = this.callOverridden.caller;
321 if (!method.$owner) {
323 sourceClass: Ext.getClassName(this),
324 sourceMethod: "callOverridden",
325 msg: "Attempting to call a protected method from the public scope, which is not allowed"
329 if (!method.$previous) {
331 sourceClass: Ext.getClassName(this),
332 sourceMethod: "callOverridden",
333 msg: "this.callOverridden was called in '" + method.$name +
334 "' but this method has never been overridden"
339 return method.$previous.apply(this, args || []);
342 destroy: function() {}
345 // These static properties will be copied to every newly created class with {@link Ext#define}
346 Ext.apply(Ext.Base, {
348 * Create a new instance of this Class.
350 * Ext.define('My.cool.Class', {
354 * My.cool.Class.create({
358 * All parameters are passed to the constructor of the class.
360 * @return {Object} the created instance.
365 return Ext.create.apply(Ext, [this].concat(Array.prototype.slice.call(arguments, 0)));
372 own: function(name, value) {
373 if (typeof value == 'function') {
374 this.ownMethod(name, value);
377 this.prototype[name] = value;
385 ownMethod: function(name, fn) {
388 if (typeof fn.$owner !== 'undefined' && fn !== Ext.emptyFn) {
392 return originalFn.apply(this, arguments);
398 className = Ext.getClassName(this);
400 fn.displayName = className + '#' + name;
406 this.prototype[name] = fn;
410 * Add / override static properties of this class.
412 * Ext.define('My.cool.Class', {
416 * My.cool.Class.addStatics({
417 * someProperty: 'someValue', // My.cool.Class.someProperty = 'someValue'
418 * method1: function() { ... }, // My.cool.Class.method1 = function() { ... };
419 * method2: function() { ... } // My.cool.Class.method2 = function() { ... };
422 * @param {Object} members
423 * @return {Ext.Base} this
427 addStatics: function(members) {
428 for (var name in members) {
429 if (members.hasOwnProperty(name)) {
430 this[name] = members[name];
439 * @param {Object} members
441 addInheritableStatics: function(members) {
442 var inheritableStatics,
443 hasInheritableStatics,
444 prototype = this.prototype,
447 inheritableStatics = prototype.$inheritableStatics;
448 hasInheritableStatics = prototype.$hasInheritableStatics;
450 if (!inheritableStatics) {
451 inheritableStatics = prototype.$inheritableStatics = [];
452 hasInheritableStatics = prototype.$hasInheritableStatics = {};
456 var className = Ext.getClassName(this);
459 for (name in members) {
460 if (members.hasOwnProperty(name)) {
461 member = members[name];
463 if (typeof member == 'function') {
464 member.displayName = className + '.' + name;
469 if (!hasInheritableStatics[name]) {
470 hasInheritableStatics[name] = true;
471 inheritableStatics.push(name);
480 * Add methods / properties to the prototype of this class.
482 * Ext.define('My.awesome.Cat', {
483 * constructor: function() {
488 * My.awesome.Cat.implement({
490 * alert('Meowww...');
494 * var kitty = new My.awesome.Cat;
497 * @param {Object} members
501 implement: function(members) {
502 var prototype = this.prototype,
503 enumerables = Ext.enumerables,
506 var className = Ext.getClassName(this);
508 for (name in members) {
509 if (members.hasOwnProperty(name)) {
510 member = members[name];
512 if (typeof member === 'function') {
513 member.$owner = this;
517 member.displayName = className + '#' + name;
522 prototype[name] = member;
527 for (i = enumerables.length; i--;) {
528 name = enumerables[i];
530 if (members.hasOwnProperty(name)) {
531 member = members[name];
532 member.$owner = this;
534 prototype[name] = member;
541 * Borrow another class' members to the prototype of this class.
543 * Ext.define('Bank', {
545 * printMoney: function() {
550 * Ext.define('Thief', {
554 * Thief.borrow(Bank, ['money', 'printMoney']);
556 * var steve = new Thief();
558 * alert(steve.money); // alerts '$$$'
559 * steve.printMoney(); // alerts '$$$$$$$'
561 * @param {Ext.Base} fromClass The class to borrow members from
562 * @param {String/String[]} members The names of the members to borrow
563 * @return {Ext.Base} this
567 borrow: function(fromClass, members) {
568 var fromPrototype = fromClass.prototype,
571 members = Ext.Array.from(members);
573 for (i = 0, ln = members.length; i < ln; i++) {
576 this.own(member, fromPrototype[member]);
583 * Override prototype members of this class. Overridden methods can be invoked via
584 * {@link Ext.Base#callOverridden}
586 * Ext.define('My.Cat', {
587 * constructor: function() {
588 * alert("I'm a cat!");
595 * constructor: function() {
596 * alert("I'm going to be a cat!");
598 * var instance = this.callOverridden();
600 * alert("Meeeeoooowwww");
606 * var kitty = new My.Cat(); // alerts "I'm going to be a cat!"
607 * // alerts "I'm a cat!"
608 * // alerts "Meeeeoooowwww"
610 * @param {Object} members
611 * @return {Ext.Base} this
615 override: function(members) {
616 var prototype = this.prototype,
617 enumerables = Ext.enumerables,
618 name, i, member, previous;
620 if (arguments.length === 2) {
622 member = arguments[1];
624 if (typeof member == 'function') {
625 if (typeof prototype[name] == 'function') {
626 previous = prototype[name];
627 member.$previous = previous;
630 this.ownMethod(name, member);
633 prototype[name] = member;
639 for (name in members) {
640 if (members.hasOwnProperty(name)) {
641 member = members[name];
643 if (typeof member === 'function') {
644 if (typeof prototype[name] === 'function') {
645 previous = prototype[name];
646 member.$previous = previous;
649 this.ownMethod(name, member);
652 prototype[name] = member;
658 for (i = enumerables.length; i--;) {
659 name = enumerables[i];
661 if (members.hasOwnProperty(name)) {
662 if (typeof prototype[name] !== 'undefined') {
663 previous = prototype[name];
664 members[name].$previous = previous;
667 this.ownMethod(name, members[name]);
675 //<feature classSystem.mixins>
677 * Used internally by the mixins pre-processor
681 mixin: function(name, cls) {
682 var mixin = cls.prototype,
687 if (mixin.hasOwnProperty(key)) {
688 if (typeof my[key] === 'undefined' && key !== 'mixins' && key !== 'mixinId') {
689 if (typeof mixin[key] === 'function') {
692 if (typeof fn.$owner === 'undefined') {
693 this.ownMethod(key, fn);
700 my[key] = mixin[key];
703 //<feature classSystem.config>
704 else if (key === 'config' && my.config && mixin.config) {
705 Ext.Object.merge(my.config, mixin.config);
711 if (typeof mixin.onClassMixedIn !== 'undefined') {
712 mixin.onClassMixedIn.call(cls, this);
715 if (!my.hasOwnProperty('mixins')) {
716 if ('mixins' in my) {
717 my.mixins = Ext.Object.merge({}, my.mixins);
724 my.mixins[name] = mixin;
729 * Get the current class' name in string format.
731 * Ext.define('My.cool.Class', {
732 * constructor: function() {
733 * alert(this.self.getName()); // alerts 'My.cool.Class'
737 * My.cool.Class.getName(); // 'My.cool.Class'
739 * @return {String} className
743 getName: function() {
744 return Ext.getClassName(this);
748 * Create aliases for existing prototype methods. Example:
750 * Ext.define('My.cool.Class', {
751 * method1: function() { ... },
752 * method2: function() { ... }
755 * var test = new My.cool.Class();
757 * My.cool.Class.createAlias({
758 * method3: 'method1',
762 * test.method3(); // test.method1()
764 * My.cool.Class.createAlias('method5', 'method3');
766 * test.method5(); // test.method3() -> test.method1()
768 * @param {String/Object} alias The new method name, or an object to set multiple aliases. See
769 * {@link Ext.Function#flexSetter flexSetter}
770 * @param {String/Object} origin The original method name
775 createAlias: flexSetter(function(alias, origin) {
776 this.prototype[alias] = function() {
777 return this[origin].apply(this, arguments);
782 })(Ext.Function.flexSetter);