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