source: [view]
/*
* loader.js - A bootstrap module. Runs before the hostenv_*.js file. Contains
* all of the package loading methods.
*/
//>>excludeStart("webkitMobile", kwArgs.webkitMobile);
(function(){
var d = dojo, currentModule;
//>>excludeEnd("webkitMobile");
d.mixin(d, {
_loadedModules: {},
_inFlightCount: 0,
_hasResource: {},
_modulePrefixes: {
dojo: { name: "dojo", value: "." },
// dojox: { name: "dojox", value: "../dojox" },
// dijit: { name: "dijit", value: "../dijit" },
doh: { name: "doh", value: "../util/doh" },
tests: { name: "tests", value: "tests" }
},
_moduleHasPrefix: function(/*String*/module){
// summary: checks to see if module has been established
var mp = d._modulePrefixes;
return !!(mp[module] && mp[module].value); // Boolean
},
_getModulePrefix: function(/*String*/module){
// summary: gets the prefix associated with module
var mp = d._modulePrefixes;
if(d._moduleHasPrefix(module)){
return mp[module].value; // String
}
return module; // String
},
_loadedUrls: [],
//WARNING:
// This variable is referenced by packages outside of bootstrap:
// FloatingPane.js and undo/browser.js
_postLoad: false,
//Egad! Lots of test files push on this directly instead of using dojo.addOnLoad.
_loaders: [],
_unloaders: [],
_loadNotifying: false
});
//>>excludeStart("xdomainExclude", fileName.indexOf("dojo.xd.js") != -1 && kwArgs.loader == "xdomain");
dojo._loadPath = function(/*String*/relpath, /*String?*/module, /*Function?*/cb){
// summary:
// Load a Javascript module given a relative path
//
// description:
// Loads and interprets the script located at relpath, which is
// relative to the script root directory. If the script is found but
// its interpretation causes a runtime exception, that exception is
// not caught by us, so the caller will see it. We return a true
// value if and only if the script is found.
//
// relpath:
// A relative path to a script (no leading '/', and typically ending
// in '.js').
// module:
// A module whose existance to check for after loading a path. Can be
// used to determine success or failure of the load.
// cb:
// a callback function to pass the result of evaluating the script
var uri = ((relpath.charAt(0) == '/' || relpath.match(/^\w+:/)) ? "" : d.baseUrl) + relpath;
try{
currentModule = module;
return !module ? d._loadUri(uri, cb) : d._loadUriAndCheck(uri, module, cb); // Boolean
}catch(e){
console.error(e);
return false; // Boolean
}finally{
currentModule = null;
}
}
dojo._loadUri = function(/*String*/uri, /*Function?*/cb){
// summary:
// Loads JavaScript from a URI
// description:
// Reads the contents of the URI, and evaluates the contents. This is
// used to load modules as well as resource bundles. Returns true if
// it succeeded. Returns false if the URI reading failed. Throws if
// the evaluation throws.
// uri: a uri which points at the script to be loaded
// cb:
// a callback function to process the result of evaluating the script
// as an expression, typically used by the resource bundle loader to
// load JSON-style resources
if(d._loadedUrls[uri]){
return true; // Boolean
}
d._inFlightCount++; // block addOnLoad calls that arrive while we're busy downloading
var contents = d._getText(uri, true);
if(contents){ // not 404, et al
d._loadedUrls[uri] = true;
d._loadedUrls.push(uri);
if(cb){
//conditional to support script-inject i18n bundle format
contents = /^define\(/.test(contents) ? contents : '('+contents+')';
}else{
//Only do the scoping if no callback. If a callback is specified,
//it is most likely the i18n bundle stuff.
contents = d._scopePrefix + contents + d._scopeSuffix;
}
if(!d.isIE){ contents += "\r\n//@ sourceURL=" + uri; } // debugging assist for Firebug
var value = d["eval"](contents);
if(cb){ cb(value); }
}
// Check to see if we need to call _callLoaded() due to an addOnLoad() that arrived while we were busy downloading
if(--d._inFlightCount == 0 && d._postLoad && d._loaders.length){
// We shouldn't be allowed to get here but Firefox allows an event
// (mouse, keybd, async xhrGet) to interrupt a synchronous xhrGet.
// If the current script block contains multiple require() statements, then after each
// require() returns, inFlightCount == 0, but we want to hold the _callLoaded() until
// all require()s are done since the out-of-sequence addOnLoad() presumably needs them all.
// setTimeout allows the next require() to start (if needed), and then we check this again.
setTimeout(function(){
// If inFlightCount > 0, then multiple require()s are running sequentially and
// the next require() started after setTimeout() was executed but before we got here.
if(d._inFlightCount == 0){
d._callLoaded();
}
}, 0);
}
return !!contents; // Boolean: contents? true : false
}
//>>excludeEnd("xdomainExclude");
// FIXME: probably need to add logging to this method
dojo._loadUriAndCheck = function(/*String*/uri, /*String*/moduleName, /*Function?*/cb){
// summary: calls loadUri then findModule and returns true if both succeed
var ok = false;
try{
ok = d._loadUri(uri, cb);
}catch(e){
console.error("failed loading " + uri + " with error: " + e);
}
return !!(ok && d._loadedModules[moduleName]); // Boolean
}
dojo.loaded = function(){
// summary:
// signal fired when initial environment and package loading is
// complete. You should use dojo.addOnLoad() instead of doing a
// direct dojo.connect() to this method in order to handle
// initialization tasks that require the environment to be
// initialized. In a browser host, declarative widgets will
// be constructed when this function finishes runing.
d._loadNotifying = true;
d._postLoad = true;
var mll = d._loaders;
//Clear listeners so new ones can be added
//For other xdomain package loads after the initial load.
d._loaders = [];
for(var x = 0; x < mll.length; x++){
mll[x]();
}
d._loadNotifying = false;
//Make sure nothing else got added to the onload queue
//after this first run. If something did, and we are not waiting for any
//more inflight resources, run again.
if(d._postLoad && d._inFlightCount == 0 && mll.length){
d._callLoaded();
}
}
dojo.unloaded = function(){
// summary:
// signal fired by impending environment destruction. You should use
// dojo.addOnUnload() instead of doing a direct dojo.connect() to this
// method to perform page/application cleanup methods. See
// dojo.addOnUnload for more info.
var mll = d._unloaders;
while(mll.length){
(mll.pop())();
}
}
d._onto = function(arr, obj, fn){
if(!fn){
arr.push(obj);
}else if(fn){
var func = (typeof fn == "string") ? obj[fn] : fn;
arr.push(function(){ func.call(obj); });
}
}
dojo.ready = dojo.addOnLoad = function(/*Object*/obj, /*String|Function?*/functionName){
// summary:
// Registers a function to be triggered after the DOM and dojo.require() calls
// have finished loading.
//
// description:
// Registers a function to be triggered after the DOM has finished
// loading and `dojo.require` modules have loaded. Widgets declared in markup
// have been instantiated if `djConfig.parseOnLoad` is true when this fires.
//
// Images and CSS files may or may not have finished downloading when
// the specified function is called. (Note that widgets' CSS and HTML
// code is guaranteed to be downloaded before said widgets are
// instantiated, though including css resouces BEFORE any script elements
// is highly recommended).
//
// example:
// Register an anonymous function to run when everything is ready
// | dojo.addOnLoad(function(){ doStuff(); });
//
// example:
// Register a function to run when everything is ready by pointer:
// | var init = function(){ doStuff(); }
// | dojo.addOnLoad(init);
//
// example:
// Register a function to run scoped to `object`, either by name or anonymously:
// | dojo.addOnLoad(object, "functionName");
// | dojo.addOnLoad(object, function(){ doStuff(); });
d._onto(d._loaders, obj, functionName);
//Added for xdomain loading. dojo.addOnLoad is used to
//indicate callbacks after doing some dojo.require() statements.
//In the xdomain case, if all the requires are loaded (after initial
//page load), then immediately call any listeners.
if(d._postLoad && d._inFlightCount == 0 && !d._loadNotifying){
d._callLoaded();
}
}
//Support calling dojo.addOnLoad via djConfig.addOnLoad. Support all the
//call permutations of dojo.addOnLoad. Mainly useful when dojo is added
//to the page after the page has loaded.
var dca = d.config.addOnLoad;
if(dca){
d.addOnLoad[(dca instanceof Array ? "apply" : "call")](d, dca);
}
dojo._modulesLoaded = function(){
if(d._postLoad){ return; }
if(d._inFlightCount > 0){
console.warn("files still in flight!");
return;
}
d._callLoaded();
}
dojo._callLoaded = function(){
// The "object" check is for IE, and the other opera check fixes an
// issue in Opera where it could not find the body element in some
// widget test cases. For 0.9, maybe route all browsers through the
// setTimeout (need protection still for non-browser environments
// though). This might also help the issue with FF 2.0 and freezing
// issues where we try to do sync xhr while background css images are
// being loaded (trac #2572)? Consider for 0.9.
if(typeof setTimeout == "object" || (d.config.useXDomain && d.isOpera)){
setTimeout(
d.isAIR ? function(){ d.loaded(); } : d._scopeName + ".loaded();",
0);
}else{
d.loaded();
}
}
dojo._getModuleSymbols = function(/*String*/modulename){
// summary:
// Converts a module name in dotted JS notation to an array
// representing the path in the source tree
var syms = modulename.split(".");
for(var i = syms.length; i>0; i--){
var parentModule = syms.slice(0, i).join(".");
if(i == 1 && !d._moduleHasPrefix(parentModule)){
// Support default module directory (sibling of dojo) for top-level modules
syms[0] = "../" + syms[0];
}else{
var parentModulePath = d._getModulePrefix(parentModule);
if(parentModulePath != parentModule){
syms.splice(0, i, parentModulePath);
break;
}
}
}
return syms; // Array
}
dojo._global_omit_module_check = false;
dojo.loadInit = function(/*Function*/init){
// summary:
// Executes a function that needs to be executed for the loader's dojo.requireIf
// resolutions to work. This is needed mostly for the xdomain loader case where
// a function needs to be executed to set up the possible values for a dojo.requireIf
// call.
// init:
// a function reference. Executed immediately.
// description: This function is mainly a marker for the xdomain loader to know parts of
// code that needs be executed outside the function wrappper that is placed around modules.
// The init function could be executed more than once, and it should make no assumptions
// on what is loaded, or what modules are available. Only the functionality in Dojo Base
// is allowed to be used. Avoid using this method. For a valid use case,
// see the source for dojox.gfx.
init();
}
dojo._loadModule = dojo.require = function(/*String*/moduleName, /*Boolean?*/omitModuleCheck){
// summary:
// loads a Javascript module from the appropriate URI
//
// moduleName: String
// module name to load, using periods for separators,
// e.g. "dojo.date.locale". Module paths are de-referenced by dojo's
// internal mapping of locations to names and are disambiguated by
// longest prefix. See `dojo.registerModulePath()` for details on
// registering new modules.
//
// omitModuleCheck: Boolean?
// if `true`, omitModuleCheck skips the step of ensuring that the
// loaded file actually defines the symbol it is referenced by.
// For example if it called as `dojo.require("a.b.c")` and the
// file located at `a/b/c.js` does not define an object `a.b.c`,
// and exception will be throws whereas no exception is raised
// when called as `dojo.require("a.b.c", true)`
//
// description:
// Modules are loaded via dojo.require by using one of two loaders: the normal loader
// and the xdomain loader. The xdomain loader is used when dojo was built with a
// custom build that specified loader=xdomain and the module lives on a modulePath
// that is a whole URL, with protocol and a domain. The versions of Dojo that are on
// the Google and AOL CDNs use the xdomain loader.
//
// If the module is loaded via the xdomain loader, it is an asynchronous load, since
// the module is added via a dynamically created script tag. This
// means that dojo.require() can return before the module has loaded. However, this
// should only happen in the case where you do dojo.require calls in the top-level
// HTML page, or if you purposely avoid the loader checking for dojo.require
// dependencies in your module by using a syntax like dojo["require"] to load the module.
//
// Sometimes it is useful to not have the loader detect the dojo.require calls in the
// module so that you can dynamically load the modules as a result of an action on the
// page, instead of right at module load time.
//
// Also, for script blocks in an HTML page, the loader does not pre-process them, so
// it does not know to download the modules before the dojo.require calls occur.
//
// So, in those two cases, when you want on-the-fly module loading or for script blocks
// in the HTML page, special care must be taken if the dojo.required code is loaded
// asynchronously. To make sure you can execute code that depends on the dojo.required
// modules, be sure to add the code that depends on the modules in a dojo.addOnLoad()
// callback. dojo.addOnLoad waits for all outstanding modules to finish loading before
// executing.
//
// This type of syntax works with both xdomain and normal loaders, so it is good
// practice to always use this idiom for on-the-fly code loading and in HTML script
// blocks. If at some point you change loaders and where the code is loaded from,
// it will all still work.
//
// More on how dojo.require
// `dojo.require("A.B")` first checks to see if symbol A.B is
// defined. If it is, it is simply returned (nothing to do).
//
// If it is not defined, it will look for `A/B.js` in the script root
// directory.
//
// `dojo.require` throws an exception if it cannot find a file
// to load, or if the symbol `A.B` is not defined after loading.
//
// It returns the object `A.B`, but note the caveats above about on-the-fly loading and
// HTML script blocks when the xdomain loader is loading a module.
//
// `dojo.require()` does nothing about importing symbols into
// the current namespace. It is presumed that the caller will
// take care of that.
//
// example:
// To use dojo.require in conjunction with dojo.ready:
//
// | dojo.require("foo");
// | dojo.require("bar");
// | dojo.addOnLoad(function(){
// | //you can now safely do something with foo and bar
// | });
//
// example:
// For example, to import all symbols into a local block, you might write:
//
// | with (dojo.require("A.B")) {
// | ...
// | }
//
// And to import just the leaf symbol to a local variable:
//
// | var B = dojo.require("A.B");
// | ...
//
// returns:
// the required namespace object
omitModuleCheck = d._global_omit_module_check || omitModuleCheck;
//Check if it is already loaded.
var module = d._loadedModules[moduleName];
if(module){
return module;
}
// convert periods to slashes
var relpath = d._getModuleSymbols(moduleName).join("/") + '.js';
var modArg = !omitModuleCheck ? moduleName : null;
var ok = d._loadPath(relpath, modArg);
if(!ok && !omitModuleCheck){
throw new Error("Could not load '" + moduleName + "'; last tried '" + relpath + "'");
}
// check that the symbol was defined
// Don't bother if we're doing xdomain (asynchronous) loading.
if(!omitModuleCheck && !d._isXDomain){
// pass in false so we can give better error
module = d._loadedModules[moduleName];
if(!module){
throw new Error("symbol '" + moduleName + "' is not defined after loading '" + relpath + "'");
}
}
return module;
}
dojo.provide = function(/*String*/ resourceName){
// summary:
// Register a resource with the package system. Works in conjunction with `dojo.require`
//
// description:
// Each javascript source file is called a resource. When a
// resource is loaded by the browser, `dojo.provide()` registers
// that it has been loaded.
//
// Each javascript source file must have at least one
// `dojo.provide()` call at the top of the file, corresponding to
// the file name. For example, `js/dojo/foo.js` must have
// `dojo.provide("dojo.foo");` before any calls to
// `dojo.require()` are made.
//
// For backwards compatibility reasons, in addition to registering
// the resource, `dojo.provide()` also ensures that the javascript
// object for the module exists. For example,
// `dojo.provide("dojox.data.FlickrStore")`, in addition to
// registering that `FlickrStore.js` is a resource for the
// `dojox.data` module, will ensure that the `dojox.data`
// javascript object exists, so that calls like
// `dojo.data.foo = function(){ ... }` don't fail.
//
// In the case of a build where multiple javascript source files
// are combined into one bigger file (similar to a .lib or .jar
// file), that file may contain multiple dojo.provide() calls, to
// note that it includes multiple resources.
//
// resourceName: String
// A dot-sperated string identifying a resource.
//
// example:
// Safely create a `my` object, and make dojo.require("my.CustomModule") work
// | dojo.provide("my.CustomModule");
//Make sure we have a string.
resourceName = resourceName + "";
return (d._loadedModules[resourceName] = d.getObject(resourceName, true)); // Object