source: Dev/trunk/src/client/dojo/_base/loader.js @ 485

Last change on this file since 485 was 483, checked in by hendrikvanantwerpen, 11 years ago

Added Dojo 1.9.3 release.

File size: 31.5 KB
Line 
1define(["./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});
Note: See TracBrowser for help on using the repository browser.