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") |
---|