<!DOCTYPE html> <html> <head> <meta http-equiv="Content-Type" content="text/html; charset=utf-8" /> <title>The source code</title> <link href="../resources/prettify/prettify.css" type="text/css" rel="stylesheet" /> <script type="text/javascript" src="../resources/prettify/prettify.js"></script> <style type="text/css"> .highlight { display: block; background-color: #ddd; } </style> <script type="text/javascript"> function highlight() { document.getElementById(location.hash.replace(/#/, "")).className = "highlight"; } </script> </head> <body onload="prettyPrint(); highlight();"> <pre class="prettyprint lang-js"><span id='Ext-Class'>/** </span> * @author Jacky Nguyen <jacky@sencha.com> * @docauthor Jacky Nguyen <jacky@sencha.com> * @class Ext.Class * * Handles class creation throughout the framework. This is a low level factory that is used by Ext.ClassManager and generally * should not be used directly. If you choose to use Ext.Class you will lose out on the namespace, aliasing and depency loading * features made available by Ext.ClassManager. The only time you would use Ext.Class directly is to create an anonymous class. * * If you wish to create a class you should use {@link Ext#define Ext.define} which aliases * {@link Ext.ClassManager#create Ext.ClassManager.create} to enable namespacing and dynamic dependency resolution. * * Ext.Class is the factory and **not** the superclass of everything. For the base class that **all** Ext classes inherit * from, see {@link Ext.Base}. */ (function() { var ExtClass, Base = Ext.Base, baseStaticMembers = [], baseStaticMember, baseStaticMemberLength; for (baseStaticMember in Base) { if (Base.hasOwnProperty(baseStaticMember)) { baseStaticMembers.push(baseStaticMember); } } baseStaticMemberLength = baseStaticMembers.length; // Creates a constructor that has nothing extra in its scope chain. function makeCtor (className) { function constructor () { // Opera has some problems returning from a constructor when Dragonfly isn't running. The || null seems to // be sufficient to stop it misbehaving. Known to be required against 10.53, 11.51 and 11.61. return this.constructor.apply(this, arguments) || null; } //<debug> if (className) { constructor.displayName = className; } //</debug> return constructor; } <span id='Ext-Class-method-constructor'> /** </span> * @method constructor * Create a new anonymous class. * * @param {Object} data An object represent the properties of this class * @param {Function} onCreated Optional, the callback function to be executed when this class is fully created. * Note that the creation process can be asynchronous depending on the pre-processors used. * * @return {Ext.Base} The newly created class */ Ext.Class = ExtClass = function(Class, data, onCreated) { if (typeof Class != 'function') { onCreated = data; data = Class; Class = null; } if (!data) { data = {}; } Class = ExtClass.create(Class, data); ExtClass.process(Class, data, onCreated); return Class; }; Ext.apply(ExtClass, { <span id='Ext-Class-method-onBeforeCreated'> /** </span> * @private * @param Class * @param data * @param hooks */ onBeforeCreated: function(Class, data, hooks) { Class.addMembers(data); hooks.onCreated.call(Class, Class); }, <span id='Ext-Class-method-create'> /** </span> * @private * @param Class * @param classData * @param onClassCreated */ create: function(Class, data) { var name, i; if (!Class) { Class = makeCtor( //<debug> data.$className //</debug> ); } for (i = 0; i < baseStaticMemberLength; i++) { name = baseStaticMembers[i]; Class[name] = Base[name]; } return Class; }, <span id='Ext-Class-method-process'> /** </span> * @private * @param Class * @param data * @param onCreated */ process: function(Class, data, onCreated) { var preprocessorStack = data.preprocessors || ExtClass.defaultPreprocessors, registeredPreprocessors = this.preprocessors, hooks = { onBeforeCreated: this.onBeforeCreated }, preprocessors = [], preprocessor, preprocessorsProperties, i, ln, j, subLn, preprocessorProperty, process; delete data.preprocessors; for (i = 0,ln = preprocessorStack.length; i < ln; i++) { preprocessor = preprocessorStack[i]; if (typeof preprocessor == 'string') { preprocessor = registeredPreprocessors[preprocessor]; preprocessorsProperties = preprocessor.properties; if (preprocessorsProperties === true) { preprocessors.push(preprocessor.fn); } else if (preprocessorsProperties) { for (j = 0,subLn = preprocessorsProperties.length; j < subLn; j++) { preprocessorProperty = preprocessorsProperties[j]; if (data.hasOwnProperty(preprocessorProperty)) { preprocessors.push(preprocessor.fn); break; } } } } else { preprocessors.push(preprocessor); } } hooks.onCreated = onCreated ? onCreated : Ext.emptyFn; hooks.preprocessors = preprocessors; this.doProcess(Class, data, hooks); }, doProcess: function(Class, data, hooks){ var me = this, preprocessor = hooks.preprocessors.shift(); if (!preprocessor) { hooks.onBeforeCreated.apply(me, arguments); return; } if (preprocessor.call(me, Class, data, hooks, me.doProcess) !== false) { me.doProcess(Class, data, hooks); } }, <span id='Ext-Class-property-preprocessors'> /** @private */ </span> preprocessors: {}, <span id='Ext-Class-static-method-registerPreprocessor'> /** </span> * Register a new pre-processor to be used during the class creation process * * @param {String} name The pre-processor's name * @param {Function} fn The callback function to be executed. Typical format: * * function(cls, data, fn) { * // Your code here * * // Execute this when the processing is finished. * // Asynchronous processing is perfectly ok * if (fn) { * fn.call(this, cls, data); * } * }); * * @param {Function} fn.cls The created class * @param {Object} fn.data The set of properties passed in {@link Ext.Class} constructor * @param {Function} fn.fn The callback function that **must** to be executed when this * pre-processor finishes, regardless of whether the processing is synchronous or aynchronous. * @return {Ext.Class} this * @private * @static */ registerPreprocessor: function(name, fn, properties, position, relativeTo) { if (!position) { position = 'last'; } if (!properties) { properties = [name]; } this.preprocessors[name] = { name: name, properties: properties || false, fn: fn }; this.setDefaultPreprocessorPosition(name, position, relativeTo); return this; }, <span id='Ext-Class-static-method-getPreprocessor'> /** </span> * Retrieve a pre-processor callback function by its name, which has been registered before * * @param {String} name * @return {Function} preprocessor * @private * @static */ getPreprocessor: function(name) { return this.preprocessors[name]; }, <span id='Ext-Class-method-getPreprocessors'> /** </span> * @private */ getPreprocessors: function() { return this.preprocessors; }, <span id='Ext-Class-property-defaultPreprocessors'> /** </span> * @private */ defaultPreprocessors: [], <span id='Ext-Class-static-method-getDefaultPreprocessors'> /** </span> * Retrieve the array stack of default pre-processors * @return {Function[]} defaultPreprocessors * @private * @static */ getDefaultPreprocessors: function() { return this.defaultPreprocessors; }, <span id='Ext-Class-static-method-setDefaultPreprocessors'> /** </span> * Set the default array stack of default pre-processors * * @private * @param {Array} preprocessors * @return {Ext.Class} this * @static */ setDefaultPreprocessors: function(preprocessors) { this.defaultPreprocessors = Ext.Array.from(preprocessors); return this; }, <span id='Ext-Class-static-method-setDefaultPreprocessorPosition'> /** </span> * Insert this pre-processor at a specific position in the stack, optionally relative to * any existing pre-processor. For example: * * Ext.Class.registerPreprocessor('debug', function(cls, data, fn) { * // Your code here * * if (fn) { * fn.call(this, cls, data); * } * }).setDefaultPreprocessorPosition('debug', 'last'); * * @private * @param {String} name The pre-processor name. Note that it needs to be registered with * {@link Ext.Class#registerPreprocessor registerPreprocessor} before this * @param {String} offset The insertion position. Four possible values are: * 'first', 'last', or: 'before', 'after' (relative to the name provided in the third argument) * @param {String} relativeName * @return {Ext.Class} this * @static */ setDefaultPreprocessorPosition: function(name, offset, relativeName) { var defaultPreprocessors = this.defaultPreprocessors, index; if (typeof offset == 'string') { if (offset === 'first') { defaultPreprocessors.unshift(name); return this; } else if (offset === 'last') { defaultPreprocessors.push(name); return this; } offset = (offset === 'after') ? 1 : -1; } index = Ext.Array.indexOf(defaultPreprocessors, relativeName); if (index !== -1) { Ext.Array.splice(defaultPreprocessors, Math.max(0, index + offset), 0, name); } return this; }, configNameCache: {}, getConfigNameMap: function(name) { var cache = this.configNameCache, map = cache[name], capitalizedName; if (!map) { capitalizedName = name.charAt(0).toUpperCase() + name.substr(1); map = cache[name] = { internal: name, initialized: '_is' + capitalizedName + 'Initialized', apply: 'apply' + capitalizedName, update: 'update' + capitalizedName, 'set': 'set' + capitalizedName, 'get': 'get' + capitalizedName, doSet : 'doSet' + capitalizedName, changeEvent: name.toLowerCase() + 'change' }; } return map; } }); <span id='Ext-Class-cfg-extend'> /** </span> * @cfg {String} extend * The parent class that this class extends. For example: * * Ext.define('Person', { * say: function(text) { alert(text); } * }); * * Ext.define('Developer', { * extend: 'Person', * say: function(text) { this.callParent(["print "+text]); } * }); */ ExtClass.registerPreprocessor('extend', function(Class, data) { var Base = Ext.Base, basePrototype = Base.prototype, extend = data.extend, Parent, parentPrototype, i; delete data.extend; if (extend && extend !== Object) { Parent = extend; } else { Parent = Base; } parentPrototype = Parent.prototype; if (!Parent.$isClass) { for (i in basePrototype) { if (!parentPrototype[i]) { parentPrototype[i] = basePrototype[i]; } } } Class.extend(Parent); Class.triggerExtended.apply(Class, arguments); if (data.onClassExtended) { Class.onExtended(data.onClassExtended, Class); delete data.onClassExtended; } }, true); //<feature classSystem.statics> <span id='Ext-Class-cfg-statics'> /** </span> * @cfg {Object} statics * List of static methods for this class. For example: * * 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'); */ ExtClass.registerPreprocessor('statics', function(Class, data) { Class.addStatics(data.statics); delete data.statics; }); //</feature> //<feature classSystem.inheritableStatics> <span id='Ext-Class-cfg-inheritableStatics'> /** </span> * @cfg {Object} inheritableStatics * List of inheritable static methods for this class. * Otherwise just like {@link #statics} but subclasses inherit these methods. */ ExtClass.registerPreprocessor('inheritableStatics', function(Class, data) { Class.addInheritableStatics(data.inheritableStatics); delete data.inheritableStatics; }); //</feature> //<feature classSystem.config> <span id='Ext-Class-cfg-config'> /** </span> * @cfg {Object} config * List of configuration options with their default values, for which automatically * accessor methods are generated. For example: * * Ext.define('SmartPhone', { * config: { * hasTouchScreen: false, * operatingSystem: 'Other', * price: 500 * }, * constructor: function(cfg) { * this.initConfig(cfg); * } * }); * * var iPhone = new SmartPhone({ * hasTouchScreen: true, * operatingSystem: 'iOS' * }); * * iPhone.getPrice(); // 500; * iPhone.getOperatingSystem(); // 'iOS' * iPhone.getHasTouchScreen(); // true; */ ExtClass.registerPreprocessor('config', function(Class, data) { var config = data.config, prototype = Class.prototype; delete data.config; Ext.Object.each(config, function(name, value) { var nameMap = ExtClass.getConfigNameMap(name), internalName = nameMap.internal, initializedName = nameMap.initialized, applyName = nameMap.apply, updateName = nameMap.update, setName = nameMap.set, getName = nameMap.get, hasOwnSetter = (setName in prototype) || data.hasOwnProperty(setName), hasOwnApplier = (applyName in prototype) || data.hasOwnProperty(applyName), hasOwnUpdater = (updateName in prototype) || data.hasOwnProperty(updateName), optimizedGetter, customGetter; if (value === null || (!hasOwnSetter && !hasOwnApplier && !hasOwnUpdater)) { prototype[internalName] = value; prototype[initializedName] = true; } else { prototype[initializedName] = false; } if (!hasOwnSetter) { data[setName] = function(value) { var oldValue = this[internalName], applier = this[applyName], updater = this[updateName]; if (!this[initializedName]) { this[initializedName] = true; } if (applier) { value = applier.call(this, value, oldValue); } if (typeof value != 'undefined') { this[internalName] = value; if (updater && value !== oldValue) { updater.call(this, value, oldValue); } } return this; }; } if (!(getName in prototype) || data.hasOwnProperty(getName)) { customGetter = data[getName] || false; if (customGetter) { optimizedGetter = function() { return customGetter.apply(this, arguments); }; } else { optimizedGetter = function() { return this[internalName]; }; } data[getName] = function() { var currentGetter; if (!this[initializedName]) { this[initializedName] = true; this[setName](this.config[name]); } currentGetter = this[getName]; if ('$previous' in currentGetter) { currentGetter.$previous = optimizedGetter; } else { this[getName] = optimizedGetter; } return optimizedGetter.apply(this, arguments); }; } }); Class.addConfig(config, true); }); //</feature> //<feature classSystem.mixins> <span id='Ext-Class-cfg-mixins'> /** </span> * @cfg {String[]/Object} mixins * List of classes to mix into this class. For example: * * Ext.define('CanSing', { * sing: function() { * alert("I'm on the highway to hell...") * } * }); * * Ext.define('Musician', { * mixins: ['CanSing'] * }) * * In this case the Musician class will get a `sing` method from CanSing mixin. * * But what if the Musician already has a `sing` method? Or you want to mix * in two classes, both of which define `sing`? In such a cases it's good * to define mixins as an object, where you assign a name to each mixin: * * Ext.define('Musician', { * mixins: { * canSing: 'CanSing' * }, * * sing: function() { * // delegate singing operation to mixin * this.mixins.canSing.sing.call(this); * } * }) * * In this case the `sing` method of Musician will overwrite the * mixed in `sing` method. But you can access the original mixed in method * through special `mixins` property. */ ExtClass.registerPreprocessor('mixins', function(Class, data, hooks) { var mixins = data.mixins, name, mixin, i, ln; delete data.mixins; Ext.Function.interceptBefore(hooks, 'onCreated', function() { if (mixins instanceof Array) { for (i = 0,ln = mixins.length; i < ln; i++) { mixin = mixins[i]; name = mixin.prototype.mixinId || mixin.$className; Class.mixin(name, mixin); } } else { for (var mixinName in mixins) { if (mixins.hasOwnProperty(mixinName)) { Class.mixin(mixinName, mixins[mixinName]); } } } }); }); //</feature> //<feature classSystem.backwardsCompatible> // Backwards compatible Ext.extend = function(Class, Parent, members) { if (arguments.length === 2 && Ext.isObject(Parent)) { members = Parent; Parent = Class; Class = null; } var cls; if (!Parent) { throw new Error("[Ext.extend] Attempting to extend from a class which has not been loaded on the page."); } members.extend = Parent; members.preprocessors = [ 'extend' //<feature classSystem.statics> ,'statics' //</feature> //<feature classSystem.inheritableStatics> ,'inheritableStatics' //</feature> //<feature classSystem.mixins> ,'mixins' //</feature> //<feature classSystem.config> ,'config' //</feature> ]; if (Class) { cls = new ExtClass(Class, members); // The 'constructor' is given as 'Class' but also needs to be on prototype cls.prototype.constructor = Class; } else { cls = new ExtClass(members); } cls.prototype.override = function(o) { for (var m in o) { if (o.hasOwnProperty(m)) { this[m] = o[m]; } } }; return cls; }; //</feature> }()); </pre> </body> </html>