From e44a7e37b6c7b5961adaffc62b9042b8d442938e Mon Sep 17 00:00:00 2001 From: mensonge Date: Thu, 13 Nov 2008 09:49:11 +0000 Subject: New feature: basic Ajax suggestion for tags and implementation of Dojo toolkit git-svn-id: https://semanticscuttle.svn.sourceforge.net/svnroot/semanticscuttle/trunk@151 b3834d28-1941-0410-a4f8-b48e95affb8f --- includes/js/dojo/_base/_loader/loader_xd.js | 631 ++++++++++++++++++++++++++++ 1 file changed, 631 insertions(+) create mode 100644 includes/js/dojo/_base/_loader/loader_xd.js (limited to 'includes/js/dojo/_base/_loader/loader_xd.js') diff --git a/includes/js/dojo/_base/_loader/loader_xd.js b/includes/js/dojo/_base/_loader/loader_xd.js new file mode 100644 index 0000000..d851df8 --- /dev/null +++ b/includes/js/dojo/_base/_loader/loader_xd.js @@ -0,0 +1,631 @@ +if(!dojo._hasResource["dojo._base._loader.loader_xd"]){ //_hasResource checks added by build. Do not use _hasResource directly in your code. +dojo._hasResource["dojo._base._loader.loader_xd"] = true; +//Cross-domain resource loader. +dojo.provide("dojo._base._loader.loader_xd"); + +dojo._xdReset = function(){ + //summary: Internal xd loader function. Resets the xd state. + + //This flag indicates where or not we have crossed into xdomain territory. Once any resource says + //it is cross domain, then the rest of the resources have to be treated as xdomain because we need + //to evaluate resources in order. If there is a xdomain resource followed by a xhr resource, we can't load + //the xhr resource until the one before it finishes loading. The text of the xhr resource will be converted + //to match the format for a xd resource and put in the xd load queue. + this._isXDomain = dojo.config.useXDomain || false; + + this._xdTimer = 0; + this._xdInFlight = {}; + this._xdOrderedReqs = []; + this._xdDepMap = {}; + this._xdContents = []; + this._xdDefList = []; +} + +//Call reset immediately to set the state. +dojo._xdReset(); + +dojo._xdCreateResource = function(/*String*/contents, /*String*/resourceName, /*String*/resourcePath){ + //summary: Internal xd loader function. Creates an xd module source given an + //non-xd module contents. + + //Remove comments. Not perfect, but good enough for dependency resolution. + var depContents = contents.replace(/(\/\*([\s\S]*?)\*\/|\/\/(.*)$)/mg , ""); + + //Find dependencies. + var deps = []; + var depRegExp = /dojo.(require|requireIf|provide|requireAfterIf|platformRequire|requireLocalization)\(([\w\W]*?)\)/mg; + var match; + while((match = depRegExp.exec(depContents)) != null){ + if(match[1] == "requireLocalization"){ + //Need to load the local bundles asap, since they are not + //part of the list of modules watched for loading. + eval(match[0]); + }else{ + deps.push('"' + match[1] + '", ' + match[2]); + } + } + + //Create resource object and the call to _xdResourceLoaded. + var output = []; + output.push(dojo._scopeName + "._xdResourceLoaded({\n"); + + //Add dependencies + if(deps.length > 0){ + output.push("depends: ["); + for(var i = 0; i < deps.length; i++){ + if(i > 0){ + output.push(",\n"); + } + output.push("[" + deps[i] + "]"); + } + output.push("],"); + } + + //Add the contents of the file inside a function. + //Pass in scope arguments so we can support multiple versions of the + //same module on a page. + output.push("\ndefineResource: function(" + dojo._scopePrefixArgs + "){"); + + //Don't put in the contents in the debugAtAllCosts case + //since the contents may have syntax errors. Let those + //get pushed up when the script tags are added to the page + //in the debugAtAllCosts case. + if(!dojo.config["debugAtAllCosts"] || resourceName == "dojo._base._loader.loader_debug"){ + output.push(contents); + } + //Add isLocal property so we know if we have to do something different + //in debugAtAllCosts situations. + output.push("\n}, resourceName: '" + resourceName + "', resourcePath: '" + resourcePath + "'});"); + + return output.join(""); //String +} + +dojo._xdIsXDomainPath = function(/*string*/relpath) { + //summary: Figure out whether the path is local or x-domain + //If there is a colon before the first / then, we have a URL with a protocol. + + var colonIndex = relpath.indexOf(":"); + var slashIndex = relpath.indexOf("/"); + + if(colonIndex > 0 && colonIndex < slashIndex){ + return true; + }else{ + //Is the base script URI-based URL a cross domain URL? + //If so, then the relpath will be evaluated relative to + //baseUrl, and therefore qualify as xdomain. + //Only treat it as xdomain if the page does not have a + //host (file:// url) or if the baseUrl does not match the + //current window's domain. + var url = this.baseUrl; + colonIndex = url.indexOf(":"); + slashIndex = url.indexOf("/"); + if(colonIndex > 0 && colonIndex < slashIndex && (!location.host || url.indexOf("http://" + location.host) != 0)){ + return true; + } + } + return false; +} + +dojo._loadPath = function(/*String*/relpath, /*String?*/module, /*Function?*/cb){ + //summary: Internal xd loader function. Overrides loadPath() from loader.js. + //xd loading requires slightly different behavior from loadPath(). + + var currentIsXDomain = this._xdIsXDomainPath(relpath); + this._isXDomain |= currentIsXDomain; + + var uri = ((relpath.charAt(0) == '/' || relpath.match(/^\w+:/)) ? "" : this.baseUrl) + relpath; + + try{ + return ((!module || this._isXDomain) ? this._loadUri(uri, cb, currentIsXDomain, module) : this._loadUriAndCheck(uri, module, cb)); //Boolean + }catch(e){ + console.debug(e); + return false; //Boolean + } +} + +dojo._loadUri = function(/*String*/uri, /*Function?*/cb, /*boolean*/currentIsXDomain, /*String?*/module){ + //summary: Internal xd loader function. Overrides loadUri() from loader.js. + // xd loading requires slightly different behavior from loadPath(). + //description: Wanted to override getText(), but it is used by + // the widget code in too many, synchronous ways right now. + if(this._loadedUrls[uri]){ + return 1; //Boolean + } + + //Add the module (resource) to the list of modules. + //Only do this work if we have a modlue name. Otherwise, + //it is a non-xd i18n bundle, which can load immediately and does not + //need to be tracked. Also, don't track dojo.i18n, since it is a prerequisite + //and will be loaded correctly if we load it right away: it has no dependencies. + if(this._isXDomain && module && module != "dojo.i18n"){ + this._xdOrderedReqs.push(module); + + //Add to waiting resources if it is an xdomain resource. + //Don't add non-xdomain i18n bundles, those get evaled immediately. + if(currentIsXDomain || uri.indexOf("/nls/") == -1){ + this._xdInFlight[module] = true; + + //Increment inFlightCount + //This will stop the modulesLoaded from firing all the way. + this._inFlightCount++; + } + + //Start timer + if(!this._xdTimer){ + if(dojo.isAIR){ + this._xdTimer = setInterval(function(){dojo._xdWatchInFlight();}, 100); + }else{ + this._xdTimer = setInterval(dojo._scopeName + "._xdWatchInFlight();", 100); + } + } + this._xdStartTime = (new Date()).getTime(); + } + + if (currentIsXDomain){ + //Fix name to be a .xd.fileextension name. + var lastIndex = uri.lastIndexOf('.'); + if(lastIndex <= 0){ + lastIndex = uri.length - 1; + } + + var xdUri = uri.substring(0, lastIndex) + ".xd"; + if(lastIndex != uri.length - 1){ + xdUri += uri.substring(lastIndex, uri.length); + } + + if (dojo.isAIR){ + xdUri = xdUri.replace("app:/", "/"); + } + + //Add to script src + var element = document.createElement("script"); + element.type = "text/javascript"; + element.src = xdUri; + if(!this.headElement){ + this._headElement = document.getElementsByTagName("head")[0]; + + //Head element may not exist, particularly in html + //html 4 or tag soup cases where the page does not + //have a head tag in it. Use html element, since that will exist. + //Seems to be an issue mostly with Opera 9 and to lesser extent Safari 2 + if(!this._headElement){ + this._headElement = document.getElementsByTagName("html")[0]; + } + } + this._headElement.appendChild(element); + }else{ + var contents = this._getText(uri, null, true); + if(contents == null){ return 0; /*boolean*/} + + //If this is not xdomain, or if loading a i18n resource bundle, then send it down + //the normal eval/callback path. + if(this._isXDomain + && uri.indexOf("/nls/") == -1 + && module != "dojo.i18n"){ + var res = this._xdCreateResource(contents, module, uri); + dojo.eval(res); + }else{ + if(cb){ + contents = '('+contents+')'; + }else{ + //Only do the scoping if no callback. If a callback is specified, + //it is most likely the i18n bundle stuff. + contents = this._scopePrefix + contents + this._scopeSuffix; + } + var value = dojo["eval"](contents+"\r\n//@ sourceURL="+uri); + if(cb){ + cb(value); + } + } + } + + //These steps are done in the non-xd loader version of this function. + //Maintain these steps to fit in with the existing system. + this._loadedUrls[uri] = true; + this._loadedUrls.push(uri); + return true; //Boolean +} + +dojo._xdResourceLoaded = function(/*Object*/res){ + //summary: Internal xd loader function. Called by an xd module resource when + //it has been loaded via a script tag. + var deps = res.depends; + var requireList = null; + var requireAfterList = null; + var provideList = []; + if(deps && deps.length > 0){ + var dep = null; + var insertHint = 0; + var attachedResource = false; + for(var i = 0; i < deps.length; i++){ + dep = deps[i]; + + //Look for specific dependency indicators. + if (dep[0] == "provide"){ + provideList.push(dep[1]); + }else{ + if(!requireList){ + requireList = []; + } + if(!requireAfterList){ + requireAfterList = []; + } + + var unpackedDeps = this._xdUnpackDependency(dep); + if(unpackedDeps.requires){ + requireList = requireList.concat(unpackedDeps.requires); + } + if(unpackedDeps.requiresAfter){ + requireAfterList = requireAfterList.concat(unpackedDeps.requiresAfter); + } + } + + //Call the dependency indicator to allow for the normal dojo setup. + //Only allow for one dot reference, for the i18n._preloadLocalizations calls + //(and maybe future, one-dot things). + var depType = dep[0]; + var objPath = depType.split("."); + if(objPath.length == 2){ + dojo[objPath[0]][objPath[1]].apply(dojo[objPath[0]], dep.slice(1)); + }else{ + dojo[depType].apply(dojo, dep.slice(1)); + } + } + + + //If loading the debugAtAllCosts module, eval it right away since we need + //its functions to properly load the other modules. + if(provideList.length == 1 && provideList[0] == "dojo._base._loader.loader_debug"){ + res.defineResource(dojo); + }else{ + //Save off the resource contents for definition later. + var contentIndex = this._xdContents.push({ + content: res.defineResource, + resourceName: res["resourceName"], + resourcePath: res["resourcePath"], + isDefined: false + }) - 1; + + //Add provide/requires to dependency map. + for(var i = 0; i < provideList.length; i++){ + this._xdDepMap[provideList[i]] = { requires: requireList, requiresAfter: requireAfterList, contentIndex: contentIndex }; + } + } + + //Now update the inflight status for any provided resources in this loaded resource. + //Do this at the very end (in a *separate* for loop) to avoid shutting down the + //inflight timer check too soon. + for(var i = 0; i < provideList.length; i++){ + this._xdInFlight[provideList[i]] = false; + } + } +} + +dojo._xdLoadFlattenedBundle = function(/*String*/moduleName, /*String*/bundleName, /*String?*/locale, /*Object*/bundleData){ + //summary: Internal xd loader function. Used when loading + //a flattened localized bundle via a script tag. + locale = locale || "root"; + var jsLoc = dojo.i18n.normalizeLocale(locale).replace('-', '_'); + var bundleResource = [moduleName, "nls", bundleName].join("."); + var bundle = dojo["provide"](bundleResource); + bundle[jsLoc] = bundleData; + + //Assign the bundle for the original locale(s) we wanted. + var mapName = [moduleName, jsLoc, bundleName].join("."); + var bundleMap = dojo._xdBundleMap[mapName]; + if(bundleMap){ + for(var param in bundleMap){ + bundle[param] = bundleData; + } + } +}; + + +dojo._xdInitExtraLocales = function(){ + // Simulate the extra locale work that dojo.requireLocalization does. + + var extra = dojo.config.extraLocale; + if(extra){ + if(!extra instanceof Array){ + extra = [extra]; + } + + dojo._xdReqLoc = dojo.xdRequireLocalization; + dojo.xdRequireLocalization = function(m, b, locale, fLocales){ + dojo._xdReqLoc(m,b,locale, fLocales); + if(locale){return;} + for(var i=0; i bestLocale.length){ + bestLocale = locales[i]; + } + } + } + + var fixedBestLocale = bestLocale.replace('-', '_'); + //See if the bundle we are going to use is already loaded. + var bundleResource = dojo.getObject([moduleName, "nls", bundleName].join(".")); + if(bundleResource && bundleResource[fixedBestLocale]){ + bundle[jsLoc.replace('-', '_')] = bundleResource[fixedBestLocale]; + }else{ + //Need to remember what locale we wanted and which one we actually use. + //Then when we load the one we are actually using, use that bundle for the one + //we originally wanted. + var mapName = [moduleName, (fixedBestLocale||"root"), bundleName].join("."); + var bundleMap = dojo._xdBundleMap[mapName]; + if(!bundleMap){ + bundleMap = dojo._xdBundleMap[mapName] = {}; + } + bundleMap[jsLoc.replace('-', '_')] = true; + + //Do just a normal dojo.require so the resource tracking stuff works as usual. + dojo.require(moduleName + ".nls" + (bestLocale ? "." + bestLocale : "") + "." + bundleName); + } +} + +// Replace dojo.requireLocalization with a wrapper +dojo._xdRealRequireLocalization = dojo.requireLocalization; +dojo.requireLocalization = function(/*String*/moduleName, /*String*/bundleName, /*String?*/locale, /*String*/availableFlatLocales){ + // summary: loads a bundle intelligently based on whether the module is + // local or xd. Overrides the local-case implementation. + + var modulePath = this.moduleUrl(moduleName).toString(); + if (this._xdIsXDomainPath(modulePath)) { + // call cross-domain loader + return dojo.xdRequireLocalization.apply(dojo, arguments); + } else { + // call local-loader + return dojo._xdRealRequireLocalization.apply(dojo, arguments); + } +} + +//This is a bit brittle: it has to know about the dojo methods that deal with dependencies +//It would be ideal to intercept the actual methods and do something fancy at that point, +//but I have concern about knowing which provide to match to the dependency in that case, +//since scripts can load whenever they want, and trigger new calls to dojo._xdResourceLoaded(). +dojo._xdUnpackDependency = function(/*Array*/dep){ + //summary: Internal xd loader function. Determines what to do with a dependency + //that was listed in an xd version of a module contents. + + //Extract the dependency(ies). + var newDeps = null; + var newAfterDeps = null; + switch(dep[0]){ + case "requireIf": + case "requireAfterIf": + //First arg (dep[1]) is the test. Depedency is dep[2]. + if(dep[1] === true){ + newDeps = [{name: dep[2], content: null}]; + } + break; + case "platformRequire": + var modMap = dep[1]; + var common = modMap["common"]||[]; + var newDeps = (modMap[dojo.hostenv.name_]) ? common.concat(modMap[dojo.hostenv.name_]||[]) : common.concat(modMap["default"]||[]); + //Flatten the array of arrays into a one-level deep array. + //Each result could be an array of 3 elements (the 3 arguments to dojo.require). + //We only need the first one. + if(newDeps){ + for(var i = 0; i < newDeps.length; i++){ + if(newDeps[i] instanceof Array){ + newDeps[i] = {name: newDeps[i][0], content: null}; + }else{ + newDeps[i] = {name: newDeps[i], content: null}; + } + } + } + break; + case "require": + //Just worry about dep[1] + newDeps = [{name: dep[1], content: null}]; + break; + case "i18n._preloadLocalizations": + //We can eval these immediately, since they load i18n bundles. + //Since i18n bundles have no dependencies, whenever they are loaded + //in a script tag, they are evaluated immediately, so we do not have to + //treat them has an explicit dependency for the dependency mapping. + //We can call it immediately since dojo.i18n is part of dojo.xd.js. + dojo.i18n._preloadLocalizations.apply(dojo.i18n._preloadLocalizations, dep.slice(1)); + break; + } + + //The requireIf and requireAfterIf needs to be evaluated after the current resource is evaluated. + if(dep[0] == "requireAfterIf" || dep[0] == "requireIf"){ + newAfterDeps = newDeps; + newDeps = null; + } + return {requires: newDeps, requiresAfter: newAfterDeps}; //Object +} + +dojo._xdWalkReqs = function(){ + //summary: Internal xd loader function. + //Walks the requires and evaluates module resource contents in + //the right order. + var reqChain = null; + var req; + for(var i = 0; i < this._xdOrderedReqs.length; i++){ + req = this._xdOrderedReqs[i]; + if(this._xdDepMap[req]){ + reqChain = [req]; + reqChain[req] = true; //Allow for fast lookup of the req in the array + this._xdEvalReqs(reqChain); + } + } +} + +dojo._xdEvalReqs = function(/*Array*/reqChain){ + //summary: Internal xd loader function. + //Does a depth first, breadth second search and eval of required modules. + while(reqChain.length > 0){ + var req = reqChain[reqChain.length - 1]; + var res = this._xdDepMap[req]; + if(res){ + //Trace down any requires for this resource. + //START dojo._xdTraceReqs() inlining for small Safari 2.0 call stack + var reqs = res.requires; + if(reqs && reqs.length > 0){ + var nextReq; + for(var i = 0; i < reqs.length; i++){ + nextReq = reqs[i].name; + if(nextReq && !reqChain[nextReq]){ + //New req depedency. Follow it down. + reqChain.push(nextReq); + reqChain[nextReq] = true; + this._xdEvalReqs(reqChain); + } + } + } + //END dojo._xdTraceReqs() inlining for small Safari 2.0 call stack + + //Evaluate the resource. + var contents = this._xdContents[res.contentIndex]; + if(!contents.isDefined){ + var content = contents.content; + content["resourceName"] = contents["resourceName"]; + content["resourcePath"] = contents["resourcePath"]; + this._xdDefList.push(content); + contents.isDefined = true; + } + this._xdDepMap[req] = null; + + //Trace down any requireAfters for this resource. + //START dojo._xdTraceReqs() inlining for small Safari 2.0 call stack + var reqs = res.requiresAfter; + if(reqs && reqs.length > 0){ + var nextReq; + for(var i = 0; i < reqs.length; i++){ + nextReq = reqs[i].name; + if(nextReq && !reqChain[nextReq]){ + //New req depedency. Follow it down. + reqChain.push(nextReq); + reqChain[nextReq] = true; + this._xdEvalReqs(reqChain); + } + } + } + //END dojo._xdTraceReqs() inlining for small Safari 2.0 call stack + } + + //Done with that require. Remove it and go to the next one. + reqChain.pop(); + } +} + +dojo._xdClearInterval = function(){ + //summary: Internal xd loader function. + //Clears the interval timer used to check on the + //status of in-flight xd module resource requests. + clearInterval(this._xdTimer); + this._xdTimer = 0; +} + +dojo._xdWatchInFlight = function(){ + //summary: Internal xd loader function. + //Monitors in-flight requests for xd module resources. + + var noLoads = ""; + var waitInterval = (dojo.config.xdWaitSeconds || 15) * 1000; + var expired = (this._xdStartTime + waitInterval) < (new Date()).getTime(); + + //If any xdInFlight are true, then still waiting for something to load. + //Come back later. If we timed out, report the things that did not load. + for(var param in this._xdInFlight){ + if(this._xdInFlight[param] === true){ + if(expired){ + noLoads += param + " "; + }else{ + return; + } + } + } + + //All done. Clean up and notify. + this._xdClearInterval(); + + if(expired){ + throw "Could not load cross-domain resources: " + noLoads; + } + + this._xdWalkReqs(); + + var defLength = this._xdDefList.length; + for(var i= 0; i < defLength; i++){ + var content = dojo._xdDefList[i]; + if(dojo.config["debugAtAllCosts"] && content["resourceName"]){ + if(!this["_xdDebugQueue"]){ + this._xdDebugQueue = []; + } + this._xdDebugQueue.push({resourceName: content.resourceName, resourcePath: content.resourcePath}); + }else{ + //Evaluate the resource to bring it into being. + //Pass in scope args to allow multiple versions of modules in a page. + content.apply(dojo.global, dojo._scopeArgs); + } + } + + //Evaluate any resources that were not evaled before. + //This normally shouldn't happen with proper dojo.provide and dojo.require + //usage, but providing it just in case. Note that these may not be executed + //in the original order that the developer intended. + for(var i = 0; i < this._xdContents.length; i++){ + var current = this._xdContents[i]; + if(current.content && !current.isDefined){ + //Pass in scope args to allow multiple versions of modules in a page. + current.content.apply(dojo.global, dojo._scopeArgs); + } + } + + //Clean up for the next round of xd loading. + this._xdReset(); + + if(this["_xdDebugQueue"] && this._xdDebugQueue.length > 0){ + this._xdDebugFileLoaded(); + }else{ + this._xdNotifyLoaded(); + } +} + +dojo._xdNotifyLoaded = function(){ + //Clear inflight count so we will finally do finish work. + this._inFlightCount = 0; + + //Only trigger call loaded if dj_load_init has run. + if(this._initFired && !this._loadNotifying){ + this._callLoaded(); + } +} + +} -- cgit v1.2.3