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-Class'>/**
2 </span> * @author Jacky Nguyen <jacky@sencha.com>
3 * @docauthor Jacky Nguyen <jacky@sencha.com>
6 * Handles class creation throughout the whole framework. Note that most of the time {@link Ext#define Ext.define} should
7 * be used instead, since it's a higher level wrapper that aliases to {@link Ext.ClassManager#create}
8 * to enable namespacing and dynamic dependency resolution.
12 * Ext.define(className, properties);
14 * in which `properties` is an object represent a collection of properties that apply to the class. See
15 * {@link Ext.ClassManager#create} for more detailed instructions.
17 * Ext.define('Person', {
20 * constructor: function(name) {
28 * eat: function(foodType) {
29 * alert("I'm eating: " + foodType);
35 * var aaron = new Person("Aaron");
36 * aaron.eat("Sandwich"); // alert("I'm eating: Sandwich");
38 * Ext.Class has a powerful set of extensible {@link Ext.Class#registerPreprocessor pre-processors} which takes care of
39 * everything related to class creation, including but not limited to inheritance, mixins, configuration, statics, etc.
43 * Ext.define('Developer', {
46 * constructor: function(name, isGeek) {
47 * this.isGeek = isGeek;
49 * // Apply a method from the parent class' prototype
50 * this.callParent([name]);
56 * code: function(language) {
57 * alert("I'm coding in: " + language);
59 * this.eat("Bugs");
65 * var jacky = new Developer("Jacky", true);
66 * jacky.code("JavaScript"); // alert("I'm coding in: JavaScript");
67 * // alert("I'm eating: Bugs");
69 * See {@link Ext.Base#callParent} for more details on calling superclass' methods
73 * Ext.define('CanPlayGuitar', {
74 * playGuitar: function() {
75 * alert("F#...G...D...A");
79 * Ext.define('CanComposeSongs', {
80 * composeSongs: function() { ... }
83 * Ext.define('CanSing', {
85 * alert("I'm on the highway to hell...")
89 * Ext.define('Musician', {
93 * canPlayGuitar: 'CanPlayGuitar',
94 * canComposeSongs: 'CanComposeSongs',
99 * Ext.define('CoolPerson', {
103 * canPlayGuitar: 'CanPlayGuitar',
108 * alert("Ahem....");
110 * this.mixins.canSing.sing.call(this);
112 * alert("[Playing guitar at the same time...]");
118 * var me = new CoolPerson("Jacky");
120 * me.sing(); // alert("Ahem...");
121 * // alert("I'm on the highway to hell...");
122 * // alert("[Playing guitar at the same time...]");
123 * // alert("F#...G...D...A");
127 * Ext.define('SmartPhone', {
129 * hasTouchScreen: false,
130 * operatingSystem: 'Other',
134 * isExpensive: false,
136 * constructor: function(config) {
137 * this.initConfig(config);
142 * applyPrice: function(price) {
143 * this.isExpensive = (price > 500);
148 * applyOperatingSystem: function(operatingSystem) {
149 * if (!(/^(iOS|Android|BlackBerry)$/i).test(operatingSystem)) {
153 * return operatingSystem;
157 * var iPhone = new SmartPhone({
158 * hasTouchScreen: true,
159 * operatingSystem: 'iOS'
162 * iPhone.getPrice(); // 500;
163 * iPhone.getOperatingSystem(); // 'iOS'
164 * iPhone.getHasTouchScreen(); // true;
165 * iPhone.hasTouchScreen(); // true
167 * iPhone.isExpensive; // false;
168 * iPhone.setPrice(600);
169 * iPhone.getPrice(); // 600
170 * iPhone.isExpensive; // true;
172 * iPhone.setOperatingSystem('AlienOS');
173 * iPhone.getOperatingSystem(); // 'Other'
177 * Ext.define('Computer', {
179 * factory: function(brand) {
180 * // 'this' in static methods refer to the class itself
181 * return new this(brand);
185 * constructor: function() { ... }
188 * var dellComputer = Computer.factory('Dell');
190 * Also see {@link Ext.Base#statics} and {@link Ext.Base#self} for more details on accessing
191 * static properties within class methods
198 baseStaticProperties = [],
201 for (baseStaticProperty in Base) {
202 if (Base.hasOwnProperty(baseStaticProperty)) {
203 baseStaticProperties.push(baseStaticProperty);
207 <span id='Ext-Class-method-constructor'><span id='Ext-Class'> /**
208 </span></span> * @constructor
209 * @param {Object} classData An object represent the properties of this class
210 * @param {Function} createdFn Optional, the callback function to be executed when this class is fully created.
211 * Note that the creation process can be asynchronous depending on the pre-processors used.
212 * @return {Ext.Base} The newly created class
214 Ext.Class = Class = function(newClass, classData, onClassCreated) {
215 if (typeof newClass !== 'function') {
216 onClassCreated = classData;
217 classData = newClass;
218 newClass = function() {
219 return this.constructor.apply(this, arguments);
227 var preprocessorStack = classData.preprocessors || Class.getDefaultPreprocessors(),
228 registeredPreprocessors = Class.getPreprocessors(),
231 preprocessor, preprocessors, staticPropertyName, process, i, j, ln;
233 for (i = 0, ln = baseStaticProperties.length; i < ln; i++) {
234 staticPropertyName = baseStaticProperties[i];
235 newClass[staticPropertyName] = Base[staticPropertyName];
238 delete classData.preprocessors;
240 for (j = 0, ln = preprocessorStack.length; j < ln; j++) {
241 preprocessor = preprocessorStack[j];
243 if (typeof preprocessor === 'string') {
244 preprocessor = registeredPreprocessors[preprocessor];
246 if (!preprocessor.always) {
247 if (classData.hasOwnProperty(preprocessor.name)) {
248 preprocessors.push(preprocessor.fn);
252 preprocessors.push(preprocessor.fn);
256 preprocessors.push(preprocessor);
260 classData.onClassCreated = onClassCreated;
262 classData.onBeforeClassCreated = function(cls, data) {
263 onClassCreated = data.onClassCreated;
265 delete data.onBeforeClassCreated;
266 delete data.onClassCreated;
270 if (onClassCreated) {
271 onClassCreated.call(cls, cls);
275 process = function(cls, data) {
276 preprocessor = preprocessors[index++];
279 data.onBeforeClassCreated.apply(this, arguments);
283 if (preprocessor.call(this, cls, data, process) !== false) {
284 process.apply(this, arguments);
288 process.call(Class, newClass, classData);
295 <span id='Ext-Class-property-preprocessors'> /** @private */
296 </span> preprocessors: {},
298 <span id='Ext-Class-method-registerPreprocessor'> /**
299 </span> * Register a new pre-processor to be used during the class creation process
301 * @member Ext.Class registerPreprocessor
302 * @param {String} name The pre-processor's name
303 * @param {Function} fn The callback function to be executed. Typical format:
305 function(cls, data, fn) {
308 // Execute this when the processing is finished.
309 // Asynchronous processing is perfectly ok
311 fn.call(this, cls, data);
315 * Passed arguments for this function are:
317 * - `{Function} cls`: The created class
318 * - `{Object} data`: The set of properties passed in {@link Ext.Class} constructor
319 * - `{Function} fn`: The callback function that <b>must</b> to be executed when this pre-processor finishes,
320 * regardless of whether the processing is synchronous or aynchronous
322 * @return {Ext.Class} this
325 registerPreprocessor: function(name, fn, always) {
326 this.preprocessors[name] = {
328 always: always || false,
335 <span id='Ext-Class-method-getPreprocessor'> /**
336 </span> * Retrieve a pre-processor callback function by its name, which has been registered before
338 * @param {String} name
339 * @return {Function} preprocessor
341 getPreprocessor: function(name) {
342 return this.preprocessors[name];
345 getPreprocessors: function() {
346 return this.preprocessors;
349 <span id='Ext-Class-method-getDefaultPreprocessors'> /**
350 </span> * Retrieve the array stack of default pre-processors
352 * @return {Function} defaultPreprocessors
354 getDefaultPreprocessors: function() {
355 return this.defaultPreprocessors || [];
358 <span id='Ext-Class-method-setDefaultPreprocessors'> /**
359 </span> * Set the default array stack of default pre-processors
361 * @param {Array} preprocessors
362 * @return {Ext.Class} this
364 setDefaultPreprocessors: function(preprocessors) {
365 this.defaultPreprocessors = Ext.Array.from(preprocessors);
370 <span id='Ext-Class-method-setDefaultPreprocessorPosition'> /**
371 </span> * Insert this pre-processor at a specific position in the stack, optionally relative to
372 * any existing pre-processor. For example:
374 Ext.Class.registerPreprocessor('debug', function(cls, data, fn) {
378 fn.call(this, cls, data);
380 }).insertDefaultPreprocessor('debug', 'last');
382 * @param {String} name The pre-processor name. Note that it needs to be registered with
383 * {@link Ext#registerPreprocessor registerPreprocessor} before this
384 * @param {String} offset The insertion position. Four possible values are:
385 * 'first', 'last', or: 'before', 'after' (relative to the name provided in the third argument)
386 * @param {String} relativeName
387 * @return {Ext.Class} this
390 setDefaultPreprocessorPosition: function(name, offset, relativeName) {
391 var defaultPreprocessors = this.defaultPreprocessors,
394 if (typeof offset === 'string') {
395 if (offset === 'first') {
396 defaultPreprocessors.unshift(name);
400 else if (offset === 'last') {
401 defaultPreprocessors.push(name);
406 offset = (offset === 'after') ? 1 : -1;
409 index = Ext.Array.indexOf(defaultPreprocessors, relativeName);
412 defaultPreprocessors.splice(Math.max(0, index + offset), 0, name);
419 Class.registerPreprocessor('extend', function(cls, data) {
420 var extend = data.extend,
422 basePrototype = base.prototype,
423 prototype = function() {},
424 parent, i, k, ln, staticName, parentStatics,
425 parentPrototype, clsPrototype;
427 if (extend && extend !== Object) {
434 parentPrototype = parent.prototype;
436 prototype.prototype = parentPrototype;
437 clsPrototype = cls.prototype = new prototype();
439 if (!('$class' in parent)) {
440 for (i in basePrototype) {
441 if (!parentPrototype[i]) {
442 parentPrototype[i] = basePrototype[i];
447 clsPrototype.self = cls;
449 cls.superclass = clsPrototype.superclass = parentPrototype;
453 // Statics inheritance
454 parentStatics = parentPrototype.$inheritableStatics;
457 for (k = 0, ln = parentStatics.length; k < ln; k++) {
458 staticName = parentStatics[k];
460 if (!cls.hasOwnProperty(staticName)) {
461 cls[staticName] = parent[staticName];
466 // Merge the parent class' config object without referencing it
467 if (parentPrototype.config) {
468 clsPrototype.config = Ext.Object.merge({}, parentPrototype.config);
471 clsPrototype.config = {};
474 if (clsPrototype.$onExtended) {
475 clsPrototype.$onExtended.call(cls, cls, data);
478 if (data.onClassExtended) {
479 clsPrototype.$onExtended = data.onClassExtended;
480 delete data.onClassExtended;
485 Class.registerPreprocessor('statics', function(cls, data) {
486 var statics = data.statics,
489 for (name in statics) {
490 if (statics.hasOwnProperty(name)) {
491 cls[name] = statics[name];
498 Class.registerPreprocessor('inheritableStatics', function(cls, data) {
499 var statics = data.inheritableStatics,
501 prototype = cls.prototype,
504 inheritableStatics = prototype.$inheritableStatics;
506 if (!inheritableStatics) {
507 inheritableStatics = prototype.$inheritableStatics = [];
510 for (name in statics) {
511 if (statics.hasOwnProperty(name)) {
512 cls[name] = statics[name];
513 inheritableStatics.push(name);
517 delete data.inheritableStatics;
520 Class.registerPreprocessor('mixins', function(cls, data) {
521 cls.mixin(data.mixins);
526 Class.registerPreprocessor('config', function(cls, data) {
527 var prototype = cls.prototype;
529 Ext.Object.each(data.config, function(name) {
530 var cName = name.charAt(0).toUpperCase() + name.substr(1),
532 apply = 'apply' + cName,
533 setter = 'set' + cName,
534 getter = 'get' + cName;
536 if (!(apply in prototype) && !data.hasOwnProperty(apply)) {
537 data[apply] = function(val) {
542 if (!(setter in prototype) && !data.hasOwnProperty(setter)) {
543 data[setter] = function(val) {
544 var ret = this[apply].call(this, val, this[pName]);
546 if (ret !== undefined) {
554 if (!(getter in prototype) && !data.hasOwnProperty(getter)) {
555 data[getter] = function() {
561 Ext.Object.merge(prototype.config, data.config);
565 Class.setDefaultPreprocessors(['extend', 'statics', 'inheritableStatics', 'mixins', 'config']);
567 // Backwards compatible
568 Ext.extend = function(subclass, superclass, members) {
569 if (arguments.length === 2 && Ext.isObject(superclass)) {
570 members = superclass;
571 superclass = subclass;
578 Ext.Error.raise("Attempting to extend from a class which has not been loaded on the page.");
581 members.extend = superclass;
582 members.preprocessors = ['extend', 'mixins', 'config', 'statics'];
585 cls = new Class(subclass, members);
588 cls = new Class(members);
591 cls.prototype.override = function(o) {
593 if (o.hasOwnProperty(m)) {
603 </pre></pre></body></html>