[483] | 1 | define(["./kernel", "../has", "require", "module", "../json", "./lang", "./array"], function(dojo, has, require, thisModule, json, lang, array) { |
---|
| 2 | // module: |
---|
| 3 | // dojo/_base/loader |
---|
| 4 | |
---|
| 5 | // This module defines the v1.x synchronous loader API. |
---|
| 6 | |
---|
| 7 | // signal the loader in sync mode... |
---|
| 8 | //>>pure-amd |
---|
| 9 | |
---|
| 10 | if (!has("dojo-loader")){ |
---|
| 11 | console.error("cannot load the Dojo v1.x loader with a foreign loader"); |
---|
| 12 | return 0; |
---|
| 13 | } |
---|
| 14 | |
---|
| 15 | has.add("dojo-fast-sync-require", 1); |
---|
| 16 | |
---|
| 17 | |
---|
| 18 | var makeErrorToken = function(id){ |
---|
| 19 | return {src:thisModule.id, id:id}; |
---|
| 20 | }, |
---|
| 21 | |
---|
| 22 | slashName = function(name){ |
---|
| 23 | return name.replace(/\./g, "/"); |
---|
| 24 | }, |
---|
| 25 | |
---|
| 26 | buildDetectRe = /\/\/>>built/, |
---|
| 27 | |
---|
| 28 | dojoRequireCallbacks = [], |
---|
| 29 | dojoRequireModuleStack = [], |
---|
| 30 | |
---|
| 31 | dojoRequirePlugin = function(mid, require, loaded){ |
---|
| 32 | dojoRequireCallbacks.push(loaded); |
---|
| 33 | array.forEach(mid.split(","), function(mid){ |
---|
| 34 | var module = getModule(mid, require.module); |
---|
| 35 | dojoRequireModuleStack.push(module); |
---|
| 36 | injectModule(module); |
---|
| 37 | }); |
---|
| 38 | checkDojoRequirePlugin(); |
---|
| 39 | }, |
---|
| 40 | |
---|
| 41 | checkDojoRequirePlugin = (has("dojo-fast-sync-require") ? |
---|
| 42 | // This version of checkDojoRequirePlugin makes the observation that all dojoRequireCallbacks can be released |
---|
| 43 | // when all *non-dojo/require!, dojo/loadInit!* modules are either executed, not requested, or arrived. This is |
---|
| 44 | // the case since there are no more modules the loader is waiting for, therefore, dojo/require! must have |
---|
| 45 | // everything it needs on board. |
---|
| 46 | // |
---|
| 47 | // The potential weakness of this algorithm is that dojo/require will not execute callbacks until *all* dependency |
---|
| 48 | // trees are ready. It is possible that some trees may be ready earlier than others, and this extra wait is non-optimal. |
---|
| 49 | // Still, for big projects, this seems better than the original algorithm below that proved slow in some cases. |
---|
| 50 | // Note, however, the original algorithm had the potential to execute partial trees, but that potential was never enabled. |
---|
| 51 | // There are also other optimization available with the original algorithm that have not been explored. |
---|
| 52 | function(){ |
---|
| 53 | var module, mid; |
---|
| 54 | for(mid in modules){ |
---|
| 55 | module = modules[mid]; |
---|
| 56 | if(module.noReqPluginCheck===undefined){ |
---|
| 57 | // tag the module as either a loadInit or require plugin or not for future reference |
---|
| 58 | module.noReqPluginCheck = /loadInit\!/.test(mid) || /require\!/.test(mid) ? 1 : 0; |
---|
| 59 | } |
---|
| 60 | if(!module.executed && !module.noReqPluginCheck && module.injected==requested){ |
---|
| 61 | return; |
---|
| 62 | } |
---|
| 63 | } |
---|
| 64 | |
---|
| 65 | guardCheckComplete(function(){ |
---|
| 66 | var oldCallbacks = dojoRequireCallbacks; |
---|
| 67 | dojoRequireCallbacks = []; |
---|
| 68 | array.forEach(oldCallbacks, function(cb){cb(1);}); |
---|
| 69 | }); |
---|
| 70 | } : (function(){ |
---|
| 71 | // Note: this is the original checkDojoRequirePlugin that is much slower than the algorithm above. However, we know it |
---|
| 72 | // works, so we leave it here in case the algorithm above fails in some corner case. |
---|
| 73 | // |
---|
| 74 | // checkDojoRequirePlugin inspects all of the modules demanded by a dojo/require!<module-list> dependency |
---|
| 75 | // to see if they have arrived. The loader does not release *any* of these modules to be instantiated |
---|
| 76 | // until *all* of these modules are on board, thereby preventing the evaluation of a module with dojo.require's |
---|
| 77 | // that reference modules that are not available. |
---|
| 78 | // |
---|
| 79 | // The algorithm works by traversing the dependency graphs (remember, there can be cycles so they are not trees) |
---|
| 80 | // of each module in the dojoRequireModuleStack array (which contains the list of modules demanded by dojo/require!). |
---|
| 81 | // The moment a single module is discovered that is missing, the algorithm gives up and indicates that not all |
---|
| 82 | // modules are on board. dojo/loadInit! and dojo/require! are ignored because there dependencies are inserted |
---|
| 83 | // directly in dojoRequireModuleStack. For example, if "your/module" module depends on "dojo/require!my/module", then |
---|
| 84 | // *both* "dojo/require!my/module" and "my/module" will be in dojoRequireModuleStack. Obviously, if "my/module" |
---|
| 85 | // is on board, then "dojo/require!my/module" is also satisfied, so the algorithm doesn't check for "dojo/require!my/module". |
---|
| 86 | // |
---|
| 87 | // Note: inserting a dojo/require!<some-module-list> dependency in the dojoRequireModuleStack achieves nothing |
---|
| 88 | // with the current algorithm; however, having such modules present makes it possible to optimize the algorithm |
---|
| 89 | // |
---|
| 90 | // Note: prior versions of this algorithm had an optimization that signaled loaded on dojo/require! dependencies |
---|
| 91 | // individually (rather than waiting for them all to be resolved). The implementation proved problematic with cycles |
---|
| 92 | // and plugins. However, it is possible to reattach that strategy in the future. |
---|
| 93 | |
---|
| 94 | // a set from module-id to {undefined | 1 | 0}, where... |
---|
| 95 | // undefined => the module has not been inspected |
---|
| 96 | // 0 => the module or at least one of its dependencies has not arrived |
---|
| 97 | // 1 => the module is a loadInit! or require! plugin resource, or is currently being traversed (therefore, assume |
---|
| 98 | // OK until proven otherwise), or has been completely traversed and all dependencies have arrived |
---|
| 99 | |
---|
| 100 | var touched, |
---|
| 101 | traverse = function(m){ |
---|
| 102 | touched[m.mid] = 1; |
---|
| 103 | for(var t, module, deps = m.deps || [], i= 0; i<deps.length; i++){ |
---|
| 104 | module = deps[i]; |
---|
| 105 | if(!(t = touched[module.mid])){ |
---|
| 106 | if(t===0 || !traverse(module)){ |
---|
| 107 | touched[m.mid] = 0; |
---|
| 108 | return false; |
---|
| 109 | } |
---|
| 110 | } |
---|
| 111 | } |
---|
| 112 | return true; |
---|
| 113 | }; |
---|
| 114 | |
---|
| 115 | return function(){ |
---|
| 116 | // initialize the touched hash with easy-to-compute values that help short circuit recursive algorithm; |
---|
| 117 | // recall loadInit/require plugin modules are dependencies of modules in dojoRequireModuleStack... |
---|
| 118 | // which would cause a circular dependency chain that would never be resolved if checked here |
---|
| 119 | // notice all dependencies of any particular loadInit/require plugin module will already |
---|
| 120 | // be checked since those are pushed into dojoRequireModuleStack explicitly by the |
---|
| 121 | // plugin...so if a particular loadInitPlugin module's dependencies are not really |
---|
| 122 | // on board, that *will* be detected elsewhere in the traversal. |
---|
| 123 | var module, mid; |
---|
| 124 | touched = {}; |
---|
| 125 | for(mid in modules){ |
---|
| 126 | module = modules[mid]; |
---|
| 127 | if(module.executed || module.noReqPluginCheck){ |
---|
| 128 | touched[mid] = 1; |
---|
| 129 | }else{ |
---|
| 130 | if(module.noReqPluginCheck!==0){ |
---|
| 131 | // tag the module as either a loadInit or require plugin or not for future reference |
---|
| 132 | module.noReqPluginCheck = /loadInit\!/.test(mid) || /require\!/.test(mid) ? 1 : 0; |
---|
| 133 | } |
---|
| 134 | if(module.noReqPluginCheck){ |
---|
| 135 | touched[mid] = 1; |
---|
| 136 | }else if(module.injected!==arrived){ |
---|
| 137 | // not executed, has not arrived, and is not a loadInit or require plugin resource |
---|
| 138 | touched[mid] = 0; |
---|
| 139 | }// else, leave undefined and we'll traverse the dependencies |
---|
| 140 | } |
---|
| 141 | } |
---|
| 142 | for(var t, i = 0, end = dojoRequireModuleStack.length; i<end; i++){ |
---|
| 143 | module = dojoRequireModuleStack[i]; |
---|
| 144 | if(!(t = touched[module.mid])){ |
---|
| 145 | if(t===0 || !traverse(module)){ |
---|
| 146 | return; |
---|
| 147 | } |
---|
| 148 | } |
---|
| 149 | } |
---|
| 150 | guardCheckComplete(function(){ |
---|
| 151 | var oldCallbacks = dojoRequireCallbacks; |
---|
| 152 | dojoRequireCallbacks = []; |
---|
| 153 | array.forEach(oldCallbacks, function(cb){cb(1);}); |
---|
| 154 | }); |
---|
| 155 | }; |
---|
| 156 | })()), |
---|
| 157 | |
---|
| 158 | dojoLoadInitPlugin = function(mid, require, loaded){ |
---|
| 159 | // mid names a module that defines a "dojo load init" bundle, an object with two properties: |
---|
| 160 | // |
---|
| 161 | // * names: a vector of module ids that give top-level names to define in the lexical scope of def |
---|
| 162 | // * def: a function that contains some some legacy loader API applications |
---|
| 163 | // |
---|
| 164 | // The point of def is to possibly cause some modules to be loaded (but not executed) by dojo/require! where the module |
---|
| 165 | // ids are possibly-determined at runtime. For example, here is dojox.gfx from v1.6 expressed as an AMD module using the dojo/loadInit |
---|
| 166 | // and dojo/require plugins. |
---|
| 167 | // |
---|
| 168 | // // dojox/gfx: |
---|
| 169 | // |
---|
| 170 | // define("*loadInit_12, { |
---|
| 171 | // names:["dojo", "dijit", "dojox"], |
---|
| 172 | // def: function(){ |
---|
| 173 | // dojo.loadInit(function(){ |
---|
| 174 | // var gfx = lang.getObject("dojox.gfx", true); |
---|
| 175 | // |
---|
| 176 | // // |
---|
| 177 | // // code required to set gfx properties ommitted... |
---|
| 178 | // // |
---|
| 179 | // |
---|
| 180 | // // now use the calculations to include the runtime-dependent module |
---|
| 181 | // dojo.require("dojox.gfx." + gfx.renderer); |
---|
| 182 | // }); |
---|
| 183 | // } |
---|
| 184 | // }); |
---|
| 185 | // |
---|
| 186 | // define(["dojo", "dojo/loadInit!" + id].concat("dojo/require!dojox/gfx/matric,dojox/gfx/_base"), function(dojo){ |
---|
| 187 | // // when this AMD factory function is executed, the following modules are guaranteed downloaded but not executed: |
---|
| 188 | // // "dojox.gfx." + gfx.renderer |
---|
| 189 | // // dojox.gfx.matrix |
---|
| 190 | // // dojox.gfx._base |
---|
| 191 | // dojo.provide("dojo.gfx"); |
---|
| 192 | // dojo.require("dojox.gfx.matrix"); |
---|
| 193 | // dojo.require("dojox.gfx._base"); |
---|
| 194 | // dojo.require("dojox.gfx." + gfx.renderer); |
---|
| 195 | // return lang.getObject("dojo.gfx"); |
---|
| 196 | // }); |
---|
| 197 | // })(); |
---|
| 198 | // |
---|
| 199 | // The idea is to run the legacy loader API with global variables shadowed, which allows these variables to |
---|
| 200 | // be relocated. For example, dojox and dojo could be relocated to different names by giving a map and the code above will |
---|
| 201 | // execute properly (because the plugin below resolves the load init bundle.names module with respect to the module that demanded |
---|
| 202 | // the plugin resource). |
---|
| 203 | // |
---|
| 204 | // Note that the relocation is specified in the runtime configuration; relocated names need not be set at build-time. |
---|
| 205 | // |
---|
| 206 | // Warning: this is not the best way to express dojox.gfx as and AMD module. In fact, the module has been properly converted in |
---|
| 207 | // v1.7. However, this technique allows the builder to convert legacy modules into AMD modules and guarantee the codepath is the |
---|
| 208 | // same in the converted AMD module. |
---|
| 209 | require([mid], function(bundle){ |
---|
| 210 | // notice how names is resolved with respect to the module that demanded the plugin resource |
---|
| 211 | require(bundle.names, function(){ |
---|
| 212 | // bring the bundle names into scope |
---|
| 213 | for(var scopeText = "", args= [], i = 0; i<arguments.length; i++){ |
---|
| 214 | scopeText+= "var " + bundle.names[i] + "= arguments[" + i + "]; "; |
---|
| 215 | args.push(arguments[i]); |
---|
| 216 | } |
---|
| 217 | eval(scopeText); |
---|
| 218 | |
---|
| 219 | var callingModule = require.module, |
---|
| 220 | // the list of modules that need to be downloaded but not executed before the callingModule can be executed |
---|
| 221 | requireList = [], |
---|
| 222 | |
---|
| 223 | // the list of i18n bundles that are xdomain; undefined if none |
---|
| 224 | i18nDeps, |
---|
| 225 | |
---|
| 226 | syncLoaderApi = { |
---|
| 227 | provide:function(moduleName){ |
---|
| 228 | // mark modules that arrive consequent to multiple provides in this module as arrived since they can't be injected |
---|
| 229 | moduleName = slashName(moduleName); |
---|
| 230 | var providedModule = getModule(moduleName, callingModule); |
---|
| 231 | if(providedModule!==callingModule){ |
---|
| 232 | setArrived(providedModule); |
---|
| 233 | } |
---|
| 234 | }, |
---|
| 235 | require:function(moduleName, omitModuleCheck){ |
---|
| 236 | moduleName = slashName(moduleName); |
---|
| 237 | omitModuleCheck && (getModule(moduleName, callingModule).result = nonmodule); |
---|
| 238 | requireList.push(moduleName); |
---|
| 239 | }, |
---|
| 240 | requireLocalization:function(moduleName, bundleName, locale){ |
---|
| 241 | // since we're going to need dojo/i8n, add it to i18nDeps if not already there |
---|
| 242 | if(!i18nDeps){ |
---|
| 243 | // don't have to map since that will occur when the dependency is resolved |
---|
| 244 | i18nDeps = ["dojo/i18n"]; |
---|
| 245 | } |
---|
| 246 | |
---|
| 247 | // figure out if the bundle is xdomain; if so, add it to the i18nDepsSet |
---|
| 248 | locale = (locale || dojo.locale).toLowerCase(); |
---|
| 249 | moduleName = slashName(moduleName) + "/nls/" + (/root/i.test(locale) ? "" : locale + "/") + slashName(bundleName); |
---|
| 250 | if(getModule(moduleName, callingModule).isXd){ |
---|
| 251 | // don't have to map since that will occur when the dependency is resolved |
---|
| 252 | i18nDeps.push("dojo/i18n!" + moduleName); |
---|
| 253 | }// else the bundle will be loaded synchronously when the module is evaluated |
---|
| 254 | }, |
---|
| 255 | loadInit:function(f){ |
---|
| 256 | f(); |
---|
| 257 | } |
---|
| 258 | }, |
---|
| 259 | |
---|
| 260 | hold = {}, |
---|
| 261 | p; |
---|
| 262 | |
---|
| 263 | // hijack the correct dojo and apply bundle.def |
---|
| 264 | try{ |
---|
| 265 | for(p in syncLoaderApi){ |
---|
| 266 | hold[p] = dojo[p]; |
---|
| 267 | dojo[p] = syncLoaderApi[p]; |
---|
| 268 | } |
---|
| 269 | bundle.def.apply(null, args); |
---|
| 270 | }catch(e){ |
---|
| 271 | signal("error", [makeErrorToken("failedDojoLoadInit"), e]); |
---|
| 272 | }finally{ |
---|
| 273 | for(p in syncLoaderApi){ |
---|
| 274 | dojo[p] = hold[p]; |
---|
| 275 | } |
---|
| 276 | } |
---|
| 277 | |
---|
| 278 | if(i18nDeps){ |
---|
| 279 | requireList = requireList.concat(i18nDeps); |
---|
| 280 | } |
---|
| 281 | |
---|
| 282 | if(requireList.length){ |
---|
| 283 | dojoRequirePlugin(requireList.join(","), require, loaded); |
---|
| 284 | }else{ |
---|
| 285 | loaded(); |
---|
| 286 | } |
---|
| 287 | }); |
---|
| 288 | }); |
---|
| 289 | }, |
---|
| 290 | |
---|
| 291 | extractApplication = function( |
---|
| 292 | text, // the text to search |
---|
| 293 | startSearch, // the position in text to start looking for the closing paren |
---|
| 294 | startApplication // the position in text where the function application expression starts |
---|
| 295 | ){ |
---|
| 296 | // find end of the call by finding the matching end paren |
---|
| 297 | // Warning: as usual, this will fail in the presense of unmatched right parans contained in strings, regexs, or unremoved comments |
---|
| 298 | var parenRe = /\(|\)/g, |
---|
| 299 | matchCount = 1, |
---|
| 300 | match; |
---|
| 301 | parenRe.lastIndex = startSearch; |
---|
| 302 | while((match = parenRe.exec(text))){ |
---|
| 303 | if(match[0] == ")"){ |
---|
| 304 | matchCount -= 1; |
---|
| 305 | }else{ |
---|
| 306 | matchCount += 1; |
---|
| 307 | } |
---|
| 308 | if(matchCount == 0){ |
---|
| 309 | break; |
---|
| 310 | } |
---|
| 311 | } |
---|
| 312 | |
---|
| 313 | if(matchCount != 0){ |
---|
| 314 | throw "unmatched paren around character " + parenRe.lastIndex + " in: " + text; |
---|
| 315 | } |
---|
| 316 | |
---|
| 317 | //Put the master matching string in the results. |
---|
| 318 | return [dojo.trim(text.substring(startApplication, parenRe.lastIndex))+";\n", parenRe.lastIndex]; |
---|
| 319 | }, |
---|
| 320 | |
---|
| 321 | // the following regex is taken from 1.6. It is a very poor technique to remove comments and |
---|
| 322 | // will fail in some cases; for example, consider the code... |
---|
| 323 | // |
---|
| 324 | // var message = "Category-1 */* Category-2"; |
---|
| 325 | // |
---|
| 326 | // The regex that follows will see a /* comment and trash the code accordingly. In fact, there are all |
---|
| 327 | // kinds of cases like this with strings and regexs that will cause this design to fail miserably. |
---|
| 328 | // |
---|
| 329 | // Alternative regex designs exist that will result in less-likely failures, but will still fail in many cases. |
---|
| 330 | // The only solution guaranteed 100% correct is to parse the code and that seems overkill for this |
---|
| 331 | // backcompat/unbuilt-xdomain layer. In the end, since it's been this way for a while, we won't change it. |
---|
| 332 | // See the opening paragraphs of Chapter 7 or ECME-262 which describes the lexical abiguity further. |
---|
| 333 | removeCommentRe = /(\/\*([\s\S]*?)\*\/|\/\/(.*)$)/mg, |
---|
| 334 | |
---|
| 335 | syncLoaderApiRe = /(^|\s)dojo\.(loadInit|require|provide|requireLocalization|requireIf|requireAfterIf|platformRequire)\s*\(/mg, |
---|
| 336 | |
---|
| 337 | amdLoaderApiRe = /(^|\s)(require|define)\s*\(/m, |
---|
| 338 | |
---|
| 339 | extractLegacyApiApplications = function(text, noCommentText){ |
---|
| 340 | // scan the noCommentText for any legacy loader API applications. Copy such applications into result (this is |
---|
| 341 | // used by the builder). Move dojo.loadInit applications to loadInitApplications string. Copy all other applications |
---|
| 342 | // to otherApplications string. If no applications were found, return 0, signalling an AMD module. Otherwise, return |
---|
| 343 | // loadInitApplications + otherApplications. Fixup text by replacing |
---|
| 344 | // |
---|
| 345 | // dojo.loadInit(// etc... |
---|
| 346 | // |
---|
| 347 | // with |
---|
| 348 | // |
---|
| 349 | // \n 0 && dojo.loadInit(// etc... |
---|
| 350 | // |
---|
| 351 | // Which results in the dojo.loadInit from *not* being applied. This design goes a long way towards protecting the |
---|
| 352 | // code from an over-agressive removeCommentRe. However... |
---|
| 353 | // |
---|
| 354 | // WARNING: the removeCommentRe will cause an error if a detected comment removes all or part of a legacy-loader application |
---|
| 355 | // that is not in a comment. |
---|
| 356 | |
---|
| 357 | var match, startSearch, startApplication, application, |
---|
| 358 | loadInitApplications = [], |
---|
| 359 | otherApplications = [], |
---|
| 360 | allApplications = []; |
---|
| 361 | |
---|
| 362 | // noCommentText may be provided by a build app with comments extracted by a better method than regex (hopefully) |
---|
| 363 | noCommentText = noCommentText || text.replace(removeCommentRe, function(match){ |
---|
| 364 | // remove iff the detected comment has text that looks like a sync loader API application; this helps by |
---|
| 365 | // removing as little as possible, minimizing the changes the janky regex will kill the module |
---|
| 366 | syncLoaderApiRe.lastIndex = amdLoaderApiRe.lastIndex = 0; |
---|
| 367 | return (syncLoaderApiRe.test(match) || amdLoaderApiRe.test(match)) ? "" : match; |
---|
| 368 | }); |
---|
| 369 | |
---|
| 370 | // find and extract all dojo.loadInit applications |
---|
| 371 | while((match = syncLoaderApiRe.exec(noCommentText))){ |
---|
| 372 | startSearch = syncLoaderApiRe.lastIndex; |
---|
| 373 | startApplication = startSearch - match[0].length; |
---|
| 374 | application = extractApplication(noCommentText, startSearch, startApplication); |
---|
| 375 | if(match[2]=="loadInit"){ |
---|
| 376 | loadInitApplications.push(application[0]); |
---|
| 377 | }else{ |
---|
| 378 | otherApplications.push(application[0]); |
---|
| 379 | } |
---|
| 380 | syncLoaderApiRe.lastIndex = application[1]; |
---|
| 381 | } |
---|
| 382 | allApplications = loadInitApplications.concat(otherApplications); |
---|
| 383 | if(allApplications.length || !amdLoaderApiRe.test(noCommentText)){ |
---|
| 384 | // either there were some legacy loader API applications or there were no AMD API applications |
---|
| 385 | return [text.replace(/(^|\s)dojo\.loadInit\s*\(/g, "\n0 && dojo.loadInit("), allApplications.join(""), allApplications]; |
---|
| 386 | }else{ |
---|
| 387 | // legacy loader API *was not* detected and AMD API *was* detected; therefore, assume it's an AMD module |
---|
| 388 | return 0; |
---|
| 389 | } |
---|
| 390 | }, |
---|
| 391 | |
---|
| 392 | transformToAmd = function(module, text){ |
---|
| 393 | // This is roughly the equivalent of dojo._xdCreateResource in 1.6-; however, it expresses a v1.6- dojo |
---|
| 394 | // module in terms of AMD define instead of creating the dojo proprietary xdomain module expression. |
---|
| 395 | // The module could have originated from several sources: |
---|
| 396 | // |
---|
| 397 | // * amd require() a module, e.g., require(["my/module"]) |
---|
| 398 | // * amd require() a nonmodule, e.g., require(["my/resource.js"') |
---|
| 399 | // * amd define() deps vector (always a module) |
---|
| 400 | // * dojo.require() a module, e.g. dojo.require("my.module") |
---|
| 401 | // * dojo.require() a nonmodule, e.g., dojo.require("my.module", true) |
---|
| 402 | // * dojo.requireIf/requireAfterIf/platformRequire a module |
---|
| 403 | // |
---|
| 404 | // The module is scanned for legacy loader API applications; if none are found, then assume the module is an |
---|
| 405 | // AMD module and return 0. Otherwise, a synthetic dojo/loadInit plugin resource is created and the module text |
---|
| 406 | // is rewritten as an AMD module with the single dependency of this synthetic resource. When the dojo/loadInit |
---|
| 407 | // plugin loaded the synthetic resource, it will cause all dojo.loadInit's to be executed, find all dojo.require's |
---|
| 408 | // (either directly consequent to dojo.require or indirectly consequent to dojo.require[After]If or |
---|
| 409 | // dojo.platformRequire, and finally cause loading of all dojo.required modules with the dojo/require plugin. Thus, |
---|
| 410 | // when the dojo/loadInit plugin reports it has been loaded, all modules required by the given module are guaranteed |
---|
| 411 | // loaded (but not executed). This then allows the module to execute it's code path without interupts, thereby |
---|
| 412 | // following the synchronous code path. |
---|
| 413 | // |
---|
| 414 | // Notice that this function behaves the same whether or not it happens to be in a mapped dojo/loader module. |
---|
| 415 | |
---|
| 416 | var extractResult, id, names = [], namesAsStrings = []; |
---|
| 417 | if(buildDetectRe.test(text) || !(extractResult = extractLegacyApiApplications(text))){ |
---|
| 418 | // buildDetectRe.test(text) => a built module, always AMD |
---|
| 419 | // extractResult==0 => no sync API |
---|
| 420 | return 0; |
---|
| 421 | } |
---|
| 422 | |
---|
| 423 | // manufacture a synthetic module id that can never be a real mdule id (just like require does) |
---|
| 424 | id = module.mid + "-*loadInit"; |
---|
| 425 | |
---|
| 426 | // construct the dojo/loadInit names vector which causes any relocated names to be defined as lexical variables under their not-relocated name |
---|
| 427 | // the dojo/loadInit plugin assumes the first name in names is "dojo" |
---|
| 428 | |
---|
| 429 | for(var p in getModule("dojo", module).result.scopeMap){ |
---|
| 430 | names.push(p); |
---|
| 431 | namesAsStrings.push('"' + p + '"'); |
---|
| 432 | } |
---|
| 433 | |
---|
| 434 | // rewrite the module as a synthetic dojo/loadInit plugin resource + the module expressed as an AMD module that depends on this synthetic resource |
---|
| 435 | // don't have to map dojo/init since that will occur when the dependency is resolved |
---|
| 436 | return "// xdomain rewrite of " + module.mid + "\n" + |
---|
| 437 | "define('" + id + "',{\n" + |
---|
| 438 | "\tnames:" + json.stringify(names) + ",\n" + |
---|
| 439 | "\tdef:function(" + names.join(",") + "){" + extractResult[1] + "}" + |
---|
| 440 | "});\n\n" + |
---|
| 441 | "define(" + json.stringify(names.concat(["dojo/loadInit!"+id])) + ", function(" + names.join(",") + "){\n" + extractResult[0] + "});"; |
---|
| 442 | }, |
---|
| 443 | |
---|
| 444 | loaderVars = require.initSyncLoader(dojoRequirePlugin, checkDojoRequirePlugin, transformToAmd), |
---|
| 445 | |
---|
| 446 | sync = |
---|
| 447 | loaderVars.sync, |
---|
| 448 | |
---|
| 449 | requested = |
---|
| 450 | loaderVars.requested, |
---|
| 451 | |
---|
| 452 | arrived = |
---|
| 453 | loaderVars.arrived, |
---|
| 454 | |
---|
| 455 | nonmodule = |
---|
| 456 | loaderVars.nonmodule, |
---|
| 457 | |
---|
| 458 | executing = |
---|
| 459 | loaderVars.executing, |
---|
| 460 | |
---|
| 461 | executed = |
---|
| 462 | loaderVars.executed, |
---|
| 463 | |
---|
| 464 | syncExecStack = |
---|
| 465 | loaderVars.syncExecStack, |
---|
| 466 | |
---|
| 467 | modules = |
---|
| 468 | loaderVars.modules, |
---|
| 469 | |
---|
| 470 | execQ = |
---|
| 471 | loaderVars.execQ, |
---|
| 472 | |
---|
| 473 | getModule = |
---|
| 474 | loaderVars.getModule, |
---|
| 475 | |
---|
| 476 | injectModule = |
---|
| 477 | loaderVars.injectModule, |
---|
| 478 | |
---|
| 479 | setArrived = |
---|
| 480 | loaderVars.setArrived, |
---|
| 481 | |
---|
| 482 | signal = |
---|
| 483 | loaderVars.signal, |
---|
| 484 | |
---|
| 485 | finishExec = |
---|
| 486 | loaderVars.finishExec, |
---|
| 487 | |
---|
| 488 | execModule = |
---|
| 489 | loaderVars.execModule, |
---|
| 490 | |
---|
| 491 | getLegacyMode = |
---|
| 492 | loaderVars.getLegacyMode, |
---|
| 493 | |
---|
| 494 | guardCheckComplete = |
---|
| 495 | loaderVars.guardCheckComplete; |
---|
| 496 | |
---|
| 497 | // there is exactly one dojoRequirePlugin among possibly-many dojo/_base/loader's (owing to mapping) |
---|
| 498 | dojoRequirePlugin = loaderVars.dojoRequirePlugin; |
---|
| 499 | |
---|
| 500 | dojo.provide = function(mid){ |
---|
| 501 | var executingModule = syncExecStack[0], |
---|
| 502 | module = lang.mixin(getModule(slashName(mid), require.module), { |
---|
| 503 | executed:executing, |
---|
| 504 | result:lang.getObject(mid, true) |
---|
| 505 | }); |
---|
| 506 | setArrived(module); |
---|
| 507 | if(executingModule){ |
---|
| 508 | (executingModule.provides || (executingModule.provides = [])).push(function(){ |
---|
| 509 | module.result = lang.getObject(mid); |
---|
| 510 | delete module.provides; |
---|
| 511 | module.executed!==executed && finishExec(module); |
---|
| 512 | }); |
---|
| 513 | }// else dojo.provide called not consequent to loading; therefore, give up trying to publish module value to loader namespace |
---|
| 514 | return module.result; |
---|
| 515 | }; |
---|
| 516 | |
---|
| 517 | has.add("config-publishRequireResult", 1, 0, 0); |
---|
| 518 | |
---|
| 519 | dojo.require = function(moduleName, omitModuleCheck) { |
---|
| 520 | // summary: |
---|
| 521 | // loads a Javascript module from the appropriate URI |
---|
| 522 | // |
---|
| 523 | // moduleName: String |
---|
| 524 | // module name to load, using periods for separators, |
---|
| 525 | // e.g. "dojo.date.locale". Module paths are de-referenced by dojo's |
---|
| 526 | // internal mapping of locations to names and are disambiguated by |
---|
| 527 | // longest prefix. See `dojo.registerModulePath()` for details on |
---|
| 528 | // registering new modules. |
---|
| 529 | // |
---|
| 530 | // omitModuleCheck: Boolean? |
---|
| 531 | // if `true`, omitModuleCheck skips the step of ensuring that the |
---|
| 532 | // loaded file actually defines the symbol it is referenced by. |
---|
| 533 | // For example if it called as `dojo.require("a.b.c")` and the |
---|
| 534 | // file located at `a/b/c.js` does not define an object `a.b.c`, |
---|
| 535 | // and exception will be throws whereas no exception is raised |
---|
| 536 | // when called as `dojo.require("a.b.c", true)` |
---|
| 537 | // |
---|
| 538 | // description: |
---|
| 539 | // Modules are loaded via dojo.require by using one of two loaders: the normal loader |
---|
| 540 | // and the xdomain loader. The xdomain loader is used when dojo was built with a |
---|
| 541 | // custom build that specified loader=xdomain and the module lives on a modulePath |
---|
| 542 | // that is a whole URL, with protocol and a domain. The versions of Dojo that are on |
---|
| 543 | // the Google and AOL CDNs use the xdomain loader. |
---|
| 544 | // |
---|
| 545 | // If the module is loaded via the xdomain loader, it is an asynchronous load, since |
---|
| 546 | // the module is added via a dynamically created script tag. This |
---|
| 547 | // means that dojo.require() can return before the module has loaded. However, this |
---|
| 548 | // should only happen in the case where you do dojo.require calls in the top-level |
---|
| 549 | // HTML page, or if you purposely avoid the loader checking for dojo.require |
---|
| 550 | // dependencies in your module by using a syntax like dojo["require"] to load the module. |
---|
| 551 | // |
---|
| 552 | // Sometimes it is useful to not have the loader detect the dojo.require calls in the |
---|
| 553 | // module so that you can dynamically load the modules as a result of an action on the |
---|
| 554 | // page, instead of right at module load time. |
---|
| 555 | // |
---|
| 556 | // Also, for script blocks in an HTML page, the loader does not pre-process them, so |
---|
| 557 | // it does not know to download the modules before the dojo.require calls occur. |
---|
| 558 | // |
---|
| 559 | // So, in those two cases, when you want on-the-fly module loading or for script blocks |
---|
| 560 | // in the HTML page, special care must be taken if the dojo.required code is loaded |
---|
| 561 | // asynchronously. To make sure you can execute code that depends on the dojo.required |
---|
| 562 | // modules, be sure to add the code that depends on the modules in a dojo.addOnLoad() |
---|
| 563 | // callback. dojo.addOnLoad waits for all outstanding modules to finish loading before |
---|
| 564 | // executing. |
---|
| 565 | // |
---|
| 566 | // This type of syntax works with both xdomain and normal loaders, so it is good |
---|
| 567 | // practice to always use this idiom for on-the-fly code loading and in HTML script |
---|
| 568 | // blocks. If at some point you change loaders and where the code is loaded from, |
---|
| 569 | // it will all still work. |
---|
| 570 | // |
---|
| 571 | // More on how dojo.require |
---|
| 572 | // `dojo.require("A.B")` first checks to see if symbol A.B is |
---|
| 573 | // defined. If it is, it is simply returned (nothing to do). |
---|
| 574 | // |
---|
| 575 | // If it is not defined, it will look for `A/B.js` in the script root |
---|
| 576 | // directory. |
---|
| 577 | // |
---|
| 578 | // `dojo.require` throws an exception if it cannot find a file |
---|
| 579 | // to load, or if the symbol `A.B` is not defined after loading. |
---|
| 580 | // |
---|
| 581 | // It returns the object `A.B`, but note the caveats above about on-the-fly loading and |
---|
| 582 | // HTML script blocks when the xdomain loader is loading a module. |
---|
| 583 | // |
---|
| 584 | // `dojo.require()` does nothing about importing symbols into |
---|
| 585 | // the current namespace. It is presumed that the caller will |
---|
| 586 | // take care of that. |
---|
| 587 | // |
---|
| 588 | // example: |
---|
| 589 | // To use dojo.require in conjunction with dojo.ready: |
---|
| 590 | // |
---|
| 591 | // | dojo.require("foo"); |
---|
| 592 | // | dojo.require("bar"); |
---|
| 593 | // | dojo.addOnLoad(function(){ |
---|
| 594 | // | //you can now safely do something with foo and bar |
---|
| 595 | // | }); |
---|
| 596 | // |
---|
| 597 | // example: |
---|
| 598 | // For example, to import all symbols into a local block, you might write: |
---|
| 599 | // |
---|
| 600 | // | with (dojo.require("A.B")) { |
---|
| 601 | // | ... |
---|
| 602 | // | } |
---|
| 603 | // |
---|
| 604 | // And to import just the leaf symbol to a local variable: |
---|
| 605 | // |
---|
| 606 | // | var B = dojo.require("A.B"); |
---|
| 607 | // | ... |
---|
| 608 | // |
---|
| 609 | // returns: |
---|
| 610 | // the required namespace object |
---|
| 611 | function doRequire(mid, omitModuleCheck){ |
---|
| 612 | var module = getModule(slashName(mid), require.module); |
---|
| 613 | if(syncExecStack.length && syncExecStack[0].finish){ |
---|
| 614 | // switched to async loading in the middle of evaluating a legacy module; stop |
---|
| 615 | // applying dojo.require so the remaining dojo.requires are applied in order |
---|
| 616 | syncExecStack[0].finish.push(mid); |
---|
| 617 | return undefined; |
---|
| 618 | } |
---|
| 619 | |
---|
| 620 | // recall module.executed has values {0, executing, executed}; therefore, truthy indicates executing or executed |
---|
| 621 | if(module.executed){ |
---|
| 622 | return module.result; |
---|
| 623 | } |
---|
| 624 | omitModuleCheck && (module.result = nonmodule); |
---|
| 625 | |
---|
| 626 | // rcg...why here and in two lines?? |
---|
| 627 | var currentMode = getLegacyMode(); |
---|
| 628 | |
---|
| 629 | // recall, in sync mode to inject is to *eval* the module text |
---|
| 630 | // if the module is a legacy module, this is the same as executing |
---|
| 631 | // but if the module is an AMD module, this means defining, not executing |
---|
| 632 | injectModule(module); |
---|
| 633 | // the inject may have changed the mode |
---|
| 634 | currentMode = getLegacyMode(); |
---|
| 635 | |
---|
| 636 | // in sync mode to dojo.require is to execute |
---|
| 637 | if(module.executed!==executed && module.injected===arrived){ |
---|
| 638 | // the module was already here before injectModule was called probably finishing up a xdomain |
---|
| 639 | // load, but maybe a module given to the loader directly rather than having the loader retrieve it |
---|
| 640 | |
---|
| 641 | loaderVars.guardCheckComplete(function(){ |
---|
| 642 | execModule(module); |
---|
| 643 | }); |
---|
| 644 | } |
---|
| 645 | if(module.executed){ |
---|
| 646 | return module.result; |
---|
| 647 | } |
---|
| 648 | |
---|
| 649 | if(currentMode==sync){ |
---|
| 650 | // the only way to get here is in sync mode and dojo.required a module that |
---|
| 651 | // * was loaded async in the injectModule application a few lines up |
---|
| 652 | // * was an AMD module that had deps that are being loaded async and therefore couldn't execute |
---|
| 653 | if(module.cjs){ |
---|
| 654 | // the module was an AMD module; unshift, not push, which causes the current traversal to be reattempted from the top |
---|
| 655 | execQ.unshift(module); |
---|
| 656 | }else{ |
---|
| 657 | // the module was a legacy module |
---|
| 658 | syncExecStack.length && (syncExecStack[0].finish= [mid]); |
---|
| 659 | } |
---|
| 660 | }else{ |
---|
| 661 | // the loader wasn't in sync mode on entry; probably async mode; therefore, no expectation of getting |
---|
| 662 | // the module value synchronously; make sure it gets executed though |
---|
| 663 | execQ.push(module); |
---|
| 664 | } |
---|
| 665 | |
---|
| 666 | return undefined; |
---|
| 667 | } |
---|
| 668 | |
---|
| 669 | var result = doRequire(moduleName, omitModuleCheck); |
---|
| 670 | if(has("config-publishRequireResult") && !lang.exists(moduleName) && result!==undefined){ |
---|
| 671 | lang.setObject(moduleName, result); |
---|
| 672 | } |
---|
| 673 | return result; |
---|
| 674 | }; |
---|
| 675 | |
---|
| 676 | dojo.loadInit = function(f) { |
---|
| 677 | f(); |
---|
| 678 | }; |
---|
| 679 | |
---|
| 680 | dojo.registerModulePath = function(/*String*/moduleName, /*String*/prefix){ |
---|
| 681 | // summary: |
---|
| 682 | // Maps a module name to a path |
---|
| 683 | // description: |
---|
| 684 | // An unregistered module is given the default path of ../[module], |
---|
| 685 | // relative to Dojo root. For example, module acme is mapped to |
---|
| 686 | // ../acme. If you want to use a different module name, use |
---|
| 687 | // dojo.registerModulePath. |
---|
| 688 | // example: |
---|
| 689 | // If your dojo.js is located at this location in the web root: |
---|
| 690 | // | /myapp/js/dojo/dojo/dojo.js |
---|
| 691 | // and your modules are located at: |
---|
| 692 | // | /myapp/js/foo/bar.js |
---|
| 693 | // | /myapp/js/foo/baz.js |
---|
| 694 | // | /myapp/js/foo/thud/xyzzy.js |
---|
| 695 | // Your application can tell Dojo to locate the "foo" namespace by calling: |
---|
| 696 | // | dojo.registerModulePath("foo", "../../foo"); |
---|
| 697 | // At which point you can then use dojo.require() to load the |
---|
| 698 | // modules (assuming they provide() the same things which are |
---|
| 699 | // required). The full code might be: |
---|
| 700 | // | <script type="text/javascript" |
---|
| 701 | // | src="/myapp/js/dojo/dojo/dojo.js"></script> |
---|
| 702 | // | <script type="text/javascript"> |
---|
| 703 | // | dojo.registerModulePath("foo", "../../foo"); |
---|
| 704 | // | dojo.require("foo.bar"); |
---|
| 705 | // | dojo.require("foo.baz"); |
---|
| 706 | // | dojo.require("foo.thud.xyzzy"); |
---|
| 707 | // | </script> |
---|
| 708 | |
---|
| 709 | var paths = {}; |
---|
| 710 | paths[moduleName.replace(/\./g, "/")] = prefix; |
---|
| 711 | require({paths:paths}); |
---|
| 712 | }; |
---|
| 713 | |
---|
| 714 | dojo.platformRequire = function(/*Object*/modMap){ |
---|
| 715 | // summary: |
---|
| 716 | // require one or more modules based on which host environment |
---|
| 717 | // Dojo is currently operating in |
---|
| 718 | // description: |
---|
| 719 | // This method takes a "map" of arrays which one can use to |
---|
| 720 | // optionally load dojo modules. The map is indexed by the |
---|
| 721 | // possible dojo.name_ values, with two additional values: |
---|
| 722 | // "default" and "common". The items in the "default" array will |
---|
| 723 | // be loaded if none of the other items have been choosen based on |
---|
| 724 | // dojo.name_, set by your host environment. The items in the |
---|
| 725 | // "common" array will *always* be loaded, regardless of which |
---|
| 726 | // list is chosen. |
---|
| 727 | // example: |
---|
| 728 | // | dojo.platformRequire({ |
---|
| 729 | // | browser: [ |
---|
| 730 | // | "foo.sample", // simple module |
---|
| 731 | // | "foo.test", |
---|
| 732 | // | ["foo.bar.baz", true] // skip object check in _loadModule (dojo.require) |
---|
| 733 | // | ], |
---|
| 734 | // | default: [ "foo.sample._base" ], |
---|
| 735 | // | common: [ "important.module.common" ] |
---|
| 736 | // | }); |
---|
| 737 | |
---|
| 738 | var result = (modMap.common || []).concat(modMap[dojo._name] || modMap["default"] || []), |
---|
| 739 | temp; |
---|
| 740 | while(result.length){ |
---|
| 741 | if(lang.isArray(temp = result.shift())){ |
---|
| 742 | dojo.require.apply(dojo, temp); |
---|
| 743 | }else{ |
---|
| 744 | dojo.require(temp); |
---|
| 745 | } |
---|
| 746 | } |
---|
| 747 | }; |
---|
| 748 | |
---|
| 749 | dojo.requireIf = dojo.requireAfterIf = function(/*Boolean*/ condition, /*String*/ moduleName, /*Boolean?*/omitModuleCheck){ |
---|
| 750 | // summary: |
---|
| 751 | // If the condition is true then call `dojo.require()` for the specified |
---|
| 752 | // resource |
---|
| 753 | // |
---|
| 754 | // example: |
---|
| 755 | // | dojo.requireIf(dojo.isBrowser, "my.special.Module"); |
---|
| 756 | |
---|
| 757 | if(condition){ |
---|
| 758 | dojo.require(moduleName, omitModuleCheck); |
---|
| 759 | } |
---|
| 760 | }; |
---|
| 761 | |
---|
| 762 | dojo.requireLocalization = function(/*String*/moduleName, /*String*/bundleName, /*String?*/locale){ |
---|
| 763 | require(["../i18n"], function(i18n){ |
---|
| 764 | i18n.getLocalization(moduleName, bundleName, locale); |
---|
| 765 | }); |
---|
| 766 | }; |
---|
| 767 | |
---|
| 768 | return { |
---|
| 769 | // summary: |
---|
| 770 | // This module defines the v1.x synchronous loader API. |
---|
| 771 | |
---|
| 772 | extractLegacyApiApplications:extractLegacyApiApplications, |
---|
| 773 | require:dojoRequirePlugin, |
---|
| 774 | loadInit:dojoLoadInitPlugin |
---|
| 775 | }; |
---|
| 776 | }); |
---|