source: Dev/branches/rest-dojo-ui/client/dojo/dojo.js @ 256

Last change on this file since 256 was 256, checked in by hendrikvanantwerpen, 13 years ago

Reworked project structure based on REST interaction and Dojo library. As
soon as this is stable, the old jQueryUI branch can be removed (it's
kept for reference).

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