source: Dev/trunk/src/client/dojo/dojo.js @ 512

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

Added Dojo 1.9.3 release.

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