]>
Commit | Line | Data |
---|---|---|
2f01fe57 | 1 | /* |
81bea17a | 2 | Copyright (c) 2004-2011, The Dojo Foundation All Rights Reserved. |
2f01fe57 AD |
3 | Available via Academic Free License >= 2.1 OR the modified BSD license. |
4 | see: http://dojotoolkit.org/license for details | |
5 | */ | |
6 | ||
7 | ||
a089699c AD |
8 | if(!dojo._hasResource["dojo._base._loader.loader_xd"]){ //_hasResource checks added by build. Do not use _hasResource directly in your code. |
9 | dojo._hasResource["dojo._base._loader.loader_xd"] = true; | |
10 | //Cross-domain resource loader. | |
2f01fe57 | 11 | dojo.provide("dojo._base._loader.loader_xd"); |
a089699c AD |
12 | |
13 | dojo._xdReset = function(){ | |
14 | //summary: Internal xd loader function. Resets the xd state. | |
15 | ||
16 | //This flag indicates where or not we have crossed into xdomain territory. Once any resource says | |
17 | //it is cross domain, then the rest of the resources have to be treated as xdomain because we need | |
18 | //to evaluate resources in order. If there is a xdomain resource followed by a xhr resource, we can't load | |
19 | //the xhr resource until the one before it finishes loading. The text of the xhr resource will be converted | |
20 | //to match the format for a xd resource and put in the xd load queue. | |
21 | dojo._isXDomain = dojo.config.useXDomain || false; | |
22 | ||
23 | dojo._xdClearInterval(); | |
24 | dojo._xdInFlight = {}; | |
25 | dojo._xdOrderedReqs = []; | |
26 | dojo._xdDepMap = {}; | |
27 | dojo._xdContents = []; | |
28 | dojo._xdDefList = []; | |
2f01fe57 | 29 | } |
a089699c AD |
30 | |
31 | dojo._xdClearInterval = function(){ | |
32 | //summary: Internal xd loader function. | |
33 | //Clears the interval timer used to check on the | |
34 | //status of in-flight xd module resource requests. | |
35 | if(dojo._xdTimer){ | |
36 | clearInterval(dojo._xdTimer); | |
37 | dojo._xdTimer = 0; | |
38 | } | |
2f01fe57 | 39 | } |
a089699c AD |
40 | |
41 | ||
42 | //Call reset immediately to set the state. | |
43 | dojo._xdReset(); | |
44 | ||
45 | dojo._xdCreateResource = function(/*String*/contents, /*String*/resourceName, /*String*/resourcePath){ | |
46 | //summary: Internal xd loader function. Creates an xd module source given an | |
47 | //non-xd module contents. | |
48 | ||
49 | //Remove comments. Not perfect, but good enough for dependency resolution. | |
50 | var depContents = contents.replace(/(\/\*([\s\S]*?)\*\/|\/\/(.*)$)/mg , ""); | |
51 | ||
52 | //Find dependencies. | |
53 | var deps = []; | |
54 | var depRegExp = /dojo.(require|requireIf|provide|requireAfterIf|platformRequire|requireLocalization)\s*\(([\w\W]*?)\)/mg; | |
55 | var match; | |
56 | while((match = depRegExp.exec(depContents)) != null){ | |
57 | if(match[1] == "requireLocalization"){ | |
58 | //Need to load the local bundles asap, since they are not | |
59 | //part of the list of modules watched for loading. | |
60 | eval(match[0]); | |
61 | }else{ | |
62 | deps.push('"' + match[1] + '", ' + match[2]); | |
63 | } | |
64 | } | |
65 | ||
66 | //Create resource object and the call to _xdResourceLoaded. | |
67 | var output = []; | |
68 | output.push(dojo._scopeName + "._xdResourceLoaded(function(" + dojo._scopePrefixArgs + "){\n"); | |
69 | ||
70 | //See if there are any dojo.loadInit calls | |
71 | var loadInitCalls = dojo._xdExtractLoadInits(contents); | |
72 | if(loadInitCalls){ | |
73 | //Adjust fileContents since extractLoadInits removed something. | |
74 | contents = loadInitCalls[0]; | |
75 | ||
76 | //Add any loadInit calls to the top of the xd file. | |
77 | for(var i = 1; i < loadInitCalls.length; i++){ | |
78 | output.push(loadInitCalls[i] + ";\n"); | |
79 | } | |
80 | } | |
81 | ||
82 | output.push("return {"); | |
83 | ||
84 | //Add dependencies | |
85 | if(deps.length > 0){ | |
86 | output.push("depends: ["); | |
87 | for(i = 0; i < deps.length; i++){ | |
88 | if(i > 0){ | |
89 | output.push(",\n"); | |
90 | } | |
91 | output.push("[" + deps[i] + "]"); | |
92 | } | |
93 | output.push("],"); | |
94 | } | |
95 | ||
96 | //Add the contents of the file inside a function. | |
97 | //Pass in scope arguments so we can support multiple versions of the | |
98 | //same module on a page. | |
99 | output.push("\ndefineResource: function(" + dojo._scopePrefixArgs + "){"); | |
100 | ||
101 | //Don't put in the contents in the debugAtAllCosts case | |
102 | //since the contents may have syntax errors. Let those | |
103 | //get pushed up when the script tags are added to the page | |
104 | //in the debugAtAllCosts case. | |
105 | if(!dojo.config["debugAtAllCosts"] || resourceName == "dojo._base._loader.loader_debug"){ | |
106 | output.push(contents); | |
107 | } | |
108 | //Add isLocal property so we know if we have to do something different | |
109 | //in debugAtAllCosts situations. | |
110 | output.push("\n}, resourceName: '" + resourceName + "', resourcePath: '" + resourcePath + "'};});"); | |
111 | ||
112 | return output.join(""); //String | |
2f01fe57 | 113 | } |
a089699c AD |
114 | |
115 | dojo._xdExtractLoadInits = function(/*String*/fileContents){ | |
116 | //Extracts | |
117 | var regexp = /dojo.loadInit\s*\(/g; | |
118 | regexp.lastIndex = 0; | |
119 | ||
120 | var parenRe = /[\(\)]/g; | |
121 | parenRe.lastIndex = 0; | |
122 | ||
123 | var results = []; | |
124 | var matches; | |
125 | while((matches = regexp.exec(fileContents))){ | |
126 | //Find end of the call by finding the matching end paren | |
127 | parenRe.lastIndex = regexp.lastIndex; | |
128 | var matchCount = 1; | |
129 | var parenMatch; | |
130 | while((parenMatch = parenRe.exec(fileContents))){ | |
131 | if(parenMatch[0] == ")"){ | |
132 | matchCount -= 1; | |
133 | }else{ | |
134 | matchCount += 1; | |
135 | } | |
136 | if(matchCount == 0){ | |
137 | break; | |
138 | } | |
139 | } | |
140 | ||
141 | if(matchCount != 0){ | |
142 | throw "unmatched paren around character " + parenRe.lastIndex + " in: " + fileContents; | |
143 | } | |
144 | ||
145 | //Put the master matching string in the results. | |
146 | var startIndex = regexp.lastIndex - matches[0].length; | |
147 | results.push(fileContents.substring(startIndex, parenRe.lastIndex)); | |
148 | ||
149 | //Remove the matching section. | |
150 | var remLength = parenRe.lastIndex - startIndex; | |
151 | fileContents = fileContents.substring(0, startIndex) + fileContents.substring(parenRe.lastIndex, fileContents.length); | |
152 | ||
153 | //Move the master regexp past the last matching paren point. | |
154 | regexp.lastIndex = parenRe.lastIndex - remLength; | |
155 | ||
156 | regexp.lastIndex = parenRe.lastIndex; | |
157 | } | |
158 | ||
159 | if(results.length > 0){ | |
160 | results.unshift(fileContents); | |
161 | } | |
162 | ||
163 | return (results.length ? results : null); | |
2f01fe57 | 164 | } |
a089699c AD |
165 | |
166 | dojo._xdIsXDomainPath = function(/*string*/relpath) { | |
167 | //summary: Figure out whether the path is local or x-domain | |
168 | //If there is a colon before the first / then, we have a URL with a protocol. | |
169 | ||
170 | var colonIndex = relpath.indexOf(":"); | |
171 | var slashIndex = relpath.indexOf("/"); | |
172 | ||
81bea17a | 173 | if(colonIndex > 0 && colonIndex < slashIndex || relpath.indexOf("//") === 0){ |
a089699c AD |
174 | return true; |
175 | }else{ | |
176 | //Is the base script URI-based URL a cross domain URL? | |
177 | //If so, then the relpath will be evaluated relative to | |
178 | //baseUrl, and therefore qualify as xdomain. | |
179 | //Only treat it as xdomain if the page does not have a | |
81bea17a AD |
180 | //host (file:// url), if the baseUrl does not match the |
181 | //current window's domain, or if the baseUrl starts with //. | |
182 | //If baseUrl starts with // then it probably means that xdomain | |
183 | //is wanted since it is such a specific path request. This is not completely robust, | |
184 | //but something more robust would require normalizing the protocol on baseUrl and on the location | |
185 | //to see if they differ. However, that requires more code, and // as a start path is unusual. | |
a089699c AD |
186 | var url = dojo.baseUrl; |
187 | colonIndex = url.indexOf(":"); | |
188 | slashIndex = url.indexOf("/"); | |
81bea17a | 189 | if(url.indexOf("//") === 0 || (colonIndex > 0 && colonIndex < slashIndex && (!location.host || url.indexOf("http://" + location.host) != 0))){ |
a089699c AD |
190 | return true; |
191 | } | |
192 | } | |
81bea17a | 193 | return false; |
2f01fe57 | 194 | } |
a089699c AD |
195 | |
196 | dojo._loadPath = function(/*String*/relpath, /*String?*/module, /*Function?*/cb){ | |
197 | //summary: Internal xd loader function. Overrides loadPath() from loader.js. | |
198 | //xd loading requires slightly different behavior from loadPath(). | |
199 | ||
200 | var currentIsXDomain = dojo._xdIsXDomainPath(relpath); | |
201 | dojo._isXDomain |= currentIsXDomain; | |
202 | ||
203 | var uri = ((relpath.charAt(0) == '/' || relpath.match(/^\w+:/)) ? "" : dojo.baseUrl) + relpath; | |
204 | ||
205 | try{ | |
206 | return ((!module || dojo._isXDomain) ? dojo._loadUri(uri, cb, currentIsXDomain, module) : dojo._loadUriAndCheck(uri, module, cb)); //Boolean | |
207 | }catch(e){ | |
208 | console.error(e); | |
209 | return false; //Boolean | |
210 | } | |
2f01fe57 | 211 | } |
a089699c AD |
212 | |
213 | dojo._xdCharSet = "utf-8"; | |
214 | ||
215 | dojo._loadUri = function(/*String*/uri, /*Function?*/cb, /*boolean*/currentIsXDomain, /*String?*/module){ | |
216 | //summary: Internal xd loader function. Overrides loadUri() from loader.js. | |
217 | // xd loading requires slightly different behavior from loadPath(). | |
218 | //description: Wanted to override getText(), but it is used by | |
219 | // the widget code in too many, synchronous ways right now. | |
220 | if(dojo._loadedUrls[uri]){ | |
221 | return 1; //Boolean | |
222 | } | |
223 | ||
224 | //Add the module (resource) to the list of modules. | |
81bea17a AD |
225 | //Only do this work if we have a modlue name. Otherwise, |
226 | //it is a non-xd i18n bundle, which can load immediately and does not | |
a089699c AD |
227 | //need to be tracked. Also, don't track dojo.i18n, since it is a prerequisite |
228 | //and will be loaded correctly if we load it right away: it has no dependencies. | |
229 | if(dojo._isXDomain && module && module != "dojo.i18n"){ | |
230 | dojo._xdOrderedReqs.push(module); | |
231 | ||
232 | //Add to waiting resources if it is an xdomain resource. | |
233 | //Don't add non-xdomain i18n bundles, those get evaled immediately. | |
234 | if(currentIsXDomain || uri.indexOf("/nls/") == -1){ | |
235 | dojo._xdInFlight[module] = true; | |
236 | ||
237 | //Increment inFlightCount | |
238 | //This will stop the modulesLoaded from firing all the way. | |
239 | dojo._inFlightCount++; | |
240 | } | |
241 | ||
242 | //Start timer | |
243 | if(!dojo._xdTimer){ | |
244 | if(dojo.isAIR){ | |
245 | dojo._xdTimer = setInterval(function(){dojo._xdWatchInFlight();}, 100); | |
246 | }else{ | |
247 | dojo._xdTimer = setInterval(dojo._scopeName + "._xdWatchInFlight();", 100); | |
248 | } | |
249 | } | |
250 | dojo._xdStartTime = (new Date()).getTime(); | |
251 | } | |
252 | ||
253 | if (currentIsXDomain){ | |
254 | //Fix name to be a .xd.fileextension name. | |
255 | var lastIndex = uri.lastIndexOf('.'); | |
256 | if(lastIndex <= 0){ | |
257 | lastIndex = uri.length - 1; | |
258 | } | |
259 | ||
260 | var xdUri = uri.substring(0, lastIndex) + ".xd"; | |
261 | if(lastIndex != uri.length - 1){ | |
262 | xdUri += uri.substring(lastIndex, uri.length); | |
263 | } | |
264 | ||
265 | if (dojo.isAIR){ | |
266 | xdUri = xdUri.replace("app:/", "/"); | |
267 | } | |
268 | ||
269 | //Add to script src | |
270 | var element = document.createElement("script"); | |
271 | element.type = "text/javascript"; | |
272 | if(dojo._xdCharSet){ | |
273 | element.charset = dojo._xdCharSet; | |
274 | } | |
275 | element.src = xdUri; | |
276 | if(!dojo.headElement){ | |
277 | dojo._headElement = document.getElementsByTagName("head")[0]; | |
278 | ||
279 | //Head element may not exist, particularly in html | |
280 | //html 4 or tag soup cases where the page does not | |
281 | //have a head tag in it. Use html element, since that will exist. | |
282 | //Seems to be an issue mostly with Opera 9 and to lesser extent Safari 2 | |
283 | if(!dojo._headElement){ | |
284 | dojo._headElement = document.getElementsByTagName("html")[0]; | |
285 | } | |
286 | } | |
287 | dojo._headElement.appendChild(element); | |
288 | }else{ | |
289 | var contents = dojo._getText(uri, null, true); | |
290 | if(contents == null){ return 0; /*boolean*/} | |
291 | ||
292 | //If this is not xdomain, or if loading a i18n resource bundle, then send it down | |
293 | //the normal eval/callback path. | |
294 | if(dojo._isXDomain | |
295 | && uri.indexOf("/nls/") == -1 | |
296 | && module != "dojo.i18n"){ | |
297 | var res = dojo._xdCreateResource(contents, module, uri); | |
298 | dojo.eval(res); | |
299 | }else{ | |
300 | if(cb){ | |
301 | contents = '('+contents+')'; | |
302 | }else{ | |
303 | //Only do the scoping if no callback. If a callback is specified, | |
304 | //it is most likely the i18n bundle stuff. | |
305 | contents = dojo._scopePrefix + contents + dojo._scopeSuffix; | |
306 | } | |
307 | var value = dojo["eval"](contents+"\r\n//@ sourceURL="+uri); | |
308 | if(cb){ | |
309 | cb(value); | |
310 | } | |
311 | } | |
312 | } | |
313 | ||
314 | //These steps are done in the non-xd loader version of this function. | |
315 | //Maintain these steps to fit in with the existing system. | |
316 | dojo._loadedUrls[uri] = true; | |
317 | dojo._loadedUrls.push(uri); | |
318 | return true; //Boolean | |
2f01fe57 | 319 | } |
a089699c AD |
320 | |
321 | dojo._xdResourceLoaded = function(/*Object*/res){ | |
322 | //summary: Internal xd loader function. Called by an xd module resource when | |
323 | //it has been loaded via a script tag. | |
324 | ||
325 | //Evaluate the function with scopeArgs for multiversion support. | |
326 | res = res.apply(dojo.global, dojo._scopeArgs); | |
327 | ||
328 | //Work through dependencies. | |
329 | var deps = res.depends; | |
330 | var requireList = null; | |
331 | var requireAfterList = null; | |
332 | var provideList = []; | |
333 | if(deps && deps.length > 0){ | |
334 | var dep = null; | |
335 | var insertHint = 0; | |
336 | var attachedResource = false; | |
337 | for(var i = 0; i < deps.length; i++){ | |
338 | dep = deps[i]; | |
339 | ||
340 | //Look for specific dependency indicators. | |
341 | if (dep[0] == "provide"){ | |
342 | provideList.push(dep[1]); | |
343 | }else{ | |
344 | if(!requireList){ | |
345 | requireList = []; | |
346 | } | |
347 | if(!requireAfterList){ | |
348 | requireAfterList = []; | |
349 | } | |
350 | ||
351 | var unpackedDeps = dojo._xdUnpackDependency(dep); | |
352 | if(unpackedDeps.requires){ | |
353 | requireList = requireList.concat(unpackedDeps.requires); | |
354 | } | |
355 | if(unpackedDeps.requiresAfter){ | |
356 | requireAfterList = requireAfterList.concat(unpackedDeps.requiresAfter); | |
357 | } | |
358 | } | |
359 | ||
360 | //Call the dependency indicator to allow for the normal dojo setup. | |
361 | //Only allow for one dot reference, for the i18n._preloadLocalizations calls | |
362 | //(and maybe future, one-dot things). | |
363 | var depType = dep[0]; | |
364 | var objPath = depType.split("."); | |
365 | if(objPath.length == 2){ | |
366 | dojo[objPath[0]][objPath[1]].apply(dojo[objPath[0]], dep.slice(1)); | |
367 | }else{ | |
368 | dojo[depType].apply(dojo, dep.slice(1)); | |
369 | } | |
370 | } | |
371 | ||
372 | ||
373 | //If loading the debugAtAllCosts module, eval it right away since we need | |
374 | //its functions to properly load the other modules. | |
375 | if(provideList.length == 1 && provideList[0] == "dojo._base._loader.loader_debug"){ | |
376 | res.defineResource(dojo); | |
377 | }else{ | |
378 | //Save off the resource contents for definition later. | |
379 | var contentIndex = dojo._xdContents.push({ | |
380 | content: res.defineResource, | |
381 | resourceName: res["resourceName"], | |
382 | resourcePath: res["resourcePath"], | |
383 | isDefined: false | |
384 | }) - 1; | |
385 | ||
386 | //Add provide/requires to dependency map. | |
387 | for(i = 0; i < provideList.length; i++){ | |
388 | dojo._xdDepMap[provideList[i]] = { requires: requireList, requiresAfter: requireAfterList, contentIndex: contentIndex }; | |
389 | } | |
390 | } | |
391 | ||
392 | //Now update the inflight status for any provided resources in this loaded resource. | |
81bea17a | 393 | //Do this at the very end (in a *separate* for loop) to avoid shutting down the |
a089699c AD |
394 | //inflight timer check too soon. |
395 | for(i = 0; i < provideList.length; i++){ | |
396 | dojo._xdInFlight[provideList[i]] = false; | |
397 | } | |
398 | } | |
2f01fe57 | 399 | } |
a089699c AD |
400 | |
401 | dojo._xdLoadFlattenedBundle = function(/*String*/moduleName, /*String*/bundleName, /*String?*/locale, /*Object*/bundleData){ | |
402 | //summary: Internal xd loader function. Used when loading | |
403 | //a flattened localized bundle via a script tag. | |
404 | locale = locale || "root"; | |
405 | var jsLoc = dojo.i18n.normalizeLocale(locale).replace('-', '_'); | |
406 | var bundleResource = [moduleName, "nls", bundleName].join("."); | |
407 | var bundle = dojo["provide"](bundleResource); | |
408 | bundle[jsLoc] = bundleData; | |
409 | ||
410 | //Assign the bundle for the original locale(s) we wanted. | |
411 | var mapName = [moduleName, jsLoc, bundleName].join("."); | |
412 | var bundleMap = dojo._xdBundleMap[mapName]; | |
413 | if(bundleMap){ | |
414 | for(var param in bundleMap){ | |
415 | bundle[param] = bundleData; | |
416 | } | |
417 | } | |
2f01fe57 | 418 | }; |
a089699c AD |
419 | |
420 | ||
421 | dojo._xdInitExtraLocales = function(){ | |
422 | // Simulate the extra locale work that dojo.requireLocalization does. | |
423 | ||
424 | var extra = dojo.config.extraLocale; | |
425 | if(extra){ | |
426 | if(!extra instanceof Array){ | |
427 | extra = [extra]; | |
428 | } | |
429 | ||
430 | dojo._xdReqLoc = dojo.xdRequireLocalization; | |
431 | dojo.xdRequireLocalization = function(m, b, locale, fLocales){ | |
432 | dojo._xdReqLoc(m,b,locale, fLocales); | |
433 | if(locale){return;} | |
434 | for(var i=0; i<extra.length; i++){ | |
435 | dojo._xdReqLoc(m,b,extra[i], fLocales); | |
436 | } | |
437 | }; | |
438 | } | |
2f01fe57 | 439 | } |
a089699c AD |
440 | |
441 | dojo._xdBundleMap = {}; | |
442 | ||
443 | dojo.xdRequireLocalization = function(/*String*/moduleName, /*String*/bundleName, /*String?*/locale, /*String*/availableFlatLocales){ | |
444 | //summary: Internal xd loader function. The xd version of dojo.requireLocalization. | |
445 | ||
446 | ||
447 | //Account for allowing multiple extra locales. Do this here inside the function | |
448 | //since dojo._xdInitExtraLocales() depends on djConfig being set up, but that only | |
449 | //happens after hostenv_browser runs. loader_xd has to come before hostenv_browser | |
450 | //though since hostenv_browser can do a dojo.require for the debug module. | |
451 | if(dojo._xdInitExtraLocales){ | |
452 | dojo._xdInitExtraLocales(); | |
453 | dojo._xdInitExtraLocales = null; | |
454 | dojo.xdRequireLocalization.apply(dojo, arguments); | |
455 | return; | |
456 | } | |
457 | ||
458 | var locales = availableFlatLocales.split(","); | |
459 | ||
460 | //Find the best-match locale to load. | |
461 | //Assumes dojo.i18n has already been loaded. This is true for xdomain builds, | |
462 | //since it is included in dojo.xd.js. | |
463 | var jsLoc = dojo.i18n.normalizeLocale(locale); | |
464 | ||
465 | var bestLocale = ""; | |
466 | for(var i = 0; i < locales.length; i++){ | |
467 | //Locale must match from start of string. | |
468 | if(jsLoc.indexOf(locales[i]) == 0){ | |
469 | if(locales[i].length > bestLocale.length){ | |
470 | bestLocale = locales[i]; | |
471 | } | |
472 | } | |
473 | } | |
474 | ||
475 | var fixedBestLocale = bestLocale.replace('-', '_'); | |
476 | //See if the bundle we are going to use is already loaded. | |
477 | var bundleResource = dojo.getObject([moduleName, "nls", bundleName].join(".")); | |
478 | if(!bundleResource || !bundleResource[fixedBestLocale]){ | |
479 | //Need to remember what locale we wanted and which one we actually use. | |
480 | //Then when we load the one we are actually using, use that bundle for the one | |
481 | //we originally wanted. | |
482 | var mapName = [moduleName, (fixedBestLocale||"root"), bundleName].join("."); | |
483 | var bundleMap = dojo._xdBundleMap[mapName]; | |
484 | if(!bundleMap){ | |
485 | bundleMap = dojo._xdBundleMap[mapName] = {}; | |
486 | } | |
487 | bundleMap[jsLoc.replace('-', '_')] = true; | |
488 | ||
489 | //Do just a normal dojo.require so the resource tracking stuff works as usual. | |
490 | dojo.require(moduleName + ".nls" + (bestLocale ? "." + bestLocale : "") + "." + bundleName); | |
491 | } | |
2f01fe57 | 492 | } |
a089699c AD |
493 | |
494 | // Replace dojo.requireLocalization with a wrapper | |
495 | dojo._xdRealRequireLocalization = dojo.requireLocalization; | |
496 | dojo.requireLocalization = function(/*String*/moduleName, /*String*/bundleName, /*String?*/locale, /*String*/availableFlatLocales){ | |
81bea17a | 497 | // summary: loads a bundle intelligently based on whether the module is |
a089699c AD |
498 | // local or xd. Overrides the local-case implementation. |
499 | ||
500 | var modulePath = dojo.moduleUrl(moduleName).toString(); | |
501 | if (dojo._xdIsXDomainPath(modulePath)) { | |
502 | // call cross-domain loader | |
503 | return dojo.xdRequireLocalization.apply(dojo, arguments); | |
504 | } else { | |
505 | // call local-loader | |
506 | return dojo._xdRealRequireLocalization.apply(dojo, arguments); | |
507 | } | |
2f01fe57 | 508 | } |
a089699c AD |
509 | |
510 | //This is a bit brittle: it has to know about the dojo methods that deal with dependencies | |
511 | //It would be ideal to intercept the actual methods and do something fancy at that point, | |
512 | //but I have concern about knowing which provide to match to the dependency in that case, | |
513 | //since scripts can load whenever they want, and trigger new calls to dojo._xdResourceLoaded(). | |
514 | dojo._xdUnpackDependency = function(/*Array*/dep){ | |
515 | //summary: Internal xd loader function. Determines what to do with a dependency | |
516 | //that was listed in an xd version of a module contents. | |
517 | ||
518 | //Extract the dependency(ies). | |
519 | var newDeps = null; | |
520 | var newAfterDeps = null; | |
521 | switch(dep[0]){ | |
522 | case "requireIf": | |
523 | case "requireAfterIf": | |
524 | //First arg (dep[1]) is the test. Depedency is dep[2]. | |
525 | if(dep[1] === true){ | |
526 | newDeps = [{name: dep[2], content: null}]; | |
527 | } | |
528 | break; | |
529 | case "platformRequire": | |
530 | var modMap = dep[1]; | |
531 | var common = modMap["common"]||[]; | |
81bea17a | 532 | newDeps = (modMap[dojo.hostenv.name_]) ? common.concat(modMap[dojo.hostenv.name_]||[]) : common.concat(modMap["default"]||[]); |
a089699c AD |
533 | //Flatten the array of arrays into a one-level deep array. |
534 | //Each result could be an array of 3 elements (the 3 arguments to dojo.require). | |
535 | //We only need the first one. | |
536 | if(newDeps){ | |
537 | for(var i = 0; i < newDeps.length; i++){ | |
538 | if(newDeps[i] instanceof Array){ | |
539 | newDeps[i] = {name: newDeps[i][0], content: null}; | |
540 | }else{ | |
541 | newDeps[i] = {name: newDeps[i], content: null}; | |
542 | } | |
543 | } | |
544 | } | |
545 | break; | |
546 | case "require": | |
547 | //Just worry about dep[1] | |
548 | newDeps = [{name: dep[1], content: null}]; | |
549 | break; | |
550 | case "i18n._preloadLocalizations": | |
551 | //We can eval these immediately, since they load i18n bundles. | |
552 | //Since i18n bundles have no dependencies, whenever they are loaded | |
553 | //in a script tag, they are evaluated immediately, so we do not have to | |
554 | //treat them has an explicit dependency for the dependency mapping. | |
555 | //We can call it immediately since dojo.i18n is part of dojo.xd.js. | |
556 | dojo.i18n._preloadLocalizations.apply(dojo.i18n._preloadLocalizations, dep.slice(1)); | |
557 | break; | |
558 | } | |
559 | ||
560 | //The requireIf and requireAfterIf needs to be evaluated after the current resource is evaluated. | |
561 | if(dep[0] == "requireAfterIf" || dep[0] == "requireIf"){ | |
562 | newAfterDeps = newDeps; | |
563 | newDeps = null; | |
564 | } | |
565 | return {requires: newDeps, requiresAfter: newAfterDeps}; //Object | |
2f01fe57 | 566 | } |
a089699c AD |
567 | |
568 | dojo._xdWalkReqs = function(){ | |
81bea17a | 569 | //summary: Internal xd loader function. |
a089699c AD |
570 | //Walks the requires and evaluates module resource contents in |
571 | //the right order. | |
572 | var reqChain = null; | |
573 | var req; | |
574 | for(var i = 0; i < dojo._xdOrderedReqs.length; i++){ | |
575 | req = dojo._xdOrderedReqs[i]; | |
576 | if(dojo._xdDepMap[req]){ | |
577 | reqChain = [req]; | |
578 | reqChain[req] = true; //Allow for fast lookup of the req in the array | |
579 | dojo._xdEvalReqs(reqChain); | |
580 | } | |
581 | } | |
2f01fe57 | 582 | } |
a089699c AD |
583 | |
584 | dojo._xdEvalReqs = function(/*Array*/reqChain){ | |
81bea17a | 585 | //summary: Internal xd loader function. |
a089699c AD |
586 | //Does a depth first, breadth second search and eval of required modules. |
587 | while(reqChain.length > 0){ | |
588 | var req = reqChain[reqChain.length - 1]; | |
589 | var res = dojo._xdDepMap[req]; | |
590 | var i, reqs, nextReq; | |
591 | if(res){ | |
592 | //Trace down any requires for this resource. | |
593 | //START dojo._xdTraceReqs() inlining for small Safari 2.0 call stack | |
594 | reqs = res.requires; | |
595 | if(reqs && reqs.length > 0){ | |
596 | for(i = 0; i < reqs.length; i++){ | |
597 | nextReq = reqs[i].name; | |
598 | if(nextReq && !reqChain[nextReq]){ | |
599 | //New req depedency. Follow it down. | |
600 | reqChain.push(nextReq); | |
601 | reqChain[nextReq] = true; | |
602 | dojo._xdEvalReqs(reqChain); | |
603 | } | |
604 | } | |
605 | } | |
606 | //END dojo._xdTraceReqs() inlining for small Safari 2.0 call stack | |
607 | ||
608 | //Evaluate the resource. | |
609 | var contents = dojo._xdContents[res.contentIndex]; | |
610 | if(!contents.isDefined){ | |
611 | var content = contents.content; | |
612 | content["resourceName"] = contents["resourceName"]; | |
613 | content["resourcePath"] = contents["resourcePath"]; | |
614 | dojo._xdDefList.push(content); | |
615 | contents.isDefined = true; | |
616 | } | |
617 | dojo._xdDepMap[req] = null; | |
618 | ||
619 | //Trace down any requireAfters for this resource. | |
620 | //START dojo._xdTraceReqs() inlining for small Safari 2.0 call stack | |
621 | reqs = res.requiresAfter; | |
622 | if(reqs && reqs.length > 0){ | |
623 | for(i = 0; i < reqs.length; i++){ | |
624 | nextReq = reqs[i].name; | |
625 | if(nextReq && !reqChain[nextReq]){ | |
626 | //New req depedency. Follow it down. | |
627 | reqChain.push(nextReq); | |
628 | reqChain[nextReq] = true; | |
629 | dojo._xdEvalReqs(reqChain); | |
630 | } | |
631 | } | |
632 | } | |
633 | //END dojo._xdTraceReqs() inlining for small Safari 2.0 call stack | |
634 | } | |
635 | ||
636 | //Done with that require. Remove it and go to the next one. | |
637 | reqChain.pop(); | |
638 | } | |
2f01fe57 | 639 | } |
a089699c AD |
640 | |
641 | dojo._xdWatchInFlight = function(){ | |
642 | //summary: Internal xd loader function. | |
643 | //Monitors in-flight requests for xd module resources. | |
644 | ||
645 | var noLoads = ""; | |
646 | var waitInterval = (dojo.config.xdWaitSeconds || 15) * 1000; | |
647 | var expired = (dojo._xdStartTime + waitInterval) < (new Date()).getTime(); | |
648 | ||
649 | //If any xdInFlight are true, then still waiting for something to load. | |
650 | //Come back later. If we timed out, report the things that did not load. | |
651 | for(var param in dojo._xdInFlight){ | |
652 | if(dojo._xdInFlight[param] === true){ | |
653 | if(expired){ | |
654 | noLoads += param + " "; | |
655 | }else{ | |
656 | return; | |
657 | } | |
658 | } | |
659 | } | |
660 | ||
661 | //All done. Clean up and notify. | |
662 | dojo._xdClearInterval(); | |
663 | ||
664 | if(expired){ | |
665 | throw "Could not load cross-domain resources: " + noLoads; | |
666 | } | |
667 | ||
668 | dojo._xdWalkReqs(); | |
669 | ||
670 | var defLength = dojo._xdDefList.length; | |
671 | for(var i= 0; i < defLength; i++){ | |
672 | var content = dojo._xdDefList[i]; | |
673 | if(dojo.config["debugAtAllCosts"] && content["resourceName"]){ | |
674 | if(!dojo["_xdDebugQueue"]){ | |
675 | dojo._xdDebugQueue = []; | |
676 | } | |
677 | dojo._xdDebugQueue.push({resourceName: content.resourceName, resourcePath: content.resourcePath}); | |
678 | }else{ | |
679 | //Evaluate the resource to bring it into being. | |
81bea17a | 680 | //Pass in scope args to allow multiple versions of modules in a page. |
a089699c AD |
681 | content.apply(dojo.global, dojo._scopeArgs); |
682 | } | |
683 | } | |
684 | ||
685 | //Evaluate any resources that were not evaled before. | |
686 | //This normally shouldn't happen with proper dojo.provide and dojo.require | |
687 | //usage, but providing it just in case. Note that these may not be executed | |
688 | //in the original order that the developer intended. | |
689 | for(i = 0; i < dojo._xdContents.length; i++){ | |
690 | var current = dojo._xdContents[i]; | |
691 | if(current.content && !current.isDefined){ | |
81bea17a | 692 | //Pass in scope args to allow multiple versions of modules in a page. |
a089699c AD |
693 | current.content.apply(dojo.global, dojo._scopeArgs); |
694 | } | |
695 | } | |
696 | ||
697 | //Clean up for the next round of xd loading. | |
698 | dojo._xdReset(); | |
699 | ||
700 | if(dojo["_xdDebugQueue"] && dojo._xdDebugQueue.length > 0){ | |
701 | dojo._xdDebugFileLoaded(); | |
702 | }else{ | |
703 | dojo._xdNotifyLoaded(); | |
704 | } | |
2f01fe57 | 705 | } |
a089699c AD |
706 | |
707 | dojo._xdNotifyLoaded = function(){ | |
708 | //Clear inflight count so we will finally do finish work. | |
709 | ||
710 | //Just having a legitimate status (true or false) for an inflight item | |
711 | //means that it is still being processed. Do the typeof test | |
712 | //to avoid bad JavaScript that might tinker with Object.prototype. | |
713 | for(var prop in dojo._xdInFlight){ | |
714 | if(typeof dojo._xdInFlight[prop] == "boolean"){ | |
715 | return; | |
716 | } | |
717 | } | |
718 | ||
81bea17a | 719 | dojo._inFlightCount = 0; |
a089699c | 720 | |
81bea17a AD |
721 | //Only trigger call loaded if dj_load_init has run. |
722 | if(dojo._initFired && !dojo._loadNotifying){ | |
a089699c AD |
723 | dojo._callLoaded(); |
724 | } | |
2f01fe57 | 725 | } |
a089699c | 726 | |
2f01fe57 | 727 | } |