4 <meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
5 <title>The source code</title>
6 <link href="../prettify/prettify.css" type="text/css" rel="stylesheet" />
7 <script type="text/javascript" src="../prettify/prettify.js"></script>
8 <style type="text/css">
9 .highlight { display: block; background-color: #ddd; }
11 <script type="text/javascript">
12 function highlight() {
13 document.getElementById(location.hash.replace(/#/, "")).className = "highlight";
17 <body onload="prettyPrint(); highlight();">
18 <pre class="prettyprint lang-js"><span id='Ext-ClassManager'>/**
19 </span> * @author Jacky Nguyen <jacky@sencha.com>
20 * @docauthor Jacky Nguyen <jacky@sencha.com>
21 * @class Ext.ClassManager
23 Ext.ClassManager manages all classes and handles mapping from string class name to
24 actual class objects throughout the whole framework. It is not generally accessed directly, rather through
25 these convenient shorthands:
27 - {@link Ext#define Ext.define}
28 - {@link Ext#create Ext.create}
29 - {@link Ext#widget Ext.widget}
30 - {@link Ext#getClass Ext.getClass}
31 - {@link Ext#getClassName Ext.getClassName}
36 (function(Class, alias) {
38 var slice = Array.prototype.slice;
40 var Manager = Ext.ClassManager = {
42 <span id='Ext-ClassManager-property-classes'> /**
43 </span> * @property classes
45 * All classes which were defined through the ClassManager. Keys are the
46 * name of the classes and the values are references to the classes.
51 <span id='Ext-ClassManager-property-existCache'> /**
56 <span id='Ext-ClassManager-property-namespaceRewrites'> /**
64 <span id='Ext-ClassManager-property-maps'> /**
73 <span id='Ext-ClassManager-property-enableNamespaceParseCache'> /** @private */
74 </span> enableNamespaceParseCache: true,
76 <span id='Ext-ClassManager-property-namespaceParseCache'> /** @private */
77 </span> namespaceParseCache: {},
79 <span id='Ext-ClassManager-property-instantiators'> /** @private */
80 </span> instantiators: [],
83 <span id='Ext-ClassManager-property-instantiationCounts'> /** @private */
84 </span> instantiationCounts: {},
87 <span id='Ext-ClassManager-method-isCreated'> /**
88 </span> * Checks if a class has already been created.
90 * @param {String} className
91 * @return {Boolean} exist
93 isCreated: function(className) {
94 var i, ln, part, root, parts;
97 if (typeof className !== 'string' || className.length < 1) {
99 sourceClass: "Ext.ClassManager",
100 sourceMethod: "exist",
101 msg: "Invalid classname, must be a string and must not be empty"
106 if (this.classes.hasOwnProperty(className) || this.existCache.hasOwnProperty(className)) {
111 parts = this.parseNamespace(className);
113 for (i = 0, ln = parts.length; i < ln; i++) {
116 if (typeof part !== 'string') {
119 if (!root || !root[part]) {
127 Ext.Loader.historyPush(className);
129 this.existCache[className] = true;
134 <span id='Ext-ClassManager-method-parseNamespace'> /**
135 </span> * Supports namespace rewriting
138 parseNamespace: function(namespace) {
139 //<debug error>
140 if (typeof namespace !== 'string') {
142 sourceClass: "Ext.ClassManager",
143 sourceMethod: "parseNamespace",
144 msg: "Invalid namespace, must be a string"
149 var cache = this.namespaceParseCache;
151 if (this.enableNamespaceParseCache) {
152 if (cache.hasOwnProperty(namespace)) {
153 return cache[namespace];
158 rewrites = this.namespaceRewrites,
159 rewrite, from, to, i, ln, root = Ext.global;
161 for (i = 0, ln = rewrites.length; i < ln; i++) {
162 rewrite = rewrites[i];
166 if (namespace === from || namespace.substring(0, from.length) === from) {
167 namespace = namespace.substring(from.length);
169 if (typeof to !== 'string') {
172 parts = parts.concat(to.split('.'));
181 parts = parts.concat(namespace.split('.'));
183 if (this.enableNamespaceParseCache) {
184 cache[namespace] = parts;
190 <span id='Ext-ClassManager-method-setNamespace'> /**
191 </span> * Creates a namespace and assign the `value` to the created object
193 Ext.ClassManager.setNamespace('MyCompany.pkg.Example', someObject);
195 alert(MyCompany.pkg.Example === someObject); // alerts true
197 * @param {String} name
198 * @param {Mixed} value
201 setNamespace: function(name, value) {
202 var root = Ext.global,
203 parts = this.parseNamespace(name),
207 for (i = 0, ln = parts.length; i < ln; i++) {
210 if (typeof part !== 'string') {
226 <span id='Ext-ClassManager-method-createNamespaces'> /**
227 </span> * The new Ext.ns, supports namespace rewriting
230 createNamespaces: function() {
231 var root = Ext.global,
232 parts, part, i, j, ln, subLn;
234 for (i = 0, ln = arguments.length; i < ln; i++) {
235 parts = this.parseNamespace(arguments[i]);
237 for (j = 0, subLn = parts.length; j < subLn; j++) {
240 if (typeof part !== 'string') {
255 <span id='Ext-ClassManager-method-set'> /**
256 </span> * Sets a name reference to a class.
258 * @param {String} name
259 * @param {Object} value
260 * @return {Ext.ClassManager} this
262 set: function(name, value) {
263 var targetName = this.getName(value);
265 this.classes[name] = this.setNamespace(name, value);
267 if (targetName && targetName !== name) {
268 this.maps.alternateToName[name] = targetName;
274 <span id='Ext-ClassManager-method-get'> /**
275 </span> * Retrieve a class by its name.
277 * @param {String} name
278 * @return {Class} class
280 get: function(name) {
281 if (this.classes.hasOwnProperty(name)) {
282 return this.classes[name];
285 var root = Ext.global,
286 parts = this.parseNamespace(name),
289 for (i = 0, ln = parts.length; i < ln; i++) {
292 if (typeof part !== 'string') {
295 if (!root || !root[part]) {
306 <span id='Ext-ClassManager-method-setAlias'> /**
307 </span> * Register the alias for a class.
309 * @param {Class/String} cls a reference to a class or a className
310 * @param {String} alias Alias to use when referring to this class
312 setAlias: function(cls, alias) {
313 var aliasToNameMap = this.maps.aliasToName,
314 nameToAliasesMap = this.maps.nameToAliases,
317 if (typeof cls === 'string') {
320 className = this.getName(cls);
323 if (alias && aliasToNameMap[alias] !== className) {
325 if (aliasToNameMap.hasOwnProperty(alias) && Ext.isDefined(Ext.global.console)) {
326 Ext.global.console.log("[Ext.ClassManager] Overriding existing alias: '" + alias + "' " +
327 "of: '" + aliasToNameMap[alias] + "' with: '" + className + "'. Be sure it's intentional.");
331 aliasToNameMap[alias] = className;
334 if (!nameToAliasesMap[className]) {
335 nameToAliasesMap[className] = [];
339 Ext.Array.include(nameToAliasesMap[className], alias);
345 <span id='Ext-ClassManager-method-getByAlias'> /**
346 </span> * Get a reference to the class by its alias.
348 * @param {String} alias
349 * @return {Class} class
351 getByAlias: function(alias) {
352 return this.get(this.getNameByAlias(alias));
355 <span id='Ext-ClassManager-method-getNameByAlias'> /**
356 </span> * Get the name of a class by its alias.
358 * @param {String} alias
359 * @return {String} className
361 getNameByAlias: function(alias) {
362 return this.maps.aliasToName[alias] || '';
365 <span id='Ext-ClassManager-method-getNameByAlternate'> /**
366 </span> * Get the name of a class by its alternate name.
368 * @param {String} alternate
369 * @return {String} className
371 getNameByAlternate: function(alternate) {
372 return this.maps.alternateToName[alternate] || '';
375 <span id='Ext-ClassManager-method-getAliasesByName'> /**
376 </span> * Get the aliases of a class by the class name
378 * @param {String} name
379 * @return {Array} aliases
381 getAliasesByName: function(name) {
382 return this.maps.nameToAliases[name] || [];
385 <span id='Ext-ClassManager-method-getName'> /**
386 </span> * Get the name of the class by its reference or its instance;
387 * usually invoked by the shorthand {@link Ext#getClassName Ext.getClassName}
389 Ext.ClassManager.getName(Ext.Action); // returns "Ext.Action"
391 * @param {Class/Object} object
392 * @return {String} className
395 getName: function(object) {
396 return object && object.$className || '';
399 <span id='Ext-ClassManager-method-getClass'> /**
400 </span> * Get the class of the provided object; returns null if it's not an instance
401 * of any class created with Ext.define. This is usually invoked by the shorthand {@link Ext#getClass Ext.getClass}
403 var component = new Ext.Component();
405 Ext.ClassManager.getClass(component); // returns Ext.Component
407 * @param {Object} object
408 * @return {Class} class
411 getClass: function(object) {
412 return object && object.self || null;
415 <span id='Ext-ClassManager-method-create'> /**
416 </span> * Defines a class. This is usually invoked via the alias {@link Ext#define Ext.define}
418 Ext.ClassManager.create('My.awesome.Class', {
419 someProperty: 'something',
420 someMethod: function() { ... }
425 alert(this === My.awesome.Class); // alerts true
427 var myInstance = new this();
430 * @param {String} className The class name to create in string dot-namespaced format, for example:
431 * 'My.very.awesome.Class', 'FeedViewer.plugin.CoolPager'
432 * It is highly recommended to follow this simple convention:
434 - The root and the class name are 'CamelCased'
435 - Everything else is lower-cased
437 * @param {Object} data The key - value pairs of properties to apply to this class. Property names can be of any valid
438 * strings, except those in the reserved listed below:
446 - `alternateClassName`
448 * @param {Function} createdFn Optional callback to execute after the class is created, the execution scope of which
449 * (`this`) will be the newly created class itself.
453 create: function(className, data, createdFn) {
456 //<debug error>
457 if (typeof className !== 'string') {
459 sourceClass: "Ext",
460 sourceMethod: "define",
461 msg: "Invalid class name '" + className + "' specified, must be a non-empty string"
466 data.$className = className;
468 return new Class(data, function() {
469 var postprocessorStack = data.postprocessors || manager.defaultPostprocessors,
470 registeredPostprocessors = manager.postprocessors,
473 postprocessor, postprocessors, process, i, ln;
475 delete data.postprocessors;
477 for (i = 0, ln = postprocessorStack.length; i < ln; i++) {
478 postprocessor = postprocessorStack[i];
480 if (typeof postprocessor === 'string') {
481 postprocessor = registeredPostprocessors[postprocessor];
483 if (!postprocessor.always) {
484 if (data[postprocessor.name] !== undefined) {
485 postprocessors.push(postprocessor.fn);
489 postprocessors.push(postprocessor.fn);
493 postprocessors.push(postprocessor);
497 process = function(clsName, cls, clsData) {
498 postprocessor = postprocessors[index++];
500 if (!postprocessor) {
501 manager.set(className, cls);
503 Ext.Loader.historyPush(className);
506 createdFn.call(cls, cls);
512 if (postprocessor.call(this, clsName, cls, clsData, process) !== false) {
513 process.apply(this, arguments);
517 process.call(manager, className, this, data);
521 <span id='Ext-ClassManager-method-instantiateByAlias'> /**
522 </span> * Instantiate a class by its alias; usually invoked by the convenient shorthand {@link Ext#createByAlias Ext.createByAlias}
523 * If {@link Ext.Loader} is {@link Ext.Loader#setConfig enabled} and the class has not been defined yet, it will
524 * attempt to load the class via synchronous loading.
526 var window = Ext.ClassManager.instantiateByAlias('widget.window', { width: 600, height: 800, ... });
528 * @param {String} alias
529 * @param {Mixed} args,... Additional arguments after the alias will be passed to the
531 * @return {Object} instance
534 instantiateByAlias: function() {
535 var alias = arguments[0],
536 args = slice.call(arguments),
537 className = this.getNameByAlias(alias);
540 className = this.maps.aliasToName[alias];
542 //<debug error>
545 sourceClass: "Ext",
546 sourceMethod: "createByAlias",
547 msg: "Cannot create an instance of unrecognized alias: " + alias
553 if (Ext.global.console) {
554 Ext.global.console.warn("[Ext.Loader] Synchronously loading '" + className + "'; consider adding " +
555 "Ext.require('" + alias + "') above Ext.onReady");
559 Ext.syncRequire(className);
564 return this.instantiate.apply(this, args);
567 <span id='Ext-ClassManager-method-instantiate'> /**
568 </span> * Instantiate a class by either full name, alias or alternate name; usually invoked by the convenient
569 * shorthand {@link Ext#create Ext.create}
571 * If {@link Ext.Loader} is {@link Ext.Loader#setConfig enabled} and the class has not been defined yet, it will
572 * attempt to load the class via synchronous loading.
574 * For example, all these three lines return the same result:
577 var window = Ext.ClassManager.instantiate('widget.window', { width: 600, height: 800, ... });
580 var window = Ext.ClassManager.instantiate('Ext.Window', { width: 600, height: 800, ... });
583 var window = Ext.ClassManager.instantiate('Ext.window.Window', { width: 600, height: 800, ... });
585 * @param {String} name
586 * @param {Mixed} args,... Additional arguments after the name will be passed to the class' constructor.
587 * @return {Object} instance
590 instantiate: function() {
591 var name = arguments[0],
592 args = slice.call(arguments, 1),
596 if (typeof name !== 'function') {
597 //<debug error>
598 if ((typeof name !== 'string' || name.length < 1)) {
600 sourceClass: "Ext",
601 sourceMethod: "create",
602 msg: "Invalid class name or alias '" + name + "' specified, must be a non-empty string"
607 cls = this.get(name);
613 // No record of this class name, it's possibly an alias, so look it up
615 possibleName = this.getNameByAlias(name);
620 cls = this.get(name);
624 // Still no record of this class name, it's possibly an alternate name, so look it up
626 possibleName = this.getNameByAlternate(name);
631 cls = this.get(name);
635 // Still not existing at this point, try to load it via synchronous mode as the last resort
638 if (Ext.global.console) {
639 Ext.global.console.warn("[Ext.Loader] Synchronously loading '" + name + "'; consider adding " +
640 "Ext.require('" + ((possibleName) ? alias : name) + "') above Ext.onReady");
644 Ext.syncRequire(name);
646 cls = this.get(name);
649 //<debug error>
652 sourceClass: "Ext",
653 sourceMethod: "create",
654 msg: "Cannot create an instance of unrecognized class name / alias: " + alias
658 if (typeof cls !== 'function') {
660 sourceClass: "Ext",
661 sourceMethod: "create",
662 msg: "'" + name + "' is a singleton and cannot be instantiated"
668 if (!this.instantiationCounts[name]) {
669 this.instantiationCounts[name] = 0;
672 this.instantiationCounts[name]++;
675 return this.getInstantiator(args.length)(cls, args);
678 <span id='Ext-ClassManager-method-dynInstantiate'> /**
683 dynInstantiate: function(name, args) {
684 args = Ext.Array.from(args, true);
687 return this.instantiate.apply(this, args);
690 <span id='Ext-ClassManager-method-getInstantiator'> /**
694 getInstantiator: function(length) {
695 if (!this.instantiators[length]) {
699 for (i = 0; i < length; i++) {
700 args.push('a['+i+']');
703 this.instantiators[length] = new Function('c', 'a', 'return new c('+args.join(',')+')');
706 return this.instantiators[length];
709 <span id='Ext-ClassManager-property-postprocessors'> /**
714 <span id='Ext-ClassManager-property-defaultPostprocessors'> /**
717 defaultPostprocessors: [],
719 <span id='Ext-ClassManager-method-registerPostprocessor'> /**
720 </span> * Register a post-processor function.
722 * @param {String} name
723 * @param {Function} postprocessor
725 registerPostprocessor: function(name, fn, always) {
726 this.postprocessors[name] = {
728 always: always || false,
735 <span id='Ext-ClassManager-method-setDefaultPostprocessors'> /**
736 </span> * Set the default post processors array stack which are applied to every class.
738 * @param {String/Array} The name of a registered post processor or an array of registered names.
739 * @return {Ext.ClassManager} this
741 setDefaultPostprocessors: function(postprocessors) {
742 this.defaultPostprocessors = Ext.Array.from(postprocessors);
747 <span id='Ext-ClassManager-method-setDefaultPostprocessorPosition'> /**
748 </span> * Insert this post-processor at a specific position in the stack, optionally relative to
749 * any existing post-processor
751 * @param {String} name The post-processor name. Note that it needs to be registered with
752 * {@link Ext.ClassManager#registerPostprocessor} before this
753 * @param {String} offset The insertion position. Four possible values are:
754 * 'first', 'last', or: 'before', 'after' (relative to the name provided in the third argument)
755 * @param {String} relativeName
756 * @return {Ext.ClassManager} this
758 setDefaultPostprocessorPosition: function(name, offset, relativeName) {
759 var defaultPostprocessors = this.defaultPostprocessors,
762 if (typeof offset === 'string') {
763 if (offset === 'first') {
764 defaultPostprocessors.unshift(name);
768 else if (offset === 'last') {
769 defaultPostprocessors.push(name);
774 offset = (offset === 'after') ? 1 : -1;
777 index = Ext.Array.indexOf(defaultPostprocessors, relativeName);
780 defaultPostprocessors.splice(Math.max(0, index + offset), 0, name);
786 <span id='Ext-ClassManager-method-getNamesByExpression'> /**
787 </span> * Converts a string expression to an array of matching class names. An expression can either refers to class aliases
788 * or class names. Expressions support wildcards:
790 // returns ['Ext.window.Window']
791 var window = Ext.ClassManager.getNamesByExpression('widget.window');
793 // returns ['widget.panel', 'widget.window', ...]
794 var allWidgets = Ext.ClassManager.getNamesByExpression('widget.*');
796 // returns ['Ext.data.Store', 'Ext.data.ArrayProxy', ...]
797 var allData = Ext.ClassManager.getNamesByExpression('Ext.data.*');
799 * @param {String} expression
800 * @return {Array} classNames
803 getNamesByExpression: function(expression) {
804 var nameToAliasesMap = this.maps.nameToAliases,
806 name, alias, aliases, possibleName, regex, i, ln;
808 //<debug error>
809 if (typeof expression !== 'string' || expression.length < 1) {
811 sourceClass: "Ext.ClassManager",
812 sourceMethod: "getNamesByExpression",
813 msg: "Expression " + expression + " is invalid, must be a non-empty string"
818 if (expression.indexOf('*') !== -1) {
819 expression = expression.replace(/\*/g, '(.*?)');
820 regex = new RegExp('^' + expression + '$');
822 for (name in nameToAliasesMap) {
823 if (nameToAliasesMap.hasOwnProperty(name)) {
824 aliases = nameToAliasesMap[name];
826 if (name.search(regex) !== -1) {
830 for (i = 0, ln = aliases.length; i < ln; i++) {
833 if (alias.search(regex) !== -1) {
843 possibleName = this.getNameByAlias(expression);
846 names.push(possibleName);
848 possibleName = this.getNameByAlternate(expression);
851 names.push(possibleName);
853 names.push(expression);
862 Manager.registerPostprocessor('alias', function(name, cls, data) {
863 var aliases = data.alias,
864 widgetPrefix = 'widget.',
867 if (!(aliases instanceof Array)) {
871 for (i = 0, ln = aliases.length; i < ln; i++) {
874 //<debug error>
875 if (typeof alias !== 'string') {
877 sourceClass: "Ext",
878 sourceMethod: "define",
879 msg: "Invalid alias of: '" + alias + "' for class: '" + name + "'; must be a valid string"
884 this.setAlias(cls, alias);
887 // This is ugly, will change to make use of parseNamespace for alias later on
888 for (i = 0, ln = aliases.length; i < ln; i++) {
891 if (alias.substring(0, widgetPrefix.length) === widgetPrefix) {
892 // Only the first alias with 'widget.' prefix will be used for xtype
893 cls.xtype = cls.$xtype = alias.substring(widgetPrefix.length);
899 Manager.registerPostprocessor('singleton', function(name, cls, data, fn) {
900 fn.call(this, name, new cls(), data);
904 Manager.registerPostprocessor('alternateClassName', function(name, cls, data) {
905 var alternates = data.alternateClassName,
908 if (!(alternates instanceof Array)) {
909 alternates = [alternates];
912 for (i = 0, ln = alternates.length; i < ln; i++) {
913 alternate = alternates[i];
915 //<debug error>
916 if (typeof alternate !== 'string') {
918 sourceClass: "Ext",
919 sourceMethod: "define",
920 msg: "Invalid alternate of: '" + alternate + "' for class: '" + name + "'; must be a valid string"
925 this.set(alternate, cls);
929 Manager.setDefaultPostprocessors(['alias', 'singleton', 'alternateClassName']);
932 <span id='Ext-method-create'> /**
933 </span> * Convenient shorthand, see {@link Ext.ClassManager#instantiate}
937 create: alias(Manager, 'instantiate'),
939 <span id='Ext-ClassManager-method-factory'> /**
941 * API to be stablized
943 * @param {Mixed} item
944 * @param {String} namespace
946 factory: function(item, namespace) {
947 if (item instanceof Array) {
950 for (i = 0, ln = item.length; i < ln; i++) {
951 item[i] = Ext.factory(item[i], namespace);
957 var isString = (typeof item === 'string');
959 if (isString || (item instanceof Object && item.constructor === Object)) {
960 var name, config = {};
966 name = item.className;
968 delete config.className;
971 if (namespace !== undefined && name.indexOf(namespace) === -1) {
972 name = namespace + '.' + Ext.String.capitalize(name);
975 return Ext.create(name, config);
978 if (typeof item === 'function') {
979 return Ext.create(item);
985 <span id='Ext-method-widget'> /**
986 </span> * Convenient shorthand to create a widget by its xtype, also see {@link Ext.ClassManager#instantiateByAlias}
988 var button = Ext.widget('button'); // Equivalent to Ext.create('widget.button')
989 var panel = Ext.widget('panel'); // Equivalent to Ext.create('widget.panel')
995 widget: function(name) {
996 var args = slice.call(arguments);
997 args[0] = 'widget.' + name;
999 return Manager.instantiateByAlias.apply(Manager, args);
1002 <span id='Ext-method-createByAlias'> /**
1003 </span> * Convenient shorthand, see {@link Ext.ClassManager#instantiateByAlias}
1005 * @method createByAlias
1007 createByAlias: alias(Manager, 'instantiateByAlias'),
1009 <span id='Ext-method-define'> /**
1010 </span> * Convenient shorthand for {@link Ext.ClassManager#create}, see detailed {@link Ext.Class explanation}
1014 define: alias(Manager, 'create'),
1016 <span id='Ext-method-getClassName'> /**
1017 </span> * Convenient shorthand, see {@link Ext.ClassManager#getName}
1019 * @method getClassName
1021 getClassName: alias(Manager, 'getName'),
1023 <span id='Ext-ClassManager-method-getDisplayName'> /**
1025 * @param {Mixed} object
1027 getDisplayName: function(object) {
1028 if (object.displayName) {
1029 return object.displayName;
1032 if (object.$name && object.$class) {
1033 return Ext.getClassName(object.$class) + '#' + object.$name;
1036 if (object.$className) {
1037 return object.$className;
1043 <span id='Ext-method-getClassName'> /**
1044 </span> * Convenient shorthand, see {@link Ext.ClassManager#getClass}
1046 * @method getClassName
1048 getClass: alias(Manager, 'getClass'),
1050 <span id='Ext-method-namespace'> /**
1051 </span> * Creates namespaces to be used for scoping variables and classes so that they are not global.
1052 * Specifying the last node of a namespace implicitly creates all other nodes. Usage:
1054 Ext.namespace('Company', 'Company.data');
1056 // equivalent and preferable to the above syntax
1057 Ext.namespace('Company.data');
1059 Company.Widget = function() { ... };
1061 Company.data.CustomStore = function(config) { ... };
1063 * @param {String} namespace1
1064 * @param {String} namespace2
1065 * @param {String} etc
1066 * @return {Object} The namespace object. (If multiple arguments are passed, this will be the last namespace created)
1072 namespace: alias(Manager, 'createNamespaces')
1075 Ext.createWidget = Ext.widget;
1077 <span id='Ext-method-ns'> /**
1078 </span> * Convenient alias for {@link Ext#namespace Ext.namespace}
1082 Ext.ns = Ext.namespace;
1084 Class.registerPreprocessor('className', function(cls, data) {
1085 if (data.$className) {
1086 cls.$className = data.$className;
1088 cls.displayName = cls.$className;
1093 Class.setDefaultPreprocessorPosition('className', 'first');
1095 })(Ext.Class, Ext.Function.alias);