]>
Commit | Line | Data |
---|---|---|
6527f429 DM |
1 | // @tag class\r |
2 | /**\r | |
3 | * This class provides dynamic loading support for JavaScript classes. Application code\r | |
4 | * does not typically need to call `Ext.Loader` except perhaps to configure path mappings\r | |
5 | * when not using [Sencha Cmd](http://www.sencha.com/products/sencha-cmd/).\r | |
6 | *\r | |
7 | * Ext.Loader.setPath('MyApp', 'app');\r | |
8 | *\r | |
9 | * When using Sencha Cmd, this is handled by the "bootstrap" provided by the application\r | |
10 | * build script and such configuration is not necessary.\r | |
11 | *\r | |
12 | * # Typical Usage\r | |
13 | *\r | |
14 | * The `Ext.Loader` is most often used behind the scenes to satisfy class references in\r | |
15 | * class declarations. Like so:\r | |
16 | *\r | |
17 | * Ext.define('MyApp.view.Main', {\r | |
18 | * extend: 'Ext.panel.Panel',\r | |
19 | *\r | |
20 | * mixins: [\r | |
21 | * 'MyApp.util.Mixin'\r | |
22 | * ],\r | |
23 | *\r | |
24 | * requires: [\r | |
25 | * 'Ext.grid.Panel'\r | |
26 | * ],\r | |
27 | *\r | |
28 | * uses: [\r | |
29 | * 'MyApp.util.Stuff'\r | |
30 | * ]\r | |
31 | * });\r | |
32 | *\r | |
33 | * In all of these cases, `Ext.Loader` is used internally to resolve these class names\r | |
34 | * and ensure that the necessary class files are loaded.\r | |
35 | *\r | |
36 | * During development, these files are loaded individually for optimal debugging. For a\r | |
37 | * production use, [Sencha Cmd](http://www.sencha.com/products/sencha-cmd/) will replace\r | |
38 | * all of these strings with the actual resolved class references because it ensures that\r | |
39 | * the classes are all contained in the build in the correct order. In development, these\r | |
40 | * files will not be loaded until the `MyApp.view.Main` class indicates they are needed\r | |
41 | * as shown above.\r | |
42 | *\r | |
43 | * # Loading Classes\r | |
44 | *\r | |
45 | * You can also use `Ext.Loader` directly to load classes or files. The simplest form of\r | |
46 | * use is `{@link Ext#require}`.\r | |
47 | *\r | |
48 | * For example:\r | |
49 | *\r | |
50 | * Ext.require('MyApp.view.Main', function () {\r | |
51 | * // On callback, the MyApp.view.Main class is now loaded\r | |
52 | *\r | |
53 | * var view = new MyApp.view.Main();\r | |
54 | * });\r | |
55 | *\r | |
56 | * You can alternatively require classes by alias or wildcard.\r | |
57 | *\r | |
58 | * Ext.require('widget.window');\r | |
59 | *\r | |
60 | * Ext.require(['widget.window', 'layout.border', 'Ext.data.Connection']);\r | |
61 | *\r | |
62 | * Ext.require(['widget.*', 'layout.*', 'Ext.data.*']);\r | |
63 | *\r | |
64 | * The callback function is optional.\r | |
65 | *\r | |
66 | * **Note** Using `Ext.require` at global scope will cause `{@link Ext#onReady}` and\r | |
67 | * `{@link Ext.app.Application#launch}` methods to be deferred until the required classes\r | |
68 | * are loaded. It is these cases where the callback function is most often unnecessary.\r | |
69 | *\r | |
70 | * ## Using Excludes\r | |
71 | *\r | |
72 | * Alternatively, you can exclude what you don't need:\r | |
73 | *\r | |
74 | * // Include everything except Ext.tree.*\r | |
75 | * Ext.exclude('Ext.tree.*').require('*');\r | |
76 | *\r | |
77 | * // Include all widgets except widget.checkbox* (this will exclude\r | |
78 | * // widget.checkbox, widget.checkboxfield, widget.checkboxgroup, etc.)\r | |
79 | * Ext.exclude('widget.checkbox*').require('widget.*');\r | |
80 | *\r | |
81 | * # Dynamic Instantiation\r | |
82 | *\r | |
83 | * Another feature enabled by `Ext.Loader` is instantiation using class names or aliases.\r | |
84 | *\r | |
85 | * For example:\r | |
86 | *\r | |
87 | * var win = Ext.create({\r | |
88 | * xtype: 'window',\r | |
89 | *\r | |
90 | * // or\r | |
91 | * // xclass: 'Ext.window.Window'\r | |
92 | *\r | |
93 | * title: 'Hello'\r | |
94 | * });\r | |
95 | *\r | |
96 | * This form of creation can be useful if the type to create (`window` in the above) is\r | |
97 | * not known statically. Internally, `{@link Ext#create}` may need to *synchronously*\r | |
98 | * load the desired class and its requirements. Doing this will generate a warning in\r | |
99 | * the console:\r | |
100 | * \r | |
101 | * [Ext.Loader] Synchronously loading 'Ext.window.Window'...\r | |
102 | *\r | |
103 | * If you see these in your debug console, you should add the indicated class(es) to the\r | |
104 | * appropriate `requires` array (as above) or make an `{@link Ext#require}` call.\r | |
105 | * \r | |
106 | * \r | |
107 | * **Note** Using `{@link Ext#create}` has some performance overhead and is best reserved\r | |
108 | * for cases where the target class is not known until run-time.\r | |
109 | * \r | |
110 | * @class Ext.Loader\r | |
111 | * @singleton\r | |
112 | */\r | |
113 | Ext.Loader = (new function() { // jshint ignore:line\r | |
114 | // @define Ext.Loader\r | |
115 | // @require Ext.Base\r | |
116 | // @require Ext.Class\r | |
117 | // @require Ext.ClassManager\r | |
118 | // @require Ext.Function\r | |
119 | // @require Ext.Array\r | |
120 | // @require Ext.env.Ready\r | |
121 | \r | |
122 | var Loader = this,\r | |
123 | Manager = Ext.ClassManager, // this is an instance of Ext.Inventory\r | |
124 | Boot = Ext.Boot,\r | |
125 | Class = Ext.Class,\r | |
126 | Ready = Ext.env.Ready,\r | |
127 | alias = Ext.Function.alias,\r | |
128 | dependencyProperties = ['extend', 'mixins', 'requires'],\r | |
129 | isInHistory = {},\r | |
130 | history = [],\r | |
131 | readyListeners = [],\r | |
132 | usedClasses = [],\r | |
133 | _requiresMap = {},\r | |
134 | _missingQueue = {},\r | |
135 | _config = {\r | |
136 | /**\r | |
137 | * @cfg {Boolean} [enabled=true]\r | |
138 | * Whether or not to enable the dynamic dependency loading feature.\r | |
139 | */\r | |
140 | enabled: true,\r | |
141 | \r | |
142 | /**\r | |
143 | * @cfg {Boolean} [scriptChainDelay=false]\r | |
144 | * millisecond delay between asynchronous script injection (prevents stack\r | |
145 | * overflow on some user agents) 'false' disables delay but potentially\r | |
146 | * increases stack load.\r | |
147 | */\r | |
148 | scriptChainDelay: false,\r | |
149 | \r | |
150 | /**\r | |
151 | * @cfg {Boolean} [disableCaching=true]\r | |
152 | * Appends current timestamp to script files to prevent caching.\r | |
153 | */\r | |
154 | disableCaching: true,\r | |
155 | \r | |
156 | /**\r | |
157 | * @cfg {String} [disableCachingParam="_dc"]\r | |
158 | * The get parameter name for the cache buster's timestamp.\r | |
159 | */\r | |
160 | disableCachingParam: '_dc',\r | |
161 | \r | |
162 | /**\r | |
163 | * @cfg {Object} paths\r | |
164 | * The mapping from namespaces to file paths\r | |
165 | *\r | |
166 | * {\r | |
167 | * 'Ext': '.', // This is set by default, Ext.layout.container.Container will be\r | |
168 | * // loaded from ./layout/Container.js\r | |
169 | *\r | |
170 | * 'My': './src/my_own_folder' // My.layout.Container will be loaded from\r | |
171 | * // ./src/my_own_folder/layout/Container.js\r | |
172 | * }\r | |
173 | *\r | |
174 | * Note that all relative paths are relative to the current HTML document.\r | |
175 | * If not being specified, for example, `Other.awesome.Class` will simply be\r | |
176 | * loaded from `"./Other/awesome/Class.js"`.\r | |
177 | */\r | |
178 | paths: Manager.paths,\r | |
179 | \r | |
180 | /**\r | |
181 | * @cfg {Boolean} preserveScripts\r | |
182 | * `false` to remove asynchronously loaded scripts, `true` to retain script\r | |
183 | * element for browser debugger compatibility and improved load performance.\r | |
184 | */\r | |
185 | preserveScripts: true,\r | |
186 | \r | |
187 | /**\r | |
188 | * @cfg {String} scriptCharset\r | |
189 | * Optional charset to specify encoding of dynamic script content.\r | |
190 | */\r | |
191 | scriptCharset: undefined\r | |
192 | },\r | |
193 | // These configs are delegated to Ext.Script and may need different names:\r | |
194 | delegatedConfigs = {\r | |
195 | disableCaching: true,\r | |
196 | disableCachingParam: true,\r | |
197 | preserveScripts: true,\r | |
198 | scriptChainDelay: 'loadDelay'\r | |
199 | };\r | |
200 | \r | |
201 | Ext.apply(Loader, {\r | |
202 | /**\r | |
203 | * @private\r | |
204 | */\r | |
205 | isInHistory: isInHistory,\r | |
206 | \r | |
207 | /**\r | |
208 | * Flag indicating whether there are still files being loaded\r | |
209 | * @private\r | |
210 | */\r | |
211 | isLoading: false,\r | |
212 | \r | |
213 | /**\r | |
214 | * An array of class names to keep track of the dependency loading order.\r | |
215 | * This is not guaranteed to be the same everytime due to the asynchronous\r | |
216 | * nature of the Loader.\r | |
217 | *\r | |
218 | * @property {Array} history\r | |
219 | */\r | |
220 | history: history,\r | |
221 | \r | |
222 | /**\r | |
223 | * Configuration\r | |
224 | * @private\r | |
225 | */\r | |
226 | config: _config,\r | |
227 | \r | |
228 | /**\r | |
229 | * Maintain the list of listeners to execute when all required scripts are fully loaded\r | |
230 | * @private\r | |
231 | */\r | |
232 | readyListeners: readyListeners,\r | |
233 | \r | |
234 | /**\r | |
235 | * Contains classes referenced in `uses` properties.\r | |
236 | * @private\r | |
237 | */\r | |
238 | optionalRequires: usedClasses,\r | |
239 | \r | |
240 | /**\r | |
241 | * Map of fully qualified class names to an array of dependent classes.\r | |
242 | * @private\r | |
243 | */\r | |
244 | requiresMap: _requiresMap,\r | |
245 | \r | |
246 | /** @private */\r | |
247 | hasFileLoadError: false,\r | |
248 | \r | |
249 | /**\r | |
250 | * The number of scripts loading via loadScript.\r | |
251 | * @private\r | |
252 | */\r | |
253 | scriptsLoading: 0,\r | |
254 | \r | |
255 | //<debug>\r | |
256 | /**\r | |
257 | * @private\r | |
258 | */\r | |
259 | classesLoading: [],\r | |
260 | //</debug>\r | |
261 | \r | |
262 | /**\r | |
263 | * @private\r | |
264 | */\r | |
265 | syncModeEnabled: false,\r | |
266 | \r | |
267 | \r | |
268 | /**\r | |
269 | * @private\r | |
270 | */\r | |
271 | missingQueue: _missingQueue,\r | |
272 | \r | |
273 | init: function () {\r | |
274 | // initalize the default path of the framework\r | |
275 | var scripts = document.getElementsByTagName('script'),\r | |
276 | src = scripts[scripts.length - 1].src,\r | |
277 | path = src.substring(0, src.lastIndexOf('/') + 1),\r | |
278 | meta = Ext._classPathMetadata,\r | |
279 | microloader = Ext.Microloader,\r | |
280 | manifest = Ext.manifest,\r | |
281 | loadOrder, baseUrl, loadlen, l, loadItem;\r | |
282 | \r | |
283 | //<debug>\r | |
284 | if (src.indexOf("packages/core/src/") !== -1) {\r | |
285 | path = path + "../../";\r | |
286 | } else if (src.indexOf("/core/src/class/") !== -1) {\r | |
287 | path = path + "../../../";\r | |
288 | }\r | |
289 | //</debug>\r | |
290 | \r | |
291 | \r | |
292 | if(!Manager.getPath("Ext")) {\r | |
293 | Manager.setPath('Ext', path + 'src');\r | |
294 | }\r | |
295 | \r | |
296 | // Pull in Cmd generated metadata if available.\r | |
297 | if (meta) {\r | |
298 | Ext._classPathMetadata = null;\r | |
299 | Loader.addClassPathMappings(meta);\r | |
300 | }\r | |
301 | \r | |
302 | if(manifest) {\r | |
303 | loadOrder = manifest.loadOrder;\r | |
304 | // if the manifest paths were calculated as relative to the \r | |
305 | // bootstrap file, then we need to prepend Boot.baseUrl to the\r | |
306 | // paths before processing\r | |
307 | baseUrl = Ext.Boot.baseUrl;\r | |
308 | if(loadOrder && manifest.bootRelative) {\r | |
309 | for(loadlen = loadOrder.length, l = 0; l < loadlen; l++) {\r | |
310 | loadItem = loadOrder[l];\r | |
311 | loadItem.path = baseUrl + loadItem.path;\r | |
312 | } \r | |
313 | }\r | |
314 | }\r | |
315 | \r | |
316 | if(microloader) {\r | |
317 | Ready.block();\r | |
318 | microloader.onMicroloaderReady(function(){\r | |
319 | Ready.unblock();\r | |
320 | });\r | |
321 | }\r | |
322 | },\r | |
323 | \r | |
324 | /**\r | |
325 | * Set the configuration for the loader. This should be called right after ext-(debug).js\r | |
326 | * is included in the page, and before Ext.onReady. i.e:\r | |
327 | *\r | |
328 | * <script type="text/javascript" src="ext-core-debug.js"></script>\r | |
329 | * <script type="text/javascript">\r | |
330 | * Ext.Loader.setConfig({\r | |
331 | * enabled: true,\r | |
332 | * paths: {\r | |
333 | * 'My': 'my_own_path'\r | |
334 | * }\r | |
335 | * });\r | |
336 | * </script>\r | |
337 | * <script type="text/javascript">\r | |
338 | * Ext.require(...);\r | |
339 | *\r | |
340 | * Ext.onReady(function() {\r | |
341 | * // application code here\r | |
342 | * });\r | |
343 | * </script>\r | |
344 | *\r | |
345 | * Refer to config options of {@link Ext.Loader} for the list of possible properties\r | |
346 | *\r | |
347 | * @param {Object} config The config object to override the default values\r | |
348 | * @return {Ext.Loader} this\r | |
349 | */\r | |
350 | setConfig: Ext.Function.flexSetter(function (name, value) {\r | |
351 | if (name === 'paths') {\r | |
352 | Loader.setPath(value);\r | |
353 | } else {\r | |
354 | _config[name] = value;\r | |
355 | \r | |
356 | var delegated = delegatedConfigs[name];\r | |
357 | if (delegated) {\r | |
358 | Boot.setConfig((delegated === true) ? name : delegated, value);\r | |
359 | }\r | |
360 | }\r | |
361 | \r | |
362 | return Loader;\r | |
363 | }),\r | |
364 | \r | |
365 | /**\r | |
366 | * Get the config value corresponding to the specified name. If no name is given, will return the config object\r | |
367 | * @param {String} name The config property name\r | |
368 | * @return {Object}\r | |
369 | */\r | |
370 | getConfig: function(name) {\r | |
371 | return name ? _config[name] : _config;\r | |
372 | },\r | |
373 | \r | |
374 | /**\r | |
375 | * Sets the path of a namespace.\r | |
376 | * For Example:\r | |
377 | *\r | |
378 | * Ext.Loader.setPath('Ext', '.');\r | |
379 | *\r | |
380 | * @param {String/Object} name See {@link Ext.Function#flexSetter flexSetter}\r | |
381 | * @param {String} [path] See {@link Ext.Function#flexSetter flexSetter}\r | |
382 | * @return {Ext.Loader} this\r | |
383 | * @method\r | |
384 | */\r | |
385 | setPath: function () {\r | |
386 | // Paths are an Ext.Inventory thing and ClassManager is an instance of that:\r | |
387 | Manager.setPath.apply(Manager, arguments);\r | |
388 | return Loader;\r | |
389 | },\r | |
390 | \r | |
391 | /**\r | |
392 | * Sets a batch of path entries\r | |
393 | *\r | |
394 | * @param {Object } paths a set of className: path mappings\r | |
395 | * @return {Ext.Loader} this\r | |
396 | */\r | |
397 | addClassPathMappings: function(paths) {\r | |
398 | // Paths are an Ext.Inventory thing and ClassManager is an instance of that:\r | |
399 | Manager.setPath(paths);\r | |
400 | return Loader;\r | |
401 | },\r | |
402 | \r | |
403 | /**\r | |
404 | * fixes up loader path configs by prepending Ext.Boot#baseUrl to the beginning\r | |
405 | * of the path, then delegates to Ext.Loader#addClassPathMappings\r | |
406 | * @param pathConfig\r | |
407 | */\r | |
408 | \r | |
409 | addBaseUrlClassPathMappings: function(pathConfig) {\r | |
410 | for(var name in pathConfig) {\r | |
411 | pathConfig[name] = Boot.baseUrl + pathConfig[name];\r | |
412 | }\r | |
413 | Ext.Loader.addClassPathMappings(pathConfig);\r | |
414 | },\r | |
415 | \r | |
416 | \r | |
417 | /**\r | |
418 | * Translates a className to a file path by adding the\r | |
419 | * the proper prefix and converting the .'s to /'s. For example:\r | |
420 | *\r | |
421 | * Ext.Loader.setPath('My', '/path/to/My');\r | |
422 | *\r | |
423 | * alert(Ext.Loader.getPath('My.awesome.Class')); // alerts '/path/to/My/awesome/Class.js'\r | |
424 | *\r | |
425 | * Note that the deeper namespace levels, if explicitly set, are always resolved first. For example:\r | |
426 | *\r | |
427 | * Ext.Loader.setPath({\r | |
428 | * 'My': '/path/to/lib',\r | |
429 | * 'My.awesome': '/other/path/for/awesome/stuff',\r | |
430 | * 'My.awesome.more': '/more/awesome/path'\r | |
431 | * });\r | |
432 | *\r | |
433 | * alert(Ext.Loader.getPath('My.awesome.Class')); // alerts '/other/path/for/awesome/stuff/Class.js'\r | |
434 | *\r | |
435 | * alert(Ext.Loader.getPath('My.awesome.more.Class')); // alerts '/more/awesome/path/Class.js'\r | |
436 | *\r | |
437 | * alert(Ext.Loader.getPath('My.cool.Class')); // alerts '/path/to/lib/cool/Class.js'\r | |
438 | *\r | |
439 | * alert(Ext.Loader.getPath('Unknown.strange.Stuff')); // alerts 'Unknown/strange/Stuff.js'\r | |
440 | *\r | |
441 | * @param {String} className\r | |
442 | * @return {String} path\r | |
443 | */\r | |
444 | getPath: function(className) {\r | |
445 | // Paths are an Ext.Inventory thing and ClassManager is an instance of that:\r | |
446 | return Manager.getPath(className);\r | |
447 | },\r | |
448 | \r | |
449 | require: function (expressions, fn, scope, excludes) {\r | |
450 | if (excludes) {\r | |
451 | return Loader.exclude(excludes).require(expressions, fn, scope);\r | |
452 | }\r | |
453 | \r | |
454 | var classNames = Manager.getNamesByExpression(expressions);\r | |
455 | \r | |
456 | return Loader.load(classNames, fn, scope);\r | |
457 | },\r | |
458 | \r | |
459 | syncRequire: function () {\r | |
460 | var wasEnabled = Loader.syncModeEnabled;\r | |
461 | \r | |
462 | Loader.syncModeEnabled = true;\r | |
463 | \r | |
464 | var ret = Loader.require.apply(Loader, arguments);\r | |
465 | \r | |
466 | Loader.syncModeEnabled = wasEnabled;\r | |
467 | \r | |
468 | return ret;\r | |
469 | },\r | |
470 | \r | |
471 | exclude: function (excludes) {\r | |
472 | var selector = Manager.select({\r | |
473 | require: function (classNames, fn, scope) {\r | |
474 | return Loader.load(classNames, fn, scope);\r | |
475 | },\r | |
476 | \r | |
477 | syncRequire: function (classNames, fn, scope) {\r | |
478 | var wasEnabled = Loader.syncModeEnabled;\r | |
479 | \r | |
480 | Loader.syncModeEnabled = true;\r | |
481 | \r | |
482 | var ret = Loader.load(classNames, fn, scope);\r | |
483 | \r | |
484 | Loader.syncModeEnabled = wasEnabled;\r | |
485 | \r | |
486 | return ret;\r | |
487 | }\r | |
488 | });\r | |
489 | \r | |
490 | selector.exclude(excludes);\r | |
491 | return selector;\r | |
492 | },\r | |
493 | \r | |
494 | load: function (classNames, callback, scope) {\r | |
495 | if (callback) {\r | |
496 | if (callback.length) {\r | |
497 | // If callback expects arguments, shim it with a function that will map\r | |
498 | // the requires class(es) from the names we are given.\r | |
499 | callback = Loader.makeLoadCallback(classNames, callback);\r | |
500 | }\r | |
501 | callback = callback.bind(scope || Ext.global);\r | |
502 | }\r | |
503 | \r | |
504 | var missingClassNames = [],\r | |
505 | numClasses = classNames.length,\r | |
506 | className, i, numMissing, urls = [],\r | |
507 | state = Manager.classState;\r | |
508 | \r | |
509 | for (i = 0; i < numClasses; ++i) {\r | |
510 | className = Manager.resolveName(classNames[i]);\r | |
511 | if (!Manager.isCreated(className)) {\r | |
512 | missingClassNames.push(className);\r | |
513 | _missingQueue[className] = Loader.getPath(className);\r | |
514 | if(!state[className]) {\r | |
515 | urls.push(_missingQueue[className]);\r | |
516 | }\r | |
517 | }\r | |
518 | }\r | |
519 | \r | |
520 | // If the dynamic dependency feature is not being used, throw an error\r | |
521 | // if the dependencies are not defined\r | |
522 | numMissing = missingClassNames.length;\r | |
523 | if (numMissing) {\r | |
524 | Loader.missingCount += numMissing;\r | |
525 | //<debug>\r | |
526 | Ext.Array.push(Loader.classesLoading, missingClassNames);\r | |
527 | //</debug>\r | |
528 | \r | |
529 | Manager.onCreated(function () {\r | |
530 | //<debug>\r | |
531 | Ext.Array.remove(Loader.classesLoading, missingClassNames);\r | |
532 | Ext.each(missingClassNames, function(name){\r | |
533 | Ext.Array.remove(Loader.classesLoading, name);\r | |
534 | });\r | |
535 | //</debug>\r | |
536 | if (callback) {\r | |
537 | Ext.callback(callback, scope, arguments);\r | |
538 | }\r | |
539 | Loader.checkReady();\r | |
540 | }, Loader, missingClassNames);\r | |
541 | \r | |
542 | if (!_config.enabled) {\r | |
543 | Ext.raise("Ext.Loader is not enabled, so dependencies cannot be resolved dynamically. " +\r | |
544 | "Missing required class" + ((missingClassNames.length > 1) ? "es" : "") + \r | |
545 | ": " + missingClassNames.join(', '));\r | |
546 | }\r | |
547 | \r | |
548 | if(urls.length) {\r | |
549 | Loader.loadScripts({\r | |
550 | url: urls,\r | |
551 | // scope: this options object so we can pass these along:\r | |
552 | _classNames: missingClassNames\r | |
553 | });\r | |
554 | } else {\r | |
555 | // need to call checkReady here, as the _missingCoun\r | |
556 | // may have transitioned from 0 to > 0, meaning we\r | |
557 | // need to block ready\r | |
558 | Loader.checkReady();\r | |
559 | }\r | |
560 | } else {\r | |
561 | if (callback) {\r | |
562 | callback.call(scope);\r | |
563 | }\r | |
564 | // need to call checkReady here, as the _missingCoun\r | |
565 | // may have transitioned from 0 to > 0, meaning we\r | |
566 | // need to block ready\r | |
567 | Loader.checkReady();\r | |
568 | }\r | |
569 | \r | |
570 | if (Loader.syncModeEnabled) {\r | |
571 | // Class may have been just loaded or was already loaded\r | |
572 | if (numClasses === 1) {\r | |
573 | return Manager.get(classNames[0]);\r | |
574 | }\r | |
575 | }\r | |
576 | \r | |
577 | return Loader;\r | |
578 | },\r | |
579 | \r | |
580 | makeLoadCallback: function (classNames, callback) {\r | |
581 | return function () {\r | |
582 | var classes = [],\r | |
583 | i = classNames.length;\r | |
584 | \r | |
585 | while (i-- > 0) {\r | |
586 | classes[i] = Manager.get(classNames[i]);\r | |
587 | }\r | |
588 | \r | |
589 | return callback.apply(this, classes);\r | |
590 | };\r | |
591 | },\r | |
592 | \r | |
593 | onLoadFailure: function () {\r | |
594 | var options = this,\r | |
595 | onError = options.onError;\r | |
596 | \r | |
597 | Loader.hasFileLoadError = true;\r | |
598 | --Loader.scriptsLoading;\r | |
599 | \r | |
600 | if (onError) {\r | |
601 | //TODO: need an adapter to convert to v4 onError signatures\r | |
602 | onError.call(options.userScope, options);\r | |
603 | }\r | |
604 | //<debug>\r | |
605 | else {\r | |
606 | Ext.log.error("[Ext.Loader] Some requested files failed to load.");\r | |
607 | }\r | |
608 | //</debug>\r | |
609 | \r | |
610 | Loader.checkReady();\r | |
611 | },\r | |
612 | \r | |
613 | onLoadSuccess: function () {\r | |
614 | var options = this,\r | |
615 | onLoad = options.onLoad;\r | |
616 | \r | |
617 | --Loader.scriptsLoading;\r | |
618 | if (onLoad) {\r | |
619 | //TODO: need an adapter to convert to v4 onLoad signatures\r | |
620 | onLoad.call(options.userScope, options);\r | |
621 | // onLoad can cause more loads to start, so it must run first\r | |
622 | }\r | |
623 | \r | |
624 | Loader.checkReady();\r | |
625 | },\r | |
626 | \r | |
627 | // TODO: this timing of this needs to be deferred until all classes have had a chance to be created\r | |
628 | //<debug>\r | |
629 | reportMissingClasses: function () {\r | |
630 | if (!Loader.syncModeEnabled && !Loader.scriptsLoading && Loader.isLoading &&\r | |
631 | !Loader.hasFileLoadError) {\r | |
632 | var missingClasses = [],\r | |
633 | missingPaths = [];\r | |
634 | \r | |
635 | for (var missingClassName in _missingQueue) {\r | |
636 | missingClasses.push(missingClassName);\r | |
637 | missingPaths.push(_missingQueue[missingClassName]);\r | |
638 | }\r | |
639 | \r | |
640 | if (missingClasses.length) {\r | |
641 | throw new Error("The following classes are not declared even if their files have been " +\r | |
642 | "loaded: '" + missingClasses.join("', '") + "'. Please check the source code of their " +\r | |
643 | "corresponding files for possible typos: '" + missingPaths.join("', '"));\r | |
644 | }\r | |
645 | }\r | |
646 | },\r | |
647 | //</debug>\r | |
648 | \r | |
649 | /**\r | |
650 | * Add a new listener to be executed when all required scripts are fully loaded\r | |
651 | *\r | |
652 | * @param {Function} fn The function callback to be executed\r | |
653 | * @param {Object} scope The execution scope (`this`) of the callback function.\r | |
654 | * @param {Boolean} [withDomReady=true] Pass `false` to not also wait for document\r | |
655 | * dom ready.\r | |
656 | * @param {Object} [options] Additional callback options.\r | |
657 | * @param {Number} [options.delay=0] A number of milliseconds to delay.\r | |
658 | * @param {Number} [options.priority=0] Relative priority of this callback. Negative\r | |
659 | * numbers are reserved.\r | |
660 | */\r | |
661 | onReady: function(fn, scope, withDomReady, options) {\r | |
662 | if (withDomReady) {\r | |
663 | Ready.on(fn, scope, options);\r | |
664 | } else {\r | |
665 | var listener = Ready.makeListener(fn, scope, options);\r | |
666 | \r | |
667 | if (Loader.isLoading) {\r | |
668 | readyListeners.push(listener);\r | |
669 | } else {\r | |
670 | Ready.invoke(listener);\r | |
671 | }\r | |
672 | }\r | |
673 | },\r | |
674 | \r | |
675 | /**\r | |
676 | * @private\r | |
677 | * Ensure that any classes referenced in the `uses` property are loaded.\r | |
678 | */\r | |
679 | addUsedClasses: function (classes) {\r | |
680 | var cls, i, ln;\r | |
681 | \r | |
682 | if (classes) {\r | |
683 | classes = (typeof classes === 'string') ? [classes] : classes;\r | |
684 | for (i = 0, ln = classes.length; i < ln; i++) {\r | |
685 | cls = classes[i];\r | |
686 | if (typeof cls === 'string' && !Ext.Array.contains(usedClasses, cls)) {\r | |
687 | usedClasses.push(cls);\r | |
688 | }\r | |
689 | }\r | |
690 | }\r | |
691 | \r | |
692 | return Loader;\r | |
693 | },\r | |
694 | \r | |
695 | /**\r | |
696 | * @private\r | |
697 | */\r | |
698 | triggerReady: function() {\r | |
699 | var listener,\r | |
700 | refClasses = usedClasses;\r | |
701 | \r | |
702 | if (Loader.isLoading && refClasses.length) {\r | |
703 | // Empty the array to eliminate potential recursive loop issue\r | |
704 | usedClasses = [];\r | |
705 | \r | |
706 | // this may immediately call us back if all 'uses' classes\r | |
707 | // have been loaded\r | |
708 | Loader.require(refClasses);\r | |
709 | } else {\r | |
710 | // Must clear this before calling callbacks. This will cause any new loads\r | |
711 | // to call Ready.block() again. See below for more on this.\r | |
712 | Loader.isLoading = false;\r | |
713 | \r | |
714 | // These listeners are just those attached directly to Loader to wait for\r | |
715 | // class loading only.\r | |
716 | readyListeners.sort(Ready.sortFn);\r | |
717 | \r | |
718 | // this method can be called with Loader.isLoading either true or false\r | |
719 | // (can be called with false when all 'uses' classes are already loaded)\r | |
720 | // this may bypass the above if condition\r | |
721 | while (readyListeners.length && !Loader.isLoading) {\r | |
722 | // we may re-enter triggerReady so we cannot necessarily iterate the\r | |
723 | // readyListeners array\r | |
724 | listener = readyListeners.pop();\r | |
725 | Ready.invoke(listener);\r | |
726 | }\r | |
727 | \r | |
728 | // If the DOM is also ready, this will fire the normal onReady listeners.\r | |
729 | // An astute observer would note that we may now be back to isLoading and\r | |
730 | // so ask "Why you call unblock?". The reason is that we must match the\r | |
731 | // calls to block and since we transitioned from isLoading to !isLoading\r | |
732 | // here we must call unblock. If we have transitioned back to isLoading in\r | |
733 | // the above loop it will have called block again so the counter will be\r | |
734 | // increased and this call will not reduce the block count to 0. This is\r | |
735 | // done by loadScripts.\r | |
736 | Ready.unblock();\r | |
737 | }\r | |
738 | },\r | |
739 | \r | |
740 | /**\r | |
741 | * @private\r | |
742 | * @param {String} className\r | |
743 | */\r | |
744 | historyPush: function(className) {\r | |
745 | if (className && !isInHistory[className] && !Manager.overrideMap[className]) {\r | |
746 | isInHistory[className] = true;\r | |
747 | history.push(className);\r | |
748 | }\r | |
749 | return Loader;\r | |
750 | },\r | |
751 | \r | |
752 | /**\r | |
753 | * This is an internal method that delegate content loading to the \r | |
754 | * bootstrap layer.\r | |
755 | * @private\r | |
756 | * @param params\r | |
757 | */\r | |
758 | loadScripts: function(params) {\r | |
759 | var manifest = Ext.manifest,\r | |
760 | loadOrder = manifest && manifest.loadOrder,\r | |
761 | loadOrderMap = manifest && manifest.loadOrderMap,\r | |
762 | options;\r | |
763 | \r | |
764 | ++Loader.scriptsLoading;\r | |
765 | \r | |
766 | // if the load order map hasn't been created, create it now \r | |
767 | // and cache on the manifest\r | |
768 | if (loadOrder && !loadOrderMap) {\r | |
769 | manifest.loadOrderMap = loadOrderMap = Boot.createLoadOrderMap(loadOrder);\r | |
770 | }\r | |
771 | \r | |
772 | // verify the loading state, as this may have transitioned us from\r | |
773 | // not loading to loading\r | |
774 | Loader.checkReady();\r | |
775 | \r | |
776 | options = Ext.apply({\r | |
777 | loadOrder: loadOrder,\r | |
778 | loadOrderMap: loadOrderMap,\r | |
779 | charset: _config.scriptCharset,\r | |
780 | success: Loader.onLoadSuccess,\r | |
781 | failure: Loader.onLoadFailure,\r | |
782 | sync: Loader.syncModeEnabled,\r | |
783 | _classNames: []\r | |
784 | }, params);\r | |
785 | \r | |
786 | options.userScope = options.scope;\r | |
787 | options.scope = options;\r | |
788 | \r | |
789 | Boot.load(options);\r | |
790 | },\r | |
791 | \r | |
792 | /**\r | |
793 | * This method is provide for use by the bootstrap layer.\r | |
794 | * @private\r | |
795 | * @param {String[]} urls\r | |
796 | */\r | |
797 | loadScriptsSync: function(urls) {\r | |
798 | var syncwas = Loader.syncModeEnabled;\r | |
799 | Loader.syncModeEnabled = true;\r | |
800 | Loader.loadScripts({url: urls});\r | |
801 | Loader.syncModeEnabled = syncwas;\r | |
802 | },\r | |
803 | \r | |
804 | /**\r | |
805 | * This method is provide for use by the bootstrap layer.\r | |
806 | * @private\r | |
807 | * @param {String[]} urls\r | |
808 | */\r | |
809 | loadScriptsSyncBasePrefix: function(urls) {\r | |
810 | var syncwas = Loader.syncModeEnabled;\r | |
811 | Loader.syncModeEnabled = true;\r | |
812 | Loader.loadScripts({url: urls, prependBaseUrl: true});\r | |
813 | Loader.syncModeEnabled = syncwas;\r | |
814 | },\r | |
815 | \r | |
816 | /**\r | |
817 | * Loads the specified script URL and calls the supplied callbacks. If this method\r | |
818 | * is called before {@link Ext#isReady}, the script's load will delay the transition\r | |
819 | * to ready. This can be used to load arbitrary scripts that may contain further\r | |
820 | * {@link Ext#require Ext.require} calls.\r | |
821 | *\r | |
822 | * @param {Object/String/String[]} options The options object or simply the URL(s) to load.\r | |
823 | * @param {String} options.url The URL from which to load the script.\r | |
824 | * @param {Function} [options.onLoad] The callback to call on successful load.\r | |
825 | * @param {Function} [options.onError] The callback to call on failure to load.\r | |
826 | * @param {Object} [options.scope] The scope (`this`) for the supplied callbacks.\r | |
827 | */\r | |
828 | loadScript: function(options) {\r | |
829 | var isString = typeof options === 'string',\r | |
830 | isArray = options instanceof Array,\r | |
831 | isObject = !isArray && !isString,\r | |
832 | url = isObject ? options.url : options,\r | |
833 | onError = isObject && options.onError,\r | |
834 | onLoad = isObject && options.onLoad,\r | |
835 | scope = isObject && options.scope,\r | |
836 | request = {\r | |
837 | url: url,\r | |
838 | scope: scope,\r | |
839 | onLoad: onLoad,\r | |
840 | onError: onError,\r | |
841 | _classNames: []\r | |
842 | };\r | |
843 | \r | |
844 | Loader.loadScripts(request);\r | |
845 | },\r | |
846 | \r | |
847 | /**\r | |
848 | * @private\r | |
849 | */\r | |
850 | flushMissingQueue: function() {\r | |
851 | var name, val, missingwas = 0, missing = 0;\r | |
852 | \r | |
853 | for(name in _missingQueue) {\r | |
854 | missingwas++;\r | |
855 | val = _missingQueue[name];\r | |
856 | if(Manager.isCreated(name)) {\r | |
857 | delete _missingQueue[name];\r | |
858 | } else if (Manager.existCache[name] === 2) {\r | |
859 | delete _missingQueue[name];\r | |
860 | } else {\r | |
861 | ++missing;\r | |
862 | }\r | |
863 | }\r | |
864 | this.missingCount = missing;\r | |
865 | },\r | |
866 | \r | |
867 | /**\r | |
868 | * @private\r | |
869 | */\r | |
870 | checkReady: function() {\r | |
871 | var wasLoading = Loader.isLoading,\r | |
872 | isLoading;\r | |
873 | \r | |
874 | Loader.flushMissingQueue();\r | |
875 | isLoading = Loader.missingCount + Loader.scriptsLoading;\r | |
876 | \r | |
877 | if (isLoading && !wasLoading) {\r | |
878 | Ready.block();\r | |
879 | Loader.isLoading = !!isLoading;\r | |
880 | } else if (!isLoading && wasLoading) {\r | |
881 | Loader.triggerReady();\r | |
882 | }\r | |
883 | \r | |
884 | //<debug>\r | |
885 | if (!Loader.scriptsLoading && Loader.missingCount) {\r | |
886 | // Things look bad, but since load requests may come later, defer this\r | |
887 | // for a bit then check if things are still stuck.\r | |
888 | Ext.defer(function () {\r | |
889 | if (!Loader.scriptsLoading && Loader.missingCount) {\r | |
890 | Ext.log.error('[Loader] The following classes failed to load:');\r | |
891 | for (var name in Loader.missingQueue) {\r | |
892 | Ext.log.error('[Loader] ' + name + ' from ' +\r | |
893 | Loader.missingQueue[name]);\r | |
894 | }\r | |
895 | }\r | |
896 | }, 1000);\r | |
897 | }\r | |
898 | //</debug>\r | |
899 | }\r | |
900 | });\r | |
901 | \r | |
902 | /**\r | |
903 | * Loads all classes by the given names and all their direct dependencies; optionally\r | |
904 | * executes the given callback function when finishes, within the optional scope.\r | |
905 | *\r | |
906 | * @param {String/String[]} expressions The class, classes or wildcards to load.\r | |
907 | * @param {Function} [fn] The callback function.\r | |
908 | * @param {Object} [scope] The execution scope (`this`) of the callback function.\r | |
909 | * @member Ext\r | |
910 | * @method require\r | |
911 | */\r | |
912 | Ext.require = alias(Loader, 'require');\r | |
913 | \r | |
914 | /**\r | |
915 | * Synchronously loads all classes by the given names and all their direct dependencies; optionally\r | |
916 | * executes the given callback function when finishes, within the optional scope.\r | |
917 | *\r | |
918 | * @param {String/String[]} expressions The class, classes or wildcards to load.\r | |
919 | * @param {Function} [fn] The callback function.\r | |
920 | * @param {Object} [scope] The execution scope (`this`) of the callback function.\r | |
921 | * @member Ext\r | |
922 | * @method syncRequire\r | |
923 | */\r | |
924 | Ext.syncRequire = alias(Loader, 'syncRequire');\r | |
925 | \r | |
926 | /**\r | |
927 | * Explicitly exclude files from being loaded. Useful when used in conjunction with a\r | |
928 | * broad include expression. Can be chained with more `require` and `exclude` methods,\r | |
929 | * for example:\r | |
930 | *\r | |
931 | * Ext.exclude('Ext.data.*').require('*');\r | |
932 | *\r | |
933 | * Ext.exclude('widget.button*').require('widget.*');\r | |
934 | *\r | |
935 | * @param {String/String[]} excludes\r | |
936 | * @return {Object} Contains `exclude`, `require` and `syncRequire` methods for chaining.\r | |
937 | * @member Ext\r | |
938 | * @method exclude\r | |
939 | */\r | |
940 | Ext.exclude = alias(Loader, 'exclude');\r | |
941 | \r | |
942 | //<feature classSystem.loader>\r | |
943 | /**\r | |
944 | * @cfg {String[]} requires\r | |
945 | * @member Ext.Class\r | |
946 | * List of classes that have to be loaded before instantiating this class.\r | |
947 | * For example:\r | |
948 | *\r | |
949 | * Ext.define('Mother', {\r | |
950 | * requires: ['Child'],\r | |
951 | * giveBirth: function() {\r | |
952 | * // we can be sure that child class is available.\r | |
953 | * return new Child();\r | |
954 | * }\r | |
955 | * });\r | |
956 | */\r | |
957 | Class.registerPreprocessor('loader', function(cls, data, hooks, continueFn) {\r | |
958 | //<debug>\r | |
959 | Ext.classSystemMonitor && Ext.classSystemMonitor(cls, 'Ext.Loader#loaderPreprocessor', arguments); // jshint ignore:line\r | |
960 | //</debug>\r | |
961 | \r | |
962 | var me = this,\r | |
963 | dependencies = [],\r | |
964 | dependency,\r | |
965 | className = Manager.getName(cls),\r | |
966 | i, j, ln, subLn, value, propertyName, propertyValue,\r | |
967 | requiredMap;\r | |
968 | \r | |
969 | /*\r | |
970 | Loop through the dependencyProperties, look for string class names and push\r | |
971 | them into a stack, regardless of whether the property's value is a string, array or object. For example:\r | |
972 | {\r | |
973 | extend: 'Ext.MyClass',\r | |
974 | requires: ['Ext.some.OtherClass'],\r | |
975 | mixins: {\r | |
976 | thing: 'Foo.bar.Thing';\r | |
977 | }\r | |
978 | }\r | |
979 | which will later be transformed into:\r | |
980 | {\r | |
981 | extend: Ext.MyClass,\r | |
982 | requires: [Ext.some.OtherClass],\r | |
983 | mixins: {\r | |
984 | thing: Foo.bar.Thing;\r | |
985 | }\r | |
986 | }\r | |
987 | */\r | |
988 | \r | |
989 | for (i = 0,ln = dependencyProperties.length; i < ln; i++) {\r | |
990 | propertyName = dependencyProperties[i];\r | |
991 | \r | |
992 | if (data.hasOwnProperty(propertyName)) {\r | |
993 | propertyValue = data[propertyName];\r | |
994 | \r | |
995 | if (typeof propertyValue === 'string') {\r | |
996 | dependencies.push(propertyValue);\r | |
997 | }\r | |
998 | else if (propertyValue instanceof Array) {\r | |
999 | for (j = 0, subLn = propertyValue.length; j < subLn; j++) {\r | |
1000 | value = propertyValue[j];\r | |
1001 | \r | |
1002 | if (typeof value === 'string') {\r | |
1003 | dependencies.push(value);\r | |
1004 | }\r | |
1005 | }\r | |
1006 | }\r | |
1007 | else if (typeof propertyValue !== 'function') {\r | |
1008 | for (j in propertyValue) {\r | |
1009 | if (propertyValue.hasOwnProperty(j)) {\r | |
1010 | value = propertyValue[j];\r | |
1011 | \r | |
1012 | if (typeof value === 'string') {\r | |
1013 | dependencies.push(value);\r | |
1014 | }\r | |
1015 | }\r | |
1016 | }\r | |
1017 | }\r | |
1018 | }\r | |
1019 | }\r | |
1020 | \r | |
1021 | if (dependencies.length === 0) {\r | |
1022 | return;\r | |
1023 | }\r | |
1024 | if (className) {\r | |
1025 | _requiresMap[className] = dependencies;\r | |
1026 | }\r | |
1027 | \r | |
1028 | //<debug>\r | |
1029 | var deadlockPath = [],\r | |
1030 | detectDeadlock;\r | |
1031 | \r | |
1032 | /*\r | |
1033 | Automatically detect deadlocks before-hand,\r | |
1034 | will throw an error with detailed path for ease of debugging. Examples of deadlock cases:\r | |
1035 | \r | |
1036 | - A extends B, then B extends A\r | |
1037 | - A requires B, B requires C, then C requires A\r | |
1038 | \r | |
1039 | The detectDeadlock function will recursively transverse till the leaf, hence it can detect deadlocks\r | |
1040 | no matter how deep the path is.\r | |
1041 | */\r | |
1042 | \r | |
1043 | if (className) {\r | |
1044 | requiredMap = Loader.requiredByMap || (Loader.requiredByMap = {});\r | |
1045 | \r | |
1046 | for (i = 0,ln = dependencies.length; i < ln; i++) {\r | |
1047 | dependency = dependencies[i];\r | |
1048 | (requiredMap[dependency] || (requiredMap[dependency] = [])).push(className);\r | |
1049 | }\r | |
1050 | \r | |
1051 | detectDeadlock = function(cls) {\r | |
1052 | deadlockPath.push(cls);\r | |
1053 | \r | |
1054 | if (_requiresMap[cls]) {\r | |
1055 | if (Ext.Array.contains(_requiresMap[cls], className)) {\r | |
1056 | Ext.raise("Circular requirement detected! '" + className +\r | |
1057 | "' and '" + deadlockPath[1] + "' mutually require each other. Path: " +\r | |
1058 | deadlockPath.join(' -> ') + " -> " + deadlockPath[0]);\r | |
1059 | }\r | |
1060 | \r | |
1061 | for (i = 0,ln = _requiresMap[cls].length; i < ln; i++) {\r | |
1062 | detectDeadlock(_requiresMap[cls][i]);\r | |
1063 | }\r | |
1064 | }\r | |
1065 | };\r | |
1066 | \r | |
1067 | detectDeadlock(className);\r | |
1068 | }\r | |
1069 | \r | |
1070 | //</debug>\r | |
1071 | \r | |
1072 | (className ? Loader.exclude(className) : Loader).require(dependencies, function() {\r | |
1073 | for (i = 0,ln = dependencyProperties.length; i < ln; i++) {\r | |
1074 | propertyName = dependencyProperties[i];\r | |
1075 | \r | |
1076 | if (data.hasOwnProperty(propertyName)) {\r | |
1077 | propertyValue = data[propertyName];\r | |
1078 | \r | |
1079 | if (typeof propertyValue === 'string') {\r | |
1080 | data[propertyName] = Manager.get(propertyValue);\r | |
1081 | }\r | |
1082 | else if (propertyValue instanceof Array) {\r | |
1083 | for (j = 0, subLn = propertyValue.length; j < subLn; j++) {\r | |
1084 | value = propertyValue[j];\r | |
1085 | \r | |
1086 | if (typeof value === 'string') {\r | |
1087 | data[propertyName][j] = Manager.get(value);\r | |
1088 | }\r | |
1089 | }\r | |
1090 | }\r | |
1091 | else if (typeof propertyValue !== 'function') {\r | |
1092 | for (var k in propertyValue) {\r | |
1093 | if (propertyValue.hasOwnProperty(k)) {\r | |
1094 | value = propertyValue[k];\r | |
1095 | \r | |
1096 | if (typeof value === 'string') {\r | |
1097 | data[propertyName][k] = Manager.get(value);\r | |
1098 | }\r | |
1099 | }\r | |
1100 | }\r | |
1101 | }\r | |
1102 | }\r | |
1103 | }\r | |
1104 | \r | |
1105 | continueFn.call(me, cls, data, hooks);\r | |
1106 | });\r | |
1107 | \r | |
1108 | return false;\r | |
1109 | }, true, 'after', 'className');\r | |
1110 | \r | |
1111 | /**\r | |
1112 | * @cfg {String[]} uses\r | |
1113 | * @member Ext.Class\r | |
1114 | * List of optional classes to load together with this class. These aren't neccessarily loaded before\r | |
1115 | * this class is created, but are guaranteed to be available before Ext.onReady listeners are\r | |
1116 | * invoked. For example:\r | |
1117 | *\r | |
1118 | * Ext.define('Mother', {\r | |
1119 | * uses: ['Child'],\r | |
1120 | * giveBirth: function() {\r | |
1121 | * // This code might, or might not work:\r | |
1122 | * // return new Child();\r | |
1123 | *\r | |
1124 | * // Instead use Ext.create() to load the class at the spot if not loaded already:\r | |
1125 | * return Ext.create('Child');\r | |
1126 | * }\r | |
1127 | * });\r | |
1128 | */\r | |
1129 | Manager.registerPostprocessor('uses', function(name, cls, data) {\r | |
1130 | //<debug>\r | |
1131 | Ext.classSystemMonitor && Ext.classSystemMonitor(cls, 'Ext.Loader#usesPostprocessor', arguments); // jshint ignore:line\r | |
1132 | //</debug>\r | |
1133 | \r | |
1134 | var manifest = Ext.manifest,\r | |
1135 | loadOrder = manifest && manifest.loadOrder,\r | |
1136 | classes = manifest && manifest.classes,\r | |
1137 | uses, clazz, item, len, i, indexMap;\r | |
1138 | \r | |
1139 | if (loadOrder) {\r | |
1140 | clazz = classes[name];\r | |
1141 | if (clazz && !isNaN(i = clazz.idx)) {\r | |
1142 | item = loadOrder[i];\r | |
1143 | uses = item.uses;\r | |
1144 | indexMap = {};\r | |
1145 | for (len = uses.length, i = 0; i < len; i++) {\r | |
1146 | indexMap[uses[i]] = true;\r | |
1147 | }\r | |
1148 | uses = Ext.Boot.getPathsFromIndexes(indexMap, loadOrder, true);\r | |
1149 | if (uses.length > 0) {\r | |
1150 | Loader.loadScripts({\r | |
1151 | url: uses,\r | |
1152 | sequential: true\r | |
1153 | });\r | |
1154 | }\r | |
1155 | }\r | |
1156 | }\r | |
1157 | \r | |
1158 | if (data.uses) {\r | |
1159 | uses = data.uses;\r | |
1160 | Loader.addUsedClasses(uses);\r | |
1161 | }\r | |
1162 | });\r | |
1163 | \r | |
1164 | Manager.onCreated(Loader.historyPush);\r | |
1165 | //</feature>\r | |
1166 | \r | |
1167 | Loader.init();\r | |
1168 | \r | |
1169 | }());\r | |
1170 | \r | |
1171 | //-----------------------------------------------------------------------------\r | |
1172 | \r | |
1173 | // Use performance.now when available to keep timestamps consistent.\r | |
1174 | Ext._endTime = Ext.ticks();\r | |
1175 | \r | |
1176 | // This hook is to allow tools like DynaTrace to deterministically detect the availability\r | |
1177 | // of Ext.onReady. Since Loader takes over Ext.onReady this must be done here and not in\r | |
1178 | // Ext.env.Ready.\r | |
1179 | if (Ext._beforereadyhandler){\r | |
1180 | Ext._beforereadyhandler();\r | |
1181 | }\r |