Class.html 23 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685
  1. <!DOCTYPE html>
  2. <html>
  3. <head>
  4. <meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
  5. <title>The source code</title>
  6. <link href="../resources/prettify/prettify.css" type="text/css" rel="stylesheet" />
  7. <script type="text/javascript" src="../resources/prettify/prettify.js"></script>
  8. <style type="text/css">
  9. .highlight { display: block; background-color: #ddd; }
  10. </style>
  11. <script type="text/javascript">
  12. function highlight() {
  13. document.getElementById(location.hash.replace(/#/, "")).className = "highlight";
  14. }
  15. </script>
  16. </head>
  17. <body onload="prettyPrint(); highlight();">
  18. <pre class="prettyprint lang-js"><span id='Ext-Class'>/**
  19. </span> * @author Jacky Nguyen &lt;jacky@sencha.com&gt;
  20. * @docauthor Jacky Nguyen &lt;jacky@sencha.com&gt;
  21. * @class Ext.Class
  22. *
  23. * Handles class creation throughout the framework. This is a low level factory that is used by Ext.ClassManager and generally
  24. * should not be used directly. If you choose to use Ext.Class you will lose out on the namespace, aliasing and depency loading
  25. * features made available by Ext.ClassManager. The only time you would use Ext.Class directly is to create an anonymous class.
  26. *
  27. * If you wish to create a class you should use {@link Ext#define Ext.define} which aliases
  28. * {@link Ext.ClassManager#create Ext.ClassManager.create} to enable namespacing and dynamic dependency resolution.
  29. *
  30. * Ext.Class is the factory and **not** the superclass of everything. For the base class that **all** Ext classes inherit
  31. * from, see {@link Ext.Base}.
  32. */
  33. (function() {
  34. var ExtClass,
  35. Base = Ext.Base,
  36. baseStaticMembers = [],
  37. baseStaticMember, baseStaticMemberLength;
  38. for (baseStaticMember in Base) {
  39. if (Base.hasOwnProperty(baseStaticMember)) {
  40. baseStaticMembers.push(baseStaticMember);
  41. }
  42. }
  43. baseStaticMemberLength = baseStaticMembers.length;
  44. // Creates a constructor that has nothing extra in its scope chain.
  45. function makeCtor (className) {
  46. function constructor () {
  47. // Opera has some problems returning from a constructor when Dragonfly isn't running. The || null seems to
  48. // be sufficient to stop it misbehaving. Known to be required against 10.53, 11.51 and 11.61.
  49. return this.constructor.apply(this, arguments) || null;
  50. }
  51. //&lt;debug&gt;
  52. if (className) {
  53. constructor.displayName = className;
  54. }
  55. //&lt;/debug&gt;
  56. return constructor;
  57. }
  58. <span id='Ext-Class-method-constructor'> /**
  59. </span> * @method constructor
  60. * Create a new anonymous class.
  61. *
  62. * @param {Object} data An object represent the properties of this class
  63. * @param {Function} onCreated Optional, the callback function to be executed when this class is fully created.
  64. * Note that the creation process can be asynchronous depending on the pre-processors used.
  65. *
  66. * @return {Ext.Base} The newly created class
  67. */
  68. Ext.Class = ExtClass = function(Class, data, onCreated) {
  69. if (typeof Class != 'function') {
  70. onCreated = data;
  71. data = Class;
  72. Class = null;
  73. }
  74. if (!data) {
  75. data = {};
  76. }
  77. Class = ExtClass.create(Class, data);
  78. ExtClass.process(Class, data, onCreated);
  79. return Class;
  80. };
  81. Ext.apply(ExtClass, {
  82. <span id='Ext-Class-method-onBeforeCreated'> /**
  83. </span> * @private
  84. * @param Class
  85. * @param data
  86. * @param hooks
  87. */
  88. onBeforeCreated: function(Class, data, hooks) {
  89. Class.addMembers(data);
  90. hooks.onCreated.call(Class, Class);
  91. },
  92. <span id='Ext-Class-method-create'> /**
  93. </span> * @private
  94. * @param Class
  95. * @param classData
  96. * @param onClassCreated
  97. */
  98. create: function(Class, data) {
  99. var name, i;
  100. if (!Class) {
  101. Class = makeCtor(
  102. //&lt;debug&gt;
  103. data.$className
  104. //&lt;/debug&gt;
  105. );
  106. }
  107. for (i = 0; i &lt; baseStaticMemberLength; i++) {
  108. name = baseStaticMembers[i];
  109. Class[name] = Base[name];
  110. }
  111. return Class;
  112. },
  113. <span id='Ext-Class-method-process'> /**
  114. </span> * @private
  115. * @param Class
  116. * @param data
  117. * @param onCreated
  118. */
  119. process: function(Class, data, onCreated) {
  120. var preprocessorStack = data.preprocessors || ExtClass.defaultPreprocessors,
  121. registeredPreprocessors = this.preprocessors,
  122. hooks = {
  123. onBeforeCreated: this.onBeforeCreated
  124. },
  125. preprocessors = [],
  126. preprocessor, preprocessorsProperties,
  127. i, ln, j, subLn, preprocessorProperty, process;
  128. delete data.preprocessors;
  129. for (i = 0,ln = preprocessorStack.length; i &lt; ln; i++) {
  130. preprocessor = preprocessorStack[i];
  131. if (typeof preprocessor == 'string') {
  132. preprocessor = registeredPreprocessors[preprocessor];
  133. preprocessorsProperties = preprocessor.properties;
  134. if (preprocessorsProperties === true) {
  135. preprocessors.push(preprocessor.fn);
  136. }
  137. else if (preprocessorsProperties) {
  138. for (j = 0,subLn = preprocessorsProperties.length; j &lt; subLn; j++) {
  139. preprocessorProperty = preprocessorsProperties[j];
  140. if (data.hasOwnProperty(preprocessorProperty)) {
  141. preprocessors.push(preprocessor.fn);
  142. break;
  143. }
  144. }
  145. }
  146. }
  147. else {
  148. preprocessors.push(preprocessor);
  149. }
  150. }
  151. hooks.onCreated = onCreated ? onCreated : Ext.emptyFn;
  152. hooks.preprocessors = preprocessors;
  153. this.doProcess(Class, data, hooks);
  154. },
  155. doProcess: function(Class, data, hooks){
  156. var me = this,
  157. preprocessor = hooks.preprocessors.shift();
  158. if (!preprocessor) {
  159. hooks.onBeforeCreated.apply(me, arguments);
  160. return;
  161. }
  162. if (preprocessor.call(me, Class, data, hooks, me.doProcess) !== false) {
  163. me.doProcess(Class, data, hooks);
  164. }
  165. },
  166. <span id='Ext-Class-property-preprocessors'> /** @private */
  167. </span> preprocessors: {},
  168. <span id='Ext-Class-static-method-registerPreprocessor'> /**
  169. </span> * Register a new pre-processor to be used during the class creation process
  170. *
  171. * @param {String} name The pre-processor's name
  172. * @param {Function} fn The callback function to be executed. Typical format:
  173. *
  174. * function(cls, data, fn) {
  175. * // Your code here
  176. *
  177. * // Execute this when the processing is finished.
  178. * // Asynchronous processing is perfectly ok
  179. * if (fn) {
  180. * fn.call(this, cls, data);
  181. * }
  182. * });
  183. *
  184. * @param {Function} fn.cls The created class
  185. * @param {Object} fn.data The set of properties passed in {@link Ext.Class} constructor
  186. * @param {Function} fn.fn The callback function that **must** to be executed when this
  187. * pre-processor finishes, regardless of whether the processing is synchronous or aynchronous.
  188. * @return {Ext.Class} this
  189. * @private
  190. * @static
  191. */
  192. registerPreprocessor: function(name, fn, properties, position, relativeTo) {
  193. if (!position) {
  194. position = 'last';
  195. }
  196. if (!properties) {
  197. properties = [name];
  198. }
  199. this.preprocessors[name] = {
  200. name: name,
  201. properties: properties || false,
  202. fn: fn
  203. };
  204. this.setDefaultPreprocessorPosition(name, position, relativeTo);
  205. return this;
  206. },
  207. <span id='Ext-Class-static-method-getPreprocessor'> /**
  208. </span> * Retrieve a pre-processor callback function by its name, which has been registered before
  209. *
  210. * @param {String} name
  211. * @return {Function} preprocessor
  212. * @private
  213. * @static
  214. */
  215. getPreprocessor: function(name) {
  216. return this.preprocessors[name];
  217. },
  218. <span id='Ext-Class-method-getPreprocessors'> /**
  219. </span> * @private
  220. */
  221. getPreprocessors: function() {
  222. return this.preprocessors;
  223. },
  224. <span id='Ext-Class-property-defaultPreprocessors'> /**
  225. </span> * @private
  226. */
  227. defaultPreprocessors: [],
  228. <span id='Ext-Class-static-method-getDefaultPreprocessors'> /**
  229. </span> * Retrieve the array stack of default pre-processors
  230. * @return {Function[]} defaultPreprocessors
  231. * @private
  232. * @static
  233. */
  234. getDefaultPreprocessors: function() {
  235. return this.defaultPreprocessors;
  236. },
  237. <span id='Ext-Class-static-method-setDefaultPreprocessors'> /**
  238. </span> * Set the default array stack of default pre-processors
  239. *
  240. * @private
  241. * @param {Array} preprocessors
  242. * @return {Ext.Class} this
  243. * @static
  244. */
  245. setDefaultPreprocessors: function(preprocessors) {
  246. this.defaultPreprocessors = Ext.Array.from(preprocessors);
  247. return this;
  248. },
  249. <span id='Ext-Class-static-method-setDefaultPreprocessorPosition'> /**
  250. </span> * Insert this pre-processor at a specific position in the stack, optionally relative to
  251. * any existing pre-processor. For example:
  252. *
  253. * Ext.Class.registerPreprocessor('debug', function(cls, data, fn) {
  254. * // Your code here
  255. *
  256. * if (fn) {
  257. * fn.call(this, cls, data);
  258. * }
  259. * }).setDefaultPreprocessorPosition('debug', 'last');
  260. *
  261. * @private
  262. * @param {String} name The pre-processor name. Note that it needs to be registered with
  263. * {@link Ext.Class#registerPreprocessor registerPreprocessor} before this
  264. * @param {String} offset The insertion position. Four possible values are:
  265. * 'first', 'last', or: 'before', 'after' (relative to the name provided in the third argument)
  266. * @param {String} relativeName
  267. * @return {Ext.Class} this
  268. * @static
  269. */
  270. setDefaultPreprocessorPosition: function(name, offset, relativeName) {
  271. var defaultPreprocessors = this.defaultPreprocessors,
  272. index;
  273. if (typeof offset == 'string') {
  274. if (offset === 'first') {
  275. defaultPreprocessors.unshift(name);
  276. return this;
  277. }
  278. else if (offset === 'last') {
  279. defaultPreprocessors.push(name);
  280. return this;
  281. }
  282. offset = (offset === 'after') ? 1 : -1;
  283. }
  284. index = Ext.Array.indexOf(defaultPreprocessors, relativeName);
  285. if (index !== -1) {
  286. Ext.Array.splice(defaultPreprocessors, Math.max(0, index + offset), 0, name);
  287. }
  288. return this;
  289. },
  290. configNameCache: {},
  291. getConfigNameMap: function(name) {
  292. var cache = this.configNameCache,
  293. map = cache[name],
  294. capitalizedName;
  295. if (!map) {
  296. capitalizedName = name.charAt(0).toUpperCase() + name.substr(1);
  297. map = cache[name] = {
  298. internal: name,
  299. initialized: '_is' + capitalizedName + 'Initialized',
  300. apply: 'apply' + capitalizedName,
  301. update: 'update' + capitalizedName,
  302. 'set': 'set' + capitalizedName,
  303. 'get': 'get' + capitalizedName,
  304. doSet : 'doSet' + capitalizedName,
  305. changeEvent: name.toLowerCase() + 'change'
  306. };
  307. }
  308. return map;
  309. }
  310. });
  311. <span id='Ext-Class-cfg-extend'> /**
  312. </span> * @cfg {String} extend
  313. * The parent class that this class extends. For example:
  314. *
  315. * Ext.define('Person', {
  316. * say: function(text) { alert(text); }
  317. * });
  318. *
  319. * Ext.define('Developer', {
  320. * extend: 'Person',
  321. * say: function(text) { this.callParent([&quot;print &quot;+text]); }
  322. * });
  323. */
  324. ExtClass.registerPreprocessor('extend', function(Class, data) {
  325. var Base = Ext.Base,
  326. basePrototype = Base.prototype,
  327. extend = data.extend,
  328. Parent, parentPrototype, i;
  329. delete data.extend;
  330. if (extend &amp;&amp; extend !== Object) {
  331. Parent = extend;
  332. }
  333. else {
  334. Parent = Base;
  335. }
  336. parentPrototype = Parent.prototype;
  337. if (!Parent.$isClass) {
  338. for (i in basePrototype) {
  339. if (!parentPrototype[i]) {
  340. parentPrototype[i] = basePrototype[i];
  341. }
  342. }
  343. }
  344. Class.extend(Parent);
  345. Class.triggerExtended.apply(Class, arguments);
  346. if (data.onClassExtended) {
  347. Class.onExtended(data.onClassExtended, Class);
  348. delete data.onClassExtended;
  349. }
  350. }, true);
  351. //&lt;feature classSystem.statics&gt;
  352. <span id='Ext-Class-cfg-statics'> /**
  353. </span> * @cfg {Object} statics
  354. * List of static methods for this class. For example:
  355. *
  356. * Ext.define('Computer', {
  357. * statics: {
  358. * factory: function(brand) {
  359. * // 'this' in static methods refer to the class itself
  360. * return new this(brand);
  361. * }
  362. * },
  363. *
  364. * constructor: function() { ... }
  365. * });
  366. *
  367. * var dellComputer = Computer.factory('Dell');
  368. */
  369. ExtClass.registerPreprocessor('statics', function(Class, data) {
  370. Class.addStatics(data.statics);
  371. delete data.statics;
  372. });
  373. //&lt;/feature&gt;
  374. //&lt;feature classSystem.inheritableStatics&gt;
  375. <span id='Ext-Class-cfg-inheritableStatics'> /**
  376. </span> * @cfg {Object} inheritableStatics
  377. * List of inheritable static methods for this class.
  378. * Otherwise just like {@link #statics} but subclasses inherit these methods.
  379. */
  380. ExtClass.registerPreprocessor('inheritableStatics', function(Class, data) {
  381. Class.addInheritableStatics(data.inheritableStatics);
  382. delete data.inheritableStatics;
  383. });
  384. //&lt;/feature&gt;
  385. //&lt;feature classSystem.config&gt;
  386. <span id='Ext-Class-cfg-config'> /**
  387. </span> * @cfg {Object} config
  388. * List of configuration options with their default values, for which automatically
  389. * accessor methods are generated. For example:
  390. *
  391. * Ext.define('SmartPhone', {
  392. * config: {
  393. * hasTouchScreen: false,
  394. * operatingSystem: 'Other',
  395. * price: 500
  396. * },
  397. * constructor: function(cfg) {
  398. * this.initConfig(cfg);
  399. * }
  400. * });
  401. *
  402. * var iPhone = new SmartPhone({
  403. * hasTouchScreen: true,
  404. * operatingSystem: 'iOS'
  405. * });
  406. *
  407. * iPhone.getPrice(); // 500;
  408. * iPhone.getOperatingSystem(); // 'iOS'
  409. * iPhone.getHasTouchScreen(); // true;
  410. */
  411. ExtClass.registerPreprocessor('config', function(Class, data) {
  412. var config = data.config,
  413. prototype = Class.prototype;
  414. delete data.config;
  415. Ext.Object.each(config, function(name, value) {
  416. var nameMap = ExtClass.getConfigNameMap(name),
  417. internalName = nameMap.internal,
  418. initializedName = nameMap.initialized,
  419. applyName = nameMap.apply,
  420. updateName = nameMap.update,
  421. setName = nameMap.set,
  422. getName = nameMap.get,
  423. hasOwnSetter = (setName in prototype) || data.hasOwnProperty(setName),
  424. hasOwnApplier = (applyName in prototype) || data.hasOwnProperty(applyName),
  425. hasOwnUpdater = (updateName in prototype) || data.hasOwnProperty(updateName),
  426. optimizedGetter, customGetter;
  427. if (value === null || (!hasOwnSetter &amp;&amp; !hasOwnApplier &amp;&amp; !hasOwnUpdater)) {
  428. prototype[internalName] = value;
  429. prototype[initializedName] = true;
  430. }
  431. else {
  432. prototype[initializedName] = false;
  433. }
  434. if (!hasOwnSetter) {
  435. data[setName] = function(value) {
  436. var oldValue = this[internalName],
  437. applier = this[applyName],
  438. updater = this[updateName];
  439. if (!this[initializedName]) {
  440. this[initializedName] = true;
  441. }
  442. if (applier) {
  443. value = applier.call(this, value, oldValue);
  444. }
  445. if (typeof value != 'undefined') {
  446. this[internalName] = value;
  447. if (updater &amp;&amp; value !== oldValue) {
  448. updater.call(this, value, oldValue);
  449. }
  450. }
  451. return this;
  452. };
  453. }
  454. if (!(getName in prototype) || data.hasOwnProperty(getName)) {
  455. customGetter = data[getName] || false;
  456. if (customGetter) {
  457. optimizedGetter = function() {
  458. return customGetter.apply(this, arguments);
  459. };
  460. }
  461. else {
  462. optimizedGetter = function() {
  463. return this[internalName];
  464. };
  465. }
  466. data[getName] = function() {
  467. var currentGetter;
  468. if (!this[initializedName]) {
  469. this[initializedName] = true;
  470. this[setName](this.config[name]);
  471. }
  472. currentGetter = this[getName];
  473. if ('$previous' in currentGetter) {
  474. currentGetter.$previous = optimizedGetter;
  475. }
  476. else {
  477. this[getName] = optimizedGetter;
  478. }
  479. return optimizedGetter.apply(this, arguments);
  480. };
  481. }
  482. });
  483. Class.addConfig(config, true);
  484. });
  485. //&lt;/feature&gt;
  486. //&lt;feature classSystem.mixins&gt;
  487. <span id='Ext-Class-cfg-mixins'> /**
  488. </span> * @cfg {String[]/Object} mixins
  489. * List of classes to mix into this class. For example:
  490. *
  491. * Ext.define('CanSing', {
  492. * sing: function() {
  493. * alert(&quot;I'm on the highway to hell...&quot;)
  494. * }
  495. * });
  496. *
  497. * Ext.define('Musician', {
  498. * mixins: ['CanSing']
  499. * })
  500. *
  501. * In this case the Musician class will get a `sing` method from CanSing mixin.
  502. *
  503. * But what if the Musician already has a `sing` method? Or you want to mix
  504. * in two classes, both of which define `sing`? In such a cases it's good
  505. * to define mixins as an object, where you assign a name to each mixin:
  506. *
  507. * Ext.define('Musician', {
  508. * mixins: {
  509. * canSing: 'CanSing'
  510. * },
  511. *
  512. * sing: function() {
  513. * // delegate singing operation to mixin
  514. * this.mixins.canSing.sing.call(this);
  515. * }
  516. * })
  517. *
  518. * In this case the `sing` method of Musician will overwrite the
  519. * mixed in `sing` method. But you can access the original mixed in method
  520. * through special `mixins` property.
  521. */
  522. ExtClass.registerPreprocessor('mixins', function(Class, data, hooks) {
  523. var mixins = data.mixins,
  524. name, mixin, i, ln;
  525. delete data.mixins;
  526. Ext.Function.interceptBefore(hooks, 'onCreated', function() {
  527. if (mixins instanceof Array) {
  528. for (i = 0,ln = mixins.length; i &lt; ln; i++) {
  529. mixin = mixins[i];
  530. name = mixin.prototype.mixinId || mixin.$className;
  531. Class.mixin(name, mixin);
  532. }
  533. }
  534. else {
  535. for (var mixinName in mixins) {
  536. if (mixins.hasOwnProperty(mixinName)) {
  537. Class.mixin(mixinName, mixins[mixinName]);
  538. }
  539. }
  540. }
  541. });
  542. });
  543. //&lt;/feature&gt;
  544. //&lt;feature classSystem.backwardsCompatible&gt;
  545. // Backwards compatible
  546. Ext.extend = function(Class, Parent, members) {
  547. if (arguments.length === 2 &amp;&amp; Ext.isObject(Parent)) {
  548. members = Parent;
  549. Parent = Class;
  550. Class = null;
  551. }
  552. var cls;
  553. if (!Parent) {
  554. throw new Error(&quot;[Ext.extend] Attempting to extend from a class which has not been loaded on the page.&quot;);
  555. }
  556. members.extend = Parent;
  557. members.preprocessors = [
  558. 'extend'
  559. //&lt;feature classSystem.statics&gt;
  560. ,'statics'
  561. //&lt;/feature&gt;
  562. //&lt;feature classSystem.inheritableStatics&gt;
  563. ,'inheritableStatics'
  564. //&lt;/feature&gt;
  565. //&lt;feature classSystem.mixins&gt;
  566. ,'mixins'
  567. //&lt;/feature&gt;
  568. //&lt;feature classSystem.config&gt;
  569. ,'config'
  570. //&lt;/feature&gt;
  571. ];
  572. if (Class) {
  573. cls = new ExtClass(Class, members);
  574. // The 'constructor' is given as 'Class' but also needs to be on prototype
  575. cls.prototype.constructor = Class;
  576. } else {
  577. cls = new ExtClass(members);
  578. }
  579. cls.prototype.override = function(o) {
  580. for (var m in o) {
  581. if (o.hasOwnProperty(m)) {
  582. this[m] = o[m];
  583. }
  584. }
  585. };
  586. return cls;
  587. };
  588. //&lt;/feature&gt;
  589. }());
  590. </pre>
  591. </body>
  592. </html>