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-Class'>/**
19 </span> * @author Jacky Nguyen <jacky@sencha.com>
20 * @docauthor Jacky Nguyen <jacky@sencha.com>
23 * Handles class creation throughout the whole framework. Note that most of the time {@link Ext#define Ext.define} should
24 * be used instead, since it's a higher level wrapper that aliases to {@link Ext.ClassManager#create}
25 * to enable namespacing and dynamic dependency resolution.
29 * Ext.define(className, properties);
31 * in which `properties` is an object represent a collection of properties that apply to the class. See
32 * {@link Ext.ClassManager#create} for more detailed instructions.
34 * Ext.define('Person', {
37 * constructor: function(name) {
45 * eat: function(foodType) {
46 * alert("I'm eating: " + foodType);
52 * var aaron = new Person("Aaron");
53 * aaron.eat("Sandwich"); // alert("I'm eating: Sandwich");
55 * Ext.Class has a powerful set of extensible {@link Ext.Class#registerPreprocessor pre-processors} which takes care of
56 * everything related to class creation, including but not limited to inheritance, mixins, configuration, statics, etc.
60 * Ext.define('Developer', {
63 * constructor: function(name, isGeek) {
64 * this.isGeek = isGeek;
66 * // Apply a method from the parent class' prototype
67 * this.callParent([name]);
73 * code: function(language) {
74 * alert("I'm coding in: " + language);
76 * this.eat("Bugs");
82 * var jacky = new Developer("Jacky", true);
83 * jacky.code("JavaScript"); // alert("I'm coding in: JavaScript");
84 * // alert("I'm eating: Bugs");
86 * See {@link Ext.Base#callParent} for more details on calling superclass' methods
90 * Ext.define('CanPlayGuitar', {
91 * playGuitar: function() {
92 * alert("F#...G...D...A");
96 * Ext.define('CanComposeSongs', {
97 * composeSongs: function() { ... }
100 * Ext.define('CanSing', {
102 * alert("I'm on the highway to hell...")
106 * Ext.define('Musician', {
110 * canPlayGuitar: 'CanPlayGuitar',
111 * canComposeSongs: 'CanComposeSongs',
116 * Ext.define('CoolPerson', {
120 * canPlayGuitar: 'CanPlayGuitar',
125 * alert("Ahem....");
127 * this.mixins.canSing.sing.call(this);
129 * alert("[Playing guitar at the same time...]");
135 * var me = new CoolPerson("Jacky");
137 * me.sing(); // alert("Ahem...");
138 * // alert("I'm on the highway to hell...");
139 * // alert("[Playing guitar at the same time...]");
140 * // alert("F#...G...D...A");
144 * Ext.define('SmartPhone', {
146 * hasTouchScreen: false,
147 * operatingSystem: 'Other',
151 * isExpensive: false,
153 * constructor: function(config) {
154 * this.initConfig(config);
159 * applyPrice: function(price) {
160 * this.isExpensive = (price > 500);
165 * applyOperatingSystem: function(operatingSystem) {
166 * if (!(/^(iOS|Android|BlackBerry)$/i).test(operatingSystem)) {
170 * return operatingSystem;
174 * var iPhone = new SmartPhone({
175 * hasTouchScreen: true,
176 * operatingSystem: 'iOS'
179 * iPhone.getPrice(); // 500;
180 * iPhone.getOperatingSystem(); // 'iOS'
181 * iPhone.getHasTouchScreen(); // true;
182 * iPhone.hasTouchScreen(); // true
184 * iPhone.isExpensive; // false;
185 * iPhone.setPrice(600);
186 * iPhone.getPrice(); // 600
187 * iPhone.isExpensive; // true;
189 * iPhone.setOperatingSystem('AlienOS');
190 * iPhone.getOperatingSystem(); // 'Other'
194 * Ext.define('Computer', {
196 * factory: function(brand) {
197 * // 'this' in static methods refer to the class itself
198 * return new this(brand);
202 * constructor: function() { ... }
205 * var dellComputer = Computer.factory('Dell');
207 * Also see {@link Ext.Base#statics} and {@link Ext.Base#self} for more details on accessing
208 * static properties within class methods
215 baseStaticProperties = [],
218 for (baseStaticProperty in Base) {
219 if (Base.hasOwnProperty(baseStaticProperty)) {
220 baseStaticProperties.push(baseStaticProperty);
224 <span id='Ext-Class-method-constructor'> /**
225 </span> * @method constructor
227 * @param {Object} classData An object represent the properties of this class
228 * @param {Function} createdFn Optional, the callback function to be executed when this class is fully created.
229 * Note that the creation process can be asynchronous depending on the pre-processors used.
230 * @return {Ext.Base} The newly created class
232 Ext.Class = Class = function(newClass, classData, onClassCreated) {
233 if (typeof newClass !== 'function') {
234 onClassCreated = classData;
235 classData = newClass;
236 newClass = function() {
237 return this.constructor.apply(this, arguments);
245 var preprocessorStack = classData.preprocessors || Class.getDefaultPreprocessors(),
246 registeredPreprocessors = Class.getPreprocessors(),
249 preprocessor, preprocessors, staticPropertyName, process, i, j, ln;
251 for (i = 0, ln = baseStaticProperties.length; i < ln; i++) {
252 staticPropertyName = baseStaticProperties[i];
253 newClass[staticPropertyName] = Base[staticPropertyName];
256 delete classData.preprocessors;
258 for (j = 0, ln = preprocessorStack.length; j < ln; j++) {
259 preprocessor = preprocessorStack[j];
261 if (typeof preprocessor === 'string') {
262 preprocessor = registeredPreprocessors[preprocessor];
264 if (!preprocessor.always) {
265 if (classData.hasOwnProperty(preprocessor.name)) {
266 preprocessors.push(preprocessor.fn);
270 preprocessors.push(preprocessor.fn);
274 preprocessors.push(preprocessor);
278 classData.onClassCreated = onClassCreated;
280 classData.onBeforeClassCreated = function(cls, data) {
281 onClassCreated = data.onClassCreated;
283 delete data.onBeforeClassCreated;
284 delete data.onClassCreated;
288 if (onClassCreated) {
289 onClassCreated.call(cls, cls);
293 process = function(cls, data) {
294 preprocessor = preprocessors[index++];
297 data.onBeforeClassCreated.apply(this, arguments);
301 if (preprocessor.call(this, cls, data, process) !== false) {
302 process.apply(this, arguments);
306 process.call(Class, newClass, classData);
313 <span id='Ext-Class-property-preprocessors'> /** @private */
314 </span> preprocessors: {},
316 <span id='Ext-Class-method-registerPreprocessor'> /**
317 </span> * Register a new pre-processor to be used during the class creation process
319 * @member Ext.Class registerPreprocessor
320 * @param {String} name The pre-processor's name
321 * @param {Function} fn The callback function to be executed. Typical format:
323 function(cls, data, fn) {
326 // Execute this when the processing is finished.
327 // Asynchronous processing is perfectly ok
329 fn.call(this, cls, data);
333 * Passed arguments for this function are:
335 * - `{Function} cls`: The created class
336 * - `{Object} data`: The set of properties passed in {@link Ext.Class} constructor
337 * - `{Function} fn`: The callback function that <b>must</b> to be executed when this pre-processor finishes,
338 * regardless of whether the processing is synchronous or aynchronous
340 * @return {Ext.Class} this
343 registerPreprocessor: function(name, fn, always) {
344 this.preprocessors[name] = {
346 always: always || false,
353 <span id='Ext-Class-method-getPreprocessor'> /**
354 </span> * Retrieve a pre-processor callback function by its name, which has been registered before
356 * @param {String} name
357 * @return {Function} preprocessor
359 getPreprocessor: function(name) {
360 return this.preprocessors[name];
363 getPreprocessors: function() {
364 return this.preprocessors;
367 <span id='Ext-Class-method-getDefaultPreprocessors'> /**
368 </span> * Retrieve the array stack of default pre-processors
370 * @return {Function} defaultPreprocessors
372 getDefaultPreprocessors: function() {
373 return this.defaultPreprocessors || [];
376 <span id='Ext-Class-method-setDefaultPreprocessors'> /**
377 </span> * Set the default array stack of default pre-processors
379 * @param {Array} preprocessors
380 * @return {Ext.Class} this
382 setDefaultPreprocessors: function(preprocessors) {
383 this.defaultPreprocessors = Ext.Array.from(preprocessors);
388 <span id='Ext-Class-method-setDefaultPreprocessorPosition'> /**
389 </span> * Insert this pre-processor at a specific position in the stack, optionally relative to
390 * any existing pre-processor. For example:
392 Ext.Class.registerPreprocessor('debug', function(cls, data, fn) {
396 fn.call(this, cls, data);
398 }).insertDefaultPreprocessor('debug', 'last');
400 * @param {String} name The pre-processor name. Note that it needs to be registered with
401 * {@link Ext#registerPreprocessor registerPreprocessor} before this
402 * @param {String} offset The insertion position. Four possible values are:
403 * 'first', 'last', or: 'before', 'after' (relative to the name provided in the third argument)
404 * @param {String} relativeName
405 * @return {Ext.Class} this
408 setDefaultPreprocessorPosition: function(name, offset, relativeName) {
409 var defaultPreprocessors = this.defaultPreprocessors,
412 if (typeof offset === 'string') {
413 if (offset === 'first') {
414 defaultPreprocessors.unshift(name);
418 else if (offset === 'last') {
419 defaultPreprocessors.push(name);
424 offset = (offset === 'after') ? 1 : -1;
427 index = Ext.Array.indexOf(defaultPreprocessors, relativeName);
430 Ext.Array.splice(defaultPreprocessors, Math.max(0, index + offset), 0, name);
437 <span id='Ext-Class-cfg-extend'> /**
438 </span> * @cfg {String} extend
439 * The parent class that this class extends. For example:
441 * Ext.define('Person', {
442 * say: function(text) { alert(text); }
445 * Ext.define('Developer', {
447 * say: function(text) { this.callParent(["print "+text]); }
450 Class.registerPreprocessor('extend', function(cls, data) {
451 var extend = data.extend,
453 basePrototype = base.prototype,
454 prototype = function() {},
455 parent, i, k, ln, staticName, parentStatics,
456 parentPrototype, clsPrototype;
458 if (extend && extend !== Object) {
465 parentPrototype = parent.prototype;
467 prototype.prototype = parentPrototype;
468 clsPrototype = cls.prototype = new prototype();
470 if (!('$class' in parent)) {
471 for (i in basePrototype) {
472 if (!parentPrototype[i]) {
473 parentPrototype[i] = basePrototype[i];
478 clsPrototype.self = cls;
480 cls.superclass = clsPrototype.superclass = parentPrototype;
484 // Statics inheritance
485 parentStatics = parentPrototype.$inheritableStatics;
488 for (k = 0, ln = parentStatics.length; k < ln; k++) {
489 staticName = parentStatics[k];
491 if (!cls.hasOwnProperty(staticName)) {
492 cls[staticName] = parent[staticName];
497 // Merge the parent class' config object without referencing it
498 if (parentPrototype.config) {
499 clsPrototype.config = Ext.Object.merge({}, parentPrototype.config);
502 clsPrototype.config = {};
505 if (clsPrototype.$onExtended) {
506 clsPrototype.$onExtended.call(cls, cls, data);
509 if (data.onClassExtended) {
510 clsPrototype.$onExtended = data.onClassExtended;
511 delete data.onClassExtended;
516 <span id='Ext-Class-cfg-statics'> /**
517 </span> * @cfg {Object} statics
518 * List of static methods for this class. For example:
520 * Ext.define('Computer', {
522 * factory: function(brand) {
523 * // 'this' in static methods refer to the class itself
524 * return new this(brand);
528 * constructor: function() { ... }
531 * var dellComputer = Computer.factory('Dell');
533 Class.registerPreprocessor('statics', function(cls, data) {
534 var statics = data.statics,
537 for (name in statics) {
538 if (statics.hasOwnProperty(name)) {
539 cls[name] = statics[name];
546 <span id='Ext-Class-cfg-inheritableStatics'> /**
547 </span> * @cfg {Object} inheritableStatics
548 * List of inheritable static methods for this class.
549 * Otherwise just like {@link #statics} but subclasses inherit these methods.
551 Class.registerPreprocessor('inheritableStatics', function(cls, data) {
552 var statics = data.inheritableStatics,
554 prototype = cls.prototype,
557 inheritableStatics = prototype.$inheritableStatics;
559 if (!inheritableStatics) {
560 inheritableStatics = prototype.$inheritableStatics = [];
563 for (name in statics) {
564 if (statics.hasOwnProperty(name)) {
565 cls[name] = statics[name];
566 inheritableStatics.push(name);
570 delete data.inheritableStatics;
573 <span id='Ext-Class-cfg-mixins'> /**
574 </span> * @cfg {Object} mixins
575 * List of classes to mix into this class. For example:
577 * Ext.define('CanSing', {
579 * alert("I'm on the highway to hell...")
583 * Ext.define('Musician', {
591 Class.registerPreprocessor('mixins', function(cls, data) {
592 cls.mixin(data.mixins);
597 <span id='Ext-Class-cfg-config'> /**
598 </span> * @cfg {Object} config
599 * List of configuration options with their default values, for which automatically
600 * accessor methods are generated. For example:
602 * Ext.define('SmartPhone', {
604 * hasTouchScreen: false,
605 * operatingSystem: 'Other',
608 * constructor: function(cfg) {
609 * this.initConfig(cfg);
613 * var iPhone = new SmartPhone({
614 * hasTouchScreen: true,
615 * operatingSystem: 'iOS'
618 * iPhone.getPrice(); // 500;
619 * iPhone.getOperatingSystem(); // 'iOS'
620 * iPhone.getHasTouchScreen(); // true;
621 * iPhone.hasTouchScreen(); // true
623 Class.registerPreprocessor('config', function(cls, data) {
624 var prototype = cls.prototype;
626 Ext.Object.each(data.config, function(name) {
627 var cName = name.charAt(0).toUpperCase() + name.substr(1),
629 apply = 'apply' + cName,
630 setter = 'set' + cName,
631 getter = 'get' + cName;
633 if (!(apply in prototype) && !data.hasOwnProperty(apply)) {
634 data[apply] = function(val) {
639 if (!(setter in prototype) && !data.hasOwnProperty(setter)) {
640 data[setter] = function(val) {
641 var ret = this[apply].call(this, val, this[pName]);
643 if (ret !== undefined) {
651 if (!(getter in prototype) && !data.hasOwnProperty(getter)) {
652 data[getter] = function() {
658 Ext.Object.merge(prototype.config, data.config);
662 Class.setDefaultPreprocessors(['extend', 'statics', 'inheritableStatics', 'mixins', 'config']);
664 // Backwards compatible
665 Ext.extend = function(subclass, superclass, members) {
666 if (arguments.length === 2 && Ext.isObject(superclass)) {
667 members = superclass;
668 superclass = subclass;
675 Ext.Error.raise("Attempting to extend from a class which has not been loaded on the page.");
678 members.extend = superclass;
679 members.preprocessors = ['extend', 'mixins', 'config', 'statics'];
682 cls = new Class(subclass, members);
685 cls = new Class(members);
688 cls.prototype.override = function(o) {
690 if (o.hasOwnProperty(m)) {