/** * @class Ext.ClassManager * * Ext.ClassManager manages all classes and handles mapping from string class name to * actual class objects throughout the whole framework. It is not generally accessed directly, rather through * these convenient shorthands: * * - {@link Ext#define Ext.define} * - {@link Ext#create Ext.create} * - {@link Ext#widget Ext.widget} * - {@link Ext#getClass Ext.getClass} * - {@link Ext#getClassName Ext.getClassName} * * # Basic syntax: * * Ext.define(className, properties); * * in which `properties` is an object represent a collection of properties that apply to the class. See * {@link Ext.ClassManager#create} for more detailed instructions. * * Ext.define('Person', { * name: 'Unknown', * * constructor: function(name) { * if (name) { * this.name = name; * } * }, * * eat: function(foodType) { * alert("I'm eating: " + foodType); * * return this; * } * }); * * var aaron = new Person("Aaron"); * aaron.eat("Sandwich"); // alert("I'm eating: Sandwich"); * * Ext.Class has a powerful set of extensible {@link Ext.Class#registerPreprocessor pre-processors} which takes care of * everything related to class creation, including but not limited to inheritance, mixins, configuration, statics, etc. * * # Inheritance: * * Ext.define('Developer', { * extend: 'Person', * * constructor: function(name, isGeek) { * this.isGeek = isGeek; * * // Apply a method from the parent class' prototype * this.callParent([name]); * }, * * code: function(language) { * alert("I'm coding in: " + language); * * this.eat("Bugs"); * * return this; * } * }); * * var jacky = new Developer("Jacky", true); * jacky.code("JavaScript"); // alert("I'm coding in: JavaScript"); * // alert("I'm eating: Bugs"); * * See {@link Ext.Base#callParent} for more details on calling superclass' methods * * # Mixins: * * Ext.define('CanPlayGuitar', { * playGuitar: function() { * alert("F#...G...D...A"); * } * }); * * Ext.define('CanComposeSongs', { * composeSongs: function() { ... } * }); * * Ext.define('CanSing', { * sing: function() { * alert("For he's a jolly good fellow...") * } * }); * * Ext.define('Musician', { * extend: 'Person', * * mixins: { * canPlayGuitar: 'CanPlayGuitar', * canComposeSongs: 'CanComposeSongs', * canSing: 'CanSing' * } * }) * * Ext.define('CoolPerson', { * extend: 'Person', * * mixins: { * canPlayGuitar: 'CanPlayGuitar', * canSing: 'CanSing' * }, * * sing: function() { * alert("Ahem...."); * * this.mixins.canSing.sing.call(this); * * alert("[Playing guitar at the same time...]"); * * this.playGuitar(); * } * }); * * var me = new CoolPerson("Jacky"); * * me.sing(); // alert("Ahem..."); * // alert("For he's a jolly good fellow..."); * // alert("[Playing guitar at the same time...]"); * // alert("F#...G...D...A"); * * # Config: * * Ext.define('SmartPhone', { * config: { * hasTouchScreen: false, * operatingSystem: 'Other', * price: 500 * }, * * isExpensive: false, * * constructor: function(config) { * this.initConfig(config); * }, * * applyPrice: function(price) { * this.isExpensive = (price > 500); * * return price; * }, * * applyOperatingSystem: function(operatingSystem) { * if (!(/^(iOS|Android|BlackBerry)$/i).test(operatingSystem)) { * return 'Other'; * } * * return operatingSystem; * } * }); * * var iPhone = new SmartPhone({ * hasTouchScreen: true, * operatingSystem: 'iOS' * }); * * iPhone.getPrice(); // 500; * iPhone.getOperatingSystem(); // 'iOS' * iPhone.getHasTouchScreen(); // true; * * iPhone.isExpensive; // false; * iPhone.setPrice(600); * iPhone.getPrice(); // 600 * iPhone.isExpensive; // true; * * iPhone.setOperatingSystem('AlienOS'); * iPhone.getOperatingSystem(); // 'Other' * * # Statics: * * Ext.define('Computer', { * statics: { * factory: function(brand) { * // 'this' in static methods refer to the class itself * return new this(brand); * } * }, * * constructor: function() { ... } * }); * * var dellComputer = Computer.factory('Dell'); * * Also see {@link Ext.Base#statics} and {@link Ext.Base#self} for more details on accessing * static properties within class methods * * @singleton */ /** * @cfg xtype * @member Ext.Class * @inheritdoc Ext.Component#cfg-xtype */ /** * @cfg {String} override * @member Ext.Class * Overrides members of the specified `target` class. * * **NOTE:** the overridden class must have been defined using * {@link Ext#define Ext.define} in order to use the `override` config. * * Methods defined on the overriding class will not automatically call the methods of * the same name in the ancestor class chain. To call the parent's method of the * same name you must call {@link Ext.Base#callParent callParent}. To skip the * method of the overridden class and call its parent you will instead call * {@link Ext.Base#callSuper callSuper}. * * See {@link Ext#define Ext.define} for additional usage examples. */ /** * @cfg {Object} platformConfig * Allows setting config values for a class based on specific platforms. The value * of this config is an object whose properties are "rules" and whose values are * objects containing config values. * * For example: * * Ext.define('App.view.Foo', { * extend: 'Ext.panel.Panel', * * platformConfig: { * desktop: { * title: 'Some Rather Descriptive Title' * }, * * '!desktop': { * title: 'Short Title' * } * } * }); * * In the above, "desktop" and "!desktop" are (mutually exclusive) rules. Whichever * evaluates to `true` will have its configs applied to the class. In this case, only * the "title" property, but the object can contain any number of config properties. * In this case, the `platformConfig` is evaluated as part of the class and there is * no cost for each instance created. * * The rules are evaluated expressions in the context of the platform tags contained * in `{@link Ext#platformTags Ext.platformTags}`. Any properties of that object are * implicitly usable (as shown above). * * If a `platformConfig` specifies a config value, it will replace any values declared * on the class itself. * * Use of `platformConfig` on instances is handled by the config system when classes * call `{@link Ext.Base#initConfig initConfig}`. For example: * * Ext.create({ * xtype: 'panel', * * platformConfig: { * desktop: { * title: 'Some Rather Descriptive Title' * }, * * '!desktop': { * title: 'Short Title' * } * } * }); * * The following is equivalent to the above: * * if (Ext.platformTags.desktop) { * Ext.create({ * xtype: 'panel', * title: 'Some Rather Descriptive Title' * }); * } else { * Ext.create({ * xtype: 'panel', * title: 'Short Title' * }); * } * * To adjust configs based on dynamic conditions, see `{@link Ext.mixin.Responsive}`. */ /** * @cfg {String/String[]} alias * @member Ext.Class * List of short aliases for class names. An alias consists of a namespace and a name * concatenated by a period as <namespace>.<name> * * - **namespace** - The namespace describes what kind of alias this is and must be * all lowercase. * - **name** - The name of the alias which allows the lazy-instantiation via the * alias. The name shouldn't contain any periods. * * A list of namespaces and the usages are: * * - **feature** - {@link Ext.grid.Panel Grid} features * - **plugin** - Plugins * - **store** - {@link Ext.data.Store} * - **widget** - Components * * Most useful for defining xtypes for widgets: * * Ext.define('MyApp.CoolPanel', { * extend: 'Ext.panel.Panel', * alias: ['widget.coolpanel'], * title: 'Yeah!' * }); * * // Using Ext.create * Ext.create('widget.coolpanel'); * * // Using the shorthand for defining widgets by xtype * Ext.widget('panel', { * items: [ * {xtype: 'coolpanel', html: 'Foo'}, * {xtype: 'coolpanel', html: 'Bar'} * ] * }); */ /** * @cfg {Boolean} singleton * @member Ext.Class * When set to true, the class will be instantiated as singleton. For example: * * Ext.define('Logger', { * singleton: true, * log: function(msg) { * console.log(msg); * } * }); * * Logger.log('Hello'); */ /** * @cfg {String/String[]} alternateClassName * @member Ext.Class * Defines alternate names for this class. For example: * * Ext.define('Developer', { * alternateClassName: ['Coder', 'Hacker'], * code: function(msg) { * alert('Typing... ' + msg); * } * }); * * var joe = Ext.create('Developer'); * joe.code('stackoverflow'); * * var rms = Ext.create('Hacker'); * rms.code('hack hack'); */ /** * @cfg {Object} debugHooks * A collection of diagnostic methods to decorate the real methods of the class. These * methods are applied as an `override` if this class has debug enabled as defined by * `Ext.isDebugEnabled`. * * These will be automatically removed by the Sencha Cmd compiler for production builds. * * Example usage: * * Ext.define('Foo.bar.Class', { * foo: function (a, b, c) { * ... * }, * * bar: function (a, b) { * ... * return 42; * }, * * debugHooks: { * foo: function (a, b, c) { * // check arguments... * return this.callParent(arguments); * } * } * }); * * If you specify a `$enabled` property in the `debugHooks` object that will be used * as the default enabled state for the hooks. If the `{@link Ext#manifest}` contains * a `debug` object of if `{@link Ext#debugConfig}` is specified, the `$enabled` flag * will override its "*" value. */ /** * @cfg {Object} deprecated * The object given has properties that describe the versions at which the deprecations * apply. * * The purpose of the `deprecated` declaration is to enable development mode to give * suitable error messages when deprecated methods or properties are used. Methods can * always be injected to provide this feedback, but properties can only be handled on * some browsers (those that support `Object.defineProperty`). * * In some cases, deprecated methods can be restored to their previous behavior or * added back if they have been removed. * * The structure of a `deprecated` declaration is this: * * Ext.define('Foo.bar.Class', { * ... * * deprecated: { * // Optional package name - default is the framework (ext or touch) * name: 'foobar', * * '5.0': { * methods: { * // Throws: '"removedMethod" is deprecated.' * removedMethod: null, * * // Throws: '"oldMethod" is deprecated. Please use "newMethod" instead.' * oldMethod: 'newMethod', * * // When this block is enabled, this method is applied as an * // override. Otherwise you get same as "removeMethod". * method: function () { * // Do what v5 "method" did. If "method" exists in newer * // versions callParent can call it. If 5.1 has "method" * // then it would be next in line, otherwise 5.2 and last * // would be the current class. * }, * * moreHelpful: { * message: 'Something helpful to do instead.', * fn: function () { * // The v5 "moreHelpful" method to use when enabled. * } * } * }, * properties: { * // Throws: '"removedProp" is deprecated.' * removedProp: null, * * // Throws: '"oldProp" is deprecated. Please use "newProp" instead.' * oldProp: 'newProp', * * helpful: { * message: 'Something helpful message about what to do.' * } * ... * }, * statics: { * methods: { * ... * }, * properties: { * ... * }, * } * }, * * '5.1': { * ... * }, * * '5.2': { * ... * } * } * }); * * The primary content of `deprecated` are the version number keys. These indicate * a version number where methods or properties were deprecated. These versions are * compared to the version reported by `Ext.getCompatVersion` to determine the action * to take for each "block". * * When the compatibility version is set to a value less than a version number key, * that block is said to be "enabled". For example, if a method was deprecated in * version 5.0 but the desired compatibility level is 4.2 then the block is used to * patch methods and (to some degree) restore pre-5.0 compatibility. * * When multiple active blocks have the same method name, each method is applied as * an override in reverse order of version. In the above example, if a method appears * in the "5.0", "5.1" and "5.2" blocks then the "5.2" method is applied as an override * first, followed by the "5.1" method and finally the "5.0" method. This means that * the `callParent` from the "5.0" method calls the "5.1" method which calls the * "5.2" method which can (if applicable) call the current version. */ /** * Instantiate a class by either full name, alias or alternate name. * * If {@link Ext.Loader} is {@link Ext.Loader#setConfig enabled} and the class has * not been defined yet, it will attempt to load the class via synchronous loading. * * For example, all these three lines return the same result: * * // xtype * var window = Ext.create({ * xtype: 'window', * width: 600, * height: 800, * ... * }); * * // alias * var window = Ext.create('widget.window', { * width: 600, * height: 800, * ... * }); * * // alternate name * var window = Ext.create('Ext.Window', { * width: 600, * height: 800, * ... * }); * * // full class name * var window = Ext.create('Ext.window.Window', { * width: 600, * height: 800, * ... * }); * * // single object with xclass property: * var window = Ext.create({ * xclass: 'Ext.window.Window', // any valid value for 'name' (above) * width: 600, * height: 800, * ... * }); * * @param {String} [name] The class name or alias. Can be specified as `xclass` * property if only one object parameter is specified. * @param {Object...} [args] Additional arguments after the name will be passed to * the class' constructor. * @return {Object} instance * @member Ext * @method create */ /** * @method widget * Convenient shorthand to create a widget by its xtype or a config object. * * var button = Ext.widget('button'); // Equivalent to Ext.create('widget.button'); * * var panel = Ext.widget('panel', { // Equivalent to Ext.create('widget.panel') * title: 'Panel' * }); * * var grid = Ext.widget({ * xtype: 'grid', * ... * }); * * If a {@link Ext.Component component} instance is passed, it is simply returned. * * @member Ext * @param {String} [name] The xtype of the widget to create. * @param {Object} [config] The configuration object for the widget constructor. * @return {Object} The widget instance */ /** * @method define * Defines a class or override. A basic class is defined like this: * * Ext.define('My.awesome.Class', { * someProperty: 'something', * * someMethod: function(s) { * alert(s + this.someProperty); * } * * ... * }); * * var obj = new My.awesome.Class(); * * obj.someMethod('Say '); // alerts 'Say something' * * To create an anonymous class, pass `null` for the `className`: * * Ext.define(null, { * constructor: function () { * // ... * } * }); * * In some cases, it is helpful to create a nested scope to contain some private * properties. The best way to do this is to pass a function instead of an object * as the second parameter. This function will be called to produce the class * body: * * Ext.define('MyApp.foo.Bar', function () { * var id = 0; * * return { * nextId: function () { * return ++id; * } * }; * }); * * _Note_ that when using override, the above syntax will not override successfully, because * the passed function would need to be executed first to determine whether or not the result * is an override or defining a new object. As such, an alternative syntax that immediately * invokes the function can be used: * * Ext.define('MyApp.override.BaseOverride', function () { * var counter = 0; * * return { * override: 'Ext.Component', * logId: function () { * console.log(++counter, this.id); * } * }; * }()); * * * When using this form of `Ext.define`, the function is passed a reference to its * class. This can be used as an efficient way to access any static properties you * may have: * * Ext.define('MyApp.foo.Bar', function (Bar) { * return { * statics: { * staticMethod: function () { * // ... * } * }, * * method: function () { * return Bar.staticMethod(); * } * }; * }); * * To define an override, include the `override` property. The content of an * override is aggregated with the specified class in order to extend or modify * that class. This can be as simple as setting default property values or it can * extend and/or replace methods. This can also extend the statics of the class. * * One use for an override is to break a large class into manageable pieces. * * // File: /src/app/Panel.js * * Ext.define('My.app.Panel', { * extend: 'Ext.panel.Panel', * requires: [ * 'My.app.PanelPart2', * 'My.app.PanelPart3' * ] * * constructor: function (config) { * this.callParent(arguments); // calls Ext.panel.Panel's constructor * //... * }, * * statics: { * method: function () { * return 'abc'; * } * } * }); * * // File: /src/app/PanelPart2.js * Ext.define('My.app.PanelPart2', { * override: 'My.app.Panel', * * constructor: function (config) { * this.callParent(arguments); // calls My.app.Panel's constructor * //... * } * }); * * Another use of overrides is to provide optional parts of classes that can be * independently required. In this case, the class may even be unaware of the * override altogether. * * Ext.define('My.ux.CoolTip', { * override: 'Ext.tip.ToolTip', * * constructor: function (config) { * this.callParent(arguments); // calls Ext.tip.ToolTip's constructor * //... * } * }); * * The above override can now be required as normal. * * Ext.define('My.app.App', { * requires: [ * 'My.ux.CoolTip' * ] * }); * * Overrides can also contain statics, inheritableStatics, or privates: * * Ext.define('My.app.BarMod', { * override: 'Ext.foo.Bar', * * statics: { * method: function (x) { * return this.callParent([x * 2]); // call Ext.foo.Bar.method * } * } * }); * * Starting in version 4.2.2, overrides can declare their `compatibility` based * on the framework version or on versions of other packages. For details on the * syntax and options for these checks, see `Ext.checkVersion`. * * The simplest use case is to test framework version for compatibility: * * Ext.define('App.overrides.grid.Panel', { * override: 'Ext.grid.Panel', * * compatibility: '4.2.2', // only if framework version is 4.2.2 * * //... * }); * * An array is treated as an OR, so if any specs match, the override is * compatible. * * Ext.define('App.overrides.some.Thing', { * override: 'Foo.some.Thing', * * compatibility: [ * '4.2.2', * '[email protected]' * ], * * //... * }); * * To require that all specifications match, an object can be provided: * * Ext.define('App.overrides.some.Thing', { * override: 'Foo.some.Thing', * * compatibility: { * and: [ * '4.2.2', * '[email protected]' * ] * }, * * //... * }); * * Because the object form is just a recursive check, these can be nested: * * Ext.define('App.overrides.some.Thing', { * override: 'Foo.some.Thing', * * compatibility: { * and: [ * '4.2.2', // exactly version 4.2.2 of the framework *AND* * { * // either (or both) of these package specs: * or: [ * '[email protected]', * '[email protected]+' * ] * } * ] * }, * * //... * }); * * IMPORTANT: An override is only included in a build if the class it overrides is * required. Otherwise, the override, like the target class, is not included. In * Sencha Cmd v4, the `compatibility` declaration can likewise be used to remove * incompatible overrides from a build. * * @param {String} className The class name to create in string dot-namespaced format, for example: * 'My.very.awesome.Class', 'FeedViewer.plugin.CoolPager' * It is highly recommended to follow this simple convention: * - The root and the class name are 'CamelCased' * - Everything else is lower-cased * Pass `null` to create an anonymous class. * @param {Object} data The key - value pairs of properties to apply to this class. Property names can be of any valid * strings, except those in the reserved listed below: * * - {@link Ext.Class#cfg-alias alias} * - {@link Ext.Class#cfg-alternateClassName alternateClassName} * - {@link Ext.Class#cfg-cachedConfig cachedConfig} * - {@link Ext.Class#cfg-config config} * - {@link Ext.Class#cfg-extend extend} * - {@link Ext.Class#cfg-inheritableStatics inheritableStatics} * - {@link Ext.Class#cfg-mixins mixins} * - {@link Ext.Class#cfg-override override} * - {@link Ext.Class#cfg-platformConfig platformConfig} * - {@link Ext.Class#cfg-privates privates} * - {@link Ext.Class#cfg-requires requires} * - `self` * - {@link Ext.Class#cfg-singleton singleton} * - {@link Ext.Class#cfg-statics statics} * - {@link Ext.Class#cfg-uses uses} * - {@link Ext.Class#cfg-xtype xtype} (for {@link Ext.Component Components} only) * * @param {Function} [createdFn] Callback to execute after the class is created, the execution scope of which * (`this`) will be the newly created class itself. * @return {Ext.Base} * @member Ext */