]>
Commit | Line | Data |
---|---|---|
f0cfe83e AD |
1 | define("dojo/_base/loader", ["./kernel", "../has", "require", "module", "./json", "./lang", "./array"], function(dojo, has, require, thisModule, json, lang, array) { |
2 | // module: | |
3 | // dojo/_base/loader | |
4 | ||
5 | // This module defines the v1.x synchronous loader API. | |
6 | ||
7 | // signal the loader in sync mode... | |
8 | //>>pure-amd | |
9 | ||
10 | if (! 1 ){ | |
11 | console.error("cannot load the Dojo v1.x loader with a foreign loader"); | |
12 | return 0; | |
13 | } | |
14 | ||
15 | 1 || has.add("dojo-fast-sync-require", 1); | |
16 | ||
17 | ||
18 | var makeErrorToken = function(id){ | |
19 | return {src:thisModule.id, id:id}; | |
20 | }, | |
21 | ||
22 | slashName = function(name){ | |
23 | return name.replace(/\./g, "/"); | |
24 | }, | |
25 | ||
26 | buildDetectRe = /\/\/>>built/, | |
27 | ||
28 | dojoRequireCallbacks = [], | |
29 | dojoRequireModuleStack = [], | |
30 | ||
31 | dojoRequirePlugin = function(mid, require, loaded){ | |
32 | dojoRequireCallbacks.push(loaded); | |
33 | array.forEach(mid.split(","), function(mid){ | |
34 | var module = getModule(mid, require.module); | |
35 | dojoRequireModuleStack.push(module); | |
36 | injectModule(module); | |
37 | }); | |
38 | checkDojoRequirePlugin(); | |
39 | }, | |
40 | ||
41 | checkDojoRequirePlugin = ( 1 ? | |
42 | // This version of checkDojoRequirePlugin makes the observation that all dojoRequireCallbacks can be released | |
43 | // when all *non-dojo/require!, dojo/loadInit!* modules are either executed, not requested, or arrived. This is | |
44 | // the case since there are no more modules the loader is waiting for, therefore, dojo/require! must have | |
45 | // everything it needs on board. | |
46 | // | |
47 | // The potential weakness of this algorithm is that dojo/require will not execute callbacks until *all* dependency | |
48 | // trees are ready. It is possible that some trees may be ready earlier than others, and this extra wait is non-optimal. | |
49 | // Still, for big projects, this seems better than the original algorithm below that proved slow in some cases. | |
50 | // Note, however, the original algorithm had the potential to execute partial trees, but that potential was never enabled. | |
51 | // There are also other optimization available with the original algorithm that have not been explored. | |
52 | function(){ | |
53 | var module, mid; | |
54 | for(mid in modules){ | |
55 | module = modules[mid]; | |
56 | if(module.noReqPluginCheck===undefined){ | |
57 | // tag the module as either a loadInit or require plugin or not for future reference | |
58 | module.noReqPluginCheck = /loadInit\!/.test(mid) || /require\!/.test(mid) ? 1 : 0; | |
59 | } | |
60 | if(!module.executed && !module.noReqPluginCheck && module.injected==requested){ | |
61 | return; | |
62 | } | |
63 | } | |
64 | ||
65 | guardCheckComplete(function(){ | |
66 | var oldCallbacks = dojoRequireCallbacks; | |
67 | dojoRequireCallbacks = []; | |
68 | array.forEach(oldCallbacks, function(cb){cb(1);}); | |
69 | }); | |
70 | } : (function(){ | |
71 | // Note: this is the original checkDojoRequirePlugin that is much slower than the algorithm above. However, we know it | |
72 | // works, so we leave it here in case the algorithm above fails in some corner case. | |
73 | // | |
74 | // checkDojoRequirePlugin inspects all of the modules demanded by a dojo/require!<module-list> dependency | |
75 | // to see if they have arrived. The loader does not release *any* of these modules to be instantiated | |
76 | // until *all* of these modules are on board, thereby preventing the evaluation of a module with dojo.require's | |
77 | // that reference modules that are not available. | |
78 | // | |
79 | // The algorithm works by traversing the dependency graphs (remember, there can be cycles so they are not trees) | |
80 | // of each module in the dojoRequireModuleStack array (which contains the list of modules demanded by dojo/require!). | |
81 | // The moment a single module is discovered that is missing, the algorithm gives up and indicates that not all | |
82 | // modules are on board. dojo/loadInit! and dojo/require! are ignored because there dependencies are inserted | |
83 | // directly in dojoRequireModuleStack. For example, if "your/module" module depends on "dojo/require!my/module", then | |
84 | // *both* "dojo/require!my/module" and "my/module" will be in dojoRequireModuleStack. Obviously, if "my/module" | |
85 | // is on board, then "dojo/require!my/module" is also satisfied, so the algorithm doesn't check for "dojo/require!my/module". | |
86 | // | |
87 | // Note: inserting a dojo/require!<some-module-list> dependency in the dojoRequireModuleStack achieves nothing | |
88 | // with the current algorithm; however, having such modules present makes it possible to optimize the algorithm | |
89 | // | |
90 | // Note: prior versions of this algorithm had an optimization that signaled loaded on dojo/require! dependencies | |
91 | // individually (rather than waiting for them all to be resolved). The implementation proved problematic with cycles | |
92 | // and plugins. However, it is possible to reattach that strategy in the future. | |
93 | ||
94 | // a set from module-id to {undefined | 1 | 0}, where... | |
95 | // undefined => the module has not been inspected | |
96 | // 0 => the module or at least one of its dependencies has not arrived | |
97 | // 1 => the module is a loadInit! or require! plugin resource, or is currently being traversed (therefore, assume | |
98 | // OK until proven otherwise), or has been completely traversed and all dependencies have arrived | |
99 | ||
100 | var touched, | |
101 | traverse = function(m){ | |
102 | touched[m.mid] = 1; | |
103 | for(var t, module, deps = m.deps || [], i= 0; i<deps.length; i++){ | |
104 | module = deps[i]; | |
105 | if(!(t = touched[module.mid])){ | |
106 | if(t===0 || !traverse(module)){ | |
107 | touched[m.mid] = 0; | |
108 | return false; | |
109 | } | |
110 | } | |
111 | } | |
112 | return true; | |
113 | }; | |
114 | ||
115 | return function(){ | |
116 | // initialize the touched hash with easy-to-compute values that help short circuit recursive algorithm; | |
117 | // recall loadInit/require plugin modules are dependencies of modules in dojoRequireModuleStack... | |
118 | // which would cause a circular dependency chain that would never be resolved if checked here | |
119 | // notice all dependencies of any particular loadInit/require plugin module will already | |
120 | // be checked since those are pushed into dojoRequireModuleStack explicitly by the | |
121 | // plugin...so if a particular loadInitPlugin module's dependencies are not really | |
122 | // on board, that *will* be detected elsewhere in the traversal. | |
123 | var module, mid; | |
124 | touched = {}; | |
125 | for(mid in modules){ | |
126 | module = modules[mid]; | |
127 | if(module.executed || module.noReqPluginCheck){ | |
128 | touched[mid] = 1; | |
129 | }else{ | |
130 | if(module.noReqPluginCheck!==0){ | |
131 | // tag the module as either a loadInit or require plugin or not for future reference | |
132 | module.noReqPluginCheck = /loadInit\!/.test(mid) || /require\!/.test(mid) ? 1 : 0; | |
133 | } | |
134 | if(module.noReqPluginCheck){ | |
135 | touched[mid] = 1; | |
136 | }else if(module.injected!==arrived){ | |
137 | // not executed, has not arrived, and is not a loadInit or require plugin resource | |
138 | touched[mid] = 0; | |
139 | }// else, leave undefined and we'll traverse the dependencies | |
140 | } | |
141 | } | |
142 | for(var t, i = 0, end = dojoRequireModuleStack.length; i<end; i++){ | |
143 | module = dojoRequireModuleStack[i]; | |
144 | if(!(t = touched[module.mid])){ | |
145 | if(t===0 || !traverse(module)){ | |
146 | return; | |
147 | } | |
148 | } | |
149 | } | |
150 | guardCheckComplete(function(){ | |
151 | var oldCallbacks = dojoRequireCallbacks; | |
152 | dojoRequireCallbacks = []; | |
153 | array.forEach(oldCallbacks, function(cb){cb(1);}); | |
154 | }); | |
155 | }; | |
156 | })()), | |
157 | ||
158 | dojoLoadInitPlugin = function(mid, require, loaded){ | |
159 | // mid names a module that defines a "dojo load init" bundle, an object with two properties: | |
160 | // | |
161 | // * names: a vector of module ids that give top-level names to define in the lexical scope of def | |
162 | // * def: a function that contains some some legacy loader API applications | |
163 | // | |
164 | // The point of def is to possibly cause some modules to be loaded (but not executed) by dojo/require! where the module | |
165 | // ids are possibly-determined at runtime. For example, here is dojox.gfx from v1.6 expressed as an AMD module using the dojo/loadInit | |
166 | // and dojo/require plugins. | |
167 | // | |
168 | // // dojox/gfx: | |
169 | // | |
170 | // define("*loadInit_12, { | |
171 | // names:["dojo", "dijit", "dojox"], | |
172 | // def: function(){ | |
173 | // dojo.loadInit(function(){ | |
174 | // var gfx = lang.getObject("dojox.gfx", true); | |
175 | // | |
176 | // // | |
177 | // // code required to set gfx properties ommitted... | |
178 | // // | |
179 | // | |
180 | // // now use the calculations to include the runtime-dependent module | |
181 | // dojo.require("dojox.gfx." + gfx.renderer); | |
182 | // }); | |
183 | // } | |
184 | // }); | |
185 | // | |
186 | // define(["dojo", "dojo/loadInit!" + id].concat("dojo/require!dojox/gfx/matric,dojox/gfx/_base"), function(dojo){ | |
187 | // // when this AMD factory function is executed, the following modules are guaranteed downloaded but not executed: | |
188 | // // "dojox.gfx." + gfx.renderer | |
189 | // // dojox.gfx.matrix | |
190 | // // dojox.gfx._base | |
191 | // dojo.provide("dojo.gfx"); | |
192 | // dojo.require("dojox.gfx.matrix"); | |
193 | // dojo.require("dojox.gfx._base"); | |
194 | // dojo.require("dojox.gfx." + gfx.renderer); | |
195 | // return lang.getObject("dojo.gfx"); | |
196 | // }); | |
197 | // })(); | |
198 | // | |
199 | // The idea is to run the legacy loader API with global variables shadowed, which allows these variables to | |
200 | // be relocated. For example, dojox and dojo could be relocated to different names by giving a map and the code above will | |
201 | // execute properly (because the plugin below resolves the load init bundle.names module with respect to the module that demanded | |
202 | // the plugin resource). | |
203 | // | |
204 | // Note that the relocation is specified in the runtime configuration; relocated names need not be set at build-time. | |
205 | // | |
206 | // Warning: this is not the best way to express dojox.gfx as and AMD module. In fact, the module has been properly converted in | |
207 | // v1.7. However, this technique allows the builder to convert legacy modules into AMD modules and guarantee the codepath is the | |
208 | // same in the converted AMD module. | |
209 | require([mid], function(bundle){ | |
210 | // notice how names is resolved with respect to the module that demanded the plugin resource | |
211 | require(bundle.names, function(){ | |
212 | // bring the bundle names into scope | |
213 | for(var scopeText = "", args= [], i = 0; i<arguments.length; i++){ | |
214 | scopeText+= "var " + bundle.names[i] + "= arguments[" + i + "]; "; | |
215 | args.push(arguments[i]); | |
216 | } | |
217 | eval(scopeText); | |
218 | ||
219 | var callingModule = require.module, | |
220 | // the list of modules that need to be downloaded but not executed before the callingModule can be executed | |
221 | requireList = [], | |
222 | ||
223 | // the list of i18n bundles that are xdomain; undefined if none | |
224 | i18nDeps, | |
225 | ||
226 | syncLoaderApi = { | |
227 | provide:function(moduleName){ | |
228 | // mark modules that arrive consequent to multiple provides in this module as arrived since they can't be injected | |
229 | moduleName = slashName(moduleName); | |
230 | var providedModule = getModule(moduleName, callingModule); | |
231 | if(providedModule!==callingModule){ | |
232 | setArrived(providedModule); | |
233 | } | |
234 | }, | |
235 | require:function(moduleName, omitModuleCheck){ | |
236 | moduleName = slashName(moduleName); | |
237 | omitModuleCheck && (getModule(moduleName, callingModule).result = nonmodule); | |
238 | requireList.push(moduleName); | |
239 | }, | |
240 | requireLocalization:function(moduleName, bundleName, locale){ | |
241 | // since we're going to need dojo/i8n, add it to i18nDeps if not already there | |
242 | if(!i18nDeps){ | |
243 | // don't have to map since that will occur when the dependency is resolved | |
244 | i18nDeps = ["dojo/i18n"]; | |
245 | } | |
246 | ||
247 | // figure out if the bundle is xdomain; if so, add it to the i18nDepsSet | |
248 | locale = (locale || dojo.locale).toLowerCase(); | |
249 | moduleName = slashName(moduleName) + "/nls/" + (/root/i.test(locale) ? "" : locale + "/") + slashName(bundleName); | |
250 | if(getModule(moduleName, callingModule).isXd){ | |
251 | // don't have to map since that will occur when the dependency is resolved | |
252 | i18nDeps.push("dojo/i18n!" + moduleName); | |
253 | }// else the bundle will be loaded synchronously when the module is evaluated | |
254 | }, | |
255 | loadInit:function(f){ | |
256 | f(); | |
257 | } | |
258 | }, | |
259 | ||
260 | hold = {}, | |
261 | p; | |
262 | ||
263 | // hijack the correct dojo and apply bundle.def | |
264 | try{ | |
265 | for(p in syncLoaderApi){ | |
266 | hold[p] = dojo[p]; | |
267 | dojo[p] = syncLoaderApi[p]; | |
268 | } | |
269 | bundle.def.apply(null, args); | |
270 | }catch(e){ | |
271 | signal("error", [makeErrorToken("failedDojoLoadInit"), e]); | |
272 | }finally{ | |
273 | for(p in syncLoaderApi){ | |
274 | dojo[p] = hold[p]; | |
275 | } | |
276 | } | |
277 | ||
278 | if(i18nDeps){ | |
279 | requireList = requireList.concat(i18nDeps); | |
280 | } | |
281 | ||
282 | if(requireList.length){ | |
283 | dojoRequirePlugin(requireList.join(","), require, loaded); | |
284 | }else{ | |
285 | loaded(); | |
286 | } | |
287 | }); | |
288 | }); | |
289 | }, | |
290 | ||
291 | extractApplication = function( | |
292 | text, // the text to search | |
293 | startSearch, // the position in text to start looking for the closing paren | |
294 | startApplication // the position in text where the function application expression starts | |
295 | ){ | |
296 | // find end of the call by finding the matching end paren | |
297 | // Warning: as usual, this will fail in the presense of unmatched right parans contained in strings, regexs, or unremoved comments | |
298 | var parenRe = /\(|\)/g, | |
299 | matchCount = 1, | |
300 | match; | |
301 | parenRe.lastIndex = startSearch; | |
302 | while((match = parenRe.exec(text))){ | |
303 | if(match[0] == ")"){ | |
304 | matchCount -= 1; | |
305 | }else{ | |
306 | matchCount += 1; | |
307 | } | |
308 | if(matchCount == 0){ | |
309 | break; | |
310 | } | |
311 | } | |
312 | ||
313 | if(matchCount != 0){ | |
314 | throw "unmatched paren around character " + parenRe.lastIndex + " in: " + text; | |
315 | } | |
316 | ||
317 | //Put the master matching string in the results. | |
318 | return [dojo.trim(text.substring(startApplication, parenRe.lastIndex))+";\n", parenRe.lastIndex]; | |
319 | }, | |
320 | ||
321 | // the following regex is taken from 1.6. It is a very poor technique to remove comments and | |
322 | // will fail in some cases; for example, consider the code... | |
323 | // | |
324 | // var message = "Category-1 */* Category-2"; | |
325 | // | |
326 | // The regex that follows will see a /* comment and trash the code accordingly. In fact, there are all | |
327 | // kinds of cases like this with strings and regexs that will cause this design to fail miserably. | |
328 | // | |
329 | // Alternative regex designs exist that will result in less-likely failures, but will still fail in many cases. | |
330 | // The only solution guaranteed 100% correct is to parse the code and that seems overkill for this | |
331 | // backcompat/unbuilt-xdomain layer. In the end, since it's been this way for a while, we won't change it. | |
332 | // See the opening paragraphs of Chapter 7 or ECME-262 which describes the lexical abiguity further. | |
333 | removeCommentRe = /(\/\*([\s\S]*?)\*\/|\/\/(.*)$)/mg, | |
334 | ||
335 | syncLoaderApiRe = /(^|\s)dojo\.(loadInit|require|provide|requireLocalization|requireIf|requireAfterIf|platformRequire)\s*\(/mg, | |
336 | ||
337 | amdLoaderApiRe = /(^|\s)(require|define)\s*\(/m, | |
338 | ||
339 | extractLegacyApiApplications = function(text, noCommentText){ | |
340 | // scan the noCommentText for any legacy loader API applications. Copy such applications into result (this is | |
341 | // used by the builder). Move dojo.loadInit applications to loadInitApplications string. Copy all other applications | |
342 | // to otherApplications string. If no applications were found, return 0, signalling an AMD module. Otherwise, return | |
343 | // loadInitApplications + otherApplications. Fixup text by replacing | |
344 | // | |
345 | // dojo.loadInit(// etc... | |
346 | // | |
347 | // with | |
348 | // | |
349 | // \n 0 && dojo.loadInit(// etc... | |
350 | // | |
351 | // Which results in the dojo.loadInit from *not* being applied. This design goes a long way towards protecting the | |
352 | // code from an over-agressive removeCommentRe. However... | |
353 | // | |
354 | // WARNING: the removeCommentRe will cause an error if a detected comment removes all or part of a legacy-loader application | |
355 | // that is not in a comment. | |
356 | ||
357 | var match, startSearch, startApplication, application, | |
358 | loadInitApplications = [], | |
359 | otherApplications = [], | |
360 | allApplications = []; | |
361 | ||
362 | // noCommentText may be provided by a build app with comments extracted by a better method than regex (hopefully) | |
363 | noCommentText = noCommentText || text.replace(removeCommentRe, function(match){ | |
364 | // remove iff the detected comment has text that looks like a sync loader API application; this helps by | |
365 | // removing as little as possible, minimizing the changes the janky regex will kill the module | |
366 | syncLoaderApiRe.lastIndex = amdLoaderApiRe.lastIndex = 0; | |
367 | return (syncLoaderApiRe.test(match) || amdLoaderApiRe.test(match)) ? "" : match; | |
368 | }); | |
369 | ||
370 | // find and extract all dojo.loadInit applications | |
371 | while((match = syncLoaderApiRe.exec(noCommentText))){ | |
372 | startSearch = syncLoaderApiRe.lastIndex; | |
373 | startApplication = startSearch - match[0].length; | |
374 | application = extractApplication(noCommentText, startSearch, startApplication); | |
375 | if(match[2]=="loadInit"){ | |
376 | loadInitApplications.push(application[0]); | |
377 | }else{ | |
378 | otherApplications.push(application[0]); | |
379 | } | |
380 | syncLoaderApiRe.lastIndex = application[1]; | |
381 | } | |
382 | allApplications = loadInitApplications.concat(otherApplications); | |
383 | if(allApplications.length || !amdLoaderApiRe.test(noCommentText)){ | |
384 | // either there were some legacy loader API applications or there were no AMD API applications | |
385 | return [text.replace(/(^|\s)dojo\.loadInit\s*\(/g, "\n0 && dojo.loadInit("), allApplications.join(""), allApplications]; | |
386 | }else{ | |
387 | // legacy loader API *was not* detected and AMD API *was* detected; therefore, assume it's an AMD module | |
388 | return 0; | |
389 | } | |
390 | }, | |
391 | ||
392 | transformToAmd = function(module, text){ | |
393 | // This is roughly the equivalent of dojo._xdCreateResource in 1.6-; however, it expresses a v1.6- dojo | |
394 | // module in terms of AMD define instead of creating the dojo proprietary xdomain module expression. | |
395 | // The module could have originated from several sources: | |
396 | // | |
397 | // * amd require() a module, e.g., require(["my/module"]) | |
398 | // * amd require() a nonmodule, e.g., require(["my/resource.js"') | |
399 | // * amd define() deps vector (always a module) | |
400 | // * dojo.require() a module, e.g. dojo.require("my.module") | |
401 | // * dojo.require() a nonmodule, e.g., dojo.require("my.module", true) | |
402 | // * dojo.requireIf/requireAfterIf/platformRequire a module | |
403 | // | |
404 | // The module is scanned for legacy loader API applications; if none are found, then assume the module is an | |
405 | // AMD module and return 0. Otherwise, a synthetic dojo/loadInit plugin resource is created and the module text | |
406 | // is rewritten as an AMD module with the single dependency of this synthetic resource. When the dojo/loadInit | |
407 | // plugin loaded the synthetic resource, it will cause all dojo.loadInit's to be executed, find all dojo.require's | |
408 | // (either directly consequent to dojo.require or indirectly consequent to dojo.require[After]If or | |
409 | // dojo.platformRequire, and finally cause loading of all dojo.required modules with the dojo/require plugin. Thus, | |
410 | // when the dojo/loadInit plugin reports it has been loaded, all modules required by the given module are guaranteed | |
411 | // loaded (but not executed). This then allows the module to execute it's code path without interupts, thereby | |
412 | // following the synchronous code path. | |
413 | // | |
414 | // Notice that this function behaves the same whether or not it happens to be in a mapped dojo/loader module. | |
415 | ||
416 | var extractResult, id, names = [], namesAsStrings = []; | |
417 | if(buildDetectRe.test(text) || !(extractResult = extractLegacyApiApplications(text))){ | |
418 | // buildDetectRe.test(text) => a built module, always AMD | |
419 | // extractResult==0 => no sync API | |
420 | return 0; | |
421 | } | |
422 | ||
423 | // manufacture a synthetic module id that can never be a real mdule id (just like require does) | |
424 | id = module.mid + "-*loadInit"; | |
425 | ||
426 | // construct the dojo/loadInit names vector which causes any relocated names to be defined as lexical variables under their not-relocated name | |
427 | // the dojo/loadInit plugin assumes the first name in names is "dojo" | |
428 | ||
429 | for(var p in getModule("dojo", module).result.scopeMap){ | |
430 | names.push(p); | |
431 | namesAsStrings.push('"' + p + '"'); | |
432 | } | |
433 | ||
434 | // rewrite the module as a synthetic dojo/loadInit plugin resource + the module expressed as an AMD module that depends on this synthetic resource | |
435 | // don't have to map dojo/init since that will occur when the dependency is resolved | |
436 | return "// xdomain rewrite of " + module.mid + "\n" + | |
437 | "define('" + id + "',{\n" + | |
438 | "\tnames:" + dojo.toJson(names) + ",\n" + | |
439 | "\tdef:function(" + names.join(",") + "){" + extractResult[1] + "}" + | |
440 | "});\n\n" + | |
441 | "define(" + dojo.toJson(names.concat(["dojo/loadInit!"+id])) + ", function(" + names.join(",") + "){\n" + extractResult[0] + "});"; | |
442 | }, | |
443 | ||
444 | loaderVars = require.initSyncLoader(dojoRequirePlugin, checkDojoRequirePlugin, transformToAmd), | |
445 | ||
446 | sync = | |
447 | loaderVars.sync, | |
448 | ||
449 | requested = | |
450 | loaderVars.requested, | |
451 | ||
452 | arrived = | |
453 | loaderVars.arrived, | |
454 | ||
455 | nonmodule = | |
456 | loaderVars.nonmodule, | |
457 | ||
458 | executing = | |
459 | loaderVars.executing, | |
460 | ||
461 | executed = | |
462 | loaderVars.executed, | |
463 | ||
464 | syncExecStack = | |
465 | loaderVars.syncExecStack, | |
466 | ||
467 | modules = | |
468 | loaderVars.modules, | |
469 | ||
470 | execQ = | |
471 | loaderVars.execQ, | |
472 | ||
473 | getModule = | |
474 | loaderVars.getModule, | |
475 | ||
476 | injectModule = | |
477 | loaderVars.injectModule, | |
478 | ||
479 | setArrived = | |
480 | loaderVars.setArrived, | |
481 | ||
482 | signal = | |
483 | loaderVars.signal, | |
484 | ||
485 | finishExec = | |
486 | loaderVars.finishExec, | |
487 | ||
488 | execModule = | |
489 | loaderVars.execModule, | |
490 | ||
491 | getLegacyMode = | |
492 | loaderVars.getLegacyMode, | |
493 | ||
494 | guardCheckComplete = | |
495 | loaderVars.guardCheckComplete; | |
496 | ||
497 | // there is exactly one dojoRequirePlugin among possibly-many dojo/_base/loader's (owing to mapping) | |
498 | dojoRequirePlugin = loaderVars.dojoRequirePlugin; | |
499 | ||
500 | dojo.provide = function(mid){ | |
501 | var executingModule = syncExecStack[0], | |
502 | module = lang.mixin(getModule(slashName(mid), require.module), { | |
503 | executed:executing, | |
504 | result:lang.getObject(mid, true) | |
505 | }); | |
506 | setArrived(module); | |
507 | if(executingModule){ | |
508 | (executingModule.provides || (executingModule.provides = [])).push(function(){ | |
509 | module.result = lang.getObject(mid); | |
510 | delete module.provides; | |
511 | module.executed!==executed && finishExec(module); | |
512 | }); | |
513 | }// else dojo.provide called not consequent to loading; therefore, give up trying to publish module value to loader namespace | |
514 | return module.result; | |
515 | }; | |
516 | ||
517 | has.add("config-publishRequireResult", 1, 0, 0); | |
518 | ||
519 | dojo.require = function(moduleName, omitModuleCheck) { | |
520 | // summary: | |
521 | // loads a Javascript module from the appropriate URI | |
522 | // | |
523 | // moduleName: String | |
524 | // module name to load, using periods for separators, | |
525 | // e.g. "dojo.date.locale". Module paths are de-referenced by dojo's | |
526 | // internal mapping of locations to names and are disambiguated by | |
527 | // longest prefix. See `dojo.registerModulePath()` for details on | |
528 | // registering new modules. | |
529 | // | |
530 | // omitModuleCheck: Boolean? | |
531 | // if `true`, omitModuleCheck skips the step of ensuring that the | |
532 | // loaded file actually defines the symbol it is referenced by. | |
533 | // For example if it called as `dojo.require("a.b.c")` and the | |
534 | // file located at `a/b/c.js` does not define an object `a.b.c`, | |
535 | // and exception will be throws whereas no exception is raised | |
536 | // when called as `dojo.require("a.b.c", true)` | |
537 | // | |
538 | // description: | |
539 | // Modules are loaded via dojo.require by using one of two loaders: the normal loader | |
540 | // and the xdomain loader. The xdomain loader is used when dojo was built with a | |
541 | // custom build that specified loader=xdomain and the module lives on a modulePath | |
542 | // that is a whole URL, with protocol and a domain. The versions of Dojo that are on | |
543 | // the Google and AOL CDNs use the xdomain loader. | |
544 | // | |
545 | // If the module is loaded via the xdomain loader, it is an asynchronous load, since | |
546 | // the module is added via a dynamically created script tag. This | |
547 | // means that dojo.require() can return before the module has loaded. However, this | |
548 | // should only happen in the case where you do dojo.require calls in the top-level | |
549 | // HTML page, or if you purposely avoid the loader checking for dojo.require | |
550 | // dependencies in your module by using a syntax like dojo["require"] to load the module. | |
551 | // | |
552 | // Sometimes it is useful to not have the loader detect the dojo.require calls in the | |
553 | // module so that you can dynamically load the modules as a result of an action on the | |
554 | // page, instead of right at module load time. | |
555 | // | |
556 | // Also, for script blocks in an HTML page, the loader does not pre-process them, so | |
557 | // it does not know to download the modules before the dojo.require calls occur. | |
558 | // | |
559 | // So, in those two cases, when you want on-the-fly module loading or for script blocks | |
560 | // in the HTML page, special care must be taken if the dojo.required code is loaded | |
561 | // asynchronously. To make sure you can execute code that depends on the dojo.required | |
562 | // modules, be sure to add the code that depends on the modules in a dojo.addOnLoad() | |
563 | // callback. dojo.addOnLoad waits for all outstanding modules to finish loading before | |
564 | // executing. | |
565 | // | |
566 | // This type of syntax works with both xdomain and normal loaders, so it is good | |
567 | // practice to always use this idiom for on-the-fly code loading and in HTML script | |
568 | // blocks. If at some point you change loaders and where the code is loaded from, | |
569 | // it will all still work. | |
570 | // | |
571 | // More on how dojo.require | |
572 | // `dojo.require("A.B")` first checks to see if symbol A.B is | |
573 | // defined. If it is, it is simply returned (nothing to do). | |
574 | // | |
575 | // If it is not defined, it will look for `A/B.js` in the script root | |
576 | // directory. | |
577 | // | |
578 | // `dojo.require` throws an exception if it cannot find a file | |
579 | // to load, or if the symbol `A.B` is not defined after loading. | |
580 | // | |
581 | // It returns the object `A.B`, but note the caveats above about on-the-fly loading and | |
582 | // HTML script blocks when the xdomain loader is loading a module. | |
583 | // | |
584 | // `dojo.require()` does nothing about importing symbols into | |
585 | // the current namespace. It is presumed that the caller will | |
586 | // take care of that. | |
587 | // | |
588 | // example: | |
589 | // To use dojo.require in conjunction with dojo.ready: | |
590 | // | |
591 | // | dojo.require("foo"); | |
592 | // | dojo.require("bar"); | |
593 | // | dojo.addOnLoad(function(){ | |
594 | // | //you can now safely do something with foo and bar | |
595 | // | }); | |
596 | // | |
597 | // example: | |
598 | // For example, to import all symbols into a local block, you might write: | |
599 | // | |
600 | // | with (dojo.require("A.B")) { | |
601 | // | ... | |
602 | // | } | |
603 | // | |
604 | // And to import just the leaf symbol to a local variable: | |
605 | // | |
606 | // | var B = dojo.require("A.B"); | |
607 | // | ... | |
608 | // | |
609 | // returns: | |
610 | // the required namespace object | |
611 | function doRequire(mid, omitModuleCheck){ | |
612 | var module = getModule(slashName(mid), require.module); | |
613 | if(syncExecStack.length && syncExecStack[0].finish){ | |
614 | // switched to async loading in the middle of evaluating a legacy module; stop | |
615 | // applying dojo.require so the remaining dojo.requires are applied in order | |
616 | syncExecStack[0].finish.push(mid); | |
617 | return undefined; | |
618 | } | |
619 | ||
620 | // recall module.executed has values {0, executing, executed}; therefore, truthy indicates executing or executed | |
621 | if(module.executed){ | |
622 | return module.result; | |
623 | } | |
624 | omitModuleCheck && (module.result = nonmodule); | |
625 | ||
626 | // rcg...why here and in two lines?? | |
627 | var currentMode = getLegacyMode(); | |
628 | ||
629 | // recall, in sync mode to inject is to *eval* the module text | |
630 | // if the module is a legacy module, this is the same as executing | |
631 | // but if the module is an AMD module, this means defining, not executing | |
632 | injectModule(module); | |
633 | // the inject may have changed the mode | |
634 | currentMode = getLegacyMode(); | |
635 | ||
636 | // in sync mode to dojo.require is to execute | |
637 | if(module.executed!==executed && module.injected===arrived){ | |
638 | // the module was already here before injectModule was called probably finishing up a xdomain | |
639 | // load, but maybe a module given to the loader directly rather than having the loader retrieve it | |
640 | ||
641 | loaderVars.guardCheckComplete(function(){ | |
642 | execModule(module); | |
643 | }); | |
644 | } | |
645 | if(module.executed){ | |
646 | return module.result; | |
647 | } | |
648 | ||
649 | if(currentMode==sync){ | |
650 | // the only way to get here is in sync mode and dojo.required a module that | |
651 | // * was loaded async in the injectModule application a few lines up | |
652 | // * was an AMD module that had deps that are being loaded async and therefore couldn't execute | |
653 | if(module.cjs){ | |
654 | // the module was an AMD module; unshift, not push, which causes the current traversal to be reattempted from the top | |
655 | execQ.unshift(module); | |
656 | }else{ | |
657 | // the module was a legacy module | |
658 | syncExecStack.length && (syncExecStack[0].finish= [mid]); | |
659 | } | |
660 | }else{ | |
661 | // the loader wasn't in sync mode on entry; probably async mode; therefore, no expectation of getting | |
662 | // the module value synchronously; make sure it gets executed though | |
663 | execQ.push(module); | |
664 | } | |
665 | ||
666 | return undefined; | |
667 | } | |
668 | ||
669 | var result = doRequire(moduleName, omitModuleCheck); | |
670 | if(has("config-publishRequireResult") && !lang.exists(moduleName) && result!==undefined){ | |
671 | lang.setObject(moduleName, result); | |
672 | } | |
673 | return result; | |
674 | }; | |
675 | ||
676 | dojo.loadInit = function(f) { | |
677 | f(); | |
678 | }; | |
679 | ||
680 | dojo.registerModulePath = function(/*String*/moduleName, /*String*/prefix){ | |
681 | // summary: | |
682 | // Maps a module name to a path | |
683 | // description: | |
684 | // An unregistered module is given the default path of ../[module], | |
685 | // relative to Dojo root. For example, module acme is mapped to | |
686 | // ../acme. If you want to use a different module name, use | |
687 | // dojo.registerModulePath. | |
688 | // example: | |
689 | // If your dojo.js is located at this location in the web root: | |
690 | // | /myapp/js/dojo/dojo/dojo.js | |
691 | // and your modules are located at: | |
692 | // | /myapp/js/foo/bar.js | |
693 | // | /myapp/js/foo/baz.js | |
694 | // | /myapp/js/foo/thud/xyzzy.js | |
695 | // Your application can tell Dojo to locate the "foo" namespace by calling: | |
696 | // | dojo.registerModulePath("foo", "../../foo"); | |
697 | // At which point you can then use dojo.require() to load the | |
698 | // modules (assuming they provide() the same things which are | |
699 | // required). The full code might be: | |
700 | // | <script type="text/javascript" | |
701 | // | src="/myapp/js/dojo/dojo/dojo.js"></script> | |
702 | // | <script type="text/javascript"> | |
703 | // | dojo.registerModulePath("foo", "../../foo"); | |
704 | // | dojo.require("foo.bar"); | |
705 | // | dojo.require("foo.baz"); | |
706 | // | dojo.require("foo.thud.xyzzy"); | |
707 | // | </script> | |
708 | ||
709 | var paths = {}; | |
710 | paths[moduleName.replace(/\./g, "/")] = prefix; | |
711 | require({paths:paths}); | |
712 | }; | |
713 | ||
714 | dojo.platformRequire = function(/*Object*/modMap){ | |
715 | // summary: | |
716 | // require one or more modules based on which host environment | |
717 | // Dojo is currently operating in | |
718 | // description: | |
719 | // This method takes a "map" of arrays which one can use to | |
720 | // optionally load dojo modules. The map is indexed by the | |
721 | // possible dojo.name_ values, with two additional values: | |
722 | // "default" and "common". The items in the "default" array will | |
723 | // be loaded if none of the other items have been choosen based on | |
724 | // dojo.name_, set by your host environment. The items in the | |
725 | // "common" array will *always* be loaded, regardless of which | |
726 | // list is chosen. | |
727 | // example: | |
728 | // | dojo.platformRequire({ | |
729 | // | browser: [ | |
730 | // | "foo.sample", // simple module | |
731 | // | "foo.test", | |
732 | // | ["foo.bar.baz", true] // skip object check in _loadModule (dojo.require) | |
733 | // | ], | |
734 | // | default: [ "foo.sample._base" ], | |
735 | // | common: [ "important.module.common" ] | |
736 | // | }); | |
737 | ||
738 | var result = (modMap.common || []).concat(modMap[dojo._name] || modMap["default"] || []), | |
739 | temp; | |
740 | while(result.length){ | |
741 | if(lang.isArray(temp = result.shift())){ | |
742 | dojo.require.apply(dojo, temp); | |
743 | }else{ | |
744 | dojo.require(temp); | |
745 | } | |
746 | } | |
747 | }; | |
748 | ||
749 | dojo.requireIf = dojo.requireAfterIf = function(/*Boolean*/ condition, /*String*/ moduleName, /*Boolean?*/omitModuleCheck){ | |
750 | // summary: | |
751 | // If the condition is true then call `dojo.require()` for the specified | |
752 | // resource | |
753 | // | |
754 | // example: | |
755 | // | dojo.requireIf(dojo.isBrowser, "my.special.Module"); | |
756 | ||
757 | if(condition){ | |
758 | dojo.require(moduleName, omitModuleCheck); | |
759 | } | |
760 | }; | |
761 | ||
762 | dojo.requireLocalization = function(/*String*/moduleName, /*String*/bundleName, /*String?*/locale){ | |
763 | require(["../i18n"], function(i18n){ | |
764 | i18n.getLocalization(moduleName, bundleName, locale); | |
765 | }); | |
766 | }; | |
767 | ||
768 | return { | |
769 | // summary: | |
770 | // This module defines the v1.x synchronous loader API. | |
771 | ||
772 | extractLegacyApiApplications:extractLegacyApiApplications, | |
773 | require:dojoRequirePlugin, | |
774 | loadInit:dojoLoadInitPlugin | |
775 | }; | |
776 | }); |