1 | define(["./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 (!has("dojo-loader")){ |
---|
11 | console.error("cannot load the Dojo v1.x loader with a foreign loader"); |
---|
12 | return 0; |
---|
13 | } |
---|
14 | |
---|
15 | 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 = (has("dojo-fast-sync-require") ? |
---|
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:" + json.stringify(names) + ",\n" + |
---|
439 | "\tdef:function(" + names.join(",") + "){" + extractResult[1] + "}" + |
---|
440 | "});\n\n" + |
---|
441 | "define(" + json.stringify(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 | }); |
---|