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>
18 * @class Ext.ClassManager
20 * Ext.ClassManager manages all classes and handles mapping from string class name to
21 * actual class objects throughout the whole framework. It is not generally accessed directly, rather through
22 * these convenient shorthands:
24 * - {@link Ext#define Ext.define}
25 * - {@link Ext#create Ext.create}
26 * - {@link Ext#widget Ext.widget}
27 * - {@link Ext#getClass Ext.getClass}
28 * - {@link Ext#getClassName Ext.getClassName}
32 * Ext.define(className, properties);
34 * in which `properties` is an object represent a collection of properties that apply to the class. See
35 * {@link Ext.ClassManager#create} for more detailed instructions.
37 * Ext.define('Person', {
40 * constructor: function(name) {
48 * eat: function(foodType) {
49 * alert("I'm eating: " + foodType);
55 * var aaron = new Person("Aaron");
56 * aaron.eat("Sandwich"); // alert("I'm eating: Sandwich");
58 * Ext.Class has a powerful set of extensible {@link Ext.Class#registerPreprocessor pre-processors} which takes care of
59 * everything related to class creation, including but not limited to inheritance, mixins, configuration, statics, etc.
63 * Ext.define('Developer', {
66 * constructor: function(name, isGeek) {
67 * this.isGeek = isGeek;
69 * // Apply a method from the parent class' prototype
70 * this.callParent([name]);
76 * code: function(language) {
77 * alert("I'm coding in: " + language);
85 * var jacky = new Developer("Jacky", true);
86 * jacky.code("JavaScript"); // alert("I'm coding in: JavaScript");
87 * // alert("I'm eating: Bugs");
89 * See {@link Ext.Base#callParent} for more details on calling superclass' methods
93 * Ext.define('CanPlayGuitar', {
94 * playGuitar: function() {
95 * alert("F#...G...D...A");
99 * Ext.define('CanComposeSongs', {
100 * composeSongs: function() { ... }
103 * Ext.define('CanSing', {
105 * alert("I'm on the highway to hell...")
109 * Ext.define('Musician', {
113 * canPlayGuitar: 'CanPlayGuitar',
114 * canComposeSongs: 'CanComposeSongs',
119 * Ext.define('CoolPerson', {
123 * canPlayGuitar: 'CanPlayGuitar',
130 * this.mixins.canSing.sing.call(this);
132 * alert("[Playing guitar at the same time...]");
138 * var me = new CoolPerson("Jacky");
140 * me.sing(); // alert("Ahem...");
141 * // alert("I'm on the highway to hell...");
142 * // alert("[Playing guitar at the same time...]");
143 * // alert("F#...G...D...A");
147 * Ext.define('SmartPhone', {
149 * hasTouchScreen: false,
150 * operatingSystem: 'Other',
154 * isExpensive: false,
156 * constructor: function(config) {
157 * this.initConfig(config);
162 * applyPrice: function(price) {
163 * this.isExpensive = (price > 500);
168 * applyOperatingSystem: function(operatingSystem) {
169 * if (!(/^(iOS|Android|BlackBerry)$/i).test(operatingSystem)) {
173 * return operatingSystem;
177 * var iPhone = new SmartPhone({
178 * hasTouchScreen: true,
179 * operatingSystem: 'iOS'
182 * iPhone.getPrice(); // 500;
183 * iPhone.getOperatingSystem(); // 'iOS'
184 * iPhone.getHasTouchScreen(); // true;
185 * iPhone.hasTouchScreen(); // true
187 * iPhone.isExpensive; // false;
188 * iPhone.setPrice(600);
189 * iPhone.getPrice(); // 600
190 * iPhone.isExpensive; // true;
192 * iPhone.setOperatingSystem('AlienOS');
193 * iPhone.getOperatingSystem(); // 'Other'
197 * Ext.define('Computer', {
199 * factory: function(brand) {
200 * // 'this' in static methods refer to the class itself
201 * return new this(brand);
205 * constructor: function() { ... }
208 * var dellComputer = Computer.factory('Dell');
210 * Also see {@link Ext.Base#statics} and {@link Ext.Base#self} for more details on accessing
211 * static properties within class methods
215 (function(Class, alias) {
217 var slice = Array.prototype.slice;
219 var Manager = Ext.ClassManager = {
222 * @property {Object} classes
223 * All classes which were defined through the ClassManager. Keys are the
224 * name of the classes and the values are references to the classes.
237 namespaceRewrites: [{
252 enableNamespaceParseCache: true,
255 namespaceParseCache: {},
262 instantiationCounts: {},
266 * Checks if a class has already been created.
268 * @param {String} className
269 * @return {Boolean} exist
271 isCreated: function(className) {
272 var i, ln, part, root, parts;
275 if (typeof className !== 'string' || className.length < 1) {
277 sourceClass: "Ext.ClassManager",
278 sourceMethod: "exist",
279 msg: "Invalid classname, must be a string and must not be empty"
284 if (this.classes.hasOwnProperty(className) || this.existCache.hasOwnProperty(className)) {
289 parts = this.parseNamespace(className);
291 for (i = 0, ln = parts.length; i < ln; i++) {
294 if (typeof part !== 'string') {
297 if (!root || !root[part]) {
305 Ext.Loader.historyPush(className);
307 this.existCache[className] = true;
313 * Supports namespace rewriting
316 parseNamespace: function(namespace) {
318 if (typeof namespace !== 'string') {
320 sourceClass: "Ext.ClassManager",
321 sourceMethod: "parseNamespace",
322 msg: "Invalid namespace, must be a string"
327 var cache = this.namespaceParseCache;
329 if (this.enableNamespaceParseCache) {
330 if (cache.hasOwnProperty(namespace)) {
331 return cache[namespace];
336 rewrites = this.namespaceRewrites,
337 rewrite, from, to, i, ln, root = Ext.global;
339 for (i = 0, ln = rewrites.length; i < ln; i++) {
340 rewrite = rewrites[i];
344 if (namespace === from || namespace.substring(0, from.length) === from) {
345 namespace = namespace.substring(from.length);
347 if (typeof to !== 'string') {
350 parts = parts.concat(to.split('.'));
359 parts = parts.concat(namespace.split('.'));
361 if (this.enableNamespaceParseCache) {
362 cache[namespace] = parts;
369 * Creates a namespace and assign the `value` to the created object
371 * Ext.ClassManager.setNamespace('MyCompany.pkg.Example', someObject);
373 * alert(MyCompany.pkg.Example === someObject); // alerts true
375 * @param {String} name
376 * @param {Object} value
378 setNamespace: function(name, value) {
379 var root = Ext.global,
380 parts = this.parseNamespace(name),
381 ln = parts.length - 1,
385 for (i = 0; i < ln; i++) {
388 if (typeof part !== 'string') {
405 * The new Ext.ns, supports namespace rewriting
408 createNamespaces: function() {
409 var root = Ext.global,
410 parts, part, i, j, ln, subLn;
412 for (i = 0, ln = arguments.length; i < ln; i++) {
413 parts = this.parseNamespace(arguments[i]);
415 for (j = 0, subLn = parts.length; j < subLn; j++) {
418 if (typeof part !== 'string') {
434 * Sets a name reference to a class.
436 * @param {String} name
437 * @param {Object} value
438 * @return {Ext.ClassManager} this
440 set: function(name, value) {
441 var targetName = this.getName(value);
443 this.classes[name] = this.setNamespace(name, value);
445 if (targetName && targetName !== name) {
446 this.maps.alternateToName[name] = targetName;
453 * Retrieve a class by its name.
455 * @param {String} name
456 * @return {Ext.Class} class
458 get: function(name) {
459 if (this.classes.hasOwnProperty(name)) {
460 return this.classes[name];
463 var root = Ext.global,
464 parts = this.parseNamespace(name),
467 for (i = 0, ln = parts.length; i < ln; i++) {
470 if (typeof part !== 'string') {
473 if (!root || !root[part]) {
485 * Register the alias for a class.
487 * @param {Ext.Class/String} cls a reference to a class or a className
488 * @param {String} alias Alias to use when referring to this class
490 setAlias: function(cls, alias) {
491 var aliasToNameMap = this.maps.aliasToName,
492 nameToAliasesMap = this.maps.nameToAliases,
495 if (typeof cls === 'string') {
498 className = this.getName(cls);
501 if (alias && aliasToNameMap[alias] !== className) {
503 if (aliasToNameMap.hasOwnProperty(alias) && Ext.isDefined(Ext.global.console)) {
504 Ext.global.console.log("[Ext.ClassManager] Overriding existing alias: '" + alias + "' " +
505 "of: '" + aliasToNameMap[alias] + "' with: '" + className + "'. Be sure it's intentional.");
509 aliasToNameMap[alias] = className;
512 if (!nameToAliasesMap[className]) {
513 nameToAliasesMap[className] = [];
517 Ext.Array.include(nameToAliasesMap[className], alias);
524 * Get a reference to the class by its alias.
526 * @param {String} alias
527 * @return {Ext.Class} class
529 getByAlias: function(alias) {
530 return this.get(this.getNameByAlias(alias));
534 * Get the name of a class by its alias.
536 * @param {String} alias
537 * @return {String} className
539 getNameByAlias: function(alias) {
540 return this.maps.aliasToName[alias] || '';
544 * Get the name of a class by its alternate name.
546 * @param {String} alternate
547 * @return {String} className
549 getNameByAlternate: function(alternate) {
550 return this.maps.alternateToName[alternate] || '';
554 * Get the aliases of a class by the class name
556 * @param {String} name
557 * @return {String[]} aliases
559 getAliasesByName: function(name) {
560 return this.maps.nameToAliases[name] || [];
564 * Get the name of the class by its reference or its instance.
566 * Ext.ClassManager.getName(Ext.Action); // returns "Ext.Action"
568 * {@link Ext#getClassName Ext.getClassName} is alias for {@link Ext.ClassManager#getName Ext.ClassManager.getName}.
570 * @param {Ext.Class/Object} object
571 * @return {String} className
573 getName: function(object) {
574 return object && object.$className || '';
578 * Get the class of the provided object; returns null if it's not an instance
579 * of any class created with Ext.define.
581 * var component = new Ext.Component();
583 * Ext.ClassManager.getClass(component); // returns Ext.Component
585 * {@link Ext#getClass Ext.getClass} is alias for {@link Ext.ClassManager#getClass Ext.ClassManager.getClass}.
587 * @param {Object} object
588 * @return {Ext.Class} class
590 getClass: function(object) {
591 return object && object.self || null;
597 * {@link Ext#define Ext.define} and {@link Ext.ClassManager#create Ext.ClassManager.create} are almost aliases
598 * of each other, with the only exception that Ext.define allows definition of {@link Ext.Class#override overrides}.
599 * To avoid trouble, always use Ext.define.
601 * Ext.define('My.awesome.Class', {
602 * someProperty: 'something',
603 * someMethod: function() { ... }
608 * alert(this === My.awesome.Class); // alerts true
610 * var myInstance = new this();
613 * @param {String} className The class name to create in string dot-namespaced format, for example:
614 * `My.very.awesome.Class`, `FeedViewer.plugin.CoolPager`. It is highly recommended to follow this simple convention:
616 * - The root and the class name are 'CamelCased'
617 * - Everything else is lower-cased
619 * @param {Object} data The key-value pairs of properties to apply to this class. Property names can be of any valid
620 * strings, except those in the reserved list below:
622 * - {@link Ext.Base#self self}
623 * - {@link Ext.Class#alias alias}
624 * - {@link Ext.Class#alternateClassName alternateClassName}
625 * - {@link Ext.Class#config config}
626 * - {@link Ext.Class#extend extend}
627 * - {@link Ext.Class#inheritableStatics inheritableStatics}
628 * - {@link Ext.Class#mixins mixins}
629 * - {@link Ext.Class#override override} (only when using {@link Ext#define Ext.define})
630 * - {@link Ext.Class#requires requires}
631 * - {@link Ext.Class#singleton singleton}
632 * - {@link Ext.Class#statics statics}
633 * - {@link Ext.Class#uses uses}
635 * @param {Function} [createdFn] callback to execute after the class is created, the execution scope of which
636 * (`this`) will be the newly created class itself.
640 create: function(className, data, createdFn) {
644 if (typeof className !== 'string') {
647 sourceMethod: "define",
648 msg: "Invalid class name '" + className + "' specified, must be a non-empty string"
653 data.$className = className;
655 return new Class(data, function() {
656 var postprocessorStack = data.postprocessors || manager.defaultPostprocessors,
657 registeredPostprocessors = manager.postprocessors,
660 postprocessor, process, i, ln;
662 delete data.postprocessors;
664 for (i = 0, ln = postprocessorStack.length; i < ln; i++) {
665 postprocessor = postprocessorStack[i];
667 if (typeof postprocessor === 'string') {
668 postprocessor = registeredPostprocessors[postprocessor];
670 if (!postprocessor.always) {
671 if (data[postprocessor.name] !== undefined) {
672 postprocessors.push(postprocessor.fn);
676 postprocessors.push(postprocessor.fn);
680 postprocessors.push(postprocessor);
684 process = function(clsName, cls, clsData) {
685 postprocessor = postprocessors[index++];
687 if (!postprocessor) {
688 manager.set(className, cls);
690 Ext.Loader.historyPush(className);
693 createdFn.call(cls, cls);
699 if (postprocessor.call(this, clsName, cls, clsData, process) !== false) {
700 process.apply(this, arguments);
704 process.call(manager, className, this, data);
709 * Instantiate a class by its alias.
711 * If {@link Ext.Loader} is {@link Ext.Loader#setConfig enabled} and the class has not been defined yet, it will
712 * attempt to load the class via synchronous loading.
714 * var window = Ext.ClassManager.instantiateByAlias('widget.window', { width: 600, height: 800, ... });
716 * {@link Ext#createByAlias Ext.createByAlias} is alias for {@link Ext.ClassManager#instantiateByAlias Ext.ClassManager.instantiateByAlias}.
718 * @param {String} alias
719 * @param {Object...} args Additional arguments after the alias will be passed to the
721 * @return {Object} instance
723 instantiateByAlias: function() {
724 var alias = arguments[0],
725 args = slice.call(arguments),
726 className = this.getNameByAlias(alias);
729 className = this.maps.aliasToName[alias];
735 sourceMethod: "createByAlias",
736 msg: "Cannot create an instance of unrecognized alias: " + alias
742 if (Ext.global.console) {
743 Ext.global.console.warn("[Ext.Loader] Synchronously loading '" + className + "'; consider adding " +
744 "Ext.require('" + alias + "') above Ext.onReady");
748 Ext.syncRequire(className);
753 return this.instantiate.apply(this, args);
757 * Instantiate a class by either full name, alias or alternate name.
759 * If {@link Ext.Loader} is {@link Ext.Loader#setConfig enabled} and the class has not been defined yet, it will
760 * attempt to load the class via synchronous loading.
762 * For example, all these three lines return the same result:
765 * var window = Ext.ClassManager.instantiate('widget.window', { width: 600, height: 800, ... });
768 * var window = Ext.ClassManager.instantiate('Ext.Window', { width: 600, height: 800, ... });
771 * var window = Ext.ClassManager.instantiate('Ext.window.Window', { width: 600, height: 800, ... });
773 * {@link Ext#create Ext.create} is alias for {@link Ext.ClassManager#instantiate Ext.ClassManager.instantiate}.
775 * @param {String} name
776 * @param {Object...} args Additional arguments after the name will be passed to the class' constructor.
777 * @return {Object} instance
779 instantiate: function() {
780 var name = arguments[0],
781 args = slice.call(arguments, 1),
785 if (typeof name !== 'function') {
787 if ((typeof name !== 'string' || name.length < 1)) {
790 sourceMethod: "create",
791 msg: "Invalid class name or alias '" + name + "' specified, must be a non-empty string"
796 cls = this.get(name);
802 // No record of this class name, it's possibly an alias, so look it up
804 possibleName = this.getNameByAlias(name);
809 cls = this.get(name);
813 // Still no record of this class name, it's possibly an alternate name, so look it up
815 possibleName = this.getNameByAlternate(name);
820 cls = this.get(name);
824 // Still not existing at this point, try to load it via synchronous mode as the last resort
827 if (Ext.global.console) {
828 Ext.global.console.warn("[Ext.Loader] Synchronously loading '" + name + "'; consider adding " +
829 "Ext.require('" + ((possibleName) ? alias : name) + "') above Ext.onReady");
833 Ext.syncRequire(name);
835 cls = this.get(name);
842 sourceMethod: "create",
843 msg: "Cannot create an instance of unrecognized class name / alias: " + alias
847 if (typeof cls !== 'function') {
850 sourceMethod: "create",
851 msg: "'" + name + "' is a singleton and cannot be instantiated"
857 if (!this.instantiationCounts[name]) {
858 this.instantiationCounts[name] = 0;
861 this.instantiationCounts[name]++;
864 return this.getInstantiator(args.length)(cls, args);
872 dynInstantiate: function(name, args) {
873 args = Ext.Array.from(args, true);
876 return this.instantiate.apply(this, args);
883 getInstantiator: function(length) {
884 if (!this.instantiators[length]) {
888 for (i = 0; i < length; i++) {
889 args.push('a['+i+']');
892 this.instantiators[length] = new Function('c', 'a', 'return new c('+args.join(',')+')');
895 return this.instantiators[length];
906 defaultPostprocessors: [],
909 * Register a post-processor function.
911 * @param {String} name
912 * @param {Function} postprocessor
914 registerPostprocessor: function(name, fn, always) {
915 this.postprocessors[name] = {
917 always: always || false,
925 * Set the default post processors array stack which are applied to every class.
927 * @param {String/String[]} The name of a registered post processor or an array of registered names.
928 * @return {Ext.ClassManager} this
930 setDefaultPostprocessors: function(postprocessors) {
931 this.defaultPostprocessors = Ext.Array.from(postprocessors);
937 * Insert this post-processor at a specific position in the stack, optionally relative to
938 * any existing post-processor
940 * @param {String} name The post-processor name. Note that it needs to be registered with
941 * {@link Ext.ClassManager#registerPostprocessor} before this
942 * @param {String} offset The insertion position. Four possible values are:
943 * 'first', 'last', or: 'before', 'after' (relative to the name provided in the third argument)
944 * @param {String} relativeName
945 * @return {Ext.ClassManager} this
947 setDefaultPostprocessorPosition: function(name, offset, relativeName) {
948 var defaultPostprocessors = this.defaultPostprocessors,
951 if (typeof offset === 'string') {
952 if (offset === 'first') {
953 defaultPostprocessors.unshift(name);
957 else if (offset === 'last') {
958 defaultPostprocessors.push(name);
963 offset = (offset === 'after') ? 1 : -1;
966 index = Ext.Array.indexOf(defaultPostprocessors, relativeName);
969 Ext.Array.splice(defaultPostprocessors, Math.max(0, index + offset), 0, name);
976 * Converts a string expression to an array of matching class names. An expression can either refers to class aliases
977 * or class names. Expressions support wildcards:
979 * // returns ['Ext.window.Window']
980 * var window = Ext.ClassManager.getNamesByExpression('widget.window');
982 * // returns ['widget.panel', 'widget.window', ...]
983 * var allWidgets = Ext.ClassManager.getNamesByExpression('widget.*');
985 * // returns ['Ext.data.Store', 'Ext.data.ArrayProxy', ...]
986 * var allData = Ext.ClassManager.getNamesByExpression('Ext.data.*');
988 * @param {String} expression
989 * @return {String[]} classNames
991 getNamesByExpression: function(expression) {
992 var nameToAliasesMap = this.maps.nameToAliases,
994 name, alias, aliases, possibleName, regex, i, ln;
997 if (typeof expression !== 'string' || expression.length < 1) {
999 sourceClass: "Ext.ClassManager",
1000 sourceMethod: "getNamesByExpression",
1001 msg: "Expression " + expression + " is invalid, must be a non-empty string"
1006 if (expression.indexOf('*') !== -1) {
1007 expression = expression.replace(/\*/g, '(.*?)');
1008 regex = new RegExp('^' + expression + '$');
1010 for (name in nameToAliasesMap) {
1011 if (nameToAliasesMap.hasOwnProperty(name)) {
1012 aliases = nameToAliasesMap[name];
1014 if (name.search(regex) !== -1) {
1018 for (i = 0, ln = aliases.length; i < ln; i++) {
1021 if (alias.search(regex) !== -1) {
1031 possibleName = this.getNameByAlias(expression);
1034 names.push(possibleName);
1036 possibleName = this.getNameByAlternate(expression);
1039 names.push(possibleName);
1041 names.push(expression);
1050 var defaultPostprocessors = Manager.defaultPostprocessors;
1051 //<feature classSystem.alias>
1054 * @cfg {String[]} alias
1056 * List of short aliases for class names. Most useful for defining xtypes for widgets:
1058 * Ext.define('MyApp.CoolPanel', {
1059 * extend: 'Ext.panel.Panel',
1060 * alias: ['widget.coolpanel'],
1064 * // Using Ext.create
1065 * Ext.widget('widget.coolpanel');
1066 * // Using the shorthand for widgets and in xtypes
1067 * Ext.widget('panel', {
1069 * {xtype: 'coolpanel', html: 'Foo'},
1070 * {xtype: 'coolpanel', html: 'Bar'}
1074 Manager.registerPostprocessor('alias', function(name, cls, data) {
1075 var aliases = data.alias,
1080 for (i = 0, ln = aliases.length; i < ln; i++) {
1083 this.setAlias(cls, alias);
1088 * @cfg {Boolean} singleton
1090 * When set to true, the class will be instantiated as singleton. For example:
1092 * Ext.define('Logger', {
1094 * log: function(msg) {
1099 * Logger.log('Hello');
1101 Manager.registerPostprocessor('singleton', function(name, cls, data, fn) {
1102 fn.call(this, name, new cls(), data);
1107 * @cfg {String/String[]} alternateClassName
1109 * Defines alternate names for this class. For example:
1111 * Ext.define('Developer', {
1112 * alternateClassName: ['Coder', 'Hacker'],
1113 * code: function(msg) {
1114 * alert('Typing... ' + msg);
1118 * var joe = Ext.create('Developer');
1119 * joe.code('stackoverflow');
1121 * var rms = Ext.create('Hacker');
1122 * rms.code('hack hack');
1124 Manager.registerPostprocessor('alternateClassName', function(name, cls, data) {
1125 var alternates = data.alternateClassName,
1128 if (!(alternates instanceof Array)) {
1129 alternates = [alternates];
1132 for (i = 0, ln = alternates.length; i < ln; i++) {
1133 alternate = alternates[i];
1136 if (typeof alternate !== 'string') {
1139 sourceMethod: "define",
1140 msg: "Invalid alternate of: '" + alternate + "' for class: '" + name + "'; must be a valid string"
1145 this.set(alternate, cls);
1149 Manager.setDefaultPostprocessors(['alias', 'singleton', 'alternateClassName']);
1155 * @alias Ext.ClassManager#instantiate
1157 create: alias(Manager, 'instantiate'),
1161 * API to be stablized
1163 * @param {Object} item
1164 * @param {String} namespace
1166 factory: function(item, namespace) {
1167 if (item instanceof Array) {
1170 for (i = 0, ln = item.length; i < ln; i++) {
1171 item[i] = Ext.factory(item[i], namespace);
1177 var isString = (typeof item === 'string');
1179 if (isString || (item instanceof Object && item.constructor === Object)) {
1180 var name, config = {};
1186 name = item.className;
1188 delete config.className;
1191 if (namespace !== undefined && name.indexOf(namespace) === -1) {
1192 name = namespace + '.' + Ext.String.capitalize(name);
1195 return Ext.create(name, config);
1198 if (typeof item === 'function') {
1199 return Ext.create(item);
1206 * Convenient shorthand to create a widget by its xtype, also see {@link Ext.ClassManager#instantiateByAlias}
1208 * var button = Ext.widget('button'); // Equivalent to Ext.create('widget.button')
1209 * var panel = Ext.widget('panel'); // Equivalent to Ext.create('widget.panel')
1213 * @param {String} name xtype of the widget to create.
1214 * @param {Object...} args arguments for the widget constructor.
1215 * @return {Object} widget instance
1217 widget: function(name) {
1218 var args = slice.call(arguments);
1219 args[0] = 'widget.' + name;
1221 return Manager.instantiateByAlias.apply(Manager, args);
1227 * @alias Ext.ClassManager#instantiateByAlias
1229 createByAlias: alias(Manager, 'instantiateByAlias'),
1232 * @cfg {String} override
1235 * Defines an override applied to a class. Note that **overrides can only be created using
1236 * {@link Ext#define}.** {@link Ext.ClassManager#create} only creates classes.
1238 * To define an override, include the override property. The content of an override is
1239 * aggregated with the specified class in order to extend or modify that class. This can be
1240 * as simple as setting default property values or it can extend and/or replace methods.
1241 * This can also extend the statics of the class.
1243 * One use for an override is to break a large class into manageable pieces.
1245 * // File: /src/app/Panel.js
1247 * Ext.define('My.app.Panel', {
1248 * extend: 'Ext.panel.Panel',
1250 * 'My.app.PanelPart2',
1251 * 'My.app.PanelPart3'
1254 * constructor: function (config) {
1255 * this.callSuper(arguments); // calls Ext.panel.Panel's constructor
1260 * method: function () {
1266 * // File: /src/app/PanelPart2.js
1267 * Ext.define('My.app.PanelPart2', {
1268 * override: 'My.app.Panel',
1270 * constructor: function (config) {
1271 * this.callSuper(arguments); // calls My.app.Panel's constructor
1276 * Another use of overrides is to provide optional parts of classes that can be
1277 * independently required. In this case, the class may even be unaware of the
1278 * override altogether.
1280 * Ext.define('My.ux.CoolTip', {
1281 * override: 'Ext.tip.ToolTip',
1283 * constructor: function (config) {
1284 * this.callSuper(arguments); // calls Ext.tip.ToolTip's constructor
1289 * The above override can now be required as normal.
1291 * Ext.define('My.app.App', {
1297 * Overrides can also contain statics:
1299 * Ext.define('My.app.BarMod', {
1300 * override: 'Ext.foo.Bar',
1303 * method: function (x) {
1304 * return this.callSuper([x * 2]); // call Ext.foo.Bar.method
1309 * IMPORTANT: An override is only included in a build if the class it overrides is
1310 * required. Otherwise, the override, like the target class, is not included.
1317 * @alias Ext.ClassManager#create
1319 define: function (className, data, createdFn) {
1320 if (!data.override) {
1321 return Manager.create.apply(Manager, arguments);
1324 var requires = data.requires,
1326 overrideName = className;
1328 className = data.override;
1330 // hoist any 'requires' or 'uses' from the body onto the faux class:
1331 data = Ext.apply({}, data);
1332 delete data.requires;
1334 delete data.override;
1336 // make sure className is in the requires list:
1337 if (typeof requires == 'string') {
1338 requires = [ className, requires ];
1339 } else if (requires) {
1340 requires = requires.slice(0);
1341 requires.unshift(className);
1343 requires = [ className ];
1346 // TODO - we need to rework this to allow the override to not require the target class
1347 // and rather 'wait' for it in such a way that if the target class is not in the build,
1348 // neither are any of its overrides.
1350 // Also, this should process the overrides for a class ASAP (ideally before any derived
1351 // classes) if the target class 'requires' the overrides. Without some special handling, the
1352 // overrides so required will be processed before the class and have to be bufferred even
1355 // TODO - we should probably support the "config" processor on an override (to config new
1356 // functionaliy like Aria) and maybe inheritableStatics (although static is now supported
1357 // by callSuper). If inheritableStatics causes those statics to be included on derived class
1358 // constructors, that probably means "no" to this since an override can come after other
1359 // classes extend the target.
1360 return Manager.create(overrideName, {
1364 constructor: function () {
1366 throw new Error("Cannot create override '" + overrideName + "'");
1370 var cls = Manager.get(className);
1371 if (cls.override) { // if (normal class)
1373 } else { // else (singleton)
1374 cls.self.override(data);
1378 // called once the override is applied and with the context of the
1379 // overridden class (the override itself is a meaningless, name-only
1381 createdFn.call(cls);
1389 * @alias Ext.ClassManager#getName
1391 getClassName: alias(Manager, 'getName'),
1394 * Returns the displayName property or className or object.
1395 * When all else fails, returns "Anonymous".
1396 * @param {Object} object
1399 getDisplayName: function(object) {
1400 if (object.displayName) {
1401 return object.displayName;
1404 if (object.$name && object.$class) {
1405 return Ext.getClassName(object.$class) + '#' + object.$name;
1408 if (object.$className) {
1409 return object.$className;
1418 * @alias Ext.ClassManager#getClass
1420 getClass: alias(Manager, 'getClass'),
1423 * Creates namespaces to be used for scoping variables and classes so that they are not global.
1424 * Specifying the last node of a namespace implicitly creates all other nodes. Usage:
1426 * Ext.namespace('Company', 'Company.data');
1428 * // equivalent and preferable to the above syntax
1429 * Ext.namespace('Company.data');
1431 * Company.Widget = function() { ... };
1433 * Company.data.CustomStore = function(config) { ... };
1437 * @param {String} namespace1
1438 * @param {String} namespace2
1439 * @param {String} etc
1440 * @return {Object} The namespace object. (If multiple arguments are passed, this will be the last namespace created)
1442 namespace: alias(Manager, 'createNamespaces')
1446 * Old name for {@link Ext#widget}.
1447 * @deprecated 4.0.0 Use {@link Ext#widget} instead.
1452 Ext.createWidget = Ext.widget;
1455 * Convenient alias for {@link Ext#namespace Ext.namespace}
1458 * @alias Ext#namespace
1460 Ext.ns = Ext.namespace;
1462 Class.registerPreprocessor('className', function(cls, data) {
1463 if (data.$className) {
1464 cls.$className = data.$className;
1466 cls.displayName = cls.$className;
1471 Class.setDefaultPreprocessorPosition('className', 'first');
1473 Class.registerPreprocessor('xtype', function(cls, data) {
1474 var xtypes = Ext.Array.from(data.xtype),
1475 widgetPrefix = 'widget.',
1476 aliases = Ext.Array.from(data.alias),
1479 data.xtype = xtypes[0];
1480 data.xtypes = xtypes;
1482 aliases = data.alias = Ext.Array.from(data.alias);
1484 for (i = 0,ln = xtypes.length; i < ln; i++) {
1488 if (typeof xtype != 'string' || xtype.length < 1) {
1489 throw new Error("[Ext.define] Invalid xtype of: '" + xtype + "' for class: '" + name + "'; must be a valid non-empty string");
1493 aliases.push(widgetPrefix + xtype);
1496 data.alias = aliases;
1499 Class.setDefaultPreprocessorPosition('xtype', 'last');
1501 Class.registerPreprocessor('alias', function(cls, data) {
1502 var aliases = Ext.Array.from(data.alias),
1503 xtypes = Ext.Array.from(data.xtypes),
1504 widgetPrefix = 'widget.',
1505 widgetPrefixLength = widgetPrefix.length,
1506 i, ln, alias, xtype;
1508 for (i = 0, ln = aliases.length; i < ln; i++) {
1512 if (typeof alias != 'string') {
1513 throw new Error("[Ext.define] Invalid alias of: '" + alias + "' for class: '" + name + "'; must be a valid string");
1517 if (alias.substring(0, widgetPrefixLength) === widgetPrefix) {
1518 xtype = alias.substring(widgetPrefixLength);
1519 Ext.Array.include(xtypes, xtype);
1522 cls.xtype = data.xtype = xtype;
1527 data.alias = aliases;
1528 data.xtypes = xtypes;
1531 Class.setDefaultPreprocessorPosition('alias', 'last');
1533 })(Ext.Class, Ext.Function.alias);