· 5 years ago · Mar 08, 2021, 12:10 AM
1(function(
2 userConfig,
3 defaultConfig
4){
5 // summary:
6 // This is the "source loader" and is the entry point for Dojo during development. You may also load Dojo with
7 // any AMD-compliant loader via the package main module dojo/main.
8 // description:
9 // This is the "source loader" for Dojo. It provides an AMD-compliant loader that can be configured
10 // to operate in either synchronous or asynchronous modes. After the loader is defined, dojo is loaded
11 // IAW the package main module dojo/main. In the event you wish to use a foreign loader, you may load dojo as a package
12 // via the package main module dojo/main and this loader is not required; see dojo/package.json for details.
13 //
14 // In order to keep compatibility with the v1.x line, this loader includes additional machinery that enables
15 // the dojo.provide, dojo.require et al API. This machinery is loaded by default, but may be dynamically removed
16 // via the has.js API and statically removed via the build system.
17 //
18 // This loader includes sniffing machinery to determine the environment; the following environments are supported:
19 //
20 // - browser
21 // - node.js
22 // - rhino
23 //
24 // This is the so-called "source loader". As such, it includes many optional features that may be discarded by
25 // building a customized version with the build system.
26
27 // Design and Implementation Notes
28 //
29 // This is a dojo-specific adaption of bdLoad, donated to the dojo foundation by Altoviso LLC.
30 //
31 // This function defines an AMD-compliant (http://wiki.commonjs.org/wiki/Modules/AsynchronousDefinition)
32 // loader that can be configured to operate in either synchronous or asynchronous modes.
33 //
34 // Since this machinery implements a loader, it does not have the luxury of using a load system and/or
35 // leveraging a utility library. This results in an unpleasantly long file; here is a road map of the contents:
36 //
37 // 1. Small library for use implementing the loader.
38 // 2. Define the has.js API; this is used throughout the loader to bracket features.
39 // 3. Define the node.js and rhino sniffs and sniff.
40 // 4. Define the loader's data.
41 // 5. Define the configuration machinery.
42 // 6. Define the script element sniffing machinery and sniff for configuration data.
43 // 7. Configure the loader IAW the provided user, default, and sniffing data.
44 // 8. Define the global require function.
45 // 9. Define the module resolution machinery.
46 // 10. Define the module and plugin module definition machinery
47 // 11. Define the script injection machinery.
48 // 12. Define the window load detection.
49 // 13. Define the logging API.
50 // 14. Define the tracing API.
51 // 16. Define the AMD define function.
52 // 17. Define the dojo v1.x provide/require machinery--so called "legacy" modes.
53 // 18. Publish global variables.
54 //
55 // Language and Acronyms and Idioms
56 //
57 // moduleId: a CJS module identifier, (used for public APIs)
58 // mid: moduleId (used internally)
59 // packageId: a package identifier (used for public APIs)
60 // pid: packageId (used internally); the implied system or default package has pid===""
61 // pack: package is used internally to reference a package object (since javascript has reserved words including "package")
62 // prid: plugin resource identifier
63 // The integer constant 1 is used in place of true and 0 in place of false.
64
65 // define global
66 var globalObject = (function(){
67 if (typeof global !== 'undefined' && typeof global !== 'function') {
68 // global spec defines a reference to the global object called 'global'
69 // https://github.com/tc39/proposal-global
70 // `global` is also defined in NodeJS
71 return global;
72 }
73 else if (typeof window !== 'undefined') {
74 // window is defined in browsers
75 return window;
76 }
77 else if (typeof self !== 'undefined') {
78 // self is defined in WebWorkers
79 return self;
80 }
81 return this;
82 })();
83
84 // define a minimal library to help build the loader
85 var noop = function(){
86 },
87
88 isEmpty = function(it){
89 for(var p in it){
90 return 0;
91 }
92 return 1;
93 },
94
95 toString = {}.toString,
96
97 isFunction = function(it){
98 return toString.call(it) == "[object Function]";
99 },
100
101 isString = function(it){
102 return toString.call(it) == "[object String]";
103 },
104
105 isArray = function(it){
106 return toString.call(it) == "[object Array]";
107 },
108
109 forEach = function(vector, callback){
110 if(vector){
111 for(var i = 0; i < vector.length;){
112 callback(vector[i++]);
113 }
114 }
115 },
116
117 mix = function(dest, src){
118 for(var p in src){
119 dest[p] = src[p];
120 }
121 return dest;
122 },
123
124 makeError = function(error, info){
125 return mix(new Error(error), {src:"dojoLoader", info:info});
126 },
127
128 uidSeed = 1,
129
130 uid = function(){
131 // Returns a unique identifier (within the lifetime of the document) of the form /_d+/.
132 return "_" + uidSeed++;
133 },
134
135 // FIXME: how to doc window.require() api
136
137 // this will be the global require function; define it immediately so we can start hanging things off of it
138 req = function(
139 config, //(object, optional) hash of configuration properties
140 dependencies, //(array of commonjs.moduleId, optional) list of modules to be loaded before applying callback
141 callback //(function, optional) lambda expression to apply to module values implied by dependencies
142 ){
143 return contextRequire(config, dependencies, callback, 0, req);
144 },
145
146 // the loader uses the has.js API to control feature inclusion/exclusion; define then use throughout
147 global = globalObject,
148
149 doc = global.document,
150
151 element = doc && doc.createElement("DiV"),
152
153 has = req.has = function(name){
154 return isFunction(hasCache[name]) ? (hasCache[name] = hasCache[name](global, doc, element)) : hasCache[name];
155 },
156
157 hasCache = has.cache = defaultConfig.hasCache;
158
159 if (isFunction(userConfig)) {
160 userConfig = userConfig(globalObject);
161 }
162
163 has.add = function(name, test, now, force){
164 (hasCache[name]===undefined || force) && (hasCache[name] = test);
165 return now && has(name);
166 };
167
168 has.add("host-node", userConfig.has && "host-node" in userConfig.has ?
169 userConfig.has["host-node"] :
170 (typeof process == "object" && process.versions && process.versions.node && process.versions.v8));
171 if(has("host-node")){
172 // fixup the default config for node.js environment
173 require("./_base/configNode.js").config(defaultConfig);
174 // remember node's require (with respect to baseUrl==dojo's root)
175 defaultConfig.loaderPatch.nodeRequire = require;
176 }
177
178 has.add("host-rhino", userConfig.has && "host-rhino" in userConfig.has ?
179 userConfig.has["host-rhino"] :
180 (typeof load == "function" && (typeof Packages == "function" || typeof Packages == "object")));
181 if(has("host-rhino")){
182 // owing to rhino's lame feature that hides the source of the script, give the user a way to specify the baseUrl...
183 for(var baseUrl = userConfig.baseUrl || ".", arg, rhinoArgs = this.arguments, i = 0; i < rhinoArgs.length;){
184 arg = (rhinoArgs[i++] + "").split("=");
185 if(arg[0] == "baseUrl"){
186 baseUrl = arg[1];
187 break;
188 }
189 }
190 load(baseUrl + "/_base/configRhino.js");
191 rhinoDojoConfig(defaultConfig, baseUrl, rhinoArgs);
192 }
193
194 has.add("host-webworker", ((typeof WorkerGlobalScope !== 'undefined') && (self instanceof WorkerGlobalScope)));
195 if(has("host-webworker")){
196 mix(defaultConfig.hasCache, {
197 "host-browser": 0,
198 "dom": 0,
199 "dojo-dom-ready-api": 0,
200 "dojo-sniff": 0,
201 "dojo-inject-api": 1,
202 "host-webworker": 1,
203 "dojo-guarantee-console": 0 // console is immutable in FF30+, see https://bugs.dojotoolkit.org/ticket/18100
204 });
205
206 defaultConfig.loaderPatch = {
207 injectUrl: function(url, callback){
208 // TODO:
209 // This is not async, nor can it be in Webworkers. It could be made better by passing
210 // the entire require array into importScripts at. This way the scripts are loaded in
211 // async mode; even if the callbacks are ran in sync. It is not a major issue as webworkers
212 // tend to be long running where initial startup is not a major factor.
213
214 try{
215 importScripts(url);
216 callback();
217 }catch(e){
218 console.info("failed to load resource (" + url + ")");
219 console.error(e);
220 }
221 }
222 };
223 }
224
225 // userConfig has tests override defaultConfig has tests; do this after the environment detection because
226 // the environment detection usually sets some has feature values in the hasCache.
227 for(var p in userConfig.has){
228 has.add(p, userConfig.has[p], 0, 1);
229 }
230
231 //
232 // define the loader data
233 //
234
235 // the loader will use these like symbols if the loader has the traceApi; otherwise
236 // define magic numbers so that modules can be provided as part of defaultConfig
237 var requested = 1,
238 arrived = 2,
239 nonmodule = 3,
240 executing = 4,
241 executed = 5;
242
243 if(has("dojo-trace-api")){
244 // these make debugging nice; but using strings for symbols is a gross rookie error; don't do it for production code
245 requested = "requested";
246 arrived = "arrived";
247 nonmodule = "not-a-module";
248 executing = "executing";
249 executed = "executed";
250 }
251
252 var legacyMode = 0,
253 sync = "sync",
254 xd = "xd",
255 syncExecStack = [],
256 dojoRequirePlugin = 0,
257 checkDojoRequirePlugin = noop,
258 transformToAmd = noop,
259 getXhr;
260 if(has("dojo-sync-loader")){
261 req.isXdUrl = noop;
262
263 req.initSyncLoader = function(dojoRequirePlugin_, checkDojoRequirePlugin_, transformToAmd_){
264 // the first dojo/_base/loader loaded gets to define these variables; they are designed to work
265 // in the presence of zero to many mapped dojo/_base/loaders
266 if(!dojoRequirePlugin){
267 dojoRequirePlugin = dojoRequirePlugin_;
268 checkDojoRequirePlugin = checkDojoRequirePlugin_;
269 transformToAmd = transformToAmd_;
270 }
271
272 return {
273 sync:sync,
274 requested:requested,
275 arrived:arrived,
276 nonmodule:nonmodule,
277 executing:executing,
278 executed:executed,
279 syncExecStack:syncExecStack,
280 modules:modules,
281 execQ:execQ,
282 getModule:getModule,
283 injectModule:injectModule,
284 setArrived:setArrived,
285 signal:signal,
286 finishExec:finishExec,
287 execModule:execModule,
288 dojoRequirePlugin:dojoRequirePlugin,
289 getLegacyMode:function(){return legacyMode;},
290 guardCheckComplete:guardCheckComplete
291 };
292 };
293
294 if(has("dom") || has("host-webworker")){
295 // in legacy sync mode, the loader needs a minimal XHR library
296
297 var locationProtocol = location.protocol,
298 locationHost = location.host;
299 req.isXdUrl = function(url){
300 if(/^\./.test(url)){
301 // begins with a dot is always relative to page URL; therefore not xdomain
302 return false;
303 }
304 if(/^\/\//.test(url)){
305 // for v1.6- backcompat, url starting with // indicates xdomain
306 return true;
307 }
308 // get protocol and host
309 // \/+ takes care of the typical file protocol that looks like file:///drive/path/to/file
310 // locationHost is falsy if file protocol => if locationProtocol matches and is "file:", || will return false
311 var match = url.match(/^([^\/\:]+\:)\/+([^\/]+)/);
312 return match && (match[1] != locationProtocol || (locationHost && match[2] != locationHost));
313 };
314
315
316 // note: to get the file:// protocol to work in FF, you must set security.fileuri.strict_origin_policy to false in about:config
317 has.add("dojo-xhr-factory", 1);
318 has.add("dojo-force-activex-xhr", has("host-browser") && !doc.addEventListener && window.location.protocol == "file:");
319 has.add("native-xhr", typeof XMLHttpRequest != "undefined");
320 if(has("native-xhr") && !has("dojo-force-activex-xhr")){
321 getXhr = function(){
322 return new XMLHttpRequest();
323 };
324 }else{
325 // if in the browser an old IE; find an xhr
326 for(var XMLHTTP_PROGIDS = ['Msxml2.XMLHTTP', 'Microsoft.XMLHTTP', 'Msxml2.XMLHTTP.4.0'], progid, i = 0; i < 3;){
327 try{
328 progid = XMLHTTP_PROGIDS[i++];
329 if(new ActiveXObject(progid)){
330 // this progid works; therefore, use it from now on
331 break;
332 }
333 }catch(e){
334 // squelch; we're just trying to find a good ActiveX progid
335 // if they all fail, then progid ends up as the last attempt and that will signal the error
336 // the first time the client actually tries to exec an xhr
337 }
338 }
339 getXhr = function(){
340 return new ActiveXObject(progid);
341 };
342 }
343 req.getXhr = getXhr;
344
345 has.add("dojo-gettext-api", 1);
346 req.getText = function(url, async, onLoad){
347 var xhr = getXhr();
348 xhr.open('GET', fixupUrl(url), false);
349 xhr.send(null);
350 if(xhr.status == 200 || (!location.host && !xhr.status)){
351 if(onLoad){
352 onLoad(xhr.responseText, async);
353 }
354 }else{
355 throw makeError("xhrFailed", xhr.status);
356 }
357 return xhr.responseText;
358 };
359 }
360 }else{
361 req.async = 1;
362 }
363
364 //
365 // loader eval
366 //
367 var eval_ = has("csp-restrictions") ?
368 // noop eval if there are csp restrictions
369 function(){} :
370 // use the function constructor so our eval is scoped close to (but not in) in the global space with minimal pollution
371 new Function('return eval(arguments[0]);');
372
373 req.eval =
374 function(text, hint){
375 return eval_(text + "\r\n//# sourceURL=" + hint);
376 };
377
378 //
379 // loader micro events API
380 //
381 var listenerQueues = {},
382 error = "error",
383 signal = req.signal = function(type, args){
384 var queue = listenerQueues[type];
385 // notice we run a copy of the queue; this allows listeners to add/remove
386 // other listeners without affecting this particular signal
387 forEach(queue && queue.slice(0), function(listener){
388 listener.apply(null, isArray(args) ? args : [args]);
389 });
390 },
391 on = req.on = function(type, listener){
392 // notice a queue is not created until a client actually connects
393 var queue = listenerQueues[type] || (listenerQueues[type] = []);
394 queue.push(listener);
395 return {
396 remove:function(){
397 for(var i = 0; i<queue.length; i++){
398 if(queue[i]===listener){
399 queue.splice(i, 1);
400 return;
401 }
402 }
403 }
404 };
405 };
406
407 // configuration machinery; with an optimized/built defaultConfig, all configuration machinery can be discarded
408 // lexical variables hold key loader data structures to help with minification; these may be completely,
409 // one-time initialized by defaultConfig for optimized/built versions
410 var
411 aliases
412 // a vector of pairs of [regexs or string, replacement] => (alias, actual)
413 = [],
414
415 paths
416 // CommonJS paths
417 = {},
418
419 pathsMapProg
420 // list of (from-path, to-path, regex, length) derived from paths;
421 // a "program" to apply paths; see computeMapProg
422 = [],
423
424 packs
425 // a map from packageId to package configuration object; see fixupPackageInfo
426 = {},
427
428 map = req.map
429 // AMD map config variable; dojo/_base/kernel needs req.map to figure out the scope map
430 = {},
431
432 mapProgs
433 // vector of quads as described by computeMapProg; map-key is AMD map key, map-value is AMD map value
434 = [],
435
436 modules
437 // A hash:(mid) --> (module-object) the module namespace
438 //
439 // pid: the package identifier to which the module belongs (e.g., "dojo"); "" indicates the system or default package
440 // mid: the fully-resolved (i.e., mappings have been applied) module identifier without the package identifier (e.g., "dojo/io/script")
441 // url: the URL from which the module was retrieved
442 // pack: the package object of the package to which the module belongs
443 // executed: 0 => not executed; executing => in the process of traversing deps and running factory; executed => factory has been executed
444 // deps: the dependency vector for this module (vector of modules objects)
445 // def: the factory for this module
446 // result: the result of the running the factory for this module
447 // injected: (0 | requested | arrived) the status of the module; nonmodule means the resource did not call define
448 // load: plugin load function; applicable only for plugins
449 //
450 // Modules go through several phases in creation:
451 //
452 // 1. Requested: some other module's definition or a require application contained the requested module in
453 // its dependency vector or executing code explicitly demands a module via req.require.
454 //
455 // 2. Injected: a script element has been appended to the insert-point element demanding the resource implied by the URL
456 //
457 // 3. Loaded: the resource injected in [2] has been evaluated.
458 //
459 // 4. Defined: the resource contained a define statement that advised the loader about the module. Notice that some
460 // resources may just contain a bundle of code and never formally define a module via define
461 //
462 // 5. Evaluated: the module was defined via define and the loader has evaluated the factory and computed a result.
463 = {},
464
465 cacheBust
466 // query string to append to module URLs to bust browser cache
467 = "",
468
469 cache
470 // hash:(mid | url)-->(function | string)
471 //
472 // A cache of resources. The resources arrive via a config.cache object, which is a hash from either mid --> function or
473 // url --> string. The url key is distinguished from the mid key by always containing the prefix "url:". url keys as provided
474 // by config.cache always have a string value that represents the contents of the resource at the given url. mid keys as provided
475 // by configl.cache always have a function value that causes the same code to execute as if the module was script injected.
476 //
477 // Both kinds of key-value pairs are entered into cache via the function consumePendingCache, which may relocate keys as given
478 // by any mappings *iff* the config.cache was received as part of a module resource request.
479 //
480 // Further, for mid keys, the implied url is computed and the value is entered into that key as well. This allows mapped modules
481 // to retrieve cached items that may have arrived consequent to another namespace.
482 //
483 = {},
484
485 urlKeyPrefix
486 // the prefix to prepend to a URL key in the cache.
487 = "url:",
488
489 pendingCacheInsert
490 // hash:(mid)-->(function)
491 //
492 // Gives a set of cache modules pending entry into cache. When cached modules are published to the loader, they are
493 // entered into pendingCacheInsert; modules are then pressed into cache upon (1) AMD define or (2) upon receiving another
494 // independent set of cached modules. (1) is the usual case, and this case allows normalizing mids given in the pending
495 // cache for the local configuration, possibly relocating modules.
496 = {},
497
498 dojoSniffConfig
499 // map of configuration variables
500 // give the data-dojo-config as sniffed from the document (if any)
501 = {},
502
503 insertPointSibling
504 // the nodes used to locate where scripts are injected into the document
505 = 0;
506
507 if(has("dojo-config-api")){
508 var consumePendingCacheInsert = function(referenceModule, clear){
509 clear = clear !== false;
510 var p, item, match, now, m;
511 for(p in pendingCacheInsert){
512 item = pendingCacheInsert[p];
513 match = p.match(/^url\:(.+)/);
514 if(match){
515 cache[urlKeyPrefix + toUrl(match[1], referenceModule)] = item;
516 }else if(p=="*now"){
517 now = item;
518 }else if(p!="*noref"){
519 m = getModuleInfo(p, referenceModule, true);
520 cache[m.mid] = cache[urlKeyPrefix + m.url] = item;
521 }
522 }
523 if(now){
524 now(createRequire(referenceModule));
525 }
526 if(clear){
527 pendingCacheInsert = {};
528 }
529 },
530
531 escapeString = function(s){
532 return s.replace(/([\.$?*|{}\(\)\[\]\\\/\+^])/g, function(c){ return "\\" + c; });
533 },
534
535 computeMapProg = function(map, dest){
536 // This routine takes a map as represented by a JavaScript object and initializes dest, a vector of
537 // quads of (map-key, map-value, refex-for-map-key, length-of-map-key), sorted decreasing by length-
538 // of-map-key. The regex looks for the map-key followed by either "/" or end-of-string at the beginning
539 // of a the search source. Notice the map-value is irrelevant to the algorithm
540 dest.splice(0, dest.length);
541 for(var p in map){
542 dest.push([
543 p,
544 map[p],
545 new RegExp("^" + escapeString(p) + "(\/|$)"),
546 p.length]);
547 }
548 dest.sort(function(lhs, rhs){ return rhs[3] - lhs[3]; });
549 return dest;
550 },
551
552 computeAliases = function(config, dest){
553 forEach(config, function(pair){
554 // take a fixed-up copy...
555 dest.push([isString(pair[0]) ? new RegExp("^" + escapeString(pair[0]) + "$") : pair[0], pair[1]]);
556 });
557 },
558
559
560 fixupPackageInfo = function(packageInfo){
561 // calculate the precise (name, location, main, mappings) for a package
562 var name = packageInfo.name;
563 if(!name){
564 // packageInfo must be a string that gives the name
565 name = packageInfo;
566 packageInfo = {name:name};
567 }
568 packageInfo = mix({main:"main"}, packageInfo);
569 packageInfo.location = packageInfo.location ? packageInfo.location : name;
570
571 // packageMap is deprecated in favor of AMD map
572 if(packageInfo.packageMap){
573 map[name] = packageInfo.packageMap;
574 }
575
576 if(!packageInfo.main.indexOf("./")){
577 packageInfo.main = packageInfo.main.substring(2);
578 }
579
580 // now that we've got a fully-resolved package object, push it into the configuration
581 packs[name] = packageInfo;
582 },
583
584 delayedModuleConfig
585 // module config cannot be consumed until the loader is completely initialized; therefore, all
586 // module config detected during booting is memorized and applied at the end of loader initialization
587 // TODO: this is a bit of a kludge; all config should be moved to end of loader initialization, but
588 // we'll delay this chore and do it with a final loader 1.x cleanup after the 2.x loader prototyping is complete
589 = [],
590
591
592 config = function(config, booting, referenceModule){
593 for(var p in config){
594 if(p=="waitSeconds"){
595 req.waitms = (config[p] || 0) * 1000;
596 }
597 if(p=="cacheBust"){
598 cacheBust = config[p] ? (isString(config[p]) ? config[p] : (new Date()).getTime() + "") : "";
599 }
600 if(p=="baseUrl" || p=="combo"){
601 req[p] = config[p];
602 }
603 if(has("dojo-sync-loader") && p=="async"){
604 // falsy or "sync" => legacy sync loader
605 // "xd" => sync but loading xdomain tree and therefore loading asynchronously (not configurable, set automatically by the loader)
606 // "legacyAsync" => permanently in "xd" by choice
607 // "debugAtAllCosts" => trying to load everything via script injection (not implemented)
608 // otherwise, must be truthy => AMD
609 // legacyMode: sync | legacyAsync | xd | false
610 var mode = config[p];
611 req.legacyMode = legacyMode = (isString(mode) && /sync|legacyAsync/.test(mode) ? mode : (!mode ? sync : false));
612 req.async = !legacyMode;
613 }
614 if(config[p]!==hasCache){
615 // accumulate raw config info for client apps which can use this to pass their own config
616 req.rawConfig[p] = config[p];
617 p!="has" && has.add("config-"+p, config[p], 0, booting);
618 }
619 }
620
621 // make sure baseUrl exists
622 if(!req.baseUrl){
623 req.baseUrl = "./";
624 }
625 // make sure baseUrl ends with a slash
626 if(!/\/$/.test(req.baseUrl)){
627 req.baseUrl += "/";
628 }
629
630 // now do the special work for has, packages, packagePaths, paths, aliases, and cache
631
632 for(p in config.has){
633 has.add(p, config.has[p], 0, booting);
634 }
635
636 // for each package found in any packages config item, augment the packs map owned by the loader
637 forEach(config.packages, fixupPackageInfo);
638
639 // for each packagePath found in any packagePaths config item, augment the packageConfig
640 // packagePaths is deprecated; remove in 2.0
641 for(var baseUrl in config.packagePaths){
642 forEach(config.packagePaths[baseUrl], function(packageInfo){
643 var location = baseUrl + "/" + packageInfo;
644 if(isString(packageInfo)){
645 packageInfo = {name:packageInfo};
646 }
647 packageInfo.location = location;
648 fixupPackageInfo(packageInfo);
649 });
650 }
651
652 // notice that computeMapProg treats the dest as a reference; therefore, if/when that variable
653 // is published (see dojo-publish-privates), the published variable will always hold a valid value.
654
655 // this must come after all package processing since package processing may mutate map
656 computeMapProg(mix(map, config.map), mapProgs);
657 forEach(mapProgs, function(item){
658 item[1] = computeMapProg(item[1], []);
659 if(item[0]=="*"){
660 mapProgs.star = item;
661 }
662 });
663
664 // push in any paths and recompute the internal pathmap
665 computeMapProg(mix(paths, config.paths), pathsMapProg);
666
667 // aliases
668 computeAliases(config.aliases, aliases);
669
670 if(booting){
671 delayedModuleConfig.push({config:config.config});
672 }else{
673 for(p in config.config){
674 var module = getModule(p, referenceModule);
675 module.config = mix(module.config || {}, config.config[p]);
676 }
677 }
678
679 // push in any new cache values
680 if(config.cache){
681 consumePendingCacheInsert();
682 pendingCacheInsert = config.cache;
683 //inject now all depencies so cache is available for mapped module
684 consumePendingCacheInsert(0, !!config.cache["*noref"]);
685 }
686
687 signal("config", [config, req.rawConfig]);
688 };
689
690 //
691 // execute the various sniffs; userConfig can override and value
692 //
693
694 if(has("dojo-cdn") || has("dojo-sniff")){
695 // the sniff regex looks for a src attribute ending in dojo.js, optionally preceded with a path.
696 // match[3] returns the path to dojo.js (if any) without the trailing slash. This is used for the
697 // dojo location on CDN deployments and baseUrl when either/both of these are not provided
698 // explicitly in the config data; this is the 1.6- behavior.
699
700 var scripts = doc.getElementsByTagName("script"),
701 i = 0,
702 script, dojoDir, src, match;
703 while(i < scripts.length){
704 script = scripts[i++];
705 if((src = script.getAttribute("src")) && (match = src.match(/(((.*)\/)|^)dojo\.js(\W|$)/i))){
706 // sniff dojoDir and baseUrl
707 dojoDir = match[3] || "";
708 defaultConfig.baseUrl = defaultConfig.baseUrl || dojoDir;
709
710 // remember an insertPointSibling
711 insertPointSibling = script;
712 }
713
714 // sniff configuration on attribute in script element
715 if((src = (script.getAttribute("data-dojo-config") || script.getAttribute("djConfig")))){
716 dojoSniffConfig = req.eval("({ " + src + " })", "data-dojo-config");
717
718 // remember an insertPointSibling
719 insertPointSibling = script;
720 }
721
722 // sniff requirejs attribute
723 if(has("dojo-requirejs-api")){
724 if((src = script.getAttribute("data-main"))){
725 dojoSniffConfig.deps = dojoSniffConfig.deps || [src];
726 }
727 }
728 }
729 }
730
731 if(has("dojo-test-sniff")){
732 // pass down doh.testConfig from parent as if it were a data-dojo-config
733 try{
734 if(window.parent != window && window.parent.require){
735 var doh = window.parent.require("doh");
736 doh && mix(dojoSniffConfig, doh.testConfig);
737 }
738 }catch(e){}
739 }
740
741 // configure the loader; let the user override defaults
742 req.rawConfig = {};
743 config(defaultConfig, 1);
744
745 // do this before setting userConfig/sniffConfig to allow userConfig/sniff overrides
746 if(has("dojo-cdn")){
747 packs.dojo.location = dojoDir;
748 if(dojoDir){
749 dojoDir += "/";
750 }
751 packs.dijit.location = dojoDir + "../dijit/";
752 packs.dojox.location = dojoDir + "../dojox/";
753 }
754
755 config(userConfig, 1);
756 config(dojoSniffConfig, 1);
757
758 }else{
759 // no config API, assume defaultConfig has everything the loader needs...for the entire lifetime of the application
760 paths = defaultConfig.paths;
761 pathsMapProg = defaultConfig.pathsMapProg;
762 packs = defaultConfig.packs;
763 aliases = defaultConfig.aliases;
764 mapProgs = defaultConfig.mapProgs;
765 modules = defaultConfig.modules;
766 cache = defaultConfig.cache;
767 cacheBust = defaultConfig.cacheBust;
768
769 // remember the default config for other processes (e.g., dojo/config)
770 req.rawConfig = defaultConfig;
771 }
772
773
774 if(has("dojo-combo-api")){
775 req.combo = req.combo || {add:noop};
776 var comboPending = 0,
777 combosPending = [],
778 comboPendingTimer = null;
779 }
780
781
782 // build the loader machinery iaw configuration, including has feature tests
783 var injectDependencies = function(module){
784 // checkComplete!=0 holds the idle signal; we're not idle if we're injecting dependencies
785 guardCheckComplete(function(){
786 forEach(module.deps, injectModule);
787 if(has("dojo-combo-api") && comboPending && !comboPendingTimer){
788 comboPendingTimer = setTimeout(function() {
789 comboPending = 0;
790 comboPendingTimer = null;
791 req.combo.done(function(mids, url) {
792 var onLoadCallback= function(){
793 // defQ is a vector of module definitions 1-to-1, onto mids
794 runDefQ(0, mids);
795 checkComplete();
796 };
797 combosPending.push(mids);
798 injectingModule = mids;
799 req.injectUrl(url, onLoadCallback, mids);
800 injectingModule = 0;
801 }, req);
802 }, 0);
803 }
804 });
805 },
806
807 contextRequire = function(a1, a2, a3, referenceModule, contextRequire){
808 var module, syntheticMid;
809 if(isString(a1)){
810 // signature is (moduleId)
811 module = getModule(a1, referenceModule, true);
812 if(module && module.executed){
813 return module.result;
814 }
815 throw makeError("undefinedModule", a1);
816 }
817 if(!isArray(a1)){
818 // a1 is a configuration
819 config(a1, 0, referenceModule);
820
821 // juggle args; (a2, a3) may be (dependencies, callback)
822 a1 = a2;
823 a2 = a3;
824 }
825 if(isArray(a1)){
826 // signature is (requestList [,callback])
827 if(!a1.length){
828 a2 && a2();
829 }else{
830 syntheticMid = "require*" + uid();
831
832 // resolve the request list with respect to the reference module
833 for(var mid, deps = [], i = 0; i < a1.length;){
834 mid = a1[i++];
835 deps.push(getModule(mid, referenceModule));
836 }
837
838 // construct a synthetic module to control execution of the requestList, and, optionally, callback
839 module = mix(makeModuleInfo("", syntheticMid, 0, ""), {
840 injected: arrived,
841 deps: deps,
842 def: a2 || noop,
843 require: referenceModule ? referenceModule.require : req,
844 gc: 1 //garbage collect
845 });
846 modules[module.mid] = module;
847
848 // checkComplete!=0 holds the idle signal; we're not idle if we're injecting dependencies
849 injectDependencies(module);
850
851 // try to immediately execute
852 // if already traversing a factory tree, then strict causes circular dependency to abort the execution; maybe
853 // it's possible to execute this require later after the current traversal completes and avoid the circular dependency.
854 // ...but *always* insist on immediate in synch mode
855 var strict = checkCompleteGuard && legacyMode!=sync;
856 guardCheckComplete(function(){
857 execModule(module, strict);
858 });
859 if(!module.executed){
860 // some deps weren't on board or circular dependency detected and strict; therefore, push into the execQ
861 execQ.push(module);
862 }
863 checkComplete();
864 }
865 }
866 return contextRequire;
867 },
868
869 createRequire = function(module){
870 if(!module){
871 return req;
872 }
873 var result = module.require;
874 if(!result){
875 result = function(a1, a2, a3){
876 return contextRequire(a1, a2, a3, module, result);
877 };
878 module.require = mix(result, req);
879 result.module = module;
880 result.toUrl = function(name){
881 return toUrl(name, module);
882 };
883 result.toAbsMid = function(mid){
884 return toAbsMid(mid, module);
885 };
886 if(has("dojo-undef-api")){
887 result.undef = function(mid){
888 req.undef(mid, module);
889 };
890 }
891 if(has("dojo-sync-loader")){
892 result.syncLoadNls = function(mid){
893 var nlsModuleInfo = getModuleInfo(mid, module),
894 nlsModule = modules[nlsModuleInfo.mid];
895 if(!nlsModule || !nlsModule.executed){
896 cached = cache[nlsModuleInfo.mid] || cache[urlKeyPrefix + nlsModuleInfo.url];
897 if(cached){
898 evalModuleText(cached);
899 nlsModule = modules[nlsModuleInfo.mid];
900 }
901 }
902 return nlsModule && nlsModule.executed && nlsModule.result;
903 };
904 }
905
906 }
907 return result;
908 },
909
910 execQ =
911 // The list of modules that need to be evaluated.
912 [],
913
914 defQ =
915 // The queue of define arguments sent to loader.
916 [],
917
918 waiting =
919 // The set of modules upon which the loader is waiting for definition to arrive
920 {},
921
922 setRequested = function(module){
923 module.injected = requested;
924 waiting[module.mid] = 1;
925 if(module.url){
926 waiting[module.url] = module.pack || 1;
927 }
928 startTimer();
929 },
930
931 setArrived = function(module){
932 module.injected = arrived;
933 delete waiting[module.mid];
934 if(module.url){
935 delete waiting[module.url];
936 }
937 if(isEmpty(waiting)){
938 clearTimer();
939 has("dojo-sync-loader") && legacyMode==xd && (legacyMode = sync);
940 }
941 },
942
943 execComplete = req.idle =
944 // says the loader has completed (or not) its work
945 function(){
946 return !defQ.length && isEmpty(waiting) && !execQ.length && !checkCompleteGuard;
947 },
948
949 runMapProg = function(targetMid, map){
950 // search for targetMid in map; return the map item if found; falsy otherwise
951 if(map){
952 for(var i = 0; i < map.length; i++){
953 if(map[i][2].test(targetMid)){
954 return map[i];
955 }
956 }
957 }
958 return 0;
959 },
960
961 compactPath = function(path){
962 var result = [],
963 segment, lastSegment;
964 path = path.replace(/\\/g, '/').split('/');
965 while(path.length){
966 segment = path.shift();
967 if(segment==".." && result.length && lastSegment!=".."){
968 result.pop();
969 lastSegment = result[result.length - 1];
970 }else if(segment!="."){
971 result.push(lastSegment= segment);
972 } // else ignore "."
973 }
974 return result.join("/");
975 },
976
977 makeModuleInfo = function(pid, mid, pack, url){
978 if(has("dojo-sync-loader")){
979 var xd= req.isXdUrl(url);
980 return {pid:pid, mid:mid, pack:pack, url:url, executed:0, def:0, isXd:xd, isAmd:!!(xd || (packs[pid] && packs[pid].isAmd))};
981 }else{
982 return {pid:pid, mid:mid, pack:pack, url:url, executed:0, def:0};
983 }
984 },
985
986 getModuleInfo_ = function(mid, referenceModule, packs, modules, baseUrl, mapProgs, pathsMapProg, aliases, alwaysCreate, fromPendingCache){
987 // arguments are passed instead of using lexical variables so that this function my be used independent of the loader (e.g., the builder)
988 // alwaysCreate is useful in this case so that getModuleInfo never returns references to real modules owned by the loader
989 var pid, pack, midInPackage, mapItem, url, result, isRelative, requestedMid;
990 requestedMid = mid;
991 isRelative = /^\./.test(mid);
992 if(/(^\/)|(\:)|(\.js$)/.test(mid) || (isRelative && !referenceModule)){
993 // absolute path or protocol of .js filetype, or relative path but no reference module and therefore relative to page
994 // whatever it is, it's not a module but just a URL of some sort
995 // note: pid===0 indicates the routine is returning an unmodified mid
996
997 return makeModuleInfo(0, mid, 0, mid);
998 }else{
999 // relative module ids are relative to the referenceModule; get rid of any dots
1000 mid = compactPath(isRelative ? (referenceModule.mid + "/../" + mid) : mid);
1001 if(/^\./.test(mid)){
1002 throw makeError("irrationalPath", mid);
1003 }
1004 // at this point, mid is an absolute mid
1005
1006 // map the mid
1007 if(!fromPendingCache && !isRelative && mapProgs.star){
1008 mapItem = runMapProg(mid, mapProgs.star[1]);
1009 }
1010 if(!mapItem && referenceModule){
1011 mapItem = runMapProg(referenceModule.mid, mapProgs);
1012 mapItem = mapItem && runMapProg(mid, mapItem[1]);
1013 }
1014
1015 if(mapItem){
1016 mid = mapItem[1] + mid.substring(mapItem[3]);
1017 }
1018
1019 match = mid.match(/^([^\/]+)(\/(.+))?$/);
1020 pid = match ? match[1] : "";
1021 if((pack = packs[pid])){
1022 mid = pid + "/" + (midInPackage = (match[3] || pack.main));
1023 }else{
1024 pid = "";
1025 }
1026
1027 // search aliases
1028 var candidateLength = 0,
1029 candidate = 0;
1030 forEach(aliases, function(pair){
1031 var match = mid.match(pair[0]);
1032 if(match && match.length>candidateLength){
1033 candidate = isFunction(pair[1]) ? mid.replace(pair[0], pair[1]) : pair[1];
1034 }
1035 });
1036 if(candidate){
1037 return getModuleInfo_(candidate, 0, packs, modules, baseUrl, mapProgs, pathsMapProg, aliases, alwaysCreate);
1038 }
1039
1040 result = modules[mid];
1041 if(result){
1042 return alwaysCreate ? makeModuleInfo(result.pid, result.mid, result.pack, result.url) : modules[mid];
1043 }
1044 }
1045 // get here iff the sought-after module does not yet exist; therefore, we need to compute the URL given the
1046 // fully resolved (i.e., all relative indicators and package mapping resolved) module id
1047
1048 // note: pid!==0 indicates the routine is returning a url that has .js appended unmodified mid
1049 mapItem = runMapProg(mid, pathsMapProg);
1050 if(mapItem){
1051 url = mapItem[1] + mid.substring(mapItem[3]);
1052 }else if(pid){
1053 url = pack.location + "/" + midInPackage;
1054 }else if(has("config-tlmSiblingOfDojo")){
1055 url = "../" + mid;
1056 }else{
1057 url = mid;
1058 }
1059 // if result is not absolute, add baseUrl
1060 if(!(/(^\/)|(\:)/.test(url))){
1061 url = baseUrl + url;
1062 }
1063 url += ".js";
1064 return makeModuleInfo(pid, mid, pack, compactPath(url));
1065 },
1066
1067 getModuleInfo = function(mid, referenceModule, fromPendingCache){
1068 return getModuleInfo_(mid, referenceModule, packs, modules, req.baseUrl, mapProgs, pathsMapProg, aliases, undefined, fromPendingCache);
1069 },
1070
1071 resolvePluginResourceId = function(plugin, prid, referenceModule){
1072 return plugin.normalize ? plugin.normalize(prid, function(mid){return toAbsMid(mid, referenceModule);}) : toAbsMid(prid, referenceModule);
1073 },
1074
1075 dynamicPluginUidGenerator = 0,
1076
1077 getModule = function(mid, referenceModule, immediate){
1078 // compute and optionally construct (if necessary) the module implied by the mid with respect to referenceModule
1079 var match, plugin, prid, result;
1080 match = mid.match(/^(.+?)\!(.*)$/);
1081 if(match){
1082 // name was <plugin-module>!<plugin-resource-id>
1083 plugin = getModule(match[1], referenceModule, immediate);
1084
1085 if(has("dojo-sync-loader") && legacyMode == sync && !plugin.executed){
1086 injectModule(plugin);
1087 if(plugin.injected===arrived && !plugin.executed){
1088 guardCheckComplete(function(){
1089 execModule(plugin);
1090 });
1091 }
1092 if(plugin.executed){
1093 promoteModuleToPlugin(plugin);
1094 }else{
1095 // we are in xdomain mode for some reason
1096 execQ.unshift(plugin);
1097 }
1098 }
1099
1100
1101
1102 if(plugin.executed === executed && !plugin.load){
1103 // executed the module not knowing it was a plugin
1104 promoteModuleToPlugin(plugin);
1105 }
1106
1107 // if the plugin has not been loaded, then can't resolve the prid and must assume this plugin is dynamic until we find out otherwise
1108 if(plugin.load){
1109 prid = resolvePluginResourceId(plugin, match[2], referenceModule);
1110 mid = (plugin.mid + "!" + (plugin.dynamic ? ++dynamicPluginUidGenerator + "!" : "") + prid);
1111 }else{
1112 prid = match[2];
1113 mid = plugin.mid + "!" + (++dynamicPluginUidGenerator) + "!waitingForPlugin";
1114 }
1115 result = {plugin:plugin, mid:mid, req:createRequire(referenceModule), prid:prid};
1116 }else{
1117 result = getModuleInfo(mid, referenceModule);
1118 }
1119 return modules[result.mid] || (!immediate && (modules[result.mid] = result));
1120 },
1121
1122 toAbsMid = req.toAbsMid = function(mid, referenceModule){
1123 return getModuleInfo(mid, referenceModule).mid;
1124 },
1125
1126 toUrl = req.toUrl = function(name, referenceModule){
1127 var moduleInfo = getModuleInfo(name+"/x", referenceModule),
1128 url= moduleInfo.url;
1129 return fixupUrl(moduleInfo.pid===0 ?
1130 // if pid===0, then name had a protocol or absolute path; either way, toUrl is the identify function in such cases
1131 name :
1132 // "/x.js" since getModuleInfo automatically appends ".js" and we appended "/x" to make name look like a module id
1133 url.substring(0, url.length-5)
1134 );
1135 },
1136
1137 nonModuleProps = {
1138 injected: arrived,
1139 executed: executed,
1140 def: nonmodule,
1141 result: nonmodule
1142 },
1143
1144 makeCjs = function(mid){
1145 return modules[mid] = mix({mid:mid}, nonModuleProps);
1146 },
1147
1148 cjsRequireModule = makeCjs("require"),
1149 cjsExportsModule = makeCjs("exports"),
1150 cjsModuleModule = makeCjs("module"),
1151
1152 runFactory = function(module, args){
1153 req.trace("loader-run-factory", [module.mid]);
1154 var factory = module.def,
1155 result;
1156 has("dojo-sync-loader") && syncExecStack.unshift(module);
1157 if(has("config-dojo-loader-catches")){
1158 try{
1159 result= isFunction(factory) ? factory.apply(null, args) : factory;
1160 }catch(e){
1161 signal(error, module.result = makeError("factoryThrew", [module, e]));
1162 }
1163 }else{
1164 result= isFunction(factory) ? factory.apply(null, args) : factory;
1165 }
1166 module.result = result===undefined && module.cjs ? module.cjs.exports : result;
1167 has("dojo-sync-loader") && syncExecStack.shift(module);
1168 },
1169
1170 abortExec = {},
1171
1172 defOrder = 0,
1173
1174 promoteModuleToPlugin = function(pluginModule){
1175 var plugin = pluginModule.result;
1176 pluginModule.dynamic = plugin.dynamic;
1177 pluginModule.normalize = plugin.normalize;
1178 pluginModule.load = plugin.load;
1179 return pluginModule;
1180 },
1181
1182 resolvePluginLoadQ = function(plugin){
1183 // plugins is a newly executed module that has a loadQ waiting to run
1184
1185 // step 1: traverse the loadQ and fixup the mid and prid; remember the map from original mid to new mid
1186 // recall the original mid was created before the plugin was on board and therefore it was impossible to
1187 // compute the final mid; accordingly, prid may or may not change, but the mid will definitely change
1188 var map = {};
1189 forEach(plugin.loadQ, function(pseudoPluginResource){
1190 // manufacture and insert the real module in modules
1191 var prid = resolvePluginResourceId(plugin, pseudoPluginResource.prid, pseudoPluginResource.req.module),
1192 mid = plugin.dynamic ? pseudoPluginResource.mid.replace(/waitingForPlugin$/, prid) : (plugin.mid + "!" + prid),
1193 pluginResource = mix(mix({}, pseudoPluginResource), {mid:mid, prid:prid, injected:0});
1194 if(!modules[mid] || !modules[mid].injected /*for require.undef*/){
1195 // create a new (the real) plugin resource and inject it normally now that the plugin is on board
1196 injectPlugin(modules[mid] = pluginResource);
1197 } // else this was a duplicate request for the same (plugin, rid) for a nondynamic plugin
1198
1199 // pluginResource is really just a placeholder with the wrong mid (because we couldn't calculate it until the plugin was on board)
1200 // mark is as arrived and delete it from modules; the real module was requested above
1201 map[pseudoPluginResource.mid] = modules[mid];
1202 setArrived(pseudoPluginResource);
1203 delete modules[pseudoPluginResource.mid];
1204 });
1205 plugin.loadQ = 0;
1206
1207 // step2: replace all references to any placeholder modules with real modules
1208 var substituteModules = function(module){
1209 for(var replacement, deps = module.deps || [], i = 0; i<deps.length; i++){
1210 replacement = map[deps[i].mid];
1211 if(replacement){
1212 deps[i] = replacement;
1213 }
1214 }
1215 };
1216 for(var p in modules){
1217 substituteModules(modules[p]);
1218 }
1219 forEach(execQ, substituteModules);
1220 },
1221
1222 finishExec = function(module){
1223 req.trace("loader-finish-exec", [module.mid]);
1224 module.executed = executed;
1225 module.defOrder = defOrder++;
1226 has("dojo-sync-loader") && forEach(module.provides, function(cb){ cb(); });
1227 if(module.loadQ){
1228 // the module was a plugin
1229 promoteModuleToPlugin(module);
1230 resolvePluginLoadQ(module);
1231 }
1232 // remove all occurrences of this module from the execQ
1233 for(i = 0; i < execQ.length;){
1234 if(execQ[i] === module){
1235 execQ.splice(i, 1);
1236 }else{
1237 i++;
1238 }
1239 }
1240 // delete references to synthetic modules
1241 if (/^require\*/.test(module.mid)) {
1242 delete modules[module.mid];
1243 }
1244 },
1245
1246 circleTrace = [],
1247
1248 execModule = function(module, strict){
1249 // run the dependency vector, then run the factory for module
1250 if(module.executed === executing){
1251 req.trace("loader-circular-dependency", [circleTrace.concat(module.mid).join("->")]);
1252 return (!module.def || strict) ? abortExec : (module.cjs && module.cjs.exports);
1253 }
1254 // at this point the module is either not executed or fully executed
1255
1256
1257 if(!module.executed){
1258 if(!module.def){
1259 return abortExec;
1260 }
1261 var mid = module.mid,
1262 deps = module.deps || [],
1263 arg, argResult,
1264 args = [],
1265 i = 0;
1266
1267 if(has("dojo-trace-api")){
1268 circleTrace.push(mid);
1269 req.trace("loader-exec-module", ["exec", circleTrace.length, mid]);
1270 }
1271
1272 // for circular dependencies, assume the first module encountered was executed OK
1273 // modules that circularly depend on a module that has not run its factory will get
1274 // the pre-made cjs.exports===module.result. They can take a reference to this object and/or
1275 // add properties to it. When the module finally runs its factory, the factory can
1276 // read/write/replace this object. Notice that so long as the object isn't replaced, any
1277 // reference taken earlier while walking the deps list is still valid.
1278 module.executed = executing;
1279 while((arg = deps[i++])){
1280 argResult = ((arg === cjsRequireModule) ? createRequire(module) :
1281 ((arg === cjsExportsModule) ? module.cjs.exports :
1282 ((arg === cjsModuleModule) ? module.cjs :
1283 execModule(arg, strict))));
1284 if(argResult === abortExec){
1285 module.executed = 0;
1286 req.trace("loader-exec-module", ["abort", mid]);
1287 has("dojo-trace-api") && circleTrace.pop();
1288 return abortExec;
1289 }
1290 args.push(argResult);
1291 }
1292 runFactory(module, args);
1293 finishExec(module);
1294 has("dojo-trace-api") && circleTrace.pop();
1295 }
1296 // at this point the module is guaranteed fully executed
1297
1298 return module.result;
1299 },
1300
1301
1302 checkCompleteGuard = 0,
1303
1304 guardCheckComplete = function(proc){
1305 try{
1306 checkCompleteGuard++;
1307 proc();
1308 }catch(e){
1309 // https://bugs.dojotoolkit.org/ticket/16617
1310 throw e;
1311 }finally{
1312 checkCompleteGuard--;
1313 }
1314 if(execComplete()){
1315 signal("idle", []);
1316 }
1317 },
1318
1319 checkComplete = function(){
1320 // keep going through the execQ as long as at least one factory is executed
1321 // plugins, recursion, cached modules all make for many execution path possibilities
1322 if(checkCompleteGuard){
1323 return;
1324 }
1325 guardCheckComplete(function(){
1326 checkDojoRequirePlugin();
1327 for(var currentDefOrder, module, i = 0; i < execQ.length;){
1328 currentDefOrder = defOrder;
1329 module = execQ[i];
1330 execModule(module);
1331 if(currentDefOrder!=defOrder){
1332 // defOrder was bumped one or more times indicating something was executed (note, this indicates
1333 // the execQ was modified, maybe a lot (for example a later module causes an earlier module to execute)
1334 checkDojoRequirePlugin();
1335 i = 0;
1336 }else{
1337 // nothing happened; check the next module in the exec queue
1338 i++;
1339 }
1340 }
1341 });
1342 },
1343
1344 fixupUrl= typeof userConfig.fixupUrl == "function" ? userConfig.fixupUrl : function(url){
1345 url += ""; // make sure url is a Javascript string (some paths may be a Java string)
1346 return url + (cacheBust ? ((/\?/.test(url) ? "&" : "?") + cacheBust) : "");
1347 };
1348
1349
1350
1351 if(has("dojo-undef-api")){
1352 req.undef = function(moduleId, referenceModule){
1353 // In order to reload a module, it must be undefined (this routine) and then re-requested.
1354 // This is useful for testing frameworks (at least).
1355 var module = getModule(moduleId, referenceModule);
1356 setArrived(module);
1357 mix(module, {def:0, executed:0, injected:0, node:0, load:0});
1358 };
1359 }
1360
1361 if(has("dojo-inject-api")){
1362 if(has("dojo-loader-eval-hint-url")===undefined){
1363 has.add("dojo-loader-eval-hint-url", 1);
1364 }
1365
1366 var injectPlugin = function(
1367 module
1368 ){
1369 // injects the plugin module given by module; may have to inject the plugin itself
1370 var plugin = module.plugin;
1371
1372 if(plugin.executed === executed && !plugin.load){
1373 // executed the module not knowing it was a plugin
1374 promoteModuleToPlugin(plugin);
1375 }
1376
1377 var onLoad = function(def){
1378 module.result = def;
1379 setArrived(module);
1380 finishExec(module);
1381 checkComplete();
1382 };
1383
1384 if(plugin.load){
1385 plugin.load(module.prid, module.req, onLoad);
1386 }else if(plugin.loadQ){
1387 plugin.loadQ.push(module);
1388 }else{
1389 // the unshift instead of push is important: we don't want plugins to execute as
1390 // dependencies of some other module because this may cause circles when the plugin
1391 // loadQ is run; also, generally, we want plugins to run early since they may load
1392 // several other modules and therefore can potentially unblock many modules
1393 plugin.loadQ = [module];
1394 execQ.unshift(plugin);
1395 injectModule(plugin);
1396 }
1397 },
1398
1399 // for IE, injecting a module may result in a recursive execution if the module is in the cache
1400
1401 cached = 0,
1402
1403 injectingModule = 0,
1404
1405 injectingCachedModule = 0,
1406
1407 evalModuleText = function(text, module){
1408 // see def() for the injectingCachedModule bracket; it simply causes a short, safe circuit
1409 if(has("config-stripStrict")){
1410 text = text.replace(/(["'])use strict\1/g, '');
1411 }
1412 injectingCachedModule = 1;
1413 if(has("config-dojo-loader-catches")){
1414 try{
1415 if(text===cached){
1416 cached.call(null);
1417 }else{
1418 req.eval(text, has("dojo-loader-eval-hint-url") ? module.url : module.mid);
1419 }
1420 }catch(e){
1421 signal(error, makeError("evalModuleThrew", module));
1422 }
1423 }else{
1424 if(text===cached){
1425 cached.call(null);
1426 }else{
1427 req.eval(text, has("dojo-loader-eval-hint-url") ? module.url : module.mid);
1428 }
1429 }
1430 injectingCachedModule = 0;
1431 },
1432
1433 injectModule = function(module){
1434 // Inject the module. In the browser environment, this means appending a script element into
1435 // the document; in other environments, it means loading a file.
1436 //
1437 // If in synchronous mode, then get the module synchronously if it's not xdomainLoading.
1438
1439 var mid = module.mid,
1440 url = module.url;
1441 if(module.executed || module.injected || waiting[mid] || (module.url && ((module.pack && waiting[module.url]===module.pack) || waiting[module.url]==1))){
1442 return;
1443 }
1444 setRequested(module);
1445
1446 if(has("dojo-combo-api")){
1447 var viaCombo = 0;
1448 if(module.plugin && module.plugin.isCombo){
1449 // a combo plugin; therefore, must be handled by combo service
1450 // the prid should have already been converted to a URL (if required by the plugin) during
1451 // the normalize process; in any event, there is no way for the loader to know how to
1452 // to the conversion; therefore the third argument is zero
1453 req.combo.add(module.plugin.mid, module.prid, 0, req);
1454 viaCombo = 1;
1455 }else if(!module.plugin){
1456 viaCombo = req.combo.add(0, module.mid, module.url, req);
1457 }
1458 if(viaCombo){
1459 comboPending= 1;
1460 return;
1461 }
1462 }
1463
1464 if(module.plugin){
1465 injectPlugin(module);
1466 return;
1467 } // else a normal module (not a plugin)
1468
1469
1470 var onLoadCallback = function(){
1471 runDefQ(module);
1472 if(module.injected !== arrived){
1473 // the script that contained the module arrived and has been executed yet
1474 // nothing was added to the defQ (so it wasn't an AMD module) and the module
1475 // wasn't marked as arrived by dojo.provide (so it wasn't a v1.6- module);
1476 // therefore, it must not have been a module; adjust state accordingly
1477 if(has("dojo-enforceDefine")){
1478 signal(error, makeError("noDefine", module));
1479 return;
1480 }
1481 setArrived(module);
1482 mix(module, nonModuleProps);
1483 req.trace("loader-define-nonmodule", [module.url]);
1484 }
1485
1486 if(has("dojo-sync-loader") && legacyMode){
1487 // must call checkComplete even in for sync loader because we may be in xdomainLoading mode;
1488 // but, if xd loading, then don't call checkComplete until out of the current sync traversal
1489 // in order to preserve order of execution of the dojo.required modules
1490 !syncExecStack.length && checkComplete();
1491 }else{
1492 checkComplete();
1493 }
1494 };
1495 cached = cache[mid] || cache[urlKeyPrefix + module.url];
1496 if(cached){
1497 req.trace("loader-inject", ["cache", module.mid, url]);
1498 evalModuleText(cached, module);
1499 onLoadCallback();
1500 return;
1501 }
1502 if(has("dojo-sync-loader") && legacyMode){
1503 if(module.isXd){
1504 // switch to async mode temporarily; if current legacyMode!=sync, then is must be one of {legacyAsync, xd, false}
1505 legacyMode==sync && (legacyMode = xd);
1506 // fall through and load via script injection
1507 }else if(module.isAmd && legacyMode!=sync){
1508 // fall through and load via script injection
1509 }else{
1510 // mode may be sync, xd/legacyAsync, or async; module may be AMD or legacy; but module is always located on the same domain
1511 var xhrCallback = function(text){
1512 if(legacyMode==sync){
1513 // the top of syncExecStack gives the current synchronously executing module; the loader needs
1514 // to know this if it has to switch to async loading in the middle of evaluating a legacy module
1515 // this happens when a modules dojo.require's a module that must be loaded async because it's xdomain
1516 // (using unshift/shift because there is no back() methods for Javascript arrays)
1517 syncExecStack.unshift(module);
1518 evalModuleText(text, module);
1519 syncExecStack.shift();
1520
1521 // maybe the module was an AMD module
1522 runDefQ(module);
1523
1524 // legacy modules never get to defineModule() => cjs and injected never set; also evaluation implies executing
1525 if(!module.cjs){
1526 setArrived(module);
1527 finishExec(module);
1528 }
1529
1530 if(module.finish){
1531 // while synchronously evaluating this module, dojo.require was applied referencing a module
1532 // that had to be loaded async; therefore, the loader stopped answering all dojo.require
1533 // requests so they could be answered completely in the correct sequence; module.finish gives
1534 // the list of dojo.requires that must be re-applied once all target modules are available;
1535 // make a synthetic module to execute the dojo.require's in the correct order
1536
1537 // compute a guaranteed-unique mid for the synthetic finish module; remember the finish vector; remove it from the reference module
1538 // TODO: can we just leave the module.finish...what's it hurting?
1539 var finishMid = mid + "*finish",
1540 finish = module.finish;
1541 delete module.finish;
1542
1543 def(finishMid, ["dojo", ("dojo/require!" + finish.join(",")).replace(/\./g, "/")], function(dojo){
1544 forEach(finish, function(mid){ dojo.require(mid); });
1545 });
1546 // unshift, not push, which causes the current traversal to be reattempted from the top
1547 execQ.unshift(getModule(finishMid));
1548 }
1549 onLoadCallback();
1550 }else{
1551 text = transformToAmd(module, text);
1552 if(text){
1553 evalModuleText(text, module);
1554 onLoadCallback();
1555 }else{
1556 // if transformToAmd returned falsy, then the module was already AMD and it can be script-injected
1557 // do so to improve debugability(even though it means another download...which probably won't happen with a good browser cache)
1558 injectingModule = module;
1559 req.injectUrl(fixupUrl(url), onLoadCallback, module);
1560 injectingModule = 0;
1561 }
1562 }
1563 };
1564
1565 req.trace("loader-inject", ["xhr", module.mid, url, legacyMode!=sync]);
1566 if(has("config-dojo-loader-catches")){
1567 try{
1568 req.getText(url, legacyMode!=sync, xhrCallback);
1569 }catch(e){
1570 signal(error, makeError("xhrInjectFailed", [module, e]));
1571 }
1572 }else{
1573 req.getText(url, legacyMode!=sync, xhrCallback);
1574 }
1575 return;
1576 }
1577 } // else async mode or fell through in xdomain loading mode; either way, load by script injection
1578 req.trace("loader-inject", ["script", module.mid, url]);
1579 injectingModule = module;
1580 req.injectUrl(fixupUrl(url), onLoadCallback, module);
1581 injectingModule = 0;
1582 },
1583
1584 defineModule = function(module, deps, def){
1585 req.trace("loader-define-module", [module.mid, deps]);
1586
1587 if(has("dojo-combo-api") && module.plugin && module.plugin.isCombo){
1588 // the module is a plugin resource loaded by the combo service
1589 // note: check for module.plugin should be enough since normal plugin resources should
1590 // not follow this path; module.plugin.isCombo is future-proofing belt and suspenders
1591 module.result = isFunction(def) ? def() : def;
1592 setArrived(module);
1593 finishExec(module);
1594 return module;
1595 }
1596
1597 var mid = module.mid;
1598 if(module.injected === arrived){
1599 signal(error, makeError("multipleDefine", module));
1600 return module;
1601 }
1602 mix(module, {
1603 deps: deps,
1604 def: def,
1605 cjs: {
1606 id: module.mid,
1607 uri: module.url,
1608 exports: (module.result = {}),
1609 setExports: function(exports){
1610 module.cjs.exports = exports;
1611 },
1612 config:function(){
1613 return module.config;
1614 }
1615 }
1616 });
1617
1618 // resolve deps with respect to this module
1619 for(var i = 0; deps[i]; i++){
1620 deps[i] = getModule(deps[i], module);
1621 }
1622
1623 if(has("dojo-sync-loader") && legacyMode && !waiting[mid]){
1624 // the module showed up without being asked for; it was probably in a <script> element
1625 injectDependencies(module);
1626 execQ.push(module);
1627 checkComplete();
1628 }
1629 setArrived(module);
1630
1631 if(!isFunction(def) && !deps.length){
1632 module.result = def;
1633 finishExec(module);
1634 }
1635
1636 return module;
1637 },
1638
1639 runDefQ = function(referenceModule, mids){
1640 // defQ is an array of [id, dependencies, factory]
1641 // mids (if any) is a vector of mids given by a combo service
1642 var definedModules = [],
1643 module, args;
1644 while(defQ.length){
1645 args = defQ.shift();
1646 mids && (args[0]= mids.shift());
1647 // explicit define indicates possible multiple modules in a single file; delay injecting dependencies until defQ fully
1648 // processed since modules earlier in the queue depend on already-arrived modules that are later in the queue
1649 // TODO: what if no args[0] and no referenceModule
1650 module = (args[0] && getModule(args[0])) || referenceModule;
1651 definedModules.push([module, args[1], args[2]]);
1652 }
1653 consumePendingCacheInsert(referenceModule);
1654 forEach(definedModules, function(args){
1655 injectDependencies(defineModule.apply(null, args));
1656 });
1657 };
1658 }
1659
1660 var timerId = 0,
1661 clearTimer = noop,
1662 startTimer = noop;
1663 if(has("dojo-timeout-api")){
1664 // Timer machinery that monitors how long the loader is waiting and signals an error when the timer runs out.
1665 clearTimer = function(){
1666 timerId && clearTimeout(timerId);
1667 timerId = 0;
1668 };
1669
1670 startTimer = function(){
1671 clearTimer();
1672 if(req.waitms){
1673 timerId = global.setTimeout(function(){
1674 clearTimer();
1675 signal(error, makeError("timeout", waiting));
1676 }, req.waitms);
1677 }
1678 };
1679 }
1680
1681 if (has("dom")) {
1682 // Test for IE's different way of signaling when scripts finish loading. Note that according to
1683 // http://bugs.dojotoolkit.org/ticket/15096#comment:14, IE9 also needs to follow the
1684 // IE specific code path even though it has an addEventListener() method.
1685 // Unknown if special path needed on IE10+, which also has a document.attachEvent() method.
1686 // Should evaluate to false for Opera and Windows 8 apps, even though they document.attachEvent()
1687 // is defined in both those environments.
1688 has.add("ie-event-behavior", doc.attachEvent && typeof Windows === "undefined" &&
1689 (typeof opera === "undefined" || opera.toString() != "[object Opera]"));
1690 }
1691
1692 if(has("dom") && (has("dojo-inject-api") || has("dojo-dom-ready-api"))){
1693 var domOn = function(node, eventName, ieEventName, handler){
1694 // Add an event listener to a DOM node using the API appropriate for the current browser;
1695 // return a function that will disconnect the listener.
1696 if(!has("ie-event-behavior")){
1697 node.addEventListener(eventName, handler, false);
1698 return function(){
1699 node.removeEventListener(eventName, handler, false);
1700 };
1701 }else{
1702 node.attachEvent(ieEventName, handler);
1703 return function(){
1704 node.detachEvent(ieEventName, handler);
1705 };
1706 }
1707 },
1708 windowOnLoadListener = domOn(window, "load", "onload", function(){
1709 req.pageLoaded = 1;
1710 // https://bugs.dojotoolkit.org/ticket/16248
1711 try{
1712 doc.readyState!="complete" && (doc.readyState = "complete");
1713 }catch(e){
1714 }
1715 windowOnLoadListener();
1716 });
1717
1718 if(has("dojo-inject-api")){
1719 // if the loader is on the page, there must be at least one script element
1720 // getting its parent and then doing insertBefore solves the "Operation Aborted"
1721 // error in IE from appending to a node that isn't properly closed; see
1722 // dojo/tests/_base/loader/requirejs/simple-badbase.html for an example
1723 // don't use scripts with type dojo/... since these may be removed; see #15809
1724 // prefer to use the insertPoint computed during the config sniff in case a script is removed; see #16958
1725 var scripts = doc.getElementsByTagName("script"),
1726 i = 0,
1727 script;
1728 while(!insertPointSibling){
1729 if(!/^dojo/.test((script = scripts[i++]) && script.type)){
1730 insertPointSibling= script;
1731 }
1732 }
1733
1734 req.injectUrl = function(url, callback, owner){
1735 // insert a script element to the insert-point element with src=url;
1736 // apply callback upon detecting the script has loaded.
1737
1738 var node = owner.node = doc.createElement("script"),
1739 onLoad = function(e){
1740 e = e || window.event;
1741 var node = e.target || e.srcElement;
1742 if(e.type === "load" || /complete|loaded/.test(node.readyState)){
1743 loadDisconnector();
1744 errorDisconnector();
1745 callback && callback();
1746 }
1747 },
1748 loadDisconnector = domOn(node, "load", "onreadystatechange", onLoad),
1749 errorDisconnector = domOn(node, "error", "onerror", function(e){
1750 loadDisconnector();
1751 errorDisconnector();
1752 signal(error, makeError("scriptError", [url, e]));
1753 });
1754
1755 node.type = "text/javascript";
1756 node.charset = "utf-8";
1757 node.src = url;
1758 insertPointSibling.parentNode.insertBefore(node, insertPointSibling);
1759 return node;
1760 };
1761 }
1762 }
1763
1764 if(has("dojo-log-api")){
1765 req.log = function(){
1766 try{
1767 for(var i = 0; i < arguments.length; i++){
1768 console.log(arguments[i]);
1769 }
1770 }catch(e){}
1771 };
1772 }else{
1773 req.log = noop;
1774 }
1775
1776 if(has("dojo-trace-api")){
1777 var trace = req.trace = function(
1778 group, // the trace group to which this application belongs
1779 args // the contents of the trace
1780 ){
1781 ///
1782 // Tracing interface by group.
1783 //
1784 // Sends the contents of args to the console iff (req.trace.on && req.trace[group])
1785
1786 if(trace.on && trace.group[group]){
1787 signal("trace", [group, args]);
1788 for(var arg, dump = [], text= "trace:" + group + (args.length ? (":" + args[0]) : ""), i= 1; i<args.length;){
1789 arg = args[i++];
1790 if(isString(arg)){
1791 text += ", " + arg;
1792 }else{
1793 dump.push(arg);
1794 }
1795 }
1796 req.log(text);
1797 dump.length && dump.push(".");
1798 req.log.apply(req, dump);
1799 }
1800 };
1801 mix(trace, {
1802 on:1,
1803 group:{},
1804 set:function(group, value){
1805 if(isString(group)){
1806 trace.group[group]= value;
1807 }else{
1808 mix(trace.group, group);
1809 }
1810 }
1811 });
1812 trace.set(mix(mix(mix({}, defaultConfig.trace), userConfig.trace), dojoSniffConfig.trace));
1813 on("config", function(config){
1814 config.trace && trace.set(config.trace);
1815 });
1816 }else{
1817 req.trace = noop;
1818 }
1819
1820 var def = function(
1821 mid, //(commonjs.moduleId, optional)
1822 dependencies, //(array of commonjs.moduleId, optional) list of modules to be loaded before running factory
1823 factory //(any)
1824 ){
1825 ///
1826 // Advises the loader of a module factory. //Implements http://wiki.commonjs.org/wiki/Modules/AsynchronousDefinition.
1827 ///
1828 //note
1829 // CommonJS factory scan courtesy of http://requirejs.org
1830
1831 var arity = arguments.length,
1832 defaultDeps = ["require", "exports", "module"],
1833 // the predominate signature...
1834 args = [0, mid, dependencies];
1835 if(arity==1){
1836 args = [0, (isFunction(mid) ? defaultDeps : []), mid];
1837 }else if(arity==2 && isString(mid)){
1838 args = [mid, (isFunction(dependencies) ? defaultDeps : []), dependencies];
1839 }else if(arity==3){
1840 args = [mid, dependencies, factory];
1841 }
1842
1843 if(has("dojo-amd-factory-scan") && args[1]===defaultDeps){
1844 args[2].toString()
1845 .replace(/(\/\*([\s\S]*?)\*\/|\/\/(.*)$)/mg, "")
1846 .replace(/require\(["']([\w\!\-_\.\/]+)["']\)/g, function(match, dep){
1847 args[1].push(dep);
1848 });
1849 }
1850
1851 req.trace("loader-define", args.slice(0, 2));
1852 var targetModule = args[0] && getModule(args[0]),
1853 module;
1854 if(targetModule && !waiting[targetModule.mid]){
1855 // given a mid that hasn't been requested; therefore, defined through means other than injecting
1856 // consequent to a require() or define() application; examples include defining modules on-the-fly
1857 // due to some code path or including a module in a script element. In any case,
1858 // there is no callback waiting to finish processing and nothing to trigger the defQ and the
1859 // dependencies are never requested; therefore, do it here.
1860 injectDependencies(defineModule(targetModule, args[1], args[2]));
1861 }else if(!has("ie-event-behavior") || !has("host-browser") || injectingCachedModule){
1862 // not IE path: anonymous module and therefore must have been injected; therefore, onLoad will fire immediately
1863 // after script finishes being evaluated and the defQ can be run from that callback to detect the module id
1864 defQ.push(args);
1865 }else{
1866 // IE path: possibly anonymous module and therefore injected; therefore, cannot depend on 1-to-1,
1867 // in-order exec of onLoad with script eval (since it's IE) and must manually detect here
1868 targetModule = targetModule || injectingModule;
1869 if(!targetModule){
1870 for(mid in waiting){
1871 module = modules[mid];
1872 if(module && module.node && module.node.readyState === 'interactive'){
1873 targetModule = module;
1874 break;
1875 }
1876 }
1877 if(has("dojo-combo-api") && !targetModule){
1878 for(var i = 0; i<combosPending.length; i++){
1879 targetModule = combosPending[i];
1880 if(targetModule.node && targetModule.node.readyState === 'interactive'){
1881 break;
1882 }
1883 targetModule= 0;
1884 }
1885 }
1886 }
1887 if(has("dojo-combo-api") && isArray(targetModule)){
1888 injectDependencies(defineModule(getModule(targetModule.shift()), args[1], args[2]));
1889 if(!targetModule.length){
1890 combosPending.splice(i, 1);
1891 }
1892 }else if(targetModule){
1893 consumePendingCacheInsert(targetModule);
1894 injectDependencies(defineModule(targetModule, args[1], args[2]));
1895 }else{
1896 signal(error, makeError("ieDefineFailed", args[0]));
1897 }
1898 checkComplete();
1899 }
1900 };
1901 def.amd = {
1902 vendor:"dojotoolkit.org"
1903 };
1904
1905 if(has("dojo-requirejs-api")){
1906 req.def = def;
1907 }
1908
1909 // allow config to override default implementation of named functions; this is useful for
1910 // non-browser environments, e.g., overriding injectUrl, getText, log, etc. in node.js, Rhino, etc.
1911 // also useful for testing and monkey patching loader
1912 mix(mix(req, defaultConfig.loaderPatch), userConfig.loaderPatch);
1913
1914 // now that req is fully initialized and won't change, we can hook it up to the error signal
1915 on(error, function(arg){
1916 try{
1917 console.error(arg);
1918 if(arg instanceof Error){
1919 for(var p in arg){
1920 console.log(p + ":", arg[p]);
1921 }
1922 console.log(".");
1923 }
1924 }catch(e){}
1925 });
1926
1927 // always publish these
1928 mix(req, {
1929 uid:uid,
1930 cache:cache,
1931 packs:packs
1932 });
1933
1934
1935 if(has("dojo-publish-privates")){
1936 mix(req, {
1937 // these may be interesting to look at when debugging
1938 paths:paths,
1939 aliases:aliases,
1940 modules:modules,
1941 legacyMode:legacyMode,
1942 execQ:execQ,
1943 defQ:defQ,
1944 waiting:waiting,
1945
1946 // these are used for testing
1947 // TODO: move testing infrastructure to a different has feature
1948 packs:packs,
1949 mapProgs:mapProgs,
1950 pathsMapProg:pathsMapProg,
1951 listenerQueues:listenerQueues,
1952
1953 // these are used by the builder (at least)
1954 computeMapProg:computeMapProg,
1955 computeAliases:computeAliases,
1956 runMapProg:runMapProg,
1957 compactPath:compactPath,
1958 getModuleInfo:getModuleInfo_
1959 });
1960 }
1961
1962 // the loader can be defined exactly once; look for global define which is the symbol AMD loaders are
1963 // *required* to define (as opposed to require, which is optional)
1964 if(global.define){
1965 if(has("dojo-log-api")){
1966 signal(error, makeError("defineAlreadyDefined", 0));
1967 }
1968 return;
1969 }else{
1970 global.define = def;
1971 global.require = req;
1972 if(has("host-node")){
1973 require = req;
1974 }
1975 }
1976
1977 if(has("dojo-combo-api") && req.combo && req.combo.plugins){
1978 var plugins = req.combo.plugins,
1979 pluginName;
1980 for(pluginName in plugins){
1981 mix(mix(getModule(pluginName), plugins[pluginName]), {isCombo:1, executed:"executed", load:1});
1982 }
1983 }
1984
1985 if(has("dojo-config-api")){
1986 forEach(delayedModuleConfig, function(c){ config(c); });
1987 var bootDeps = dojoSniffConfig.deps || userConfig.deps || defaultConfig.deps,
1988 bootCallback = dojoSniffConfig.callback || userConfig.callback || defaultConfig.callback;
1989 req.boot = (bootDeps || bootCallback) ? [bootDeps || [], bootCallback] : 0;
1990 }
1991 if(!has("dojo-built")){
1992 !req.async && req(["dojo"]);
1993 req.boot && req.apply(null, req.boot);
1994 }
1995})
1996//>>excludeStart("replaceLoaderConfig", kwArgs.replaceLoaderConfig);
1997(
1998 // userConfig
1999 function(global){ return global.dojoConfig || global.djConfig || global.require || {}; },
2000
2001 // defaultConfig
2002 {
2003 // the default configuration for a browser; this will be modified by other environments
2004 hasCache:{
2005 "host-browser":1,
2006 "dom":1,
2007 "dojo-amd-factory-scan":1,
2008 "dojo-loader":1,
2009 "dojo-has-api":1,
2010 "dojo-inject-api":1,
2011 "dojo-timeout-api":1,
2012 "dojo-trace-api":1,
2013 "dojo-log-api":1,
2014 "dojo-dom-ready-api":1,
2015 "dojo-publish-privates":1,
2016 "dojo-config-api":1,
2017 "dojo-sniff":1,
2018 "dojo-sync-loader":1,
2019 "dojo-test-sniff":1,
2020 "config-deferredInstrumentation":1,
2021 "config-tlmSiblingOfDojo":1
2022 },
2023 packages:[{
2024 // note: like v1.6-, this bootstrap computes baseUrl to be the dojo directory
2025 name:'dojo',
2026 location:'.'
2027 },{
2028 name:'tests',
2029 location:'./tests'
2030 },{
2031 name:'dijit',
2032 location:'../dijit'
2033 },{
2034 name:'build',
2035 location:'../util/build'
2036 },{
2037 name:'doh',
2038 location:'../util/doh'
2039 },{
2040 name:'dojox',
2041 location:'../dojox'
2042 },{
2043 name:'demos',
2044 location:'../demos'
2045 }],
2046 trace:{
2047 // these are listed so it's simple to turn them on/off while debugging loading
2048 "loader-inject":0,
2049 "loader-define":0,
2050 "loader-exec-module":0,
2051 "loader-run-factory":0,
2052 "loader-finish-exec":0,
2053 "loader-define-module":0,
2054 "loader-circular-dependency":0,
2055 "loader-define-nonmodule":0
2056 },
2057 async:0,
2058 waitSeconds:15
2059 }
2060);
2061//>>excludeEnd("replaceLoaderConfig")