]>
Commit | Line | Data |
---|---|---|
6527f429 DM |
1 | // @tag class\r |
2 | /**\r | |
3 | * @class Ext.ClassManager\r | |
4 | *\r | |
5 | * Ext.ClassManager manages all classes and handles mapping from string class name to\r | |
6 | * actual class objects throughout the whole framework. It is not generally accessed directly, rather through\r | |
7 | * these convenient shorthands:\r | |
8 | *\r | |
9 | * - {@link Ext#define Ext.define}\r | |
10 | * - {@link Ext#create Ext.create}\r | |
11 | * - {@link Ext#widget Ext.widget}\r | |
12 | * - {@link Ext#getClass Ext.getClass}\r | |
13 | * - {@link Ext#getClassName Ext.getClassName}\r | |
14 | *\r | |
15 | * # Basic syntax:\r | |
16 | *\r | |
17 | * Ext.define(className, properties);\r | |
18 | *\r | |
19 | * in which `properties` is an object represent a collection of properties that apply to the class. See\r | |
20 | * {@link Ext.ClassManager#create} for more detailed instructions.\r | |
21 | *\r | |
22 | * Ext.define('Person', {\r | |
23 | * name: 'Unknown',\r | |
24 | *\r | |
25 | * constructor: function(name) {\r | |
26 | * if (name) {\r | |
27 | * this.name = name;\r | |
28 | * }\r | |
29 | * },\r | |
30 | *\r | |
31 | * eat: function(foodType) {\r | |
32 | * alert("I'm eating: " + foodType);\r | |
33 | *\r | |
34 | * return this;\r | |
35 | * }\r | |
36 | * });\r | |
37 | *\r | |
38 | * var aaron = new Person("Aaron");\r | |
39 | * aaron.eat("Sandwich"); // alert("I'm eating: Sandwich");\r | |
40 | *\r | |
41 | * Ext.Class has a powerful set of extensible {@link Ext.Class#registerPreprocessor pre-processors} which takes care of\r | |
42 | * everything related to class creation, including but not limited to inheritance, mixins, configuration, statics, etc.\r | |
43 | *\r | |
44 | * # Inheritance:\r | |
45 | *\r | |
46 | * Ext.define('Developer', {\r | |
47 | * extend: 'Person',\r | |
48 | *\r | |
49 | * constructor: function(name, isGeek) {\r | |
50 | * this.isGeek = isGeek;\r | |
51 | *\r | |
52 | * // Apply a method from the parent class' prototype\r | |
53 | * this.callParent([name]);\r | |
54 | * },\r | |
55 | *\r | |
56 | * code: function(language) {\r | |
57 | * alert("I'm coding in: " + language);\r | |
58 | *\r | |
59 | * this.eat("Bugs");\r | |
60 | *\r | |
61 | * return this;\r | |
62 | * }\r | |
63 | * });\r | |
64 | *\r | |
65 | * var jacky = new Developer("Jacky", true);\r | |
66 | * jacky.code("JavaScript"); // alert("I'm coding in: JavaScript");\r | |
67 | * // alert("I'm eating: Bugs");\r | |
68 | *\r | |
69 | * See {@link Ext.Base#callParent} for more details on calling superclass' methods\r | |
70 | *\r | |
71 | * # Mixins:\r | |
72 | *\r | |
73 | * Ext.define('CanPlayGuitar', {\r | |
74 | * playGuitar: function() {\r | |
75 | * alert("F#...G...D...A");\r | |
76 | * }\r | |
77 | * });\r | |
78 | *\r | |
79 | * Ext.define('CanComposeSongs', {\r | |
80 | * composeSongs: function() { ... }\r | |
81 | * });\r | |
82 | *\r | |
83 | * Ext.define('CanSing', {\r | |
84 | * sing: function() {\r | |
85 | * alert("For he's a jolly good fellow...")\r | |
86 | * }\r | |
87 | * });\r | |
88 | *\r | |
89 | * Ext.define('Musician', {\r | |
90 | * extend: 'Person',\r | |
91 | *\r | |
92 | * mixins: {\r | |
93 | * canPlayGuitar: 'CanPlayGuitar',\r | |
94 | * canComposeSongs: 'CanComposeSongs',\r | |
95 | * canSing: 'CanSing'\r | |
96 | * }\r | |
97 | * })\r | |
98 | *\r | |
99 | * Ext.define('CoolPerson', {\r | |
100 | * extend: 'Person',\r | |
101 | *\r | |
102 | * mixins: {\r | |
103 | * canPlayGuitar: 'CanPlayGuitar',\r | |
104 | * canSing: 'CanSing'\r | |
105 | * },\r | |
106 | *\r | |
107 | * sing: function() {\r | |
108 | * alert("Ahem....");\r | |
109 | *\r | |
110 | * this.mixins.canSing.sing.call(this);\r | |
111 | *\r | |
112 | * alert("[Playing guitar at the same time...]");\r | |
113 | *\r | |
114 | * this.playGuitar();\r | |
115 | * }\r | |
116 | * });\r | |
117 | *\r | |
118 | * var me = new CoolPerson("Jacky");\r | |
119 | *\r | |
120 | * me.sing(); // alert("Ahem...");\r | |
121 | * // alert("For he's a jolly good fellow...");\r | |
122 | * // alert("[Playing guitar at the same time...]");\r | |
123 | * // alert("F#...G...D...A");\r | |
124 | *\r | |
125 | * # Config:\r | |
126 | *\r | |
127 | * Ext.define('SmartPhone', {\r | |
128 | * config: {\r | |
129 | * hasTouchScreen: false,\r | |
130 | * operatingSystem: 'Other',\r | |
131 | * price: 500\r | |
132 | * },\r | |
133 | *\r | |
134 | * isExpensive: false,\r | |
135 | *\r | |
136 | * constructor: function(config) {\r | |
137 | * this.initConfig(config);\r | |
138 | * },\r | |
139 | *\r | |
140 | * applyPrice: function(price) {\r | |
141 | * this.isExpensive = (price > 500);\r | |
142 | *\r | |
143 | * return price;\r | |
144 | * },\r | |
145 | *\r | |
146 | * applyOperatingSystem: function(operatingSystem) {\r | |
147 | * if (!(/^(iOS|Android|BlackBerry)$/i).test(operatingSystem)) {\r | |
148 | * return 'Other';\r | |
149 | * }\r | |
150 | *\r | |
151 | * return operatingSystem;\r | |
152 | * }\r | |
153 | * });\r | |
154 | *\r | |
155 | * var iPhone = new SmartPhone({\r | |
156 | * hasTouchScreen: true,\r | |
157 | * operatingSystem: 'iOS'\r | |
158 | * });\r | |
159 | *\r | |
160 | * iPhone.getPrice(); // 500;\r | |
161 | * iPhone.getOperatingSystem(); // 'iOS'\r | |
162 | * iPhone.getHasTouchScreen(); // true;\r | |
163 | *\r | |
164 | * iPhone.isExpensive; // false;\r | |
165 | * iPhone.setPrice(600);\r | |
166 | * iPhone.getPrice(); // 600\r | |
167 | * iPhone.isExpensive; // true;\r | |
168 | *\r | |
169 | * iPhone.setOperatingSystem('AlienOS');\r | |
170 | * iPhone.getOperatingSystem(); // 'Other'\r | |
171 | *\r | |
172 | * # Statics:\r | |
173 | *\r | |
174 | * Ext.define('Computer', {\r | |
175 | * statics: {\r | |
176 | * factory: function(brand) {\r | |
177 | * // 'this' in static methods refer to the class itself\r | |
178 | * return new this(brand);\r | |
179 | * }\r | |
180 | * },\r | |
181 | *\r | |
182 | * constructor: function() { ... }\r | |
183 | * });\r | |
184 | *\r | |
185 | * var dellComputer = Computer.factory('Dell');\r | |
186 | *\r | |
187 | * Also see {@link Ext.Base#statics} and {@link Ext.Base#self} for more details on accessing\r | |
188 | * static properties within class methods\r | |
189 | *\r | |
190 | * @singleton\r | |
191 | */\r | |
192 | Ext.ClassManager = (function(Class, alias, arraySlice, arrayFrom, global) {\r | |
193 | // @define Ext.ClassManager\r | |
194 | // @require Ext.Inventory\r | |
195 | // @require Ext.Class\r | |
196 | // @require Ext.Function\r | |
197 | // @require Ext.Array\r | |
198 | \r | |
199 | var makeCtor = Ext.Class.makeCtor,\r | |
200 | //<if nonBrowser>\r | |
201 | isNonBrowser = typeof window === 'undefined',\r | |
202 | //</if>\r | |
203 | nameLookupStack = [],\r | |
204 | namespaceCache = {\r | |
205 | Ext: {\r | |
206 | name: 'Ext',\r | |
207 | value: Ext // specially added for sandbox (Ext === global.Ext6)\r | |
208 | }\r | |
209 | /*\r | |
210 | 'Ext.grid': {\r | |
211 | name: 'grid',\r | |
212 | parent: namespaceCache['Ext']\r | |
213 | },\r | |
214 | 'Ext.grid.Panel': {\r | |
215 | name: 'Panel',\r | |
216 | parent: namespaceCache['Ext.grid']\r | |
217 | },\r | |
218 | ...\r | |
219 | \r | |
220 | Also,\r | |
221 | 'MyApp': {\r | |
222 | name: 'MyApp',\r | |
223 | value: MyApp\r | |
224 | }\r | |
225 | */\r | |
226 | },\r | |
227 | \r | |
228 | Manager = Ext.apply(new Ext.Inventory(), {\r | |
229 | /**\r | |
230 | * @property {Object} classes\r | |
231 | * All classes which were defined through the ClassManager. Keys are the\r | |
232 | * name of the classes and the values are references to the classes.\r | |
233 | * @private\r | |
234 | */\r | |
235 | classes: {},\r | |
236 | \r | |
237 | classState: {\r | |
238 | /*\r | |
239 | * 'Ext.foo.Bar': <state enum>\r | |
240 | *\r | |
241 | * 10 = Ext.define called\r | |
242 | * 20 = Ext.define/override called\r | |
243 | * 30 = Manager.existCache[<name>] == true for define\r | |
244 | * 40 = Manager.existCache[<name>] == true for define/override\r | |
245 | * 50 = Manager.isCreated(<name>) == true for define\r | |
246 | * 60 = Manager.isCreated(<name>) == true for define/override\r | |
247 | *\r | |
248 | */\r | |
249 | },\r | |
250 | \r | |
251 | /**\r | |
252 | * @private\r | |
253 | */\r | |
254 | existCache: {},\r | |
255 | \r | |
256 | /** @private */\r | |
257 | instantiators: [],\r | |
258 | \r | |
259 | /**\r | |
260 | * Checks if a class has already been created.\r | |
261 | *\r | |
262 | * @param {String} className\r | |
263 | * @return {Boolean} exist\r | |
264 | */\r | |
265 | isCreated: function(className) {\r | |
266 | //<debug>\r | |
267 | if (typeof className !== 'string' || className.length < 1) {\r | |
268 | throw new Error("[Ext.ClassManager] Invalid classname, must be a string and must not be empty");\r | |
269 | }\r | |
270 | //</debug>\r | |
271 | \r | |
272 | if (Manager.classes[className] || Manager.existCache[className]) {\r | |
273 | return true;\r | |
274 | }\r | |
275 | \r | |
276 | if (!Manager.lookupName(className, false)) {\r | |
277 | return false;\r | |
278 | }\r | |
279 | \r | |
280 | Manager.triggerCreated(className);\r | |
281 | return true;\r | |
282 | },\r | |
283 | \r | |
284 | /**\r | |
285 | * @private\r | |
286 | */\r | |
287 | createdListeners: [],\r | |
288 | \r | |
289 | /**\r | |
290 | * @private\r | |
291 | */\r | |
292 | nameCreatedListeners: {},\r | |
293 | \r | |
294 | /**\r | |
295 | * @private\r | |
296 | */\r | |
297 | existsListeners: [],\r | |
298 | \r | |
299 | /**\r | |
300 | * @private\r | |
301 | */\r | |
302 | nameExistsListeners: {},\r | |
303 | \r | |
304 | /**\r | |
305 | * @private\r | |
306 | */\r | |
307 | overrideMap: {},\r | |
308 | \r | |
309 | /**\r | |
310 | * @private\r | |
311 | */\r | |
312 | triggerCreated: function (className, state) {\r | |
313 | Manager.existCache[className] = state || 1;\r | |
314 | Manager.classState[className] += 40;\r | |
315 | Manager.notify(className, Manager.createdListeners, Manager.nameCreatedListeners);\r | |
316 | },\r | |
317 | \r | |
318 | /**\r | |
319 | * @private\r | |
320 | */\r | |
321 | onCreated: function(fn, scope, className) {\r | |
322 | Manager.addListener(fn, scope, className, Manager.createdListeners, Manager.nameCreatedListeners);\r | |
323 | },\r | |
324 | \r | |
325 | /**\r | |
326 | * @private\r | |
327 | */\r | |
328 | notify: function (className, listeners, nameListeners) {\r | |
329 | var alternateNames = Manager.getAlternatesByName(className),\r | |
330 | names = [className],\r | |
331 | i, ln, j, subLn, listener, name;\r | |
332 | \r | |
333 | for (i = 0,ln = listeners.length; i < ln; i++) {\r | |
334 | listener = listeners[i];\r | |
335 | listener.fn.call(listener.scope, className);\r | |
336 | }\r | |
337 | \r | |
338 | while (names) {\r | |
339 | for (i = 0,ln = names.length; i < ln; i++) {\r | |
340 | name = names[i];\r | |
341 | listeners = nameListeners[name];\r | |
342 | \r | |
343 | if (listeners) {\r | |
344 | for (j = 0,subLn = listeners.length; j < subLn; j++) {\r | |
345 | listener = listeners[j];\r | |
346 | listener.fn.call(listener.scope, name);\r | |
347 | }\r | |
348 | delete nameListeners[name];\r | |
349 | }\r | |
350 | }\r | |
351 | \r | |
352 | names = alternateNames; // for 2nd pass (if needed)\r | |
353 | alternateNames = null; // no 3rd pass\r | |
354 | }\r | |
355 | },\r | |
356 | \r | |
357 | /**\r | |
358 | * @private\r | |
359 | */\r | |
360 | addListener: function(fn, scope, className, listeners, nameListeners) {\r | |
361 | if (Ext.isArray(className)) {\r | |
362 | fn = Ext.Function.createBarrier(className.length, fn, scope);\r | |
363 | for (i = 0; i < className.length; i++) {\r | |
364 | this.addListener(fn, null, className[i], listeners, nameListeners);\r | |
365 | }\r | |
366 | return;\r | |
367 | }\r | |
368 | var i,\r | |
369 | listener = {\r | |
370 | fn: fn,\r | |
371 | scope: scope\r | |
372 | };\r | |
373 | \r | |
374 | if (className) {\r | |
375 | if (this.isCreated(className)) {\r | |
376 | fn.call(scope, className);\r | |
377 | return;\r | |
378 | }\r | |
379 | \r | |
380 | if (!nameListeners[className]) {\r | |
381 | nameListeners[className] = [];\r | |
382 | }\r | |
383 | \r | |
384 | nameListeners[className].push(listener);\r | |
385 | }\r | |
386 | else {\r | |
387 | listeners.push(listener);\r | |
388 | }\r | |
389 | },\r | |
390 | \r | |
391 | /**\r | |
392 | * Supports namespace rewriting.\r | |
393 | * @private\r | |
394 | */\r | |
395 | $namespaceCache: namespaceCache,\r | |
396 | \r | |
397 | /**\r | |
398 | * See `{@link Ext#addRootNamespaces Ext.addRootNamespaces}`.\r | |
399 | * @since 6.0.0\r | |
400 | * @private\r | |
401 | */\r | |
402 | addRootNamespaces: function (namespaces) {\r | |
403 | for (var name in namespaces) {\r | |
404 | namespaceCache[name] = {\r | |
405 | name: name,\r | |
406 | value: namespaces[name]\r | |
407 | };\r | |
408 | }\r | |
409 | },\r | |
410 | \r | |
411 | /**\r | |
412 | * Clears the namespace lookup cache. After application launch, this cache can\r | |
413 | * often contain several hundred entries that are unlikely to be needed again.\r | |
414 | * These will be rebuilt as needed, so it is harmless to clear this cache even\r | |
415 | * if its results will be used again.\r | |
416 | * @since 6.0.0\r | |
417 | * @private\r | |
418 | */\r | |
419 | clearNamespaceCache: function () {\r | |
420 | nameLookupStack.length = 0;\r | |
421 | \r | |
422 | for (var name in namespaceCache) {\r | |
423 | if (!namespaceCache[name].value) {\r | |
424 | delete namespaceCache[name];\r | |
425 | }\r | |
426 | }\r | |
427 | },\r | |
428 | \r | |
429 | /**\r | |
430 | * Return the namespace cache entry for the given a class name or namespace (e.g.,\r | |
431 | * "Ext.grid.Panel").\r | |
432 | *\r | |
433 | * @param {String} namespace The namespace or class name to lookup.\r | |
434 | * @return {Object} The cache entry.\r | |
435 | * @return {String} return.name The leaf name ("Panel" for "Ext.grid.Panel").\r | |
436 | * @return {Object} return.parent The entry of the parent namespace (i.e., "Ext.grid").\r | |
437 | * @return {Object} return.value The namespace object. This is only set for\r | |
438 | * top-level namespace entries to support renaming them for sandboxing ("Ext6" vs\r | |
439 | * "Ext").\r | |
440 | * @since 6.0.0\r | |
441 | * @private\r | |
442 | */\r | |
443 | getNamespaceEntry: function (namespace) {\r | |
444 | if (typeof namespace !== 'string') {\r | |
445 | return namespace; // assume we've been given an entry object\r | |
446 | }\r | |
447 | \r | |
448 | var entry = namespaceCache[namespace],\r | |
449 | i;\r | |
450 | \r | |
451 | if (!entry) {\r | |
452 | i = namespace.lastIndexOf('.');\r | |
453 | \r | |
454 | if (i < 0) {\r | |
455 | entry = {\r | |
456 | name: namespace\r | |
457 | };\r | |
458 | } else {\r | |
459 | entry = {\r | |
460 | name: namespace.substring(i + 1),\r | |
461 | parent: Manager.getNamespaceEntry(namespace.substring(0, i))\r | |
462 | };\r | |
463 | }\r | |
464 | \r | |
465 | namespaceCache[namespace] = entry;\r | |
466 | }\r | |
467 | \r | |
468 | return entry;\r | |
469 | },\r | |
470 | \r | |
471 | /**\r | |
472 | * Return the value of the given "dot path" name. This supports remapping (for use\r | |
473 | * in sandbox builds) as well as auto-creating of namespaces.\r | |
474 | *\r | |
475 | * @param {String} namespace The name of the namespace or class.\r | |
476 | * @param {Boolean} [autoCreate] Pass `true` to create objects for undefined names.\r | |
477 | * @return {Object} The object that is the namespace or class name.\r | |
478 | * @since 6.0.0\r | |
479 | * @private\r | |
480 | */\r | |
481 | lookupName: function (namespace, autoCreate) {\r | |
482 | var entry = Manager.getNamespaceEntry(namespace),\r | |
483 | scope = Ext.global,\r | |
484 | i = 0,\r | |
485 | e, parent;\r | |
486 | \r | |
487 | // Put entries on the stack in reverse order: [ 'Panel', 'grid', 'Ext' ]\r | |
488 | for (e = entry; e; e = e.parent) {\r | |
489 | // since we process only what we add to the array, and that always\r | |
490 | // starts at index=0, we don't need to clean up the array (that would\r | |
491 | // just encourage the GC to do something pointless).\r | |
492 | nameLookupStack[i++] = e;\r | |
493 | }\r | |
494 | \r | |
495 | while (scope && i-- > 0) {\r | |
496 | // We'll process entries in top-down order ('Ext', 'grid' then 'Panel').\r | |
497 | e = nameLookupStack[i];\r | |
498 | parent = scope;\r | |
499 | \r | |
500 | scope = e.value || scope[e.name];\r | |
501 | \r | |
502 | if (!scope && autoCreate) {\r | |
503 | parent[e.name] = scope = {};\r | |
504 | }\r | |
505 | }\r | |
506 | \r | |
507 | return scope;\r | |
508 | },\r | |
509 | \r | |
510 | /**\r | |
511 | * Creates a namespace and assign the `value` to the created object.\r | |
512 | *\r | |
513 | * Ext.ClassManager.setNamespace('MyCompany.pkg.Example', someObject);\r | |
514 | *\r | |
515 | * alert(MyCompany.pkg.Example === someObject); // alerts true\r | |
516 | *\r | |
517 | * @param {String} name\r | |
518 | * @param {Object} value\r | |
519 | */\r | |
520 | setNamespace: function (namespace, value) {\r | |
521 | var entry = Manager.getNamespaceEntry(namespace),\r | |
522 | scope = Ext.global;\r | |
523 | \r | |
524 | if (entry.parent) {\r | |
525 | scope = Manager.lookupName(entry.parent, true);\r | |
526 | }\r | |
527 | \r | |
528 | scope[entry.name] = value;\r | |
529 | \r | |
530 | return value;\r | |
531 | },\r | |
532 | \r | |
533 | /**\r | |
534 | * Changes the mapping of an `xtype` to map to the specified component class.\r | |
535 | * @param {String/Ext.Class} cls The class or class name to which `xtype` is mapped.\r | |
536 | * @param {String} xtype The `xtype` to map or redefine as `cls`.\r | |
537 | * @since 6.0.1\r | |
538 | * @private\r | |
539 | */\r | |
540 | setXType: function (cls, xtype) {\r | |
541 | var className = cls.$className,\r | |
542 | C = className ? cls : Manager.get(className = cls),\r | |
543 | proto = C.prototype,\r | |
544 | xtypes = proto.xtypes,\r | |
545 | xtypesChain = proto.xtypesChain,\r | |
546 | xtypesMap = proto.xtypesMap;\r | |
547 | \r | |
548 | if (!proto.hasOwnProperty('xtypes')) {\r | |
549 | proto.xtypes = xtypes = [];\r | |
550 | proto.xtypesChain = xtypesChain = xtypesChain ? xtypesChain.slice(0) : [];\r | |
551 | proto.xtypesMap = xtypesMap = Ext.apply({}, xtypesMap);\r | |
552 | }\r | |
553 | \r | |
554 | Manager.addAlias(className, 'widget.' + xtype, true);\r | |
555 | \r | |
556 | xtypes.push(xtype);\r | |
557 | xtypesChain.push(xtype);\r | |
558 | xtypesMap[xtype] = true;\r | |
559 | \r | |
560 | //TODO consider updating derived class xtypesChain / xtypesMap\r | |
561 | },\r | |
562 | \r | |
563 | /**\r | |
564 | * Sets a name reference to a class.\r | |
565 | *\r | |
566 | * @param {String} name\r | |
567 | * @param {Object} value\r | |
568 | * @return {Ext.ClassManager} this\r | |
569 | */\r | |
570 | set: function (name, value) {\r | |
571 | var targetName = Manager.getName(value);\r | |
572 | \r | |
573 | Manager.classes[name] = Manager.setNamespace(name, value);\r | |
574 | \r | |
575 | if (targetName && targetName !== name) {\r | |
576 | Manager.addAlternate(targetName, name);\r | |
577 | }\r | |
578 | \r | |
579 | return Manager;\r | |
580 | },\r | |
581 | \r | |
582 | /**\r | |
583 | * Retrieve a class by its name.\r | |
584 | *\r | |
585 | * @param {String} name\r | |
586 | * @return {Ext.Class} class\r | |
587 | */\r | |
588 | get: function(name) {\r | |
589 | return Manager.classes[name] || Manager.lookupName(name, false);\r | |
590 | },\r | |
591 | \r | |
592 | /**\r | |
593 | * Adds a batch of class name to alias mappings.\r | |
594 | * @param {Object} aliases The set of mappings of the form.\r | |
595 | * className : [values...]\r | |
596 | */\r | |
597 | addNameAliasMappings: function(aliases) {\r | |
598 | Manager.addAlias(aliases);\r | |
599 | },\r | |
600 | \r | |
601 | /**\r | |
602 | *\r | |
603 | * @param {Object} alternates The set of mappings of the form\r | |
604 | * className : [values...]\r | |
605 | */\r | |
606 | addNameAlternateMappings: function (alternates) {\r | |
607 | Manager.addAlternate(alternates);\r | |
608 | },\r | |
609 | \r | |
610 | /**\r | |
611 | * Get a reference to the class by its alias.\r | |
612 | *\r | |
613 | * @param {String} alias\r | |
614 | * @return {Ext.Class} class\r | |
615 | */\r | |
616 | getByAlias: function(alias) {\r | |
617 | return Manager.get(Manager.getNameByAlias(alias));\r | |
618 | },\r | |
619 | \r | |
620 | /**\r | |
621 | * Get a component class name from a config object.\r | |
622 | * @param {Object} config The config object.\r | |
623 | * @param {String} [aliasPrefix] A prefix to use when getting\r | |
624 | * a class name by alias.\r | |
625 | * @return {Ext.Class} The class.\r | |
626 | *\r | |
627 | * @private\r | |
628 | */\r | |
629 | getByConfig: function(config, aliasPrefix) {\r | |
630 | var xclass = config.xclass,\r | |
631 | name;\r | |
632 | \r | |
633 | if (xclass) {\r | |
634 | name = xclass;\r | |
635 | } else {\r | |
636 | name = config.xtype;\r | |
637 | if (name) {\r | |
638 | aliasPrefix = 'widget.';\r | |
639 | } else {\r | |
640 | name = config.type;\r | |
641 | }\r | |
642 | name = Manager.getNameByAlias(aliasPrefix + name);\r | |
643 | }\r | |
644 | return Manager.get(name);\r | |
645 | }, \r | |
646 | \r | |
647 | /**\r | |
648 | * Get the name of the class by its reference or its instance. This is\r | |
649 | * usually invoked by the shorthand {@link Ext#getClassName}.\r | |
650 | *\r | |
651 | * Ext.ClassManager.getName(Ext.Action); // returns "Ext.Action"\r | |
652 | *\r | |
653 | * @param {Ext.Class/Object} object\r | |
654 | * @return {String} className\r | |
655 | */\r | |
656 | getName: function(object) {\r | |
657 | return object && object.$className || '';\r | |
658 | },\r | |
659 | \r | |
660 | /**\r | |
661 | * Get the class of the provided object; returns null if it's not an instance\r | |
662 | * of any class created with Ext.define. This is usually invoked by the\r | |
663 | * shorthand {@link Ext#getClass}.\r | |
664 | *\r | |
665 | * var component = new Ext.Component();\r | |
666 | *\r | |
667 | * Ext.getClass(component); // returns Ext.Component\r | |
668 | *\r | |
669 | * @param {Object} object\r | |
670 | * @return {Ext.Class} class\r | |
671 | */\r | |
672 | getClass: function(object) {\r | |
673 | return object && object.self || null;\r | |
674 | },\r | |
675 | \r | |
676 | /**\r | |
677 | * Defines a class.\r | |
678 | * @deprecated Use {@link Ext#define} instead, as that also supports creating overrides.\r | |
679 | * @private\r | |
680 | */\r | |
681 | create: function(className, data, createdFn) {\r | |
682 | //<debug>\r | |
683 | if (className != null && typeof className !== 'string') {\r | |
684 | throw new Error("[Ext.define] Invalid class name '" + className + "' specified, must be a non-empty string");\r | |
685 | }\r | |
686 | //</debug>\r | |
687 | \r | |
688 | var ctor = makeCtor(className);\r | |
689 | if (typeof data === 'function') {\r | |
690 | data = data(ctor);\r | |
691 | }\r | |
692 | \r | |
693 | //<debug>\r | |
694 | if (className) {\r | |
695 | if (Manager.classes[className]) {\r | |
696 | Ext.log.warn("[Ext.define] Duplicate class name '" + className + "' specified, must be a non-empty string");\r | |
697 | }\r | |
698 | ctor.name = className;\r | |
699 | }\r | |
700 | //</debug>\r | |
701 | \r | |
702 | data.$className = className;\r | |
703 | \r | |
704 | return new Class(ctor, data, function() {\r | |
705 | var postprocessorStack = data.postprocessors || Manager.defaultPostprocessors,\r | |
706 | registeredPostprocessors = Manager.postprocessors,\r | |
707 | postprocessors = [],\r | |
708 | postprocessor, i, ln, j, subLn, postprocessorProperties, postprocessorProperty;\r | |
709 | \r | |
710 | delete data.postprocessors;\r | |
711 | \r | |
712 | for (i = 0,ln = postprocessorStack.length; i < ln; i++) {\r | |
713 | postprocessor = postprocessorStack[i];\r | |
714 | \r | |
715 | if (typeof postprocessor === 'string') {\r | |
716 | postprocessor = registeredPostprocessors[postprocessor];\r | |
717 | postprocessorProperties = postprocessor.properties;\r | |
718 | \r | |
719 | if (postprocessorProperties === true) {\r | |
720 | postprocessors.push(postprocessor.fn);\r | |
721 | }\r | |
722 | else if (postprocessorProperties) {\r | |
723 | for (j = 0,subLn = postprocessorProperties.length; j < subLn; j++) {\r | |
724 | postprocessorProperty = postprocessorProperties[j];\r | |
725 | \r | |
726 | if (data.hasOwnProperty(postprocessorProperty)) {\r | |
727 | postprocessors.push(postprocessor.fn);\r | |
728 | break;\r | |
729 | }\r | |
730 | }\r | |
731 | }\r | |
732 | }\r | |
733 | else {\r | |
734 | postprocessors.push(postprocessor);\r | |
735 | }\r | |
736 | }\r | |
737 | \r | |
738 | data.postprocessors = postprocessors;\r | |
739 | data.createdFn = createdFn;\r | |
740 | Manager.processCreate(className, this, data);\r | |
741 | });\r | |
742 | },\r | |
743 | \r | |
744 | processCreate: function(className, cls, clsData){\r | |
745 | var me = this,\r | |
746 | postprocessor = clsData.postprocessors.shift(),\r | |
747 | createdFn = clsData.createdFn;\r | |
748 | \r | |
749 | if (!postprocessor) {\r | |
750 | //<debug>\r | |
751 | Ext.classSystemMonitor && Ext.classSystemMonitor(className, 'Ext.ClassManager#classCreated', arguments);\r | |
752 | //</debug>\r | |
753 | \r | |
754 | if (className) {\r | |
755 | me.set(className, cls);\r | |
756 | }\r | |
757 | \r | |
758 | delete cls._classHooks;\r | |
759 | \r | |
760 | if (createdFn) {\r | |
761 | createdFn.call(cls, cls);\r | |
762 | }\r | |
763 | \r | |
764 | if (className) {\r | |
765 | me.triggerCreated(className);\r | |
766 | }\r | |
767 | return;\r | |
768 | }\r | |
769 | \r | |
770 | if (postprocessor.call(me, className, cls, clsData, me.processCreate) !== false) {\r | |
771 | me.processCreate(className, cls, clsData);\r | |
772 | }\r | |
773 | },\r | |
774 | \r | |
775 | createOverride: function (className, data, createdFn) {\r | |
776 | var me = this,\r | |
777 | overriddenClassName = data.override,\r | |
778 | requires = data.requires,\r | |
779 | uses = data.uses,\r | |
780 | mixins = data.mixins,\r | |
781 | mixinsIsArray,\r | |
782 | compat = 1, // default if 'compatibility' is not specified\r | |
783 | depedenciesLoaded,\r | |
784 | classReady = function () {\r | |
785 | var cls, dependencies, i, key, temp;\r | |
786 | \r | |
787 | if (!depedenciesLoaded) {\r | |
788 | dependencies = requires ? requires.slice(0) : [];\r | |
789 | \r | |
790 | if (mixins) {\r | |
791 | if (!(mixinsIsArray = mixins instanceof Array)) {\r | |
792 | for (key in mixins) {\r | |
793 | if (Ext.isString(cls = mixins[key])) {\r | |
794 | dependencies.push(cls);\r | |
795 | }\r | |
796 | }\r | |
797 | } else {\r | |
798 | for (i = 0, temp = mixins.length; i < temp; ++i) {\r | |
799 | if (Ext.isString(cls = mixins[i])) {\r | |
800 | dependencies.push(cls);\r | |
801 | }\r | |
802 | }\r | |
803 | }\r | |
804 | }\r | |
805 | \r | |
806 | depedenciesLoaded = true;\r | |
807 | if (dependencies.length) {\r | |
808 | // Since the override is going to be used (its target class is\r | |
809 | // now created), we need to fetch the required classes for the\r | |
810 | // override and call us back once they are loaded:\r | |
811 | Ext.require(dependencies, classReady);\r | |
812 | return;\r | |
813 | }\r | |
814 | // else we have no dependencies, so proceed\r | |
815 | }\r | |
816 | \r | |
817 | // transform mixin class names into class references, This\r | |
818 | // loop can handle both the array and object forms of\r | |
819 | // mixin definitions\r | |
820 | if (mixinsIsArray) {\r | |
821 | for (i = 0, temp = mixins.length; i < temp; ++i) {\r | |
822 | if (Ext.isString(cls = mixins[i])) {\r | |
823 | mixins[i] = Ext.ClassManager.get(cls);\r | |
824 | }\r | |
825 | }\r | |
826 | } else if (mixins) {\r | |
827 | for (key in mixins) {\r | |
828 | if (Ext.isString(cls = mixins[key])) {\r | |
829 | mixins[key] = Ext.ClassManager.get(cls);\r | |
830 | }\r | |
831 | }\r | |
832 | }\r | |
833 | \r | |
834 | // The target class and the required classes for this override are\r | |
835 | // ready, so we can apply the override now:\r | |
836 | cls = me.get(overriddenClassName);\r | |
837 | \r | |
838 | // We don't want to apply these:\r | |
839 | delete data.override;\r | |
840 | delete data.compatibility;\r | |
841 | delete data.requires;\r | |
842 | delete data.uses;\r | |
843 | \r | |
844 | Ext.override(cls, data);\r | |
845 | \r | |
846 | // This pushes the overriding file itself into Ext.Loader.history\r | |
847 | // Hence if the target class never exists, the overriding file will\r | |
848 | // never be included in the build.\r | |
849 | Ext.Loader.history.push(className);\r | |
850 | \r | |
851 | if (uses) {\r | |
852 | // This "hides" from the Cmd auto-dependency scanner since\r | |
853 | // the reference is circular (Loader requires us).\r | |
854 | Ext['Loader'].addUsedClasses(uses); // get these classes too!\r | |
855 | }\r | |
856 | \r | |
857 | if (createdFn) {\r | |
858 | createdFn.call(cls, cls); // last but not least!\r | |
859 | }\r | |
860 | };\r | |
861 | \r | |
862 | Manager.overrideMap[className] = true;\r | |
863 | \r | |
864 | // If specified, parse strings as versions, but otherwise treat as a\r | |
865 | // boolean (maybe "compatibility: Ext.isIE8" or something).\r | |
866 | //\r | |
867 | if ('compatibility' in data && Ext.isString(compat = data.compatibility)) {\r | |
868 | compat = Ext.checkVersion(compat);\r | |
869 | }\r | |
870 | \r | |
871 | if (compat) {\r | |
872 | // Override the target class right after it's created\r | |
873 | me.onCreated(classReady, me, overriddenClassName);\r | |
874 | }\r | |
875 | \r | |
876 | me.triggerCreated(className, 2);\r | |
877 | return me;\r | |
878 | },\r | |
879 | \r | |
880 | /**\r | |
881 | * Instantiate a class by its alias. This is usually invoked by the\r | |
882 | * shorthand {@link Ext#createByAlias}.\r | |
883 | *\r | |
884 | * If {@link Ext.Loader} is {@link Ext.Loader#setConfig enabled} and the class\r | |
885 | * has not been defined yet, it will attempt to load the class via synchronous\r | |
886 | * loading.\r | |
887 | *\r | |
888 | * var window = Ext.createByAlias('widget.window', { width: 600, height: 800 });\r | |
889 | *\r | |
890 | * @param {String} alias\r | |
891 | * @param {Object...} args Additional arguments after the alias will be passed to the\r | |
892 | * class constructor.\r | |
893 | * @return {Object} instance\r | |
894 | */\r | |
895 | instantiateByAlias: function() {\r | |
896 | var alias = arguments[0],\r | |
897 | args = arraySlice.call(arguments),\r | |
898 | className = this.getNameByAlias(alias);\r | |
899 | \r | |
900 | //<debug>\r | |
901 | if (!className) {\r | |
902 | throw new Error("[Ext.createByAlias] Unrecognized alias: " + alias);\r | |
903 | }\r | |
904 | //</debug>\r | |
905 | \r | |
906 | args[0] = className;\r | |
907 | \r | |
908 | return Ext.create.apply(Ext, args);\r | |
909 | },\r | |
910 | \r | |
911 | //<deprecated since=5.0>\r | |
912 | /**\r | |
913 | * Instantiate a class by either full name, alias or alternate name\r | |
914 | * @param {String} name\r | |
915 | * @param {Mixed} args Additional arguments after the name will be passed to the class' constructor.\r | |
916 | * @return {Object} instance\r | |
917 | * @deprecated 5.0 Use Ext.create() instead.\r | |
918 | */\r | |
919 | instantiate: function() {\r | |
920 | //<debug>\r | |
921 | Ext.log.warn('Ext.ClassManager.instantiate() is deprecated. Use Ext.create() instead.');\r | |
922 | //</debug>\r | |
923 | return Ext.create.apply(Ext, arguments);\r | |
924 | },\r | |
925 | //</deprecated>\r | |
926 | \r | |
927 | /**\r | |
928 | * @private\r | |
929 | * @param name\r | |
930 | * @param args\r | |
931 | */\r | |
932 | dynInstantiate: function(name, args) {\r | |
933 | args = arrayFrom(args, true);\r | |
934 | args.unshift(name);\r | |
935 | \r | |
936 | return Ext.create.apply(Ext, args);\r | |
937 | },\r | |
938 | \r | |
939 | /**\r | |
940 | * @private\r | |
941 | * @param length\r | |
942 | */\r | |
943 | getInstantiator: function(length) {\r | |
944 | var instantiators = this.instantiators,\r | |
945 | instantiator,\r | |
946 | i,\r | |
947 | args;\r | |
948 | \r | |
949 | instantiator = instantiators[length];\r | |
950 | \r | |
951 | if (!instantiator) {\r | |
952 | i = length;\r | |
953 | args = [];\r | |
954 | \r | |
955 | for (i = 0; i < length; i++) {\r | |
956 | args.push('a[' + i + ']');\r | |
957 | }\r | |
958 | \r | |
959 | instantiator = instantiators[length] = new Function('c', 'a', 'return new c(' + args.join(',') + ')');\r | |
960 | //<debug>\r | |
961 | instantiator.name = "Ext.create" + length;\r | |
962 | //</debug>\r | |
963 | }\r | |
964 | \r | |
965 | return instantiator;\r | |
966 | },\r | |
967 | \r | |
968 | /**\r | |
969 | * @private\r | |
970 | */\r | |
971 | postprocessors: {},\r | |
972 | \r | |
973 | /**\r | |
974 | * @private\r | |
975 | */\r | |
976 | defaultPostprocessors: [],\r | |
977 | \r | |
978 | /**\r | |
979 | * Register a post-processor function.\r | |
980 | *\r | |
981 | * @private\r | |
982 | * @param {String} name\r | |
983 | * @param {Function} postprocessor\r | |
984 | */\r | |
985 | registerPostprocessor: function(name, fn, properties, position, relativeTo) {\r | |
986 | if (!position) {\r | |
987 | position = 'last';\r | |
988 | }\r | |
989 | \r | |
990 | if (!properties) {\r | |
991 | properties = [name];\r | |
992 | }\r | |
993 | \r | |
994 | this.postprocessors[name] = {\r | |
995 | name: name,\r | |
996 | properties: properties || false,\r | |
997 | fn: fn\r | |
998 | };\r | |
999 | \r | |
1000 | this.setDefaultPostprocessorPosition(name, position, relativeTo);\r | |
1001 | \r | |
1002 | return this;\r | |
1003 | },\r | |
1004 | \r | |
1005 | /**\r | |
1006 | * Set the default post processors array stack which are applied to every class.\r | |
1007 | *\r | |
1008 | * @private\r | |
1009 | * @param {String/Array} postprocessors The name of a registered post processor or an array of registered names.\r | |
1010 | * @return {Ext.ClassManager} this\r | |
1011 | */\r | |
1012 | setDefaultPostprocessors: function(postprocessors) {\r | |
1013 | this.defaultPostprocessors = arrayFrom(postprocessors);\r | |
1014 | \r | |
1015 | return this;\r | |
1016 | },\r | |
1017 | \r | |
1018 | /**\r | |
1019 | * Insert this post-processor at a specific position in the stack, optionally relative to\r | |
1020 | * any existing post-processor\r | |
1021 | *\r | |
1022 | * @private\r | |
1023 | * @param {String} name The post-processor name. Note that it needs to be registered with\r | |
1024 | * {@link Ext.ClassManager#registerPostprocessor} before this\r | |
1025 | * @param {String} offset The insertion position. Four possible values are:\r | |
1026 | * 'first', 'last', or: 'before', 'after' (relative to the name provided in the third argument)\r | |
1027 | * @param {String} relativeName\r | |
1028 | * @return {Ext.ClassManager} this\r | |
1029 | */\r | |
1030 | setDefaultPostprocessorPosition: function(name, offset, relativeName) {\r | |
1031 | var defaultPostprocessors = this.defaultPostprocessors,\r | |
1032 | index;\r | |
1033 | \r | |
1034 | if (typeof offset === 'string') {\r | |
1035 | if (offset === 'first') {\r | |
1036 | defaultPostprocessors.unshift(name);\r | |
1037 | \r | |
1038 | return this;\r | |
1039 | }\r | |
1040 | else if (offset === 'last') {\r | |
1041 | defaultPostprocessors.push(name);\r | |
1042 | \r | |
1043 | return this;\r | |
1044 | }\r | |
1045 | \r | |
1046 | offset = (offset === 'after') ? 1 : -1;\r | |
1047 | }\r | |
1048 | \r | |
1049 | index = Ext.Array.indexOf(defaultPostprocessors, relativeName);\r | |
1050 | \r | |
1051 | if (index !== -1) {\r | |
1052 | Ext.Array.splice(defaultPostprocessors, Math.max(0, index + offset), 0, name);\r | |
1053 | }\r | |
1054 | \r | |
1055 | return this;\r | |
1056 | }\r | |
1057 | });\r | |
1058 | \r | |
1059 | /**\r | |
1060 | * @cfg xtype\r | |
1061 | * @member Ext.Class\r | |
1062 | * @inheritdoc Ext.Component#cfg-xtype\r | |
1063 | */\r | |
1064 | \r | |
1065 | /**\r | |
1066 | * @cfg {String} override\r | |
1067 | * @member Ext.Class\r | |
1068 | * Overrides members of the specified `target` class.\r | |
1069 | * \r | |
1070 | * **NOTE:** the overridden class must have been defined using \r | |
1071 | * {@link Ext#define Ext.define} in order to use the `override` config.\r | |
1072 | * \r | |
1073 | * Methods defined on the overriding class will not automatically call the methods of \r | |
1074 | * the same name in the ancestor class chain. To call the parent's method of the \r | |
1075 | * same name you must call {@link Ext.Base#callParent callParent}. To skip the \r | |
1076 | * method of the overridden class and call its parent you will instead call \r | |
1077 | * {@link Ext.Base#callSuper callSuper}.\r | |
1078 | *\r | |
1079 | * See {@link Ext#define Ext.define} for additional usage examples.\r | |
1080 | */\r | |
1081 | \r | |
1082 | //<feature classSystem.alias>\r | |
1083 | /**\r | |
1084 | * @cfg {String/String[]} alias\r | |
1085 | * @member Ext.Class\r | |
1086 | * List of short aliases for class names. An alias consists of a namespace and a name\r | |
1087 | * concatenated by a period as <namespace>.<name>\r | |
1088 | *\r | |
1089 | * - **namespace** - The namespace describes what kind of alias this is and must be\r | |
1090 | * all lowercase.\r | |
1091 | * - **name** - The name of the alias which allows the lazy-instantiation via the\r | |
1092 | * alias. The name shouldn't contain any periods.\r | |
1093 | *\r | |
1094 | * A list of namespaces and the usages are:\r | |
1095 | *\r | |
1096 | * - **feature** - {@link Ext.grid.Panel Grid} features\r | |
1097 | * - **plugin** - Plugins\r | |
1098 | * - **store** - {@link Ext.data.Store}\r | |
1099 | * - **widget** - Components\r | |
1100 | *\r | |
1101 | * Most useful for defining xtypes for widgets:\r | |
1102 | *\r | |
1103 | * Ext.define('MyApp.CoolPanel', {\r | |
1104 | * extend: 'Ext.panel.Panel',\r | |
1105 | * alias: ['widget.coolpanel'],\r | |
1106 | * title: 'Yeah!'\r | |
1107 | * });\r | |
1108 | *\r | |
1109 | * // Using Ext.create\r | |
1110 | * Ext.create('widget.coolpanel');\r | |
1111 | *\r | |
1112 | * // Using the shorthand for defining widgets by xtype\r | |
1113 | * Ext.widget('panel', {\r | |
1114 | * items: [\r | |
1115 | * {xtype: 'coolpanel', html: 'Foo'},\r | |
1116 | * {xtype: 'coolpanel', html: 'Bar'}\r | |
1117 | * ]\r | |
1118 | * });\r | |
1119 | */\r | |
1120 | Manager.registerPostprocessor('alias', function(name, cls, data) {\r | |
1121 | //<debug>\r | |
1122 | Ext.classSystemMonitor && Ext.classSystemMonitor(name, 'Ext.ClassManager#aliasPostProcessor', arguments);\r | |
1123 | //</debug>\r | |
1124 | \r | |
1125 | var aliases = Ext.Array.from(data.alias),\r | |
1126 | i, ln;\r | |
1127 | \r | |
1128 | for (i = 0,ln = aliases.length; i < ln; i++) {\r | |
1129 | alias = aliases[i];\r | |
1130 | \r | |
1131 | this.addAlias(cls, alias);\r | |
1132 | }\r | |
1133 | \r | |
1134 | }, ['xtype', 'alias']);\r | |
1135 | //</feature>\r | |
1136 | \r | |
1137 | //<feature classSystem.singleton>\r | |
1138 | /**\r | |
1139 | * @cfg {Boolean} singleton\r | |
1140 | * @member Ext.Class\r | |
1141 | * When set to true, the class will be instantiated as singleton. For example:\r | |
1142 | *\r | |
1143 | * Ext.define('Logger', {\r | |
1144 | * singleton: true,\r | |
1145 | * log: function(msg) {\r | |
1146 | * console.log(msg);\r | |
1147 | * }\r | |
1148 | * });\r | |
1149 | *\r | |
1150 | * Logger.log('Hello');\r | |
1151 | */\r | |
1152 | Manager.registerPostprocessor('singleton', function(name, cls, data, fn) {\r | |
1153 | //<debug>\r | |
1154 | Ext.classSystemMonitor && Ext.classSystemMonitor(name, 'Ext.ClassManager#singletonPostProcessor', arguments);\r | |
1155 | //</debug>\r | |
1156 | \r | |
1157 | if (data.singleton) {\r | |
1158 | fn.call(this, name, new cls(), data);\r | |
1159 | }\r | |
1160 | else {\r | |
1161 | return true;\r | |
1162 | }\r | |
1163 | return false;\r | |
1164 | });\r | |
1165 | //</feature>\r | |
1166 | \r | |
1167 | //<feature classSystem.alternateClassName>\r | |
1168 | /**\r | |
1169 | * @cfg {String/String[]} alternateClassName\r | |
1170 | * @member Ext.Class\r | |
1171 | * Defines alternate names for this class. For example:\r | |
1172 | *\r | |
1173 | * Ext.define('Developer', {\r | |
1174 | * alternateClassName: ['Coder', 'Hacker'],\r | |
1175 | * code: function(msg) {\r | |
1176 | * alert('Typing... ' + msg);\r | |
1177 | * }\r | |
1178 | * });\r | |
1179 | *\r | |
1180 | * var joe = Ext.create('Developer');\r | |
1181 | * joe.code('stackoverflow');\r | |
1182 | *\r | |
1183 | * var rms = Ext.create('Hacker');\r | |
1184 | * rms.code('hack hack');\r | |
1185 | */\r | |
1186 | Manager.registerPostprocessor('alternateClassName', function(name, cls, data) {\r | |
1187 | //<debug>\r | |
1188 | Ext.classSystemMonitor && Ext.classSystemMonitor(name, 'Ext.ClassManager#alternateClassNamePostprocessor', arguments);\r | |
1189 | //</debug>\r | |
1190 | \r | |
1191 | var alternates = data.alternateClassName,\r | |
1192 | i, ln, alternate;\r | |
1193 | \r | |
1194 | if (!(alternates instanceof Array)) {\r | |
1195 | alternates = [alternates];\r | |
1196 | }\r | |
1197 | \r | |
1198 | for (i = 0, ln = alternates.length; i < ln; i++) {\r | |
1199 | alternate = alternates[i];\r | |
1200 | \r | |
1201 | //<debug>\r | |
1202 | if (typeof alternate !== 'string') {\r | |
1203 | throw new Error("[Ext.define] Invalid alternate of: '" + alternate + "' for class: '" + name + "'; must be a valid string");\r | |
1204 | }\r | |
1205 | //</debug>\r | |
1206 | \r | |
1207 | this.set(alternate, cls);\r | |
1208 | }\r | |
1209 | });\r | |
1210 | //</feature>\r | |
1211 | \r | |
1212 | /**\r | |
1213 | * @cfg {Object} debugHooks\r | |
1214 | * A collection of diagnostic methods to decorate the real methods of the class. These\r | |
1215 | * methods are applied as an `override` if this class has debug enabled as defined by\r | |
1216 | * `Ext.isDebugEnabled`.\r | |
1217 | *\r | |
1218 | * These will be automatically removed by the Sencha Cmd compiler for production builds.\r | |
1219 | *\r | |
1220 | * Example usage:\r | |
1221 | *\r | |
1222 | * Ext.define('Foo.bar.Class', {\r | |
1223 | * foo: function (a, b, c) {\r | |
1224 | * ...\r | |
1225 | * },\r | |
1226 | *\r | |
1227 | * bar: function (a, b) {\r | |
1228 | * ...\r | |
1229 | * return 42;\r | |
1230 | * },\r | |
1231 | *\r | |
1232 | * debugHooks: {\r | |
1233 | * foo: function (a, b, c) {\r | |
1234 | * // check arguments...\r | |
1235 | * return this.callParent(arguments);\r | |
1236 | * }\r | |
1237 | * }\r | |
1238 | * });\r | |
1239 | *\r | |
1240 | * If you specify a `$enabled` property in the `debugHooks` object that will be used\r | |
1241 | * as the default enabled state for the hooks. If the `{@link Ext#manifest}` contains\r | |
1242 | * a `debug` object of if `{@link Ext#debugConfig}` is specified, the `$enabled` flag\r | |
1243 | * will override its "*" value.\r | |
1244 | */\r | |
1245 | Manager.registerPostprocessor('debugHooks', function(name, Class, data) {\r | |
1246 | //<debug>\r | |
1247 | Ext.classSystemMonitor && Ext.classSystemMonitor(Class, 'Ext.Class#debugHooks', arguments);\r | |
1248 | \r | |
1249 | if (Ext.isDebugEnabled(Class.$className, data.debugHooks.$enabled)) {\r | |
1250 | delete data.debugHooks.$enabled;\r | |
1251 | Ext.override(Class, data.debugHooks);\r | |
1252 | }\r | |
1253 | //</debug>\r | |
1254 | \r | |
1255 | // may already have an instance here in the case of singleton\r | |
1256 | var target = Class.isInstance ? Class.self : Class;\r | |
1257 | \r | |
1258 | delete target.prototype.debugHooks;\r | |
1259 | });\r | |
1260 | \r | |
1261 | /**\r | |
1262 | * @cfg {Object} deprecated\r | |
1263 | * The object given has properties that describe the versions at which the deprecations\r | |
1264 | * apply.\r | |
1265 | *\r | |
1266 | * The purpose of the `deprecated` declaration is to enable development mode to give\r | |
1267 | * suitable error messages when deprecated methods or properties are used. Methods can\r | |
1268 | * always be injected to provide this feedback, but properties can only be handled on\r | |
1269 | * some browsers (those that support `Object.defineProperty`).\r | |
1270 | *\r | |
1271 | * In some cases, deprecated methods can be restored to their previous behavior or\r | |
1272 | * added back if they have been removed.\r | |
1273 | *\r | |
1274 | * The structure of a `deprecated` declaration is this:\r | |
1275 | *\r | |
1276 | * Ext.define('Foo.bar.Class', {\r | |
1277 | * ...\r | |
1278 | *\r | |
1279 | * deprecated: {\r | |
1280 | * // Optional package name - default is the framework (ext or touch)\r | |
1281 | * name: 'foobar',\r | |
1282 | *\r | |
1283 | * '5.0': {\r | |
1284 | * methods: {\r | |
1285 | * // Throws: '"removedMethod" is deprecated.'\r | |
1286 | * removedMethod: null,\r | |
1287 | *\r | |
1288 | * // Throws: '"oldMethod" is deprecated. Please use "newMethod" instead.'\r | |
1289 | * oldMethod: 'newMethod',\r | |
1290 | *\r | |
1291 | * // When this block is enabled, this method is applied as an\r | |
1292 | * // override. Otherwise you get same as "removeMethod".\r | |
1293 | * method: function () {\r | |
1294 | * // Do what v5 "method" did. If "method" exists in newer\r | |
1295 | * // versions callParent can call it. If 5.1 has "method"\r | |
1296 | * // then it would be next in line, otherwise 5.2 and last\r | |
1297 | * // would be the current class.\r | |
1298 | * },\r | |
1299 | *\r | |
1300 | * moreHelpful: {\r | |
1301 | * message: 'Something helpful to do instead.',\r | |
1302 | * fn: function () {\r | |
1303 | * // The v5 "moreHelpful" method to use when enabled.\r | |
1304 | * }\r | |
1305 | * }\r | |
1306 | * },\r | |
1307 | * properties: {\r | |
1308 | * // Throws: '"removedProp" is deprecated.'\r | |
1309 | * removedProp: null,\r | |
1310 | *\r | |
1311 | * // Throws: '"oldProp" is deprecated. Please use "newProp" instead.'\r | |
1312 | * oldProp: 'newProp',\r | |
1313 | *\r | |
1314 | * helpful: {\r | |
1315 | * message: 'Something helpful message about what to do.'\r | |
1316 | * }\r | |
1317 | * ...\r | |
1318 | * },\r | |
1319 | * statics: {\r | |
1320 | * methods: {\r | |
1321 | * ...\r | |
1322 | * },\r | |
1323 | * properties: {\r | |
1324 | * ...\r | |
1325 | * },\r | |
1326 | * }\r | |
1327 | * },\r | |
1328 | *\r | |
1329 | * '5.1': {\r | |
1330 | * ...\r | |
1331 | * },\r | |
1332 | *\r | |
1333 | * '5.2': {\r | |
1334 | * ...\r | |
1335 | * }\r | |
1336 | * }\r | |
1337 | * });\r | |
1338 | *\r | |
1339 | * The primary content of `deprecated` are the version number keys. These indicate\r | |
1340 | * a version number where methods or properties were deprecated. These versions are\r | |
1341 | * compared to the version reported by `Ext.getCompatVersion` to determine the action\r | |
1342 | * to take for each "block".\r | |
1343 | *\r | |
1344 | * When the compatibility version is set to a value less than a version number key,\r | |
1345 | * that block is said to be "enabled". For example, if a method was deprecated in\r | |
1346 | * version 5.0 but the desired compatibility level is 4.2 then the block is used to\r | |
1347 | * patch methods and (to some degree) restore pre-5.0 compatibility.\r | |
1348 | *\r | |
1349 | * When multiple active blocks have the same method name, each method is applied as\r | |
1350 | * an override in reverse order of version. In the above example, if a method appears\r | |
1351 | * in the "5.0", "5.1" and "5.2" blocks then the "5.2" method is applied as an override\r | |
1352 | * first, followed by the "5.1" method and finally the "5.0" method. This means that\r | |
1353 | * the `callParent` from the "5.0" method calls the "5.1" method which calls the\r | |
1354 | * "5.2" method which can (if applicable) call the current version.\r | |
1355 | */\r | |
1356 | Manager.registerPostprocessor('deprecated', function(name, Class, data) {\r | |
1357 | //<debug>\r | |
1358 | Ext.classSystemMonitor && Ext.classSystemMonitor(Class, 'Ext.Class#deprecated', arguments);\r | |
1359 | //</debug>\r | |
1360 | \r | |
1361 | // may already have an instance here in the case of singleton\r | |
1362 | var target = Class.isInstance ? Class.self : Class;\r | |
1363 | target.addDeprecations(data.deprecated);\r | |
1364 | \r | |
1365 | delete target.prototype.deprecated;\r | |
1366 | });\r | |
1367 | \r | |
1368 | Ext.apply(Ext, {\r | |
1369 | /**\r | |
1370 | * Instantiate a class by either full name, alias or alternate name.\r | |
1371 | *\r | |
1372 | * If {@link Ext.Loader} is {@link Ext.Loader#setConfig enabled} and the class has\r | |
1373 | * not been defined yet, it will attempt to load the class via synchronous loading.\r | |
1374 | *\r | |
1375 | * For example, all these three lines return the same result:\r | |
1376 | *\r | |
1377 | * // xtype\r | |
1378 | * var window = Ext.create({\r | |
1379 | * xtype: 'window',\r | |
1380 | * width: 600,\r | |
1381 | * height: 800,\r | |
1382 | * ...\r | |
1383 | * });\r | |
1384 | *\r | |
1385 | * // alias\r | |
1386 | * var window = Ext.create('widget.window', {\r | |
1387 | * width: 600,\r | |
1388 | * height: 800,\r | |
1389 | * ...\r | |
1390 | * });\r | |
1391 | *\r | |
1392 | * // alternate name\r | |
1393 | * var window = Ext.create('Ext.Window', {\r | |
1394 | * width: 600,\r | |
1395 | * height: 800,\r | |
1396 | * ...\r | |
1397 | * });\r | |
1398 | *\r | |
1399 | * // full class name\r | |
1400 | * var window = Ext.create('Ext.window.Window', {\r | |
1401 | * width: 600,\r | |
1402 | * height: 800,\r | |
1403 | * ...\r | |
1404 | * });\r | |
1405 | *\r | |
1406 | * // single object with xclass property:\r | |
1407 | * var window = Ext.create({\r | |
1408 | * xclass: 'Ext.window.Window', // any valid value for 'name' (above)\r | |
1409 | * width: 600,\r | |
1410 | * height: 800,\r | |
1411 | * ...\r | |
1412 | * });\r | |
1413 | *\r | |
1414 | * @param {String} [name] The class name or alias. Can be specified as `xclass`\r | |
1415 | * property if only one object parameter is specified.\r | |
1416 | * @param {Object...} [args] Additional arguments after the name will be passed to\r | |
1417 | * the class' constructor.\r | |
1418 | * @return {Object} instance\r | |
1419 | * @member Ext\r | |
1420 | * @method create\r | |
1421 | */\r | |
1422 | create: function () {\r | |
1423 | var name = arguments[0],\r | |
1424 | nameType = typeof name,\r | |
1425 | args = arraySlice.call(arguments, 1),\r | |
1426 | cls;\r | |
1427 | \r | |
1428 | if (nameType === 'function') {\r | |
1429 | cls = name;\r | |
1430 | } else {\r | |
1431 | if (nameType !== 'string' && args.length === 0) {\r | |
1432 | args = [name];\r | |
1433 | if (!(name = name.xclass)) {\r | |
1434 | name = args[0].xtype;\r | |
1435 | if (name) {\r | |
1436 | name = 'widget.' + name;\r | |
1437 | }\r | |
1438 | }\r | |
1439 | }\r | |
1440 | \r | |
1441 | //<debug>\r | |
1442 | if (typeof name !== 'string' || name.length < 1) {\r | |
1443 | throw new Error("[Ext.create] Invalid class name or alias '" + name +\r | |
1444 | "' specified, must be a non-empty string");\r | |
1445 | }\r | |
1446 | //</debug>\r | |
1447 | \r | |
1448 | name = Manager.resolveName(name);\r | |
1449 | cls = Manager.get(name);\r | |
1450 | }\r | |
1451 | \r | |
1452 | // Still not existing at this point, try to load it via synchronous mode as the last resort\r | |
1453 | if (!cls) {\r | |
1454 | //<debug>\r | |
1455 | //<if nonBrowser>\r | |
1456 | !isNonBrowser &&\r | |
1457 | //</if>\r | |
1458 | Ext.log.warn("[Ext.Loader] Synchronously loading '" + name + "'; consider adding " +\r | |
1459 | "Ext.require('" + name + "') above Ext.onReady");\r | |
1460 | //</debug>\r | |
1461 | \r | |
1462 | Ext.syncRequire(name);\r | |
1463 | \r | |
1464 | cls = Manager.get(name);\r | |
1465 | }\r | |
1466 | \r | |
1467 | //<debug>\r | |
1468 | if (!cls) {\r | |
1469 | throw new Error("[Ext.create] Unrecognized class name / alias: " + name);\r | |
1470 | }\r | |
1471 | \r | |
1472 | if (typeof cls !== 'function') {\r | |
1473 | throw new Error("[Ext.create] Singleton '" + name + "' cannot be instantiated.");\r | |
1474 | }\r | |
1475 | //</debug>\r | |
1476 | \r | |
1477 | return Manager.getInstantiator(args.length)(cls, args);\r | |
1478 | },\r | |
1479 | \r | |
1480 | /**\r | |
1481 | * Convenient shorthand to create a widget by its xtype or a config object.\r | |
1482 | *\r | |
1483 | * var button = Ext.widget('button'); // Equivalent to Ext.create('widget.button');\r | |
1484 | *\r | |
1485 | * var panel = Ext.widget('panel', { // Equivalent to Ext.create('widget.panel')\r | |
1486 | * title: 'Panel'\r | |
1487 | * });\r | |
1488 | *\r | |
1489 | * var grid = Ext.widget({\r | |
1490 | * xtype: 'grid',\r | |
1491 | * ...\r | |
1492 | * });\r | |
1493 | *\r | |
1494 | * If a {@link Ext.Component component} instance is passed, it is simply returned.\r | |
1495 | *\r | |
1496 | * @member Ext\r | |
1497 | * @param {String} [name] The xtype of the widget to create.\r | |
1498 | * @param {Object} [config] The configuration object for the widget constructor.\r | |
1499 | * @return {Object} The widget instance\r | |
1500 | */\r | |
1501 | widget: function(name, config) {\r | |
1502 | // forms:\r | |
1503 | // 1: (xtype)\r | |
1504 | // 2: (xtype, config)\r | |
1505 | // 3: (config)\r | |
1506 | // 4: (xtype, component)\r | |
1507 | // 5: (component)\r | |
1508 | // \r | |
1509 | var xtype = name,\r | |
1510 | alias, className, T;\r | |
1511 | \r | |
1512 | if (typeof xtype !== 'string') { // if (form 3 or 5)\r | |
1513 | // first arg is config or component\r | |
1514 | config = name; // arguments[0]\r | |
1515 | xtype = config.xtype;\r | |
1516 | className = config.xclass;\r | |
1517 | } else {\r | |
1518 | config = config || {};\r | |
1519 | }\r | |
1520 | \r | |
1521 | if (config.isComponent) {\r | |
1522 | return config;\r | |
1523 | }\r | |
1524 | \r | |
1525 | if (!className) {\r | |
1526 | alias = 'widget.' + xtype;\r | |
1527 | className = Manager.getNameByAlias(alias);\r | |
1528 | }\r | |
1529 | \r | |
1530 | // this is needed to support demand loading of the class\r | |
1531 | if (className) {\r | |
1532 | T = Manager.get(className);\r | |
1533 | }\r | |
1534 | \r | |
1535 | if (!T) {\r | |
1536 | return Ext.create(className || alias, config);\r | |
1537 | }\r | |
1538 | return new T(config);\r | |
1539 | },\r | |
1540 | \r | |
1541 | /**\r | |
1542 | * @inheritdoc Ext.ClassManager#instantiateByAlias\r | |
1543 | * @member Ext\r | |
1544 | * @method createByAlias\r | |
1545 | */\r | |
1546 | createByAlias: alias(Manager, 'instantiateByAlias'),\r | |
1547 | \r | |
1548 | /**\r | |
1549 | * Defines a class or override. A basic class is defined like this:\r | |
1550 | *\r | |
1551 | * Ext.define('My.awesome.Class', {\r | |
1552 | * someProperty: 'something',\r | |
1553 | *\r | |
1554 | * someMethod: function(s) {\r | |
1555 | * alert(s + this.someProperty);\r | |
1556 | * }\r | |
1557 | *\r | |
1558 | * ...\r | |
1559 | * });\r | |
1560 | *\r | |
1561 | * var obj = new My.awesome.Class();\r | |
1562 | *\r | |
1563 | * obj.someMethod('Say '); // alerts 'Say something'\r | |
1564 | *\r | |
1565 | * To create an anonymous class, pass `null` for the `className`:\r | |
1566 | *\r | |
1567 | * Ext.define(null, {\r | |
1568 | * constructor: function () {\r | |
1569 | * // ...\r | |
1570 | * }\r | |
1571 | * });\r | |
1572 | *\r | |
1573 | * In some cases, it is helpful to create a nested scope to contain some private\r | |
1574 | * properties. The best way to do this is to pass a function instead of an object\r | |
1575 | * as the second parameter. This function will be called to produce the class\r | |
1576 | * body:\r | |
1577 | *\r | |
1578 | * Ext.define('MyApp.foo.Bar', function () {\r | |
1579 | * var id = 0;\r | |
1580 | *\r | |
1581 | * return {\r | |
1582 | * nextId: function () {\r | |
1583 | * return ++id;\r | |
1584 | * }\r | |
1585 | * };\r | |
1586 | * });\r | |
1587 | * \r | |
1588 | * _Note_ that when using override, the above syntax will not override successfully, because\r | |
1589 | * the passed function would need to be executed first to determine whether or not the result \r | |
1590 | * is an override or defining a new object. As such, an alternative syntax that immediately \r | |
1591 | * invokes the function can be used:\r | |
1592 | * \r | |
1593 | * Ext.define('MyApp.override.BaseOverride', function () {\r | |
1594 | * var counter = 0;\r | |
1595 | *\r | |
1596 | * return {\r | |
1597 | * override: 'Ext.Component',\r | |
1598 | * logId: function () {\r | |
1599 | * console.log(++counter, this.id);\r | |
1600 | * }\r | |
1601 | * };\r | |
1602 | * }());\r | |
1603 | * \r | |
1604 | *\r | |
1605 | * When using this form of `Ext.define`, the function is passed a reference to its\r | |
1606 | * class. This can be used as an efficient way to access any static properties you\r | |
1607 | * may have:\r | |
1608 | *\r | |
1609 | * Ext.define('MyApp.foo.Bar', function (Bar) {\r | |
1610 | * return {\r | |
1611 | * statics: {\r | |
1612 | * staticMethod: function () {\r | |
1613 | * // ...\r | |
1614 | * }\r | |
1615 | * },\r | |
1616 | *\r | |
1617 | * method: function () {\r | |
1618 | * return Bar.staticMethod();\r | |
1619 | * }\r | |
1620 | * };\r | |
1621 | * });\r | |
1622 | *\r | |
1623 | * To define an override, include the `override` property. The content of an\r | |
1624 | * override is aggregated with the specified class in order to extend or modify\r | |
1625 | * that class. This can be as simple as setting default property values or it can\r | |
1626 | * extend and/or replace methods. This can also extend the statics of the class.\r | |
1627 | *\r | |
1628 | * One use for an override is to break a large class into manageable pieces.\r | |
1629 | *\r | |
1630 | * // File: /src/app/Panel.js\r | |
1631 | *\r | |
1632 | * Ext.define('My.app.Panel', {\r | |
1633 | * extend: 'Ext.panel.Panel',\r | |
1634 | * requires: [\r | |
1635 | * 'My.app.PanelPart2',\r | |
1636 | * 'My.app.PanelPart3'\r | |
1637 | * ]\r | |
1638 | *\r | |
1639 | * constructor: function (config) {\r | |
1640 | * this.callParent(arguments); // calls Ext.panel.Panel's constructor\r | |
1641 | * //...\r | |
1642 | * },\r | |
1643 | *\r | |
1644 | * statics: {\r | |
1645 | * method: function () {\r | |
1646 | * return 'abc';\r | |
1647 | * }\r | |
1648 | * }\r | |
1649 | * });\r | |
1650 | *\r | |
1651 | * // File: /src/app/PanelPart2.js\r | |
1652 | * Ext.define('My.app.PanelPart2', {\r | |
1653 | * override: 'My.app.Panel',\r | |
1654 | *\r | |
1655 | * constructor: function (config) {\r | |
1656 | * this.callParent(arguments); // calls My.app.Panel's constructor\r | |
1657 | * //...\r | |
1658 | * }\r | |
1659 | * });\r | |
1660 | *\r | |
1661 | * Another use of overrides is to provide optional parts of classes that can be\r | |
1662 | * independently required. In this case, the class may even be unaware of the\r | |
1663 | * override altogether.\r | |
1664 | *\r | |
1665 | * Ext.define('My.ux.CoolTip', {\r | |
1666 | * override: 'Ext.tip.ToolTip',\r | |
1667 | *\r | |
1668 | * constructor: function (config) {\r | |
1669 | * this.callParent(arguments); // calls Ext.tip.ToolTip's constructor\r | |
1670 | * //...\r | |
1671 | * }\r | |
1672 | * });\r | |
1673 | *\r | |
1674 | * The above override can now be required as normal.\r | |
1675 | *\r | |
1676 | * Ext.define('My.app.App', {\r | |
1677 | * requires: [\r | |
1678 | * 'My.ux.CoolTip'\r | |
1679 | * ]\r | |
1680 | * });\r | |
1681 | *\r | |
1682 | * Overrides can also contain statics, inheritableStatics, or privates:\r | |
1683 | *\r | |
1684 | * Ext.define('My.app.BarMod', {\r | |
1685 | * override: 'Ext.foo.Bar',\r | |
1686 | *\r | |
1687 | * statics: {\r | |
1688 | * method: function (x) {\r | |
1689 | * return this.callParent([x * 2]); // call Ext.foo.Bar.method\r | |
1690 | * }\r | |
1691 | * }\r | |
1692 | * });\r | |
1693 | * \r | |
1694 | * Starting in version 4.2.2, overrides can declare their `compatibility` based\r | |
1695 | * on the framework version or on versions of other packages. For details on the\r | |
1696 | * syntax and options for these checks, see `Ext.checkVersion`.\r | |
1697 | * \r | |
1698 | * The simplest use case is to test framework version for compatibility:\r | |
1699 | * \r | |
1700 | * Ext.define('App.overrides.grid.Panel', {\r | |
1701 | * override: 'Ext.grid.Panel',\r | |
1702 | *\r | |
1703 | * compatibility: '4.2.2', // only if framework version is 4.2.2\r | |
1704 | *\r | |
1705 | * //...\r | |
1706 | * });\r | |
1707 | * \r | |
1708 | * An array is treated as an OR, so if any specs match, the override is\r | |
1709 | * compatible.\r | |
1710 | * \r | |
1711 | * Ext.define('App.overrides.some.Thing', {\r | |
1712 | * override: 'Foo.some.Thing',\r | |
1713 | *\r | |
1714 | * compatibility: [\r | |
1715 | * '4.2.2',\r | |
1716 | * 'foo@1.0.1-1.0.2'\r | |
1717 | * ],\r | |
1718 | *\r | |
1719 | * //...\r | |
1720 | * });\r | |
1721 | * \r | |
1722 | * To require that all specifications match, an object can be provided:\r | |
1723 | * \r | |
1724 | * Ext.define('App.overrides.some.Thing', {\r | |
1725 | * override: 'Foo.some.Thing',\r | |
1726 | *\r | |
1727 | * compatibility: {\r | |
1728 | * and: [\r | |
1729 | * '4.2.2',\r | |
1730 | * 'foo@1.0.1-1.0.2'\r | |
1731 | * ]\r | |
1732 | * },\r | |
1733 | *\r | |
1734 | * //...\r | |
1735 | * });\r | |
1736 | * \r | |
1737 | * Because the object form is just a recursive check, these can be nested:\r | |
1738 | * \r | |
1739 | * Ext.define('App.overrides.some.Thing', {\r | |
1740 | * override: 'Foo.some.Thing',\r | |
1741 | *\r | |
1742 | * compatibility: {\r | |
1743 | * and: [\r | |
1744 | * '4.2.2', // exactly version 4.2.2 of the framework *AND*\r | |
1745 | * {\r | |
1746 | * // either (or both) of these package specs:\r | |
1747 | * or: [\r | |
1748 | * 'foo@1.0.1-1.0.2',\r | |
1749 | * 'bar@3.0+'\r | |
1750 | * ]\r | |
1751 | * }\r | |
1752 | * ]\r | |
1753 | * },\r | |
1754 | *\r | |
1755 | * //...\r | |
1756 | * });\r | |
1757 | *\r | |
1758 | * IMPORTANT: An override is only included in a build if the class it overrides is\r | |
1759 | * required. Otherwise, the override, like the target class, is not included. In\r | |
1760 | * Sencha Cmd v4, the `compatibility` declaration can likewise be used to remove\r | |
1761 | * incompatible overrides from a build.\r | |
1762 | *\r | |
1763 | * @param {String} className The class name to create in string dot-namespaced format, for example:\r | |
1764 | * 'My.very.awesome.Class', 'FeedViewer.plugin.CoolPager'\r | |
1765 | * It is highly recommended to follow this simple convention:\r | |
1766 | * - The root and the class name are 'CamelCased'\r | |
1767 | * - Everything else is lower-cased\r | |
1768 | * Pass `null` to create an anonymous class.\r | |
1769 | * @param {Object} data The key - value pairs of properties to apply to this class. Property names can be of any valid\r | |
1770 | * strings, except those in the reserved listed below:\r | |
1771 | * \r | |
1772 | * - {@link Ext.Class#cfg-alias alias}\r | |
1773 | * - {@link Ext.Class#cfg-alternateClassName alternateClassName}\r | |
1774 | * - {@link Ext.Class#cfg-cachedConfig cachedConfig}\r | |
1775 | * - {@link Ext.Class#cfg-config config}\r | |
1776 | * - {@link Ext.Class#cfg-extend extend}\r | |
1777 | * - {@link Ext.Class#cfg-inheritableStatics inheritableStatics}\r | |
1778 | * - {@link Ext.Class#cfg-mixins mixins}\r | |
1779 | * - {@link Ext.Class#cfg-override override}\r | |
1780 | * - {@link Ext.Class#cfg-platformConfig platformConfig}\r | |
1781 | * - {@link Ext.Class#cfg-privates privates}\r | |
1782 | * - {@link Ext.Class#cfg-requires requires}\r | |
1783 | * - `self`\r | |
1784 | * - {@link Ext.Class#cfg-singleton singleton}\r | |
1785 | * - {@link Ext.Class#cfg-statics statics}\r | |
1786 | * - {@link Ext.Class#cfg-uses uses}\r | |
1787 | * - {@link Ext.Class#cfg-xtype xtype} (for {@link Ext.Component Components} only)\r | |
1788 | *\r | |
1789 | * @param {Function} [createdFn] Callback to execute after the class is created, the execution scope of which\r | |
1790 | * (`this`) will be the newly created class itself.\r | |
1791 | * @return {Ext.Base}\r | |
1792 | * @member Ext\r | |
1793 | */\r | |
1794 | define: function (className, data, createdFn) {\r | |
1795 | //<debug>\r | |
1796 | Ext.classSystemMonitor && Ext.classSystemMonitor(className, 'ClassManager#define', arguments);\r | |
1797 | //</debug>\r | |
1798 | \r | |
1799 | if (data.override) {\r | |
1800 | Manager.classState[className] = 20;\r | |
1801 | return Manager.createOverride.apply(Manager, arguments);\r | |
1802 | }\r | |
1803 | \r | |
1804 | Manager.classState[className] = 10;\r | |
1805 | return Manager.create.apply(Manager, arguments);\r | |
1806 | },\r | |
1807 | \r | |
1808 | /**\r | |
1809 | * Undefines a class defined using the #define method. Typically used\r | |
1810 | * for unit testing where setting up and tearing down a class multiple\r | |
1811 | * times is required. For example:\r | |
1812 | * \r | |
1813 | * // define a class\r | |
1814 | * Ext.define('Foo', {\r | |
1815 | * ...\r | |
1816 | * });\r | |
1817 | * \r | |
1818 | * // run test\r | |
1819 | * \r | |
1820 | * // undefine the class\r | |
1821 | * Ext.undefine('Foo');\r | |
1822 | * @param {String} className The class name to undefine in string dot-namespaced format.\r | |
1823 | * @private\r | |
1824 | */\r | |
1825 | undefine: function(className) {\r | |
1826 | //<debug>\r | |
1827 | Ext.classSystemMonitor && Ext.classSystemMonitor(className, 'Ext.ClassManager#undefine', arguments);\r | |
1828 | //</debug>\r | |
1829 | \r | |
1830 | var classes = Manager.classes;\r | |
1831 | \r | |
1832 | delete classes[className];\r | |
1833 | delete Manager.existCache[className];\r | |
1834 | delete Manager.classState[className];\r | |
1835 | \r | |
1836 | Manager.removeName(className);\r | |
1837 | \r | |
1838 | var entry = Manager.getNamespaceEntry(className),\r | |
1839 | scope = entry.parent ? Manager.lookupName(entry.parent, false) : Ext.global;\r | |
1840 | \r | |
1841 | if (scope) {\r | |
1842 | // Old IE blows up on attempt to delete window property\r | |
1843 | try {\r | |
1844 | delete scope[entry.name];\r | |
1845 | }\r | |
1846 | catch (e) {\r | |
1847 | scope[entry.name] = undefined;\r | |
1848 | }\r | |
1849 | }\r | |
1850 | },\r | |
1851 | \r | |
1852 | /**\r | |
1853 | * @inheritdoc Ext.ClassManager#getName\r | |
1854 | * @member Ext\r | |
1855 | * @method getClassName\r | |
1856 | */\r | |
1857 | getClassName: alias(Manager, 'getName'),\r | |
1858 | \r | |
1859 | /**\r | |
1860 | * Returns the displayName property or className or object. When all else fails, returns "Anonymous".\r | |
1861 | * @param {Object} object\r | |
1862 | * @return {String}\r | |
1863 | */\r | |
1864 | getDisplayName: function(object) {\r | |
1865 | if (object) {\r | |
1866 | if (object.displayName) {\r | |
1867 | return object.displayName;\r | |
1868 | }\r | |
1869 | \r | |
1870 | if (object.$name && object.$class) {\r | |
1871 | return Ext.getClassName(object.$class) + '#' + object.$name;\r | |
1872 | }\r | |
1873 | \r | |
1874 | if (object.$className) {\r | |
1875 | return object.$className;\r | |
1876 | }\r | |
1877 | }\r | |
1878 | \r | |
1879 | return 'Anonymous';\r | |
1880 | },\r | |
1881 | \r | |
1882 | /**\r | |
1883 | * @inheritdoc Ext.ClassManager#getClass\r | |
1884 | * @member Ext\r | |
1885 | * @method getClass\r | |
1886 | */\r | |
1887 | getClass: alias(Manager, 'getClass'),\r | |
1888 | \r | |
1889 | /**\r | |
1890 | * Creates namespaces to be used for scoping variables and classes so that they are not global.\r | |
1891 | * Specifying the last node of a namespace implicitly creates all other nodes. Usage:\r | |
1892 | *\r | |
1893 | * Ext.namespace('Company', 'Company.data');\r | |
1894 | *\r | |
1895 | * // equivalent and preferable to the above syntax\r | |
1896 | * Ext.ns('Company.data');\r | |
1897 | *\r | |
1898 | * Company.Widget = function() { ... };\r | |
1899 | *\r | |
1900 | * Company.data.CustomStore = function(config) { ... };\r | |
1901 | *\r | |
1902 | * @param {String...} namespaces\r | |
1903 | * @return {Object} The (last) namespace object created.\r | |
1904 | * @member Ext\r | |
1905 | * @method namespace\r | |
1906 | */\r | |
1907 | namespace: function () {\r | |
1908 | var root = global,\r | |
1909 | i;\r | |
1910 | \r | |
1911 | for (i = arguments.length; i-- > 0; ) {\r | |
1912 | root = Manager.lookupName(arguments[i], true);\r | |
1913 | }\r | |
1914 | \r | |
1915 | return root;\r | |
1916 | }\r | |
1917 | });\r | |
1918 | \r | |
1919 | /**\r | |
1920 | * This function registers top-level (root) namespaces. This is needed for "sandbox"\r | |
1921 | * builds.\r | |
1922 | *\r | |
1923 | * Ext.addRootNamespaces({\r | |
1924 | * MyApp: MyApp,\r | |
1925 | * Common: Common\r | |
1926 | * });\r | |
1927 | *\r | |
1928 | * In the above example, `MyApp` and `Common` are top-level namespaces that happen\r | |
1929 | * to also be included in the sandbox closure. Something like this:\r | |
1930 | *\r | |
1931 | * (function(Ext) {\r | |
1932 | *\r | |
1933 | * Ext.sandboxName = 'Ext6';\r | |
1934 | * Ext.isSandboxed = true;\r | |
1935 | * Ext.buildSettings = { baseCSSPrefix: "x6-", scopeResetCSS: true };\r | |
1936 | *\r | |
1937 | * var MyApp = MyApp || {};\r | |
1938 | * Ext.addRootNamespaces({ MyApp: MyApp );\r | |
1939 | *\r | |
1940 | * ... normal app.js goes here ...\r | |
1941 | *\r | |
1942 | * })(this.Ext6 || (this.Ext6 = {}));\r | |
1943 | *\r | |
1944 | * The sandbox wrapper around the normally built `app.js` content has to take care\r | |
1945 | * of introducing top-level namespaces as well as call this method.\r | |
1946 | *\r | |
1947 | * @param {Object} namespaces\r | |
1948 | * @method addRootNamespaces\r | |
1949 | * @member Ext\r | |
1950 | * @since 6.0.0\r | |
1951 | * @private\r | |
1952 | */\r | |
1953 | Ext.addRootNamespaces = Manager.addRootNamespaces;\r | |
1954 | \r | |
1955 | /**\r | |
1956 | * Old name for {@link Ext#widget}.\r | |
1957 | * @deprecated Use {@link Ext#widget} instead.\r | |
1958 | * @method createWidget\r | |
1959 | * @member Ext\r | |
1960 | * @private\r | |
1961 | */\r | |
1962 | Ext.createWidget = Ext.widget;\r | |
1963 | \r | |
1964 | /**\r | |
1965 | * Convenient alias for {@link Ext#namespace Ext.namespace}.\r | |
1966 | * @inheritdoc Ext#namespace\r | |
1967 | * @member Ext\r | |
1968 | * @method ns\r | |
1969 | */\r | |
1970 | Ext.ns = Ext.namespace;\r | |
1971 | \r | |
1972 | Class.registerPreprocessor('className', function(cls, data) {\r | |
1973 | if ('$className' in data) {\r | |
1974 | cls.$className = data.$className;\r | |
1975 | //<debug>\r | |
1976 | cls.displayName = cls.$className;\r | |
1977 | //</debug>\r | |
1978 | }\r | |
1979 | \r | |
1980 | //<debug>\r | |
1981 | Ext.classSystemMonitor && Ext.classSystemMonitor(cls, 'Ext.ClassManager#classNamePreprocessor', arguments);\r | |
1982 | //</debug>\r | |
1983 | }, true, 'first');\r | |
1984 | \r | |
1985 | Class.registerPreprocessor('alias', function(cls, data) {\r | |
1986 | //<debug>\r | |
1987 | Ext.classSystemMonitor && Ext.classSystemMonitor(cls, 'Ext.ClassManager#aliasPreprocessor', arguments);\r | |
1988 | //</debug>\r | |
1989 | \r | |
1990 | var prototype = cls.prototype,\r | |
1991 | xtypes = arrayFrom(data.xtype),\r | |
1992 | aliases = arrayFrom(data.alias),\r | |
1993 | widgetPrefix = 'widget.',\r | |
1994 | widgetPrefixLength = widgetPrefix.length,\r | |
1995 | xtypesChain = Array.prototype.slice.call(prototype.xtypesChain || []),\r | |
1996 | xtypesMap = Ext.merge({}, prototype.xtypesMap || {}),\r | |
1997 | i, ln, alias, xtype;\r | |
1998 | \r | |
1999 | for (i = 0,ln = aliases.length; i < ln; i++) {\r | |
2000 | alias = aliases[i];\r | |
2001 | \r | |
2002 | //<debug>\r | |
2003 | if (typeof alias !== 'string' || alias.length < 1) {\r | |
2004 | throw new Error("[Ext.define] Invalid alias of: '" + alias + "' for class: '" + name + "'; must be a valid string");\r | |
2005 | }\r | |
2006 | //</debug>\r | |
2007 | \r | |
2008 | if (alias.substring(0, widgetPrefixLength) === widgetPrefix) {\r | |
2009 | xtype = alias.substring(widgetPrefixLength);\r | |
2010 | Ext.Array.include(xtypes, xtype);\r | |
2011 | }\r | |
2012 | }\r | |
2013 | \r | |
2014 | cls.xtype = data.xtype = xtypes[0];\r | |
2015 | data.xtypes = xtypes;\r | |
2016 | \r | |
2017 | for (i = 0,ln = xtypes.length; i < ln; i++) {\r | |
2018 | xtype = xtypes[i];\r | |
2019 | \r | |
2020 | if (!xtypesMap[xtype]) {\r | |
2021 | xtypesMap[xtype] = true;\r | |
2022 | xtypesChain.push(xtype);\r | |
2023 | }\r | |
2024 | }\r | |
2025 | \r | |
2026 | data.xtypesChain = xtypesChain;\r | |
2027 | data.xtypesMap = xtypesMap;\r | |
2028 | \r | |
2029 | Ext.Function.interceptAfter(data, 'onClassCreated', function() {\r | |
2030 | //<debug>\r | |
2031 | Ext.classSystemMonitor && Ext.classSystemMonitor(cls, 'Ext.ClassManager#aliasPreprocessor#afterClassCreated', arguments);\r | |
2032 | //</debug>\r | |
2033 | \r | |
2034 | var mixins = prototype.mixins,\r | |
2035 | key, mixin;\r | |
2036 | \r | |
2037 | for (key in mixins) {\r | |
2038 | if (mixins.hasOwnProperty(key)) {\r | |
2039 | mixin = mixins[key];\r | |
2040 | \r | |
2041 | xtypes = mixin.xtypes;\r | |
2042 | \r | |
2043 | if (xtypes) {\r | |
2044 | for (i = 0,ln = xtypes.length; i < ln; i++) {\r | |
2045 | xtype = xtypes[i];\r | |
2046 | \r | |
2047 | if (!xtypesMap[xtype]) {\r | |
2048 | xtypesMap[xtype] = true;\r | |
2049 | xtypesChain.push(xtype);\r | |
2050 | }\r | |
2051 | }\r | |
2052 | }\r | |
2053 | }\r | |
2054 | }\r | |
2055 | });\r | |
2056 | \r | |
2057 | for (i = 0,ln = xtypes.length; i < ln; i++) {\r | |
2058 | xtype = xtypes[i];\r | |
2059 | \r | |
2060 | //<debug>\r | |
2061 | if (typeof xtype !== 'string' || xtype.length < 1) {\r | |
2062 | throw new Error("[Ext.define] Invalid xtype of: '" + xtype + "' for class: '" + name + "'; must be a valid non-empty string");\r | |
2063 | }\r | |
2064 | //</debug>\r | |
2065 | \r | |
2066 | Ext.Array.include(aliases, widgetPrefix + xtype);\r | |
2067 | }\r | |
2068 | \r | |
2069 | data.alias = aliases;\r | |
2070 | \r | |
2071 | }, ['xtype', 'alias']);\r | |
2072 | \r | |
2073 | // load the cmd-5 style app manifest metadata now, if available...\r | |
2074 | if (Ext.manifest) {\r | |
2075 | var manifest = Ext.manifest,\r | |
2076 | classes = manifest.classes,\r | |
2077 | paths = manifest.paths,\r | |
2078 | aliases = {},\r | |
2079 | alternates = {},\r | |
2080 | className, obj, name, path, baseUrl;\r | |
2081 | \r | |
2082 | if (paths) {\r | |
2083 | // if the manifest paths were calculated as relative to the\r | |
2084 | // bootstrap file, then we need to prepend Boot.baseUrl to the\r | |
2085 | // paths before processing\r | |
2086 | if (manifest.bootRelative) {\r | |
2087 | baseUrl = Ext.Boot.baseUrl;\r | |
2088 | for (path in paths) {\r | |
2089 | if (paths.hasOwnProperty(path)) {\r | |
2090 | paths[path] = baseUrl + paths[path];\r | |
2091 | }\r | |
2092 | }\r | |
2093 | }\r | |
2094 | Manager.setPath(paths);\r | |
2095 | }\r | |
2096 | \r | |
2097 | if (classes) {\r | |
2098 | for (className in classes) {\r | |
2099 | alternates[className] = [];\r | |
2100 | aliases[className] = [];\r | |
2101 | obj = classes[className];\r | |
2102 | if (obj.alias) {\r | |
2103 | aliases[className] = obj.alias;\r | |
2104 | }\r | |
2105 | if (obj.alternates) {\r | |
2106 | alternates[className] = obj.alternates;\r | |
2107 | }\r | |
2108 | }\r | |
2109 | }\r | |
2110 | \r | |
2111 | Manager.addAlias(aliases);\r | |
2112 | Manager.addAlternate(alternates);\r | |
2113 | }\r | |
2114 | \r | |
2115 | return Manager;\r | |
2116 | }(Ext.Class, Ext.Function.alias, Array.prototype.slice, Ext.Array.from, Ext.global));\r |