1 <!DOCTYPE html><html><head><title>Sencha Documentation Project</title><link rel="stylesheet" href="../reset.css" type="text/css"><link rel="stylesheet" href="../prettify.css" type="text/css"><link rel="stylesheet" href="../prettify_sa.css" type="text/css"><script type="text/javascript" src="../prettify.js"></script></head><body onload="prettyPrint()"><pre class="prettyprint"><pre><span id='Ext-ClassManager'>/**
2 </span> * @author Jacky Nguyen <jacky@sencha.com>
3 * @docauthor Jacky Nguyen <jacky@sencha.com>
4 * @class Ext.ClassManager
6 Ext.ClassManager manages all classes and handles mapping from string class name to
7 actual class objects throughout the whole framework. It is not generally accessed directly, rather through
8 these convenient shorthands:
10 - {@link Ext#define Ext.define}
11 - {@link Ext#create Ext.create}
12 - {@link Ext#widget Ext.widget}
13 - {@link Ext#getClass Ext.getClass}
14 - {@link Ext#getClassName Ext.getClassName}
19 (function(Class, alias) {
21 var slice = Array.prototype.slice;
23 var Manager = Ext.ClassManager = {
25 <span id='Ext-ClassManager-property-classes'> /**
26 </span> * @property classes
28 * All classes which were defined through the ClassManager. Keys are the
29 * name of the classes and the values are references to the classes.
34 <span id='Ext-ClassManager-property-existCache'> /**
39 <span id='Ext-ClassManager-property-namespaceRewrites'> /**
47 <span id='Ext-ClassManager-property-maps'> /**
56 <span id='Ext-ClassManager-property-enableNamespaceParseCache'> /** @private */
57 </span> enableNamespaceParseCache: true,
59 <span id='Ext-ClassManager-property-namespaceParseCache'> /** @private */
60 </span> namespaceParseCache: {},
62 <span id='Ext-ClassManager-property-instantiators'> /** @private */
63 </span> instantiators: [],
66 <span id='Ext-ClassManager-property-instantiationCounts'> /** @private */
67 </span> instantiationCounts: {},
70 <span id='Ext-ClassManager-method-isCreated'> /**
71 </span> * Checks if a class has already been created.
73 * @param {String} className
74 * @return {Boolean} exist
76 isCreated: function(className) {
77 var i, ln, part, root, parts;
80 if (typeof className !== 'string' || className.length < 1) {
82 sourceClass: "Ext.ClassManager",
83 sourceMethod: "exist",
84 msg: "Invalid classname, must be a string and must not be empty"
89 if (this.classes.hasOwnProperty(className) || this.existCache.hasOwnProperty(className)) {
94 parts = this.parseNamespace(className);
96 for (i = 0, ln = parts.length; i < ln; i++) {
99 if (typeof part !== 'string') {
102 if (!root || !root[part]) {
110 Ext.Loader.historyPush(className);
112 this.existCache[className] = true;
117 <span id='Ext-ClassManager-method-parseNamespace'> /**
118 </span> * Supports namespace rewriting
121 parseNamespace: function(namespace) {
122 //<debug error>
123 if (typeof namespace !== 'string') {
125 sourceClass: "Ext.ClassManager",
126 sourceMethod: "parseNamespace",
127 msg: "Invalid namespace, must be a string"
132 var cache = this.namespaceParseCache;
134 if (this.enableNamespaceParseCache) {
135 if (cache.hasOwnProperty(namespace)) {
136 return cache[namespace];
141 rewrites = this.namespaceRewrites,
142 rewrite, from, to, i, ln, root = Ext.global;
144 for (i = 0, ln = rewrites.length; i < ln; i++) {
145 rewrite = rewrites[i];
149 if (namespace === from || namespace.substring(0, from.length) === from) {
150 namespace = namespace.substring(from.length);
152 if (typeof to !== 'string') {
155 parts = parts.concat(to.split('.'));
164 parts = parts.concat(namespace.split('.'));
166 if (this.enableNamespaceParseCache) {
167 cache[namespace] = parts;
173 <span id='Ext-ClassManager-method-setNamespace'> /**
174 </span> * Creates a namespace and assign the `value` to the created object
176 Ext.ClassManager.setNamespace('MyCompany.pkg.Example', someObject);
178 alert(MyCompany.pkg.Example === someObject); // alerts true
180 * @param {String} name
181 * @param {Mixed} value
184 setNamespace: function(name, value) {
185 var root = Ext.global,
186 parts = this.parseNamespace(name),
190 for (i = 0, ln = parts.length; i < ln; i++) {
193 if (typeof part !== 'string') {
209 <span id='Ext-ClassManager-method-createNamespaces'> /**
210 </span> * The new Ext.ns, supports namespace rewriting
213 createNamespaces: function() {
214 var root = Ext.global,
215 parts, part, i, j, ln, subLn;
217 for (i = 0, ln = arguments.length; i < ln; i++) {
218 parts = this.parseNamespace(arguments[i]);
220 for (j = 0, subLn = parts.length; j < subLn; j++) {
223 if (typeof part !== 'string') {
238 <span id='Ext-ClassManager-method-set'> /**
239 </span> * Sets a name reference to a class.
241 * @param {String} name
242 * @param {Object} value
243 * @return {Ext.ClassManager} this
245 set: function(name, value) {
246 var targetName = this.getName(value);
248 this.classes[name] = this.setNamespace(name, value);
250 if (targetName && targetName !== name) {
251 this.maps.alternateToName[name] = targetName;
257 <span id='Ext-ClassManager-method-get'> /**
258 </span> * Retrieve a class by its name.
260 * @param {String} name
261 * @return {Class} class
263 get: function(name) {
264 if (this.classes.hasOwnProperty(name)) {
265 return this.classes[name];
268 var root = Ext.global,
269 parts = this.parseNamespace(name),
272 for (i = 0, ln = parts.length; i < ln; i++) {
275 if (typeof part !== 'string') {
278 if (!root || !root[part]) {
289 <span id='Ext-ClassManager-method-setAlias'> /**
290 </span> * Register the alias for a class.
292 * @param {Class/String} cls a reference to a class or a className
293 * @param {String} alias Alias to use when referring to this class
295 setAlias: function(cls, alias) {
296 var aliasToNameMap = this.maps.aliasToName,
297 nameToAliasesMap = this.maps.nameToAliases,
300 if (typeof cls === 'string') {
303 className = this.getName(cls);
306 if (alias && aliasToNameMap[alias] !== className) {
308 if (aliasToNameMap.hasOwnProperty(alias) && Ext.isDefined(Ext.global.console)) {
309 Ext.global.console.log("[Ext.ClassManager] Overriding existing alias: '" + alias + "' " +
310 "of: '" + aliasToNameMap[alias] + "' with: '" + className + "'. Be sure it's intentional.");
314 aliasToNameMap[alias] = className;
317 if (!nameToAliasesMap[className]) {
318 nameToAliasesMap[className] = [];
322 Ext.Array.include(nameToAliasesMap[className], alias);
328 <span id='Ext-ClassManager-method-getByAlias'> /**
329 </span> * Get a reference to the class by its alias.
331 * @param {String} alias
332 * @return {Class} class
334 getByAlias: function(alias) {
335 return this.get(this.getNameByAlias(alias));
338 <span id='Ext-ClassManager-method-getNameByAlias'> /**
339 </span> * Get the name of a class by its alias.
341 * @param {String} alias
342 * @return {String} className
344 getNameByAlias: function(alias) {
345 return this.maps.aliasToName[alias] || '';
348 <span id='Ext-ClassManager-method-getNameByAlternate'> /**
349 </span> * Get the name of a class by its alternate name.
351 * @param {String} alternate
352 * @return {String} className
354 getNameByAlternate: function(alternate) {
355 return this.maps.alternateToName[alternate] || '';
358 <span id='Ext-ClassManager-method-getAliasesByName'> /**
359 </span> * Get the aliases of a class by the class name
361 * @param {String} name
362 * @return {Array} aliases
364 getAliasesByName: function(name) {
365 return this.maps.nameToAliases[name] || [];
368 <span id='Ext-ClassManager-method-getName'> /**
369 </span> * Get the name of the class by its reference or its instance;
370 * usually invoked by the shorthand {@link Ext#getClassName Ext.getClassName}
372 Ext.ClassManager.getName(Ext.Action); // returns "Ext.Action"
374 * @param {Class/Object} object
375 * @return {String} className
378 getName: function(object) {
379 return object && object.$className || '';
382 <span id='Ext-ClassManager-method-getClass'> /**
383 </span> * Get the class of the provided object; returns null if it's not an instance
384 * of any class created with Ext.define. This is usually invoked by the shorthand {@link Ext#getClass Ext.getClass}
386 var component = new Ext.Component();
388 Ext.ClassManager.getClass(component); // returns Ext.Component
390 * @param {Object} object
391 * @return {Class} class
394 getClass: function(object) {
395 return object && object.self || null;
398 <span id='Ext-ClassManager-method-create'> /**
399 </span> * Defines a class. This is usually invoked via the alias {@link Ext#define Ext.define}
401 Ext.ClassManager.create('My.awesome.Class', {
402 someProperty: 'something',
403 someMethod: function() { ... }
408 alert(this === My.awesome.Class); // alerts true
410 var myInstance = new this();
413 * @param {String} className The class name to create in string dot-namespaced format, for example:
414 * 'My.very.awesome.Class', 'FeedViewer.plugin.CoolPager'
415 * It is highly recommended to follow this simple convention:
417 - The root and the class name are 'CamelCased'
418 - Everything else is lower-cased
420 * @param {Object} data The key - value pairs of properties to apply to this class. Property names can be of any valid
421 * strings, except those in the reserved listed below:
429 - `alternateClassName`
431 * @param {Function} createdFn Optional callback to execute after the class is created, the execution scope of which
432 * (`this`) will be the newly created class itself.
436 create: function(className, data, createdFn) {
439 //<debug error>
440 if (typeof className !== 'string') {
442 sourceClass: "Ext",
443 sourceMethod: "define",
444 msg: "Invalid class name '" + className + "' specified, must be a non-empty string"
449 data.$className = className;
451 return new Class(data, function() {
452 var postprocessorStack = data.postprocessors || manager.defaultPostprocessors,
453 registeredPostprocessors = manager.postprocessors,
456 postprocessor, postprocessors, process, i, ln;
458 delete data.postprocessors;
460 for (i = 0, ln = postprocessorStack.length; i < ln; i++) {
461 postprocessor = postprocessorStack[i];
463 if (typeof postprocessor === 'string') {
464 postprocessor = registeredPostprocessors[postprocessor];
466 if (!postprocessor.always) {
467 if (data[postprocessor.name] !== undefined) {
468 postprocessors.push(postprocessor.fn);
472 postprocessors.push(postprocessor.fn);
476 postprocessors.push(postprocessor);
480 process = function(clsName, cls, clsData) {
481 postprocessor = postprocessors[index++];
483 if (!postprocessor) {
484 manager.set(className, cls);
486 Ext.Loader.historyPush(className);
489 createdFn.call(cls, cls);
495 if (postprocessor.call(this, clsName, cls, clsData, process) !== false) {
496 process.apply(this, arguments);
500 process.call(manager, className, this, data);
504 <span id='Ext-ClassManager-method-instantiateByAlias'> /**
505 </span> * Instantiate a class by its alias; usually invoked by the convenient shorthand {@link Ext#createByAlias Ext.createByAlias}
506 * If {@link Ext.Loader} is {@link Ext.Loader#setConfig enabled} and the class has not been defined yet, it will
507 * attempt to load the class via synchronous loading.
509 var window = Ext.ClassManager.instantiateByAlias('widget.window', { width: 600, height: 800, ... });
511 * @param {String} alias
512 * @param {Mixed} args,... Additional arguments after the alias will be passed to the
514 * @return {Object} instance
517 instantiateByAlias: function() {
518 var alias = arguments[0],
519 args = slice.call(arguments),
520 className = this.getNameByAlias(alias);
523 className = this.maps.aliasToName[alias];
525 //<debug error>
528 sourceClass: "Ext",
529 sourceMethod: "createByAlias",
530 msg: "Cannot create an instance of unrecognized alias: " + alias
536 if (Ext.global.console) {
537 Ext.global.console.warn("[Ext.Loader] Synchronously loading '" + className + "'; consider adding " +
538 "Ext.require('" + alias + "') above Ext.onReady");
542 Ext.syncRequire(className);
547 return this.instantiate.apply(this, args);
550 <span id='Ext-ClassManager-method-instantiate'> /**
551 </span> * Instantiate a class by either full name, alias or alternate name; usually invoked by the convenient
552 * shorthand {@link Ext#create Ext.create}
554 * If {@link Ext.Loader} is {@link Ext.Loader#setConfig enabled} and the class has not been defined yet, it will
555 * attempt to load the class via synchronous loading.
557 * For example, all these three lines return the same result:
560 var window = Ext.ClassManager.instantiate('widget.window', { width: 600, height: 800, ... });
563 var window = Ext.ClassManager.instantiate('Ext.Window', { width: 600, height: 800, ... });
566 var window = Ext.ClassManager.instantiate('Ext.window.Window', { width: 600, height: 800, ... });
568 * @param {String} name
569 * @param {Mixed} args,... Additional arguments after the name will be passed to the class' constructor.
570 * @return {Object} instance
573 instantiate: function() {
574 var name = arguments[0],
575 args = slice.call(arguments, 1),
579 if (typeof name !== 'function') {
580 //<debug error>
581 if ((typeof name !== 'string' || name.length < 1)) {
583 sourceClass: "Ext",
584 sourceMethod: "create",
585 msg: "Invalid class name or alias '" + name + "' specified, must be a non-empty string"
590 cls = this.get(name);
596 // No record of this class name, it's possibly an alias, so look it up
598 possibleName = this.getNameByAlias(name);
603 cls = this.get(name);
607 // Still no record of this class name, it's possibly an alternate name, so look it up
609 possibleName = this.getNameByAlternate(name);
614 cls = this.get(name);
618 // Still not existing at this point, try to load it via synchronous mode as the last resort
621 if (Ext.global.console) {
622 Ext.global.console.warn("[Ext.Loader] Synchronously loading '" + name + "'; consider adding " +
623 "Ext.require('" + ((possibleName) ? alias : name) + "') above Ext.onReady");
627 Ext.syncRequire(name);
629 cls = this.get(name);
632 //<debug error>
635 sourceClass: "Ext",
636 sourceMethod: "create",
637 msg: "Cannot create an instance of unrecognized class name / alias: " + alias
641 if (typeof cls !== 'function') {
643 sourceClass: "Ext",
644 sourceMethod: "create",
645 msg: "'" + name + "' is a singleton and cannot be instantiated"
651 if (!this.instantiationCounts[name]) {
652 this.instantiationCounts[name] = 0;
655 this.instantiationCounts[name]++;
658 return this.getInstantiator(args.length)(cls, args);
661 <span id='Ext-ClassManager-method-dynInstantiate'> /**
666 dynInstantiate: function(name, args) {
667 args = Ext.Array.from(args, true);
670 return this.instantiate.apply(this, args);
673 <span id='Ext-ClassManager-method-getInstantiator'> /**
677 getInstantiator: function(length) {
678 if (!this.instantiators[length]) {
682 for (i = 0; i < length; i++) {
683 args.push('a['+i+']');
686 this.instantiators[length] = new Function('c', 'a', 'return new c('+args.join(',')+')');
689 return this.instantiators[length];
692 <span id='Ext-ClassManager-property-postprocessors'> /**
697 <span id='Ext-ClassManager-property-defaultPostprocessors'> /**
700 defaultPostprocessors: [],
702 <span id='Ext-ClassManager-method-registerPostprocessor'> /**
703 </span> * Register a post-processor function.
705 * @param {String} name
706 * @param {Function} postprocessor
708 registerPostprocessor: function(name, fn, always) {
709 this.postprocessors[name] = {
711 always: always || false,
718 <span id='Ext-ClassManager-method-setDefaultPostprocessors'> /**
719 </span> * Set the default post processors array stack which are applied to every class.
721 * @param {String/Array} The name of a registered post processor or an array of registered names.
722 * @return {Ext.ClassManager} this
724 setDefaultPostprocessors: function(postprocessors) {
725 this.defaultPostprocessors = Ext.Array.from(postprocessors);
730 <span id='Ext-ClassManager-method-setDefaultPostprocessorPosition'> /**
731 </span> * Insert this post-processor at a specific position in the stack, optionally relative to
732 * any existing post-processor
734 * @param {String} name The post-processor name. Note that it needs to be registered with
735 * {@link Ext.ClassManager#registerPostprocessor} before this
736 * @param {String} offset The insertion position. Four possible values are:
737 * 'first', 'last', or: 'before', 'after' (relative to the name provided in the third argument)
738 * @param {String} relativeName
739 * @return {Ext.ClassManager} this
741 setDefaultPostprocessorPosition: function(name, offset, relativeName) {
742 var defaultPostprocessors = this.defaultPostprocessors,
745 if (typeof offset === 'string') {
746 if (offset === 'first') {
747 defaultPostprocessors.unshift(name);
751 else if (offset === 'last') {
752 defaultPostprocessors.push(name);
757 offset = (offset === 'after') ? 1 : -1;
760 index = Ext.Array.indexOf(defaultPostprocessors, relativeName);
763 defaultPostprocessors.splice(Math.max(0, index + offset), 0, name);
769 <span id='Ext-ClassManager-method-getNamesByExpression'> /**
770 </span> * Converts a string expression to an array of matching class names. An expression can either refers to class aliases
771 * or class names. Expressions support wildcards:
773 // returns ['Ext.window.Window']
774 var window = Ext.ClassManager.getNamesByExpression('widget.window');
776 // returns ['widget.panel', 'widget.window', ...]
777 var allWidgets = Ext.ClassManager.getNamesByExpression('widget.*');
779 // returns ['Ext.data.Store', 'Ext.data.ArrayProxy', ...]
780 var allData = Ext.ClassManager.getNamesByExpression('Ext.data.*');
782 * @param {String} expression
783 * @return {Array} classNames
786 getNamesByExpression: function(expression) {
787 var nameToAliasesMap = this.maps.nameToAliases,
789 name, alias, aliases, possibleName, regex, i, ln;
791 //<debug error>
792 if (typeof expression !== 'string' || expression.length < 1) {
794 sourceClass: "Ext.ClassManager",
795 sourceMethod: "getNamesByExpression",
796 msg: "Expression " + expression + " is invalid, must be a non-empty string"
801 if (expression.indexOf('*') !== -1) {
802 expression = expression.replace(/\*/g, '(.*?)');
803 regex = new RegExp('^' + expression + '$');
805 for (name in nameToAliasesMap) {
806 if (nameToAliasesMap.hasOwnProperty(name)) {
807 aliases = nameToAliasesMap[name];
809 if (name.search(regex) !== -1) {
813 for (i = 0, ln = aliases.length; i < ln; i++) {
816 if (alias.search(regex) !== -1) {
826 possibleName = this.getNameByAlias(expression);
829 names.push(possibleName);
831 possibleName = this.getNameByAlternate(expression);
834 names.push(possibleName);
836 names.push(expression);
845 Manager.registerPostprocessor('alias', function(name, cls, data) {
846 var aliases = data.alias,
847 widgetPrefix = 'widget.',
850 if (!(aliases instanceof Array)) {
854 for (i = 0, ln = aliases.length; i < ln; i++) {
857 //<debug error>
858 if (typeof alias !== 'string') {
860 sourceClass: "Ext",
861 sourceMethod: "define",
862 msg: "Invalid alias of: '" + alias + "' for class: '" + name + "'; must be a valid string"
867 this.setAlias(cls, alias);
870 // This is ugly, will change to make use of parseNamespace for alias later on
871 for (i = 0, ln = aliases.length; i < ln; i++) {
874 if (alias.substring(0, widgetPrefix.length) === widgetPrefix) {
875 // Only the first alias with 'widget.' prefix will be used for xtype
876 cls.xtype = cls.$xtype = alias.substring(widgetPrefix.length);
882 Manager.registerPostprocessor('singleton', function(name, cls, data, fn) {
883 fn.call(this, name, new cls(), data);
887 Manager.registerPostprocessor('alternateClassName', function(name, cls, data) {
888 var alternates = data.alternateClassName,
891 if (!(alternates instanceof Array)) {
892 alternates = [alternates];
895 for (i = 0, ln = alternates.length; i < ln; i++) {
896 alternate = alternates[i];
898 //<debug error>
899 if (typeof alternate !== 'string') {
901 sourceClass: "Ext",
902 sourceMethod: "define",
903 msg: "Invalid alternate of: '" + alternate + "' for class: '" + name + "'; must be a valid string"
908 this.set(alternate, cls);
912 Manager.setDefaultPostprocessors(['alias', 'singleton', 'alternateClassName']);
915 <span id='Ext-method-create'> /**
916 </span> * Convenient shorthand, see {@link Ext.ClassManager#instantiate}
920 create: alias(Manager, 'instantiate'),
922 <span id='Ext-ClassManager-method-factory'> /**
924 * API to be stablized
926 * @param {Mixed} item
927 * @param {String} namespace
929 factory: function(item, namespace) {
930 if (item instanceof Array) {
933 for (i = 0, ln = item.length; i < ln; i++) {
934 item[i] = Ext.factory(item[i], namespace);
940 var isString = (typeof item === 'string');
942 if (isString || (item instanceof Object && item.constructor === Object)) {
943 var name, config = {};
949 name = item.className;
951 delete config.className;
954 if (namespace !== undefined && name.indexOf(namespace) === -1) {
955 name = namespace + '.' + Ext.String.capitalize(name);
958 return Ext.create(name, config);
961 if (typeof item === 'function') {
962 return Ext.create(item);
968 <span id='Ext-method-widget'> /**
969 </span> * Convenient shorthand to create a widget by its xtype, also see {@link Ext.ClassManager#instantiateByAlias}
971 var button = Ext.widget('button'); // Equivalent to Ext.create('widget.button')
972 var panel = Ext.widget('panel'); // Equivalent to Ext.create('widget.panel')
978 widget: function(name) {
979 var args = slice.call(arguments);
980 args[0] = 'widget.' + name;
982 return Manager.instantiateByAlias.apply(Manager, args);
985 <span id='Ext-method-createByAlias'> /**
986 </span> * Convenient shorthand, see {@link Ext.ClassManager#instantiateByAlias}
988 * @method createByAlias
990 createByAlias: alias(Manager, 'instantiateByAlias'),
992 <span id='Ext-method-define'> /**
993 </span> * Convenient shorthand for {@link Ext.ClassManager#create}, see detailed {@link Ext.Class explanation}
997 define: alias(Manager, 'create'),
999 <span id='Ext-method-getClassName'> /**
1000 </span> * Convenient shorthand, see {@link Ext.ClassManager#getName}
1002 * @method getClassName
1004 getClassName: alias(Manager, 'getName'),
1006 <span id='Ext-ClassManager-method-getDisplayName'> /**
1008 * @param {Mixed} object
1010 getDisplayName: function(object) {
1011 if (object.displayName) {
1012 return object.displayName;
1015 if (object.$name && object.$class) {
1016 return Ext.getClassName(object.$class) + '#' + object.$name;
1019 if (object.$className) {
1020 return object.$className;
1026 <span id='Ext-method-getClassName'> /**
1027 </span> * Convenient shorthand, see {@link Ext.ClassManager#getClass}
1029 * @method getClassName
1031 getClass: alias(Manager, 'getClass'),
1033 <span id='Ext-method-namespace'> /**
1034 </span> * Creates namespaces to be used for scoping variables and classes so that they are not global.
1035 * Specifying the last node of a namespace implicitly creates all other nodes. Usage:
1037 Ext.namespace('Company', 'Company.data');
1039 // equivalent and preferable to the above syntax
1040 Ext.namespace('Company.data');
1042 Company.Widget = function() { ... };
1044 Company.data.CustomStore = function(config) { ... };
1046 * @param {String} namespace1
1047 * @param {String} namespace2
1048 * @param {String} etc
1049 * @return {Object} The namespace object. (If multiple arguments are passed, this will be the last namespace created)
1055 namespace: alias(Manager, 'createNamespaces')
1058 Ext.createWidget = Ext.widget;
1060 <span id='Ext-method-ns'> /**
1061 </span> * Convenient alias for {@link Ext#namespace Ext.namespace}
1065 Ext.ns = Ext.namespace;
1067 Class.registerPreprocessor('className', function(cls, data) {
1068 if (data.$className) {
1069 cls.$className = data.$className;
1071 cls.displayName = cls.$className;
1076 Class.setDefaultPreprocessorPosition('className', 'first');
1078 })(Ext.Class, Ext.Function.alias);
1079 </pre></pre></body></html>