18980 lines
628 KiB
JavaScript
18980 lines
628 KiB
JavaScript
|
/*
|
||
|
Copyright (c) 2004-2016, The JS Foundation All Rights Reserved.
|
||
|
Available via Academic Free License >= 2.1 OR the modified BSD license.
|
||
|
see: http://dojotoolkit.org/license for details
|
||
|
*/
|
||
|
|
||
|
/*
|
||
|
This is an optimized version of Dojo, built for deployment and not for
|
||
|
development. To get sources and documentation, please visit:
|
||
|
|
||
|
http://dojotoolkit.org
|
||
|
*/
|
||
|
|
||
|
(function(
|
||
|
userConfig,
|
||
|
defaultConfig
|
||
|
){
|
||
|
// summary:
|
||
|
// This is the "source loader" and is the entry point for Dojo during development. You may also load Dojo with
|
||
|
// any AMD-compliant loader via the package main module dojo/main.
|
||
|
// description:
|
||
|
// This is the "source loader" for Dojo. It provides an AMD-compliant loader that can be configured
|
||
|
// to operate in either synchronous or asynchronous modes. After the loader is defined, dojo is loaded
|
||
|
// IAW the package main module dojo/main. In the event you wish to use a foreign loader, you may load dojo as a package
|
||
|
// via the package main module dojo/main and this loader is not required; see dojo/package.json for details.
|
||
|
//
|
||
|
// In order to keep compatibility with the v1.x line, this loader includes additional machinery that enables
|
||
|
// the dojo.provide, dojo.require et al API. This machinery is loaded by default, but may be dynamically removed
|
||
|
// via the has.js API and statically removed via the build system.
|
||
|
//
|
||
|
// This loader includes sniffing machinery to determine the environment; the following environments are supported:
|
||
|
//
|
||
|
// - browser
|
||
|
// - node.js
|
||
|
// - rhino
|
||
|
//
|
||
|
// This is the so-called "source loader". As such, it includes many optional features that may be discarded by
|
||
|
// building a customized version with the build system.
|
||
|
|
||
|
// Design and Implementation Notes
|
||
|
//
|
||
|
// This is a dojo-specific adaption of bdLoad, donated to the dojo foundation by Altoviso LLC.
|
||
|
//
|
||
|
// This function defines an AMD-compliant (http://wiki.commonjs.org/wiki/Modules/AsynchronousDefinition)
|
||
|
// loader that can be configured to operate in either synchronous or asynchronous modes.
|
||
|
//
|
||
|
// Since this machinery implements a loader, it does not have the luxury of using a load system and/or
|
||
|
// leveraging a utility library. This results in an unpleasantly long file; here is a road map of the contents:
|
||
|
//
|
||
|
// 1. Small library for use implementing the loader.
|
||
|
// 2. Define the has.js API; this is used throughout the loader to bracket features.
|
||
|
// 3. Define the node.js and rhino sniffs and sniff.
|
||
|
// 4. Define the loader's data.
|
||
|
// 5. Define the configuration machinery.
|
||
|
// 6. Define the script element sniffing machinery and sniff for configuration data.
|
||
|
// 7. Configure the loader IAW the provided user, default, and sniffing data.
|
||
|
// 8. Define the global require function.
|
||
|
// 9. Define the module resolution machinery.
|
||
|
// 10. Define the module and plugin module definition machinery
|
||
|
// 11. Define the script injection machinery.
|
||
|
// 12. Define the window load detection.
|
||
|
// 13. Define the logging API.
|
||
|
// 14. Define the tracing API.
|
||
|
// 16. Define the AMD define function.
|
||
|
// 17. Define the dojo v1.x provide/require machinery--so called "legacy" modes.
|
||
|
// 18. Publish global variables.
|
||
|
//
|
||
|
// Language and Acronyms and Idioms
|
||
|
//
|
||
|
// moduleId: a CJS module identifier, (used for public APIs)
|
||
|
// mid: moduleId (used internally)
|
||
|
// packageId: a package identifier (used for public APIs)
|
||
|
// pid: packageId (used internally); the implied system or default package has pid===""
|
||
|
// pack: package is used internally to reference a package object (since javascript has reserved words including "package")
|
||
|
// prid: plugin resource identifier
|
||
|
// The integer constant 1 is used in place of true and 0 in place of false.
|
||
|
//
|
||
|
// The "foreign-loader" has condition is defined if another loader is being used (e.g. webpack) and this code is only
|
||
|
// needed for resolving module identifiers based on the config. In this case, only the functions require.toUrl and
|
||
|
// require.toAbsMid are supported. The require and define functions are not supported.
|
||
|
|
||
|
// define global
|
||
|
var globalObject = (function(){
|
||
|
if (typeof global !== 'undefined' && typeof global !== 'function') {
|
||
|
// global spec defines a reference to the global object called 'global'
|
||
|
// https://github.com/tc39/proposal-global
|
||
|
// `global` is also defined in NodeJS
|
||
|
return global;
|
||
|
}
|
||
|
else if (typeof window !== 'undefined') {
|
||
|
// window is defined in browsers
|
||
|
return window;
|
||
|
}
|
||
|
else if (typeof self !== 'undefined') {
|
||
|
// self is defined in WebWorkers
|
||
|
return self;
|
||
|
}
|
||
|
return this;
|
||
|
})();
|
||
|
|
||
|
// define a minimal library to help build the loader
|
||
|
var noop = function(){
|
||
|
},
|
||
|
|
||
|
isEmpty = function(it){
|
||
|
for(var p in it){
|
||
|
return 0;
|
||
|
}
|
||
|
return 1;
|
||
|
},
|
||
|
|
||
|
toString = {}.toString,
|
||
|
|
||
|
isFunction = function(it){
|
||
|
return toString.call(it) == "[object Function]";
|
||
|
},
|
||
|
|
||
|
isString = function(it){
|
||
|
return toString.call(it) == "[object String]";
|
||
|
},
|
||
|
|
||
|
isArray = function(it){
|
||
|
return toString.call(it) == "[object Array]";
|
||
|
},
|
||
|
|
||
|
forEach = function(vector, callback){
|
||
|
if(vector){
|
||
|
for(var i = 0; i < vector.length;){
|
||
|
callback(vector[i++]);
|
||
|
}
|
||
|
}
|
||
|
},
|
||
|
|
||
|
mix = function(dest, src){
|
||
|
for(var p in src){
|
||
|
dest[p] = src[p];
|
||
|
}
|
||
|
return dest;
|
||
|
},
|
||
|
|
||
|
makeError = function(error, info){
|
||
|
return mix(new Error(error), {src:"dojoLoader", info:info});
|
||
|
},
|
||
|
|
||
|
uidSeed = 1,
|
||
|
|
||
|
uid = function(){
|
||
|
// Returns a unique identifier (within the lifetime of the document) of the form /_d+/.
|
||
|
return "_" + uidSeed++;
|
||
|
},
|
||
|
|
||
|
// FIXME: how to doc window.require() api
|
||
|
|
||
|
// this will be the global require function; define it immediately so we can start hanging things off of it
|
||
|
req = function(
|
||
|
config, //(object, optional) hash of configuration properties
|
||
|
dependencies, //(array of commonjs.moduleId, optional) list of modules to be loaded before applying callback
|
||
|
callback //(function, optional) lambda expression to apply to module values implied by dependencies
|
||
|
){
|
||
|
return contextRequire(config, dependencies, callback, 0, req);
|
||
|
},
|
||
|
|
||
|
// the loader uses the has.js API to control feature inclusion/exclusion; define then use throughout
|
||
|
global = globalObject,
|
||
|
|
||
|
doc = global.document,
|
||
|
|
||
|
element = doc && doc.createElement("DiV"),
|
||
|
|
||
|
has = req.has = function(name){
|
||
|
return isFunction(hasCache[name]) ? (hasCache[name] = hasCache[name](global, doc, element)) : hasCache[name];
|
||
|
},
|
||
|
|
||
|
hasCache = has.cache = defaultConfig.hasCache;
|
||
|
|
||
|
if (isFunction(userConfig)) {
|
||
|
userConfig = userConfig(globalObject);
|
||
|
}
|
||
|
|
||
|
has.add = function(name, test, now, force){
|
||
|
(hasCache[name]===undefined || force) && (hasCache[name] = test);
|
||
|
return now && has(name);
|
||
|
};
|
||
|
|
||
|
0 && has.add("host-node", userConfig.has && "host-node" in userConfig.has ?
|
||
|
userConfig.has["host-node"] :
|
||
|
(typeof process == "object" && process.versions && process.versions.node && process.versions.v8));
|
||
|
if( 0 ){
|
||
|
// fixup the default config for node.js environment
|
||
|
require("./_base/configNode.js").config(defaultConfig);
|
||
|
// remember node's require (with respect to baseUrl==dojo's root)
|
||
|
defaultConfig.loaderPatch.nodeRequire = require;
|
||
|
}
|
||
|
|
||
|
0 && has.add("host-rhino", userConfig.has && "host-rhino" in userConfig.has ?
|
||
|
userConfig.has["host-rhino"] :
|
||
|
(typeof load == "function" && (typeof Packages == "function" || typeof Packages == "object")));
|
||
|
if( 0 ){
|
||
|
// owing to rhino's lame feature that hides the source of the script, give the user a way to specify the baseUrl...
|
||
|
for(var baseUrl = userConfig.baseUrl || ".", arg, rhinoArgs = this.arguments, i = 0; i < rhinoArgs.length;){
|
||
|
arg = (rhinoArgs[i++] + "").split("=");
|
||
|
if(arg[0] == "baseUrl"){
|
||
|
baseUrl = arg[1];
|
||
|
break;
|
||
|
}
|
||
|
}
|
||
|
load(baseUrl + "/_base/configRhino.js");
|
||
|
rhinoDojoConfig(defaultConfig, baseUrl, rhinoArgs);
|
||
|
}
|
||
|
|
||
|
has.add("host-webworker", ((typeof WorkerGlobalScope !== 'undefined') && (self instanceof WorkerGlobalScope)));
|
||
|
if(has("host-webworker")){
|
||
|
mix(defaultConfig.hasCache, {
|
||
|
"host-browser": 0,
|
||
|
"dom": 0,
|
||
|
"dojo-dom-ready-api": 0,
|
||
|
"dojo-sniff": 0,
|
||
|
"dojo-inject-api": 1,
|
||
|
"host-webworker": 1,
|
||
|
"dojo-guarantee-console": 0 // console is immutable in FF30+, see https://bugs.dojotoolkit.org/ticket/18100
|
||
|
});
|
||
|
|
||
|
defaultConfig.loaderPatch = {
|
||
|
injectUrl: function(url, callback){
|
||
|
// TODO:
|
||
|
// This is not async, nor can it be in Webworkers. It could be made better by passing
|
||
|
// the entire require array into importScripts at. This way the scripts are loaded in
|
||
|
// async mode; even if the callbacks are ran in sync. It is not a major issue as webworkers
|
||
|
// tend to be long running where initial startup is not a major factor.
|
||
|
|
||
|
try{
|
||
|
importScripts(url);
|
||
|
callback();
|
||
|
}catch(e){
|
||
|
console.info("failed to load resource (" + url + ")");
|
||
|
console.error(e);
|
||
|
}
|
||
|
}
|
||
|
};
|
||
|
}
|
||
|
|
||
|
// userConfig has tests override defaultConfig has tests; do this after the environment detection because
|
||
|
// the environment detection usually sets some has feature values in the hasCache.
|
||
|
for(var p in userConfig.has){
|
||
|
has.add(p, userConfig.has[p], 0, 1);
|
||
|
}
|
||
|
|
||
|
//
|
||
|
// define the loader data
|
||
|
//
|
||
|
|
||
|
// the loader will use these like symbols if the loader has the traceApi; otherwise
|
||
|
// define magic numbers so that modules can be provided as part of defaultConfig
|
||
|
var requested = 1,
|
||
|
arrived = 2,
|
||
|
nonmodule = 3,
|
||
|
executing = 4,
|
||
|
executed = 5;
|
||
|
|
||
|
if( 0 ){
|
||
|
// these make debugging nice; but using strings for symbols is a gross rookie error; don't do it for production code
|
||
|
requested = "requested";
|
||
|
arrived = "arrived";
|
||
|
nonmodule = "not-a-module";
|
||
|
executing = "executing";
|
||
|
executed = "executed";
|
||
|
}
|
||
|
|
||
|
var legacyMode = 0,
|
||
|
sync = "sync",
|
||
|
xd = "xd",
|
||
|
syncExecStack = [],
|
||
|
dojoRequirePlugin = 0,
|
||
|
checkDojoRequirePlugin = noop,
|
||
|
transformToAmd = noop,
|
||
|
getXhr;
|
||
|
if( 1 ){
|
||
|
req.isXdUrl = noop;
|
||
|
|
||
|
req.initSyncLoader = function(dojoRequirePlugin_, checkDojoRequirePlugin_, transformToAmd_){
|
||
|
// the first dojo/_base/loader loaded gets to define these variables; they are designed to work
|
||
|
// in the presence of zero to many mapped dojo/_base/loaders
|
||
|
if(!dojoRequirePlugin){
|
||
|
dojoRequirePlugin = dojoRequirePlugin_;
|
||
|
checkDojoRequirePlugin = checkDojoRequirePlugin_;
|
||
|
transformToAmd = transformToAmd_;
|
||
|
}
|
||
|
|
||
|
return {
|
||
|
sync:sync,
|
||
|
requested:requested,
|
||
|
arrived:arrived,
|
||
|
nonmodule:nonmodule,
|
||
|
executing:executing,
|
||
|
executed:executed,
|
||
|
syncExecStack:syncExecStack,
|
||
|
modules:modules,
|
||
|
execQ:execQ,
|
||
|
getModule:getModule,
|
||
|
injectModule:injectModule,
|
||
|
setArrived:setArrived,
|
||
|
signal:signal,
|
||
|
finishExec:finishExec,
|
||
|
execModule:execModule,
|
||
|
dojoRequirePlugin:dojoRequirePlugin,
|
||
|
getLegacyMode:function(){return legacyMode;},
|
||
|
guardCheckComplete:guardCheckComplete
|
||
|
};
|
||
|
};
|
||
|
|
||
|
if( 1 || has("host-webworker")){
|
||
|
// in legacy sync mode, the loader needs a minimal XHR library
|
||
|
|
||
|
var locationProtocol = location.protocol,
|
||
|
locationHost = location.host;
|
||
|
req.isXdUrl = function(url){
|
||
|
if(/^\./.test(url)){
|
||
|
// begins with a dot is always relative to page URL; therefore not xdomain
|
||
|
return false;
|
||
|
}
|
||
|
if(/^\/\//.test(url)){
|
||
|
// for v1.6- backcompat, url starting with // indicates xdomain
|
||
|
return true;
|
||
|
}
|
||
|
// get protocol and host
|
||
|
// \/+ takes care of the typical file protocol that looks like file:///drive/path/to/file
|
||
|
// locationHost is falsy if file protocol => if locationProtocol matches and is "file:", || will return false
|
||
|
var match = url.match(/^([^\/\:]+\:)\/+([^\/]+)/);
|
||
|
return match && (match[1] != locationProtocol || (locationHost && match[2] != locationHost));
|
||
|
};
|
||
|
|
||
|
|
||
|
// note: to get the file:// protocol to work in FF, you must set security.fileuri.strict_origin_policy to false in about:config
|
||
|
1 || has.add("dojo-xhr-factory", 1);
|
||
|
has.add("dojo-force-activex-xhr", 1 && !doc.addEventListener && window.location.protocol == "file:");
|
||
|
has.add("native-xhr", typeof XMLHttpRequest != "undefined");
|
||
|
if(has("native-xhr") && !has("dojo-force-activex-xhr")){
|
||
|
getXhr = function(){
|
||
|
return new XMLHttpRequest();
|
||
|
};
|
||
|
}else{
|
||
|
// if in the browser an old IE; find an xhr
|
||
|
for(var XMLHTTP_PROGIDS = ['Msxml2.XMLHTTP', 'Microsoft.XMLHTTP', 'Msxml2.XMLHTTP.4.0'], progid, i = 0; i < 3;){
|
||
|
try{
|
||
|
progid = XMLHTTP_PROGIDS[i++];
|
||
|
if(new ActiveXObject(progid)){
|
||
|
// this progid works; therefore, use it from now on
|
||
|
break;
|
||
|
}
|
||
|
}catch(e){
|
||
|
// squelch; we're just trying to find a good ActiveX progid
|
||
|
// if they all fail, then progid ends up as the last attempt and that will signal the error
|
||
|
// the first time the client actually tries to exec an xhr
|
||
|
}
|
||
|
}
|
||
|
getXhr = function(){
|
||
|
return new ActiveXObject(progid);
|
||
|
};
|
||
|
}
|
||
|
req.getXhr = getXhr;
|
||
|
|
||
|
has.add("dojo-gettext-api", 1);
|
||
|
req.getText = function(url, async, onLoad){
|
||
|
var xhr = getXhr();
|
||
|
xhr.open('GET', fixupUrl(url), false);
|
||
|
xhr.send(null);
|
||
|
if(xhr.status == 200 || (!location.host && !xhr.status)){
|
||
|
if(onLoad){
|
||
|
onLoad(xhr.responseText, async);
|
||
|
}
|
||
|
}else{
|
||
|
throw makeError("xhrFailed", xhr.status);
|
||
|
}
|
||
|
return xhr.responseText;
|
||
|
};
|
||
|
}
|
||
|
}else{
|
||
|
req.async = 1;
|
||
|
}
|
||
|
|
||
|
//
|
||
|
// loader eval
|
||
|
//
|
||
|
var eval_ = has("csp-restrictions") ?
|
||
|
// noop eval if there are csp restrictions
|
||
|
function(){} :
|
||
|
// use the function constructor so our eval is scoped close to (but not in) in the global space with minimal pollution
|
||
|
new Function('return eval(arguments[0]);');
|
||
|
|
||
|
req.eval =
|
||
|
function(text, hint){
|
||
|
return eval_(text + "\r\n//# sourceURL=" + hint);
|
||
|
};
|
||
|
|
||
|
//
|
||
|
// loader micro events API
|
||
|
//
|
||
|
var listenerQueues = {},
|
||
|
error = "error",
|
||
|
signal = req.signal = function(type, args){
|
||
|
var queue = listenerQueues[type];
|
||
|
// notice we run a copy of the queue; this allows listeners to add/remove
|
||
|
// other listeners without affecting this particular signal
|
||
|
forEach(queue && queue.slice(0), function(listener){
|
||
|
listener.apply(null, isArray(args) ? args : [args]);
|
||
|
});
|
||
|
},
|
||
|
on = req.on = function(type, listener){
|
||
|
// notice a queue is not created until a client actually connects
|
||
|
var queue = listenerQueues[type] || (listenerQueues[type] = []);
|
||
|
queue.push(listener);
|
||
|
return {
|
||
|
remove:function(){
|
||
|
for(var i = 0; i<queue.length; i++){
|
||
|
if(queue[i]===listener){
|
||
|
queue.splice(i, 1);
|
||
|
return;
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
};
|
||
|
};
|
||
|
|
||
|
// configuration machinery; with an optimized/built defaultConfig, all configuration machinery can be discarded
|
||
|
// lexical variables hold key loader data structures to help with minification; these may be completely,
|
||
|
// one-time initialized by defaultConfig for optimized/built versions
|
||
|
var
|
||
|
aliases
|
||
|
// a vector of pairs of [regexs or string, replacement] => (alias, actual)
|
||
|
= [],
|
||
|
|
||
|
paths
|
||
|
// CommonJS paths
|
||
|
= {},
|
||
|
|
||
|
pathsMapProg
|
||
|
// list of (from-path, to-path, regex, length) derived from paths;
|
||
|
// a "program" to apply paths; see computeMapProg
|
||
|
= [],
|
||
|
|
||
|
packs
|
||
|
// a map from packageId to package configuration object; see fixupPackageInfo
|
||
|
= {},
|
||
|
|
||
|
map = req.map
|
||
|
// AMD map config variable; dojo/_base/kernel needs req.map to figure out the scope map
|
||
|
= {},
|
||
|
|
||
|
mapProgs
|
||
|
// vector of quads as described by computeMapProg; map-key is AMD map key, map-value is AMD map value
|
||
|
= [],
|
||
|
|
||
|
modules
|
||
|
// A hash:(mid) --> (module-object) the module namespace
|
||
|
//
|
||
|
// pid: the package identifier to which the module belongs (e.g., "dojo"); "" indicates the system or default package
|
||
|
// mid: the fully-resolved (i.e., mappings have been applied) module identifier without the package identifier (e.g., "dojo/io/script")
|
||
|
// url: the URL from which the module was retrieved
|
||
|
// pack: the package object of the package to which the module belongs
|
||
|
// executed: 0 => not executed; executing => in the process of traversing deps and running factory; executed => factory has been executed
|
||
|
// deps: the dependency vector for this module (vector of modules objects)
|
||
|
// def: the factory for this module
|
||
|
// result: the result of the running the factory for this module
|
||
|
// injected: (0 | requested | arrived) the status of the module; nonmodule means the resource did not call define
|
||
|
// load: plugin load function; applicable only for plugins
|
||
|
//
|
||
|
// Modules go through several phases in creation:
|
||
|
//
|
||
|
// 1. Requested: some other module's definition or a require application contained the requested module in
|
||
|
// its dependency vector or executing code explicitly demands a module via req.require.
|
||
|
//
|
||
|
// 2. Injected: a script element has been appended to the insert-point element demanding the resource implied by the URL
|
||
|
//
|
||
|
// 3. Loaded: the resource injected in [2] has been evaluated.
|
||
|
//
|
||
|
// 4. Defined: the resource contained a define statement that advised the loader about the module. Notice that some
|
||
|
// resources may just contain a bundle of code and never formally define a module via define
|
||
|
//
|
||
|
// 5. Evaluated: the module was defined via define and the loader has evaluated the factory and computed a result.
|
||
|
= {},
|
||
|
|
||
|
cacheBust
|
||
|
// query string to append to module URLs to bust browser cache
|
||
|
= "",
|
||
|
|
||
|
cache
|
||
|
// hash:(mid | url)-->(function | string)
|
||
|
//
|
||
|
// A cache of resources. The resources arrive via a config.cache object, which is a hash from either mid --> function or
|
||
|
// url --> string. The url key is distinguished from the mid key by always containing the prefix "url:". url keys as provided
|
||
|
// by config.cache always have a string value that represents the contents of the resource at the given url. mid keys as provided
|
||
|
// by configl.cache always have a function value that causes the same code to execute as if the module was script injected.
|
||
|
//
|
||
|
// Both kinds of key-value pairs are entered into cache via the function consumePendingCache, which may relocate keys as given
|
||
|
// by any mappings *iff* the config.cache was received as part of a module resource request.
|
||
|
//
|
||
|
// Further, for mid keys, the implied url is computed and the value is entered into that key as well. This allows mapped modules
|
||
|
// to retrieve cached items that may have arrived consequent to another namespace.
|
||
|
//
|
||
|
= {},
|
||
|
|
||
|
urlKeyPrefix
|
||
|
// the prefix to prepend to a URL key in the cache.
|
||
|
= "url:",
|
||
|
|
||
|
pendingCacheInsert
|
||
|
// hash:(mid)-->(function)
|
||
|
//
|
||
|
// Gives a set of cache modules pending entry into cache. When cached modules are published to the loader, they are
|
||
|
// entered into pendingCacheInsert; modules are then pressed into cache upon (1) AMD define or (2) upon receiving another
|
||
|
// independent set of cached modules. (1) is the usual case, and this case allows normalizing mids given in the pending
|
||
|
// cache for the local configuration, possibly relocating modules.
|
||
|
= {},
|
||
|
|
||
|
dojoSniffConfig
|
||
|
// map of configuration variables
|
||
|
// give the data-dojo-config as sniffed from the document (if any)
|
||
|
= {},
|
||
|
|
||
|
insertPointSibling
|
||
|
// the nodes used to locate where scripts are injected into the document
|
||
|
= 0;
|
||
|
|
||
|
if( 1 ){
|
||
|
if (!has("foreign-loader")) {
|
||
|
var consumePendingCacheInsert = function(referenceModule, clear){
|
||
|
clear = clear !== false;
|
||
|
var p, item, match, now, m;
|
||
|
for(p in pendingCacheInsert){
|
||
|
item = pendingCacheInsert[p];
|
||
|
match = p.match(/^url\:(.+)/);
|
||
|
if(match){
|
||
|
cache[urlKeyPrefix + toUrl(match[1], referenceModule)] = item;
|
||
|
}else if(p=="*now"){
|
||
|
now = item;
|
||
|
}else if(p!="*noref"){
|
||
|
m = getModuleInfo(p, referenceModule, true);
|
||
|
cache[m.mid] = cache[urlKeyPrefix + m.url] = item;
|
||
|
}
|
||
|
}
|
||
|
if(now){
|
||
|
now(createRequire(referenceModule));
|
||
|
}
|
||
|
if(clear){
|
||
|
pendingCacheInsert = {};
|
||
|
}
|
||
|
};
|
||
|
}
|
||
|
var escapeString = function(s){
|
||
|
return s.replace(/([\.$?*|{}\(\)\[\]\\\/\+^])/g, function(c){ return "\\" + c; });
|
||
|
},
|
||
|
|
||
|
computeMapProg = function(map, dest){
|
||
|
// This routine takes a map as represented by a JavaScript object and initializes dest, a vector of
|
||
|
// quads of (map-key, map-value, refex-for-map-key, length-of-map-key), sorted decreasing by length-
|
||
|
// of-map-key. The regex looks for the map-key followed by either "/" or end-of-string at the beginning
|
||
|
// of a the search source. Notice the map-value is irrelevant to the algorithm
|
||
|
dest.splice(0, dest.length);
|
||
|
for(var p in map){
|
||
|
dest.push([
|
||
|
p,
|
||
|
map[p],
|
||
|
new RegExp("^" + escapeString(p) + "(\/|$)"),
|
||
|
p.length]);
|
||
|
}
|
||
|
dest.sort(function(lhs, rhs){ return rhs[3] - lhs[3]; });
|
||
|
return dest;
|
||
|
},
|
||
|
|
||
|
computeAliases = function(config, dest){
|
||
|
forEach(config, function(pair){
|
||
|
// take a fixed-up copy...
|
||
|
dest.push([isString(pair[0]) ? new RegExp("^" + escapeString(pair[0]) + "$") : pair[0], pair[1]]);
|
||
|
});
|
||
|
},
|
||
|
|
||
|
|
||
|
fixupPackageInfo = function(packageInfo){
|
||
|
// calculate the precise (name, location, main, mappings) for a package
|
||
|
var name = packageInfo.name;
|
||
|
if(!name){
|
||
|
// packageInfo must be a string that gives the name
|
||
|
name = packageInfo;
|
||
|
packageInfo = {name:name};
|
||
|
}
|
||
|
packageInfo = mix({main:"main"}, packageInfo);
|
||
|
packageInfo.location = packageInfo.location ? packageInfo.location : name;
|
||
|
|
||
|
// packageMap is deprecated in favor of AMD map
|
||
|
if(packageInfo.packageMap){
|
||
|
map[name] = packageInfo.packageMap;
|
||
|
}
|
||
|
|
||
|
if(!packageInfo.main.indexOf("./")){
|
||
|
packageInfo.main = packageInfo.main.substring(2);
|
||
|
}
|
||
|
|
||
|
// now that we've got a fully-resolved package object, push it into the configuration
|
||
|
packs[name] = packageInfo;
|
||
|
},
|
||
|
|
||
|
delayedModuleConfig
|
||
|
// module config cannot be consumed until the loader is completely initialized; therefore, all
|
||
|
// module config detected during booting is memorized and applied at the end of loader initialization
|
||
|
// TODO: this is a bit of a kludge; all config should be moved to end of loader initialization, but
|
||
|
// we'll delay this chore and do it with a final loader 1.x cleanup after the 2.x loader prototyping is complete
|
||
|
= [],
|
||
|
|
||
|
|
||
|
config = function(config, booting, referenceModule){
|
||
|
for(var p in config){
|
||
|
if(p=="waitSeconds"){
|
||
|
req.waitms = (config[p] || 0) * 1000;
|
||
|
}
|
||
|
if(p=="cacheBust"){
|
||
|
cacheBust = config[p] ? (isString(config[p]) ? config[p] : (new Date()).getTime() + "") : "";
|
||
|
}
|
||
|
if(p=="baseUrl" || p=="combo"){
|
||
|
req[p] = config[p];
|
||
|
}
|
||
|
if( 1 && p=="async"){
|
||
|
// falsy or "sync" => legacy sync loader
|
||
|
// "xd" => sync but loading xdomain tree and therefore loading asynchronously (not configurable, set automatically by the loader)
|
||
|
// "legacyAsync" => permanently in "xd" by choice
|
||
|
// "debugAtAllCosts" => trying to load everything via script injection (not implemented)
|
||
|
// otherwise, must be truthy => AMD
|
||
|
// legacyMode: sync | legacyAsync | xd | false
|
||
|
var mode = config[p];
|
||
|
req.legacyMode = legacyMode = (isString(mode) && /sync|legacyAsync/.test(mode) ? mode : (!mode ? sync : false));
|
||
|
req.async = !legacyMode;
|
||
|
}
|
||
|
if(config[p]!==hasCache){
|
||
|
// accumulate raw config info for client apps which can use this to pass their own config
|
||
|
req.rawConfig[p] = config[p];
|
||
|
p!="has" && has.add("config-"+p, config[p], 0, booting);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
// make sure baseUrl exists
|
||
|
if(!req.baseUrl){
|
||
|
req.baseUrl = "./";
|
||
|
}
|
||
|
// make sure baseUrl ends with a slash
|
||
|
if(!/\/$/.test(req.baseUrl)){
|
||
|
req.baseUrl += "/";
|
||
|
}
|
||
|
|
||
|
// now do the special work for has, packages, packagePaths, paths, aliases, and cache
|
||
|
|
||
|
for(p in config.has){
|
||
|
has.add(p, config.has[p], 0, booting);
|
||
|
}
|
||
|
|
||
|
// for each package found in any packages config item, augment the packs map owned by the loader
|
||
|
forEach(config.packages, fixupPackageInfo);
|
||
|
|
||
|
// for each packagePath found in any packagePaths config item, augment the packageConfig
|
||
|
// packagePaths is deprecated; remove in 2.0
|
||
|
for(var baseUrl in config.packagePaths){
|
||
|
forEach(config.packagePaths[baseUrl], function(packageInfo){
|
||
|
var location = baseUrl + "/" + packageInfo;
|
||
|
if(isString(packageInfo)){
|
||
|
packageInfo = {name:packageInfo};
|
||
|
}
|
||
|
packageInfo.location = location;
|
||
|
fixupPackageInfo(packageInfo);
|
||
|
});
|
||
|
}
|
||
|
|
||
|
// notice that computeMapProg treats the dest as a reference; therefore, if/when that variable
|
||
|
// is published (see dojo-publish-privates), the published variable will always hold a valid value.
|
||
|
|
||
|
// this must come after all package processing since package processing may mutate map
|
||
|
computeMapProg(mix(map, config.map), mapProgs);
|
||
|
forEach(mapProgs, function(item){
|
||
|
item[1] = computeMapProg(item[1], []);
|
||
|
if(item[0]=="*"){
|
||
|
mapProgs.star = item;
|
||
|
}
|
||
|
});
|
||
|
|
||
|
// push in any paths and recompute the internal pathmap
|
||
|
computeMapProg(mix(paths, config.paths), pathsMapProg);
|
||
|
|
||
|
// aliases
|
||
|
computeAliases(config.aliases, aliases);
|
||
|
|
||
|
if (!has("foreign-loader")) {
|
||
|
if(booting){
|
||
|
delayedModuleConfig.push({config:config.config});
|
||
|
}else{
|
||
|
for(p in config.config){
|
||
|
var module = getModule(p, referenceModule);
|
||
|
module.config = mix(module.config || {}, config.config[p]);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
// push in any new cache values
|
||
|
if(config.cache){
|
||
|
consumePendingCacheInsert();
|
||
|
pendingCacheInsert = config.cache;
|
||
|
//inject now all depencies so cache is available for mapped module
|
||
|
consumePendingCacheInsert(0, !!config.cache["*noref"]);
|
||
|
}
|
||
|
}
|
||
|
signal("config", [config, req.rawConfig]);
|
||
|
};
|
||
|
|
||
|
//
|
||
|
// execute the various sniffs; userConfig can override and value
|
||
|
//
|
||
|
|
||
|
if(has("dojo-cdn") || 1 ){
|
||
|
// the sniff regex looks for a src attribute ending in dojo.js, optionally preceded with a path.
|
||
|
// match[3] returns the path to dojo.js (if any) without the trailing slash. This is used for the
|
||
|
// dojo location on CDN deployments and baseUrl when either/both of these are not provided
|
||
|
// explicitly in the config data; this is the 1.6- behavior.
|
||
|
|
||
|
var scripts = doc.getElementsByTagName("script"),
|
||
|
i = 0,
|
||
|
script, dojoDir, src, match;
|
||
|
while(i < scripts.length){
|
||
|
script = scripts[i++];
|
||
|
if((src = script.getAttribute("src")) && (match = src.match(/(((.*)\/)|^)dojo\.js(\W|$)/i))){
|
||
|
// sniff dojoDir and baseUrl
|
||
|
dojoDir = match[3] || "";
|
||
|
defaultConfig.baseUrl = defaultConfig.baseUrl || dojoDir;
|
||
|
|
||
|
// remember an insertPointSibling
|
||
|
insertPointSibling = script;
|
||
|
}
|
||
|
|
||
|
// sniff configuration on attribute in script element
|
||
|
if((src = (script.getAttribute("data-dojo-config") || script.getAttribute("djConfig")))){
|
||
|
dojoSniffConfig = req.eval("({ " + src + " })", "data-dojo-config");
|
||
|
|
||
|
// remember an insertPointSibling
|
||
|
insertPointSibling = script;
|
||
|
}
|
||
|
|
||
|
// sniff requirejs attribute
|
||
|
if( 0 ){
|
||
|
if((src = script.getAttribute("data-main"))){
|
||
|
dojoSniffConfig.deps = dojoSniffConfig.deps || [src];
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
|
||
|
if( 0 ){
|
||
|
// pass down doh.testConfig from parent as if it were a data-dojo-config
|
||
|
try{
|
||
|
if(window.parent != window && window.parent.require){
|
||
|
var doh = window.parent.require("doh");
|
||
|
doh && mix(dojoSniffConfig, doh.testConfig);
|
||
|
}
|
||
|
}catch(e){}
|
||
|
}
|
||
|
|
||
|
// configure the loader; let the user override defaults
|
||
|
req.rawConfig = {};
|
||
|
config(defaultConfig, 1);
|
||
|
|
||
|
// do this before setting userConfig/sniffConfig to allow userConfig/sniff overrides
|
||
|
if(has("dojo-cdn")){
|
||
|
packs.dojo.location = dojoDir;
|
||
|
if(dojoDir){
|
||
|
dojoDir += "/";
|
||
|
}
|
||
|
packs.dijit.location = dojoDir + "../dijit/";
|
||
|
packs.dojox.location = dojoDir + "../dojox/";
|
||
|
}
|
||
|
|
||
|
config(userConfig, 1);
|
||
|
config(dojoSniffConfig, 1);
|
||
|
|
||
|
}else{
|
||
|
// no config API, assume defaultConfig has everything the loader needs...for the entire lifetime of the application
|
||
|
paths = defaultConfig.paths;
|
||
|
pathsMapProg = defaultConfig.pathsMapProg;
|
||
|
packs = defaultConfig.packs;
|
||
|
aliases = defaultConfig.aliases;
|
||
|
mapProgs = defaultConfig.mapProgs;
|
||
|
modules = defaultConfig.modules;
|
||
|
cache = defaultConfig.cache;
|
||
|
cacheBust = defaultConfig.cacheBust;
|
||
|
|
||
|
// remember the default config for other processes (e.g., dojo/config)
|
||
|
req.rawConfig = defaultConfig;
|
||
|
}
|
||
|
|
||
|
|
||
|
if (!has("foreign-loader")) {
|
||
|
if( 0 ){
|
||
|
req.combo = req.combo || {add:noop};
|
||
|
var comboPending = 0,
|
||
|
combosPending = [],
|
||
|
comboPendingTimer = null;
|
||
|
}
|
||
|
|
||
|
|
||
|
// build the loader machinery iaw configuration, including has feature tests
|
||
|
var injectDependencies = function(module){
|
||
|
// checkComplete!=0 holds the idle signal; we're not idle if we're injecting dependencies
|
||
|
guardCheckComplete(function(){
|
||
|
forEach(module.deps, injectModule);
|
||
|
if( 0 && comboPending && !comboPendingTimer){
|
||
|
comboPendingTimer = setTimeout(function() {
|
||
|
comboPending = 0;
|
||
|
comboPendingTimer = null;
|
||
|
req.combo.done(function(mids, url) {
|
||
|
var onLoadCallback= function(){
|
||
|
// defQ is a vector of module definitions 1-to-1, onto mids
|
||
|
runDefQ(0, mids);
|
||
|
checkComplete();
|
||
|
};
|
||
|
combosPending.push(mids);
|
||
|
injectingModule = mids;
|
||
|
req.injectUrl(url, onLoadCallback, mids);
|
||
|
injectingModule = 0;
|
||
|
}, req);
|
||
|
}, 0);
|
||
|
}
|
||
|
});
|
||
|
},
|
||
|
|
||
|
contextRequire = function(a1, a2, a3, referenceModule, contextRequire){
|
||
|
var module, syntheticMid;
|
||
|
if(isString(a1)){
|
||
|
// signature is (moduleId)
|
||
|
module = getModule(a1, referenceModule, true);
|
||
|
if(module && module.executed){
|
||
|
return module.result;
|
||
|
}
|
||
|
throw makeError("undefinedModule", a1);
|
||
|
}
|
||
|
if(!isArray(a1)){
|
||
|
// a1 is a configuration
|
||
|
config(a1, 0, referenceModule);
|
||
|
|
||
|
// juggle args; (a2, a3) may be (dependencies, callback)
|
||
|
a1 = a2;
|
||
|
a2 = a3;
|
||
|
}
|
||
|
if(isArray(a1)){
|
||
|
// signature is (requestList [,callback])
|
||
|
if(!a1.length){
|
||
|
a2 && a2();
|
||
|
}else{
|
||
|
syntheticMid = "require*" + uid();
|
||
|
|
||
|
// resolve the request list with respect to the reference module
|
||
|
for(var mid, deps = [], i = 0; i < a1.length;){
|
||
|
mid = a1[i++];
|
||
|
deps.push(getModule(mid, referenceModule));
|
||
|
}
|
||
|
|
||
|
// construct a synthetic module to control execution of the requestList, and, optionally, callback
|
||
|
module = mix(makeModuleInfo("", syntheticMid, 0, ""), {
|
||
|
injected: arrived,
|
||
|
deps: deps,
|
||
|
def: a2 || noop,
|
||
|
require: referenceModule ? referenceModule.require : req,
|
||
|
gc: 1 //garbage collect
|
||
|
});
|
||
|
modules[module.mid] = module;
|
||
|
|
||
|
// checkComplete!=0 holds the idle signal; we're not idle if we're injecting dependencies
|
||
|
injectDependencies(module);
|
||
|
|
||
|
// try to immediately execute
|
||
|
// if already traversing a factory tree, then strict causes circular dependency to abort the execution; maybe
|
||
|
// it's possible to execute this require later after the current traversal completes and avoid the circular dependency.
|
||
|
// ...but *always* insist on immediate in synch mode
|
||
|
var strict = checkCompleteGuard && legacyMode!=sync;
|
||
|
guardCheckComplete(function(){
|
||
|
execModule(module, strict);
|
||
|
});
|
||
|
if(!module.executed){
|
||
|
// some deps weren't on board or circular dependency detected and strict; therefore, push into the execQ
|
||
|
execQ.push(module);
|
||
|
}
|
||
|
checkComplete();
|
||
|
}
|
||
|
}
|
||
|
return contextRequire;
|
||
|
},
|
||
|
|
||
|
createRequire = function(module){
|
||
|
if(!module){
|
||
|
return req;
|
||
|
}
|
||
|
var result = module.require;
|
||
|
if(!result){
|
||
|
result = function(a1, a2, a3){
|
||
|
return contextRequire(a1, a2, a3, module, result);
|
||
|
};
|
||
|
module.require = mix(result, req);
|
||
|
result.module = module;
|
||
|
result.toUrl = function(name){
|
||
|
return toUrl(name, module);
|
||
|
};
|
||
|
result.toAbsMid = function(mid){
|
||
|
return toAbsMid(mid, module);
|
||
|
};
|
||
|
if( 0 ){
|
||
|
result.undef = function(mid){
|
||
|
req.undef(mid, module);
|
||
|
};
|
||
|
}
|
||
|
if( 1 ){
|
||
|
result.syncLoadNls = function(mid){
|
||
|
var nlsModuleInfo = getModuleInfo(mid, module),
|
||
|
nlsModule = modules[nlsModuleInfo.mid];
|
||
|
if(!nlsModule || !nlsModule.executed){
|
||
|
cached = cache[nlsModuleInfo.mid] || cache[urlKeyPrefix + nlsModuleInfo.url];
|
||
|
if(cached){
|
||
|
evalModuleText(cached);
|
||
|
nlsModule = modules[nlsModuleInfo.mid];
|
||
|
}
|
||
|
}
|
||
|
return nlsModule && nlsModule.executed && nlsModule.result;
|
||
|
};
|
||
|
}
|
||
|
|
||
|
}
|
||
|
return result;
|
||
|
},
|
||
|
|
||
|
execQ =
|
||
|
// The list of modules that need to be evaluated.
|
||
|
[],
|
||
|
|
||
|
defQ =
|
||
|
// The queue of define arguments sent to loader.
|
||
|
[],
|
||
|
|
||
|
waiting =
|
||
|
// The set of modules upon which the loader is waiting for definition to arrive
|
||
|
{},
|
||
|
|
||
|
setRequested = function(module){
|
||
|
module.injected = requested;
|
||
|
waiting[module.mid] = 1;
|
||
|
if(module.url){
|
||
|
waiting[module.url] = module.pack || 1;
|
||
|
}
|
||
|
startTimer();
|
||
|
},
|
||
|
|
||
|
setArrived = function(module){
|
||
|
module.injected = arrived;
|
||
|
delete waiting[module.mid];
|
||
|
if(module.url){
|
||
|
delete waiting[module.url];
|
||
|
}
|
||
|
if(isEmpty(waiting)){
|
||
|
clearTimer();
|
||
|
1 && legacyMode==xd && (legacyMode = sync);
|
||
|
}
|
||
|
},
|
||
|
|
||
|
execComplete = req.idle =
|
||
|
// says the loader has completed (or not) its work
|
||
|
function(){
|
||
|
return !defQ.length && isEmpty(waiting) && !execQ.length && !checkCompleteGuard;
|
||
|
};
|
||
|
}
|
||
|
|
||
|
var runMapProg = function(targetMid, map){
|
||
|
// search for targetMid in map; return the map item if found; falsy otherwise
|
||
|
if(map){
|
||
|
for(var i = 0; i < map.length; i++){
|
||
|
if(map[i][2].test(targetMid)){
|
||
|
return map[i];
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
return 0;
|
||
|
},
|
||
|
|
||
|
compactPath = function(path){
|
||
|
var result = [],
|
||
|
segment, lastSegment;
|
||
|
path = path.replace(/\\/g, '/').split('/');
|
||
|
while(path.length){
|
||
|
segment = path.shift();
|
||
|
if(segment==".." && result.length && lastSegment!=".."){
|
||
|
result.pop();
|
||
|
lastSegment = result[result.length - 1];
|
||
|
}else if(segment!="."){
|
||
|
result.push(lastSegment= segment);
|
||
|
} // else ignore "."
|
||
|
}
|
||
|
return result.join("/");
|
||
|
},
|
||
|
|
||
|
makeModuleInfo = function(pid, mid, pack, url){
|
||
|
if( 1 ){
|
||
|
var xd= req.isXdUrl(url);
|
||
|
return {pid:pid, mid:mid, pack:pack, url:url, executed:0, def:0, isXd:xd, isAmd:!!(xd || (packs[pid] && packs[pid].isAmd))};
|
||
|
}else{
|
||
|
return {pid:pid, mid:mid, pack:pack, url:url, executed:0, def:0};
|
||
|
}
|
||
|
},
|
||
|
|
||
|
getModuleInfo_ = function(mid, referenceModule, packs, modules, baseUrl, mapProgs, pathsMapProg, aliases, alwaysCreate, fromPendingCache){
|
||
|
// arguments are passed instead of using lexical variables so that this function my be used independent of the loader (e.g., the builder)
|
||
|
// alwaysCreate is useful in this case so that getModuleInfo never returns references to real modules owned by the loader
|
||
|
var pid, pack, midInPackage, mapItem, url, result, isRelative, requestedMid;
|
||
|
requestedMid = mid;
|
||
|
isRelative = /^\./.test(mid);
|
||
|
if(/(^\/)|(\:)|(\.js$)/.test(mid) || (isRelative && !referenceModule)){
|
||
|
// absolute path or protocol of .js filetype, or relative path but no reference module and therefore relative to page
|
||
|
// whatever it is, it's not a module but just a URL of some sort
|
||
|
// note: pid===0 indicates the routine is returning an unmodified mid
|
||
|
|
||
|
return makeModuleInfo(0, mid, 0, mid);
|
||
|
}else{
|
||
|
// relative module ids are relative to the referenceModule; get rid of any dots
|
||
|
mid = compactPath(isRelative ? (referenceModule.mid + "/../" + mid) : mid);
|
||
|
if(/^\./.test(mid)){
|
||
|
throw makeError("irrationalPath", mid);
|
||
|
}
|
||
|
// at this point, mid is an absolute mid
|
||
|
|
||
|
// map the mid
|
||
|
if(!fromPendingCache && !isRelative && mapProgs.star){
|
||
|
mapItem = runMapProg(mid, mapProgs.star[1]);
|
||
|
}
|
||
|
if(!mapItem && referenceModule){
|
||
|
mapItem = runMapProg(referenceModule.mid, mapProgs);
|
||
|
mapItem = mapItem && runMapProg(mid, mapItem[1]);
|
||
|
}
|
||
|
|
||
|
if(mapItem){
|
||
|
mid = mapItem[1] + mid.substring(mapItem[3]);
|
||
|
}
|
||
|
|
||
|
match = mid.match(/^([^\/]+)(\/(.+))?$/);
|
||
|
pid = match ? match[1] : "";
|
||
|
if((pack = packs[pid])){
|
||
|
mid = pid + "/" + (midInPackage = (match[3] || pack.main));
|
||
|
}else{
|
||
|
pid = "";
|
||
|
}
|
||
|
|
||
|
// search aliases
|
||
|
var candidateLength = 0,
|
||
|
candidate = 0;
|
||
|
forEach(aliases, function(pair){
|
||
|
var match = mid.match(pair[0]);
|
||
|
if(match && match.length>candidateLength){
|
||
|
candidate = isFunction(pair[1]) ? mid.replace(pair[0], pair[1]) : pair[1];
|
||
|
}
|
||
|
});
|
||
|
if(candidate){
|
||
|
return getModuleInfo_(candidate, 0, packs, modules, baseUrl, mapProgs, pathsMapProg, aliases, alwaysCreate);
|
||
|
}
|
||
|
|
||
|
result = modules[mid];
|
||
|
if(result){
|
||
|
return alwaysCreate ? makeModuleInfo(result.pid, result.mid, result.pack, result.url) : modules[mid];
|
||
|
}
|
||
|
}
|
||
|
// get here iff the sought-after module does not yet exist; therefore, we need to compute the URL given the
|
||
|
// fully resolved (i.e., all relative indicators and package mapping resolved) module id
|
||
|
|
||
|
// note: pid!==0 indicates the routine is returning a url that has .js appended unmodified mid
|
||
|
mapItem = runMapProg(mid, pathsMapProg);
|
||
|
if(mapItem){
|
||
|
url = mapItem[1] + mid.substring(mapItem[3]);
|
||
|
}else if(pid){
|
||
|
url = (pack.location.slice(-1) === '/' ? pack.location.slice(0, -1) : pack.location) + "/" + midInPackage;
|
||
|
}else if(has("config-tlmSiblingOfDojo")){
|
||
|
url = "../" + mid;
|
||
|
}else{
|
||
|
url = mid;
|
||
|
}
|
||
|
// if result is not absolute, add baseUrl
|
||
|
if(!(/(^\/)|(\:)/.test(url))){
|
||
|
url = baseUrl + url;
|
||
|
}
|
||
|
url += ".js";
|
||
|
return makeModuleInfo(pid, mid, pack, compactPath(url));
|
||
|
},
|
||
|
|
||
|
getModuleInfo = function(mid, referenceModule, fromPendingCache){
|
||
|
return getModuleInfo_(mid, referenceModule, packs, modules, req.baseUrl, mapProgs, pathsMapProg, aliases, undefined, fromPendingCache);
|
||
|
};
|
||
|
|
||
|
if (!has("foreign-loader")) {
|
||
|
var resolvePluginResourceId = function(plugin, prid, referenceModule){
|
||
|
return plugin.normalize ? plugin.normalize(prid, function(mid){return toAbsMid(mid, referenceModule);}) : toAbsMid(prid, referenceModule);
|
||
|
},
|
||
|
|
||
|
dynamicPluginUidGenerator = 0,
|
||
|
|
||
|
getModule = function(mid, referenceModule, immediate){
|
||
|
// compute and optionally construct (if necessary) the module implied by the mid with respect to referenceModule
|
||
|
var match, plugin, prid, result;
|
||
|
match = mid.match(/^(.+?)\!(.*)$/);
|
||
|
if(match){
|
||
|
// name was <plugin-module>!<plugin-resource-id>
|
||
|
plugin = getModule(match[1], referenceModule, immediate);
|
||
|
|
||
|
if( 1 && legacyMode == sync && !plugin.executed){
|
||
|
injectModule(plugin);
|
||
|
if(plugin.injected===arrived && !plugin.executed){
|
||
|
guardCheckComplete(function(){
|
||
|
execModule(plugin);
|
||
|
});
|
||
|
}
|
||
|
if(plugin.executed){
|
||
|
promoteModuleToPlugin(plugin);
|
||
|
}else{
|
||
|
// we are in xdomain mode for some reason
|
||
|
execQ.unshift(plugin);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
|
||
|
|
||
|
if(plugin.executed === executed && !plugin.load){
|
||
|
// executed the module not knowing it was a plugin
|
||
|
promoteModuleToPlugin(plugin);
|
||
|
}
|
||
|
|
||
|
// if the plugin has not been loaded, then can't resolve the prid and must assume this plugin is dynamic until we find out otherwise
|
||
|
if(plugin.load){
|
||
|
prid = resolvePluginResourceId(plugin, match[2], referenceModule);
|
||
|
mid = (plugin.mid + "!" + (plugin.dynamic ? ++dynamicPluginUidGenerator + "!" : "") + prid);
|
||
|
}else{
|
||
|
prid = match[2];
|
||
|
mid = plugin.mid + "!" + (++dynamicPluginUidGenerator) + "!waitingForPlugin";
|
||
|
}
|
||
|
result = {plugin:plugin, mid:mid, req:createRequire(referenceModule), prid:prid};
|
||
|
}else{
|
||
|
result = getModuleInfo(mid, referenceModule);
|
||
|
}
|
||
|
return modules[result.mid] || (!immediate && (modules[result.mid] = result));
|
||
|
};
|
||
|
}
|
||
|
|
||
|
var toAbsMid = req.toAbsMid = function(mid, referenceModule){
|
||
|
return getModuleInfo(mid, referenceModule).mid;
|
||
|
},
|
||
|
|
||
|
toUrl = req.toUrl = function(name, referenceModule){
|
||
|
var moduleInfo = getModuleInfo(name+"/x", referenceModule),
|
||
|
url= moduleInfo.url;
|
||
|
return fixupUrl(moduleInfo.pid===0 ?
|
||
|
// if pid===0, then name had a protocol or absolute path; either way, toUrl is the identify function in such cases
|
||
|
name :
|
||
|
// "/x.js" since getModuleInfo automatically appends ".js" and we appended "/x" to make name look like a module id
|
||
|
url.substring(0, url.length-5)
|
||
|
);
|
||
|
};
|
||
|
|
||
|
if (!has("foreign-loader")) {
|
||
|
var nonModuleProps = {
|
||
|
injected: arrived,
|
||
|
executed: executed,
|
||
|
def: nonmodule,
|
||
|
result: nonmodule
|
||
|
},
|
||
|
|
||
|
makeCjs = function(mid){
|
||
|
return modules[mid] = mix({mid:mid}, nonModuleProps);
|
||
|
},
|
||
|
|
||
|
cjsRequireModule = makeCjs("require"),
|
||
|
cjsExportsModule = makeCjs("exports"),
|
||
|
cjsModuleModule = makeCjs("module"),
|
||
|
|
||
|
runFactory = function(module, args){
|
||
|
req.trace("loader-run-factory", [module.mid]);
|
||
|
var factory = module.def,
|
||
|
result;
|
||
|
1 && syncExecStack.unshift(module);
|
||
|
if(has("config-dojo-loader-catches")){
|
||
|
try{
|
||
|
result= isFunction(factory) ? factory.apply(null, args) : factory;
|
||
|
}catch(e){
|
||
|
signal(error, module.result = makeError("factoryThrew", [module, e]));
|
||
|
}
|
||
|
}else{
|
||
|
result= isFunction(factory) ? factory.apply(null, args) : factory;
|
||
|
}
|
||
|
module.result = result===undefined && module.cjs ? module.cjs.exports : result;
|
||
|
1 && syncExecStack.shift(module);
|
||
|
},
|
||
|
|
||
|
abortExec = {},
|
||
|
|
||
|
defOrder = 0,
|
||
|
|
||
|
promoteModuleToPlugin = function(pluginModule){
|
||
|
var plugin = pluginModule.result;
|
||
|
pluginModule.dynamic = plugin.dynamic;
|
||
|
pluginModule.normalize = plugin.normalize;
|
||
|
pluginModule.load = plugin.load;
|
||
|
return pluginModule;
|
||
|
},
|
||
|
|
||
|
resolvePluginLoadQ = function(plugin){
|
||
|
// plugins is a newly executed module that has a loadQ waiting to run
|
||
|
|
||
|
// step 1: traverse the loadQ and fixup the mid and prid; remember the map from original mid to new mid
|
||
|
// recall the original mid was created before the plugin was on board and therefore it was impossible to
|
||
|
// compute the final mid; accordingly, prid may or may not change, but the mid will definitely change
|
||
|
var map = {};
|
||
|
forEach(plugin.loadQ, function(pseudoPluginResource){
|
||
|
// manufacture and insert the real module in modules
|
||
|
var prid = resolvePluginResourceId(plugin, pseudoPluginResource.prid, pseudoPluginResource.req.module),
|
||
|
mid = plugin.dynamic ? pseudoPluginResource.mid.replace(/waitingForPlugin$/, prid) : (plugin.mid + "!" + prid),
|
||
|
pluginResource = mix(mix({}, pseudoPluginResource), {mid:mid, prid:prid, injected:0});
|
||
|
if(!modules[mid] || !modules[mid].injected /*for require.undef*/){
|
||
|
// create a new (the real) plugin resource and inject it normally now that the plugin is on board
|
||
|
injectPlugin(modules[mid] = pluginResource);
|
||
|
} // else this was a duplicate request for the same (plugin, rid) for a nondynamic plugin
|
||
|
|
||
|
// pluginResource is really just a placeholder with the wrong mid (because we couldn't calculate it until the plugin was on board)
|
||
|
// mark is as arrived and delete it from modules; the real module was requested above
|
||
|
map[pseudoPluginResource.mid] = modules[mid];
|
||
|
setArrived(pseudoPluginResource);
|
||
|
delete modules[pseudoPluginResource.mid];
|
||
|
});
|
||
|
plugin.loadQ = 0;
|
||
|
|
||
|
// step2: replace all references to any placeholder modules with real modules
|
||
|
var substituteModules = function(module){
|
||
|
for(var replacement, deps = module.deps || [], i = 0; i<deps.length; i++){
|
||
|
replacement = map[deps[i].mid];
|
||
|
if(replacement){
|
||
|
deps[i] = replacement;
|
||
|
}
|
||
|
}
|
||
|
};
|
||
|
for(var p in modules){
|
||
|
substituteModules(modules[p]);
|
||
|
}
|
||
|
forEach(execQ, substituteModules);
|
||
|
},
|
||
|
|
||
|
finishExec = function(module){
|
||
|
req.trace("loader-finish-exec", [module.mid]);
|
||
|
module.executed = executed;
|
||
|
module.defOrder = defOrder++;
|
||
|
1 && forEach(module.provides, function(cb){ cb(); });
|
||
|
if(module.loadQ){
|
||
|
// the module was a plugin
|
||
|
promoteModuleToPlugin(module);
|
||
|
resolvePluginLoadQ(module);
|
||
|
}
|
||
|
// remove all occurrences of this module from the execQ
|
||
|
for(i = 0; i < execQ.length;){
|
||
|
if(execQ[i] === module){
|
||
|
execQ.splice(i, 1);
|
||
|
}else{
|
||
|
i++;
|
||
|
}
|
||
|
}
|
||
|
// delete references to synthetic modules
|
||
|
if (/^require\*/.test(module.mid)) {
|
||
|
delete modules[module.mid];
|
||
|
}
|
||
|
},
|
||
|
|
||
|
circleTrace = [],
|
||
|
|
||
|
execModule = function(module, strict){
|
||
|
// run the dependency vector, then run the factory for module
|
||
|
if(module.executed === executing){
|
||
|
req.trace("loader-circular-dependency", [circleTrace.concat(module.mid).join("->")]);
|
||
|
return (!module.def || strict) ? abortExec : (module.cjs && module.cjs.exports);
|
||
|
}
|
||
|
// at this point the module is either not executed or fully executed
|
||
|
|
||
|
|
||
|
if(!module.executed){
|
||
|
if(!module.def){
|
||
|
return abortExec;
|
||
|
}
|
||
|
var mid = module.mid,
|
||
|
deps = module.deps || [],
|
||
|
arg, argResult,
|
||
|
args = [],
|
||
|
i = 0;
|
||
|
|
||
|
if( 0 ){
|
||
|
circleTrace.push(mid);
|
||
|
req.trace("loader-exec-module", ["exec", circleTrace.length, mid]);
|
||
|
}
|
||
|
|
||
|
// for circular dependencies, assume the first module encountered was executed OK
|
||
|
// modules that circularly depend on a module that has not run its factory will get
|
||
|
// the pre-made cjs.exports===module.result. They can take a reference to this object and/or
|
||
|
// add properties to it. When the module finally runs its factory, the factory can
|
||
|
// read/write/replace this object. Notice that so long as the object isn't replaced, any
|
||
|
// reference taken earlier while walking the deps list is still valid.
|
||
|
module.executed = executing;
|
||
|
while((arg = deps[i++])){
|
||
|
argResult = ((arg === cjsRequireModule) ? createRequire(module) :
|
||
|
((arg === cjsExportsModule) ? module.cjs.exports :
|
||
|
((arg === cjsModuleModule) ? module.cjs :
|
||
|
execModule(arg, strict))));
|
||
|
if(argResult === abortExec){
|
||
|
module.executed = 0;
|
||
|
req.trace("loader-exec-module", ["abort", mid]);
|
||
|
0 && circleTrace.pop();
|
||
|
return abortExec;
|
||
|
}
|
||
|
args.push(argResult);
|
||
|
}
|
||
|
runFactory(module, args);
|
||
|
finishExec(module);
|
||
|
0 && circleTrace.pop();
|
||
|
}
|
||
|
// at this point the module is guaranteed fully executed
|
||
|
|
||
|
return module.result;
|
||
|
},
|
||
|
|
||
|
|
||
|
checkCompleteGuard = 0,
|
||
|
|
||
|
guardCheckComplete = function(proc){
|
||
|
try{
|
||
|
checkCompleteGuard++;
|
||
|
proc();
|
||
|
}catch(e){
|
||
|
// https://bugs.dojotoolkit.org/ticket/16617
|
||
|
throw e;
|
||
|
}finally{
|
||
|
checkCompleteGuard--;
|
||
|
}
|
||
|
if(execComplete()){
|
||
|
signal("idle", []);
|
||
|
}
|
||
|
},
|
||
|
|
||
|
checkComplete = function(){
|
||
|
// keep going through the execQ as long as at least one factory is executed
|
||
|
// plugins, recursion, cached modules all make for many execution path possibilities
|
||
|
if(checkCompleteGuard){
|
||
|
return;
|
||
|
}
|
||
|
guardCheckComplete(function(){
|
||
|
checkDojoRequirePlugin();
|
||
|
for(var currentDefOrder, module, i = 0; i < execQ.length;){
|
||
|
currentDefOrder = defOrder;
|
||
|
module = execQ[i];
|
||
|
execModule(module);
|
||
|
if(currentDefOrder!=defOrder){
|
||
|
// defOrder was bumped one or more times indicating something was executed (note, this indicates
|
||
|
// the execQ was modified, maybe a lot (for example a later module causes an earlier module to execute)
|
||
|
checkDojoRequirePlugin();
|
||
|
i = 0;
|
||
|
}else{
|
||
|
// nothing happened; check the next module in the exec queue
|
||
|
i++;
|
||
|
}
|
||
|
}
|
||
|
});
|
||
|
};
|
||
|
}
|
||
|
|
||
|
var fixupUrl= typeof userConfig.fixupUrl == "function" ? userConfig.fixupUrl : function(url){
|
||
|
url += ""; // make sure url is a Javascript string (some paths may be a Java string)
|
||
|
return url + (cacheBust ? ((/\?/.test(url) ? "&" : "?") + cacheBust) : "");
|
||
|
};
|
||
|
|
||
|
|
||
|
|
||
|
if( 0 ){
|
||
|
req.undef = function(moduleId, referenceModule){
|
||
|
// In order to reload a module, it must be undefined (this routine) and then re-requested.
|
||
|
// This is useful for testing frameworks (at least).
|
||
|
var module = getModule(moduleId, referenceModule);
|
||
|
setArrived(module);
|
||
|
mix(module, {def:0, executed:0, injected:0, node:0, load:0});
|
||
|
};
|
||
|
}
|
||
|
|
||
|
if( 1 ){
|
||
|
if(has("dojo-loader-eval-hint-url")===undefined){
|
||
|
has.add("dojo-loader-eval-hint-url", 1);
|
||
|
}
|
||
|
|
||
|
var injectPlugin = function(
|
||
|
module
|
||
|
){
|
||
|
// injects the plugin module given by module; may have to inject the plugin itself
|
||
|
var plugin = module.plugin;
|
||
|
|
||
|
if(plugin.executed === executed && !plugin.load){
|
||
|
// executed the module not knowing it was a plugin
|
||
|
promoteModuleToPlugin(plugin);
|
||
|
}
|
||
|
|
||
|
var onLoad = function(def){
|
||
|
module.result = def;
|
||
|
setArrived(module);
|
||
|
finishExec(module);
|
||
|
checkComplete();
|
||
|
};
|
||
|
|
||
|
if(plugin.load){
|
||
|
plugin.load(module.prid, module.req, onLoad);
|
||
|
}else if(plugin.loadQ){
|
||
|
plugin.loadQ.push(module);
|
||
|
}else{
|
||
|
// the unshift instead of push is important: we don't want plugins to execute as
|
||
|
// dependencies of some other module because this may cause circles when the plugin
|
||
|
// loadQ is run; also, generally, we want plugins to run early since they may load
|
||
|
// several other modules and therefore can potentially unblock many modules
|
||
|
plugin.loadQ = [module];
|
||
|
execQ.unshift(plugin);
|
||
|
injectModule(plugin);
|
||
|
}
|
||
|
},
|
||
|
|
||
|
// for IE, injecting a module may result in a recursive execution if the module is in the cache
|
||
|
|
||
|
cached = 0,
|
||
|
|
||
|
injectingModule = 0,
|
||
|
|
||
|
injectingCachedModule = 0,
|
||
|
|
||
|
evalModuleText = function(text, module){
|
||
|
// see def() for the injectingCachedModule bracket; it simply causes a short, safe circuit
|
||
|
if(has("config-stripStrict")){
|
||
|
text = text.replace(/(["'])use strict\1/g, '');
|
||
|
}
|
||
|
injectingCachedModule = 1;
|
||
|
if(has("config-dojo-loader-catches")){
|
||
|
try{
|
||
|
if(text===cached){
|
||
|
cached.call(null);
|
||
|
}else{
|
||
|
req.eval(text, has("dojo-loader-eval-hint-url") ? module.url : module.mid);
|
||
|
}
|
||
|
}catch(e){
|
||
|
signal(error, makeError("evalModuleThrew", module));
|
||
|
}
|
||
|
}else{
|
||
|
if(text===cached){
|
||
|
cached.call(null);
|
||
|
}else{
|
||
|
req.eval(text, has("dojo-loader-eval-hint-url") ? module.url : module.mid);
|
||
|
}
|
||
|
}
|
||
|
injectingCachedModule = 0;
|
||
|
},
|
||
|
|
||
|
injectModule = function(module){
|
||
|
// Inject the module. In the browser environment, this means appending a script element into
|
||
|
// the document; in other environments, it means loading a file.
|
||
|
//
|
||
|
// If in synchronous mode, then get the module synchronously if it's not xdomainLoading.
|
||
|
|
||
|
var mid = module.mid,
|
||
|
url = module.url;
|
||
|
if(module.executed || module.injected || waiting[mid] || (module.url && ((module.pack && waiting[module.url]===module.pack) || waiting[module.url]==1))){
|
||
|
return;
|
||
|
}
|
||
|
setRequested(module);
|
||
|
|
||
|
if( 0 ){
|
||
|
var viaCombo = 0;
|
||
|
if(module.plugin && module.plugin.isCombo){
|
||
|
// a combo plugin; therefore, must be handled by combo service
|
||
|
// the prid should have already been converted to a URL (if required by the plugin) during
|
||
|
// the normalize process; in any event, there is no way for the loader to know how to
|
||
|
// to the conversion; therefore the third argument is zero
|
||
|
req.combo.add(module.plugin.mid, module.prid, 0, req);
|
||
|
viaCombo = 1;
|
||
|
}else if(!module.plugin){
|
||
|
viaCombo = req.combo.add(0, module.mid, module.url, req);
|
||
|
}
|
||
|
if(viaCombo){
|
||
|
comboPending= 1;
|
||
|
return;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
if(module.plugin){
|
||
|
injectPlugin(module);
|
||
|
return;
|
||
|
} // else a normal module (not a plugin)
|
||
|
|
||
|
|
||
|
var onLoadCallback = function(){
|
||
|
runDefQ(module);
|
||
|
if(module.injected !== arrived){
|
||
|
// the script that contained the module arrived and has been executed yet
|
||
|
// nothing was added to the defQ (so it wasn't an AMD module) and the module
|
||
|
// wasn't marked as arrived by dojo.provide (so it wasn't a v1.6- module);
|
||
|
// therefore, it must not have been a module; adjust state accordingly
|
||
|
if(has("dojo-enforceDefine")){
|
||
|
signal(error, makeError("noDefine", module));
|
||
|
return;
|
||
|
}
|
||
|
setArrived(module);
|
||
|
mix(module, nonModuleProps);
|
||
|
req.trace("loader-define-nonmodule", [module.url]);
|
||
|
}
|
||
|
|
||
|
if( 1 && legacyMode){
|
||
|
// must call checkComplete even in for sync loader because we may be in xdomainLoading mode;
|
||
|
// but, if xd loading, then don't call checkComplete until out of the current sync traversal
|
||
|
// in order to preserve order of execution of the dojo.required modules
|
||
|
!syncExecStack.length && checkComplete();
|
||
|
}else{
|
||
|
checkComplete();
|
||
|
}
|
||
|
};
|
||
|
cached = cache[mid] || cache[urlKeyPrefix + module.url];
|
||
|
if(cached){
|
||
|
req.trace("loader-inject", ["cache", module.mid, url]);
|
||
|
evalModuleText(cached, module);
|
||
|
onLoadCallback();
|
||
|
return;
|
||
|
}
|
||
|
if( 1 && legacyMode){
|
||
|
if(module.isXd){
|
||
|
// switch to async mode temporarily; if current legacyMode!=sync, then is must be one of {legacyAsync, xd, false}
|
||
|
legacyMode==sync && (legacyMode = xd);
|
||
|
// fall through and load via script injection
|
||
|
}else if(module.isAmd && legacyMode!=sync){
|
||
|
// fall through and load via script injection
|
||
|
}else{
|
||
|
// mode may be sync, xd/legacyAsync, or async; module may be AMD or legacy; but module is always located on the same domain
|
||
|
var xhrCallback = function(text){
|
||
|
if(legacyMode==sync){
|
||
|
// the top of syncExecStack gives the current synchronously executing module; the loader needs
|
||
|
// to know this if it has to switch to async loading in the middle of evaluating a legacy module
|
||
|
// this happens when a modules dojo.require's a module that must be loaded async because it's xdomain
|
||
|
// (using unshift/shift because there is no back() methods for Javascript arrays)
|
||
|
syncExecStack.unshift(module);
|
||
|
evalModuleText(text, module);
|
||
|
syncExecStack.shift();
|
||
|
|
||
|
// maybe the module was an AMD module
|
||
|
runDefQ(module);
|
||
|
|
||
|
// legacy modules never get to defineModule() => cjs and injected never set; also evaluation implies executing
|
||
|
if(!module.cjs){
|
||
|
setArrived(module);
|
||
|
finishExec(module);
|
||
|
}
|
||
|
|
||
|
if(module.finish){
|
||
|
// while synchronously evaluating this module, dojo.require was applied referencing a module
|
||
|
// that had to be loaded async; therefore, the loader stopped answering all dojo.require
|
||
|
// requests so they could be answered completely in the correct sequence; module.finish gives
|
||
|
// the list of dojo.requires that must be re-applied once all target modules are available;
|
||
|
// make a synthetic module to execute the dojo.require's in the correct order
|
||
|
|
||
|
// compute a guaranteed-unique mid for the synthetic finish module; remember the finish vector; remove it from the reference module
|
||
|
// TODO: can we just leave the module.finish...what's it hurting?
|
||
|
var finishMid = mid + "*finish",
|
||
|
finish = module.finish;
|
||
|
delete module.finish;
|
||
|
|
||
|
def(finishMid, ["dojo", ("dojo/require!" + finish.join(",")).replace(/\./g, "/")], function(dojo){
|
||
|
forEach(finish, function(mid){ dojo.require(mid); });
|
||
|
});
|
||
|
// unshift, not push, which causes the current traversal to be reattempted from the top
|
||
|
execQ.unshift(getModule(finishMid));
|
||
|
}
|
||
|
onLoadCallback();
|
||
|
}else{
|
||
|
text = transformToAmd(module, text);
|
||
|
if(text){
|
||
|
evalModuleText(text, module);
|
||
|
onLoadCallback();
|
||
|
}else{
|
||
|
// if transformToAmd returned falsy, then the module was already AMD and it can be script-injected
|
||
|
// do so to improve debugability(even though it means another download...which probably won't happen with a good browser cache)
|
||
|
injectingModule = module;
|
||
|
req.injectUrl(fixupUrl(url), onLoadCallback, module);
|
||
|
injectingModule = 0;
|
||
|
}
|
||
|
}
|
||
|
};
|
||
|
|
||
|
req.trace("loader-inject", ["xhr", module.mid, url, legacyMode!=sync]);
|
||
|
if(has("config-dojo-loader-catches")){
|
||
|
try{
|
||
|
req.getText(url, legacyMode!=sync, xhrCallback);
|
||
|
}catch(e){
|
||
|
signal(error, makeError("xhrInjectFailed", [module, e]));
|
||
|
}
|
||
|
}else{
|
||
|
req.getText(url, legacyMode!=sync, xhrCallback);
|
||
|
}
|
||
|
return;
|
||
|
}
|
||
|
} // else async mode or fell through in xdomain loading mode; either way, load by script injection
|
||
|
req.trace("loader-inject", ["script", module.mid, url]);
|
||
|
injectingModule = module;
|
||
|
req.injectUrl(fixupUrl(url), onLoadCallback, module);
|
||
|
injectingModule = 0;
|
||
|
},
|
||
|
|
||
|
defineModule = function(module, deps, def){
|
||
|
req.trace("loader-define-module", [module.mid, deps]);
|
||
|
|
||
|
if( 0 && module.plugin && module.plugin.isCombo){
|
||
|
// the module is a plugin resource loaded by the combo service
|
||
|
// note: check for module.plugin should be enough since normal plugin resources should
|
||
|
// not follow this path; module.plugin.isCombo is future-proofing belt and suspenders
|
||
|
module.result = isFunction(def) ? def() : def;
|
||
|
setArrived(module);
|
||
|
finishExec(module);
|
||
|
return module;
|
||
|
}
|
||
|
|
||
|
var mid = module.mid;
|
||
|
if(module.injected === arrived){
|
||
|
signal(error, makeError("multipleDefine", module));
|
||
|
return module;
|
||
|
}
|
||
|
mix(module, {
|
||
|
deps: deps,
|
||
|
def: def,
|
||
|
cjs: {
|
||
|
id: module.mid,
|
||
|
uri: module.url,
|
||
|
exports: (module.result = {}),
|
||
|
setExports: function(exports){
|
||
|
module.cjs.exports = exports;
|
||
|
},
|
||
|
config:function(){
|
||
|
return module.config;
|
||
|
}
|
||
|
}
|
||
|
});
|
||
|
|
||
|
// resolve deps with respect to this module
|
||
|
for(var i = 0; deps[i]; i++){
|
||
|
deps[i] = getModule(deps[i], module);
|
||
|
}
|
||
|
|
||
|
if( 1 && legacyMode && !waiting[mid]){
|
||
|
// the module showed up without being asked for; it was probably in a <script> element
|
||
|
injectDependencies(module);
|
||
|
execQ.push(module);
|
||
|
checkComplete();
|
||
|
}
|
||
|
setArrived(module);
|
||
|
|
||
|
if(!isFunction(def) && !deps.length){
|
||
|
module.result = def;
|
||
|
finishExec(module);
|
||
|
}
|
||
|
|
||
|
return module;
|
||
|
},
|
||
|
|
||
|
runDefQ = function(referenceModule, mids){
|
||
|
// defQ is an array of [id, dependencies, factory]
|
||
|
// mids (if any) is a vector of mids given by a combo service
|
||
|
var definedModules = [],
|
||
|
module, args;
|
||
|
while(defQ.length){
|
||
|
args = defQ.shift();
|
||
|
mids && (args[0]= mids.shift());
|
||
|
// explicit define indicates possible multiple modules in a single file; delay injecting dependencies until defQ fully
|
||
|
// processed since modules earlier in the queue depend on already-arrived modules that are later in the queue
|
||
|
// TODO: what if no args[0] and no referenceModule
|
||
|
module = (args[0] && getModule(args[0])) || referenceModule;
|
||
|
definedModules.push([module, args[1], args[2]]);
|
||
|
}
|
||
|
consumePendingCacheInsert(referenceModule);
|
||
|
forEach(definedModules, function(args){
|
||
|
injectDependencies(defineModule.apply(null, args));
|
||
|
});
|
||
|
};
|
||
|
}
|
||
|
|
||
|
var timerId = 0,
|
||
|
clearTimer = noop,
|
||
|
startTimer = noop;
|
||
|
if( 1 ){
|
||
|
// Timer machinery that monitors how long the loader is waiting and signals an error when the timer runs out.
|
||
|
clearTimer = function(){
|
||
|
timerId && clearTimeout(timerId);
|
||
|
timerId = 0;
|
||
|
};
|
||
|
|
||
|
startTimer = function(){
|
||
|
clearTimer();
|
||
|
if(req.waitms){
|
||
|
timerId = global.setTimeout(function(){
|
||
|
clearTimer();
|
||
|
signal(error, makeError("timeout", waiting));
|
||
|
}, req.waitms);
|
||
|
}
|
||
|
};
|
||
|
}
|
||
|
|
||
|
if ( 1 ) {
|
||
|
// Test for IE's different way of signaling when scripts finish loading. Note that according to
|
||
|
// http://bugs.dojotoolkit.org/ticket/15096#comment:14, IE9 also needs to follow the
|
||
|
// IE specific code path even though it has an addEventListener() method.
|
||
|
// Unknown if special path needed on IE10+, which also has a document.attachEvent() method.
|
||
|
// Should evaluate to false for Opera and Windows 8 apps, even though they document.attachEvent()
|
||
|
// is defined in both those environments.
|
||
|
has.add("ie-event-behavior", doc.attachEvent && typeof Windows === "undefined" &&
|
||
|
(typeof opera === "undefined" || opera.toString() != "[object Opera]"));
|
||
|
}
|
||
|
|
||
|
if( 1 && ( 1 || 1 )){
|
||
|
var domOn = function(node, eventName, ieEventName, handler){
|
||
|
// Add an event listener to a DOM node using the API appropriate for the current browser;
|
||
|
// return a function that will disconnect the listener.
|
||
|
if(!has("ie-event-behavior")){
|
||
|
node.addEventListener(eventName, handler, false);
|
||
|
return function(){
|
||
|
node.removeEventListener(eventName, handler, false);
|
||
|
};
|
||
|
}else{
|
||
|
node.attachEvent(ieEventName, handler);
|
||
|
return function(){
|
||
|
node.detachEvent(ieEventName, handler);
|
||
|
};
|
||
|
}
|
||
|
},
|
||
|
windowOnLoadListener = domOn(window, "load", "onload", function(){
|
||
|
req.pageLoaded = 1;
|
||
|
// https://bugs.dojotoolkit.org/ticket/16248
|
||
|
try{
|
||
|
doc.readyState!="complete" && (doc.readyState = "complete");
|
||
|
}catch(e){
|
||
|
}
|
||
|
windowOnLoadListener();
|
||
|
});
|
||
|
|
||
|
if( 1 ){
|
||
|
// if the loader is on the page, there must be at least one script element
|
||
|
// getting its parent and then doing insertBefore solves the "Operation Aborted"
|
||
|
// error in IE from appending to a node that isn't properly closed; see
|
||
|
// dojo/tests/_base/loader/requirejs/simple-badbase.html for an example
|
||
|
// don't use scripts with type dojo/... since these may be removed; see #15809
|
||
|
// prefer to use the insertPoint computed during the config sniff in case a script is removed; see #16958
|
||
|
var scripts = doc.getElementsByTagName("script"),
|
||
|
i = 0,
|
||
|
script;
|
||
|
while(!insertPointSibling){
|
||
|
if(!/^dojo/.test((script = scripts[i++]) && script.type)){
|
||
|
insertPointSibling= script;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
req.injectUrl = function(url, callback, owner){
|
||
|
// insert a script element to the insert-point element with src=url;
|
||
|
// apply callback upon detecting the script has loaded.
|
||
|
|
||
|
var node = owner.node = doc.createElement("script"),
|
||
|
onLoad = function(e){
|
||
|
e = e || window.event;
|
||
|
var node = e.target || e.srcElement;
|
||
|
if(e.type === "load" || /complete|loaded/.test(node.readyState)){
|
||
|
loadDisconnector();
|
||
|
errorDisconnector();
|
||
|
callback && callback();
|
||
|
}
|
||
|
},
|
||
|
loadDisconnector = domOn(node, "load", "onreadystatechange", onLoad),
|
||
|
errorDisconnector = domOn(node, "error", "onerror", function(e){
|
||
|
loadDisconnector();
|
||
|
errorDisconnector();
|
||
|
signal(error, makeError("scriptError: " + url, [url, e]));
|
||
|
});
|
||
|
|
||
|
node.type = "text/javascript";
|
||
|
node.charset = "utf-8";
|
||
|
node.src = url;
|
||
|
insertPointSibling.parentNode.insertBefore(node, insertPointSibling);
|
||
|
return node;
|
||
|
};
|
||
|
}
|
||
|
}
|
||
|
|
||
|
if( 1 ){
|
||
|
req.log = function(){
|
||
|
try{
|
||
|
for(var i = 0; i < arguments.length; i++){
|
||
|
console.log(arguments[i]);
|
||
|
}
|
||
|
}catch(e){}
|
||
|
};
|
||
|
}else{
|
||
|
req.log = noop;
|
||
|
}
|
||
|
|
||
|
if( 0 ){
|
||
|
var trace = req.trace = function(
|
||
|
group, // the trace group to which this application belongs
|
||
|
args // the contents of the trace
|
||
|
){
|
||
|
///
|
||
|
// Tracing interface by group.
|
||
|
//
|
||
|
// Sends the contents of args to the console iff (req.trace.on && req.trace[group])
|
||
|
|
||
|
if(trace.on && trace.group[group]){
|
||
|
signal("trace", [group, args]);
|
||
|
for(var arg, dump = [], text= "trace:" + group + (args.length ? (":" + args[0]) : ""), i= 1; i<args.length;){
|
||
|
arg = args[i++];
|
||
|
if(isString(arg)){
|
||
|
text += ", " + arg;
|
||
|
}else{
|
||
|
dump.push(arg);
|
||
|
}
|
||
|
}
|
||
|
req.log(text);
|
||
|
dump.length && dump.push(".");
|
||
|
req.log.apply(req, dump);
|
||
|
}
|
||
|
};
|
||
|
mix(trace, {
|
||
|
on:1,
|
||
|
group:{},
|
||
|
set:function(group, value){
|
||
|
if(isString(group)){
|
||
|
trace.group[group]= value;
|
||
|
}else{
|
||
|
mix(trace.group, group);
|
||
|
}
|
||
|
}
|
||
|
});
|
||
|
trace.set(mix(mix(mix({}, defaultConfig.trace), userConfig.trace), dojoSniffConfig.trace));
|
||
|
on("config", function(config){
|
||
|
config.trace && trace.set(config.trace);
|
||
|
});
|
||
|
}else{
|
||
|
req.trace = noop;
|
||
|
}
|
||
|
if (!has("foreign-loader")) {
|
||
|
var def = function(
|
||
|
mid, //(commonjs.moduleId, optional)
|
||
|
dependencies, //(array of commonjs.moduleId, optional) list of modules to be loaded before running factory
|
||
|
factory //(any)
|
||
|
){
|
||
|
///
|
||
|
// Advises the loader of a module factory. //Implements http://wiki.commonjs.org/wiki/Modules/AsynchronousDefinition.
|
||
|
///
|
||
|
//note
|
||
|
// CommonJS factory scan courtesy of http://requirejs.org
|
||
|
|
||
|
var arity = arguments.length,
|
||
|
defaultDeps = ["require", "exports", "module"],
|
||
|
// the predominate signature...
|
||
|
args = [0, mid, dependencies];
|
||
|
if(arity==1){
|
||
|
args = [0, (isFunction(mid) ? defaultDeps : []), mid];
|
||
|
}else if(arity==2 && isString(mid)){
|
||
|
args = [mid, (isFunction(dependencies) ? defaultDeps : []), dependencies];
|
||
|
}else if(arity==3){
|
||
|
args = [mid, dependencies, factory];
|
||
|
}
|
||
|
|
||
|
if( 0 && args[1]===defaultDeps){
|
||
|
args[2].toString()
|
||
|
.replace(/(\/\*([\s\S]*?)\*\/|\/\/(.*)$)/mg, "")
|
||
|
.replace(/require\(["']([\w\!\-_\.\/]+)["']\)/g, function(match, dep){
|
||
|
args[1].push(dep);
|
||
|
});
|
||
|
}
|
||
|
|
||
|
req.trace("loader-define", args.slice(0, 2));
|
||
|
var targetModule = args[0] && getModule(args[0]),
|
||
|
module;
|
||
|
if(targetModule && !waiting[targetModule.mid]){
|
||
|
// given a mid that hasn't been requested; therefore, defined through means other than injecting
|
||
|
// consequent to a require() or define() application; examples include defining modules on-the-fly
|
||
|
// due to some code path or including a module in a script element. In any case,
|
||
|
// there is no callback waiting to finish processing and nothing to trigger the defQ and the
|
||
|
// dependencies are never requested; therefore, do it here.
|
||
|
injectDependencies(defineModule(targetModule, args[1], args[2]));
|
||
|
}else if(!has("ie-event-behavior") || ! 1 || injectingCachedModule){
|
||
|
// not IE path: anonymous module and therefore must have been injected; therefore, onLoad will fire immediately
|
||
|
// after script finishes being evaluated and the defQ can be run from that callback to detect the module id
|
||
|
defQ.push(args);
|
||
|
}else{
|
||
|
// IE path: possibly anonymous module and therefore injected; therefore, cannot depend on 1-to-1,
|
||
|
// in-order exec of onLoad with script eval (since it's IE) and must manually detect here
|
||
|
targetModule = targetModule || injectingModule;
|
||
|
if(!targetModule){
|
||
|
for(mid in waiting){
|
||
|
module = modules[mid];
|
||
|
if(module && module.node && module.node.readyState === 'interactive'){
|
||
|
targetModule = module;
|
||
|
break;
|
||
|
}
|
||
|
}
|
||
|
if( 0 && !targetModule){
|
||
|
for(var i = 0; i<combosPending.length; i++){
|
||
|
targetModule = combosPending[i];
|
||
|
if(targetModule.node && targetModule.node.readyState === 'interactive'){
|
||
|
break;
|
||
|
}
|
||
|
targetModule= 0;
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
if( 0 && isArray(targetModule)){
|
||
|
injectDependencies(defineModule(getModule(targetModule.shift()), args[1], args[2]));
|
||
|
if(!targetModule.length){
|
||
|
combosPending.splice(i, 1);
|
||
|
}
|
||
|
}else if(targetModule){
|
||
|
consumePendingCacheInsert(targetModule);
|
||
|
injectDependencies(defineModule(targetModule, args[1], args[2]));
|
||
|
}else{
|
||
|
signal(error, makeError("ieDefineFailed", args[0]));
|
||
|
}
|
||
|
checkComplete();
|
||
|
}
|
||
|
};
|
||
|
def.amd = {
|
||
|
vendor:"dojotoolkit.org"
|
||
|
};
|
||
|
|
||
|
if( 0 ){
|
||
|
req.def = def;
|
||
|
}
|
||
|
} else {
|
||
|
var def = noop;
|
||
|
}
|
||
|
// allow config to override default implementation of named functions; this is useful for
|
||
|
// non-browser environments, e.g., overriding injectUrl, getText, log, etc. in node.js, Rhino, etc.
|
||
|
// also useful for testing and monkey patching loader
|
||
|
mix(mix(req, defaultConfig.loaderPatch), userConfig.loaderPatch);
|
||
|
|
||
|
// now that req is fully initialized and won't change, we can hook it up to the error signal
|
||
|
on(error, function(arg){
|
||
|
try{
|
||
|
console.error(arg);
|
||
|
if(arg instanceof Error){
|
||
|
for(var p in arg){
|
||
|
console.log(p + ":", arg[p]);
|
||
|
}
|
||
|
console.log(".");
|
||
|
}
|
||
|
}catch(e){}
|
||
|
});
|
||
|
|
||
|
// always publish these
|
||
|
mix(req, {
|
||
|
uid:uid,
|
||
|
cache:cache,
|
||
|
packs:packs
|
||
|
});
|
||
|
|
||
|
|
||
|
if( 0 ){
|
||
|
mix(req, {
|
||
|
// these may be interesting to look at when debugging
|
||
|
paths:paths,
|
||
|
aliases:aliases,
|
||
|
modules:modules,
|
||
|
legacyMode:legacyMode,
|
||
|
execQ:execQ,
|
||
|
defQ:defQ,
|
||
|
waiting:waiting,
|
||
|
|
||
|
// these are used for testing
|
||
|
// TODO: move testing infrastructure to a different has feature
|
||
|
packs:packs,
|
||
|
mapProgs:mapProgs,
|
||
|
pathsMapProg:pathsMapProg,
|
||
|
listenerQueues:listenerQueues,
|
||
|
|
||
|
// these are used by the builder (at least)
|
||
|
computeMapProg:computeMapProg,
|
||
|
computeAliases:computeAliases,
|
||
|
runMapProg:runMapProg,
|
||
|
compactPath:compactPath,
|
||
|
getModuleInfo:getModuleInfo_
|
||
|
});
|
||
|
}
|
||
|
|
||
|
// the loader can be defined exactly once; look for global define which is the symbol AMD loaders are
|
||
|
// *required* to define (as opposed to require, which is optional)
|
||
|
if(global.define){
|
||
|
if( 1 ){
|
||
|
signal(error, makeError("defineAlreadyDefined", 0));
|
||
|
}
|
||
|
return;
|
||
|
}else{
|
||
|
global.define = def;
|
||
|
global.require = req;
|
||
|
if( 0 ){
|
||
|
require = req;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
if( 0 && req.combo && req.combo.plugins){
|
||
|
var plugins = req.combo.plugins,
|
||
|
pluginName;
|
||
|
for(pluginName in plugins){
|
||
|
mix(mix(getModule(pluginName), plugins[pluginName]), {isCombo:1, executed:"executed", load:1});
|
||
|
}
|
||
|
}
|
||
|
|
||
|
if( 1 && !has("foreign-loader")){
|
||
|
forEach(delayedModuleConfig, function(c){ config(c); });
|
||
|
var bootDeps = dojoSniffConfig.deps || userConfig.deps || defaultConfig.deps,
|
||
|
bootCallback = dojoSniffConfig.callback || userConfig.callback || defaultConfig.callback;
|
||
|
req.boot = (bootDeps || bootCallback) ? [bootDeps || [], bootCallback] : 0;
|
||
|
}
|
||
|
if(! 1 ){
|
||
|
!req.async && req(["dojo"]);
|
||
|
req.boot && req.apply(null, req.boot);
|
||
|
}
|
||
|
})
|
||
|
(function(global){ return global.dojoConfig || global.djConfig || global.require || {}; }, {
|
||
|
async:0,
|
||
|
hasCache:{
|
||
|
'config-selectorEngine':"acme",
|
||
|
'config-tlmSiblingOfDojo':1,
|
||
|
'dojo-built':1,
|
||
|
'dojo-loader':1,
|
||
|
dom:1,
|
||
|
'host-browser':1
|
||
|
},
|
||
|
packages:[
|
||
|
{
|
||
|
location:"../dijit",
|
||
|
name:"dijit"
|
||
|
},
|
||
|
{
|
||
|
location:"../dojox",
|
||
|
name:"dojox"
|
||
|
},
|
||
|
{
|
||
|
location:"../themes",
|
||
|
name:"themes"
|
||
|
},
|
||
|
{
|
||
|
location:".",
|
||
|
name:"dojo"
|
||
|
}
|
||
|
]
|
||
|
});require({cache:{
|
||
|
'dojo/loadInit':function(){
|
||
|
define(["./_base/loader"], function(loader){
|
||
|
return {
|
||
|
dynamic:0,
|
||
|
normalize:function(id){return id;},
|
||
|
load:loader.loadInit
|
||
|
};
|
||
|
});
|
||
|
|
||
|
},
|
||
|
'dojo/_base/loader':function(){
|
||
|
define(["./kernel", "../has", "require", "module", "../json", "./lang", "./array"], function(dojo, has, require, thisModule, json, lang, array) {
|
||
|
// module:
|
||
|
// dojo/_base/loader
|
||
|
|
||
|
// This module defines the v1.x synchronous loader API.
|
||
|
|
||
|
// signal the loader in sync mode...
|
||
|
//>>pure-amd
|
||
|
|
||
|
if (! 1 ){
|
||
|
console.error("cannot load the Dojo v1.x loader with a foreign loader");
|
||
|
return 0;
|
||
|
}
|
||
|
|
||
|
1 || has.add("dojo-fast-sync-require", 1);
|
||
|
|
||
|
|
||
|
var makeErrorToken = function(id){
|
||
|
return {src:thisModule.id, id:id};
|
||
|
},
|
||
|
|
||
|
slashName = function(name){
|
||
|
return name.replace(/\./g, "/");
|
||
|
},
|
||
|
|
||
|
buildDetectRe = /\/\/>>built/,
|
||
|
|
||
|
dojoRequireCallbacks = [],
|
||
|
dojoRequireModuleStack = [],
|
||
|
|
||
|
dojoRequirePlugin = function(mid, require, loaded){
|
||
|
dojoRequireCallbacks.push(loaded);
|
||
|
array.forEach(mid.split(","), function(mid){
|
||
|
var module = getModule(mid, require.module);
|
||
|
dojoRequireModuleStack.push(module);
|
||
|
injectModule(module);
|
||
|
});
|
||
|
checkDojoRequirePlugin();
|
||
|
},
|
||
|
|
||
|
checkDojoRequirePlugin = ( 1 ?
|
||
|
// This version of checkDojoRequirePlugin makes the observation that all dojoRequireCallbacks can be released
|
||
|
// when all *non-dojo/require!, dojo/loadInit!* modules are either executed, not requested, or arrived. This is
|
||
|
// the case since there are no more modules the loader is waiting for, therefore, dojo/require! must have
|
||
|
// everything it needs on board.
|
||
|
//
|
||
|
// The potential weakness of this algorithm is that dojo/require will not execute callbacks until *all* dependency
|
||
|
// trees are ready. It is possible that some trees may be ready earlier than others, and this extra wait is non-optimal.
|
||
|
// Still, for big projects, this seems better than the original algorithm below that proved slow in some cases.
|
||
|
// Note, however, the original algorithm had the potential to execute partial trees, but that potential was never enabled.
|
||
|
// There are also other optimization available with the original algorithm that have not been explored.
|
||
|
function(){
|
||
|
var module, mid;
|
||
|
for(mid in modules){
|
||
|
module = modules[mid];
|
||
|
if(module.noReqPluginCheck===undefined){
|
||
|
// tag the module as either a loadInit or require plugin or not for future reference
|
||
|
module.noReqPluginCheck = /loadInit\!/.test(mid) || /require\!/.test(mid) ? 1 : 0;
|
||
|
}
|
||
|
if(!module.executed && !module.noReqPluginCheck && module.injected==requested){
|
||
|
return;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
guardCheckComplete(function(){
|
||
|
var oldCallbacks = dojoRequireCallbacks;
|
||
|
dojoRequireCallbacks = [];
|
||
|
array.forEach(oldCallbacks, function(cb){cb(1);});
|
||
|
});
|
||
|
} : (function(){
|
||
|
// Note: this is the original checkDojoRequirePlugin that is much slower than the algorithm above. However, we know it
|
||
|
// works, so we leave it here in case the algorithm above fails in some corner case.
|
||
|
//
|
||
|
// checkDojoRequirePlugin inspects all of the modules demanded by a dojo/require!<module-list> dependency
|
||
|
// to see if they have arrived. The loader does not release *any* of these modules to be instantiated
|
||
|
// until *all* of these modules are on board, thereby preventing the evaluation of a module with dojo.require's
|
||
|
// that reference modules that are not available.
|
||
|
//
|
||
|
// The algorithm works by traversing the dependency graphs (remember, there can be cycles so they are not trees)
|
||
|
// of each module in the dojoRequireModuleStack array (which contains the list of modules demanded by dojo/require!).
|
||
|
// The moment a single module is discovered that is missing, the algorithm gives up and indicates that not all
|
||
|
// modules are on board. dojo/loadInit! and dojo/require! are ignored because there dependencies are inserted
|
||
|
// directly in dojoRequireModuleStack. For example, if "your/module" module depends on "dojo/require!my/module", then
|
||
|
// *both* "dojo/require!my/module" and "my/module" will be in dojoRequireModuleStack. Obviously, if "my/module"
|
||
|
// is on board, then "dojo/require!my/module" is also satisfied, so the algorithm doesn't check for "dojo/require!my/module".
|
||
|
//
|
||
|
// Note: inserting a dojo/require!<some-module-list> dependency in the dojoRequireModuleStack achieves nothing
|
||
|
// with the current algorithm; however, having such modules present makes it possible to optimize the algorithm
|
||
|
//
|
||
|
// Note: prior versions of this algorithm had an optimization that signaled loaded on dojo/require! dependencies
|
||
|
// individually (rather than waiting for them all to be resolved). The implementation proved problematic with cycles
|
||
|
// and plugins. However, it is possible to reattach that strategy in the future.
|
||
|
|
||
|
// a set from module-id to {undefined | 1 | 0}, where...
|
||
|
// undefined => the module has not been inspected
|
||
|
// 0 => the module or at least one of its dependencies has not arrived
|
||
|
// 1 => the module is a loadInit! or require! plugin resource, or is currently being traversed (therefore, assume
|
||
|
// OK until proven otherwise), or has been completely traversed and all dependencies have arrived
|
||
|
|
||
|
var touched,
|
||
|
traverse = function(m){
|
||
|
touched[m.mid] = 1;
|
||
|
for(var t, module, deps = m.deps || [], i= 0; i<deps.length; i++){
|
||
|
module = deps[i];
|
||
|
if(!(t = touched[module.mid])){
|
||
|
if(t===0 || !traverse(module)){
|
||
|
touched[m.mid] = 0;
|
||
|
return false;
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
return true;
|
||
|
};
|
||
|
|
||
|
return function(){
|
||
|
// initialize the touched hash with easy-to-compute values that help short circuit recursive algorithm;
|
||
|
// recall loadInit/require plugin modules are dependencies of modules in dojoRequireModuleStack...
|
||
|
// which would cause a circular dependency chain that would never be resolved if checked here
|
||
|
// notice all dependencies of any particular loadInit/require plugin module will already
|
||
|
// be checked since those are pushed into dojoRequireModuleStack explicitly by the
|
||
|
// plugin...so if a particular loadInitPlugin module's dependencies are not really
|
||
|
// on board, that *will* be detected elsewhere in the traversal.
|
||
|
var module, mid;
|
||
|
touched = {};
|
||
|
for(mid in modules){
|
||
|
module = modules[mid];
|
||
|
if(module.executed || module.noReqPluginCheck){
|
||
|
touched[mid] = 1;
|
||
|
}else{
|
||
|
if(module.noReqPluginCheck!==0){
|
||
|
// tag the module as either a loadInit or require plugin or not for future reference
|
||
|
module.noReqPluginCheck = /loadInit\!/.test(mid) || /require\!/.test(mid) ? 1 : 0;
|
||
|
}
|
||
|
if(module.noReqPluginCheck){
|
||
|
touched[mid] = 1;
|
||
|
}else if(module.injected!==arrived){
|
||
|
// not executed, has not arrived, and is not a loadInit or require plugin resource
|
||
|
touched[mid] = 0;
|
||
|
}// else, leave undefined and we'll traverse the dependencies
|
||
|
}
|
||
|
}
|
||
|
for(var t, i = 0, end = dojoRequireModuleStack.length; i<end; i++){
|
||
|
module = dojoRequireModuleStack[i];
|
||
|
if(!(t = touched[module.mid])){
|
||
|
if(t===0 || !traverse(module)){
|
||
|
return;
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
guardCheckComplete(function(){
|
||
|
var oldCallbacks = dojoRequireCallbacks;
|
||
|
dojoRequireCallbacks = [];
|
||
|
array.forEach(oldCallbacks, function(cb){cb(1);});
|
||
|
});
|
||
|
};
|
||
|
})()),
|
||
|
|
||
|
dojoLoadInitPlugin = function(mid, require, loaded){
|
||
|
// mid names a module that defines a "dojo load init" bundle, an object with two properties:
|
||
|
//
|
||
|
// * names: a vector of module ids that give top-level names to define in the lexical scope of def
|
||
|
// * def: a function that contains some some legacy loader API applications
|
||
|
//
|
||
|
// The point of def is to possibly cause some modules to be loaded (but not executed) by dojo/require! where the module
|
||
|
// ids are possibly-determined at runtime. For example, here is dojox.gfx from v1.6 expressed as an AMD module using the dojo/loadInit
|
||
|
// and dojo/require plugins.
|
||
|
//
|
||
|
// // dojox/gfx:
|
||
|
//
|
||
|
// define("*loadInit_12, {
|
||
|
// names:["dojo", "dijit", "dojox"],
|
||
|
// def: function(){
|
||
|
// dojo.loadInit(function(){
|
||
|
// var gfx = lang.getObject("dojox.gfx", true);
|
||
|
//
|
||
|
// //
|
||
|
// // code required to set gfx properties ommitted...
|
||
|
// //
|
||
|
//
|
||
|
// // now use the calculations to include the runtime-dependent module
|
||
|
// dojo.require("dojox.gfx." + gfx.renderer);
|
||
|
// });
|
||
|
// }
|
||
|
// });
|
||
|
//
|
||
|
// define(["dojo", "dojo/loadInit!" + id].concat("dojo/require!dojox/gfx/matric,dojox/gfx/_base"), function(dojo){
|
||
|
// // when this AMD factory function is executed, the following modules are guaranteed downloaded but not executed:
|
||
|
// // "dojox.gfx." + gfx.renderer
|
||
|
// // dojox.gfx.matrix
|
||
|
// // dojox.gfx._base
|
||
|
// dojo.provide("dojo.gfx");
|
||
|
// dojo.require("dojox.gfx.matrix");
|
||
|
// dojo.require("dojox.gfx._base");
|
||
|
// dojo.require("dojox.gfx." + gfx.renderer);
|
||
|
// return lang.getObject("dojo.gfx");
|
||
|
// });
|
||
|
// })();
|
||
|
//
|
||
|
// The idea is to run the legacy loader API with global variables shadowed, which allows these variables to
|
||
|
// be relocated. For example, dojox and dojo could be relocated to different names by giving a map and the code above will
|
||
|
// execute properly (because the plugin below resolves the load init bundle.names module with respect to the module that demanded
|
||
|
// the plugin resource).
|
||
|
//
|
||
|
// Note that the relocation is specified in the runtime configuration; relocated names need not be set at build-time.
|
||
|
//
|
||
|
// Warning: this is not the best way to express dojox.gfx as and AMD module. In fact, the module has been properly converted in
|
||
|
// v1.7. However, this technique allows the builder to convert legacy modules into AMD modules and guarantee the codepath is the
|
||
|
// same in the converted AMD module.
|
||
|
require([mid], function(bundle){
|
||
|
// notice how names is resolved with respect to the module that demanded the plugin resource
|
||
|
require(bundle.names, function(){
|
||
|
// bring the bundle names into scope
|
||
|
for(var scopeText = "", args= [], i = 0; i<arguments.length; i++){
|
||
|
scopeText+= "var " + bundle.names[i] + "= arguments[" + i + "]; ";
|
||
|
args.push(arguments[i]);
|
||
|
}
|
||
|
eval(scopeText);
|
||
|
|
||
|
var callingModule = require.module,
|
||
|
// the list of modules that need to be downloaded but not executed before the callingModule can be executed
|
||
|
requireList = [],
|
||
|
|
||
|
// the list of i18n bundles that are xdomain; undefined if none
|
||
|
i18nDeps,
|
||
|
|
||
|
syncLoaderApi = {
|
||
|
provide:function(moduleName){
|
||
|
// mark modules that arrive consequent to multiple provides in this module as arrived since they can't be injected
|
||
|
moduleName = slashName(moduleName);
|
||
|
var providedModule = getModule(moduleName, callingModule);
|
||
|
if(providedModule!==callingModule){
|
||
|
setArrived(providedModule);
|
||
|
}
|
||
|
},
|
||
|
require:function(moduleName, omitModuleCheck){
|
||
|
moduleName = slashName(moduleName);
|
||
|
omitModuleCheck && (getModule(moduleName, callingModule).result = nonmodule);
|
||
|
requireList.push(moduleName);
|
||
|
},
|
||
|
requireLocalization:function(moduleName, bundleName, locale){
|
||
|
// since we're going to need dojo/i8n, add it to i18nDeps if not already there
|
||
|
if(!i18nDeps){
|
||
|
// don't have to map since that will occur when the dependency is resolved
|
||
|
i18nDeps = ["dojo/i18n"];
|
||
|
}
|
||
|
|
||
|
// figure out if the bundle is xdomain; if so, add it to the i18nDepsSet
|
||
|
locale = (locale || dojo.locale).toLowerCase();
|
||
|
moduleName = slashName(moduleName) + "/nls/" + (/root/i.test(locale) ? "" : locale + "/") + slashName(bundleName);
|
||
|
if(getModule(moduleName, callingModule).isXd){
|
||
|
// don't have to map since that will occur when the dependency is resolved
|
||
|
i18nDeps.push("dojo/i18n!" + moduleName);
|
||
|
}// else the bundle will be loaded synchronously when the module is evaluated
|
||
|
},
|
||
|
loadInit:function(f){
|
||
|
f();
|
||
|
}
|
||
|
},
|
||
|
|
||
|
hold = {},
|
||
|
p;
|
||
|
|
||
|
// hijack the correct dojo and apply bundle.def
|
||
|
try{
|
||
|
for(p in syncLoaderApi){
|
||
|
hold[p] = dojo[p];
|
||
|
dojo[p] = syncLoaderApi[p];
|
||
|
}
|
||
|
bundle.def.apply(null, args);
|
||
|
}catch(e){
|
||
|
signal("error", [makeErrorToken("failedDojoLoadInit"), e]);
|
||
|
}finally{
|
||
|
for(p in syncLoaderApi){
|
||
|
dojo[p] = hold[p];
|
||
|
}
|
||
|
}
|
||
|
|
||
|
if(i18nDeps){
|
||
|
requireList = requireList.concat(i18nDeps);
|
||
|
}
|
||
|
|
||
|
if(requireList.length){
|
||
|
dojoRequirePlugin(requireList.join(","), require, loaded);
|
||
|
}else{
|
||
|
loaded();
|
||
|
}
|
||
|
});
|
||
|
});
|
||
|
},
|
||
|
|
||
|
extractApplication = function(
|
||
|
text, // the text to search
|
||
|
startSearch, // the position in text to start looking for the closing paren
|
||
|
startApplication // the position in text where the function application expression starts
|
||
|
){
|
||
|
// find end of the call by finding the matching end paren
|
||
|
// Warning: as usual, this will fail in the presence of unmatched right parans contained in strings, regexs, or unremoved comments
|
||
|
var parenRe = /\(|\)/g,
|
||
|
matchCount = 1,
|
||
|
match;
|
||
|
parenRe.lastIndex = startSearch;
|
||
|
while((match = parenRe.exec(text))){
|
||
|
if(match[0] == ")"){
|
||
|
matchCount -= 1;
|
||
|
}else{
|
||
|
matchCount += 1;
|
||
|
}
|
||
|
if(matchCount == 0){
|
||
|
break;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
if(matchCount != 0){
|
||
|
throw "unmatched paren around character " + parenRe.lastIndex + " in: " + text;
|
||
|
}
|
||
|
|
||
|
//Put the master matching string in the results.
|
||
|
return [dojo.trim(text.substring(startApplication, parenRe.lastIndex))+";\n", parenRe.lastIndex];
|
||
|
},
|
||
|
|
||
|
// The following regex matches all comments and strings, with the strings in the capturing group.
|
||
|
// Replacing all matches with "$1" will remove comments and keep strings.
|
||
|
//
|
||
|
// It accounts for single quotes, double quotes, backslashes (line continuations and escaped characters), and template strings.
|
||
|
removeCommentRe = /\/\/.*|\/\*[\s\S]*?\*\/|("(?:\\.|[^"])*"|'(?:\\.|[^'])*'|`(?:\\.|[^`])*`)/mg,
|
||
|
|
||
|
syncLoaderApiRe = /(^|\s)dojo\.(loadInit|require|provide|requireLocalization|requireIf|requireAfterIf|platformRequire)\s*\(/mg,
|
||
|
|
||
|
amdLoaderApiRe = /(^|\s)(require|define)\s*\(/m,
|
||
|
|
||
|
extractLegacyApiApplications = function(text, noCommentText){
|
||
|
// scan the noCommentText for any legacy loader API applications. Copy such applications into result (this is
|
||
|
// used by the builder). Move dojo.loadInit applications to loadInitApplications string. Copy all other applications
|
||
|
// to otherApplications string. If no applications were found, return 0, signalling an AMD module. Otherwise, return
|
||
|
// loadInitApplications + otherApplications. Fixup text by replacing
|
||
|
//
|
||
|
// dojo.loadInit(// etc...
|
||
|
//
|
||
|
// with
|
||
|
//
|
||
|
// \n 0 && dojo.loadInit(// etc...
|
||
|
//
|
||
|
// Which results in the dojo.loadInit from *not* being applied. This design goes a long way towards protecting the
|
||
|
// code from an over-agressive removeCommentRe. However...
|
||
|
//
|
||
|
// WARNING: the removeCommentRe will cause an error if a detected comment removes all or part of a legacy-loader application
|
||
|
// that is not in a comment.
|
||
|
|
||
|
var match, startSearch, startApplication, application,
|
||
|
loadInitApplications = [],
|
||
|
otherApplications = [],
|
||
|
allApplications = [];
|
||
|
|
||
|
// noCommentText may be provided by a build app with comments extracted by a better method than regex (hopefully)
|
||
|
noCommentText = noCommentText || text.replace(removeCommentRe, "$1");
|
||
|
|
||
|
// find and extract all dojo.loadInit applications
|
||
|
while((match = syncLoaderApiRe.exec(noCommentText))){
|
||
|
startSearch = syncLoaderApiRe.lastIndex;
|
||
|
startApplication = startSearch - match[0].length;
|
||
|
application = extractApplication(noCommentText, startSearch, startApplication);
|
||
|
if(match[2]=="loadInit"){
|
||
|
loadInitApplications.push(application[0]);
|
||
|
}else{
|
||
|
otherApplications.push(application[0]);
|
||
|
}
|
||
|
syncLoaderApiRe.lastIndex = application[1];
|
||
|
}
|
||
|
allApplications = loadInitApplications.concat(otherApplications);
|
||
|
if(allApplications.length || !amdLoaderApiRe.test(noCommentText)){
|
||
|
// either there were some legacy loader API applications or there were no AMD API applications
|
||
|
return [text.replace(/(^|\s)dojo\.loadInit\s*\(/g, "\n0 && dojo.loadInit("), allApplications.join(""), allApplications];
|
||
|
}else{
|
||
|
// legacy loader API *was not* detected and AMD API *was* detected; therefore, assume it's an AMD module
|
||
|
return 0;
|
||
|
}
|
||
|
},
|
||
|
|
||
|
transformToAmd = function(module, text){
|
||
|
// This is roughly the equivalent of dojo._xdCreateResource in 1.6-; however, it expresses a v1.6- dojo
|
||
|
// module in terms of AMD define instead of creating the dojo proprietary xdomain module expression.
|
||
|
// The module could have originated from several sources:
|
||
|
//
|
||
|
// * amd require() a module, e.g., require(["my/module"])
|
||
|
// * amd require() a nonmodule, e.g., require(["my/resource.js"')
|
||
|
// * amd define() deps vector (always a module)
|
||
|
// * dojo.require() a module, e.g. dojo.require("my.module")
|
||
|
// * dojo.require() a nonmodule, e.g., dojo.require("my.module", true)
|
||
|
// * dojo.requireIf/requireAfterIf/platformRequire a module
|
||
|
//
|
||
|
// The module is scanned for legacy loader API applications; if none are found, then assume the module is an
|
||
|
// AMD module and return 0. Otherwise, a synthetic dojo/loadInit plugin resource is created and the module text
|
||
|
// is rewritten as an AMD module with the single dependency of this synthetic resource. When the dojo/loadInit
|
||
|
// plugin loaded the synthetic resource, it will cause all dojo.loadInit's to be executed, find all dojo.require's
|
||
|
// (either directly consequent to dojo.require or indirectly consequent to dojo.require[After]If or
|
||
|
// dojo.platformRequire, and finally cause loading of all dojo.required modules with the dojo/require plugin. Thus,
|
||
|
// when the dojo/loadInit plugin reports it has been loaded, all modules required by the given module are guaranteed
|
||
|
// loaded (but not executed). This then allows the module to execute it's code path without interupts, thereby
|
||
|
// following the synchronous code path.
|
||
|
//
|
||
|
// Notice that this function behaves the same whether or not it happens to be in a mapped dojo/loader module.
|
||
|
|
||
|
var extractResult, id, names = [], namesAsStrings = [];
|
||
|
if(buildDetectRe.test(text) || !(extractResult = extractLegacyApiApplications(text))){
|
||
|
// buildDetectRe.test(text) => a built module, always AMD
|
||
|
// extractResult==0 => no sync API
|
||
|
return 0;
|
||
|
}
|
||
|
|
||
|
// manufacture a synthetic module id that can never be a real mdule id (just like require does)
|
||
|
id = module.mid + "-*loadInit";
|
||
|
|
||
|
// construct the dojo/loadInit names vector which causes any relocated names to be defined as lexical variables under their not-relocated name
|
||
|
// the dojo/loadInit plugin assumes the first name in names is "dojo"
|
||
|
|
||
|
for(var p in getModule("dojo", module).result.scopeMap){
|
||
|
names.push(p);
|
||
|
namesAsStrings.push('"' + p + '"');
|
||
|
}
|
||
|
|
||
|
// rewrite the module as a synthetic dojo/loadInit plugin resource + the module expressed as an AMD module that depends on this synthetic resource
|
||
|
// don't have to map dojo/init since that will occur when the dependency is resolved
|
||
|
return "// xdomain rewrite of " + module.mid + "\n" +
|
||
|
"define('" + id + "',{\n" +
|
||
|
"\tnames:" + json.stringify(names) + ",\n" +
|
||
|
"\tdef:function(" + names.join(",") + "){" + extractResult[1] + "}" +
|
||
|
"});\n\n" +
|
||
|
"define(" + json.stringify(names.concat(["dojo/loadInit!"+id])) + ", function(" + names.join(",") + "){\n" + extractResult[0] + "});";
|
||
|
},
|
||
|
|
||
|
loaderVars = require.initSyncLoader(dojoRequirePlugin, checkDojoRequirePlugin, transformToAmd),
|
||
|
|
||
|
sync =
|
||
|
loaderVars.sync,
|
||
|
|
||
|
requested =
|
||
|
loaderVars.requested,
|
||
|
|
||
|
arrived =
|
||
|
loaderVars.arrived,
|
||
|
|
||
|
nonmodule =
|
||
|
loaderVars.nonmodule,
|
||
|
|
||
|
executing =
|
||
|
loaderVars.executing,
|
||
|
|
||
|
executed =
|
||
|
loaderVars.executed,
|
||
|
|
||
|
syncExecStack =
|
||
|
loaderVars.syncExecStack,
|
||
|
|
||
|
modules =
|
||
|
loaderVars.modules,
|
||
|
|
||
|
execQ =
|
||
|
loaderVars.execQ,
|
||
|
|
||
|
getModule =
|
||
|
loaderVars.getModule,
|
||
|
|
||
|
injectModule =
|
||
|
loaderVars.injectModule,
|
||
|
|
||
|
setArrived =
|
||
|
loaderVars.setArrived,
|
||
|
|
||
|
signal =
|
||
|
loaderVars.signal,
|
||
|
|
||
|
finishExec =
|
||
|
loaderVars.finishExec,
|
||
|
|
||
|
execModule =
|
||
|
loaderVars.execModule,
|
||
|
|
||
|
getLegacyMode =
|
||
|
loaderVars.getLegacyMode,
|
||
|
|
||
|
guardCheckComplete =
|
||
|
loaderVars.guardCheckComplete;
|
||
|
|
||
|
// there is exactly one dojoRequirePlugin among possibly-many dojo/_base/loader's (owing to mapping)
|
||
|
dojoRequirePlugin = loaderVars.dojoRequirePlugin;
|
||
|
|
||
|
dojo.provide = function(mid){
|
||
|
var executingModule = syncExecStack[0],
|
||
|
module = lang.mixin(getModule(slashName(mid), require.module), {
|
||
|
executed:executing,
|
||
|
result:lang.getObject(mid, true)
|
||
|
});
|
||
|
setArrived(module);
|
||
|
if(executingModule){
|
||
|
(executingModule.provides || (executingModule.provides = [])).push(function(){
|
||
|
module.result = lang.getObject(mid);
|
||
|
delete module.provides;
|
||
|
module.executed!==executed && finishExec(module);
|
||
|
});
|
||
|
}// else dojo.provide called not consequent to loading; therefore, give up trying to publish module value to loader namespace
|
||
|
return module.result;
|
||
|
};
|
||
|
|
||
|
has.add("config-publishRequireResult", 1, 0, 0);
|
||
|
|
||
|
dojo.require = function(moduleName, 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
|
||
|
function doRequire(mid, omitModuleCheck){
|
||
|
var module = getModule(slashName(mid), require.module);
|
||
|
if(syncExecStack.length && syncExecStack[0].finish){
|
||
|
// switched to async loading in the middle of evaluating a legacy module; stop
|
||
|
// applying dojo.require so the remaining dojo.requires are applied in order
|
||
|
syncExecStack[0].finish.push(mid);
|
||
|
return undefined;
|
||
|
}
|
||
|
|
||
|
// recall module.executed has values {0, executing, executed}; therefore, truthy indicates executing or executed
|
||
|
if(module.executed){
|
||
|
return module.result;
|
||
|
}
|
||
|
omitModuleCheck && (module.result = nonmodule);
|
||
|
|
||
|
// rcg...why here and in two lines??
|
||
|
var currentMode = getLegacyMode();
|
||
|
|
||
|
// recall, in sync mode to inject is to *eval* the module text
|
||
|
// if the module is a legacy module, this is the same as executing
|
||
|
// but if the module is an AMD module, this means defining, not executing
|
||
|
injectModule(module);
|
||
|
// the inject may have changed the mode
|
||
|
currentMode = getLegacyMode();
|
||
|
|
||
|
// in sync mode to dojo.require is to execute
|
||
|
if(module.executed!==executed && module.injected===arrived){
|
||
|
// the module was already here before injectModule was called probably finishing up a xdomain
|
||
|
// load, but maybe a module given to the loader directly rather than having the loader retrieve it
|
||
|
|
||
|
loaderVars.guardCheckComplete(function(){
|
||
|
execModule(module);
|
||
|
});
|
||
|
}
|
||
|
if(module.executed){
|
||
|
return module.result;
|
||
|
}
|
||
|
|
||
|
if(currentMode==sync){
|
||
|
// the only way to get here is in sync mode and dojo.required a module that
|
||
|
// * was loaded async in the injectModule application a few lines up
|
||
|
// * was an AMD module that had deps that are being loaded async and therefore couldn't execute
|
||
|
if(module.cjs){
|
||
|
// the module was an AMD module; unshift, not push, which causes the current traversal to be reattempted from the top
|
||
|
execQ.unshift(module);
|
||
|
}else{
|
||
|
// the module was a legacy module
|
||
|
syncExecStack.length && (syncExecStack[0].finish= [mid]);
|
||
|
}
|
||
|
}else{
|
||
|
// the loader wasn't in sync mode on entry; probably async mode; therefore, no expectation of getting
|
||
|
// the module value synchronously; make sure it gets executed though
|
||
|
execQ.push(module);
|
||
|
}
|
||
|
|
||
|
return undefined;
|
||
|
}
|
||
|
|
||
|
var result = doRequire(moduleName, omitModuleCheck);
|
||
|
if(has("config-publishRequireResult") && !lang.exists(moduleName) && result!==undefined){
|
||
|
lang.setObject(moduleName, result);
|
||
|
}
|
||
|
return result;
|
||
|
};
|
||
|
|
||
|
dojo.loadInit = function(f) {
|
||
|
f();
|
||
|
};
|
||
|
|
||
|
dojo.registerModulePath = function(/*String*/moduleName, /*String*/prefix){
|
||
|
// summary:
|
||
|
// Maps a module name to a path
|
||
|
// description:
|
||
|
// An unregistered module is given the default path of ../[module],
|
||
|
// relative to Dojo root. For example, module acme is mapped to
|
||
|
// ../acme. If you want to use a different module name, use
|
||
|
// dojo.registerModulePath.
|
||
|
// example:
|
||
|
// If your dojo.js is located at this location in the web root:
|
||
|
// | /myapp/js/dojo/dojo/dojo.js
|
||
|
// and your modules are located at:
|
||
|
// | /myapp/js/foo/bar.js
|
||
|
// | /myapp/js/foo/baz.js
|
||
|
// | /myapp/js/foo/thud/xyzzy.js
|
||
|
// Your application can tell Dojo to locate the "foo" namespace by calling:
|
||
|
// | dojo.registerModulePath("foo", "../../foo");
|
||
|
// At which point you can then use dojo.require() to load the
|
||
|
// modules (assuming they provide() the same things which are
|
||
|
// required). The full code might be:
|
||
|
// | <script type="text/javascript"
|
||
|
// | src="/myapp/js/dojo/dojo/dojo.js"></script>
|
||
|
// | <script type="text/javascript">
|
||
|
// | dojo.registerModulePath("foo", "../../foo");
|
||
|
// | dojo.require("foo.bar");
|
||
|
// | dojo.require("foo.baz");
|
||
|
// | dojo.require("foo.thud.xyzzy");
|
||
|
// | </script>
|
||
|
|
||
|
var paths = {};
|
||
|
paths[moduleName.replace(/\./g, "/")] = prefix;
|
||
|
require({paths:paths});
|
||
|
};
|
||
|
|
||
|
dojo.platformRequire = function(/*Object*/modMap){
|
||
|
// summary:
|
||
|
// require one or more modules based on which host environment
|
||
|
// Dojo is currently operating in
|
||
|
// description:
|
||
|
// This method takes a "map" of arrays which one can use to
|
||
|
// optionally load dojo modules. The map is indexed by the
|
||
|
// possible dojo.name_ values, with two additional values:
|
||
|
// "default" and "common". The items in the "default" array will
|
||
|
// be loaded if none of the other items have been chosen based on
|
||
|
// dojo.name_, set by your host environment. The items in the
|
||
|
// "common" array will *always* be loaded, regardless of which
|
||
|
// list is chosen.
|
||
|
// example:
|
||
|
// | dojo.platformRequire({
|
||
|
// | browser: [
|
||
|
// | "foo.sample", // simple module
|
||
|
// | "foo.test",
|
||
|
// | ["foo.bar.baz", true] // skip object check in _loadModule (dojo.require)
|
||
|
// | ],
|
||
|
// | default: [ "foo.sample._base" ],
|
||
|
// | common: [ "important.module.common" ]
|
||
|
// | });
|
||
|
|
||
|
var result = (modMap.common || []).concat(modMap[dojo._name] || modMap["default"] || []),
|
||
|
temp;
|
||
|
while(result.length){
|
||
|
if(lang.isArray(temp = result.shift())){
|
||
|
dojo.require.apply(dojo, temp);
|
||
|
}else{
|
||
|
dojo.require(temp);
|
||
|
}
|
||
|
}
|
||
|
};
|
||
|
|
||
|
dojo.requireIf = dojo.requireAfterIf = function(/*Boolean*/ condition, /*String*/ moduleName, /*Boolean?*/omitModuleCheck){
|
||
|
// summary:
|
||
|
// If the condition is true then call `dojo.require()` for the specified
|
||
|
// resource
|
||
|
//
|
||
|
// example:
|
||
|
// | dojo.requireIf(dojo.isBrowser, "my.special.Module");
|
||
|
|
||
|
if(condition){
|
||
|
dojo.require(moduleName, omitModuleCheck);
|
||
|
}
|
||
|
};
|
||
|
|
||
|
dojo.requireLocalization = function(/*String*/moduleName, /*String*/bundleName, /*String?*/locale){
|
||
|
require(["../i18n"], function(i18n){
|
||
|
i18n.getLocalization(moduleName, bundleName, locale);
|
||
|
});
|
||
|
};
|
||
|
|
||
|
return {
|
||
|
// summary:
|
||
|
// This module defines the v1.x synchronous loader API.
|
||
|
|
||
|
extractLegacyApiApplications:extractLegacyApiApplications,
|
||
|
require:dojoRequirePlugin,
|
||
|
loadInit:dojoLoadInitPlugin
|
||
|
};
|
||
|
});
|
||
|
|
||
|
},
|
||
|
'dojo/_base/kernel':function(){
|
||
|
define(["../global", "../has", "./config", "require", "module"], function(global, has, config, require, module){
|
||
|
// module:
|
||
|
// dojo/_base/kernel
|
||
|
|
||
|
// This module is the foundational module of the dojo boot sequence; it defines the dojo object.
|
||
|
|
||
|
var
|
||
|
// loop variables for this module
|
||
|
i, p,
|
||
|
|
||
|
// create dojo, dijit, and dojox
|
||
|
// FIXME: in 2.0 remove dijit, dojox being created by dojo
|
||
|
dijit = {},
|
||
|
dojox = {},
|
||
|
dojo = {
|
||
|
// summary:
|
||
|
// This module is the foundational module of the dojo boot sequence; it defines the dojo object.
|
||
|
|
||
|
// notice dojo takes ownership of the value of the config module
|
||
|
config:config,
|
||
|
global:global,
|
||
|
dijit:dijit,
|
||
|
dojox:dojox
|
||
|
};
|
||
|
|
||
|
|
||
|
// Configure the scope map. For a 100% AMD application, the scope map is not needed other than to provide
|
||
|
// a _scopeName property for the dojo, dijit, and dojox root object so those packages can create
|
||
|
// unique names in the global space.
|
||
|
//
|
||
|
// Built, legacy modules use the scope map to allow those modules to be expressed as if dojo, dijit, and dojox,
|
||
|
// where global when in fact they are either global under different names or not global at all. In v1.6-, the
|
||
|
// config variable "scopeMap" was used to map names as used within a module to global names. This has been
|
||
|
// subsumed by the AMD map configuration variable which can relocate packages to different names. For backcompat,
|
||
|
// only the "*" mapping is supported. See http://livedocs.dojotoolkit.org/developer/design/loader#legacy-cross-domain-mode for details.
|
||
|
//
|
||
|
// The following computations contort the packageMap for this dojo instance into a scopeMap.
|
||
|
var scopeMap =
|
||
|
// a map from a name used in a legacy module to the (global variable name, object addressed by that name)
|
||
|
// always map dojo, dijit, and dojox
|
||
|
{
|
||
|
dojo:["dojo", dojo],
|
||
|
dijit:["dijit", dijit],
|
||
|
dojox:["dojox", dojox]
|
||
|
},
|
||
|
|
||
|
packageMap =
|
||
|
// the package map for this dojo instance; note, a foreign loader or no pacakgeMap results in the above default config
|
||
|
(require.map && require.map[module.id.match(/[^\/]+/)[0]]),
|
||
|
|
||
|
item;
|
||
|
|
||
|
|
||
|
// process all mapped top-level names for this instance of dojo
|
||
|
for(p in packageMap){
|
||
|
if(scopeMap[p]){
|
||
|
// mapped dojo, dijit, or dojox
|
||
|
scopeMap[p][0] = packageMap[p];
|
||
|
}else{
|
||
|
// some other top-level name
|
||
|
scopeMap[p] = [packageMap[p], {}];
|
||
|
}
|
||
|
}
|
||
|
|
||
|
// publish those names to _scopeName and, optionally, the global namespace
|
||
|
for(p in scopeMap){
|
||
|
item = scopeMap[p];
|
||
|
item[1]._scopeName = item[0];
|
||
|
if(!config.noGlobals){
|
||
|
global[item[0]] = item[1];
|
||
|
}
|
||
|
}
|
||
|
dojo.scopeMap = scopeMap;
|
||
|
|
||
|
/*===== dojo.__docParserConfigureScopeMap(scopeMap); =====*/
|
||
|
|
||
|
// FIXME: dojo.baseUrl and dojo.config.baseUrl should be deprecated
|
||
|
dojo.baseUrl = dojo.config.baseUrl = require.baseUrl;
|
||
|
dojo.isAsync = ! 1 || require.async;
|
||
|
dojo.locale = config.locale;
|
||
|
|
||
|
var rev = "$Rev:$".match(/[0-9a-f]{7,}/);
|
||
|
dojo.version = {
|
||
|
// summary:
|
||
|
// Version number of the Dojo Toolkit
|
||
|
// description:
|
||
|
// Hash about the version, including
|
||
|
//
|
||
|
// - major: Integer: Major version. If total version is "1.2.0beta1", will be 1
|
||
|
// - minor: Integer: Minor version. If total version is "1.2.0beta1", will be 2
|
||
|
// - patch: Integer: Patch version. If total version is "1.2.0beta1", will be 0
|
||
|
// - flag: String: Descriptor flag. If total version is "1.2.0beta1", will be "beta1"
|
||
|
// - revision: Number: The Git rev from which dojo was pulled
|
||
|
|
||
|
major: 1, minor: 17, patch: 3, flag: "",
|
||
|
revision: rev ? rev[0] : NaN,
|
||
|
toString: function(){
|
||
|
var v = dojo.version;
|
||
|
return v.major + "." + v.minor + "." + v.patch + v.flag + " (" + v.revision + ")"; // String
|
||
|
}
|
||
|
};
|
||
|
|
||
|
// If 1 is truthy, then as a dojo module is defined it should push it's definitions
|
||
|
// into the dojo object, and conversely. In 2.0, it will likely be unusual to augment another object
|
||
|
// as a result of defining a module. This has feature gives a way to force 2.0 behavior as the code
|
||
|
// is migrated. Absent specific advice otherwise, set extend-dojo to truthy.
|
||
|
1 || has.add("extend-dojo", 1);
|
||
|
|
||
|
if(!has("csp-restrictions")){
|
||
|
(Function("d", "d.eval = function(){return d.global.eval ? d.global.eval(arguments[0]) : eval(arguments[0]);}"))(dojo);
|
||
|
}
|
||
|
/*=====
|
||
|
dojo.eval = function(scriptText){
|
||
|
// summary:
|
||
|
// A legacy method created for use exclusively by internal Dojo methods. Do not use this method
|
||
|
// directly unless you understand its possibly-different implications on the platforms your are targeting.
|
||
|
// description:
|
||
|
// Makes an attempt to evaluate scriptText in the global scope. The function works correctly for browsers
|
||
|
// that support indirect eval.
|
||
|
//
|
||
|
// As usual, IE does not. On IE, the only way to implement global eval is to
|
||
|
// use execScript. Unfortunately, execScript does not return a value and breaks some current usages of dojo.eval.
|
||
|
// This implementation uses the technique of executing eval in the scope of a function that is a single scope
|
||
|
// frame below the global scope; thereby coming close to the global scope. Note carefully that
|
||
|
//
|
||
|
// dojo.eval("var pi = 3.14;");
|
||
|
//
|
||
|
// will define global pi in non-IE environments, but define pi only in a temporary local scope for IE. If you want
|
||
|
// to define a global variable using dojo.eval, write something like
|
||
|
//
|
||
|
// dojo.eval("window.pi = 3.14;")
|
||
|
// scriptText:
|
||
|
// The text to evaluation.
|
||
|
// returns:
|
||
|
// The result of the evaluation. Often `undefined`
|
||
|
};
|
||
|
=====*/
|
||
|
|
||
|
|
||
|
if( 0 ){
|
||
|
dojo.exit = function(exitcode){
|
||
|
quit(exitcode);
|
||
|
};
|
||
|
}else{
|
||
|
dojo.exit = function(){
|
||
|
};
|
||
|
}
|
||
|
|
||
|
if(!has("host-webworker")){
|
||
|
// console is immutable in FF30+, https://bugs.dojotoolkit.org/ticket/18100
|
||
|
1 || has.add("dojo-guarantee-console",
|
||
|
// ensure that console.log, console.warn, etc. are defined
|
||
|
1
|
||
|
);
|
||
|
}
|
||
|
|
||
|
if( 1 ){
|
||
|
// IE 9 bug: https://bugs.dojotoolkit.org/ticket/18197
|
||
|
has.add("console-as-object", function () {
|
||
|
return Function.prototype.bind && console && typeof console.log === "object";
|
||
|
});
|
||
|
|
||
|
typeof console != "undefined" || (console = {}); // intentional assignment
|
||
|
// Be careful to leave 'log' always at the end
|
||
|
var cn = [
|
||
|
"assert", "count", "debug", "dir", "dirxml", "error", "group",
|
||
|
"groupEnd", "info", "profile", "profileEnd", "time", "timeEnd",
|
||
|
"trace", "warn", "log"
|
||
|
];
|
||
|
var tn;
|
||
|
i = 0;
|
||
|
while((tn = cn[i++])){
|
||
|
if(!console[tn]){
|
||
|
(function(){
|
||
|
var tcn = tn + "";
|
||
|
console[tcn] = ('log' in console) ? function(){
|
||
|
var a = Array.prototype.slice.call(arguments);
|
||
|
a.unshift(tcn + ":");
|
||
|
console["log"](a.join(" "));
|
||
|
} : function(){};
|
||
|
console[tcn]._fake = true;
|
||
|
})();
|
||
|
}else if(has("console-as-object")){
|
||
|
console[tn] = Function.prototype.bind.call(console[tn], console);
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
|
||
|
has.add("dojo-debug-messages",
|
||
|
// include dojo.deprecated/dojo.experimental implementations
|
||
|
!!config.isDebug
|
||
|
);
|
||
|
dojo.deprecated = dojo.experimental = function(){};
|
||
|
if(has("dojo-debug-messages")){
|
||
|
dojo.deprecated = function(/*String*/ behaviour, /*String?*/ extra, /*String?*/ removal){
|
||
|
// summary:
|
||
|
// Log a debug message to indicate that a behavior has been
|
||
|
// deprecated.
|
||
|
// behaviour: String
|
||
|
// The API or behavior being deprecated. Usually in the form
|
||
|
// of "myApp.someFunction()".
|
||
|
// extra: String?
|
||
|
// Text to append to the message. Often provides advice on a
|
||
|
// new function or facility to achieve the same goal during
|
||
|
// the deprecation period.
|
||
|
// removal: String?
|
||
|
// Text to indicate when in the future the behavior will be
|
||
|
// removed. Usually a version number.
|
||
|
// example:
|
||
|
// | dojo.deprecated("myApp.getTemp()", "use myApp.getLocaleTemp() instead", "1.0");
|
||
|
|
||
|
var message = "DEPRECATED: " + behaviour;
|
||
|
if(extra){ message += " " + extra; }
|
||
|
if(removal){ message += " -- will be removed in version: " + removal; }
|
||
|
console.warn(message);
|
||
|
};
|
||
|
|
||
|
dojo.experimental = function(/* String */ moduleName, /* String? */ extra){
|
||
|
// summary:
|
||
|
// Marks code as experimental.
|
||
|
// description:
|
||
|
// This can be used to mark a function, file, or module as
|
||
|
// experimental. Experimental code is not ready to be used, and the
|
||
|
// APIs are subject to change without notice. Experimental code may be
|
||
|
// completed deleted without going through the normal deprecation
|
||
|
// process.
|
||
|
// moduleName: String
|
||
|
// The name of a module, or the name of a module file or a specific
|
||
|
// function
|
||
|
// extra: String?
|
||
|
// some additional message for the user
|
||
|
// example:
|
||
|
// | dojo.experimental("dojo.data.Result");
|
||
|
// example:
|
||
|
// | dojo.experimental("dojo.weather.toKelvin()", "PENDING approval from NOAA");
|
||
|
|
||
|
var message = "EXPERIMENTAL: " + moduleName + " -- APIs subject to change without notice.";
|
||
|
if(extra){ message += " " + extra; }
|
||
|
console.warn(message);
|
||
|
};
|
||
|
}
|
||
|
|
||
|
1 || has.add("dojo-modulePaths",
|
||
|
// consume dojo.modulePaths processing
|
||
|
1
|
||
|
);
|
||
|
if( 1 ){
|
||
|
// notice that modulePaths won't be applied to any require's before the dojo/_base/kernel factory is run;
|
||
|
// this is the v1.6- behavior.
|
||
|
if(config.modulePaths){
|
||
|
dojo.deprecated("dojo.modulePaths", "use paths configuration");
|
||
|
var paths = {};
|
||
|
for(p in config.modulePaths){
|
||
|
paths[p.replace(/\./g, "/")] = config.modulePaths[p];
|
||
|
}
|
||
|
require({paths:paths});
|
||
|
}
|
||
|
}
|
||
|
|
||
|
1 || has.add("dojo-moduleUrl",
|
||
|
// include dojo.moduleUrl
|
||
|
1
|
||
|
);
|
||
|
if( 1 ){
|
||
|
dojo.moduleUrl = function(/*String*/module, /*String?*/url){
|
||
|
// summary:
|
||
|
// Returns a URL relative to a module.
|
||
|
// example:
|
||
|
// | var pngPath = dojo.moduleUrl("acme","images/small.png");
|
||
|
// | console.dir(pngPath); // list the object properties
|
||
|
// | // create an image and set it's source to pngPath's value:
|
||
|
// | var img = document.createElement("img");
|
||
|
// | img.src = pngPath;
|
||
|
// | // add our image to the document
|
||
|
// | dojo.body().appendChild(img);
|
||
|
// example:
|
||
|
// you may de-reference as far as you like down the package
|
||
|
// hierarchy. This is sometimes handy to avoid lengthy relative
|
||
|
// urls or for building portable sub-packages. In this example,
|
||
|
// the `acme.widget` and `acme.util` directories may be located
|
||
|
// under different roots (see `dojo.registerModulePath`) but the
|
||
|
// the modules which reference them can be unaware of their
|
||
|
// relative locations on the filesystem:
|
||
|
// | // somewhere in a configuration block
|
||
|
// | dojo.registerModulePath("acme.widget", "../../acme/widget");
|
||
|
// | dojo.registerModulePath("acme.util", "../../util");
|
||
|
// |
|
||
|
// | // ...
|
||
|
// |
|
||
|
// | // code in a module using acme resources
|
||
|
// | var tmpltPath = dojo.moduleUrl("acme.widget","templates/template.html");
|
||
|
// | var dataPath = dojo.moduleUrl("acme.util","resources/data.json");
|
||
|
|
||
|
dojo.deprecated("dojo.moduleUrl()", "use require.toUrl", "2.0");
|
||
|
|
||
|
// require.toUrl requires a filetype; therefore, just append the suffix "/*.*" to guarantee a filetype, then
|
||
|
// remove the suffix from the result. This way clients can request a url w/out a filetype. This should be
|
||
|
// rare, but it maintains backcompat for the v1.x line (note: dojo.moduleUrl will be removed in v2.0).
|
||
|
// Notice * is an illegal filename so it won't conflict with any real path map that may exist the paths config.
|
||
|
var result = null;
|
||
|
if(module){
|
||
|
result = require.toUrl(module.replace(/\./g, "/") + (url ? ("/" + url) : "") + "/*.*").replace(/\/\*\.\*/, "") + (url ? "" : "/");
|
||
|
}
|
||
|
return result;
|
||
|
};
|
||
|
}
|
||
|
|
||
|
dojo._hasResource = {}; // for backward compatibility with layers built with 1.6 tooling
|
||
|
|
||
|
return dojo;
|
||
|
});
|
||
|
|
||
|
},
|
||
|
'dojo/global':function(){
|
||
|
define(function(){
|
||
|
if (typeof global !== 'undefined' && typeof global !== 'function') {
|
||
|
// global spec defines a reference to the global object called 'global'
|
||
|
// https://github.com/tc39/proposal-global
|
||
|
// `global` is also defined in NodeJS
|
||
|
return global;
|
||
|
}
|
||
|
else if (typeof window !== 'undefined') {
|
||
|
// window is defined in browsers
|
||
|
return window;
|
||
|
}
|
||
|
else if (typeof self !== 'undefined') {
|
||
|
// self is defined in WebWorkers
|
||
|
return self;
|
||
|
}
|
||
|
return this;
|
||
|
});
|
||
|
|
||
|
},
|
||
|
'dojo/has':function(){
|
||
|
define(["./global", "require", "module"], function(global, require, module){
|
||
|
// module:
|
||
|
// dojo/has
|
||
|
// summary:
|
||
|
// Defines the has.js API and several feature tests used by dojo.
|
||
|
// description:
|
||
|
// This module defines the has API as described by the project has.js with the following additional features:
|
||
|
//
|
||
|
// - the has test cache is exposed at has.cache.
|
||
|
// - the method has.add includes a forth parameter that controls whether or not existing tests are replaced
|
||
|
// - the loader's has cache may be optionally copied into this module's has cahce.
|
||
|
//
|
||
|
// This module adopted from https://github.com/phiggins42/has.js; thanks has.js team!
|
||
|
|
||
|
// try to pull the has implementation from the loader; both the dojo loader and bdLoad provide one
|
||
|
// if using a foreign loader, then the has cache may be initialized via the config object for this module
|
||
|
// WARNING: if a foreign loader defines require.has to be something other than the has.js API, then this implementation fail
|
||
|
var has = require.has || function(){};
|
||
|
if(! 1 ){
|
||
|
var
|
||
|
isBrowser =
|
||
|
// the most fundamental decision: are we in the browser?
|
||
|
typeof window != "undefined" &&
|
||
|
typeof location != "undefined" &&
|
||
|
typeof document != "undefined" &&
|
||
|
window.location == location && window.document == document,
|
||
|
|
||
|
// has API variables
|
||
|
doc = isBrowser && document,
|
||
|
element = doc && doc.createElement("DiV"),
|
||
|
cache = (module.config && module.config()) || {};
|
||
|
|
||
|
has = function(name){
|
||
|
// summary:
|
||
|
// Return the current value of the named feature.
|
||
|
//
|
||
|
// name: String|Integer
|
||
|
// The name (if a string) or identifier (if an integer) of the feature to test.
|
||
|
//
|
||
|
// description:
|
||
|
// Returns the value of the feature named by name. The feature must have been
|
||
|
// previously added to the cache by has.add.
|
||
|
|
||
|
return typeof cache[name] == "function" ? (cache[name] = cache[name](global, doc, element)) : cache[name]; // Boolean
|
||
|
};
|
||
|
|
||
|
has.cache = cache;
|
||
|
|
||
|
has.add = function(name, test, now, force){
|
||
|
// summary:
|
||
|
// Register a new feature test for some named feature.
|
||
|
// name: String|Integer
|
||
|
// The name (if a string) or identifier (if an integer) of the feature to test.
|
||
|
// test: Function
|
||
|
// A test function to register. If a function, queued for testing until actually
|
||
|
// needed. The test function should return a boolean indicating
|
||
|
// the presence of a feature or bug.
|
||
|
// now: Boolean?
|
||
|
// Optional. Omit if `test` is not a function. Provides a way to immediately
|
||
|
// run the test and cache the result.
|
||
|
// force: Boolean?
|
||
|
// Optional. If the test already exists and force is truthy, then the existing
|
||
|
// test will be replaced; otherwise, add does not replace an existing test (that
|
||
|
// is, by default, the first test advice wins).
|
||
|
// example:
|
||
|
// A redundant test, testFn with immediate execution:
|
||
|
// | has.add("javascript", function(){ return true; }, true);
|
||
|
//
|
||
|
// example:
|
||
|
// Again with the redundantness. You can do this in your tests, but we should
|
||
|
// not be doing this in any internal has.js tests
|
||
|
// | has.add("javascript", true);
|
||
|
//
|
||
|
// example:
|
||
|
// Three things are passed to the testFunction. `global`, `document`, and a generic element
|
||
|
// from which to work your test should the need arise.
|
||
|
// | has.add("bug-byid", function(g, d, el){
|
||
|
// | // g == global, typically window, yadda yadda
|
||
|
// | // d == document object
|
||
|
// | // el == the generic element. a `has` element.
|
||
|
// | return false; // fake test, byid-when-form-has-name-matching-an-id is slightly longer
|
||
|
// | });
|
||
|
|
||
|
(typeof cache[name]=="undefined" || force) && (cache[name]= test);
|
||
|
return now && has(name);
|
||
|
};
|
||
|
|
||
|
// since we're operating under a loader that doesn't provide a has API, we must explicitly initialize
|
||
|
// has as it would have otherwise been initialized by the dojo loader; use has.add to the builder
|
||
|
// can optimize these away iff desired
|
||
|
1 || has.add("host-browser", isBrowser);
|
||
|
0 && has.add("host-node", (typeof process == "object" && process.versions && process.versions.node && process.versions.v8));
|
||
|
0 && has.add("host-rhino", (typeof load == "function" && (typeof Packages == "function" || typeof Packages == "object")));
|
||
|
1 || has.add("dom", isBrowser);
|
||
|
1 || has.add("dojo-dom-ready-api", 1);
|
||
|
1 || has.add("dojo-sniff", 1);
|
||
|
}
|
||
|
|
||
|
if( 1 ){
|
||
|
// Common application level tests
|
||
|
has.add("dom-addeventlistener", !!document.addEventListener);
|
||
|
|
||
|
// Do the device and browser have touch capability?
|
||
|
has.add("touch", "ontouchstart" in document
|
||
|
|| ("onpointerdown" in document && navigator.maxTouchPoints > 0)
|
||
|
|| window.navigator.msMaxTouchPoints);
|
||
|
|
||
|
// Touch events support
|
||
|
has.add("touch-events", "ontouchstart" in document);
|
||
|
|
||
|
// Test if pointer events are supported and enabled, with either standard names ("pointerdown" etc.) or
|
||
|
// IE specific names ("MSPointerDown" etc.). Tests are designed to work on embedded C# WebBrowser Controls
|
||
|
// in addition to IE, Edge, and future versions of Firefox and Chrome.
|
||
|
// Note that on IE11, has("pointer-events") and has("MSPointer") are both true.
|
||
|
has.add("pointer-events", "pointerEnabled" in window.navigator ?
|
||
|
window.navigator.pointerEnabled : "PointerEvent" in window);
|
||
|
has.add("MSPointer", window.navigator.msPointerEnabled);
|
||
|
// The "pointermove"" event is only continuously emitted in a touch environment if
|
||
|
// the target node's "touch-action"" CSS property is set to "none"
|
||
|
// https://www.w3.org/TR/pointerevents/#the-touch-action-css-property
|
||
|
has.add("touch-action", has("touch") && has("pointer-events"));
|
||
|
|
||
|
// I don't know if any of these tests are really correct, just a rough guess
|
||
|
has.add("device-width", screen.availWidth || innerWidth);
|
||
|
|
||
|
// Tests for DOMNode.attributes[] behavior:
|
||
|
// - dom-attributes-explicit - attributes[] only lists explicitly user specified attributes
|
||
|
// - dom-attributes-specified-flag (IE8) - need to check attr.specified flag to skip attributes user didn't specify
|
||
|
// - Otherwise, in IE6-7. attributes[] will list hundreds of values, so need to do outerHTML to get attrs instead.
|
||
|
var form = document.createElement("form");
|
||
|
has.add("dom-attributes-explicit", form.attributes.length == 0); // W3C
|
||
|
has.add("dom-attributes-specified-flag", form.attributes.length > 0 && form.attributes.length < 40); // IE8
|
||
|
}
|
||
|
|
||
|
has.clearElement = function(element){
|
||
|
// summary:
|
||
|
// Deletes the contents of the element passed to test functions.
|
||
|
element.innerHTML= "";
|
||
|
return element;
|
||
|
};
|
||
|
|
||
|
has.normalize = function(id, toAbsMid){
|
||
|
// summary:
|
||
|
// Resolves id into a module id based on possibly-nested tenary expression that branches on has feature test value(s).
|
||
|
//
|
||
|
// toAbsMid: Function
|
||
|
// Resolves a relative module id into an absolute module id
|
||
|
var
|
||
|
tokens = id.match(/[\?:]|[^:\?]*/g), i = 0,
|
||
|
get = function(skip){
|
||
|
var term = tokens[i++];
|
||
|
if(term == ":"){
|
||
|
// empty string module name, resolves to 0
|
||
|
return 0;
|
||
|
}else{
|
||
|
// postfixed with a ? means it is a feature to branch on, the term is the name of the feature
|
||
|
if(tokens[i++] == "?"){
|
||
|
if(!skip && has(term)){
|
||
|
// matched the feature, get the first value from the options
|
||
|
return get();
|
||
|
}else{
|
||
|
// did not match, get the second value, passing over the first
|
||
|
get(true);
|
||
|
return get(skip);
|
||
|
}
|
||
|
}
|
||
|
// a module
|
||
|
return term || 0;
|
||
|
}
|
||
|
};
|
||
|
id = get();
|
||
|
return id && toAbsMid(id);
|
||
|
};
|
||
|
|
||
|
has.load = function(id, parentRequire, loaded){
|
||
|
// summary:
|
||
|
// Conditional loading of AMD modules based on a has feature test value.
|
||
|
// id: String
|
||
|
// Gives the resolved module id to load.
|
||
|
// parentRequire: Function
|
||
|
// The loader require function with respect to the module that contained the plugin resource in it's
|
||
|
// dependency list.
|
||
|
// loaded: Function
|
||
|
// Callback to loader that consumes result of plugin demand.
|
||
|
|
||
|
if(id){
|
||
|
parentRequire([id], loaded);
|
||
|
}else{
|
||
|
loaded();
|
||
|
}
|
||
|
};
|
||
|
|
||
|
return has;
|
||
|
});
|
||
|
|
||
|
},
|
||
|
'dojo/_base/config':function(){
|
||
|
define(["../global", "../has", "require"], function(global, has, require){
|
||
|
// module:
|
||
|
// dojo/_base/config
|
||
|
|
||
|
/*=====
|
||
|
return {
|
||
|
// summary:
|
||
|
// This module defines the user configuration during bootstrap.
|
||
|
// description:
|
||
|
// By defining user configuration as a module value, an entire configuration can be specified in a build,
|
||
|
// thereby eliminating the need for sniffing and or explicitly setting in the global variable dojoConfig.
|
||
|
// Also, when multiple instances of dojo exist in a single application, each will necessarily be located
|
||
|
// at an unique absolute module identifier as given by the package configuration. Implementing configuration
|
||
|
// as a module allows for specifying unique, per-instance configurations.
|
||
|
// example:
|
||
|
// Create a second instance of dojo with a different, instance-unique configuration (assume the loader and
|
||
|
// dojo.js are already loaded).
|
||
|
// | // specify a configuration that creates a new instance of dojo at the absolute module identifier "myDojo"
|
||
|
// | require({
|
||
|
// | packages:[{
|
||
|
// | name:"myDojo",
|
||
|
// | location:".", //assume baseUrl points to dojo.js
|
||
|
// | }]
|
||
|
// | });
|
||
|
// |
|
||
|
// | // specify a configuration for the myDojo instance
|
||
|
// | define("myDojo/config", {
|
||
|
// | // normal configuration variables go here, e.g.,
|
||
|
// | locale:"fr-ca"
|
||
|
// | });
|
||
|
// |
|
||
|
// | // load and use the new instance of dojo
|
||
|
// | require(["myDojo"], function(dojo){
|
||
|
// | // dojo is the new instance of dojo
|
||
|
// | // use as required
|
||
|
// | });
|
||
|
|
||
|
// isDebug: Boolean
|
||
|
// Defaults to `false`. If set to `true`, ensures that Dojo provides
|
||
|
// extended debugging feedback to the console.
|
||
|
isDebug: false,
|
||
|
|
||
|
// locale: String
|
||
|
// The locale to assume for loading localized resources in this page,
|
||
|
// specified according to [RFC 3066](http://www.ietf.org/rfc/rfc3066.txt).
|
||
|
// Must be specified entirely in lowercase, e.g. `en-us` and `zh-cn`.
|
||
|
// See the documentation for `dojo.i18n` and `dojo.requireLocalization`
|
||
|
// for details on loading localized resources. If no locale is specified,
|
||
|
// Dojo assumes the locale of the user agent, according to `navigator.userLanguage`
|
||
|
// or `navigator.language` properties.
|
||
|
locale: undefined,
|
||
|
|
||
|
// extraLocale: Array
|
||
|
// No default value. Specifies additional locales whose
|
||
|
// resources should also be loaded alongside the default locale when
|
||
|
// calls to `dojo.requireLocalization()` are processed.
|
||
|
extraLocale: undefined,
|
||
|
|
||
|
// baseUrl: String
|
||
|
// The directory in which `dojo.js` is located. Under normal
|
||
|
// conditions, Dojo auto-detects the correct location from which it
|
||
|
// was loaded. You may need to manually configure `baseUrl` in cases
|
||
|
// where you have renamed `dojo.js` or in which `<base>` tags confuse
|
||
|
// some browsers (e.g. IE 6). The variable `dojo.baseUrl` is assigned
|
||
|
// either the value of `djConfig.baseUrl` if one is provided or the
|
||
|
// auto-detected root if not. Other modules are located relative to
|
||
|
// this path. The path should end in a slash.
|
||
|
baseUrl: undefined,
|
||
|
|
||
|
// modulePaths: [deprecated] Object
|
||
|
// A map of module names to paths relative to `dojo.baseUrl`. The
|
||
|
// key/value pairs correspond directly to the arguments which
|
||
|
// `dojo.registerModulePath` accepts. Specifying
|
||
|
// `djConfig.modulePaths = { "foo": "../../bar" }` is the equivalent
|
||
|
// of calling `dojo.registerModulePath("foo", "../../bar");`. Multiple
|
||
|
// modules may be configured via `djConfig.modulePaths`.
|
||
|
modulePaths: {},
|
||
|
|
||
|
// addOnLoad: Function|Array
|
||
|
// Adds a callback via dojo/ready. Useful when Dojo is added after
|
||
|
// the page loads and djConfig.afterOnLoad is true. Supports the same
|
||
|
// arguments as dojo/ready. When using a function reference, use
|
||
|
// `djConfig.addOnLoad = function(){};`. For object with function name use
|
||
|
// `djConfig.addOnLoad = [myObject, "functionName"];` and for object with
|
||
|
// function reference use
|
||
|
// `djConfig.addOnLoad = [myObject, function(){}];`
|
||
|
addOnLoad: null,
|
||
|
|
||
|
// parseOnLoad: Boolean
|
||
|
// Run the parser after the page is loaded
|
||
|
parseOnLoad: false,
|
||
|
|
||
|
// require: String[]
|
||
|
// An array of module names to be loaded immediately after dojo.js has been included
|
||
|
// in a page.
|
||
|
require: [],
|
||
|
|
||
|
// defaultDuration: Number
|
||
|
// Default duration, in milliseconds, for wipe and fade animations within dijits.
|
||
|
// Assigned to dijit.defaultDuration.
|
||
|
defaultDuration: 200,
|
||
|
|
||
|
// dojoBlankHtmlUrl: String
|
||
|
// Used by some modules to configure an empty iframe. Used by dojo/io/iframe and
|
||
|
// dojo/back, and dijit/popup support in IE where an iframe is needed to make sure native
|
||
|
// controls do not bleed through the popups. Normally this configuration variable
|
||
|
// does not need to be set, except when using cross-domain/CDN Dojo builds.
|
||
|
// Save dojo/resources/blank.html to your domain and set `djConfig.dojoBlankHtmlUrl`
|
||
|
// to the path on your domain your copy of blank.html.
|
||
|
dojoBlankHtmlUrl: undefined,
|
||
|
|
||
|
// ioPublish: Boolean?
|
||
|
// Set this to true to enable publishing of topics for the different phases of
|
||
|
// IO operations. Publishing is done via dojo/topic.publish(). See dojo/main.__IoPublish for a list
|
||
|
// of topics that are published.
|
||
|
ioPublish: false,
|
||
|
|
||
|
// transparentColor: Array
|
||
|
// Array containing the r, g, b components used as transparent color in dojo.Color;
|
||
|
// if undefined, [255,255,255] (white) will be used.
|
||
|
transparentColor: undefined,
|
||
|
|
||
|
// deps: Function|Array
|
||
|
// Defines dependencies to be used before the loader has been loaded.
|
||
|
// When provided, they cause the loader to execute require(deps, callback)
|
||
|
// once it has finished loading. Should be used with callback.
|
||
|
deps: undefined,
|
||
|
|
||
|
// callback: Function|Array
|
||
|
// Defines a callback to be used when dependencies are defined before
|
||
|
// the loader has been loaded. When provided, they cause the loader to
|
||
|
// execute require(deps, callback) once it has finished loading.
|
||
|
// Should be used with deps.
|
||
|
callback: undefined,
|
||
|
|
||
|
// deferredInstrumentation: Boolean
|
||
|
// Whether deferred instrumentation should be loaded or included
|
||
|
// in builds.
|
||
|
deferredInstrumentation: true,
|
||
|
|
||
|
// useDeferredInstrumentation: Boolean|String
|
||
|
// Whether the deferred instrumentation should be used.
|
||
|
//
|
||
|
// * `"report-rejections"`: report each rejection as it occurs.
|
||
|
// * `true` or `1` or `"report-unhandled-rejections"`: wait 1 second
|
||
|
// in an attempt to detect unhandled rejections.
|
||
|
useDeferredInstrumentation: "report-unhandled-rejections"
|
||
|
};
|
||
|
=====*/
|
||
|
|
||
|
var result = {};
|
||
|
if( 1 ){
|
||
|
// must be the dojo loader; take a shallow copy of require.rawConfig
|
||
|
var src = require.rawConfig, p;
|
||
|
for(p in src){
|
||
|
result[p] = src[p];
|
||
|
}
|
||
|
}else{
|
||
|
var adviseHas = function(featureSet, prefix, booting){
|
||
|
for(p in featureSet){
|
||
|
p!="has" && has.add(prefix + p, featureSet[p], 0, booting);
|
||
|
}
|
||
|
};
|
||
|
result = 1 ?
|
||
|
// must be a built version of the dojo loader; all config stuffed in require.rawConfig
|
||
|
require.rawConfig :
|
||
|
// a foreign loader
|
||
|
global.dojoConfig || global.djConfig || {};
|
||
|
adviseHas(result, "config", 1);
|
||
|
adviseHas(result.has, "", 1);
|
||
|
}
|
||
|
|
||
|
if(!result.locale && typeof navigator != "undefined"){
|
||
|
// Default locale for browsers (ensure it's read from user-settings not download locale).
|
||
|
var language = (navigator.languages && navigator.languages.length) ? navigator.languages[0] :
|
||
|
(navigator.language || navigator.userLanguage);
|
||
|
if(language){
|
||
|
result.locale = language.toLowerCase();
|
||
|
}
|
||
|
}
|
||
|
|
||
|
return result;
|
||
|
});
|
||
|
|
||
|
|
||
|
},
|
||
|
'dojo/json':function(){
|
||
|
define(["./has"], function(has){
|
||
|
"use strict";
|
||
|
var hasJSON = typeof JSON != "undefined";
|
||
|
has.add("json-parse", hasJSON); // all the parsers work fine
|
||
|
// Firefox 3.5/Gecko 1.9 fails to use replacer in stringify properly https://bugzilla.mozilla.org/show_bug.cgi?id=509184
|
||
|
has.add("json-stringify", hasJSON && JSON.stringify({a:0}, function(k,v){return v||1;}) == '{"a":1}');
|
||
|
|
||
|
/*=====
|
||
|
return {
|
||
|
// summary:
|
||
|
// Functions to parse and serialize JSON
|
||
|
|
||
|
parse: function(str, strict){
|
||
|
// summary:
|
||
|
// Parses a [JSON](http://json.org) string to return a JavaScript object.
|
||
|
// description:
|
||
|
// This function follows [native JSON API](https://developer.mozilla.org/en/JSON)
|
||
|
// Throws for invalid JSON strings. This delegates to eval() if native JSON
|
||
|
// support is not available. By default this will evaluate any valid JS expression.
|
||
|
// With the strict parameter set to true, the parser will ensure that only
|
||
|
// valid JSON strings are parsed (otherwise throwing an error). Without the strict
|
||
|
// parameter, the content passed to this method must come
|
||
|
// from a trusted source.
|
||
|
// str:
|
||
|
// a string literal of a JSON item, for instance:
|
||
|
// `'{ "foo": [ "bar", 1, { "baz": "thud" } ] }'`
|
||
|
// strict:
|
||
|
// When set to true, this will ensure that only valid, secure JSON is ever parsed.
|
||
|
// Make sure this is set to true for untrusted content. Note that on browsers/engines
|
||
|
// without native JSON support, setting this to true will run slower.
|
||
|
},
|
||
|
stringify: function(value, replacer, spacer){
|
||
|
// summary:
|
||
|
// Returns a [JSON](http://json.org) serialization of an object.
|
||
|
// description:
|
||
|
// Returns a [JSON](http://json.org) serialization of an object.
|
||
|
// This function follows [native JSON API](https://developer.mozilla.org/en/JSON)
|
||
|
// Note that this doesn't check for infinite recursion, so don't do that!
|
||
|
// value:
|
||
|
// A value to be serialized.
|
||
|
// replacer:
|
||
|
// A replacer function that is called for each value and can return a replacement
|
||
|
// spacer:
|
||
|
// A spacer string to be used for pretty printing of JSON
|
||
|
// example:
|
||
|
// simple serialization of a trivial object
|
||
|
// | define(["dojo/json"], function(JSON){
|
||
|
// | var jsonStr = JSON.stringify({ howdy: "stranger!", isStrange: true });
|
||
|
// | doh.is('{"howdy":"stranger!","isStrange":true}', jsonStr);
|
||
|
}
|
||
|
};
|
||
|
=====*/
|
||
|
|
||
|
if(has("json-stringify")){
|
||
|
return JSON;
|
||
|
}else{
|
||
|
var escapeString = function(/*String*/str){
|
||
|
// summary:
|
||
|
// Adds escape sequences for non-visual characters, double quote and
|
||
|
// backslash and surrounds with double quotes to form a valid string
|
||
|
// literal.
|
||
|
return ('"' + str.replace(/(["\\])/g, '\\$1') + '"').
|
||
|
replace(/[\f]/g, "\\f").replace(/[\b]/g, "\\b").replace(/[\n]/g, "\\n").
|
||
|
replace(/[\t]/g, "\\t").replace(/[\r]/g, "\\r"); // string
|
||
|
};
|
||
|
return {
|
||
|
parse: has("json-parse") ? JSON.parse : function(str, strict){
|
||
|
if(strict && !/^([\s\[\{]*(?:"(?:\\.|[^"])*"|-?\d[\d\.]*(?:[Ee][+-]?\d+)?|null|true|false|)[\s\]\}]*(?:,|:|$))+$/.test(str)){
|
||
|
throw new SyntaxError("Invalid characters in JSON");
|
||
|
}
|
||
|
return eval('(' + str + ')');
|
||
|
},
|
||
|
stringify: function(value, replacer, spacer){
|
||
|
var undef;
|
||
|
if(typeof replacer == "string"){
|
||
|
spacer = replacer;
|
||
|
replacer = null;
|
||
|
}
|
||
|
function stringify(it, indent, key){
|
||
|
if(replacer){
|
||
|
it = replacer(key, it);
|
||
|
}
|
||
|
var val, objtype = typeof it;
|
||
|
if(objtype == "number"){
|
||
|
return isFinite(it) ? it + "" : "null";
|
||
|
}
|
||
|
if(objtype == "boolean"){
|
||
|
return it + "";
|
||
|
}
|
||
|
if(it === null){
|
||
|
return "null";
|
||
|
}
|
||
|
if(typeof it == "string"){
|
||
|
return escapeString(it);
|
||
|
}
|
||
|
if(objtype == "function" || objtype == "undefined"){
|
||
|
return undef; // undefined
|
||
|
}
|
||
|
// short-circuit for objects that support "json" serialization
|
||
|
// if they return "self" then just pass-through...
|
||
|
if(typeof it.toJSON == "function"){
|
||
|
return stringify(it.toJSON(key), indent, key);
|
||
|
}
|
||
|
if(it instanceof Date){
|
||
|
return '"{FullYear}-{Month+}-{Date}T{Hours}:{Minutes}:{Seconds}Z"'.replace(/\{(\w+)(\+)?\}/g, function(t, prop, plus){
|
||
|
var num = it["getUTC" + prop]() + (plus ? 1 : 0);
|
||
|
return num < 10 ? "0" + num : num;
|
||
|
});
|
||
|
}
|
||
|
if(it.valueOf() !== it){
|
||
|
// primitive wrapper, try again unwrapped:
|
||
|
return stringify(it.valueOf(), indent, key);
|
||
|
}
|
||
|
var nextIndent= spacer ? (indent + spacer) : "";
|
||
|
/* we used to test for DOM nodes and throw, but FF serializes them as {}, so cross-browser consistency is probably not efficiently attainable */
|
||
|
|
||
|
var sep = spacer ? " " : "";
|
||
|
var newLine = spacer ? "\n" : "";
|
||
|
|
||
|
// array
|
||
|
if(it instanceof Array){
|
||
|
var itl = it.length, res = [];
|
||
|
for(key = 0; key < itl; key++){
|
||
|
var obj = it[key];
|
||
|
val = stringify(obj, nextIndent, key);
|
||
|
if(typeof val != "string"){
|
||
|
val = "null";
|
||
|
}
|
||
|
res.push(newLine + nextIndent + val);
|
||
|
}
|
||
|
return "[" + res.join(",") + newLine + indent + "]";
|
||
|
}
|
||
|
// generic object code path
|
||
|
var output = [];
|
||
|
for(key in it){
|
||
|
var keyStr;
|
||
|
if(it.hasOwnProperty(key)){
|
||
|
if(typeof key == "number"){
|
||
|
keyStr = '"' + key + '"';
|
||
|
}else if(typeof key == "string"){
|
||
|
keyStr = escapeString(key);
|
||
|
}else{
|
||
|
// skip non-string or number keys
|
||
|
continue;
|
||
|
}
|
||
|
val = stringify(it[key], nextIndent, key);
|
||
|
if(typeof val != "string"){
|
||
|
// skip non-serializable values
|
||
|
continue;
|
||
|
}
|
||
|
// At this point, the most non-IE browsers don't get in this branch
|
||
|
// (they have native JSON), so push is definitely the way to
|
||
|
output.push(newLine + nextIndent + keyStr + ":" + sep + val);
|
||
|
}
|
||
|
}
|
||
|
return "{" + output.join(",") + newLine + indent + "}"; // String
|
||
|
}
|
||
|
return stringify(value, "", "");
|
||
|
}
|
||
|
};
|
||
|
}
|
||
|
});
|
||
|
|
||
|
},
|
||
|
'dojo/_base/lang':function(){
|
||
|
define(["./kernel", "../has", "../sniff"], function(dojo, has){
|
||
|
// module:
|
||
|
// dojo/_base/lang
|
||
|
|
||
|
has.add("bug-for-in-skips-shadowed", function(){
|
||
|
// if true, the for-in iterator skips object properties that exist in Object's prototype (IE 6 - ?)
|
||
|
for(var i in {toString: 1}){
|
||
|
return 0;
|
||
|
}
|
||
|
return 1;
|
||
|
});
|
||
|
|
||
|
// Helper methods
|
||
|
var _extraNames =
|
||
|
has("bug-for-in-skips-shadowed") ?
|
||
|
"hasOwnProperty.valueOf.isPrototypeOf.propertyIsEnumerable.toLocaleString.toString.constructor".split(".") : [],
|
||
|
|
||
|
_extraLen = _extraNames.length,
|
||
|
|
||
|
getProp = function(/*Array*/parts, /*Boolean*/create, /*Object*/context){
|
||
|
if(!context){
|
||
|
if(parts[0] && dojo.scopeMap[parts[0]]) {
|
||
|
// Voodoo code from the old days where "dojo" or "dijit" maps to some special object
|
||
|
// rather than just window.dojo
|
||
|
context = dojo.scopeMap[parts.shift()][1];
|
||
|
}else{
|
||
|
context = dojo.global;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
try{
|
||
|
for(var i = 0; i < parts.length; i++){
|
||
|
var p = parts[i];
|
||
|
// Fix for prototype pollution CVE-2021-23450
|
||
|
if (p === '__proto__' || p === 'constructor') {
|
||
|
return;
|
||
|
}
|
||
|
if(!(p in context)){
|
||
|
if(create){
|
||
|
context[p] = {};
|
||
|
}else{
|
||
|
return; // return undefined
|
||
|
}
|
||
|
}
|
||
|
context = context[p];
|
||
|
}
|
||
|
return context; // mixed
|
||
|
}catch(e){
|
||
|
// "p in context" throws an exception when context is a number, boolean, etc. rather than an object,
|
||
|
// so in that corner case just return undefined (by having no return statement)
|
||
|
}
|
||
|
},
|
||
|
|
||
|
opts = Object.prototype.toString,
|
||
|
|
||
|
efficient = function(obj, offset, startWith){
|
||
|
return (startWith||[]).concat(Array.prototype.slice.call(obj, offset||0));
|
||
|
},
|
||
|
|
||
|
_pattern = /\{([^\}]+)\}/g;
|
||
|
|
||
|
// Module export
|
||
|
var lang = {
|
||
|
// summary:
|
||
|
// This module defines Javascript language extensions.
|
||
|
|
||
|
// _extraNames: String[]
|
||
|
// Lists property names that must be explicitly processed during for-in iteration
|
||
|
// in environments that have has("bug-for-in-skips-shadowed") true.
|
||
|
_extraNames:_extraNames,
|
||
|
|
||
|
_mixin: function(dest, source, copyFunc){
|
||
|
// summary:
|
||
|
// Copies/adds all properties of source to dest; returns dest.
|
||
|
// dest: Object
|
||
|
// The object to which to copy/add all properties contained in source.
|
||
|
// source: Object
|
||
|
// The object from which to draw all properties to copy into dest.
|
||
|
// copyFunc: Function?
|
||
|
// The process used to copy/add a property in source; defaults to the Javascript assignment operator.
|
||
|
// returns:
|
||
|
// dest, as modified
|
||
|
// description:
|
||
|
// All properties, including functions (sometimes termed "methods"), excluding any non-standard extensions
|
||
|
// found in Object.prototype, are copied/added to dest. Copying/adding each particular property is
|
||
|
// delegated to copyFunc (if any); copyFunc defaults to the Javascript assignment operator if not provided.
|
||
|
// Notice that by default, _mixin executes a so-called "shallow copy" and aggregate types are copied/added by reference.
|
||
|
var name, s, i, empty = {};
|
||
|
for(name in source){
|
||
|
// the (!(name in empty) || empty[name] !== s) condition avoids copying properties in "source"
|
||
|
// inherited from Object.prototype. For example, if dest has a custom toString() method,
|
||
|
// don't overwrite it with the toString() method that source inherited from Object.prototype
|
||
|
s = source[name];
|
||
|
if(!(name in dest) || (dest[name] !== s && (!(name in empty) || empty[name] !== s))){
|
||
|
dest[name] = copyFunc ? copyFunc(s) : s;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
if(has("bug-for-in-skips-shadowed")){
|
||
|
if(source){
|
||
|
for(i = 0; i < _extraLen; ++i){
|
||
|
name = _extraNames[i];
|
||
|
s = source[name];
|
||
|
if(!(name in dest) || (dest[name] !== s && (!(name in empty) || empty[name] !== s))){
|
||
|
dest[name] = copyFunc ? copyFunc(s) : s;
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
|
||
|
return dest; // Object
|
||
|
},
|
||
|
|
||
|
mixin: function(dest, sources){
|
||
|
// summary:
|
||
|
// Copies/adds all properties of one or more sources to dest; returns dest.
|
||
|
// dest: Object
|
||
|
// The object to which to copy/add all properties contained in source. If dest is falsy, then
|
||
|
// a new object is manufactured before copying/adding properties begins.
|
||
|
// sources: Object...
|
||
|
// One of more objects from which to draw all properties to copy into dest. sources are processed
|
||
|
// left-to-right and if more than one of these objects contain the same property name, the right-most
|
||
|
// value "wins".
|
||
|
// returns: Object
|
||
|
// dest, as modified
|
||
|
// description:
|
||
|
// All properties, including functions (sometimes termed "methods"), excluding any non-standard extensions
|
||
|
// found in Object.prototype, are copied/added from sources to dest. sources are processed left to right.
|
||
|
// The Javascript assignment operator is used to copy/add each property; therefore, by default, mixin
|
||
|
// executes a so-called "shallow copy" and aggregate types are copied/added by reference.
|
||
|
// example:
|
||
|
// make a shallow copy of an object
|
||
|
// | var copy = lang.mixin({}, source);
|
||
|
// example:
|
||
|
// many class constructors often take an object which specifies
|
||
|
// values to be configured on the object. In this case, it is
|
||
|
// often simplest to call `lang.mixin` on the `this` object:
|
||
|
// | declare("acme.Base", null, {
|
||
|
// | constructor: function(properties){
|
||
|
// | // property configuration:
|
||
|
// | lang.mixin(this, properties);
|
||
|
// |
|
||
|
// | console.log(this.quip);
|
||
|
// | // ...
|
||
|
// | },
|
||
|
// | quip: "I wasn't born yesterday, you know - I've seen movies.",
|
||
|
// | // ...
|
||
|
// | });
|
||
|
// |
|
||
|
// | // create an instance of the class and configure it
|
||
|
// | var b = new acme.Base({quip: "That's what it does!" });
|
||
|
// example:
|
||
|
// copy in properties from multiple objects
|
||
|
// | var flattened = lang.mixin(
|
||
|
// | {
|
||
|
// | name: "Frylock",
|
||
|
// | braces: true
|
||
|
// | },
|
||
|
// | {
|
||
|
// | name: "Carl Brutanananadilewski"
|
||
|
// | }
|
||
|
// | );
|
||
|
// |
|
||
|
// | // will print "Carl Brutanananadilewski"
|
||
|
// | console.log(flattened.name);
|
||
|
// | // will print "true"
|
||
|
// | console.log(flattened.braces);
|
||
|
|
||
|
if(!dest){ dest = {}; }
|
||
|
for(var i = 1, l = arguments.length; i < l; i++){
|
||
|
lang._mixin(dest, arguments[i]);
|
||
|
}
|
||
|
return dest; // Object
|
||
|
},
|
||
|
|
||
|
setObject: function(name, value, context){
|
||
|
// summary:
|
||
|
// Set a property from a dot-separated string, such as "A.B.C"
|
||
|
// description:
|
||
|
// Useful for longer api chains where you have to test each object in
|
||
|
// the chain, or when you have an object reference in string format.
|
||
|
// Objects are created as needed along `path`. Returns the passed
|
||
|
// value if setting is successful or `undefined` if not.
|
||
|
// name: String
|
||
|
// Path to a property, in the form "A.B.C".
|
||
|
// value: anything
|
||
|
// value or object to place at location given by name
|
||
|
// context: Object?
|
||
|
// Optional. Object to use as root of path. Defaults to
|
||
|
// `dojo.global`.
|
||
|
// example:
|
||
|
// set the value of `foo.bar.baz`, regardless of whether
|
||
|
// intermediate objects already exist:
|
||
|
// | lang.setObject("foo.bar.baz", value);
|
||
|
// example:
|
||
|
// without `lang.setObject`, we often see code like this:
|
||
|
// | // ensure that intermediate objects are available
|
||
|
// | if(!obj["parent"]){ obj.parent = {}; }
|
||
|
// | if(!obj.parent["child"]){ obj.parent.child = {}; }
|
||
|
// | // now we can safely set the property
|
||
|
// | obj.parent.child.prop = "some value";
|
||
|
// whereas with `lang.setObject`, we can shorten that to:
|
||
|
// | lang.setObject("parent.child.prop", "some value", obj);
|
||
|
|
||
|
var parts = name.split("."), p = parts.pop(), obj = getProp(parts, true, context);
|
||
|
return obj && p ? (obj[p] = value) : undefined; // Object
|
||
|
},
|
||
|
|
||
|
getObject: function(name, create, context){
|
||
|
// summary:
|
||
|
// Get a property from a dot-separated string, such as "A.B.C"
|
||
|
// description:
|
||
|
// Useful for longer api chains where you have to test each object in
|
||
|
// the chain, or when you have an object reference in string format.
|
||
|
// name: String
|
||
|
// Path to an property, in the form "A.B.C".
|
||
|
// create: Boolean?
|
||
|
// Optional. Defaults to `false`. If `true`, Objects will be
|
||
|
// created at any point along the 'path' that is undefined.
|
||
|
// context: Object?
|
||
|
// Optional. Object to use as root of path. Defaults to
|
||
|
// 'dojo.global'. Null may be passed.
|
||
|
return !name ? context : getProp(name.split("."), create, context); // Object
|
||
|
},
|
||
|
|
||
|
exists: function(name, obj){
|
||
|
// summary:
|
||
|
// determine if an object supports a given method
|
||
|
// description:
|
||
|
// useful for longer api chains where you have to test each object in
|
||
|
// the chain. Useful for object and method detection.
|
||
|
// name: String
|
||
|
// Path to an object, in the form "A.B.C".
|
||
|
// obj: Object?
|
||
|
// Object to use as root of path. Defaults to
|
||
|
// 'dojo.global'. Null may be passed.
|
||
|
// example:
|
||
|
// | // define an object
|
||
|
// | var foo = {
|
||
|
// | bar: { }
|
||
|
// | };
|
||
|
// |
|
||
|
// | // search the global scope
|
||
|
// | lang.exists("foo.bar"); // true
|
||
|
// | lang.exists("foo.bar.baz"); // false
|
||
|
// |
|
||
|
// | // search from a particular scope
|
||
|
// | lang.exists("bar", foo); // true
|
||
|
// | lang.exists("bar.baz", foo); // false
|
||
|
return lang.getObject(name, false, obj) !== undefined; // Boolean
|
||
|
},
|
||
|
|
||
|
// Crockford (ish) functions
|
||
|
|
||
|
isString: function(it){
|
||
|
// summary:
|
||
|
// Return true if it is a String
|
||
|
// it: anything
|
||
|
// Item to test.
|
||
|
return (typeof it == "string" || it instanceof String); // Boolean
|
||
|
},
|
||
|
|
||
|
isArray: Array.isArray || function(it){
|
||
|
// summary:
|
||
|
// Return true if it is an Array.
|
||
|
// it: anything
|
||
|
// Item to test.
|
||
|
return opts.call(it) == "[object Array]"; // Boolean
|
||
|
},
|
||
|
|
||
|
isFunction: function(it){
|
||
|
// summary:
|
||
|
// Return true if it is a Function
|
||
|
// it: anything
|
||
|
// Item to test.
|
||
|
return opts.call(it) === "[object Function]";
|
||
|
},
|
||
|
|
||
|
isObject: function(it){
|
||
|
// summary:
|
||
|
// Returns true if it is a JavaScript object (or an Array, a Function
|
||
|
// or null)
|
||
|
// it: anything
|
||
|
// Item to test.
|
||
|
return it !== undefined &&
|
||
|
(it === null || typeof it == "object" || lang.isArray(it) || lang.isFunction(it)); // Boolean
|
||
|
},
|
||
|
|
||
|
isArrayLike: function(it){
|
||
|
// summary:
|
||
|
// similar to isArray() but more permissive
|
||
|
// it: anything
|
||
|
// Item to test.
|
||
|
// returns:
|
||
|
// If it walks like a duck and quacks like a duck, return `true`
|
||
|
// description:
|
||
|
// Doesn't strongly test for "arrayness". Instead, settles for "isn't
|
||
|
// a string or number and has a length property". Arguments objects
|
||
|
// and DOM collections will return true when passed to
|
||
|
// isArrayLike(), but will return false when passed to
|
||
|
// isArray().
|
||
|
return !!it && // Boolean
|
||
|
// keep out built-in constructors (Number, String, ...) which have length
|
||
|
// properties
|
||
|
!lang.isString(it) && !lang.isFunction(it) &&
|
||
|
!(it.tagName && it.tagName.toLowerCase() == 'form') &&
|
||
|
(lang.isArray(it) || isFinite(it.length));
|
||
|
},
|
||
|
|
||
|
isAlien: function(it){
|
||
|
// summary:
|
||
|
// Returns true if it is a built-in function or some other kind of
|
||
|
// oddball that *should* report as a function but doesn't
|
||
|
return it && !lang.isFunction(it) && /\{\s*\[native code\]\s*\}/.test(String(it)); // Boolean
|
||
|
},
|
||
|
|
||
|
extend: function(ctor, props){
|
||
|
// summary:
|
||
|
// Adds all properties and methods of props to constructor's
|
||
|
// prototype, making them available to all instances created with
|
||
|
// constructor.
|
||
|
// ctor: Object
|
||
|
// Target constructor to extend.
|
||
|
// props: Object
|
||
|
// One or more objects to mix into ctor.prototype
|
||
|
for(var i=1, l=arguments.length; i<l; i++){
|
||
|
lang._mixin(ctor.prototype, arguments[i]);
|
||
|
}
|
||
|
return ctor; // Object
|
||
|
},
|
||
|
|
||
|
_hitchArgs: function(scope, method){
|
||
|
var pre = lang._toArray(arguments, 2);
|
||
|
var named = lang.isString(method);
|
||
|
return function(){
|
||
|
// arrayify arguments
|
||
|
var args = lang._toArray(arguments);
|
||
|
// locate our method
|
||
|
var f = named ? (scope||dojo.global)[method] : method;
|
||
|
// invoke with collected args
|
||
|
return f && f.apply(scope || this, pre.concat(args)); // mixed
|
||
|
}; // Function
|
||
|
},
|
||
|
|
||
|
hitch: function(scope, method){
|
||
|
// summary:
|
||
|
// Returns a function that will only ever execute in the given scope.
|
||
|
// This allows for easy use of object member functions
|
||
|
// in callbacks and other places in which the "this" keyword may
|
||
|
// otherwise not reference the expected scope.
|
||
|
// Any number of default positional arguments may be passed as parameters
|
||
|
// beyond "method".
|
||
|
// Each of these values will be used to "placehold" (similar to curry)
|
||
|
// for the hitched function.
|
||
|
// scope: Object
|
||
|
// The scope to use when method executes. If method is a string,
|
||
|
// scope is also the object containing method.
|
||
|
// method: Function|String...
|
||
|
// A function to be hitched to scope, or the name of the method in
|
||
|
// scope to be hitched.
|
||
|
// example:
|
||
|
// | lang.hitch(foo, "bar")();
|
||
|
// runs foo.bar() in the scope of foo
|
||
|
// example:
|
||
|
// | lang.hitch(foo, myFunction);
|
||
|
// returns a function that runs myFunction in the scope of foo
|
||
|
// example:
|
||
|
// Expansion on the default positional arguments passed along from
|
||
|
// hitch. Passed args are mixed first, additional args after.
|
||
|
// | var foo = { bar: function(a, b, c){ console.log(a, b, c); } };
|
||
|
// | var fn = lang.hitch(foo, "bar", 1, 2);
|
||
|
// | fn(3); // logs "1, 2, 3"
|
||
|
// example:
|
||
|
// | var foo = { bar: 2 };
|
||
|
// | lang.hitch(foo, function(){ this.bar = 10; })();
|
||
|
// execute an anonymous function in scope of foo
|
||
|
if(arguments.length > 2){
|
||
|
return lang._hitchArgs.apply(dojo, arguments); // Function
|
||
|
}
|
||
|
if(!method){
|
||
|
method = scope;
|
||
|
scope = null;
|
||
|
}
|
||
|
if(lang.isString(method)){
|
||
|
scope = scope || dojo.global;
|
||
|
if(!scope[method]){ throw(['lang.hitch: scope["', method, '"] is null (scope="', scope, '")'].join('')); }
|
||
|
return function(){ return scope[method].apply(scope, arguments || []); }; // Function
|
||
|
}
|
||
|
return !scope ? method : function(){ return method.apply(scope, arguments || []); }; // Function
|
||
|
},
|
||
|
|
||
|
delegate: (function(){
|
||
|
// boodman/crockford delegation w/ cornford optimization
|
||
|
function TMP(){}
|
||
|
return function(obj, props){
|
||
|
TMP.prototype = obj;
|
||
|
var tmp = new TMP();
|
||
|
TMP.prototype = null;
|
||
|
if(props){
|
||
|
lang._mixin(tmp, props);
|
||
|
}
|
||
|
return tmp; // Object
|
||
|
};
|
||
|
})(),
|
||
|
/*=====
|
||
|
delegate: function(obj, props){
|
||
|
// summary:
|
||
|
// Returns a new object which "looks" to obj for properties which it
|
||
|
// does not have a value for. Optionally takes a bag of properties to
|
||
|
// seed the returned object with initially.
|
||
|
// description:
|
||
|
// This is a small implementation of the Boodman/Crockford delegation
|
||
|
// pattern in JavaScript. An intermediate object constructor mediates
|
||
|
// the prototype chain for the returned object, using it to delegate
|
||
|
// down to obj for property lookup when object-local lookup fails.
|
||
|
// This can be thought of similarly to ES4's "wrap", save that it does
|
||
|
// not act on types but rather on pure objects.
|
||
|
// obj: Object
|
||
|
// The object to delegate to for properties not found directly on the
|
||
|
// return object or in props.
|
||
|
// props: Object...
|
||
|
// an object containing properties to assign to the returned object
|
||
|
// returns:
|
||
|
// an Object of anonymous type
|
||
|
// example:
|
||
|
// | var foo = { bar: "baz" };
|
||
|
// | var thinger = lang.delegate(foo, { thud: "xyzzy"});
|
||
|
// | thinger.bar == "baz"; // delegated to foo
|
||
|
// | foo.thud == undefined; // by definition
|
||
|
// | thinger.thud == "xyzzy"; // mixed in from props
|
||
|
// | foo.bar = "thonk";
|
||
|
// | thinger.bar == "thonk"; // still delegated to foo's bar
|
||
|
},
|
||
|
=====*/
|
||
|
|
||
|
_toArray: has("ie") ?
|
||
|
(function(){
|
||
|
function slow(obj, offset, startWith){
|
||
|
var arr = startWith||[];
|
||
|
for(var x = offset || 0; x < obj.length; x++){
|
||
|
arr.push(obj[x]);
|
||
|
}
|
||
|
return arr;
|
||
|
}
|
||
|
return function(obj){
|
||
|
return ((obj.item) ? slow : efficient).apply(this, arguments);
|
||
|
};
|
||
|
})() : efficient,
|
||
|
/*=====
|
||
|
_toArray: function(obj, offset, startWith){
|
||
|
// summary:
|
||
|
// Converts an array-like object (i.e. arguments, DOMCollection) to an
|
||
|
// array. Returns a new Array with the elements of obj.
|
||
|
// obj: Object
|
||
|
// the object to "arrayify". We expect the object to have, at a
|
||
|
// minimum, a length property which corresponds to integer-indexed
|
||
|
// properties.
|
||
|
// offset: Number?
|
||
|
// the location in obj to start iterating from. Defaults to 0.
|
||
|
// Optional.
|
||
|
// startWith: Array?
|
||
|
// An array to pack with the properties of obj. If provided,
|
||
|
// properties in obj are appended at the end of startWith and
|
||
|
// startWith is the returned array.
|
||
|
},
|
||
|
=====*/
|
||
|
|
||
|
partial: function(/*Function|String*/ method /*, ...*/){
|
||
|
// summary:
|
||
|
// similar to hitch() except that the scope object is left to be
|
||
|
// whatever the execution context eventually becomes.
|
||
|
// description:
|
||
|
// Calling lang.partial is the functional equivalent of calling:
|
||
|
// | lang.hitch(null, funcName, ...);
|
||
|
// method:
|
||
|
// The function to "wrap"
|
||
|
var arr = [ null ];
|
||
|
return lang.hitch.apply(dojo, arr.concat(lang._toArray(arguments))); // Function
|
||
|
},
|
||
|
|
||
|
clone: function(/*anything*/ src){
|
||
|
// summary:
|
||
|
// Clones objects (including DOM nodes) and all children.
|
||
|
// Warning: do not clone cyclic structures.
|
||
|
// src:
|
||
|
// The object to clone
|
||
|
if(!src || typeof src != "object" || lang.isFunction(src)){
|
||
|
// null, undefined, any non-object, or function
|
||
|
return src; // anything
|
||
|
}
|
||
|
if(src.nodeType && "cloneNode" in src){
|
||
|
// DOM Node
|
||
|
return src.cloneNode(true); // Node
|
||
|
}
|
||
|
if(src instanceof Date){
|
||
|
// Date
|
||
|
return new Date(src.getTime()); // Date
|
||
|
}
|
||
|
if(src instanceof RegExp){
|
||
|
// RegExp
|
||
|
return new RegExp(src); // RegExp
|
||
|
}
|
||
|
var r, i, l;
|
||
|
if(lang.isArray(src)){
|
||
|
// array
|
||
|
r = [];
|
||
|
for(i = 0, l = src.length; i < l; ++i){
|
||
|
if(i in src){
|
||
|
r[i] = lang.clone(src[i]);
|
||
|
}
|
||
|
}
|
||
|
// we don't clone functions for performance reasons
|
||
|
// }else if(d.isFunction(src)){
|
||
|
// // function
|
||
|
// r = function(){ return src.apply(this, arguments); };
|
||
|
}else{
|
||
|
// generic objects
|
||
|
r = src.constructor ? new src.constructor() : {};
|
||
|
}
|
||
|
return lang._mixin(r, src, lang.clone);
|
||
|
},
|
||
|
|
||
|
|
||
|
trim: String.prototype.trim ?
|
||
|
function(str){ return str.trim(); } :
|
||
|
function(str){ return str.replace(/^\s\s*/, '').replace(/\s\s*$/, ''); },
|
||
|
/*=====
|
||
|
trim: function(str){
|
||
|
// summary:
|
||
|
// Trims whitespace from both sides of the string
|
||
|
// str: String
|
||
|
// String to be trimmed
|
||
|
// returns: String
|
||
|
// Returns the trimmed string
|
||
|
// description:
|
||
|
// This version of trim() was selected for inclusion into the base due
|
||
|
// to its compact size and relatively good performance
|
||
|
// (see [Steven Levithan's blog](http://blog.stevenlevithan.com/archives/faster-trim-javascript)
|
||
|
// Uses String.prototype.trim instead, if available.
|
||
|
// The fastest but longest version of this function is located at
|
||
|
// lang.string.trim()
|
||
|
},
|
||
|
=====*/
|
||
|
|
||
|
replace: function(tmpl, map, pattern){
|
||
|
// summary:
|
||
|
// Performs parameterized substitutions on a string. Throws an
|
||
|
// exception if any parameter is unmatched.
|
||
|
// tmpl: String
|
||
|
// String to be used as a template.
|
||
|
// map: Object|Function
|
||
|
// If an object, it is used as a dictionary to look up substitutions.
|
||
|
// If a function, it is called for every substitution with following parameters:
|
||
|
// a whole match, a name, an offset, and the whole template
|
||
|
// string (see https://developer.mozilla.org/en/Core_JavaScript_1.5_Reference/Global_Objects/String/replace
|
||
|
// for more details).
|
||
|
// pattern: RegEx?
|
||
|
// Optional regular expression objects that overrides the default pattern.
|
||
|
// Must be global and match one item. The default is: /\{([^\}]+)\}/g,
|
||
|
// which matches patterns like that: "{xxx}", where "xxx" is any sequence
|
||
|
// of characters, which doesn't include "}".
|
||
|
// returns: String
|
||
|
// Returns the substituted string.
|
||
|
// example:
|
||
|
// | // uses a dictionary for substitutions:
|
||
|
// | lang.replace("Hello, {name.first} {name.last} AKA {nick}!",
|
||
|
// | {
|
||
|
// | nick: "Bob",
|
||
|
// | name: {
|
||
|
// | first: "Robert",
|
||
|
// | middle: "X",
|
||
|
// | last: "Cringely"
|
||
|
// | }
|
||
|
// | });
|
||
|
// | // returns: Hello, Robert Cringely AKA Bob!
|
||
|
// example:
|
||
|
// | // uses an array for substitutions:
|
||
|
// | lang.replace("Hello, {0} {2}!",
|
||
|
// | ["Robert", "X", "Cringely"]);
|
||
|
// | // returns: Hello, Robert Cringely!
|
||
|
// example:
|
||
|
// | // uses a function for substitutions:
|
||
|
// | function sum(a){
|
||
|
// | var t = 0;
|
||
|
// | arrayforEach(a, function(x){ t += x; });
|
||
|
// | return t;
|
||
|
// | }
|
||
|
// | lang.replace(
|
||
|
// | "{count} payments averaging {avg} USD per payment.",
|
||
|
// | lang.hitch(
|
||
|
// | { payments: [11, 16, 12] },
|
||
|
// | function(_, key){
|
||
|
// | switch(key){
|
||
|
// | case "count": return this.payments.length;
|
||
|
// | case "min": return Math.min.apply(Math, this.payments);
|
||
|
// | case "max": return Math.max.apply(Math, this.payments);
|
||
|
// | case "sum": return sum(this.payments);
|
||
|
// | case "avg": return sum(this.payments) / this.payments.length;
|
||
|
// | }
|
||
|
// | }
|
||
|
// | )
|
||
|
// | );
|
||
|
// | // prints: 3 payments averaging 13 USD per payment.
|
||
|
// example:
|
||
|
// | // uses an alternative PHP-like pattern for substitutions:
|
||
|
// | lang.replace("Hello, ${0} ${2}!",
|
||
|
// | ["Robert", "X", "Cringely"], /\$\{([^\}]+)\}/g);
|
||
|
// | // returns: Hello, Robert Cringely!
|
||
|
|
||
|
return tmpl.replace(pattern || _pattern, lang.isFunction(map) ?
|
||
|
map : function(_, k){ return lang.getObject(k, false, map); });
|
||
|
}
|
||
|
};
|
||
|
|
||
|
1 && lang.mixin(dojo, lang);
|
||
|
|
||
|
return lang;
|
||
|
});
|
||
|
|
||
|
},
|
||
|
'dojo/sniff':function(){
|
||
|
define(["./has"], function(has){
|
||
|
// module:
|
||
|
// dojo/sniff
|
||
|
|
||
|
/*=====
|
||
|
return function(){
|
||
|
// summary:
|
||
|
// This module sets has() flags based on the current browser.
|
||
|
// It returns the has() function.
|
||
|
};
|
||
|
=====*/
|
||
|
|
||
|
if( 1 ){
|
||
|
var n = navigator,
|
||
|
dua = n.userAgent,
|
||
|
dav = n.appVersion,
|
||
|
tv = parseFloat(dav);
|
||
|
has.add("air", dua.indexOf("AdobeAIR") >= 0);
|
||
|
has.add("wp", parseFloat(dua.split("Windows Phone")[1]) || undefined);
|
||
|
has.add("msapp", parseFloat(dua.split("MSAppHost/")[1]) || undefined);
|
||
|
has.add("khtml", dav.indexOf("Konqueror") >= 0 ? tv : undefined);
|
||
|
has.add("edge", parseFloat(dua.split("Edge/")[1]) || undefined);
|
||
|
has.add("opr", parseFloat(dua.split("OPR/")[1]) || undefined);
|
||
|
// NOTE: https://dev.opera.com/blog/opera-user-agent-strings-opera-15-and-beyond/
|
||
|
has.add("webkit", !has("wp") // NOTE: necessary since Windows Phone 8.1 Update 1, see #18540
|
||
|
&& !has("edge") && parseFloat(dua.split("WebKit/")[1]) || undefined);
|
||
|
has.add("chrome", !has("edge") && !has("opr")
|
||
|
&& parseFloat(dua.split("Chrome/")[1]) || undefined);
|
||
|
has.add("android", !has("wp") // NOTE: necessary since Windows Phone 8.1 Update 1, see #18528
|
||
|
&& parseFloat(dua.split("Android ")[1]) || undefined);
|
||
|
has.add("safari", dav.indexOf("Safari") >= 0
|
||
|
&& !has("wp") // NOTE: necessary since Windows Phone 8.1 Update 1, see #18540
|
||
|
&& !has("chrome") && !has("android") && !has("edge") && !has("opr") ?
|
||
|
parseFloat(dav.split("Version/")[1]) : undefined);
|
||
|
has.add("mac", dav.indexOf("Macintosh") >= 0);
|
||
|
has.add("quirks", document.compatMode == "BackCompat");
|
||
|
if(!has("wp") // NOTE: necessary since Windows Phone 8.1 Update 1, see #18528
|
||
|
&& dua.match(/(iPhone|iPod|iPad)/)){
|
||
|
var p = RegExp.$1.replace(/P/, "p");
|
||
|
var v = dua.match(/OS ([\d_]+)/) ? RegExp.$1 : "1";
|
||
|
var os = parseFloat(v.replace(/_/, ".").replace(/_/g, ""));
|
||
|
has.add(p, os); // "iphone", "ipad" or "ipod"
|
||
|
has.add("ios", os);
|
||
|
}
|
||
|
has.add("bb", (dua.indexOf("BlackBerry") >= 0 || dua.indexOf("BB10") >= 0) && parseFloat(dua.split("Version/")[1]) || undefined);
|
||
|
has.add("trident", parseFloat(dav.split("Trident/")[1]) || undefined);
|
||
|
|
||
|
has.add("svg", typeof SVGAngle !== "undefined");
|
||
|
|
||
|
if(!has("webkit")){
|
||
|
// Opera
|
||
|
if(dua.indexOf("Opera") >= 0){
|
||
|
// see http://dev.opera.com/articles/view/opera-ua-string-changes and http://www.useragentstring.com/pages/Opera/
|
||
|
// 9.8 has both styles; <9.8, 9.9 only old style
|
||
|
has.add("opera", tv >= 9.8 ? parseFloat(dua.split("Version/")[1]) || tv : tv);
|
||
|
}
|
||
|
|
||
|
// Mozilla and firefox
|
||
|
if(dua.indexOf("Gecko") >= 0 && !has("wp") // NOTE: necessary since Windows Phone 8.1 Update 1
|
||
|
&& !has("khtml") && !has("trident") && !has("edge")){
|
||
|
has.add("mozilla", tv);
|
||
|
}
|
||
|
if(has("mozilla")){
|
||
|
//We really need to get away from this. Consider a sane isGecko approach for the future.
|
||
|
has.add("ff", parseFloat(dua.split("Firefox/")[1] || dua.split("Minefield/")[1]) || undefined);
|
||
|
}
|
||
|
|
||
|
// IE
|
||
|
if(document.all && !has("opera")){
|
||
|
var isIE = parseFloat(dav.split("MSIE ")[1]) || undefined;
|
||
|
|
||
|
//In cases where the page has an HTTP header or META tag with
|
||
|
//X-UA-Compatible, then it is in emulation mode.
|
||
|
//Make sure isIE reflects the desired version.
|
||
|
//document.documentMode of 5 means quirks mode.
|
||
|
//Only switch the value if documentMode's major version
|
||
|
//is different from isIE's major version.
|
||
|
var mode = document.documentMode;
|
||
|
if(mode && mode != 5 && Math.floor(isIE) != mode){
|
||
|
isIE = mode;
|
||
|
}
|
||
|
|
||
|
has.add("ie", isIE);
|
||
|
}
|
||
|
|
||
|
// Wii
|
||
|
has.add("wii", typeof opera != "undefined" && opera.wiiremote);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
return has;
|
||
|
});
|
||
|
|
||
|
},
|
||
|
'dojo/_base/array':function(){
|
||
|
define(["./kernel", "../has", "./lang"], function(dojo, has, lang){
|
||
|
// module:
|
||
|
// dojo/_base/array
|
||
|
|
||
|
// our old simple function builder stuff
|
||
|
var cache = {}, u;
|
||
|
|
||
|
var buildFn;
|
||
|
if(!has("csp-restrictions")){
|
||
|
buildFn = function (fn){
|
||
|
return cache[fn] = new Function("item", "index", "array", fn); // Function
|
||
|
};
|
||
|
}
|
||
|
|
||
|
// magic snippet: if(typeof fn == "string") fn = cache[fn] || buildFn(fn);
|
||
|
|
||
|
// every & some
|
||
|
|
||
|
function everyOrSome(some){
|
||
|
var every = !some;
|
||
|
return function(a, fn, o){
|
||
|
var i = 0, l = a && a.length || 0, result;
|
||
|
if(l && typeof a == "string") a = a.split("");
|
||
|
if(typeof fn == "string"){
|
||
|
if(has("csp-restrictions")){
|
||
|
throw new TypeError("callback must be a function");
|
||
|
}
|
||
|
else{
|
||
|
fn = cache[fn] || buildFn(fn);
|
||
|
}
|
||
|
}
|
||
|
if(o){
|
||
|
for(; i < l; ++i){
|
||
|
result = !fn.call(o, a[i], i, a);
|
||
|
if(some ^ result){
|
||
|
return !result;
|
||
|
}
|
||
|
}
|
||
|
}else{
|
||
|
for(; i < l; ++i){
|
||
|
result = !fn(a[i], i, a);
|
||
|
if(some ^ result){
|
||
|
return !result;
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
return every; // Boolean
|
||
|
};
|
||
|
}
|
||
|
|
||
|
// indexOf, lastIndexOf
|
||
|
|
||
|
function index(up){
|
||
|
var delta = 1, lOver = 0, uOver = 0;
|
||
|
if(!up){
|
||
|
delta = lOver = uOver = -1;
|
||
|
}
|
||
|
return function(a, x, from, last){
|
||
|
if(last && delta > 0){
|
||
|
// TODO: why do we use a non-standard signature? why do we need "last"?
|
||
|
return array.lastIndexOf(a, x, from);
|
||
|
}
|
||
|
var l = a && a.length || 0, end = up ? l + uOver : lOver, i;
|
||
|
if(from === u){
|
||
|
i = up ? lOver : l + uOver;
|
||
|
}else{
|
||
|
if(from < 0){
|
||
|
i = l + from;
|
||
|
if(i < 0){
|
||
|
i = lOver;
|
||
|
}
|
||
|
}else{
|
||
|
i = from >= l ? l + uOver : from;
|
||
|
}
|
||
|
}
|
||
|
if(l && typeof a == "string") a = a.split("");
|
||
|
for(; i != end; i += delta){
|
||
|
if(a[i] == x){
|
||
|
return i; // Number
|
||
|
}
|
||
|
}
|
||
|
return -1; // Number
|
||
|
};
|
||
|
}
|
||
|
|
||
|
var array = {
|
||
|
// summary:
|
||
|
// The Javascript v1.6 array extensions.
|
||
|
|
||
|
every: everyOrSome(false),
|
||
|
/*=====
|
||
|
every: function(arr, callback, thisObject){
|
||
|
// summary:
|
||
|
// Determines whether or not every item in arr satisfies the
|
||
|
// condition implemented by callback.
|
||
|
// arr: Array|String
|
||
|
// the array to iterate on. If a string, operates on individual characters.
|
||
|
// callback: Function|String
|
||
|
// a function is invoked with three arguments: item, index,
|
||
|
// and array and returns true if the condition is met.
|
||
|
// thisObject: Object?
|
||
|
// may be used to scope the call to callback
|
||
|
// returns: Boolean
|
||
|
// description:
|
||
|
// This function corresponds to the JavaScript 1.6 Array.every() method, with one difference: when
|
||
|
// run over sparse arrays, this implementation passes the "holes" in the sparse array to
|
||
|
// the callback function with a value of undefined. JavaScript 1.6's every skips the holes in the sparse array.
|
||
|
// For more details, see:
|
||
|
// https://developer.mozilla.org/en/Core_JavaScript_1.5_Reference/Objects/Array/every
|
||
|
// example:
|
||
|
// | // returns false
|
||
|
// | array.every([1, 2, 3, 4], function(item){ return item>1; });
|
||
|
// example:
|
||
|
// | // returns true
|
||
|
// | array.every([1, 2, 3, 4], function(item){ return item>0; });
|
||
|
},
|
||
|
=====*/
|
||
|
|
||
|
some: everyOrSome(true),
|
||
|
/*=====
|
||
|
some: function(arr, callback, thisObject){
|
||
|
// summary:
|
||
|
// Determines whether or not any item in arr satisfies the
|
||
|
// condition implemented by callback.
|
||
|
// arr: Array|String
|
||
|
// the array to iterate over. If a string, operates on individual characters.
|
||
|
// callback: Function|String
|
||
|
// a function is invoked with three arguments: item, index,
|
||
|
// and array and returns true if the condition is met.
|
||
|
// thisObject: Object?
|
||
|
// may be used to scope the call to callback
|
||
|
// returns: Boolean
|
||
|
// description:
|
||
|
// This function corresponds to the JavaScript 1.6 Array.some() method, with one difference: when
|
||
|
// run over sparse arrays, this implementation passes the "holes" in the sparse array to
|
||
|
// the callback function with a value of undefined. JavaScript 1.6's some skips the holes in the sparse array.
|
||
|
// For more details, see:
|
||
|
// https://developer.mozilla.org/en/Core_JavaScript_1.5_Reference/Objects/Array/some
|
||
|
// example:
|
||
|
// | // is true
|
||
|
// | array.some([1, 2, 3, 4], function(item){ return item>1; });
|
||
|
// example:
|
||
|
// | // is false
|
||
|
// | array.some([1, 2, 3, 4], function(item){ return item<1; });
|
||
|
},
|
||
|
=====*/
|
||
|
|
||
|
indexOf: index(true),
|
||
|
/*=====
|
||
|
indexOf: function(arr, value, fromIndex, findLast){
|
||
|
// summary:
|
||
|
// locates the first index of the provided value in the
|
||
|
// passed array. If the value is not found, -1 is returned.
|
||
|
// description:
|
||
|
// This method corresponds to the JavaScript 1.6 Array.indexOf method, with two differences:
|
||
|
//
|
||
|
// 1. when run over sparse arrays, the Dojo function invokes the callback for every index
|
||
|
// whereas JavaScript 1.6's indexOf skips the holes in the sparse array.
|
||
|
// 2. uses equality (==) rather than strict equality (===)
|
||
|
//
|
||
|
// For details on this method, see:
|
||
|
// https://developer.mozilla.org/en/Core_JavaScript_1.5_Reference/Objects/Array/indexOf
|
||
|
// arr: Array
|
||
|
// value: Object
|
||
|
// fromIndex: Integer?
|
||
|
// findLast: Boolean?
|
||
|
// Makes indexOf() work like lastIndexOf(). Used internally; not meant for external usage.
|
||
|
// returns: Number
|
||
|
},
|
||
|
=====*/
|
||
|
|
||
|
lastIndexOf: index(false),
|
||
|
/*=====
|
||
|
lastIndexOf: function(arr, value, fromIndex){
|
||
|
// summary:
|
||
|
// locates the last index of the provided value in the passed
|
||
|
// array. If the value is not found, -1 is returned.
|
||
|
// description:
|
||
|
// This method corresponds to the JavaScript 1.6 Array.lastIndexOf method, with two differences:
|
||
|
//
|
||
|
// 1. when run over sparse arrays, the Dojo function invokes the callback for every index
|
||
|
// whereas JavaScript 1.6's lasIndexOf skips the holes in the sparse array.
|
||
|
// 2. uses equality (==) rather than strict equality (===)
|
||
|
//
|
||
|
// For details on this method, see:
|
||
|
// https://developer.mozilla.org/en/Core_JavaScript_1.5_Reference/Objects/Array/lastIndexOf
|
||
|
// arr: Array,
|
||
|
// value: Object,
|
||
|
// fromIndex: Integer?
|
||
|
// returns: Number
|
||
|
},
|
||
|
=====*/
|
||
|
|
||
|
forEach: function(arr, callback, thisObject){
|
||
|
// summary:
|
||
|
// for every item in arr, callback is invoked. Return values are ignored.
|
||
|
// If you want to break out of the loop, consider using array.every() or array.some().
|
||
|
// forEach does not allow breaking out of the loop over the items in arr.
|
||
|
// arr:
|
||
|
// the array to iterate over. If a string, operates on individual characters.
|
||
|
// callback:
|
||
|
// a function is invoked with three arguments: item, index, and array
|
||
|
// thisObject:
|
||
|
// may be used to scope the call to callback
|
||
|
// description:
|
||
|
// This function corresponds to the JavaScript 1.6 Array.forEach() method, with one difference: when
|
||
|
// run over sparse arrays, this implementation passes the "holes" in the sparse array to
|
||
|
// the callback function with a value of undefined. JavaScript 1.6's forEach skips the holes in the sparse array.
|
||
|
// For more details, see:
|
||
|
// https://developer.mozilla.org/en/Core_JavaScript_1.5_Reference/Objects/Array/forEach
|
||
|
// example:
|
||
|
// | // log out all members of the array:
|
||
|
// | array.forEach(
|
||
|
// | [ "thinger", "blah", "howdy", 10 ],
|
||
|
// | function(item){
|
||
|
// | console.log(item);
|
||
|
// | }
|
||
|
// | );
|
||
|
// example:
|
||
|
// | // log out the members and their indexes
|
||
|
// | array.forEach(
|
||
|
// | [ "thinger", "blah", "howdy", 10 ],
|
||
|
// | function(item, idx, arr){
|
||
|
// | console.log(item, "at index:", idx);
|
||
|
// | }
|
||
|
// | );
|
||
|
// example:
|
||
|
// | // use a scoped object member as the callback
|
||
|
// |
|
||
|
// | var obj = {
|
||
|
// | prefix: "logged via obj.callback:",
|
||
|
// | callback: function(item){
|
||
|
// | console.log(this.prefix, item);
|
||
|
// | }
|
||
|
// | };
|
||
|
// |
|
||
|
// | // specifying the scope function executes the callback in that scope
|
||
|
// | array.forEach(
|
||
|
// | [ "thinger", "blah", "howdy", 10 ],
|
||
|
// | obj.callback,
|
||
|
// | obj
|
||
|
// | );
|
||
|
// |
|
||
|
// | // alternately, we can accomplish the same thing with lang.hitch()
|
||
|
// | array.forEach(
|
||
|
// | [ "thinger", "blah", "howdy", 10 ],
|
||
|
// | lang.hitch(obj, "callback")
|
||
|
// | );
|
||
|
// arr: Array|String
|
||
|
// callback: Function|String
|
||
|
// thisObject: Object?
|
||
|
|
||
|
var i = 0, l = arr && arr.length || 0;
|
||
|
if(l && typeof arr == "string") arr = arr.split("");
|
||
|
if(typeof callback == "string"){
|
||
|
if(has("csp-restrictions")){
|
||
|
throw new TypeError("callback must be a function");
|
||
|
}
|
||
|
else{
|
||
|
callback = cache[callback] || buildFn(callback);
|
||
|
}
|
||
|
}
|
||
|
if(thisObject){
|
||
|
for(; i < l; ++i){
|
||
|
callback.call(thisObject, arr[i], i, arr);
|
||
|
}
|
||
|
}else{
|
||
|
for(; i < l; ++i){
|
||
|
callback(arr[i], i, arr);
|
||
|
}
|
||
|
}
|
||
|
},
|
||
|
|
||
|
map: function(arr, callback, thisObject, Ctr){
|
||
|
// summary:
|
||
|
// applies callback to each element of arr and returns
|
||
|
// an Array with the results
|
||
|
// arr: Array|String
|
||
|
// the array to iterate on. If a string, operates on
|
||
|
// individual characters.
|
||
|
// callback: Function|String
|
||
|
// a function is invoked with three arguments, (item, index,
|
||
|
// array), and returns a value
|
||
|
// thisObject: Object?
|
||
|
// may be used to scope the call to callback
|
||
|
// returns: Array
|
||
|
// description:
|
||
|
// This function corresponds to the JavaScript 1.6 Array.map() method, with one difference: when
|
||
|
// run over sparse arrays, this implementation passes the "holes" in the sparse array to
|
||
|
// the callback function with a value of undefined. JavaScript 1.6's map skips the holes in the sparse array.
|
||
|
// For more details, see:
|
||
|
// https://developer.mozilla.org/en/Core_JavaScript_1.5_Reference/Objects/Array/map
|
||
|
// example:
|
||
|
// | // returns [2, 3, 4, 5]
|
||
|
// | array.map([1, 2, 3, 4], function(item){ return item+1 });
|
||
|
|
||
|
// TODO: why do we have a non-standard signature here? do we need "Ctr"?
|
||
|
var i = 0, l = arr && arr.length || 0, out = new (Ctr || Array)(l);
|
||
|
if(l && typeof arr == "string") arr = arr.split("");
|
||
|
if(typeof callback == "string"){
|
||
|
if(has("csp-restrictions")){
|
||
|
throw new TypeError("callback must be a function");
|
||
|
}
|
||
|
else{
|
||
|
callback = cache[callback] || buildFn(callback);
|
||
|
}
|
||
|
}
|
||
|
if(thisObject){
|
||
|
for(; i < l; ++i){
|
||
|
out[i] = callback.call(thisObject, arr[i], i, arr);
|
||
|
}
|
||
|
}else{
|
||
|
for(; i < l; ++i){
|
||
|
out[i] = callback(arr[i], i, arr);
|
||
|
}
|
||
|
}
|
||
|
return out; // Array
|
||
|
},
|
||
|
|
||
|
filter: function(arr, callback, thisObject){
|
||
|
// summary:
|
||
|
// Returns a new Array with those items from arr that match the
|
||
|
// condition implemented by callback.
|
||
|
// arr: Array
|
||
|
// the array to iterate over.
|
||
|
// callback: Function|String
|
||
|
// a function that is invoked with three arguments (item,
|
||
|
// index, array). The return of this function is expected to
|
||
|
// be a boolean which determines whether the passed-in item
|
||
|
// will be included in the returned array.
|
||
|
// thisObject: Object?
|
||
|
// may be used to scope the call to callback
|
||
|
// returns: Array
|
||
|
// description:
|
||
|
// This function corresponds to the JavaScript 1.6 Array.filter() method, with one difference: when
|
||
|
// run over sparse arrays, this implementation passes the "holes" in the sparse array to
|
||
|
// the callback function with a value of undefined. JavaScript 1.6's filter skips the holes in the sparse array.
|
||
|
// For more details, see:
|
||
|
// https://developer.mozilla.org/en/Core_JavaScript_1.5_Reference/Objects/Array/filter
|
||
|
// example:
|
||
|
// | // returns [2, 3, 4]
|
||
|
// | array.filter([1, 2, 3, 4], function(item){ return item>1; });
|
||
|
|
||
|
// TODO: do we need "Ctr" here like in map()?
|
||
|
var i = 0, l = arr && arr.length || 0, out = [], value;
|
||
|
if(l && typeof arr == "string") arr = arr.split("");
|
||
|
if(typeof callback == "string"){
|
||
|
if(has("csp-restrictions")){
|
||
|
throw new TypeError("callback must be a function");
|
||
|
}
|
||
|
else{
|
||
|
callback = cache[callback] || buildFn(callback);
|
||
|
}
|
||
|
}
|
||
|
if(thisObject){
|
||
|
for(; i < l; ++i){
|
||
|
value = arr[i];
|
||
|
if(callback.call(thisObject, value, i, arr)){
|
||
|
out.push(value);
|
||
|
}
|
||
|
}
|
||
|
}else{
|
||
|
for(; i < l; ++i){
|
||
|
value = arr[i];
|
||
|
if(callback(value, i, arr)){
|
||
|
out.push(value);
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
return out; // Array
|
||
|
},
|
||
|
|
||
|
clearCache: function(){
|
||
|
cache = {};
|
||
|
}
|
||
|
};
|
||
|
|
||
|
|
||
|
1 && lang.mixin(dojo, array);
|
||
|
|
||
|
return array;
|
||
|
});
|
||
|
|
||
|
},
|
||
|
'dojo/text':function(){
|
||
|
define(["./_base/kernel", "require", "./has", "./request"], function(dojo, require, has, request){
|
||
|
// module:
|
||
|
// dojo/text
|
||
|
|
||
|
var getText;
|
||
|
if( 1 ){
|
||
|
getText= function(url, sync, load){
|
||
|
request(url, {sync:!!sync, headers: { 'X-Requested-With': null } }).then(load);
|
||
|
};
|
||
|
}else{
|
||
|
// Path for node.js and rhino, to load from local file system.
|
||
|
// TODO: use node.js native methods rather than depending on a require.getText() method to exist.
|
||
|
if(require.getText){
|
||
|
getText= require.getText;
|
||
|
}else{
|
||
|
console.error("dojo/text plugin failed to load because loader does not support getText");
|
||
|
}
|
||
|
}
|
||
|
|
||
|
var
|
||
|
theCache = {},
|
||
|
|
||
|
strip= function(text){
|
||
|
//Strips <?xml ...?> declarations so that external SVG and XML
|
||
|
//documents can be added to a document without worry. Also, if the string
|
||
|
//is an HTML document, only the part inside the body tag is returned.
|
||
|
if(text){
|
||
|
text= text.replace(/^\s*<\?xml(\s)+version=[\'\"](\d)*.(\d)*[\'\"](\s)*\?>/im, "");
|
||
|
var matches= text.match(/<body[^>]*>\s*([\s\S]+)\s*<\/body>/im);
|
||
|
if(matches){
|
||
|
text= matches[1];
|
||
|
}
|
||
|
}else{
|
||
|
text = "";
|
||
|
}
|
||
|
return text;
|
||
|
},
|
||
|
|
||
|
notFound = {},
|
||
|
|
||
|
pending = {};
|
||
|
|
||
|
dojo.cache = function(/*String||Object*/module, /*String*/url, /*String||Object?*/value){
|
||
|
// summary:
|
||
|
// A getter and setter for storing the string content associated with the
|
||
|
// module and url arguments.
|
||
|
// description:
|
||
|
// If module is a string that contains slashes, then it is interpretted as a fully
|
||
|
// resolved path (typically a result returned by require.toUrl), and url should not be
|
||
|
// provided. This is the preferred signature. If module is a string that does not
|
||
|
// contain slashes, then url must also be provided and module and url are used to
|
||
|
// call `dojo.moduleUrl()` to generate a module URL. This signature is deprecated.
|
||
|
// If value is specified, the cache value for the moduleUrl will be set to
|
||
|
// that value. Otherwise, dojo.cache will fetch the moduleUrl and store it
|
||
|
// in its internal cache and return that cached value for the URL. To clear
|
||
|
// a cache value pass null for value. Since XMLHttpRequest (XHR) is used to fetch the
|
||
|
// the URL contents, only modules on the same domain of the page can use this capability.
|
||
|
// The build system can inline the cache values though, to allow for xdomain hosting.
|
||
|
// module: String||Object
|
||
|
// If a String with slashes, a fully resolved path; if a String without slashes, the
|
||
|
// module name to use for the base part of the URL, similar to module argument
|
||
|
// to `dojo.moduleUrl`. If an Object, something that has a .toString() method that
|
||
|
// generates a valid path for the cache item. For example, a dojo._Url object.
|
||
|
// url: String
|
||
|
// The rest of the path to append to the path derived from the module argument. If
|
||
|
// module is an object, then this second argument should be the "value" argument instead.
|
||
|
// value: String||Object?
|
||
|
// If a String, the value to use in the cache for the module/url combination.
|
||
|
// If an Object, it can have two properties: value and sanitize. The value property
|
||
|
// should be the value to use in the cache, and sanitize can be set to true or false,
|
||
|
// to indicate if XML declarations should be removed from the value and if the HTML
|
||
|
// inside a body tag in the value should be extracted as the real value. The value argument
|
||
|
// or the value property on the value argument are usually only used by the build system
|
||
|
// as it inlines cache content.
|
||
|
// example:
|
||
|
// To ask dojo.cache to fetch content and store it in the cache (the dojo["cache"] style
|
||
|
// of call is used to avoid an issue with the build system erroneously trying to intern
|
||
|
// this example. To get the build system to intern your dojo.cache calls, use the
|
||
|
// "dojo.cache" style of call):
|
||
|
// | //If template.html contains "<h1>Hello</h1>" that will be
|
||
|
// | //the value for the text variable.
|
||
|
// | //Note: This is pre-AMD, deprecated syntax
|
||
|
// | var text = dojo["cache"]("my.module", "template.html");
|
||
|
// example:
|
||
|
// To ask dojo.cache to fetch content and store it in the cache, and sanitize the input
|
||
|
// (the dojo["cache"] style of call is used to avoid an issue with the build system
|
||
|
// erroneously trying to intern this example. To get the build system to intern your
|
||
|
// dojo.cache calls, use the "dojo.cache" style of call):
|
||
|
// | //If template.html contains "<html><body><h1>Hello</h1></body></html>", the
|
||
|
// | //text variable will contain just "<h1>Hello</h1>".
|
||
|
// | //Note: This is pre-AMD, deprecated syntax
|
||
|
// | var text = dojo["cache"]("my.module", "template.html", {sanitize: true});
|
||
|
// example:
|
||
|
// Same example as previous, but demonstrates how an object can be passed in as
|
||
|
// the first argument, then the value argument can then be the second argument.
|
||
|
// | //If template.html contains "<html><body><h1>Hello</h1></body></html>", the
|
||
|
// | //text variable will contain just "<h1>Hello</h1>".
|
||
|
// | //Note: This is pre-AMD, deprecated syntax
|
||
|
// | var text = dojo["cache"](new dojo._Url("my/module/template.html"), {sanitize: true});
|
||
|
|
||
|
// * (string string [value]) => (module, url, value)
|
||
|
// * (object [value]) => (module, value), url defaults to ""
|
||
|
//
|
||
|
// * if module is an object, then it must be convertable to a string
|
||
|
// * (module, url) module + (url ? ("/" + url) : "") must be a legal argument to require.toUrl
|
||
|
// * value may be a string or an object; if an object then may have the properties "value" and/or "sanitize"
|
||
|
var key;
|
||
|
if(typeof module=="string"){
|
||
|
if(/\//.test(module)){
|
||
|
// module is a version 1.7+ resolved path
|
||
|
key = module;
|
||
|
value = url;
|
||
|
}else{
|
||
|
// module is a version 1.6- argument to dojo.moduleUrl
|
||
|
key = require.toUrl(module.replace(/\./g, "/") + (url ? ("/" + url) : ""));
|
||
|
}
|
||
|
}else{
|
||
|
key = module + "";
|
||
|
value = url;
|
||
|
}
|
||
|
var
|
||
|
val = (value != undefined && typeof value != "string") ? value.value : value,
|
||
|
sanitize = value && value.sanitize;
|
||
|
|
||
|
if(typeof val == "string"){
|
||
|
//We have a string, set cache value
|
||
|
theCache[key] = val;
|
||
|
return sanitize ? strip(val) : val;
|
||
|
}else if(val === null){
|
||
|
//Remove cached value
|
||
|
delete theCache[key];
|
||
|
return null;
|
||
|
}else{
|
||
|
//Allow cache values to be empty strings. If key property does
|
||
|
//not exist, fetch it.
|
||
|
if(!(key in theCache)){
|
||
|
getText(key, true, function(text){
|
||
|
theCache[key]= text;
|
||
|
});
|
||
|
}
|
||
|
return sanitize ? strip(theCache[key]) : theCache[key];
|
||
|
}
|
||
|
};
|
||
|
|
||
|
return {
|
||
|
// summary:
|
||
|
// This module implements the dojo/text! plugin and the dojo.cache API.
|
||
|
// description:
|
||
|
// We choose to include our own plugin to leverage functionality already contained in dojo
|
||
|
// and thereby reduce the size of the plugin compared to various foreign loader implementations.
|
||
|
// Also, this allows foreign AMD loaders to be used without their plugins.
|
||
|
//
|
||
|
// CAUTION: this module is designed to optionally function synchronously to support the dojo v1.x synchronous
|
||
|
// loader. This feature is outside the scope of the CommonJS plugins specification.
|
||
|
|
||
|
// the dojo/text caches it's own resources because of dojo.cache
|
||
|
dynamic: true,
|
||
|
|
||
|
normalize: function(id, toAbsMid){
|
||
|
// id is something like (path may be relative):
|
||
|
//
|
||
|
// "path/to/text.html"
|
||
|
// "path/to/text.html!strip"
|
||
|
var parts= id.split("!"),
|
||
|
url= parts[0];
|
||
|
return (/^\./.test(url) ? toAbsMid(url) : url) + (parts[1] ? "!" + parts[1] : "");
|
||
|
},
|
||
|
|
||
|
load: function(id, require, load){
|
||
|
// id: String
|
||
|
// Path to the resource.
|
||
|
// require: Function
|
||
|
// Object that include the function toUrl with given id returns a valid URL from which to load the text.
|
||
|
// load: Function
|
||
|
// Callback function which will be called, when the loading finished.
|
||
|
|
||
|
// id is something like (path is always absolute):
|
||
|
//
|
||
|
// "path/to/text.html"
|
||
|
// "path/to/text.html!strip"
|
||
|
var
|
||
|
parts= id.split("!"),
|
||
|
stripFlag= parts.length>1,
|
||
|
absMid= parts[0],
|
||
|
url = require.toUrl(parts[0]),
|
||
|
requireCacheUrl = "url:" + url,
|
||
|
text = notFound,
|
||
|
finish = function(text){
|
||
|
load(stripFlag ? strip(text) : text);
|
||
|
};
|
||
|
if(absMid in theCache){
|
||
|
text = theCache[absMid];
|
||
|
}else if(require.cache && requireCacheUrl in require.cache){
|
||
|
text = require.cache[requireCacheUrl];
|
||
|
}else if(url in theCache){
|
||
|
text = theCache[url];
|
||
|
}
|
||
|
if(text===notFound){
|
||
|
if(pending[url]){
|
||
|
pending[url].push(finish);
|
||
|
}else{
|
||
|
var pendingList = pending[url] = [finish];
|
||
|
getText(url, !require.async, function(text){
|
||
|
theCache[absMid]= theCache[url]= text;
|
||
|
for(var i = 0; i<pendingList.length;){
|
||
|
pendingList[i++](text);
|
||
|
}
|
||
|
delete pending[url];
|
||
|
});
|
||
|
}
|
||
|
}else{
|
||
|
finish(text);
|
||
|
}
|
||
|
}
|
||
|
};
|
||
|
|
||
|
});
|
||
|
|
||
|
|
||
|
},
|
||
|
'dojo/request':function(){
|
||
|
define([
|
||
|
'./request/default!'/*=====,
|
||
|
'./_base/declare',
|
||
|
'./promise/Promise' =====*/
|
||
|
], function(request/*=====, declare, Promise =====*/){
|
||
|
/*=====
|
||
|
request = function(url, options){
|
||
|
// summary:
|
||
|
// Send a request using the default transport for the current platform.
|
||
|
// url: String
|
||
|
// The URL to request.
|
||
|
// options: dojo/request.__Options?
|
||
|
// Options for the request.
|
||
|
// returns: dojo/request.__Promise
|
||
|
};
|
||
|
request.__Promise = declare(Promise, {
|
||
|
// response: dojo/promise/Promise
|
||
|
// A promise resolving to an object representing
|
||
|
// the response from the server.
|
||
|
});
|
||
|
request.__BaseOptions = declare(null, {
|
||
|
// query: String|Object?
|
||
|
// Query parameters to append to the URL.
|
||
|
// data: String|Object?
|
||
|
// Data to transfer. This is ignored for GET and DELETE
|
||
|
// requests.
|
||
|
// preventCache: Boolean?
|
||
|
// Whether to append a cache-busting parameter to the URL.
|
||
|
// timeout: Integer?
|
||
|
// Milliseconds to wait for the response. If this time
|
||
|
// passes, the then the promise is rejected.
|
||
|
// handleAs: String?
|
||
|
// How to handle the response from the server. Default is
|
||
|
// 'text'. Other values are 'json', 'javascript', and 'xml'.
|
||
|
});
|
||
|
request.__MethodOptions = declare(null, {
|
||
|
// method: String?
|
||
|
// The HTTP method to use to make the request. Must be
|
||
|
// uppercase.
|
||
|
});
|
||
|
request.__Options = declare([request.__BaseOptions, request.__MethodOptions]);
|
||
|
|
||
|
request.get = function(url, options){
|
||
|
// summary:
|
||
|
// Send an HTTP GET request using the default transport for the current platform.
|
||
|
// url: String
|
||
|
// URL to request
|
||
|
// options: dojo/request.__BaseOptions?
|
||
|
// Options for the request.
|
||
|
// returns: dojo/request.__Promise
|
||
|
};
|
||
|
request.post = function(url, options){
|
||
|
// summary:
|
||
|
// Send an HTTP POST request using the default transport for the current platform.
|
||
|
// url: String
|
||
|
// URL to request
|
||
|
// options: dojo/request.__BaseOptions?
|
||
|
// Options for the request.
|
||
|
// returns: dojo/request.__Promise
|
||
|
};
|
||
|
request.put = function(url, options){
|
||
|
// summary:
|
||
|
// Send an HTTP POST request using the default transport for the current platform.
|
||
|
// url: String
|
||
|
// URL to request
|
||
|
// options: dojo/request.__BaseOptions?
|
||
|
// Options for the request.
|
||
|
// returns: dojo/request.__Promise
|
||
|
};
|
||
|
request.del = function(url, options){
|
||
|
// summary:
|
||
|
// Send an HTTP DELETE request using the default transport for the current platform.
|
||
|
// url: String
|
||
|
// URL to request
|
||
|
// options: dojo/request.__BaseOptions?
|
||
|
// Options for the request.
|
||
|
// returns: dojo/request.__Promise
|
||
|
};
|
||
|
=====*/
|
||
|
return request;
|
||
|
});
|
||
|
|
||
|
},
|
||
|
'dojo/request/default':function(){
|
||
|
define([
|
||
|
'exports',
|
||
|
'require',
|
||
|
'../has'
|
||
|
], function(exports, require, has){
|
||
|
var defId = has('config-requestProvider'),
|
||
|
platformId;
|
||
|
|
||
|
if( 1 || has('host-webworker')){
|
||
|
platformId = './xhr';
|
||
|
}else if( 0 ){
|
||
|
platformId = './node';
|
||
|
/* TODO:
|
||
|
}else if( 0 ){
|
||
|
platformId = './rhino';
|
||
|
*/
|
||
|
}
|
||
|
|
||
|
if(!defId){
|
||
|
defId = platformId;
|
||
|
}
|
||
|
|
||
|
exports.getPlatformDefaultId = function(){
|
||
|
return platformId;
|
||
|
};
|
||
|
|
||
|
exports.load = function(id, parentRequire, loaded, config){
|
||
|
require([id == 'platform' ? platformId : defId], function(provider){
|
||
|
loaded(provider);
|
||
|
});
|
||
|
};
|
||
|
});
|
||
|
|
||
|
},
|
||
|
'dojo/i18n':function(){
|
||
|
define(["./_base/kernel", "require", "./has", "./_base/array", "./_base/config", "./_base/lang", "./_base/xhr", "./json", "module"],
|
||
|
function(dojo, require, has, array, config, lang, xhr, json, module){
|
||
|
|
||
|
// module:
|
||
|
// dojo/i18n
|
||
|
|
||
|
has.add("dojo-preload-i18n-Api",
|
||
|
// if true, define the preload localizations machinery
|
||
|
1
|
||
|
);
|
||
|
|
||
|
1 || has.add("dojo-v1x-i18n-Api",
|
||
|
// if true, define the v1.x i18n functions
|
||
|
1
|
||
|
);
|
||
|
|
||
|
var
|
||
|
thisModule = dojo.i18n =
|
||
|
{
|
||
|
// summary:
|
||
|
// This module implements the dojo/i18n! plugin and the v1.6- i18n API
|
||
|
// description:
|
||
|
// We choose to include our own plugin to leverage functionality already contained in dojo
|
||
|
// and thereby reduce the size of the plugin compared to various loader implementations. Also, this
|
||
|
// allows foreign AMD loaders to be used without their plugins.
|
||
|
},
|
||
|
|
||
|
nlsRe =
|
||
|
// regexp for reconstructing the master bundle name from parts of the regexp match
|
||
|
// nlsRe.exec("foo/bar/baz/nls/en-ca/foo") gives:
|
||
|
// ["foo/bar/baz/nls/en-ca/foo", "foo/bar/baz/nls/", "/", "/", "en-ca", "foo"]
|
||
|
// nlsRe.exec("foo/bar/baz/nls/foo") gives:
|
||
|
// ["foo/bar/baz/nls/foo", "foo/bar/baz/nls/", "/", "/", "foo", ""]
|
||
|
// so, if match[5] is blank, it means this is the top bundle definition.
|
||
|
// courtesy of http://requirejs.org
|
||
|
/(^.*(^|\/)nls)(\/|$)([^\/]*)\/?([^\/]*)/,
|
||
|
|
||
|
getAvailableLocales = function(
|
||
|
root,
|
||
|
locale,
|
||
|
bundlePath,
|
||
|
bundleName
|
||
|
){
|
||
|
// summary:
|
||
|
// return a vector of module ids containing all available locales with respect to the target locale
|
||
|
// For example, assuming:
|
||
|
//
|
||
|
// - the root bundle indicates specific bundles for "fr" and "fr-ca",
|
||
|
// - bundlePath is "myPackage/nls"
|
||
|
// - bundleName is "myBundle"
|
||
|
//
|
||
|
// Then a locale argument of "fr-ca" would return
|
||
|
//
|
||
|
// ["myPackage/nls/myBundle", "myPackage/nls/fr/myBundle", "myPackage/nls/fr-ca/myBundle"]
|
||
|
//
|
||
|
// Notice that bundles are returned least-specific to most-specific, starting with the root.
|
||
|
//
|
||
|
// If root===false indicates we're working with a pre-AMD i18n bundle that doesn't tell about the available locales;
|
||
|
// therefore, assume everything is available and get 404 errors that indicate a particular localization is not available
|
||
|
|
||
|
for(var result = [bundlePath + bundleName], localeParts = locale.split("-"), current = "", i = 0; i<localeParts.length; i++){
|
||
|
current += (current ? "-" : "") + localeParts[i];
|
||
|
if(!root || root[current]){
|
||
|
result.push(bundlePath + current + "/" + bundleName);
|
||
|
result.specificity = current;
|
||
|
}
|
||
|
}
|
||
|
return result;
|
||
|
},
|
||
|
|
||
|
cache = {},
|
||
|
|
||
|
getBundleName = function(moduleName, bundleName, locale){
|
||
|
locale = locale ? locale.toLowerCase() : dojo.locale;
|
||
|
moduleName = moduleName.replace(/\./g, "/");
|
||
|
bundleName = bundleName.replace(/\./g, "/");
|
||
|
return (/root/i.test(locale)) ?
|
||
|
(moduleName + "/nls/" + bundleName) :
|
||
|
(moduleName + "/nls/" + locale + "/" + bundleName);
|
||
|
},
|
||
|
|
||
|
getL10nName = dojo.getL10nName = function(moduleName, bundleName, locale){
|
||
|
return moduleName = module.id + "!" + getBundleName(moduleName, bundleName, locale);
|
||
|
},
|
||
|
|
||
|
doLoad = function(require, bundlePathAndName, bundlePath, bundleName, locale, load){
|
||
|
// summary:
|
||
|
// get the root bundle which instructs which other bundles are required to construct the localized bundle
|
||
|
require([bundlePathAndName], function(root){
|
||
|
var current = lang.clone(root.root || root.ROOT),// 1.6 built bundle defined ROOT
|
||
|
availableLocales = getAvailableLocales(!root._v1x && root, locale, bundlePath, bundleName);
|
||
|
require(availableLocales, function(){
|
||
|
for (var i = 1; i<availableLocales.length; i++){
|
||
|
current = lang.mixin(lang.clone(current), arguments[i]);
|
||
|
}
|
||
|
// target may not have been resolve (e.g., maybe only "fr" exists when "fr-ca" was requested)
|
||
|
var target = bundlePathAndName + "/" + locale;
|
||
|
cache[target] = current;
|
||
|
current.$locale = availableLocales.specificity;
|
||
|
load();
|
||
|
});
|
||
|
});
|
||
|
},
|
||
|
|
||
|
normalize = function(id, toAbsMid){
|
||
|
// summary:
|
||
|
// id may be relative.
|
||
|
// preload has form `*preload*<path>/nls/<module>*<flattened locales>` and
|
||
|
// therefore never looks like a relative
|
||
|
return /^\./.test(id) ? toAbsMid(id) : id;
|
||
|
},
|
||
|
|
||
|
getLocalesToLoad = function(targetLocale){
|
||
|
var list = config.extraLocale || [];
|
||
|
list = lang.isArray(list) ? list : [list];
|
||
|
list.push(targetLocale);
|
||
|
return list;
|
||
|
},
|
||
|
|
||
|
load = function(id, require, load){
|
||
|
// summary:
|
||
|
// id is in one of the following formats
|
||
|
//
|
||
|
// 1. <path>/nls/<bundle>
|
||
|
// => load the bundle, localized to config.locale; load all bundles localized to
|
||
|
// config.extraLocale (if any); return the loaded bundle localized to config.locale.
|
||
|
//
|
||
|
// 2. <path>/nls/<locale>/<bundle>
|
||
|
// => load then return the bundle localized to <locale>
|
||
|
//
|
||
|
// 3. *preload*<path>/nls/<module>*<JSON array of available locales>
|
||
|
// => for config.locale and all config.extraLocale, load all bundles found
|
||
|
// in the best-matching bundle rollup. A value of 1 is returned, which
|
||
|
// is meaningless other than to say the plugin is executing the requested
|
||
|
// preloads
|
||
|
//
|
||
|
// In cases 1 and 2, <path> is always normalized to an absolute module id upon entry; see
|
||
|
// normalize. In case 3, it <path> is assumed to be absolute; this is arranged by the builder.
|
||
|
//
|
||
|
// To load a bundle means to insert the bundle into the plugin's cache and publish the bundle
|
||
|
// value to the loader. Given <path>, <bundle>, and a particular <locale>, the cache key
|
||
|
//
|
||
|
// <path>/nls/<bundle>/<locale>
|
||
|
//
|
||
|
// will hold the value. Similarly, then plugin will publish this value to the loader by
|
||
|
//
|
||
|
// define("<path>/nls/<bundle>/<locale>", <bundle-value>);
|
||
|
//
|
||
|
// Given this algorithm, other machinery can provide fast load paths be preplacing
|
||
|
// values in the plugin's cache, which is public. When a load is demanded the
|
||
|
// cache is inspected before starting any loading. Explicitly placing values in the plugin
|
||
|
// cache is an advanced/experimental feature that should not be needed; use at your own risk.
|
||
|
//
|
||
|
// For the normal AMD algorithm, the root bundle is loaded first, which instructs the
|
||
|
// plugin what additional localized bundles are required for a particular locale. These
|
||
|
// additional locales are loaded and a mix of the root and each progressively-specific
|
||
|
// locale is returned. For example:
|
||
|
//
|
||
|
// 1. The client demands "dojo/i18n!some/path/nls/someBundle
|
||
|
//
|
||
|
// 2. The loader demands load(some/path/nls/someBundle)
|
||
|
//
|
||
|
// 3. This plugin require's "some/path/nls/someBundle", which is the root bundle.
|
||
|
//
|
||
|
// 4. Assuming config.locale is "ab-cd-ef" and the root bundle indicates that localizations
|
||
|
// are available for "ab" and "ab-cd-ef" (note the missing "ab-cd", then the plugin
|
||
|
// requires "some/path/nls/ab/someBundle" and "some/path/nls/ab-cd-ef/someBundle"
|
||
|
//
|
||
|
// 5. Upon receiving all required bundles, the plugin constructs the value of the bundle
|
||
|
// ab-cd-ef as...
|
||
|
//
|
||
|
// mixin(mixin(mixin({}, require("some/path/nls/someBundle"),
|
||
|
// require("some/path/nls/ab/someBundle")),
|
||
|
// require("some/path/nls/ab-cd-ef/someBundle"));
|
||
|
//
|
||
|
// This value is inserted into the cache and published to the loader at the
|
||
|
// key/module-id some/path/nls/someBundle/ab-cd-ef.
|
||
|
//
|
||
|
// The special preload signature (case 3) instructs the plugin to stop servicing all normal requests
|
||
|
// (further preload requests will be serviced) until all ongoing preloading has completed.
|
||
|
//
|
||
|
// The preload signature instructs the plugin that a special rollup module is available that contains
|
||
|
// one or more flattened, localized bundles. The JSON array of available locales indicates which locales
|
||
|
// are available. Here is an example:
|
||
|
//
|
||
|
// *preload*some/path/nls/someModule*["root", "ab", "ab-cd-ef"]
|
||
|
//
|
||
|
// This indicates the following rollup modules are available:
|
||
|
//
|
||
|
// some/path/nls/someModule_ROOT
|
||
|
// some/path/nls/someModule_ab
|
||
|
// some/path/nls/someModule_ab-cd-ef
|
||
|
//
|
||
|
// Each of these modules is a normal AMD module that contains one or more flattened bundles in a hash.
|
||
|
// For example, assume someModule contained the bundles some/bundle/path/someBundle and
|
||
|
// some/bundle/path/someOtherBundle, then some/path/nls/someModule_ab would be expressed as follows:
|
||
|
//
|
||
|
// define({
|
||
|
// some/bundle/path/someBundle:<value of someBundle, flattened with respect to locale ab>,
|
||
|
// some/bundle/path/someOtherBundle:<value of someOtherBundle, flattened with respect to locale ab>,
|
||
|
// });
|
||
|
//
|
||
|
// E.g., given this design, preloading for locale=="ab" can execute the following algorithm:
|
||
|
//
|
||
|
// require(["some/path/nls/someModule_ab"], function(rollup){
|
||
|
// for(var p in rollup){
|
||
|
// var id = p + "/ab",
|
||
|
// cache[id] = rollup[p];
|
||
|
// define(id, rollup[p]);
|
||
|
// }
|
||
|
// });
|
||
|
//
|
||
|
// Similarly, if "ab-cd" is requested, the algorithm can determine that "ab" is the best available and
|
||
|
// load accordingly.
|
||
|
//
|
||
|
// The builder will write such rollups for every layer if a non-empty localeList profile property is
|
||
|
// provided. Further, the builder will include the following cache entry in the cache associated with
|
||
|
// any layer.
|
||
|
//
|
||
|
// "*now":function(r){r(['dojo/i18n!*preload*<path>/nls/<module>*<JSON array of available locales>']);}
|
||
|
//
|
||
|
// The *now special cache module instructs the loader to apply the provided function to context-require
|
||
|
// with respect to the particular layer being defined. This causes the plugin to hold all normal service
|
||
|
// requests until all preloading is complete.
|
||
|
//
|
||
|
// Notice that this algorithm is rarely better than the standard AMD load algorithm. Consider the normal case
|
||
|
// where the target locale has a single segment and a layer depends on a single bundle:
|
||
|
//
|
||
|
// Without Preloads:
|
||
|
//
|
||
|
// 1. Layer loads root bundle.
|
||
|
// 2. bundle is demanded; plugin loads single localized bundle.
|
||
|
//
|
||
|
// With Preloads:
|
||
|
//
|
||
|
// 1. Layer causes preloading of target bundle.
|
||
|
// 2. bundle is demanded; service is delayed until preloading complete; bundle is returned.
|
||
|
//
|
||
|
// In each case a single transaction is required to load the target bundle. In cases where multiple bundles
|
||
|
// are required and/or the locale has multiple segments, preloads still requires a single transaction whereas
|
||
|
// the normal path requires an additional transaction for each additional bundle/locale-segment. However all
|
||
|
// of these additional transactions can be done concurrently. Owing to this analysis, the entire preloading
|
||
|
// algorithm can be discard during a build by setting the has feature dojo-preload-i18n-Api to false.
|
||
|
|
||
|
var match = nlsRe.exec(id),
|
||
|
bundlePath = match[1] + "/",
|
||
|
bundleName = match[5] || match[4],
|
||
|
bundlePathAndName = bundlePath + bundleName,
|
||
|
localeSpecified = (match[5] && match[4]),
|
||
|
targetLocale = localeSpecified || dojo.locale || "",
|
||
|
loadTarget = bundlePathAndName + "/" + targetLocale,
|
||
|
loadList = localeSpecified ? [targetLocale] : getLocalesToLoad(targetLocale),
|
||
|
remaining = loadList.length,
|
||
|
finish = function(){
|
||
|
if(!--remaining){
|
||
|
load(lang.delegate(cache[loadTarget]));
|
||
|
}
|
||
|
},
|
||
|
split = id.split("*"),
|
||
|
preloadDemand = split[1] == "preload";
|
||
|
|
||
|
if(has("dojo-preload-i18n-Api")){
|
||
|
if(preloadDemand){
|
||
|
if(!cache[id]){
|
||
|
// use cache[id] to prevent multiple preloads of the same preload; this shouldn't happen, but
|
||
|
// who knows what over-aggressive human optimizers may attempt
|
||
|
cache[id] = 1;
|
||
|
preloadL10n(split[2], json.parse(split[3]), 1, require);
|
||
|
}
|
||
|
// don't stall the loader!
|
||
|
load(1);
|
||
|
}
|
||
|
if(preloadDemand || (waitForPreloads(id, require, load) && !cache[loadTarget])){
|
||
|
return;
|
||
|
}
|
||
|
}
|
||
|
else if (preloadDemand) {
|
||
|
// If a build is created with nls resources and 'dojo-preload-i18n-Api' has not been set to false,
|
||
|
// the built file will include a preload in the cache (which looks about like so:)
|
||
|
// '*now':function(r){r(['dojo/i18n!*preload*dojo/nls/dojo*["ar","ca","cs","da","de","el","en-gb","en-us","es-es","fi-fi","fr-fr","he-il","hu","it-it","ja-jp","ko-kr","nl-nl","nb","pl","pt-br","pt-pt","ru","sk","sl","sv","th","tr","zh-tw","zh-cn","ROOT"]']);}
|
||
|
// If the consumer of the build sets 'dojo-preload-i18n-Api' to false in the Dojo config, the cached
|
||
|
// preload will not be parsed and will result in an attempt to call 'require' passing it the unparsed
|
||
|
// preload, which is not a valid module id.
|
||
|
// In this case we should skip this request.
|
||
|
load(1);
|
||
|
|
||
|
return;
|
||
|
}
|
||
|
|
||
|
array.forEach(loadList, function(locale){
|
||
|
var target = bundlePathAndName + "/" + locale;
|
||
|
if(has("dojo-preload-i18n-Api")){
|
||
|
checkForLegacyModules(target);
|
||
|
}
|
||
|
if(!cache[target]){
|
||
|
doLoad(require, bundlePathAndName, bundlePath, bundleName, locale, finish);
|
||
|
}else{
|
||
|
finish();
|
||
|
}
|
||
|
});
|
||
|
};
|
||
|
|
||
|
if(has("dojo-preload-i18n-Api") || 1 ){
|
||
|
var normalizeLocale = thisModule.normalizeLocale = function(locale){
|
||
|
var result = locale ? locale.toLowerCase() : dojo.locale;
|
||
|
return result == "root" ? "ROOT" : result;
|
||
|
},
|
||
|
|
||
|
isXd = function(mid, contextRequire){
|
||
|
return ( 1 && 1 ) ?
|
||
|
contextRequire.isXdUrl(require.toUrl(mid + ".js")) :
|
||
|
true;
|
||
|
},
|
||
|
|
||
|
preloading = 0,
|
||
|
|
||
|
preloadWaitQueue = [],
|
||
|
|
||
|
preloadL10n = thisModule._preloadLocalizations = function(/*String*/bundlePrefix, /*Array*/localesGenerated, /*boolean?*/ guaranteedAmdFormat, /*function?*/ contextRequire){
|
||
|
// summary:
|
||
|
// Load available flattened resource bundles associated with a particular module for dojo/locale and all dojo/config.extraLocale (if any)
|
||
|
// description:
|
||
|
// Only called by built layer files. The entire locale hierarchy is loaded. For example,
|
||
|
// if locale=="ab-cd", then ROOT, "ab", and "ab-cd" are loaded. This is different than v1.6-
|
||
|
// in that the v1.6- would only load ab-cd...which was *always* flattened.
|
||
|
//
|
||
|
// If guaranteedAmdFormat is true, then the module can be loaded with require thereby circumventing the detection algorithm
|
||
|
// and the extra possible extra transaction.
|
||
|
|
||
|
// If this function is called from legacy code, then guaranteedAmdFormat and contextRequire will be undefined. Since the function
|
||
|
// needs a require in order to resolve module ids, fall back to the context-require associated with this dojo/i18n module, which
|
||
|
// itself may have been mapped.
|
||
|
contextRequire = contextRequire || require;
|
||
|
|
||
|
function doRequire(mid, callback){
|
||
|
if(isXd(mid, contextRequire) || guaranteedAmdFormat){
|
||
|
contextRequire([mid], callback);
|
||
|
}else{
|
||
|
syncRequire([mid], callback, contextRequire);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
function forEachLocale(locale, func){
|
||
|
// given locale= "ab-cd-ef", calls func on "ab-cd-ef", "ab-cd", "ab", "ROOT"; stops calling the first time func returns truthy
|
||
|
var parts = locale.split("-");
|
||
|
while(parts.length){
|
||
|
if(func(parts.join("-"))){
|
||
|
return;
|
||
|
}
|
||
|
parts.pop();
|
||
|
}
|
||
|
func("ROOT");
|
||
|
}
|
||
|
|
||
|
function preloadingAddLock(){
|
||
|
preloading++;
|
||
|
}
|
||
|
|
||
|
function preloadingRelLock(){
|
||
|
--preloading;
|
||
|
while(!preloading && preloadWaitQueue.length){
|
||
|
load.apply(null, preloadWaitQueue.shift());
|
||
|
}
|
||
|
}
|
||
|
|
||
|
function cacheId(path, name, loc, require){
|
||
|
// path is assumed to have a trailing "/"
|
||
|
return require.toAbsMid(path + name + "/" + loc)
|
||
|
}
|
||
|
|
||
|
function preload(locale){
|
||
|
locale = normalizeLocale(locale);
|
||
|
forEachLocale(locale, function(loc){
|
||
|
if(array.indexOf(localesGenerated, loc) >= 0){
|
||
|
var mid = bundlePrefix.replace(/\./g, "/") + "_" + loc;
|
||
|
preloadingAddLock();
|
||
|
doRequire(mid, function(rollup){
|
||
|
for(var p in rollup){
|
||
|
var bundle = rollup[p],
|
||
|
match = p.match(/(.+)\/([^\/]+)$/),
|
||
|
bundleName, bundlePath;
|
||
|
|
||
|
// If there is no match, the bundle is not a regular bundle from an AMD layer.
|
||
|
if (!match){continue;}
|
||
|
|
||
|
bundleName = match[2];
|
||
|
bundlePath = match[1] + "/";
|
||
|
|
||
|
// backcompat
|
||
|
if(!bundle._localized){continue;}
|
||
|
|
||
|
var localized;
|
||
|
if(loc === "ROOT"){
|
||
|
var root = localized = bundle._localized;
|
||
|
delete bundle._localized;
|
||
|
root.root = bundle;
|
||
|
cache[require.toAbsMid(p)] = root;
|
||
|
}else{
|
||
|
localized = bundle._localized;
|
||
|
cache[cacheId(bundlePath, bundleName, loc, require)] = bundle;
|
||
|
}
|
||
|
|
||
|
if(loc !== locale){
|
||
|
// capture some locale variables
|
||
|
var improveBundle = function improveBundle(bundlePath, bundleName, bundle, localized){
|
||
|
// locale was not flattened and we've fallen back to a less-specific locale that was flattened
|
||
|
// for example, we had a flattened 'fr', a 'fr-ca' is available for at least this bundle, and
|
||
|
// locale==='fr-ca'; therefore, we must improve the bundle as retrieved from the rollup by
|
||
|
// manually loading the fr-ca version of the bundle and mixing this into the already-retrieved 'fr'
|
||
|
// version of the bundle.
|
||
|
//
|
||
|
// Remember, different bundles may have different sets of locales available.
|
||
|
//
|
||
|
// we are really falling back on the regular algorithm here, but--hopefully--starting with most
|
||
|
// of the required bundles already on board as given by the rollup and we need to "manually" load
|
||
|
// only one locale from a few bundles...or even better...we won't find anything better to load.
|
||
|
// This algorithm ensures there is nothing better to load even when we can only load a less-specific rollup.
|
||
|
//
|
||
|
// note: this feature is only available in async mode
|
||
|
|
||
|
// inspect the loaded bundle that came from the rollup to see if something better is available
|
||
|
// for any bundle in a rollup, more-specific available locales are given at localized.
|
||
|
var requiredBundles = [],
|
||
|
cacheIds = [];
|
||
|
forEachLocale(locale, function(loc){
|
||
|
if(localized[loc]){
|
||
|
requiredBundles.push(require.toAbsMid(bundlePath + loc + "/" + bundleName));
|
||
|
cacheIds.push(cacheId(bundlePath, bundleName, loc, require));
|
||
|
}
|
||
|
});
|
||
|
|
||
|
if(requiredBundles.length){
|
||
|
preloadingAddLock();
|
||
|
contextRequire(requiredBundles, function(){
|
||
|
// requiredBundles was constructed by forEachLocale so it contains locales from
|
||
|
// less specific to most specific.
|
||
|
// the loop starts with the most specific locale, the last one.
|
||
|
for(var i = requiredBundles.length - 1; i >= 0 ; i--){
|
||
|
bundle = lang.mixin(lang.clone(bundle), arguments[i]);
|
||
|
cache[cacheIds[i]] = bundle;
|
||
|
}
|
||
|
// this is the best possible (maybe a perfect match, maybe not), accept it
|
||
|
cache[cacheId(bundlePath, bundleName, locale, require)] = lang.clone(bundle);
|
||
|
preloadingRelLock();
|
||
|
});
|
||
|
}else{
|
||
|
// this is the best possible (definitely not a perfect match), accept it
|
||
|
cache[cacheId(bundlePath, bundleName, locale, require)] = bundle;
|
||
|
}
|
||
|
};
|
||
|
improveBundle(bundlePath, bundleName, bundle, localized);
|
||
|
}
|
||
|
}
|
||
|
preloadingRelLock();
|
||
|
});
|
||
|
return true;
|
||
|
}
|
||
|
return false;
|
||
|
});
|
||
|
}
|
||
|
|
||
|
preload();
|
||
|
array.forEach(dojo.config.extraLocale, preload);
|
||
|
},
|
||
|
|
||
|
waitForPreloads = function(id, require, load){
|
||
|
if(preloading){
|
||
|
preloadWaitQueue.push([id, require, load]);
|
||
|
}
|
||
|
return preloading;
|
||
|
},
|
||
|
|
||
|
checkForLegacyModules = function()
|
||
|
{};
|
||
|
}
|
||
|
|
||
|
if( 1 ){
|
||
|
// this code path assumes the dojo loader and won't work with a standard AMD loader
|
||
|
var amdValue = {},
|
||
|
l10nCache = {},
|
||
|
evalBundle,
|
||
|
|
||
|
syncRequire = function(deps, callback, require){
|
||
|
var results = [];
|
||
|
array.forEach(deps, function(mid){
|
||
|
var url = require.toUrl(mid + ".js");
|
||
|
|
||
|
function load(text){
|
||
|
if (!evalBundle) {
|
||
|
// use the function ctor to keep the minifiers away (also come close to global scope, but this is secondary)
|
||
|
evalBundle = new Function(
|
||
|
"__bundle", // the bundle to evalutate
|
||
|
"__checkForLegacyModules", // a function that checks if __bundle defined __mid in the global space
|
||
|
"__mid", // the mid that __bundle is intended to define
|
||
|
"__amdValue",
|
||
|
|
||
|
// returns one of:
|
||
|
// 1 => the bundle was an AMD bundle
|
||
|
// a legacy bundle object that is the value of __mid
|
||
|
// instance of Error => could not figure out how to evaluate bundle
|
||
|
|
||
|
// used to detect when __bundle calls define
|
||
|
"var define = function(mid, factory){define.called = 1; __amdValue.result = factory || mid;},"
|
||
|
+ " require = function(){define.called = 1;};"
|
||
|
|
||
|
+ "try{"
|
||
|
+ "define.called = 0;"
|
||
|
+ "eval(__bundle);"
|
||
|
+ "if(define.called==1)"
|
||
|
// bundle called define; therefore signal it's an AMD bundle
|
||
|
+ "return __amdValue;"
|
||
|
|
||
|
+ "if((__checkForLegacyModules = __checkForLegacyModules(__mid)))"
|
||
|
// bundle was probably a v1.6- built NLS flattened NLS bundle that defined __mid in the global space
|
||
|
+ "return __checkForLegacyModules;"
|
||
|
|
||
|
+ "}catch(e){}"
|
||
|
// evaulating the bundle was *neither* an AMD *nor* a legacy flattened bundle
|
||
|
// either way, re-eval *after* surrounding with parentheses
|
||
|
|
||
|
+ "try{"
|
||
|
+ "return eval('('+__bundle+')');"
|
||
|
+ "}catch(e){"
|
||
|
+ "return e;"
|
||
|
+ "}"
|
||
|
);
|
||
|
}
|
||
|
var result = evalBundle(text, checkForLegacyModules, mid, amdValue);
|
||
|
if(result===amdValue){
|
||
|
// the bundle was an AMD module; re-inject it through the normal AMD path
|
||
|
// we gotta do this since it could be an anonymous module and simply evaluating
|
||
|
// the text here won't provide the loader with the context to know what
|
||
|
// module is being defined()'d. With browser caching, this should be free; further
|
||
|
// this entire code path can be circumvented by using the AMD format to begin with
|
||
|
results.push(cache[url] = amdValue.result);
|
||
|
}else{
|
||
|
if(result instanceof Error){
|
||
|
console.error("failed to evaluate i18n bundle; url=" + url, result);
|
||
|
result = {};
|
||
|
}
|
||
|
// nls/<locale>/<bundle-name> indicates not the root.
|
||
|
results.push(cache[url] = (/nls\/[^\/]+\/[^\/]+$/.test(url) ? result : {root:result, _v1x:1}));
|
||
|
}
|
||
|
}
|
||
|
|
||
|
if(cache[url]){
|
||
|
results.push(cache[url]);
|
||
|
}else{
|
||
|
var bundle = require.syncLoadNls(mid);
|
||
|
// need to check for legacy module here because there might be a legacy module for a
|
||
|
// less specific locale (which was not looked up during the first checkForLegacyModules
|
||
|
// call in load()).
|
||
|
// Also need to reverse the locale and the module name in the mid because syncRequire
|
||
|
// deps parameters uses the AMD style package/nls/locale/module while legacy code uses
|
||
|
// package/nls/module/locale.
|
||
|
if(!bundle){
|
||
|
bundle = checkForLegacyModules(mid.replace(/nls\/([^\/]*)\/([^\/]*)$/, "nls/$2/$1"));
|
||
|
}
|
||
|
if(bundle){
|
||
|
results.push(bundle);
|
||
|
}else{
|
||
|
if(!xhr){
|
||
|
try{
|
||
|
require.getText(url, true, load);
|
||
|
}catch(e){
|
||
|
results.push(cache[url] = {});
|
||
|
}
|
||
|
}else{
|
||
|
xhr.get({
|
||
|
url:url,
|
||
|
sync:true,
|
||
|
load:load,
|
||
|
error:function(){
|
||
|
results.push(cache[url] = {});
|
||
|
}
|
||
|
});
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
});
|
||
|
callback && callback.apply(null, results);
|
||
|
};
|
||
|
|
||
|
checkForLegacyModules = function(target){
|
||
|
// legacy code may have already loaded [e.g] the raw bundle x/y/z at x.y.z; when true, push into the cache
|
||
|
for(var result, names = target.split("/"), object = dojo.global[names[0]], i = 1; object && i<names.length-1; object = object[names[i++]]){}
|
||
|
if(object){
|
||
|
result = object[names[i]];
|
||
|
if(!result){
|
||
|
// fallback for incorrect bundle build of 1.6
|
||
|
result = object[names[i].replace(/-/g,"_")];
|
||
|
}
|
||
|
if(result){
|
||
|
cache[target] = result;
|
||
|
}
|
||
|
}
|
||
|
return result;
|
||
|
};
|
||
|
|
||
|
thisModule.getLocalization = function(moduleName, bundleName, locale){
|
||
|
var result,
|
||
|
l10nName = getBundleName(moduleName, bundleName, locale);
|
||
|
|
||
|
if (l10nCache[l10nName]) {
|
||
|
return l10nCache[l10nName];
|
||
|
}
|
||
|
|
||
|
load(
|
||
|
l10nName,
|
||
|
|
||
|
// isXd() and syncRequire() need a context-require in order to resolve the mid with respect to a reference module.
|
||
|
// Since this legacy function does not have the concept of a reference module, resolve with respect to this
|
||
|
// dojo/i18n module, which, itself may have been mapped.
|
||
|
(!isXd(l10nName, require) ? function(deps, callback){ syncRequire(deps, callback, require); } : require),
|
||
|
|
||
|
function(result_){
|
||
|
l10nCache[l10nName] = result_;
|
||
|
result = result_;
|
||
|
}
|
||
|
);
|
||
|
return result;
|
||
|
};
|
||
|
}
|
||
|
else {
|
||
|
thisModule.getLocalization = function(moduleName, bundleName, locale){
|
||
|
var key = moduleName.replace(/\./g, '/') + '/nls/' + bundleName + '/' + (locale || config.locale);
|
||
|
return this.cache[key];
|
||
|
};
|
||
|
}
|
||
|
|
||
|
return lang.mixin(thisModule, {
|
||
|
dynamic:true,
|
||
|
normalize:normalize,
|
||
|
load:load,
|
||
|
cache:cache,
|
||
|
getL10nName: getL10nName
|
||
|
});
|
||
|
});
|
||
|
|
||
|
},
|
||
|
'dojo/_base/xhr':function(){
|
||
|
define([
|
||
|
"./kernel",
|
||
|
"./sniff",
|
||
|
"require",
|
||
|
"../io-query",
|
||
|
/*===== "./declare", =====*/
|
||
|
"../dom",
|
||
|
"../dom-form",
|
||
|
"./Deferred",
|
||
|
"./config",
|
||
|
"./json",
|
||
|
"./lang",
|
||
|
"./array",
|
||
|
"../on",
|
||
|
"../aspect",
|
||
|
"../request/watch",
|
||
|
"../request/xhr",
|
||
|
"../request/util"
|
||
|
], function(dojo, has, require, ioq, /*===== declare, =====*/ dom, domForm, Deferred, config, json, lang, array, on, aspect, watch, _xhr, util){
|
||
|
// module:
|
||
|
// dojo/_base/xhr
|
||
|
|
||
|
/*=====
|
||
|
dojo._xhrObj = function(){
|
||
|
// summary:
|
||
|
// does the work of portably generating a new XMLHTTPRequest object.
|
||
|
};
|
||
|
=====*/
|
||
|
dojo._xhrObj = _xhr._create;
|
||
|
|
||
|
var cfg = dojo.config;
|
||
|
|
||
|
// mix in io-query and dom-form
|
||
|
dojo.objectToQuery = ioq.objectToQuery;
|
||
|
dojo.queryToObject = ioq.queryToObject;
|
||
|
dojo.fieldToObject = domForm.fieldToObject;
|
||
|
dojo.formToObject = domForm.toObject;
|
||
|
dojo.formToQuery = domForm.toQuery;
|
||
|
dojo.formToJson = domForm.toJson;
|
||
|
|
||
|
// need to block async callbacks from snatching this thread as the result
|
||
|
// of an async callback might call another sync XHR, this hangs khtml forever
|
||
|
// must checked by watchInFlight()
|
||
|
|
||
|
dojo._blockAsync = false;
|
||
|
|
||
|
// MOW: remove dojo._contentHandlers alias in 2.0
|
||
|
var handlers = dojo._contentHandlers = dojo.contentHandlers = {
|
||
|
// summary:
|
||
|
// A map of available XHR transport handle types. Name matches the
|
||
|
// `handleAs` attribute passed to XHR calls.
|
||
|
// description:
|
||
|
// A map of available XHR transport handle types. Name matches the
|
||
|
// `handleAs` attribute passed to XHR calls. Each contentHandler is
|
||
|
// called, passing the xhr object for manipulation. The return value
|
||
|
// from the contentHandler will be passed to the `load` or `handle`
|
||
|
// functions defined in the original xhr call.
|
||
|
// example:
|
||
|
// Creating a custom content-handler:
|
||
|
// | xhr.contentHandlers.makeCaps = function(xhr){
|
||
|
// | return xhr.responseText.toUpperCase();
|
||
|
// | }
|
||
|
// | // and later:
|
||
|
// | dojo.xhrGet({
|
||
|
// | url:"foo.txt",
|
||
|
// | handleAs:"makeCaps",
|
||
|
// | load: function(data){ /* data is a toUpper version of foo.txt */ }
|
||
|
// | });
|
||
|
|
||
|
"text": function(xhr){
|
||
|
// summary:
|
||
|
// A contentHandler which simply returns the plaintext response data
|
||
|
return xhr.responseText;
|
||
|
},
|
||
|
"json": function(xhr){
|
||
|
// summary:
|
||
|
// A contentHandler which returns a JavaScript object created from the response data
|
||
|
return json.fromJson(xhr.responseText || null);
|
||
|
},
|
||
|
"json-comment-filtered": function(xhr){
|
||
|
// summary:
|
||
|
// A contentHandler which expects comment-filtered JSON.
|
||
|
// description:
|
||
|
// A contentHandler which expects comment-filtered JSON.
|
||
|
// the json-comment-filtered option was implemented to prevent
|
||
|
// "JavaScript Hijacking", but it is less secure than standard JSON. Use
|
||
|
// standard JSON instead. JSON prefixing can be used to subvert hijacking.
|
||
|
//
|
||
|
// Will throw a notice suggesting to use application/json mimetype, as
|
||
|
// json-commenting can introduce security issues. To decrease the chances of hijacking,
|
||
|
// use the standard `json` contentHandler, and prefix your "JSON" with: {}&&
|
||
|
//
|
||
|
// use djConfig.useCommentedJson = true to turn off the notice
|
||
|
if(!config.useCommentedJson){
|
||
|
console.warn("Consider using the standard mimetype:application/json."
|
||
|
+ " json-commenting can introduce security issues. To"
|
||
|
+ " decrease the chances of hijacking, use the standard the 'json' handler and"
|
||
|
+ " prefix your json with: {}&&\n"
|
||
|
+ "Use djConfig.useCommentedJson=true to turn off this message.");
|
||
|
}
|
||
|
|
||
|
var value = xhr.responseText;
|
||
|
var cStartIdx = value.indexOf("\/*");
|
||
|
var cEndIdx = value.lastIndexOf("*\/");
|
||
|
if(cStartIdx == -1 || cEndIdx == -1){
|
||
|
throw new Error("JSON was not comment filtered");
|
||
|
}
|
||
|
return json.fromJson(value.substring(cStartIdx+2, cEndIdx));
|
||
|
},
|
||
|
"javascript": function(xhr){
|
||
|
// summary:
|
||
|
// A contentHandler which evaluates the response data, expecting it to be valid JavaScript
|
||
|
|
||
|
// FIXME: try Moz and IE specific eval variants?
|
||
|
return dojo.eval(xhr.responseText);
|
||
|
},
|
||
|
"xml": function(xhr){
|
||
|
// summary:
|
||
|
// A contentHandler returning an XML Document parsed from the response data
|
||
|
var result = xhr.responseXML;
|
||
|
|
||
|
if(result && has("dom-qsa2.1") && !result.querySelectorAll && has("dom-parser")){
|
||
|
// http://bugs.dojotoolkit.org/ticket/15631
|
||
|
// IE9 supports a CSS3 querySelectorAll implementation, but the DOM implementation
|
||
|
// returned by IE9 xhr.responseXML does not. Manually create the XML DOM to gain
|
||
|
// the fuller-featured implementation and avoid bugs caused by the inconsistency
|
||
|
result = new DOMParser().parseFromString(xhr.responseText, "application/xml");
|
||
|
}
|
||
|
|
||
|
if(has("ie")){
|
||
|
if((!result || !result.documentElement)){
|
||
|
//WARNING: this branch used by the xml handling in dojo.io.iframe,
|
||
|
//so be sure to test dojo.io.iframe if making changes below.
|
||
|
var ms = function(n){ return "MSXML" + n + ".DOMDocument"; };
|
||
|
var dp = ["Microsoft.XMLDOM", ms(6), ms(4), ms(3), ms(2)];
|
||
|
array.some(dp, function(p){
|
||
|
try{
|
||
|
var dom = new ActiveXObject(p);
|
||
|
dom.async = false;
|
||
|
dom.loadXML(xhr.responseText);
|
||
|
result = dom;
|
||
|
}catch(e){ return false; }
|
||
|
return true;
|
||
|
});
|
||
|
}
|
||
|
}
|
||
|
return result; // DOMDocument
|
||
|
},
|
||
|
"json-comment-optional": function(xhr){
|
||
|
// summary:
|
||
|
// A contentHandler which checks the presence of comment-filtered JSON and
|
||
|
// alternates between the `json` and `json-comment-filtered` contentHandlers.
|
||
|
if(xhr.responseText && /^[^{\[]*\/\*/.test(xhr.responseText)){
|
||
|
return handlers["json-comment-filtered"](xhr);
|
||
|
}else{
|
||
|
return handlers["json"](xhr);
|
||
|
}
|
||
|
}
|
||
|
};
|
||
|
|
||
|
/*=====
|
||
|
|
||
|
// kwargs function parameter definitions. Assigning to dojo namespace rather than making them local variables
|
||
|
// because they are used by dojo/io modules too
|
||
|
|
||
|
dojo.__IoArgs = declare(null, {
|
||
|
// url: String
|
||
|
// URL to server endpoint.
|
||
|
// content: Object?
|
||
|
// Contains properties with string values. These
|
||
|
// properties will be serialized as name1=value2 and
|
||
|
// passed in the request.
|
||
|
// timeout: Integer?
|
||
|
// Milliseconds to wait for the response. If this time
|
||
|
// passes, the then error callbacks are called.
|
||
|
// form: DOMNode?
|
||
|
// DOM node for a form. Used to extract the form values
|
||
|
// and send to the server.
|
||
|
// preventCache: Boolean?
|
||
|
// Default is false. If true, then a
|
||
|
// "dojo.preventCache" parameter is sent in the request
|
||
|
// with a value that changes with each request
|
||
|
// (timestamp). Useful only with GET-type requests.
|
||
|
// handleAs: String?
|
||
|
// Acceptable values depend on the type of IO
|
||
|
// transport (see specific IO calls for more information).
|
||
|
// rawBody: String?
|
||
|
// Sets the raw body for an HTTP request. If this is used, then the content
|
||
|
// property is ignored. This is mostly useful for HTTP methods that have
|
||
|
// a body to their requests, like PUT or POST. This property can be used instead
|
||
|
// of postData and putData for dojo/_base/xhr.rawXhrPost and dojo/_base/xhr.rawXhrPut respectively.
|
||
|
// ioPublish: Boolean?
|
||
|
// Set this explicitly to false to prevent publishing of topics related to
|
||
|
// IO operations. Otherwise, if djConfig.ioPublish is set to true, topics
|
||
|
// will be published via dojo/topic.publish() for different phases of an IO operation.
|
||
|
// See dojo/main.__IoPublish for a list of topics that are published.
|
||
|
|
||
|
load: function(response, ioArgs){
|
||
|
// summary:
|
||
|
// This function will be
|
||
|
// called on a successful HTTP response code.
|
||
|
// ioArgs: dojo/main.__IoCallbackArgs
|
||
|
// Provides additional information about the request.
|
||
|
// response: Object
|
||
|
// The response in the format as defined with handleAs.
|
||
|
},
|
||
|
|
||
|
error: function(response, ioArgs){
|
||
|
// summary:
|
||
|
// This function will
|
||
|
// be called when the request fails due to a network or server error, the url
|
||
|
// is invalid, etc. It will also be called if the load or handle callback throws an
|
||
|
// exception, unless djConfig.debugAtAllCosts is true. This allows deployed applications
|
||
|
// to continue to run even when a logic error happens in the callback, while making
|
||
|
// it easier to troubleshoot while in debug mode.
|
||
|
// ioArgs: dojo/main.__IoCallbackArgs
|
||
|
// Provides additional information about the request.
|
||
|
// response: Object
|
||
|
// The response in the format as defined with handleAs.
|
||
|
},
|
||
|
|
||
|
handle: function(loadOrError, response, ioArgs){
|
||
|
// summary:
|
||
|
// This function will
|
||
|
// be called at the end of every request, whether or not an error occurs.
|
||
|
// loadOrError: String
|
||
|
// Provides a string that tells you whether this function
|
||
|
// was called because of success (load) or failure (error).
|
||
|
// response: Object
|
||
|
// The response in the format as defined with handleAs.
|
||
|
// ioArgs: dojo/main.__IoCallbackArgs
|
||
|
// Provides additional information about the request.
|
||
|
}
|
||
|
});
|
||
|
|
||
|
dojo.__IoCallbackArgs = declare(null, {
|
||
|
// args: Object
|
||
|
// the original object argument to the IO call.
|
||
|
// xhr: XMLHttpRequest
|
||
|
// For XMLHttpRequest calls only, the
|
||
|
// XMLHttpRequest object that was used for the
|
||
|
// request.
|
||
|
// url: String
|
||
|
// The final URL used for the call. Many times it
|
||
|
// will be different than the original args.url
|
||
|
// value.
|
||
|
// query: String
|
||
|
// For non-GET requests, the
|
||
|
// name1=value1&name2=value2 parameters sent up in
|
||
|
// the request.
|
||
|
// handleAs: String
|
||
|
// The final indicator on how the response will be
|
||
|
// handled.
|
||
|
// id: String
|
||
|
// For dojo/io/script calls only, the internal
|
||
|
// script ID used for the request.
|
||
|
// canDelete: Boolean
|
||
|
// For dojo/io/script calls only, indicates
|
||
|
// whether the script tag that represents the
|
||
|
// request can be deleted after callbacks have
|
||
|
// been called. Used internally to know when
|
||
|
// cleanup can happen on JSONP-type requests.
|
||
|
// json: Object
|
||
|
// For dojo/io/script calls only: holds the JSON
|
||
|
// response for JSONP-type requests. Used
|
||
|
// internally to hold on to the JSON responses.
|
||
|
// You should not need to access it directly --
|
||
|
// the same object should be passed to the success
|
||
|
// callbacks directly.
|
||
|
});
|
||
|
|
||
|
dojo.__IoPublish = declare(null, {
|
||
|
// summary:
|
||
|
// This is a list of IO topics that can be published
|
||
|
// if djConfig.ioPublish is set to true. IO topics can be
|
||
|
// published for any Input/Output, network operation. So,
|
||
|
// dojo.xhr, dojo.io.script and dojo.io.iframe can all
|
||
|
// trigger these topics to be published.
|
||
|
// start: String
|
||
|
// "/dojo/io/start" is sent when there are no outstanding IO
|
||
|
// requests, and a new IO request is started. No arguments
|
||
|
// are passed with this topic.
|
||
|
// send: String
|
||
|
// "/dojo/io/send" is sent whenever a new IO request is started.
|
||
|
// It passes the dojo.Deferred for the request with the topic.
|
||
|
// load: String
|
||
|
// "/dojo/io/load" is sent whenever an IO request has loaded
|
||
|
// successfully. It passes the response and the dojo.Deferred
|
||
|
// for the request with the topic.
|
||
|
// error: String
|
||
|
// "/dojo/io/error" is sent whenever an IO request has errored.
|
||
|
// It passes the error and the dojo.Deferred
|
||
|
// for the request with the topic.
|
||
|
// done: String
|
||
|
// "/dojo/io/done" is sent whenever an IO request has completed,
|
||
|
// either by loading or by erroring. It passes the error and
|
||
|
// the dojo.Deferred for the request with the topic.
|
||
|
// stop: String
|
||
|
// "/dojo/io/stop" is sent when all outstanding IO requests have
|
||
|
// finished. No arguments are passed with this topic.
|
||
|
});
|
||
|
=====*/
|
||
|
|
||
|
|
||
|
dojo._ioSetArgs = function(/*dojo/main.__IoArgs*/args,
|
||
|
/*Function*/canceller,
|
||
|
/*Function*/okHandler,
|
||
|
/*Function*/errHandler){
|
||
|
// summary:
|
||
|
// sets up the Deferred and ioArgs property on the Deferred so it
|
||
|
// can be used in an io call.
|
||
|
// args:
|
||
|
// The args object passed into the public io call. Recognized properties on
|
||
|
// the args object are:
|
||
|
// canceller:
|
||
|
// The canceller function used for the Deferred object. The function
|
||
|
// will receive one argument, the Deferred object that is related to the
|
||
|
// canceller.
|
||
|
// okHandler:
|
||
|
// The first OK callback to be registered with Deferred. It has the opportunity
|
||
|
// to transform the OK response. It will receive one argument -- the Deferred
|
||
|
// object returned from this function.
|
||
|
// errHandler:
|
||
|
// The first error callback to be registered with Deferred. It has the opportunity
|
||
|
// to do cleanup on an error. It will receive two arguments: error (the
|
||
|
// Error object) and dfd, the Deferred object returned from this function.
|
||
|
|
||
|
var ioArgs = {args: args, url: args.url};
|
||
|
|
||
|
//Get values from form if requested.
|
||
|
var formObject = null;
|
||
|
if(args.form){
|
||
|
var form = dom.byId(args.form);
|
||
|
//IE requires going through getAttributeNode instead of just getAttribute in some form cases,
|
||
|
//so use it for all. See #2844
|
||
|
var actnNode = form.getAttributeNode("action");
|
||
|
ioArgs.url = ioArgs.url || (actnNode ? actnNode.value : (dojo.doc ? dojo.doc.URL : null));
|
||
|
formObject = domForm.toObject(form);
|
||
|
}
|
||
|
|
||
|
// set up the query params
|
||
|
var miArgs = {};
|
||
|
|
||
|
if(formObject){
|
||
|
// potentially over-ride url-provided params w/ form values
|
||
|
lang.mixin(miArgs, formObject);
|
||
|
}
|
||
|
if(args.content){
|
||
|
// stuff in content over-rides what's set by form
|
||
|
lang.mixin(miArgs, args.content);
|
||
|
}
|
||
|
if(args.preventCache){
|
||
|
miArgs["dojo.preventCache"] = new Date().valueOf();
|
||
|
}
|
||
|
ioArgs.query = ioq.objectToQuery(miArgs);
|
||
|
|
||
|
// .. and the real work of getting the deferred in order, etc.
|
||
|
ioArgs.handleAs = args.handleAs || "text";
|
||
|
var d = new Deferred(function(dfd){
|
||
|
dfd.canceled = true;
|
||
|
canceller && canceller(dfd);
|
||
|
|
||
|
var err = dfd.ioArgs.error;
|
||
|
if(!err){
|
||
|
err = new Error("request cancelled");
|
||
|
err.dojoType="cancel";
|
||
|
dfd.ioArgs.error = err;
|
||
|
}
|
||
|
return err;
|
||
|
});
|
||
|
d.addCallback(okHandler);
|
||
|
|
||
|
//Support specifying load, error and handle callback functions from the args.
|
||
|
//For those callbacks, the "this" object will be the args object.
|
||
|
//The callbacks will get the deferred result value as the
|
||
|
//first argument and the ioArgs object as the second argument.
|
||
|
var ld = args.load;
|
||
|
if(ld && lang.isFunction(ld)){
|
||
|
d.addCallback(function(value){
|
||
|
return ld.call(args, value, ioArgs);
|
||
|
});
|
||
|
}
|
||
|
var err = args.error;
|
||
|
if(err && lang.isFunction(err)){
|
||
|
d.addErrback(function(value){
|
||
|
return err.call(args, value, ioArgs);
|
||
|
});
|
||
|
}
|
||
|
var handle = args.handle;
|
||
|
if(handle && lang.isFunction(handle)){
|
||
|
d.addBoth(function(value){
|
||
|
return handle.call(args, value, ioArgs);
|
||
|
});
|
||
|
}
|
||
|
|
||
|
// Attach error handler last (not including topic publishing)
|
||
|
// to catch any errors that may have been generated from load
|
||
|
// or handle functions.
|
||
|
d.addErrback(function(error){
|
||
|
return errHandler(error, d);
|
||
|
});
|
||
|
|
||
|
//Plug in topic publishing, if dojo.publish is loaded.
|
||
|
if(cfg.ioPublish && dojo.publish && ioArgs.args.ioPublish !== false){
|
||
|
d.addCallbacks(
|
||
|
function(res){
|
||
|
dojo.publish("/dojo/io/load", [d, res]);
|
||
|
return res;
|
||
|
},
|
||
|
function(res){
|
||
|
dojo.publish("/dojo/io/error", [d, res]);
|
||
|
return res;
|
||
|
}
|
||
|
);
|
||
|
d.addBoth(function(res){
|
||
|
dojo.publish("/dojo/io/done", [d, res]);
|
||
|
return res;
|
||
|
});
|
||
|
}
|
||
|
|
||
|
d.ioArgs = ioArgs;
|
||
|
|
||
|
// FIXME: need to wire up the xhr object's abort method to something
|
||
|
// analogous in the Deferred
|
||
|
return d;
|
||
|
};
|
||
|
|
||
|
var _deferredOk = function(/*Deferred*/dfd){
|
||
|
// summary:
|
||
|
// okHandler function for dojo._ioSetArgs call.
|
||
|
|
||
|
var ret = handlers[dfd.ioArgs.handleAs](dfd.ioArgs.xhr);
|
||
|
return ret === undefined ? null : ret;
|
||
|
};
|
||
|
var _deferError = function(/*Error*/error, /*Deferred*/dfd){
|
||
|
// summary:
|
||
|
// errHandler function for dojo._ioSetArgs call.
|
||
|
|
||
|
if(!dfd.ioArgs.args.failOk){
|
||
|
console.error(error);
|
||
|
}
|
||
|
return error;
|
||
|
};
|
||
|
|
||
|
//Use a separate count for knowing if we are starting/stopping io calls.
|
||
|
var _checkPubCount = function(dfd){
|
||
|
if(_pubCount <= 0){
|
||
|
_pubCount = 0;
|
||
|
if(cfg.ioPublish && dojo.publish && (!dfd || dfd && dfd.ioArgs.args.ioPublish !== false)){
|
||
|
dojo.publish("/dojo/io/stop");
|
||
|
}
|
||
|
}
|
||
|
};
|
||
|
|
||
|
var _pubCount = 0;
|
||
|
aspect.after(watch, "_onAction", function(){
|
||
|
_pubCount -= 1;
|
||
|
});
|
||
|
aspect.after(watch, "_onInFlight", _checkPubCount);
|
||
|
|
||
|
dojo._ioCancelAll = watch.cancelAll;
|
||
|
/*=====
|
||
|
dojo._ioCancelAll = function(){
|
||
|
// summary:
|
||
|
// Cancels all pending IO requests, regardless of IO type
|
||
|
// (xhr, script, iframe).
|
||
|
};
|
||
|
=====*/
|
||
|
|
||
|
dojo._ioNotifyStart = function(/*Deferred*/dfd){
|
||
|
// summary:
|
||
|
// If dojo.publish is available, publish topics
|
||
|
// about the start of a request queue and/or the
|
||
|
// the beginning of request.
|
||
|
//
|
||
|
// Used by IO transports. An IO transport should
|
||
|
// call this method before making the network connection.
|
||
|
if(cfg.ioPublish && dojo.publish && dfd.ioArgs.args.ioPublish !== false){
|
||
|
if(!_pubCount){
|
||
|
dojo.publish("/dojo/io/start");
|
||
|
}
|
||
|
_pubCount += 1;
|
||
|
dojo.publish("/dojo/io/send", [dfd]);
|
||
|
}
|
||
|
};
|
||
|
|
||
|
dojo._ioWatch = function(dfd, validCheck, ioCheck, resHandle){
|
||
|
// summary:
|
||
|
// Watches the io request represented by dfd to see if it completes.
|
||
|
// dfd: Deferred
|
||
|
// The Deferred object to watch.
|
||
|
// validCheck: Function
|
||
|
// Function used to check if the IO request is still valid. Gets the dfd
|
||
|
// object as its only argument.
|
||
|
// ioCheck: Function
|
||
|
// Function used to check if basic IO call worked. Gets the dfd
|
||
|
// object as its only argument.
|
||
|
// resHandle: Function
|
||
|
// Function used to process response. Gets the dfd
|
||
|
// object as its only argument.
|
||
|
|
||
|
var args = dfd.ioArgs.options = dfd.ioArgs.args;
|
||
|
lang.mixin(dfd, {
|
||
|
response: dfd.ioArgs,
|
||
|
isValid: function(response){
|
||
|
return validCheck(dfd);
|
||
|
},
|
||
|
isReady: function(response){
|
||
|
return ioCheck(dfd);
|
||
|
},
|
||
|
handleResponse: function(response){
|
||
|
return resHandle(dfd);
|
||
|
}
|
||
|
});
|
||
|
watch(dfd);
|
||
|
|
||
|
_checkPubCount(dfd);
|
||
|
};
|
||
|
|
||
|
var _defaultContentType = "application/x-www-form-urlencoded";
|
||
|
|
||
|
dojo._ioAddQueryToUrl = function(/*dojo.__IoCallbackArgs*/ioArgs){
|
||
|
// summary:
|
||
|
// Adds query params discovered by the io deferred construction to the URL.
|
||
|
// Only use this for operations which are fundamentally GET-type operations.
|
||
|
if(ioArgs.query.length){
|
||
|
ioArgs.url += (ioArgs.url.indexOf("?") == -1 ? "?" : "&") + ioArgs.query;
|
||
|
ioArgs.query = null;
|
||
|
}
|
||
|
};
|
||
|
|
||
|
/*=====
|
||
|
dojo.__XhrArgs = declare(dojo.__IoArgs, {
|
||
|
// summary:
|
||
|
// In addition to the properties listed for the dojo._IoArgs type,
|
||
|
// the following properties are allowed for dojo.xhr* methods.
|
||
|
// handleAs: String?
|
||
|
// Acceptable values are: text (default), json, json-comment-optional,
|
||
|
// json-comment-filtered, javascript, xml. See `dojo/_base/xhr.contentHandlers`
|
||
|
// sync: Boolean?
|
||
|
// false is default. Indicates whether the request should
|
||
|
// be a synchronous (blocking) request.
|
||
|
// headers: Object?
|
||
|
// Additional HTTP headers to send in the request.
|
||
|
// failOk: Boolean?
|
||
|
// false is default. Indicates whether a request should be
|
||
|
// allowed to fail (and therefore no console error message in
|
||
|
// the event of a failure)
|
||
|
// contentType: String|Boolean
|
||
|
// "application/x-www-form-urlencoded" is default. Set to false to
|
||
|
// prevent a Content-Type header from being sent, or to a string
|
||
|
// to send a different Content-Type.
|
||
|
});
|
||
|
=====*/
|
||
|
|
||
|
dojo.xhr = function(/*String*/ method, /*dojo.__XhrArgs*/ args, /*Boolean?*/ hasBody){
|
||
|
// summary:
|
||
|
// Deprecated. Use dojo/request instead.
|
||
|
// description:
|
||
|
// Sends an HTTP request with the given method.
|
||
|
// See also dojo.xhrGet(), xhrPost(), xhrPut() and dojo.xhrDelete() for shortcuts
|
||
|
// for those HTTP methods. There are also methods for "raw" PUT and POST methods
|
||
|
// via dojo.rawXhrPut() and dojo.rawXhrPost() respectively.
|
||
|
// method:
|
||
|
// HTTP method to be used, such as GET, POST, PUT, DELETE. Should be uppercase.
|
||
|
// hasBody:
|
||
|
// If the request has an HTTP body, then pass true for hasBody.
|
||
|
|
||
|
var rDfd;
|
||
|
//Make the Deferred object for this xhr request.
|
||
|
var dfd = dojo._ioSetArgs(args, function(dfd){
|
||
|
rDfd && rDfd.cancel();
|
||
|
}, _deferredOk, _deferError);
|
||
|
var ioArgs = dfd.ioArgs;
|
||
|
|
||
|
//Allow for specifying the HTTP body completely.
|
||
|
if("postData" in args){
|
||
|
ioArgs.query = args.postData;
|
||
|
}else if("putData" in args){
|
||
|
ioArgs.query = args.putData;
|
||
|
}else if("rawBody" in args){
|
||
|
ioArgs.query = args.rawBody;
|
||
|
}else if((arguments.length > 2 && !hasBody) || "POST|PUT".indexOf(method.toUpperCase()) === -1){
|
||
|
//Check for hasBody being passed. If no hasBody,
|
||
|
//then only append query string if not a POST or PUT request.
|
||
|
dojo._ioAddQueryToUrl(ioArgs);
|
||
|
}
|
||
|
|
||
|
var options = {
|
||
|
method: method,
|
||
|
handleAs: "text",
|
||
|
timeout: args.timeout,
|
||
|
withCredentials: args.withCredentials,
|
||
|
ioArgs: ioArgs
|
||
|
};
|
||
|
|
||
|
if(typeof args.headers !== 'undefined'){
|
||
|
options.headers = args.headers;
|
||
|
}
|
||
|
if(typeof args.contentType !== 'undefined'){
|
||
|
if(!options.headers){
|
||
|
options.headers = {};
|
||
|
}
|
||
|
options.headers['Content-Type'] = args.contentType;
|
||
|
}
|
||
|
if(typeof ioArgs.query !== 'undefined'){
|
||
|
options.data = ioArgs.query;
|
||
|
}
|
||
|
if(typeof args.sync !== 'undefined'){
|
||
|
options.sync = args.sync;
|
||
|
}
|
||
|
|
||
|
dojo._ioNotifyStart(dfd);
|
||
|
try{
|
||
|
rDfd = _xhr(ioArgs.url, options, true);
|
||
|
}catch(e){
|
||
|
// If XHR creation fails, dojo/request/xhr throws
|
||
|
// When this happens, cancel the deferred
|
||
|
dfd.cancel();
|
||
|
return dfd;
|
||
|
}
|
||
|
|
||
|
// sync ioArgs
|
||
|
dfd.ioArgs.xhr = rDfd.response.xhr;
|
||
|
|
||
|
rDfd.then(function(){
|
||
|
dfd.resolve(dfd);
|
||
|
}).otherwise(function(error){
|
||
|
ioArgs.error = error;
|
||
|
if(error.response){
|
||
|
error.status = error.response.status;
|
||
|
error.responseText = error.response.text;
|
||
|
error.xhr = error.response.xhr;
|
||
|
}
|
||
|
dfd.reject(error);
|
||
|
});
|
||
|
return dfd; // dojo/_base/Deferred
|
||
|
};
|
||
|
|
||
|
dojo.xhrGet = function(/*dojo.__XhrArgs*/ args){
|
||
|
// summary:
|
||
|
// Sends an HTTP GET request to the server.
|
||
|
return dojo.xhr("GET", args); // dojo/_base/Deferred
|
||
|
};
|
||
|
|
||
|
dojo.rawXhrPost = dojo.xhrPost = function(/*dojo.__XhrArgs*/ args){
|
||
|
// summary:
|
||
|
// Sends an HTTP POST request to the server. In addition to the properties
|
||
|
// listed for the dojo.__XhrArgs type, the following property is allowed:
|
||
|
// postData:
|
||
|
// String. Send raw data in the body of the POST request.
|
||
|
return dojo.xhr("POST", args, true); // dojo/_base/Deferred
|
||
|
};
|
||
|
|
||
|
dojo.rawXhrPut = dojo.xhrPut = function(/*dojo.__XhrArgs*/ args){
|
||
|
// summary:
|
||
|
// Sends an HTTP PUT request to the server. In addition to the properties
|
||
|
// listed for the dojo.__XhrArgs type, the following property is allowed:
|
||
|
// putData:
|
||
|
// String. Send raw data in the body of the PUT request.
|
||
|
return dojo.xhr("PUT", args, true); // dojo/_base/Deferred
|
||
|
};
|
||
|
|
||
|
dojo.xhrDelete = function(/*dojo.__XhrArgs*/ args){
|
||
|
// summary:
|
||
|
// Sends an HTTP DELETE request to the server.
|
||
|
return dojo.xhr("DELETE", args); // dojo/_base/Deferred
|
||
|
};
|
||
|
|
||
|
/*
|
||
|
dojo.wrapForm = function(formNode){
|
||
|
// summary:
|
||
|
// A replacement for FormBind, but not implemented yet.
|
||
|
|
||
|
// FIXME: need to think harder about what extensions to this we might
|
||
|
// want. What should we allow folks to do w/ this? What events to
|
||
|
// set/send?
|
||
|
throw new Error("dojo.wrapForm not yet implemented");
|
||
|
}
|
||
|
*/
|
||
|
|
||
|
dojo._isDocumentOk = function(x){
|
||
|
return util.checkStatus(x.status);
|
||
|
};
|
||
|
|
||
|
dojo._getText = function(url){
|
||
|
var result;
|
||
|
dojo.xhrGet({url:url, sync:true, load:function(text){
|
||
|
result = text;
|
||
|
}});
|
||
|
return result;
|
||
|
};
|
||
|
|
||
|
// Add aliases for static functions to dojo.xhr since dojo.xhr is what's returned from this module
|
||
|
lang.mixin(dojo.xhr, {
|
||
|
_xhrObj: dojo._xhrObj,
|
||
|
fieldToObject: domForm.fieldToObject,
|
||
|
formToObject: domForm.toObject,
|
||
|
objectToQuery: ioq.objectToQuery,
|
||
|
formToQuery: domForm.toQuery,
|
||
|
formToJson: domForm.toJson,
|
||
|
queryToObject: ioq.queryToObject,
|
||
|
contentHandlers: handlers,
|
||
|
_ioSetArgs: dojo._ioSetArgs,
|
||
|
_ioCancelAll: dojo._ioCancelAll,
|
||
|
_ioNotifyStart: dojo._ioNotifyStart,
|
||
|
_ioWatch: dojo._ioWatch,
|
||
|
_ioAddQueryToUrl: dojo._ioAddQueryToUrl,
|
||
|
_isDocumentOk: dojo._isDocumentOk,
|
||
|
_getText: dojo._getText,
|
||
|
get: dojo.xhrGet,
|
||
|
post: dojo.xhrPost,
|
||
|
put: dojo.xhrPut,
|
||
|
del: dojo.xhrDelete // because "delete" is a reserved word
|
||
|
});
|
||
|
|
||
|
return dojo.xhr;
|
||
|
});
|
||
|
|
||
|
},
|
||
|
'dojo/_base/sniff':function(){
|
||
|
define(["./kernel", "./lang", "../sniff"], function(dojo, lang, has){
|
||
|
// module:
|
||
|
// dojo/_base/sniff
|
||
|
|
||
|
/*=====
|
||
|
return {
|
||
|
// summary:
|
||
|
// Deprecated. New code should use dojo/sniff.
|
||
|
// This module populates the dojo browser version sniffing properties like dojo.isIE.
|
||
|
};
|
||
|
=====*/
|
||
|
|
||
|
if(! 1 ){
|
||
|
return has;
|
||
|
}
|
||
|
|
||
|
// no idea what this is for, or if it's used
|
||
|
dojo._name = "browser";
|
||
|
|
||
|
lang.mixin(dojo, {
|
||
|
// isBrowser: Boolean
|
||
|
// True if the client is a web-browser
|
||
|
isBrowser: true,
|
||
|
|
||
|
// isFF: Number|undefined
|
||
|
// Version as a Number if client is FireFox. undefined otherwise. Corresponds to
|
||
|
// major detected FireFox version (1.5, 2, 3, etc.)
|
||
|
isFF: has("ff"),
|
||
|
|
||
|
// isIE: Number|undefined
|
||
|
// Version as a Number if client is MSIE(PC). undefined otherwise. Corresponds to
|
||
|
// major detected IE version (6, 7, 8, etc.)
|
||
|
isIE: has("ie"),
|
||
|
|
||
|
// isKhtml: Number|undefined
|
||
|
// Version as a Number if client is a KHTML browser. undefined otherwise. Corresponds to major
|
||
|
// detected version.
|
||
|
isKhtml: has("khtml"),
|
||
|
|
||
|
// isWebKit: Number|undefined
|
||
|
// Version as a Number if client is a WebKit-derived browser (Konqueror,
|
||
|
// Safari, Chrome, etc.). undefined otherwise.
|
||
|
isWebKit: has("webkit"),
|
||
|
|
||
|
// isMozilla: Number|undefined
|
||
|
// Version as a Number if client is a Mozilla-based browser (Firefox,
|
||
|
// SeaMonkey). undefined otherwise. Corresponds to major detected version.
|
||
|
isMozilla: has("mozilla"),
|
||
|
// isMoz: Number|undefined
|
||
|
// Version as a Number if client is a Mozilla-based browser (Firefox,
|
||
|
// SeaMonkey). undefined otherwise. Corresponds to major detected version.
|
||
|
isMoz: has("mozilla"),
|
||
|
|
||
|
// isOpera: Number|undefined
|
||
|
// Version as a Number if client is Opera. undefined otherwise. Corresponds to
|
||
|
// major detected version.
|
||
|
isOpera: has("opera"),
|
||
|
|
||
|
// isSafari: Number|undefined
|
||
|
// Version as a Number if client is Safari or iPhone. undefined otherwise.
|
||
|
isSafari: has("safari"),
|
||
|
|
||
|
// isChrome: Number|undefined
|
||
|
// Version as a Number if client is Chrome browser. undefined otherwise.
|
||
|
isChrome: has("chrome"),
|
||
|
|
||
|
// isMac: Boolean
|
||
|
// True if the client runs on Mac
|
||
|
isMac: has("mac"),
|
||
|
|
||
|
// isIos: Number|undefined
|
||
|
// Version as a Number if client is iPhone, iPod, or iPad. undefined otherwise.
|
||
|
isIos: has("ios"),
|
||
|
|
||
|
// isAndroid: Number|undefined
|
||
|
// Version as a Number if client is android browser. undefined otherwise.
|
||
|
isAndroid: has("android"),
|
||
|
|
||
|
// isWii: Boolean
|
||
|
// True if client is Wii
|
||
|
isWii: has("wii"),
|
||
|
|
||
|
// isQuirks: Boolean
|
||
|
// Page is in quirks mode.
|
||
|
isQuirks: has("quirks"),
|
||
|
|
||
|
// isAir: Boolean
|
||
|
// True if client is Adobe Air
|
||
|
isAir: has("air")
|
||
|
});
|
||
|
|
||
|
return has;
|
||
|
});
|
||
|
|
||
|
},
|
||
|
'dojo/io-query':function(){
|
||
|
define(["./_base/lang"], function(lang){
|
||
|
|
||
|
// module:
|
||
|
// dojo/io-query
|
||
|
|
||
|
var backstop = {};
|
||
|
|
||
|
return {
|
||
|
// summary:
|
||
|
// This module defines query string processing functions.
|
||
|
|
||
|
objectToQuery: function objectToQuery(/*Object*/ map){
|
||
|
// summary:
|
||
|
// takes a name/value mapping object and returns a string representing
|
||
|
// a URL-encoded version of that object.
|
||
|
// example:
|
||
|
// this object:
|
||
|
//
|
||
|
// | {
|
||
|
// | blah: "blah",
|
||
|
// | multi: [
|
||
|
// | "thud",
|
||
|
// | "thonk"
|
||
|
// | ]
|
||
|
// | };
|
||
|
//
|
||
|
// yields the following query string:
|
||
|
//
|
||
|
// | "blah=blah&multi=thud&multi=thonk"
|
||
|
|
||
|
// FIXME: need to implement encodeAscii!!
|
||
|
var enc = encodeURIComponent, pairs = [];
|
||
|
for(var name in map){
|
||
|
var value = map[name];
|
||
|
if(value != backstop[name]){
|
||
|
var assign = enc(name) + "=";
|
||
|
if(lang.isArray(value)){
|
||
|
for(var i = 0, l = value.length; i < l; ++i){
|
||
|
pairs.push(assign + enc(value[i]));
|
||
|
}
|
||
|
}else{
|
||
|
pairs.push(assign + enc(value));
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
return pairs.join("&"); // String
|
||
|
},
|
||
|
|
||
|
queryToObject: function queryToObject(/*String*/ str){
|
||
|
// summary:
|
||
|
// Create an object representing a de-serialized query section of a
|
||
|
// URL. Query keys with multiple values are returned in an array.
|
||
|
//
|
||
|
// example:
|
||
|
// This string:
|
||
|
//
|
||
|
// | "foo=bar&foo=baz&thinger=%20spaces%20=blah&zonk=blarg&"
|
||
|
//
|
||
|
// results in this object structure:
|
||
|
//
|
||
|
// | {
|
||
|
// | foo: [ "bar", "baz" ],
|
||
|
// | thinger: " spaces =blah",
|
||
|
// | zonk: "blarg"
|
||
|
// | }
|
||
|
//
|
||
|
// Note that spaces and other urlencoded entities are correctly
|
||
|
// handled.
|
||
|
|
||
|
var dec = decodeURIComponent, qp = str.split("&"), ret = {}, name, val;
|
||
|
for(var i = 0, l = qp.length, item; i < l; ++i){
|
||
|
item = qp[i];
|
||
|
if(item.length){
|
||
|
var s = item.indexOf("=");
|
||
|
if(s < 0){
|
||
|
name = dec(item);
|
||
|
val = "";
|
||
|
}else{
|
||
|
name = dec(item.slice(0, s));
|
||
|
val = dec(item.slice(s + 1));
|
||
|
}
|
||
|
if(typeof ret[name] == "string"){ // inline'd type check
|
||
|
ret[name] = [ret[name]];
|
||
|
}
|
||
|
|
||
|
if(lang.isArray(ret[name])){
|
||
|
ret[name].push(val);
|
||
|
}else{
|
||
|
ret[name] = val;
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
return ret; // Object
|
||
|
}
|
||
|
};
|
||
|
});
|
||
|
},
|
||
|
'dojo/dom':function(){
|
||
|
define(["./sniff", "./_base/window", "./_base/kernel"],
|
||
|
function(has, win, kernel){
|
||
|
// module:
|
||
|
// dojo/dom
|
||
|
|
||
|
// FIXME: need to add unit tests for all the semi-public methods
|
||
|
|
||
|
if(has("ie") <= 7){
|
||
|
try{
|
||
|
document.execCommand("BackgroundImageCache", false, true);
|
||
|
}catch(e){
|
||
|
// sane browsers don't have cache "issues"
|
||
|
}
|
||
|
}
|
||
|
|
||
|
// =============================
|
||
|
// DOM Functions
|
||
|
// =============================
|
||
|
|
||
|
// the result object
|
||
|
var dom = {
|
||
|
// summary:
|
||
|
// This module defines the core dojo DOM API.
|
||
|
};
|
||
|
|
||
|
if(has("ie")){
|
||
|
dom.byId = function(id, doc){
|
||
|
if(typeof id != "string"){
|
||
|
return id || null;
|
||
|
}
|
||
|
var _d = doc || win.doc, te = id && _d.getElementById(id);
|
||
|
// attributes.id.value is better than just id in case the
|
||
|
// user has a name=id inside a form
|
||
|
if(te && (te.attributes.id.value == id || te.id == id)){
|
||
|
return te;
|
||
|
}else{
|
||
|
var eles = _d.all[id];
|
||
|
if(!eles || eles.nodeName){
|
||
|
eles = [eles];
|
||
|
}
|
||
|
// if more than 1, choose first with the correct id
|
||
|
var i = 0;
|
||
|
while((te = eles[i++])){
|
||
|
if((te.attributes && te.attributes.id && te.attributes.id.value == id) || te.id == id){
|
||
|
return te;
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
return null;
|
||
|
};
|
||
|
}else{
|
||
|
dom.byId = function(id, doc){
|
||
|
// inline'd type check.
|
||
|
// be sure to return null per documentation, to match IE branch.
|
||
|
return ((typeof id == "string") ? (doc || win.doc).getElementById(id) : id) || null; // DOMNode
|
||
|
};
|
||
|
}
|
||
|
/*=====
|
||
|
dom.byId = function(id, doc){
|
||
|
// summary:
|
||
|
// Returns DOM node with matching `id` attribute or falsy value (ex: null or undefined)
|
||
|
// if not found. If `id` is a DomNode, this function is a no-op.
|
||
|
//
|
||
|
// id: String|DOMNode
|
||
|
// A string to match an HTML id attribute or a reference to a DOM Node
|
||
|
//
|
||
|
// doc: Document?
|
||
|
// Document to work in. Defaults to the current value of
|
||
|
// dojo/_base/window.doc. Can be used to retrieve
|
||
|
// node references from other documents.
|
||
|
//
|
||
|
// example:
|
||
|
// Look up a node by ID:
|
||
|
// | require(["dojo/dom"], function(dom){
|
||
|
// | var n = dom.byId("foo");
|
||
|
// | });
|
||
|
//
|
||
|
// example:
|
||
|
// Check if a node exists, and use it.
|
||
|
// | require(["dojo/dom"], function(dom){
|
||
|
// | var n = dom.byId("bar");
|
||
|
// | if(n){ doStuff() ... }
|
||
|
// | });
|
||
|
//
|
||
|
// example:
|
||
|
// Allow string or DomNode references to be passed to a custom function:
|
||
|
// | require(["dojo/dom"], function(dom){
|
||
|
// | var foo = function(nodeOrId){
|
||
|
// | nodeOrId = dom.byId(nodeOrId);
|
||
|
// | // ... more stuff
|
||
|
// | }
|
||
|
// | });
|
||
|
};
|
||
|
=====*/
|
||
|
|
||
|
// Test for DOMNode.contains() method, available everywhere except FF8-
|
||
|
// and IE8-, where it's available in general, but not on document itself,
|
||
|
// and also problems when either ancestor or node are text nodes.
|
||
|
|
||
|
var doc = kernel.global["document"] || null;
|
||
|
has.add("dom-contains", !!(doc && doc.contains));
|
||
|
dom.isDescendant = has("dom-contains") ?
|
||
|
// FF9+, IE9+, webkit, opera, iOS, Android, Edge, etc.
|
||
|
function(/*DOMNode|String*/ node, /*DOMNode|String*/ ancestor){
|
||
|
return !!( (ancestor = dom.byId(ancestor)) && ancestor.contains(dom.byId(node)) );
|
||
|
} :
|
||
|
function(/*DOMNode|String*/ node, /*DOMNode|String*/ ancestor){
|
||
|
// summary:
|
||
|
// Returns true if node is a descendant of ancestor
|
||
|
// node: DOMNode|String
|
||
|
// string id or node reference to test
|
||
|
// ancestor: DOMNode|String
|
||
|
// string id or node reference of potential parent to test against
|
||
|
//
|
||
|
// example:
|
||
|
// Test is node id="bar" is a descendant of node id="foo"
|
||
|
// | require(["dojo/dom"], function(dom){
|
||
|
// | if(dom.isDescendant("bar", "foo")){ ... }
|
||
|
// | });
|
||
|
|
||
|
try{
|
||
|
node = dom.byId(node);
|
||
|
ancestor = dom.byId(ancestor);
|
||
|
while(node){
|
||
|
if(node == ancestor){
|
||
|
return true; // Boolean
|
||
|
}
|
||
|
node = node.parentNode;
|
||
|
}
|
||
|
}catch(e){ /* squelch, return false */ }
|
||
|
return false; // Boolean
|
||
|
};
|
||
|
|
||
|
// TODO: do we need setSelectable in the base?
|
||
|
|
||
|
// Add feature test for user-select CSS property
|
||
|
// (currently known to work in all but IE < 10 and Opera)
|
||
|
// TODO: The user-select CSS property as of May 2014 is no longer part of
|
||
|
// any CSS specification. In IE, -ms-user-select does not do the same thing
|
||
|
// as the unselectable attribute on elements; namely, dijit Editor buttons
|
||
|
// do not properly prevent the content of the editable content frame from
|
||
|
// unblurring. As a result, the -ms- prefixed version is omitted here.
|
||
|
has.add("css-user-select", function(global, doc, element){
|
||
|
// Avoid exception when dom.js is loaded in non-browser environments
|
||
|
if(!element){ return false; }
|
||
|
|
||
|
var style = element.style;
|
||
|
var prefixes = ["Khtml", "O", "Moz", "Webkit"],
|
||
|
i = prefixes.length,
|
||
|
name = "userSelect",
|
||
|
prefix;
|
||
|
|
||
|
// Iterate prefixes from most to least likely
|
||
|
do{
|
||
|
if(typeof style[name] !== "undefined"){
|
||
|
// Supported; return property name
|
||
|
return name;
|
||
|
}
|
||
|
}while(i-- && (name = prefixes[i] + "UserSelect"));
|
||
|
|
||
|
// Not supported if we didn't return before now
|
||
|
return false;
|
||
|
});
|
||
|
|
||
|
/*=====
|
||
|
dom.setSelectable = function(node, selectable){
|
||
|
// summary:
|
||
|
// Enable or disable selection on a node
|
||
|
// node: DOMNode|String
|
||
|
// id or reference to node
|
||
|
// selectable: Boolean
|
||
|
// state to put the node in. false indicates unselectable, true
|
||
|
// allows selection.
|
||
|
// example:
|
||
|
// Make the node id="bar" unselectable
|
||
|
// | require(["dojo/dom"], function(dom){
|
||
|
// | dom.setSelectable("bar");
|
||
|
// | });
|
||
|
// example:
|
||
|
// Make the node id="bar" selectable
|
||
|
// | require(["dojo/dom"], function(dom){
|
||
|
// | dom.setSelectable("bar", true);
|
||
|
// | });
|
||
|
};
|
||
|
=====*/
|
||
|
|
||
|
var cssUserSelect = has("css-user-select");
|
||
|
dom.setSelectable = cssUserSelect ? function(node, selectable){
|
||
|
// css-user-select returns a (possibly vendor-prefixed) CSS property name
|
||
|
dom.byId(node).style[cssUserSelect] = selectable ? "" : "none";
|
||
|
} : function(node, selectable){
|
||
|
node = dom.byId(node);
|
||
|
|
||
|
// (IE < 10 / Opera) Fall back to setting/removing the
|
||
|
// unselectable attribute on the element and all its children
|
||
|
var nodes = node.getElementsByTagName("*"),
|
||
|
i = nodes.length;
|
||
|
|
||
|
if(selectable){
|
||
|
node.removeAttribute("unselectable");
|
||
|
while(i--){
|
||
|
nodes[i].removeAttribute("unselectable");
|
||
|
}
|
||
|
}else{
|
||
|
node.setAttribute("unselectable", "on");
|
||
|
while(i--){
|
||
|
nodes[i].setAttribute("unselectable", "on");
|
||
|
}
|
||
|
}
|
||
|
};
|
||
|
|
||
|
return dom;
|
||
|
});
|
||
|
|
||
|
},
|
||
|
'dojo/_base/window':function(){
|
||
|
define(["./kernel", "./lang", "../sniff"], function(dojo, lang, has){
|
||
|
// module:
|
||
|
// dojo/_base/window
|
||
|
|
||
|
var ret = {
|
||
|
// summary:
|
||
|
// API to save/set/restore the global/document scope.
|
||
|
|
||
|
global: dojo.global,
|
||
|
/*=====
|
||
|
global: {
|
||
|
// summary:
|
||
|
// Alias for the current window. 'global' can be modified
|
||
|
// for temporary context shifting. See also withGlobal().
|
||
|
// description:
|
||
|
// Use this rather than referring to 'window' to ensure your code runs
|
||
|
// correctly in managed contexts.
|
||
|
},
|
||
|
=====*/
|
||
|
|
||
|
doc: dojo.global["document"] || null,
|
||
|
/*=====
|
||
|
doc: {
|
||
|
// summary:
|
||
|
// Alias for the current document. 'doc' can be modified
|
||
|
// for temporary context shifting. See also withDoc().
|
||
|
// description:
|
||
|
// Use this rather than referring to 'window.document' to ensure your code runs
|
||
|
// correctly in managed contexts.
|
||
|
// example:
|
||
|
// | n.appendChild(dojo.doc.createElement('div'));
|
||
|
},
|
||
|
=====*/
|
||
|
|
||
|
body: function(/*Document?*/ doc){
|
||
|
// summary:
|
||
|
// Return the body element of the specified document or of dojo/_base/window::doc.
|
||
|
// example:
|
||
|
// | win.body().appendChild(dojo.doc.createElement('div'));
|
||
|
|
||
|
// Note: document.body is not defined for a strict xhtml document
|
||
|
// Would like to memoize this, but dojo.doc can change vi dojo.withDoc().
|
||
|
doc = doc || dojo.doc;
|
||
|
return doc.body || doc.getElementsByTagName("body")[0]; // Node
|
||
|
},
|
||
|
|
||
|
setContext: function(/*Object*/ globalObject, /*DocumentElement*/ globalDocument){
|
||
|
// summary:
|
||
|
// changes the behavior of many core Dojo functions that deal with
|
||
|
// namespace and DOM lookup, changing them to work in a new global
|
||
|
// context (e.g., an iframe). The varibles dojo.global and dojo.doc
|
||
|
// are modified as a result of calling this function and the result of
|
||
|
// `dojo.body()` likewise differs.
|
||
|
dojo.global = ret.global = globalObject;
|
||
|
dojo.doc = ret.doc = globalDocument;
|
||
|
},
|
||
|
|
||
|
withGlobal: function( /*Object*/ globalObject,
|
||
|
/*Function*/ callback,
|
||
|
/*Object?*/ thisObject,
|
||
|
/*Array?*/ cbArguments){
|
||
|
// summary:
|
||
|
// Invoke callback with globalObject as dojo.global and
|
||
|
// globalObject.document as dojo.doc.
|
||
|
// description:
|
||
|
// Invoke callback with globalObject as dojo.global and
|
||
|
// globalObject.document as dojo.doc. If provided, globalObject
|
||
|
// will be executed in the context of object thisObject
|
||
|
// When callback() returns or throws an error, the dojo.global
|
||
|
// and dojo.doc will be restored to its previous state.
|
||
|
|
||
|
var oldGlob = dojo.global;
|
||
|
try{
|
||
|
dojo.global = ret.global = globalObject;
|
||
|
return ret.withDoc.call(null, globalObject.document, callback, thisObject, cbArguments);
|
||
|
}finally{
|
||
|
dojo.global = ret.global = oldGlob;
|
||
|
}
|
||
|
},
|
||
|
|
||
|
withDoc: function( /*DocumentElement*/ documentObject,
|
||
|
/*Function*/ callback,
|
||
|
/*Object?*/ thisObject,
|
||
|
/*Array?*/ cbArguments){
|
||
|
// summary:
|
||
|
// Invoke callback with documentObject as dojo/_base/window::doc.
|
||
|
// description:
|
||
|
// Invoke callback with documentObject as dojo/_base/window::doc. If provided,
|
||
|
// callback will be executed in the context of object thisObject
|
||
|
// When callback() returns or throws an error, the dojo/_base/window::doc will
|
||
|
// be restored to its previous state.
|
||
|
|
||
|
var oldDoc = ret.doc,
|
||
|
oldQ = has("quirks"),
|
||
|
oldIE = has("ie"), isIE, mode, pwin;
|
||
|
|
||
|
try{
|
||
|
dojo.doc = ret.doc = documentObject;
|
||
|
// update dojo.isQuirks and the value of the has feature "quirks".
|
||
|
// remove setting dojo.isQuirks and dojo.isIE for 2.0
|
||
|
dojo.isQuirks = has.add("quirks", dojo.doc.compatMode == "BackCompat", true, true); // no need to check for QuirksMode which was Opera 7 only
|
||
|
|
||
|
if(has("ie")){
|
||
|
if((pwin = documentObject.parentWindow) && pwin.navigator){
|
||
|
// re-run IE detection logic and update dojo.isIE / has("ie")
|
||
|
// (the only time parentWindow/navigator wouldn't exist is if we were not
|
||
|
// passed an actual legitimate document object)
|
||
|
isIE = parseFloat(pwin.navigator.appVersion.split("MSIE ")[1]) || undefined;
|
||
|
mode = documentObject.documentMode;
|
||
|
if(mode && mode != 5 && Math.floor(isIE) != mode){
|
||
|
isIE = mode;
|
||
|
}
|
||
|
dojo.isIE = has.add("ie", isIE, true, true);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
if(thisObject && typeof callback == "string"){
|
||
|
callback = thisObject[callback];
|
||
|
}
|
||
|
|
||
|
return callback.apply(thisObject, cbArguments || []);
|
||
|
}finally{
|
||
|
dojo.doc = ret.doc = oldDoc;
|
||
|
dojo.isQuirks = has.add("quirks", oldQ, true, true);
|
||
|
dojo.isIE = has.add("ie", oldIE, true, true);
|
||
|
}
|
||
|
}
|
||
|
};
|
||
|
|
||
|
1 && lang.mixin(dojo, ret);
|
||
|
|
||
|
return ret;
|
||
|
|
||
|
});
|
||
|
|
||
|
},
|
||
|
'dojo/dom-form':function(){
|
||
|
define(["./_base/lang", "./dom", "./io-query", "./json"], function(lang, dom, ioq, json){
|
||
|
// module:
|
||
|
// dojo/dom-form
|
||
|
|
||
|
function setValue(/*Object*/ obj, /*String*/ name, /*String*/ value){
|
||
|
// summary:
|
||
|
// For the named property in object, set the value. If a value
|
||
|
// already exists and it is a string, convert the value to be an
|
||
|
// array of values.
|
||
|
|
||
|
// Skip it if there is no value
|
||
|
if(value === null){
|
||
|
return;
|
||
|
}
|
||
|
|
||
|
var val = obj[name];
|
||
|
if(typeof val == "string"){ // inline'd type check
|
||
|
obj[name] = [val, value];
|
||
|
}else if(lang.isArray(val)){
|
||
|
val.push(value);
|
||
|
}else{
|
||
|
obj[name] = value;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
var exclude = "file|submit|image|reset|button";
|
||
|
|
||
|
var form = {
|
||
|
// summary:
|
||
|
// This module defines form-processing functions.
|
||
|
|
||
|
fieldToObject: function fieldToObject(/*DOMNode|String*/ inputNode){
|
||
|
// summary:
|
||
|
// Serialize a form field to a JavaScript object.
|
||
|
// description:
|
||
|
// Returns the value encoded in a form field as
|
||
|
// as a string or an array of strings. Disabled form elements
|
||
|
// and unchecked radio and checkboxes are skipped. Multi-select
|
||
|
// elements are returned as an array of string values.
|
||
|
// inputNode: DOMNode|String
|
||
|
// returns: Object
|
||
|
|
||
|
var ret = null;
|
||
|
inputNode = dom.byId(inputNode);
|
||
|
if(inputNode){
|
||
|
var _in = inputNode.name, type = (inputNode.type || "").toLowerCase();
|
||
|
if(_in && type && !inputNode.disabled){
|
||
|
if(type == "radio" || type == "checkbox"){
|
||
|
if(inputNode.checked){
|
||
|
ret = inputNode.value;
|
||
|
}
|
||
|
}else if(inputNode.multiple){
|
||
|
ret = [];
|
||
|
var nodes = [inputNode.firstChild];
|
||
|
while(nodes.length){
|
||
|
for(var node = nodes.pop(); node; node = node.nextSibling){
|
||
|
if(node.nodeType == 1 && node.tagName.toLowerCase() == "option"){
|
||
|
if(node.selected){
|
||
|
ret.push(node.value);
|
||
|
}
|
||
|
}else{
|
||
|
if(node.nextSibling){
|
||
|
nodes.push(node.nextSibling);
|
||
|
}
|
||
|
if(node.firstChild){
|
||
|
nodes.push(node.firstChild);
|
||
|
}
|
||
|
break;
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
}else{
|
||
|
ret = inputNode.value;
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
return ret; // Object
|
||
|
},
|
||
|
|
||
|
toObject: function formToObject(/*DOMNode|String*/ formNode){
|
||
|
// summary:
|
||
|
// Serialize a form node to a JavaScript object.
|
||
|
// description:
|
||
|
// Returns the values encoded in an HTML form as
|
||
|
// string properties in an object which it then returns. Disabled form
|
||
|
// elements, buttons, and other non-value form elements are skipped.
|
||
|
// Multi-select elements are returned as an array of string values.
|
||
|
// formNode: DOMNode|String
|
||
|
// example:
|
||
|
// This form:
|
||
|
// | <form id="test_form">
|
||
|
// | <input type="text" name="blah" value="blah">
|
||
|
// | <input type="text" name="no_value" value="blah" disabled>
|
||
|
// | <input type="button" name="no_value2" value="blah">
|
||
|
// | <select type="select" multiple name="multi" size="5">
|
||
|
// | <option value="blah">blah</option>
|
||
|
// | <option value="thud" selected>thud</option>
|
||
|
// | <option value="thonk" selected>thonk</option>
|
||
|
// | </select>
|
||
|
// | </form>
|
||
|
//
|
||
|
// yields this object structure as the result of a call to
|
||
|
// formToObject():
|
||
|
//
|
||
|
// | {
|
||
|
// | blah: "blah",
|
||
|
// | multi: [
|
||
|
// | "thud",
|
||
|
// | "thonk"
|
||
|
// | ]
|
||
|
// | };
|
||
|
|
||
|
var ret = {}, elems = dom.byId(formNode).elements;
|
||
|
for(var i = 0, l = elems.length; i < l; ++i){
|
||
|
var item = elems[i], _in = item.name, type = (item.type || "").toLowerCase();
|
||
|
if(_in && type && exclude.indexOf(type) < 0 && !item.disabled){
|
||
|
setValue(ret, _in, form.fieldToObject(item));
|
||
|
if(type == "image"){
|
||
|
ret[_in + ".x"] = ret[_in + ".y"] = ret[_in].x = ret[_in].y = 0;
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
return ret; // Object
|
||
|
},
|
||
|
|
||
|
toQuery: function formToQuery(/*DOMNode|String*/ formNode){
|
||
|
// summary:
|
||
|
// Returns a URL-encoded string representing the form passed as either a
|
||
|
// node or string ID identifying the form to serialize
|
||
|
// formNode: DOMNode|String
|
||
|
// returns: String
|
||
|
|
||
|
return ioq.objectToQuery(form.toObject(formNode)); // String
|
||
|
},
|
||
|
|
||
|
toJson: function formToJson(/*DOMNode|String*/ formNode, /*Boolean?*/ prettyPrint){
|
||
|
// summary:
|
||
|
// Create a serialized JSON string from a form node or string
|
||
|
// ID identifying the form to serialize
|
||
|
// formNode: DOMNode|String
|
||
|
// prettyPrint: Boolean?
|
||
|
// returns: String
|
||
|
|
||
|
return json.stringify(form.toObject(formNode), null, prettyPrint ? 4 : 0); // String
|
||
|
}
|
||
|
};
|
||
|
|
||
|
return form;
|
||
|
});
|
||
|
|
||
|
},
|
||
|
'dojo/_base/Deferred':function(){
|
||
|
define([
|
||
|
"./kernel",
|
||
|
"../Deferred",
|
||
|
"../promise/Promise",
|
||
|
"../errors/CancelError",
|
||
|
"../has",
|
||
|
"./lang",
|
||
|
"../when"
|
||
|
], function(dojo, NewDeferred, Promise, CancelError, has, lang, when){
|
||
|
// module:
|
||
|
// dojo/_base/Deferred
|
||
|
|
||
|
var mutator = function(){};
|
||
|
var freeze = Object.freeze || function(){};
|
||
|
// A deferred provides an API for creating and resolving a promise.
|
||
|
var Deferred = dojo.Deferred = function(/*Function?*/ canceller){
|
||
|
// summary:
|
||
|
// Deprecated. This module defines the legacy dojo/_base/Deferred API.
|
||
|
// New code should use dojo/Deferred instead.
|
||
|
// description:
|
||
|
// The Deferred API is based on the concept of promises that provide a
|
||
|
// generic interface into the eventual completion of an asynchronous action.
|
||
|
// The motivation for promises fundamentally is about creating a
|
||
|
// separation of concerns that allows one to achieve the same type of
|
||
|
// call patterns and logical data flow in asynchronous code as can be
|
||
|
// achieved in synchronous code. Promises allows one
|
||
|
// to be able to call a function purely with arguments needed for
|
||
|
// execution, without conflating the call with concerns of whether it is
|
||
|
// sync or async. One shouldn't need to alter a call's arguments if the
|
||
|
// implementation switches from sync to async (or vice versa). By having
|
||
|
// async functions return promises, the concerns of making the call are
|
||
|
// separated from the concerns of asynchronous interaction (which are
|
||
|
// handled by the promise).
|
||
|
//
|
||
|
// The Deferred is a type of promise that provides methods for fulfilling the
|
||
|
// promise with a successful result or an error. The most important method for
|
||
|
// working with Dojo's promises is the then() method, which follows the
|
||
|
// CommonJS proposed promise API. An example of using a Dojo promise:
|
||
|
//
|
||
|
// | var resultingPromise = someAsyncOperation.then(function(result){
|
||
|
// | ... handle result ...
|
||
|
// | },
|
||
|
// | function(error){
|
||
|
// | ... handle error ...
|
||
|
// | });
|
||
|
//
|
||
|
// The .then() call returns a new promise that represents the result of the
|
||
|
// execution of the callback. The callbacks will never affect the original promises value.
|
||
|
//
|
||
|
// The Deferred instances also provide the following functions for backwards compatibility:
|
||
|
//
|
||
|
// - addCallback(handler)
|
||
|
// - addErrback(handler)
|
||
|
// - callback(result)
|
||
|
// - errback(result)
|
||
|
//
|
||
|
// Callbacks are allowed to return promises themselves, so
|
||
|
// you can build complicated sequences of events with ease.
|
||
|
//
|
||
|
// The creator of the Deferred may specify a canceller. The canceller
|
||
|
// is a function that will be called if Deferred.cancel is called
|
||
|
// before the Deferred fires. You can use this to implement clean
|
||
|
// aborting of an XMLHttpRequest, etc. Note that cancel will fire the
|
||
|
// deferred with a CancelledError (unless your canceller returns
|
||
|
// another kind of error), so the errbacks should be prepared to
|
||
|
// handle that error for cancellable Deferreds.
|
||
|
// example:
|
||
|
// | var deferred = new Deferred();
|
||
|
// | setTimeout(function(){ deferred.callback({success: true}); }, 1000);
|
||
|
// | return deferred;
|
||
|
// example:
|
||
|
// Deferred objects are often used when making code asynchronous. It
|
||
|
// may be easiest to write functions in a synchronous manner and then
|
||
|
// split code using a deferred to trigger a response to a long-lived
|
||
|
// operation. For example, instead of register a callback function to
|
||
|
// denote when a rendering operation completes, the function can
|
||
|
// simply return a deferred:
|
||
|
//
|
||
|
// | // callback style:
|
||
|
// | function renderLotsOfData(data, callback){
|
||
|
// | var success = false
|
||
|
// | try{
|
||
|
// | for(var x in data){
|
||
|
// | renderDataitem(data[x]);
|
||
|
// | }
|
||
|
// | success = true;
|
||
|
// | }catch(e){ }
|
||
|
// | if(callback){
|
||
|
// | callback(success);
|
||
|
// | }
|
||
|
// | }
|
||
|
//
|
||
|
// | // using callback style
|
||
|
// | renderLotsOfData(someDataObj, function(success){
|
||
|
// | // handles success or failure
|
||
|
// | if(!success){
|
||
|
// | promptUserToRecover();
|
||
|
// | }
|
||
|
// | });
|
||
|
// | // NOTE: no way to add another callback here!!
|
||
|
// example:
|
||
|
// Using a Deferred doesn't simplify the sending code any, but it
|
||
|
// provides a standard interface for callers and senders alike,
|
||
|
// providing both with a simple way to service multiple callbacks for
|
||
|
// an operation and freeing both sides from worrying about details
|
||
|
// such as "did this get called already?". With Deferreds, new
|
||
|
// callbacks can be added at any time.
|
||
|
//
|
||
|
// | // Deferred style:
|
||
|
// | function renderLotsOfData(data){
|
||
|
// | var d = new Deferred();
|
||
|
// | try{
|
||
|
// | for(var x in data){
|
||
|
// | renderDataitem(data[x]);
|
||
|
// | }
|
||
|
// | d.callback(true);
|
||
|
// | }catch(e){
|
||
|
// | d.errback(new Error("rendering failed"));
|
||
|
// | }
|
||
|
// | return d;
|
||
|
// | }
|
||
|
//
|
||
|
// | // using Deferred style
|
||
|
// | renderLotsOfData(someDataObj).then(null, function(){
|
||
|
// | promptUserToRecover();
|
||
|
// | });
|
||
|
// | // NOTE: addErrback and addCallback both return the Deferred
|
||
|
// | // again, so we could chain adding callbacks or save the
|
||
|
// | // deferred for later should we need to be notified again.
|
||
|
// example:
|
||
|
// In this example, renderLotsOfData is synchronous and so both
|
||
|
// versions are pretty artificial. Putting the data display on a
|
||
|
// timeout helps show why Deferreds rock:
|
||
|
//
|
||
|
// | // Deferred style and async func
|
||
|
// | function renderLotsOfData(data){
|
||
|
// | var d = new Deferred();
|
||
|
// | setTimeout(function(){
|
||
|
// | try{
|
||
|
// | for(var x in data){
|
||
|
// | renderDataitem(data[x]);
|
||
|
// | }
|
||
|
// | d.callback(true);
|
||
|
// | }catch(e){
|
||
|
// | d.errback(new Error("rendering failed"));
|
||
|
// | }
|
||
|
// | }, 100);
|
||
|
// | return d;
|
||
|
// | }
|
||
|
//
|
||
|
// | // using Deferred style
|
||
|
// | renderLotsOfData(someDataObj).then(null, function(){
|
||
|
// | promptUserToRecover();
|
||
|
// | });
|
||
|
//
|
||
|
// Note that the caller doesn't have to change his code at all to
|
||
|
// handle the asynchronous case.
|
||
|
|
||
|
var result, finished, canceled, fired, isError, head, nextListener;
|
||
|
var promise = (this.promise = new Promise());
|
||
|
|
||
|
function complete(value){
|
||
|
if(finished){
|
||
|
throw new Error("This deferred has already been resolved");
|
||
|
}
|
||
|
result = value;
|
||
|
finished = true;
|
||
|
notify();
|
||
|
}
|
||
|
function notify(){
|
||
|
var mutated;
|
||
|
while(!mutated && nextListener){
|
||
|
var listener = nextListener;
|
||
|
nextListener = nextListener.next;
|
||
|
if((mutated = (listener.progress == mutator))){ // assignment and check
|
||
|
finished = false;
|
||
|
}
|
||
|
|
||
|
var func = (isError ? listener.error : listener.resolved);
|
||
|
if(has("config-useDeferredInstrumentation")){
|
||
|
if(isError && NewDeferred.instrumentRejected){
|
||
|
NewDeferred.instrumentRejected(result, !!func);
|
||
|
}
|
||
|
}
|
||
|
if(func){
|
||
|
try{
|
||
|
var newResult = func(result);
|
||
|
if (newResult && typeof newResult.then === "function"){
|
||
|
newResult.then(lang.hitch(listener.deferred, "resolve"), lang.hitch(listener.deferred, "reject"), lang.hitch(listener.deferred, "progress"));
|
||
|
continue;
|
||
|
}
|
||
|
var unchanged = mutated && newResult === undefined;
|
||
|
if(mutated && !unchanged){
|
||
|
isError = newResult instanceof Error;
|
||
|
}
|
||
|
listener.deferred[unchanged && isError ? "reject" : "resolve"](unchanged ? result : newResult);
|
||
|
}catch(e){
|
||
|
listener.deferred.reject(e);
|
||
|
}
|
||
|
}else{
|
||
|
if(isError){
|
||
|
listener.deferred.reject(result);
|
||
|
}else{
|
||
|
listener.deferred.resolve(result);
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
|
||
|
this.isResolved = promise.isResolved = function(){
|
||
|
// summary:
|
||
|
// Checks whether the deferred has been resolved.
|
||
|
// returns: Boolean
|
||
|
|
||
|
return fired == 0;
|
||
|
};
|
||
|
|
||
|
this.isRejected = promise.isRejected = function(){
|
||
|
// summary:
|
||
|
// Checks whether the deferred has been rejected.
|
||
|
// returns: Boolean
|
||
|
|
||
|
return fired == 1;
|
||
|
};
|
||
|
|
||
|
this.isFulfilled = promise.isFulfilled = function(){
|
||
|
// summary:
|
||
|
// Checks whether the deferred has been resolved or rejected.
|
||
|
// returns: Boolean
|
||
|
|
||
|
return fired >= 0;
|
||
|
};
|
||
|
|
||
|
this.isCanceled = promise.isCanceled = function(){
|
||
|
// summary:
|
||
|
// Checks whether the deferred has been canceled.
|
||
|
// returns: Boolean
|
||
|
|
||
|
return canceled;
|
||
|
};
|
||
|
|
||
|
// calling resolve will resolve the promise
|
||
|
this.resolve = this.callback = function(value){
|
||
|
// summary:
|
||
|
// Fulfills the Deferred instance successfully with the provide value
|
||
|
this.fired = fired = 0;
|
||
|
this.results = [value, null];
|
||
|
complete(value);
|
||
|
};
|
||
|
|
||
|
|
||
|
// calling error will indicate that the promise failed
|
||
|
this.reject = this.errback = function(error){
|
||
|
// summary:
|
||
|
// Fulfills the Deferred instance as an error with the provided error
|
||
|
isError = true;
|
||
|
this.fired = fired = 1;
|
||
|
if(has("config-useDeferredInstrumentation")){
|
||
|
if(NewDeferred.instrumentRejected){
|
||
|
NewDeferred.instrumentRejected(error, !!nextListener);
|
||
|
}
|
||
|
}
|
||
|
complete(error);
|
||
|
this.results = [null, error];
|
||
|
};
|
||
|
// call progress to provide updates on the progress on the completion of the promise
|
||
|
this.progress = function(update){
|
||
|
// summary:
|
||
|
// Send progress events to all listeners
|
||
|
var listener = nextListener;
|
||
|
while(listener){
|
||
|
var progress = listener.progress;
|
||
|
progress && progress(update);
|
||
|
listener = listener.next;
|
||
|
}
|
||
|
};
|
||
|
this.addCallbacks = function(callback, errback){
|
||
|
// summary:
|
||
|
// Adds callback and error callback for this deferred instance.
|
||
|
// callback: Function?
|
||
|
// The callback attached to this deferred object.
|
||
|
// errback: Function?
|
||
|
// The error callback attached to this deferred object.
|
||
|
// returns:
|
||
|
// Returns this deferred object.
|
||
|
this.then(callback, errback, mutator);
|
||
|
return this; // Deferred
|
||
|
};
|
||
|
// provide the implementation of the promise
|
||
|
promise.then = this.then = function(/*Function?*/resolvedCallback, /*Function?*/errorCallback, /*Function?*/progressCallback){
|
||
|
// summary:
|
||
|
// Adds a fulfilledHandler, errorHandler, and progressHandler to be called for
|
||
|
// completion of a promise. The fulfilledHandler is called when the promise
|
||
|
// is fulfilled. The errorHandler is called when a promise fails. The
|
||
|
// progressHandler is called for progress events. All arguments are optional
|
||
|
// and non-function values are ignored. The progressHandler is not only an
|
||
|
// optional argument, but progress events are purely optional. Promise
|
||
|
// providers are not required to ever create progress events.
|
||
|
//
|
||
|
// This function will return a new promise that is fulfilled when the given
|
||
|
// fulfilledHandler or errorHandler callback is finished. This allows promise
|
||
|
// operations to be chained together. The value returned from the callback
|
||
|
// handler is the fulfillment value for the returned promise. If the callback
|
||
|
// throws an error, the returned promise will be moved to failed state.
|
||
|
//
|
||
|
// returns:
|
||
|
// Returns a new promise that represents the result of the
|
||
|
// execution of the callback. The callbacks will never affect the original promises value.
|
||
|
// example:
|
||
|
// An example of using a CommonJS compliant promise:
|
||
|
// | asyncComputeTheAnswerToEverything().
|
||
|
// | then(addTwo).
|
||
|
// | then(printResult, onError);
|
||
|
// | >44
|
||
|
//
|
||
|
var returnDeferred = progressCallback == mutator ? this : new Deferred(promise.cancel);
|
||
|
var listener = {
|
||
|
resolved: resolvedCallback,
|
||
|
error: errorCallback,
|
||
|
progress: progressCallback,
|
||
|
deferred: returnDeferred
|
||
|
};
|
||
|
if(nextListener){
|
||
|
head = head.next = listener;
|
||
|
}
|
||
|
else{
|
||
|
nextListener = head = listener;
|
||
|
}
|
||
|
if(finished){
|
||
|
notify();
|
||
|
}
|
||
|
return returnDeferred.promise; // Promise
|
||
|
};
|
||
|
var deferred = this;
|
||
|
promise.cancel = this.cancel = function(){
|
||
|
// summary:
|
||
|
// Cancels the asynchronous operation
|
||
|
if(!finished){
|
||
|
var error = canceller && canceller(deferred);
|
||
|
if(!finished){
|
||
|
if (!(error instanceof Error)){
|
||
|
error = new CancelError(error);
|
||
|
}
|
||
|
error.log = false;
|
||
|
deferred.reject(error);
|
||
|
}
|
||
|
}
|
||
|
canceled = true;
|
||
|
};
|
||
|
freeze(promise);
|
||
|
};
|
||
|
lang.extend(Deferred, {
|
||
|
addCallback: function(/*Function*/ callback){
|
||
|
// summary:
|
||
|
// Adds successful callback for this deferred instance.
|
||
|
// returns:
|
||
|
// Returns this deferred object.
|
||
|
return this.addCallbacks(lang.hitch.apply(dojo, arguments)); // Deferred
|
||
|
},
|
||
|
|
||
|
addErrback: function(/*Function*/ errback){
|
||
|
// summary:
|
||
|
// Adds error callback for this deferred instance.
|
||
|
// returns:
|
||
|
// Returns this deferred object.
|
||
|
return this.addCallbacks(null, lang.hitch.apply(dojo, arguments)); // Deferred
|
||
|
},
|
||
|
|
||
|
addBoth: function(/*Function*/ callback){
|
||
|
// summary:
|
||
|
// Add handler as both successful callback and error callback for this deferred instance.
|
||
|
// returns:
|
||
|
// Returns this deferred object.
|
||
|
var enclosed = lang.hitch.apply(dojo, arguments);
|
||
|
return this.addCallbacks(enclosed, enclosed); // Deferred
|
||
|
},
|
||
|
fired: -1
|
||
|
});
|
||
|
|
||
|
Deferred.when = dojo.when = when;
|
||
|
|
||
|
return Deferred;
|
||
|
});
|
||
|
|
||
|
},
|
||
|
'dojo/Deferred':function(){
|
||
|
define([
|
||
|
"./has",
|
||
|
"./_base/lang",
|
||
|
"./errors/CancelError",
|
||
|
"./promise/Promise",
|
||
|
"./promise/instrumentation"
|
||
|
], function(has, lang, CancelError, Promise, instrumentation){
|
||
|
"use strict";
|
||
|
|
||
|
// module:
|
||
|
// dojo/Deferred
|
||
|
|
||
|
var PROGRESS = 0,
|
||
|
RESOLVED = 1,
|
||
|
REJECTED = 2;
|
||
|
var FULFILLED_ERROR_MESSAGE = "This deferred has already been fulfilled.";
|
||
|
|
||
|
var freezeObject = Object.freeze || function(){};
|
||
|
|
||
|
var signalWaiting = function(waiting, type, result, rejection, deferred){
|
||
|
if( 1 ){
|
||
|
if(type === REJECTED && Deferred.instrumentRejected && waiting.length === 0){
|
||
|
Deferred.instrumentRejected(result, false, rejection, deferred);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
for(var i = 0; i < waiting.length; i++){
|
||
|
signalListener(waiting[i], type, result, rejection);
|
||
|
}
|
||
|
};
|
||
|
|
||
|
var signalListener = function(listener, type, result, rejection){
|
||
|
var func = listener[type];
|
||
|
var deferred = listener.deferred;
|
||
|
if(func){
|
||
|
try{
|
||
|
var newResult = func(result);
|
||
|
if(type === PROGRESS){
|
||
|
if(typeof newResult !== "undefined"){
|
||
|
signalDeferred(deferred, type, newResult);
|
||
|
}
|
||
|
}else{
|
||
|
if(newResult && typeof newResult.then === "function"){
|
||
|
listener.cancel = newResult.cancel;
|
||
|
newResult.then(
|
||
|
// Only make resolvers if they're actually going to be used
|
||
|
makeDeferredSignaler(deferred, RESOLVED),
|
||
|
makeDeferredSignaler(deferred, REJECTED),
|
||
|
makeDeferredSignaler(deferred, PROGRESS));
|
||
|
return;
|
||
|
}
|
||
|
signalDeferred(deferred, RESOLVED, newResult);
|
||
|
}
|
||
|
}catch(error){
|
||
|
signalDeferred(deferred, REJECTED, error);
|
||
|
}
|
||
|
}else{
|
||
|
signalDeferred(deferred, type, result);
|
||
|
}
|
||
|
|
||
|
if( 1 ){
|
||
|
if(type === REJECTED && Deferred.instrumentRejected){
|
||
|
Deferred.instrumentRejected(result, !!func, rejection, deferred.promise);
|
||
|
}
|
||
|
}
|
||
|
};
|
||
|
|
||
|
var makeDeferredSignaler = function(deferred, type){
|
||
|
return function(value){
|
||
|
signalDeferred(deferred, type, value);
|
||
|
};
|
||
|
};
|
||
|
|
||
|
var signalDeferred = function(deferred, type, result){
|
||
|
if(!deferred.isCanceled()){
|
||
|
switch(type){
|
||
|
case PROGRESS:
|
||
|
deferred.progress(result);
|
||
|
break;
|
||
|
case RESOLVED:
|
||
|
deferred.resolve(result);
|
||
|
break;
|
||
|
case REJECTED:
|
||
|
deferred.reject(result);
|
||
|
break;
|
||
|
}
|
||
|
}
|
||
|
};
|
||
|
|
||
|
var Deferred = function(canceler){
|
||
|
// summary:
|
||
|
// Creates a new deferred. This API is preferred over
|
||
|
// `dojo/_base/Deferred`.
|
||
|
// description:
|
||
|
// Creates a new deferred, as an abstraction over (primarily)
|
||
|
// asynchronous operations. The deferred is the private interface
|
||
|
// that should not be returned to calling code. That's what the
|
||
|
// `promise` is for. See `dojo/promise/Promise`.
|
||
|
// canceler: Function?
|
||
|
// Will be invoked if the deferred is canceled. The canceler
|
||
|
// receives the reason the deferred was canceled as its argument.
|
||
|
// The deferred is rejected with its return value, or a new
|
||
|
// `dojo/errors/CancelError` instance.
|
||
|
|
||
|
// promise: dojo/promise/Promise
|
||
|
// The public promise object that clients can add callbacks to.
|
||
|
var promise = this.promise = new Promise();
|
||
|
|
||
|
var deferred = this;
|
||
|
var fulfilled, result, rejection;
|
||
|
var canceled = false;
|
||
|
var waiting = [];
|
||
|
|
||
|
if( 1 && Error.captureStackTrace){
|
||
|
Error.captureStackTrace(deferred, Deferred);
|
||
|
Error.captureStackTrace(promise, Deferred);
|
||
|
}
|
||
|
|
||
|
this.isResolved = promise.isResolved = function(){
|
||
|
// summary:
|
||
|
// Checks whether the deferred has been resolved.
|
||
|
// returns: Boolean
|
||
|
|
||
|
return fulfilled === RESOLVED;
|
||
|
};
|
||
|
|
||
|
this.isRejected = promise.isRejected = function(){
|
||
|
// summary:
|
||
|
// Checks whether the deferred has been rejected.
|
||
|
// returns: Boolean
|
||
|
|
||
|
return fulfilled === REJECTED;
|
||
|
};
|
||
|
|
||
|
this.isFulfilled = promise.isFulfilled = function(){
|
||
|
// summary:
|
||
|
// Checks whether the deferred has been resolved or rejected.
|
||
|
// returns: Boolean
|
||
|
|
||
|
return !!fulfilled;
|
||
|
};
|
||
|
|
||
|
this.isCanceled = promise.isCanceled = function(){
|
||
|
// summary:
|
||
|
// Checks whether the deferred has been canceled.
|
||
|
// returns: Boolean
|
||
|
|
||
|
return canceled;
|
||
|
};
|
||
|
|
||
|
this.progress = function(update, strict){
|
||
|
// summary:
|
||
|
// Emit a progress update on the deferred.
|
||
|
// description:
|
||
|
// Emit a progress update on the deferred. Progress updates
|
||
|
// can be used to communicate updates about the asynchronous
|
||
|
// operation before it has finished.
|
||
|
// update: any
|
||
|
// The progress update. Passed to progbacks.
|
||
|
// strict: Boolean?
|
||
|
// If strict, will throw an error if the deferred has already
|
||
|
// been fulfilled and consequently no progress can be emitted.
|
||
|
// returns: dojo/promise/Promise
|
||
|
// Returns the original promise for the deferred.
|
||
|
|
||
|
if(!fulfilled){
|
||
|
signalWaiting(waiting, PROGRESS, update, null, deferred);
|
||
|
return promise;
|
||
|
}else if(strict === true){
|
||
|
throw new Error(FULFILLED_ERROR_MESSAGE);
|
||
|
}else{
|
||
|
return promise;
|
||
|
}
|
||
|
};
|
||
|
|
||
|
this.resolve = function(value, strict){
|
||
|
// summary:
|
||
|
// Resolve the deferred.
|
||
|
// description:
|
||
|
// Resolve the deferred, putting it in a success state.
|
||
|
// value: any
|
||
|
// The result of the deferred. Passed to callbacks.
|
||
|
// strict: Boolean?
|
||
|
// If strict, will throw an error if the deferred has already
|
||
|
// been fulfilled and consequently cannot be resolved.
|
||
|
// returns: dojo/promise/Promise
|
||
|
// Returns the original promise for the deferred.
|
||
|
|
||
|
if(!fulfilled){
|
||
|
// Set fulfilled, store value. After signaling waiting listeners unset
|
||
|
// waiting.
|
||
|
signalWaiting(waiting, fulfilled = RESOLVED, result = value, null, deferred);
|
||
|
waiting = null;
|
||
|
return promise;
|
||
|
}else if(strict === true){
|
||
|
throw new Error(FULFILLED_ERROR_MESSAGE);
|
||
|
}else{
|
||
|
return promise;
|
||
|
}
|
||
|
};
|
||
|
|
||
|
var reject = this.reject = function(error, strict){
|
||
|
// summary:
|
||
|
// Reject the deferred.
|
||
|
// description:
|
||
|
// Reject the deferred, putting it in an error state.
|
||
|
// error: any
|
||
|
// The error result of the deferred. Passed to errbacks.
|
||
|
// strict: Boolean?
|
||
|
// If strict, will throw an error if the deferred has already
|
||
|
// been fulfilled and consequently cannot be rejected.
|
||
|
// returns: dojo/promise/Promise
|
||
|
// Returns the original promise for the deferred.
|
||
|
|
||
|
if(!fulfilled){
|
||
|
if( 1 && Error.captureStackTrace){
|
||
|
Error.captureStackTrace(rejection = {}, reject);
|
||
|
}
|
||
|
signalWaiting(waiting, fulfilled = REJECTED, result = error, rejection, deferred);
|
||
|
waiting = null;
|
||
|
return promise;
|
||
|
}else if(strict === true){
|
||
|
throw new Error(FULFILLED_ERROR_MESSAGE);
|
||
|
}else{
|
||
|
return promise;
|
||
|
}
|
||
|
};
|
||
|
|
||
|
this.then = promise.then = function(callback, errback, progback){
|
||
|
// summary:
|
||
|
// Add new callbacks to the deferred.
|
||
|
// description:
|
||
|
// Add new callbacks to the deferred. Callbacks can be added
|
||
|
// before or after the deferred is fulfilled.
|
||
|
// callback: Function?
|
||
|
// Callback to be invoked when the promise is resolved.
|
||
|
// Receives the resolution value.
|
||
|
// errback: Function?
|
||
|
// Callback to be invoked when the promise is rejected.
|
||
|
// Receives the rejection error.
|
||
|
// progback: Function?
|
||
|
// Callback to be invoked when the promise emits a progress
|
||
|
// update. Receives the progress update.
|
||
|
// returns: dojo/promise/Promise
|
||
|
// Returns a new promise for the result of the callback(s).
|
||
|
// This can be used for chaining many asynchronous operations.
|
||
|
|
||
|
var listener = [progback, callback, errback];
|
||
|
// Ensure we cancel the promise we're waiting for, or if callback/errback
|
||
|
// have returned a promise, cancel that one.
|
||
|
listener.cancel = promise.cancel;
|
||
|
listener.deferred = new Deferred(function(reason){
|
||
|
// Check whether cancel is really available, returned promises are not
|
||
|
// required to expose `cancel`
|
||
|
return listener.cancel && listener.cancel(reason);
|
||
|
});
|
||
|
if(fulfilled && !waiting){
|
||
|
signalListener(listener, fulfilled, result, rejection);
|
||
|
}else{
|
||
|
waiting.push(listener);
|
||
|
}
|
||
|
return listener.deferred.promise;
|
||
|
};
|
||
|
|
||
|
this.cancel = promise.cancel = function(reason, strict){
|
||
|
// summary:
|
||
|
// Inform the deferred it may cancel its asynchronous operation.
|
||
|
// description:
|
||
|
// Inform the deferred it may cancel its asynchronous operation.
|
||
|
// The deferred's (optional) canceler is invoked and the
|
||
|
// deferred will be left in a rejected state. Can affect other
|
||
|
// promises that originate with the same deferred.
|
||
|
// reason: any
|
||
|
// A message that may be sent to the deferred's canceler,
|
||
|
// explaining why it's being canceled.
|
||
|
// strict: Boolean?
|
||
|
// If strict, will throw an error if the deferred has already
|
||
|
// been fulfilled and consequently cannot be canceled.
|
||
|
// returns: any
|
||
|
// Returns the rejection reason if the deferred was canceled
|
||
|
// normally.
|
||
|
|
||
|
if(!fulfilled){
|
||
|
// Cancel can be called even after the deferred is fulfilled
|
||
|
if(canceler){
|
||
|
var returnedReason = canceler(reason);
|
||
|
reason = typeof returnedReason === "undefined" ? reason : returnedReason;
|
||
|
}
|
||
|
canceled = true;
|
||
|
if(!fulfilled){
|
||
|
// Allow canceler to provide its own reason, but fall back to a CancelError
|
||
|
if(typeof reason === "undefined"){
|
||
|
reason = new CancelError();
|
||
|
}
|
||
|
reject(reason);
|
||
|
return reason;
|
||
|
}else if(fulfilled === REJECTED && result === reason){
|
||
|
return reason;
|
||
|
}
|
||
|
}else if(strict === true){
|
||
|
throw new Error(FULFILLED_ERROR_MESSAGE);
|
||
|
}
|
||
|
};
|
||
|
|
||
|
freezeObject(promise);
|
||
|
};
|
||
|
|
||
|
Deferred.prototype.toString = function(){
|
||
|
// returns: String
|
||
|
// Returns `[object Deferred]`.
|
||
|
|
||
|
return "[object Deferred]";
|
||
|
};
|
||
|
|
||
|
if(instrumentation){
|
||
|
instrumentation(Deferred);
|
||
|
}
|
||
|
|
||
|
return Deferred;
|
||
|
});
|
||
|
|
||
|
},
|
||
|
'dojo/errors/CancelError':function(){
|
||
|
define(["./create"], function(create){
|
||
|
// module:
|
||
|
// dojo/errors/CancelError
|
||
|
|
||
|
/*=====
|
||
|
return function(){
|
||
|
// summary:
|
||
|
// Default error if a promise is canceled without a reason.
|
||
|
};
|
||
|
=====*/
|
||
|
|
||
|
return create("CancelError", null, null, { dojoType: "cancel", log: false });
|
||
|
});
|
||
|
|
||
|
},
|
||
|
'dojo/errors/create':function(){
|
||
|
define(["../_base/lang"], function(lang){
|
||
|
return function(name, ctor, base, props){
|
||
|
base = base || Error;
|
||
|
|
||
|
var ErrorCtor = function(message){
|
||
|
if(base === Error){
|
||
|
if(Error.captureStackTrace){
|
||
|
Error.captureStackTrace(this, ErrorCtor);
|
||
|
}
|
||
|
|
||
|
// Error.call() operates on the returned error
|
||
|
// object rather than operating on |this|
|
||
|
var err = Error.call(this, message),
|
||
|
prop;
|
||
|
|
||
|
// Copy own properties from err to |this|
|
||
|
for(prop in err){
|
||
|
if(err.hasOwnProperty(prop)){
|
||
|
this[prop] = err[prop];
|
||
|
}
|
||
|
}
|
||
|
|
||
|
// messsage is non-enumerable in ES5
|
||
|
this.message = message;
|
||
|
// stack is non-enumerable in at least Firefox
|
||
|
this.stack = err.stack;
|
||
|
}else{
|
||
|
base.apply(this, arguments);
|
||
|
}
|
||
|
if(ctor){
|
||
|
ctor.apply(this, arguments);
|
||
|
}
|
||
|
};
|
||
|
|
||
|
ErrorCtor.prototype = lang.delegate(base.prototype, props);
|
||
|
ErrorCtor.prototype.name = name;
|
||
|
ErrorCtor.prototype.constructor = ErrorCtor;
|
||
|
|
||
|
return ErrorCtor;
|
||
|
};
|
||
|
});
|
||
|
|
||
|
},
|
||
|
'dojo/promise/Promise':function(){
|
||
|
define([
|
||
|
"../_base/lang"
|
||
|
], function(lang){
|
||
|
"use strict";
|
||
|
|
||
|
// module:
|
||
|
// dojo/promise/Promise
|
||
|
|
||
|
function throwAbstract(){
|
||
|
throw new TypeError("abstract");
|
||
|
}
|
||
|
|
||
|
return lang.extend(function Promise(){
|
||
|
// summary:
|
||
|
// The public interface to a deferred.
|
||
|
// description:
|
||
|
// The public interface to a deferred. All promises in Dojo are
|
||
|
// instances of this class.
|
||
|
}, {
|
||
|
then: function(callback, errback, progback){
|
||
|
// summary:
|
||
|
// Add new callbacks to the promise.
|
||
|
// description:
|
||
|
// Add new callbacks to the deferred. Callbacks can be added
|
||
|
// before or after the deferred is fulfilled.
|
||
|
// callback: Function?
|
||
|
// Callback to be invoked when the promise is resolved.
|
||
|
// Receives the resolution value.
|
||
|
// errback: Function?
|
||
|
// Callback to be invoked when the promise is rejected.
|
||
|
// Receives the rejection error.
|
||
|
// progback: Function?
|
||
|
// Callback to be invoked when the promise emits a progress
|
||
|
// update. Receives the progress update.
|
||
|
// returns: dojo/promise/Promise
|
||
|
// Returns a new promise for the result of the callback(s).
|
||
|
// This can be used for chaining many asynchronous operations.
|
||
|
|
||
|
throwAbstract();
|
||
|
},
|
||
|
|
||
|
cancel: function(reason, strict){
|
||
|
// summary:
|
||
|
// Inform the deferred it may cancel its asynchronous operation.
|
||
|
// description:
|
||
|
// Inform the deferred it may cancel its asynchronous operation.
|
||
|
// The deferred's (optional) canceler is invoked and the
|
||
|
// deferred will be left in a rejected state. Can affect other
|
||
|
// promises that originate with the same deferred.
|
||
|
// reason: any
|
||
|
// A message that may be sent to the deferred's canceler,
|
||
|
// explaining why it's being canceled.
|
||
|
// strict: Boolean?
|
||
|
// If strict, will throw an error if the deferred has already
|
||
|
// been fulfilled and consequently cannot be canceled.
|
||
|
// returns: any
|
||
|
// Returns the rejection reason if the deferred was canceled
|
||
|
// normally.
|
||
|
|
||
|
throwAbstract();
|
||
|
},
|
||
|
|
||
|
isResolved: function(){
|
||
|
// summary:
|
||
|
// Checks whether the promise has been resolved.
|
||
|
// returns: Boolean
|
||
|
|
||
|
throwAbstract();
|
||
|
},
|
||
|
|
||
|
isRejected: function(){
|
||
|
// summary:
|
||
|
// Checks whether the promise has been rejected.
|
||
|
// returns: Boolean
|
||
|
|
||
|
throwAbstract();
|
||
|
},
|
||
|
|
||
|
isFulfilled: function(){
|
||
|
// summary:
|
||
|
// Checks whether the promise has been resolved or rejected.
|
||
|
// returns: Boolean
|
||
|
|
||
|
throwAbstract();
|
||
|
},
|
||
|
|
||
|
isCanceled: function(){
|
||
|
// summary:
|
||
|
// Checks whether the promise has been canceled.
|
||
|
// returns: Boolean
|
||
|
|
||
|
throwAbstract();
|
||
|
},
|
||
|
|
||
|
"finally": function(callback) {
|
||
|
// summary:
|
||
|
// Add a callback to the promise that will fire whether it
|
||
|
// resolves or rejects.
|
||
|
// description:
|
||
|
// Conforms to ES2018's `Promise.prototype.finally`.
|
||
|
// Add a callback to the promise that will fire whether it
|
||
|
// resolves or rejects. No value is passed to the callback.
|
||
|
// Returns a promise that reflects the state of the original promise,
|
||
|
// with two exceptions:
|
||
|
// - If the callback return a promise, the outer promise will wait
|
||
|
// until the returned promise is resolved, then it will resolve
|
||
|
// with the original value.
|
||
|
// - If the callback throws an exception or returns a promise that
|
||
|
// is rejected (or rejects later), the outer promise will reject
|
||
|
// with the inner promise's rejection reason.
|
||
|
// callback: Function?
|
||
|
// Callback to be invoked when the promise is resolved
|
||
|
// or rejected. Doesn't receive any value.
|
||
|
// returns: dojo/promise/Promise
|
||
|
// Returns a new promise that reflects the state of the original promise,
|
||
|
// with two small exceptions (see description).
|
||
|
//
|
||
|
|
||
|
return this.then(function (value){
|
||
|
var valueOrPromise = callback();
|
||
|
if (valueOrPromise && typeof valueOrPromise.then === "function"){
|
||
|
return valueOrPromise.then(function (){
|
||
|
return value;
|
||
|
});
|
||
|
}
|
||
|
return value;
|
||
|
}, function(reason) {
|
||
|
var valueOrPromise = callback();
|
||
|
if (valueOrPromise && typeof valueOrPromise.then === "function"){
|
||
|
return valueOrPromise.then(function (){
|
||
|
throw reason;
|
||
|
});
|
||
|
}
|
||
|
throw reason;
|
||
|
});
|
||
|
},
|
||
|
|
||
|
always: function(callbackOrErrback){
|
||
|
// summary:
|
||
|
// Add a callback to be invoked when the promise is resolved
|
||
|
// or rejected.
|
||
|
// callbackOrErrback: Function?
|
||
|
// A function that is used both as a callback and errback.
|
||
|
// returns: dojo/promise/Promise
|
||
|
// Returns a new promise for the result of the callback/errback.
|
||
|
|
||
|
return this.then(callbackOrErrback, callbackOrErrback);
|
||
|
},
|
||
|
|
||
|
"catch": function(errback){
|
||
|
// summary:
|
||
|
// Add new errbacks to the promise. Follows ECMA specification naming.
|
||
|
// errback: Function?
|
||
|
// Callback to be invoked when the promise is rejected.
|
||
|
// returns: dojo/promise/Promise
|
||
|
// Returns a new promise for the result of the errback.
|
||
|
|
||
|
return this.then(null, errback);
|
||
|
},
|
||
|
|
||
|
otherwise: function(errback){
|
||
|
// summary:
|
||
|
// Add new errbacks to the promise.
|
||
|
// errback: Function?
|
||
|
// Callback to be invoked when the promise is rejected.
|
||
|
// returns: dojo/promise/Promise
|
||
|
// Returns a new promise for the result of the errback.
|
||
|
|
||
|
return this.then(null, errback);
|
||
|
},
|
||
|
|
||
|
trace: function(){
|
||
|
return this;
|
||
|
},
|
||
|
|
||
|
traceRejected: function(){
|
||
|
return this;
|
||
|
},
|
||
|
|
||
|
toString: function(){
|
||
|
// returns: string
|
||
|
// Returns `[object Promise]`.
|
||
|
|
||
|
return "[object Promise]";
|
||
|
}
|
||
|
});
|
||
|
});
|
||
|
|
||
|
},
|
||
|
'dojo/promise/instrumentation':function(){
|
||
|
define([
|
||
|
"./tracer",
|
||
|
"../has",
|
||
|
"../_base/lang",
|
||
|
"../_base/array"
|
||
|
], function(tracer, has, lang, arrayUtil){
|
||
|
has.add("config-useDeferredInstrumentation", "report-unhandled-rejections");
|
||
|
|
||
|
function logError(error, rejection, deferred){
|
||
|
if(error && error.log === false){
|
||
|
return;
|
||
|
}
|
||
|
var stack = "";
|
||
|
if(error && error.stack){
|
||
|
stack += error.stack;
|
||
|
}
|
||
|
if(rejection && rejection.stack){
|
||
|
stack += "\n ----------------------------------------\n rejected" + rejection.stack.split("\n").slice(1).join("\n").replace(/^\s+/, " ");
|
||
|
}
|
||
|
if(deferred && deferred.stack){
|
||
|
stack += "\n ----------------------------------------\n" + deferred.stack;
|
||
|
}
|
||
|
console.error(error, stack);
|
||
|
}
|
||
|
|
||
|
function reportRejections(error, handled, rejection, deferred){
|
||
|
if(!handled){
|
||
|
logError(error, rejection, deferred);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
var errors = [];
|
||
|
var activeTimeout = false;
|
||
|
var unhandledWait = 1000;
|
||
|
function trackUnhandledRejections(error, handled, rejection, deferred){
|
||
|
// try to find the existing tracking object
|
||
|
if(!arrayUtil.some(errors, function(obj){
|
||
|
if(obj.error === error){
|
||
|
// found the tracking object for this error
|
||
|
if(handled){
|
||
|
// if handled, update the state
|
||
|
obj.handled = true;
|
||
|
}
|
||
|
return true;
|
||
|
}
|
||
|
})){
|
||
|
// no tracking object has been setup, create one
|
||
|
errors.push({
|
||
|
error: error,
|
||
|
rejection: rejection,
|
||
|
handled: handled,
|
||
|
deferred: deferred,
|
||
|
timestamp: new Date().getTime()
|
||
|
});
|
||
|
}
|
||
|
|
||
|
if(!activeTimeout){
|
||
|
activeTimeout = setTimeout(logRejected, unhandledWait);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
function logRejected(){
|
||
|
var now = new Date().getTime();
|
||
|
var reportBefore = now - unhandledWait;
|
||
|
errors = arrayUtil.filter(errors, function(obj){
|
||
|
// only report the error if we have waited long enough and
|
||
|
// it hasn't been handled
|
||
|
if(obj.timestamp < reportBefore){
|
||
|
if(!obj.handled){
|
||
|
logError(obj.error, obj.rejection, obj.deferred);
|
||
|
}
|
||
|
return false;
|
||
|
}
|
||
|
return true;
|
||
|
});
|
||
|
|
||
|
if(errors.length){
|
||
|
activeTimeout = setTimeout(logRejected, errors[0].timestamp + unhandledWait - now);
|
||
|
}else{
|
||
|
activeTimeout = false;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
return function(Deferred){
|
||
|
// summary:
|
||
|
// Initialize instrumentation for the Deferred class.
|
||
|
// description:
|
||
|
// Initialize instrumentation for the Deferred class.
|
||
|
// Done automatically by `dojo/Deferred` if the
|
||
|
// `deferredInstrumentation` and `useDeferredInstrumentation`
|
||
|
// config options are set.
|
||
|
//
|
||
|
// Sets up `dojo/promise/tracer` to log to the console.
|
||
|
//
|
||
|
// Sets up instrumentation of rejected deferreds so unhandled
|
||
|
// errors are logged to the console.
|
||
|
|
||
|
var usage = has("config-useDeferredInstrumentation");
|
||
|
if(usage){
|
||
|
tracer.on("resolved", lang.hitch(console, "log", "resolved"));
|
||
|
tracer.on("rejected", lang.hitch(console, "log", "rejected"));
|
||
|
tracer.on("progress", lang.hitch(console, "log", "progress"));
|
||
|
|
||
|
var args = [];
|
||
|
if(typeof usage === "string"){
|
||
|
args = usage.split(",");
|
||
|
usage = args.shift();
|
||
|
}
|
||
|
if(usage === "report-rejections"){
|
||
|
Deferred.instrumentRejected = reportRejections;
|
||
|
}else if(usage === "report-unhandled-rejections" || usage === true || usage === 1){
|
||
|
Deferred.instrumentRejected = trackUnhandledRejections;
|
||
|
unhandledWait = parseInt(args[0], 10) || unhandledWait;
|
||
|
}else{
|
||
|
throw new Error("Unsupported instrumentation usage <" + usage + ">");
|
||
|
}
|
||
|
}
|
||
|
};
|
||
|
});
|
||
|
|
||
|
},
|
||
|
'dojo/promise/tracer':function(){
|
||
|
define([
|
||
|
"../_base/lang",
|
||
|
"./Promise",
|
||
|
"../Evented"
|
||
|
], function(lang, Promise, Evented){
|
||
|
"use strict";
|
||
|
|
||
|
// module:
|
||
|
// dojo/promise/tracer
|
||
|
|
||
|
/*=====
|
||
|
return {
|
||
|
// summary:
|
||
|
// Trace promise fulfillment.
|
||
|
// description:
|
||
|
// Trace promise fulfillment. Calling `.trace()` or `.traceError()` on a
|
||
|
// promise enables tracing. Will emit `resolved`, `rejected` or `progress`
|
||
|
// events.
|
||
|
|
||
|
on: function(type, listener){
|
||
|
// summary:
|
||
|
// Subscribe to traces.
|
||
|
// description:
|
||
|
// See `dojo/Evented#on()`.
|
||
|
// type: String
|
||
|
// `resolved`, `rejected`, or `progress`
|
||
|
// listener: Function
|
||
|
// The listener is passed the traced value and any arguments
|
||
|
// that were used with the `.trace()` call.
|
||
|
}
|
||
|
};
|
||
|
=====*/
|
||
|
|
||
|
var evented = new Evented;
|
||
|
var emit = evented.emit;
|
||
|
evented.emit = null;
|
||
|
// Emit events asynchronously since they should not change the promise state.
|
||
|
function emitAsync(args){
|
||
|
setTimeout(function(){
|
||
|
emit.apply(evented, args);
|
||
|
}, 0);
|
||
|
}
|
||
|
|
||
|
Promise.prototype.trace = function(){
|
||
|
// summary:
|
||
|
// Trace the promise.
|
||
|
// description:
|
||
|
// Tracing allows you to transparently log progress,
|
||
|
// resolution and rejection of promises, without affecting the
|
||
|
// promise itself. Any arguments passed to `trace()` are
|
||
|
// emitted in trace events. See `dojo/promise/tracer` on how
|
||
|
// to handle traces.
|
||
|
// returns: dojo/promise/Promise
|
||
|
// The promise instance `trace()` is called on.
|
||
|
|
||
|
var args = lang._toArray(arguments);
|
||
|
this.then(
|
||
|
function(value){ emitAsync(["resolved", value].concat(args)); },
|
||
|
function(error){ emitAsync(["rejected", error].concat(args)); },
|
||
|
function(update){ emitAsync(["progress", update].concat(args)); }
|
||
|
);
|
||
|
return this;
|
||
|
};
|
||
|
|
||
|
Promise.prototype.traceRejected = function(){
|
||
|
// summary:
|
||
|
// Trace rejection of the promise.
|
||
|
// description:
|
||
|
// Tracing allows you to transparently log progress,
|
||
|
// resolution and rejection of promises, without affecting the
|
||
|
// promise itself. Any arguments passed to `trace()` are
|
||
|
// emitted in trace events. See `dojo/promise/tracer` on how
|
||
|
// to handle traces.
|
||
|
// returns: dojo/promise/Promise
|
||
|
// The promise instance `traceRejected()` is called on.
|
||
|
|
||
|
var args = lang._toArray(arguments);
|
||
|
this.otherwise(function(error){
|
||
|
emitAsync(["rejected", error].concat(args));
|
||
|
});
|
||
|
return this;
|
||
|
};
|
||
|
|
||
|
return evented;
|
||
|
});
|
||
|
|
||
|
},
|
||
|
'dojo/Evented':function(){
|
||
|
define(["./aspect", "./on"], function(aspect, on){
|
||
|
// module:
|
||
|
// dojo/Evented
|
||
|
|
||
|
"use strict";
|
||
|
var after = aspect.after;
|
||
|
function Evented(){
|
||
|
// summary:
|
||
|
// A class that can be used as a mixin or base class,
|
||
|
// to add on() and emit() methods to a class
|
||
|
// for listening for events and emitting events:
|
||
|
// example:
|
||
|
// | define(["dojo/Evented", "dojo/_base/declare", "dojo/Stateful"
|
||
|
// | ], function(Evented, declare, Stateful){
|
||
|
// | var EventedStateful = declare([Evented, Stateful], {...});
|
||
|
// | var instance = new EventedStateful();
|
||
|
// | instance.on("open", function(event){
|
||
|
// | ... do something with event
|
||
|
// | });
|
||
|
// |
|
||
|
// | instance.emit("open", {name:"some event", ...});
|
||
|
}
|
||
|
Evented.prototype = {
|
||
|
on: function(type, listener){
|
||
|
return on.parse(this, type, listener, function(target, type){
|
||
|
return after(target, 'on' + type, listener, true);
|
||
|
});
|
||
|
},
|
||
|
emit: function(type, event){
|
||
|
var args = [this];
|
||
|
args.push.apply(args, arguments);
|
||
|
return on.emit.apply(on, args);
|
||
|
}
|
||
|
};
|
||
|
return Evented;
|
||
|
});
|
||
|
|
||
|
},
|
||
|
'dojo/aspect':function(){
|
||
|
define([], function(){
|
||
|
|
||
|
// module:
|
||
|
// dojo/aspect
|
||
|
|
||
|
"use strict";
|
||
|
var undefined;
|
||
|
function advise(dispatcher, type, advice, receiveArguments){
|
||
|
var previous = dispatcher[type];
|
||
|
var around = type == "around";
|
||
|
var signal;
|
||
|
if(around){
|
||
|
var advised = advice(function(){
|
||
|
return previous.advice(this, arguments);
|
||
|
});
|
||
|
signal = {
|
||
|
remove: function(){
|
||
|
if(advised){
|
||
|
advised = dispatcher = advice = null;
|
||
|
}
|
||
|
},
|
||
|
advice: function(target, args){
|
||
|
return advised ?
|
||
|
advised.apply(target, args) : // called the advised function
|
||
|
previous.advice(target, args); // cancelled, skip to next one
|
||
|
}
|
||
|
};
|
||
|
}else{
|
||
|
// create the remove handler
|
||
|
signal = {
|
||
|
remove: function(){
|
||
|
if(signal.advice){
|
||
|
var previous = signal.previous;
|
||
|
var next = signal.next;
|
||
|
if(!next && !previous){
|
||
|
delete dispatcher[type];
|
||
|
}else{
|
||
|
if(previous){
|
||
|
previous.next = next;
|
||
|
}else{
|
||
|
dispatcher[type] = next;
|
||
|
}
|
||
|
if(next){
|
||
|
next.previous = previous;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
// remove the advice to signal that this signal has been removed
|
||
|
dispatcher = advice = signal.advice = null;
|
||
|
}
|
||
|
},
|
||
|
id: dispatcher.nextId++,
|
||
|
advice: advice,
|
||
|
receiveArguments: receiveArguments
|
||
|
};
|
||
|
}
|
||
|
if(previous && !around){
|
||
|
if(type == "after"){
|
||
|
// add the listener to the end of the list
|
||
|
// note that we had to change this loop a little bit to workaround a bizarre IE10 JIT bug
|
||
|
while(previous.next && (previous = previous.next)){}
|
||
|
previous.next = signal;
|
||
|
signal.previous = previous;
|
||
|
}else if(type == "before"){
|
||
|
// add to beginning
|
||
|
dispatcher[type] = signal;
|
||
|
signal.next = previous;
|
||
|
previous.previous = signal;
|
||
|
}
|
||
|
}else{
|
||
|
// around or first one just replaces
|
||
|
dispatcher[type] = signal;
|
||
|
}
|
||
|
return signal;
|
||
|
}
|
||
|
function aspect(type){
|
||
|
return function(target, methodName, advice, receiveArguments){
|
||
|
var existing = target[methodName], dispatcher;
|
||
|
if(!existing || existing.target != target){
|
||
|
// no dispatcher in place
|
||
|
target[methodName] = dispatcher = function(){
|
||
|
var executionId = dispatcher.nextId;
|
||
|
// before advice
|
||
|
var args = arguments;
|
||
|
var before = dispatcher.before;
|
||
|
while(before){
|
||
|
if(before.advice){
|
||
|
args = before.advice.apply(this, args) || args;
|
||
|
}
|
||
|
before = before.next;
|
||
|
}
|
||
|
// around advice
|
||
|
if(dispatcher.around){
|
||
|
var results = dispatcher.around.advice(this, args);
|
||
|
}
|
||
|
// after advice
|
||
|
var after = dispatcher.after;
|
||
|
while(after && after.id < executionId){
|
||
|
if(after.advice){
|
||
|
if(after.receiveArguments){
|
||
|
var newResults = after.advice.apply(this, args);
|
||
|
// change the return value only if a new value was returned
|
||
|
results = newResults === undefined ? results : newResults;
|
||
|
}else{
|
||
|
results = after.advice.call(this, results, args);
|
||
|
}
|
||
|
}
|
||
|
after = after.next;
|
||
|
}
|
||
|
return results;
|
||
|
};
|
||
|
if(existing){
|
||
|
dispatcher.around = {advice: function(target, args){
|
||
|
return existing.apply(target, args);
|
||
|
}};
|
||
|
}
|
||
|
dispatcher.target = target;
|
||
|
dispatcher.nextId = dispatcher.nextId || 0;
|
||
|
}
|
||
|
var results = advise((dispatcher || existing), type, advice, receiveArguments);
|
||
|
advice = null;
|
||
|
return results;
|
||
|
};
|
||
|
}
|
||
|
|
||
|
// TODOC: after/before/around return object
|
||
|
|
||
|
var after = aspect("after");
|
||
|
/*=====
|
||
|
after = function(target, methodName, advice, receiveArguments){
|
||
|
// summary:
|
||
|
// The "after" export of the aspect module is a function that can be used to attach
|
||
|
// "after" advice to a method. This function will be executed after the original method
|
||
|
// is executed. By default the function will be called with a single argument, the return
|
||
|
// value of the original method, or the the return value of the last executed advice (if a previous one exists).
|
||
|
// The fourth (optional) argument can be set to true to so the function receives the original
|
||
|
// arguments (from when the original method was called) rather than the return value.
|
||
|
// If there are multiple "after" advisors, they are executed in the order they were registered.
|
||
|
// target: Object
|
||
|
// This is the target object
|
||
|
// methodName: String
|
||
|
// This is the name of the method to attach to.
|
||
|
// advice: Function
|
||
|
// This is function to be called after the original method
|
||
|
// receiveArguments: Boolean?
|
||
|
// If this is set to true, the advice function receives the original arguments (from when the original mehtod
|
||
|
// was called) rather than the return value of the original/previous method.
|
||
|
// returns:
|
||
|
// A signal object that can be used to cancel the advice. If remove() is called on this signal object, it will
|
||
|
// stop the advice function from being executed.
|
||
|
};
|
||
|
=====*/
|
||
|
|
||
|
var before = aspect("before");
|
||
|
/*=====
|
||
|
before = function(target, methodName, advice){
|
||
|
// summary:
|
||
|
// The "before" export of the aspect module is a function that can be used to attach
|
||
|
// "before" advice to a method. This function will be executed before the original method
|
||
|
// is executed. This function will be called with the arguments used to call the method.
|
||
|
// This function may optionally return an array as the new arguments to use to call
|
||
|
// the original method (or the previous, next-to-execute before advice, if one exists).
|
||
|
// If the before method doesn't return anything (returns undefined) the original arguments
|
||
|
// will be preserved.
|
||
|
// If there are multiple "before" advisors, they are executed in the reverse order they were registered.
|
||
|
// target: Object
|
||
|
// This is the target object
|
||
|
// methodName: String
|
||
|
// This is the name of the method to attach to.
|
||
|
// advice: Function
|
||
|
// This is function to be called before the original method
|
||
|
};
|
||
|
=====*/
|
||
|
|
||
|
var around = aspect("around");
|
||
|
/*=====
|
||
|
around = function(target, methodName, advice){
|
||
|
// summary:
|
||
|
// The "around" export of the aspect module is a function that can be used to attach
|
||
|
// "around" advice to a method. The advisor function is immediately executed when
|
||
|
// the around() is called, is passed a single argument that is a function that can be
|
||
|
// called to continue execution of the original method (or the next around advisor).
|
||
|
// The advisor function should return a function, and this function will be called whenever
|
||
|
// the method is called. It will be called with the arguments used to call the method.
|
||
|
// Whatever this function returns will be returned as the result of the method call (unless after advise changes it).
|
||
|
// example:
|
||
|
// If there are multiple "around" advisors, the most recent one is executed first,
|
||
|
// which can then delegate to the next one and so on. For example:
|
||
|
// | around(obj, "foo", function(originalFoo){
|
||
|
// | return function(){
|
||
|
// | var start = new Date().getTime();
|
||
|
// | var results = originalFoo.apply(this, arguments); // call the original
|
||
|
// | var end = new Date().getTime();
|
||
|
// | console.log("foo execution took " + (end - start) + " ms");
|
||
|
// | return results;
|
||
|
// | };
|
||
|
// | });
|
||
|
// target: Object
|
||
|
// This is the target object
|
||
|
// methodName: String
|
||
|
// This is the name of the method to attach to.
|
||
|
// advice: Function
|
||
|
// This is function to be called around the original method
|
||
|
};
|
||
|
=====*/
|
||
|
|
||
|
return {
|
||
|
// summary:
|
||
|
// provides aspect oriented programming functionality, allowing for
|
||
|
// one to add before, around, or after advice on existing methods.
|
||
|
// example:
|
||
|
// | define(["dojo/aspect"], function(aspect){
|
||
|
// | var signal = aspect.after(targetObject, "methodName", function(someArgument){
|
||
|
// | this will be called when targetObject.methodName() is called, after the original function is called
|
||
|
// | });
|
||
|
//
|
||
|
// example:
|
||
|
// The returned signal object can be used to cancel the advice.
|
||
|
// | signal.remove(); // this will stop the advice from being executed anymore
|
||
|
// | aspect.before(targetObject, "methodName", function(someArgument){
|
||
|
// | // this will be called when targetObject.methodName() is called, before the original function is called
|
||
|
// | });
|
||
|
|
||
|
before: before,
|
||
|
around: around,
|
||
|
after: after
|
||
|
};
|
||
|
});
|
||
|
|
||
|
},
|
||
|
'dojo/on':function(){
|
||
|
define(["./has!dom-addeventlistener?:./aspect", "./_base/kernel", "./sniff"], function(aspect, dojo, has){
|
||
|
|
||
|
"use strict";
|
||
|
if( 1 ){ // check to make sure we are in a browser, this module should work anywhere
|
||
|
var major = window.ScriptEngineMajorVersion;
|
||
|
has.add("jscript", major && (major() + ScriptEngineMinorVersion() / 10));
|
||
|
has.add("event-orientationchange", has("touch") && !has("android")); // TODO: how do we detect this?
|
||
|
has.add("event-stopimmediatepropagation", window.Event && !!window.Event.prototype && !!window.Event.prototype.stopImmediatePropagation);
|
||
|
has.add("event-focusin", function(global, doc, element){
|
||
|
return 'onfocusin' in element;
|
||
|
});
|
||
|
|
||
|
if(has("touch")){
|
||
|
has.add("touch-can-modify-event-delegate", function(){
|
||
|
// This feature test checks whether deleting a property of an event delegate works
|
||
|
// for a touch-enabled device. If it works, event delegation can be used as fallback
|
||
|
// for browsers such as Safari in older iOS where deleting properties of the original
|
||
|
// event does not work.
|
||
|
var EventDelegate = function(){};
|
||
|
EventDelegate.prototype =
|
||
|
document.createEvent("MouseEvents"); // original event
|
||
|
// Attempt to modify a property of an event delegate and check if
|
||
|
// it succeeds. Depending on browsers and on whether dojo/on's
|
||
|
// strict mode is stripped in a Dojo build, there are 3 known behaviors:
|
||
|
// it may either succeed, or raise an error, or fail to set the property
|
||
|
// without raising an error.
|
||
|
try{
|
||
|
var eventDelegate = new EventDelegate;
|
||
|
eventDelegate.target = null;
|
||
|
return eventDelegate.target === null;
|
||
|
}catch(e){
|
||
|
return false; // cannot use event delegation
|
||
|
}
|
||
|
});
|
||
|
}
|
||
|
}
|
||
|
var on = function(target, type, listener, dontFix){
|
||
|
// summary:
|
||
|
// A function that provides core event listening functionality. With this function
|
||
|
// you can provide a target, event type, and listener to be notified of
|
||
|
// future matching events that are fired.
|
||
|
// target: Element|Object
|
||
|
// This is the target object or DOM element that to receive events from
|
||
|
// type: String|Function
|
||
|
// This is the name of the event to listen for or an extension event type.
|
||
|
// listener: Function
|
||
|
// This is the function that should be called when the event fires.
|
||
|
// returns: Object
|
||
|
// An object with a remove() method that can be used to stop listening for this
|
||
|
// event.
|
||
|
// description:
|
||
|
// To listen for "click" events on a button node, we can do:
|
||
|
// | define(["dojo/on"], function(on){
|
||
|
// | on(button, "click", clickHandler);
|
||
|
// | ...
|
||
|
// Evented JavaScript objects can also have their own events.
|
||
|
// | var obj = new Evented;
|
||
|
// | on(obj, "foo", fooHandler);
|
||
|
// And then we could publish a "foo" event:
|
||
|
// | on.emit(obj, "foo", {key: "value"});
|
||
|
// We can use extension events as well. For example, you could listen for a tap gesture:
|
||
|
// | define(["dojo/on", "dojo/gesture/tap", function(on, tap){
|
||
|
// | on(button, tap, tapHandler);
|
||
|
// | ...
|
||
|
// which would trigger fooHandler. Note that for a simple object this is equivalent to calling:
|
||
|
// | obj.onfoo({key:"value"});
|
||
|
// If you use on.emit on a DOM node, it will use native event dispatching when possible.
|
||
|
|
||
|
if(typeof target.on == "function" && typeof type != "function" && !target.nodeType){
|
||
|
// delegate to the target's on() method, so it can handle it's own listening if it wants (unless it
|
||
|
// is DOM node and we may be dealing with jQuery or Prototype's incompatible addition to the
|
||
|
// Element prototype
|
||
|
return target.on(type, listener);
|
||
|
}
|
||
|
// delegate to main listener code
|
||
|
return on.parse(target, type, listener, addListener, dontFix, this);
|
||
|
};
|
||
|
on.pausable = function(target, type, listener, dontFix){
|
||
|
// summary:
|
||
|
// This function acts the same as on(), but with pausable functionality. The
|
||
|
// returned signal object has pause() and resume() functions. Calling the
|
||
|
// pause() method will cause the listener to not be called for future events. Calling the
|
||
|
// resume() method will cause the listener to again be called for future events.
|
||
|
var paused;
|
||
|
var signal = on(target, type, function(){
|
||
|
if(!paused){
|
||
|
return listener.apply(this, arguments);
|
||
|
}
|
||
|
}, dontFix);
|
||
|
signal.pause = function(){
|
||
|
paused = true;
|
||
|
};
|
||
|
signal.resume = function(){
|
||
|
paused = false;
|
||
|
};
|
||
|
return signal;
|
||
|
};
|
||
|
on.once = function(target, type, listener, dontFix){
|
||
|
// summary:
|
||
|
// This function acts the same as on(), but will only call the listener once. The
|
||
|
// listener will be called for the first
|
||
|
// event that takes place and then listener will automatically be removed.
|
||
|
var signal = on(target, type, function(){
|
||
|
// remove this listener
|
||
|
signal.remove();
|
||
|
// proceed to call the listener
|
||
|
return listener.apply(this, arguments);
|
||
|
});
|
||
|
return signal;
|
||
|
};
|
||
|
on.parse = function(target, type, listener, addListener, dontFix, matchesTarget){
|
||
|
var events;
|
||
|
if(type.call){
|
||
|
// event handler function
|
||
|
// on(node, touch.press, touchListener);
|
||
|
return type.call(matchesTarget, target, listener);
|
||
|
}
|
||
|
|
||
|
if(type instanceof Array){
|
||
|
// allow an array of event names (or event handler functions)
|
||
|
events = type;
|
||
|
}else if(type.indexOf(",") > -1){
|
||
|
// we allow comma delimited event names, so you can register for multiple events at once
|
||
|
events = type.split(/\s*,\s*/);
|
||
|
}
|
||
|
if(events){
|
||
|
var handles = [];
|
||
|
var i = 0;
|
||
|
var eventName;
|
||
|
while(eventName = events[i++]){ // intentional assignment
|
||
|
handles.push(on.parse(target, eventName, listener, addListener, dontFix, matchesTarget));
|
||
|
}
|
||
|
handles.remove = function(){
|
||
|
for(var i = 0; i < handles.length; i++){
|
||
|
handles[i].remove();
|
||
|
}
|
||
|
};
|
||
|
return handles;
|
||
|
}
|
||
|
return addListener(target, type, listener, dontFix, matchesTarget);
|
||
|
};
|
||
|
var touchEvents = /^touch/;
|
||
|
function addListener(target, type, listener, dontFix, matchesTarget){
|
||
|
// event delegation:
|
||
|
var selector = type.match(/(.*):(.*)/);
|
||
|
// if we have a selector:event, the last one is interpreted as an event, and we use event delegation
|
||
|
if(selector){
|
||
|
type = selector[2];
|
||
|
selector = selector[1];
|
||
|
// create the extension event for selectors and directly call it
|
||
|
return on.selector(selector, type).call(matchesTarget, target, listener);
|
||
|
}
|
||
|
// test to see if it a touch event right now, so we don't have to do it every time it fires
|
||
|
if(has("touch")){
|
||
|
if(touchEvents.test(type)){
|
||
|
// touch event, fix it
|
||
|
listener = fixTouchListener(listener);
|
||
|
}
|
||
|
if(!has("event-orientationchange") && (type == "orientationchange")){
|
||
|
//"orientationchange" not supported <= Android 2.1,
|
||
|
//but works through "resize" on window
|
||
|
type = "resize";
|
||
|
target = window;
|
||
|
listener = fixTouchListener(listener);
|
||
|
}
|
||
|
}
|
||
|
if(addStopImmediate){
|
||
|
// add stopImmediatePropagation if it doesn't exist
|
||
|
listener = addStopImmediate(listener);
|
||
|
}
|
||
|
// normal path, the target is |this|
|
||
|
if(target.addEventListener){
|
||
|
// the target has addEventListener, which should be used if available (might or might not be a node, non-nodes can implement this method as well)
|
||
|
// check for capture conversions
|
||
|
var capture = type in captures,
|
||
|
adjustedType = capture ? captures[type] : type;
|
||
|
target.addEventListener(adjustedType, listener, capture);
|
||
|
// create and return the signal
|
||
|
return {
|
||
|
remove: function(){
|
||
|
target.removeEventListener(adjustedType, listener, capture);
|
||
|
}
|
||
|
};
|
||
|
}
|
||
|
type = "on" + type;
|
||
|
if(fixAttach && target.attachEvent){
|
||
|
return fixAttach(target, type, listener);
|
||
|
}
|
||
|
throw new Error("Target must be an event emitter");
|
||
|
}
|
||
|
on.matches = function(node, selector, context, children, matchesTarget) {
|
||
|
// summary:
|
||
|
// Check if a node match the current selector within the constraint of a context
|
||
|
// node: DOMNode
|
||
|
// The node that originate the event
|
||
|
// selector: String
|
||
|
// The selector to check against
|
||
|
// context: DOMNode
|
||
|
// The context to search in.
|
||
|
// children: Boolean
|
||
|
// Indicates if children elements of the selector should be allowed. This defaults to
|
||
|
// true
|
||
|
// matchesTarget: Object|dojo/query?
|
||
|
// An object with a property "matches" as a function. Default is dojo/query.
|
||
|
// Matching DOMNodes will be done against this function
|
||
|
// The function must return a Boolean.
|
||
|
// It will have 3 arguments: "node", "selector" and "context"
|
||
|
// True is expected if "node" is matching the current "selector" in the passed "context"
|
||
|
// returns: DOMNode?
|
||
|
// The matching node, if any. Else you get false
|
||
|
|
||
|
// see if we have a valid matchesTarget or default to dojo/query
|
||
|
matchesTarget = matchesTarget && (typeof matchesTarget.matches == "function") ? matchesTarget : dojo.query;
|
||
|
children = children !== false;
|
||
|
// there is a selector, so make sure it matches
|
||
|
if(node.nodeType != 1){
|
||
|
// text node will fail in native match selector
|
||
|
node = node.parentNode;
|
||
|
}
|
||
|
while(!matchesTarget.matches(node, selector, context)){
|
||
|
if(node == context || children === false || !(node = node.parentNode) || node.nodeType != 1){ // intentional assignment
|
||
|
return false;
|
||
|
}
|
||
|
}
|
||
|
return node;
|
||
|
};
|
||
|
on.selector = function(selector, eventType, children){
|
||
|
// summary:
|
||
|
// Creates a new extension event with event delegation. This is based on
|
||
|
// the provided event type (can be extension event) that
|
||
|
// only calls the listener when the CSS selector matches the target of the event.
|
||
|
//
|
||
|
// The application must require() an appropriate level of dojo/query to handle the selector.
|
||
|
// selector:
|
||
|
// The CSS selector to use for filter events and determine the |this| of the event listener.
|
||
|
// eventType:
|
||
|
// The event to listen for
|
||
|
// children:
|
||
|
// Indicates if children elements of the selector should be allowed. This defaults to
|
||
|
// true
|
||
|
// example:
|
||
|
// | require(["dojo/on", "dojo/mouse", "dojo/query!css2"], function(on, mouse){
|
||
|
// | on(node, on.selector(".my-class", mouse.enter), handlerForMyHover);
|
||
|
return function(target, listener){
|
||
|
// if the selector is function, use it to select the node, otherwise use the matches method
|
||
|
var matchesTarget = typeof selector == "function" ? {matches: selector} : this,
|
||
|
bubble = eventType.bubble;
|
||
|
function select(eventTarget){
|
||
|
return on.matches(eventTarget, selector, target, children, matchesTarget);
|
||
|
}
|
||
|
if(bubble){
|
||
|
// the event type doesn't naturally bubble, but has a bubbling form, use that, and give it the selector so it can perform the select itself
|
||
|
return on(target, bubble(select), listener);
|
||
|
}
|
||
|
// standard event delegation
|
||
|
return on(target, eventType, function(event){
|
||
|
// call select to see if we match
|
||
|
var eventTarget = select(event.target);
|
||
|
// if it matches we call the listener
|
||
|
if (eventTarget) {
|
||
|
// We save the matching target into the event, so it can be accessed even when hitching (see #18355)
|
||
|
event.selectorTarget = eventTarget;
|
||
|
return listener.call(eventTarget, event);
|
||
|
}
|
||
|
});
|
||
|
};
|
||
|
};
|
||
|
|
||
|
function syntheticPreventDefault(){
|
||
|
this.cancelable = false;
|
||
|
this.defaultPrevented = true;
|
||
|
}
|
||
|
function syntheticStopPropagation(){
|
||
|
this.bubbles = false;
|
||
|
}
|
||
|
var slice = [].slice,
|
||
|
syntheticDispatch = on.emit = function(target, type, event){
|
||
|
// summary:
|
||
|
// Fires an event on the target object.
|
||
|
// target:
|
||
|
// The target object to fire the event on. This can be a DOM element or a plain
|
||
|
// JS object. If the target is a DOM element, native event emitting mechanisms
|
||
|
// are used when possible.
|
||
|
// type:
|
||
|
// The event type name. You can emulate standard native events like "click" and
|
||
|
// "mouseover" or create custom events like "open" or "finish".
|
||
|
// event:
|
||
|
// An object that provides the properties for the event. See https://developer.mozilla.org/en/DOM/event.initEvent
|
||
|
// for some of the properties. These properties are copied to the event object.
|
||
|
// Of particular importance are the cancelable and bubbles properties. The
|
||
|
// cancelable property indicates whether or not the event has a default action
|
||
|
// that can be cancelled. The event is cancelled by calling preventDefault() on
|
||
|
// the event object. The bubbles property indicates whether or not the
|
||
|
// event will bubble up the DOM tree. If bubbles is true, the event will be called
|
||
|
// on the target and then each parent successively until the top of the tree
|
||
|
// is reached or stopPropagation() is called. Both bubbles and cancelable
|
||
|
// default to false.
|
||
|
// returns:
|
||
|
// If the event is cancelable and the event is not cancelled,
|
||
|
// emit will return true. If the event is cancelable and the event is cancelled,
|
||
|
// emit will return false.
|
||
|
// details:
|
||
|
// Note that this is designed to emit events for listeners registered through
|
||
|
// dojo/on. It should actually work with any event listener except those
|
||
|
// added through IE's attachEvent (IE8 and below's non-W3C event emitting
|
||
|
// doesn't support custom event types). It should work with all events registered
|
||
|
// through dojo/on. Also note that the emit method does do any default
|
||
|
// action, it only returns a value to indicate if the default action should take
|
||
|
// place. For example, emitting a keypress event would not cause a character
|
||
|
// to appear in a textbox.
|
||
|
// example:
|
||
|
// To fire our own click event
|
||
|
// | require(["dojo/on", "dojo/dom"
|
||
|
// | ], function(on, dom){
|
||
|
// | on.emit(dom.byId("button"), "click", {
|
||
|
// | cancelable: true,
|
||
|
// | bubbles: true,
|
||
|
// | screenX: 33,
|
||
|
// | screenY: 44
|
||
|
// | });
|
||
|
// We can also fire our own custom events:
|
||
|
// | on.emit(dom.byId("slider"), "slide", {
|
||
|
// | cancelable: true,
|
||
|
// | bubbles: true,
|
||
|
// | direction: "left-to-right"
|
||
|
// | });
|
||
|
// | });
|
||
|
var args = slice.call(arguments, 2);
|
||
|
var method = "on" + type;
|
||
|
if("parentNode" in target){
|
||
|
// node (or node-like), create event controller methods
|
||
|
var newEvent = args[0] = {};
|
||
|
for(var i in event){
|
||
|
newEvent[i] = event[i];
|
||
|
}
|
||
|
newEvent.preventDefault = syntheticPreventDefault;
|
||
|
newEvent.stopPropagation = syntheticStopPropagation;
|
||
|
newEvent.target = target;
|
||
|
newEvent.type = type;
|
||
|
event = newEvent;
|
||
|
}
|
||
|
do{
|
||
|
// call any node which has a handler (note that ideally we would try/catch to simulate normal event propagation but that causes too much pain for debugging)
|
||
|
target[method] && target[method].apply(target, args);
|
||
|
// and then continue up the parent node chain if it is still bubbling (if started as bubbles and stopPropagation hasn't been called)
|
||
|
}while(event && event.bubbles && (target = target.parentNode));
|
||
|
return event && event.cancelable && event; // if it is still true (was cancelable and was cancelled), return the event to indicate default action should happen
|
||
|
};
|
||
|
var captures = has("event-focusin") ? {} : {focusin: "focus", focusout: "blur"};
|
||
|
if(!has("event-stopimmediatepropagation")){
|
||
|
var stopImmediatePropagation =function(){
|
||
|
this.immediatelyStopped = true;
|
||
|
this.modified = true; // mark it as modified so the event will be cached in IE
|
||
|
};
|
||
|
var addStopImmediate = function(listener){
|
||
|
return function(event){
|
||
|
if(!event.immediatelyStopped){// check to make sure it hasn't been stopped immediately
|
||
|
event.stopImmediatePropagation = stopImmediatePropagation;
|
||
|
return listener.apply(this, arguments);
|
||
|
}
|
||
|
};
|
||
|
};
|
||
|
}
|
||
|
if(has("dom-addeventlistener")){
|
||
|
// emitter that works with native event handling
|
||
|
on.emit = function(target, type, event){
|
||
|
if(target.dispatchEvent && document.createEvent){
|
||
|
// use the native event emitting mechanism if it is available on the target object
|
||
|
// create a generic event
|
||
|
// we could create branch into the different types of event constructors, but
|
||
|
// that would be a lot of extra code, with little benefit that I can see, seems
|
||
|
// best to use the generic constructor and copy properties over, making it
|
||
|
// easy to have events look like the ones created with specific initializers
|
||
|
var ownerDocument = target.ownerDocument || document;
|
||
|
var nativeEvent = ownerDocument.createEvent("HTMLEvents");
|
||
|
nativeEvent.initEvent(type, !!event.bubbles, !!event.cancelable);
|
||
|
// and copy all our properties over
|
||
|
for(var i in event){
|
||
|
if(!(i in nativeEvent)){
|
||
|
nativeEvent[i] = event[i];
|
||
|
}
|
||
|
}
|
||
|
return target.dispatchEvent(nativeEvent) && nativeEvent;
|
||
|
}
|
||
|
return syntheticDispatch.apply(on, arguments); // emit for a non-node
|
||
|
};
|
||
|
}else{
|
||
|
// no addEventListener, basically old IE event normalization
|
||
|
on._fixEvent = function(evt, sender){
|
||
|
// summary:
|
||
|
// normalizes properties on the event object including event
|
||
|
// bubbling methods, keystroke normalization, and x/y positions
|
||
|
// evt:
|
||
|
// native event object
|
||
|
// sender:
|
||
|
// node to treat as "currentTarget"
|
||
|
if(!evt){
|
||
|
var w = sender && (sender.ownerDocument || sender.document || sender).parentWindow || window;
|
||
|
evt = w.event;
|
||
|
}
|
||
|
if(!evt){return evt;}
|
||
|
try{
|
||
|
if(lastEvent && evt.type == lastEvent.type && evt.srcElement == lastEvent.target){
|
||
|
// should be same event, reuse event object (so it can be augmented);
|
||
|
// accessing evt.srcElement rather than evt.target since evt.target not set on IE until fixup below
|
||
|
evt = lastEvent;
|
||
|
}
|
||
|
}catch(e){
|
||
|
// will occur on IE on lastEvent.type reference if lastEvent points to a previous event that already
|
||
|
// finished bubbling, but the setTimeout() to clear lastEvent hasn't fired yet
|
||
|
}
|
||
|
if(!evt.target){ // check to see if it has been fixed yet
|
||
|
evt.target = evt.srcElement;
|
||
|
evt.currentTarget = (sender || evt.srcElement);
|
||
|
if(evt.type == "mouseover"){
|
||
|
evt.relatedTarget = evt.fromElement;
|
||
|
}
|
||
|
if(evt.type == "mouseout"){
|
||
|
evt.relatedTarget = evt.toElement;
|
||
|
}
|
||
|
if(!evt.stopPropagation){
|
||
|
evt.stopPropagation = stopPropagation;
|
||
|
evt.preventDefault = preventDefault;
|
||
|
}
|
||
|
switch(evt.type){
|
||
|
case "keypress":
|
||
|
var c = ("charCode" in evt ? evt.charCode : evt.keyCode);
|
||
|
if (c==10){
|
||
|
// CTRL-ENTER is CTRL-ASCII(10) on IE, but CTRL-ENTER on Mozilla
|
||
|
c=0;
|
||
|
evt.keyCode = 13;
|
||
|
}else if(c==13||c==27){
|
||
|
c=0; // Mozilla considers ENTER and ESC non-printable
|
||
|
}else if(c==3){
|
||
|
c=99; // Mozilla maps CTRL-BREAK to CTRL-c
|
||
|
}
|
||
|
// Mozilla sets keyCode to 0 when there is a charCode
|
||
|
// but that stops the event on IE.
|
||
|
evt.charCode = c;
|
||
|
_setKeyChar(evt);
|
||
|
break;
|
||
|
}
|
||
|
}
|
||
|
return evt;
|
||
|
};
|
||
|
var lastEvent, IESignal = function(handle){
|
||
|
this.handle = handle;
|
||
|
};
|
||
|
IESignal.prototype.remove = function(){
|
||
|
delete _dojoIEListeners_[this.handle];
|
||
|
};
|
||
|
var fixListener = function(listener){
|
||
|
// this is a minimal function for closing on the previous listener with as few as variables as possible
|
||
|
return function(evt){
|
||
|
evt = on._fixEvent(evt, this);
|
||
|
var result = listener.call(this, evt);
|
||
|
if(evt.modified){
|
||
|
// cache the last event and reuse it if we can
|
||
|
if(!lastEvent){
|
||
|
setTimeout(function(){
|
||
|
lastEvent = null;
|
||
|
});
|
||
|
}
|
||
|
lastEvent = evt;
|
||
|
}
|
||
|
return result;
|
||
|
};
|
||
|
};
|
||
|
var fixAttach = function(target, type, listener){
|
||
|
listener = fixListener(listener);
|
||
|
if(((target.ownerDocument ? target.ownerDocument.parentWindow : target.parentWindow || target.window || window) != top ||
|
||
|
has("jscript") < 5.8) &&
|
||
|
!has("config-_allow_leaks")){
|
||
|
// IE will leak memory on certain handlers in frames (IE8 and earlier) and in unattached DOM nodes for JScript 5.7 and below.
|
||
|
// Here we use global redirection to solve the memory leaks
|
||
|
if(typeof _dojoIEListeners_ == "undefined"){
|
||
|
_dojoIEListeners_ = [];
|
||
|
}
|
||
|
var emitter = target[type];
|
||
|
if(!emitter || !emitter.listeners){
|
||
|
var oldListener = emitter;
|
||
|
emitter = Function('event', 'var callee = arguments.callee; for(var i = 0; i<callee.listeners.length; i++){var listener = _dojoIEListeners_[callee.listeners[i]]; if(listener){listener.call(this,event);}}');
|
||
|
emitter.listeners = [];
|
||
|
target[type] = emitter;
|
||
|
emitter.global = this;
|
||
|
if(oldListener){
|
||
|
emitter.listeners.push(_dojoIEListeners_.push(oldListener) - 1);
|
||
|
}
|
||
|
}
|
||
|
var handle;
|
||
|
emitter.listeners.push(handle = (emitter.global._dojoIEListeners_.push(listener) - 1));
|
||
|
return new IESignal(handle);
|
||
|
}
|
||
|
return aspect.after(target, type, listener, true);
|
||
|
};
|
||
|
|
||
|
var _setKeyChar = function(evt){
|
||
|
evt.keyChar = evt.charCode ? String.fromCharCode(evt.charCode) : '';
|
||
|
evt.charOrCode = evt.keyChar || evt.keyCode; // TODO: remove for 2.0
|
||
|
};
|
||
|
// Called in Event scope
|
||
|
var stopPropagation = function(){
|
||
|
this.cancelBubble = true;
|
||
|
};
|
||
|
var preventDefault = on._preventDefault = function(){
|
||
|
// Setting keyCode to 0 is the only way to prevent certain keypresses (namely
|
||
|
// ctrl-combinations that correspond to menu accelerator keys).
|
||
|
// Otoh, it prevents upstream listeners from getting this information
|
||
|
// Try to split the difference here by clobbering keyCode only for ctrl
|
||
|
// combinations. If you still need to access the key upstream, bubbledKeyCode is
|
||
|
// provided as a workaround.
|
||
|
this.bubbledKeyCode = this.keyCode;
|
||
|
if(this.ctrlKey){
|
||
|
try{
|
||
|
// squelch errors when keyCode is read-only
|
||
|
// (e.g. if keyCode is ctrl or shift)
|
||
|
this.keyCode = 0;
|
||
|
}catch(e){
|
||
|
}
|
||
|
}
|
||
|
this.defaultPrevented = true;
|
||
|
this.returnValue = false;
|
||
|
this.modified = true; // mark it as modified (for defaultPrevented flag) so the event will be cached in IE
|
||
|
};
|
||
|
}
|
||
|
if(has("touch")){
|
||
|
var EventDelegate = function(){};
|
||
|
var windowOrientation = window.orientation;
|
||
|
var fixTouchListener = function(listener){
|
||
|
return function(originalEvent){
|
||
|
//Event normalization(for ontouchxxx and resize):
|
||
|
//1.incorrect e.pageX|pageY in iOS
|
||
|
//2.there are no "e.rotation", "e.scale" and "onorientationchange" in Android
|
||
|
//3.More TBD e.g. force | screenX | screenX | clientX | clientY | radiusX | radiusY
|
||
|
|
||
|
// see if it has already been corrected
|
||
|
var event = originalEvent.corrected;
|
||
|
if(!event){
|
||
|
var type = originalEvent.type;
|
||
|
try{
|
||
|
delete originalEvent.type; // on some JS engines (android), deleting properties makes them mutable
|
||
|
}catch(e){}
|
||
|
if(originalEvent.type){
|
||
|
// Deleting the property of the original event did not work (this is the case of
|
||
|
// browsers such as older Safari iOS), hence fallback:
|
||
|
if(has("touch-can-modify-event-delegate")){
|
||
|
// If deleting properties of delegated event works, use event delegation:
|
||
|
EventDelegate.prototype = originalEvent;
|
||
|
event = new EventDelegate;
|
||
|
}else{
|
||
|
// Otherwise last fallback: other browsers, such as mobile Firefox, do not like
|
||
|
// delegated properties, so we have to copy
|
||
|
event = {};
|
||
|
for(var name in originalEvent){
|
||
|
event[name] = originalEvent[name];
|
||
|
}
|
||
|
}
|
||
|
// have to delegate methods to make them work
|
||
|
event.preventDefault = function(){
|
||
|
originalEvent.preventDefault();
|
||
|
};
|
||
|
event.stopPropagation = function(){
|
||
|
originalEvent.stopPropagation();
|
||
|
};
|
||
|
}else{
|
||
|
// deletion worked, use property as is
|
||
|
event = originalEvent;
|
||
|
event.type = type;
|
||
|
}
|
||
|
originalEvent.corrected = event;
|
||
|
if(type == 'resize'){
|
||
|
if(windowOrientation == window.orientation){
|
||
|
return null;//double tap causes an unexpected 'resize' in Android
|
||
|
}
|
||
|
windowOrientation = window.orientation;
|
||
|
event.type = "orientationchange";
|
||
|
return listener.call(this, event);
|
||
|
}
|
||
|
// We use the original event and augment, rather than doing an expensive mixin operation
|
||
|
if(!("rotation" in event)){ // test to see if it has rotation
|
||
|
event.rotation = 0;
|
||
|
event.scale = 1;
|
||
|
}
|
||
|
if (window.TouchEvent && originalEvent instanceof TouchEvent) {
|
||
|
// use event.changedTouches[0].pageX|pageY|screenX|screenY|clientX|clientY|target
|
||
|
var firstChangeTouch = event.changedTouches[0];
|
||
|
for(var i in firstChangeTouch){ // use for-in, we don't need to have dependency on dojo/_base/lang here
|
||
|
delete event[i]; // delete it first to make it mutable
|
||
|
event[i] = firstChangeTouch[i];
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
return listener.call(this, event);
|
||
|
};
|
||
|
};
|
||
|
}
|
||
|
return on;
|
||
|
});
|
||
|
|
||
|
},
|
||
|
'dojo/when':function(){
|
||
|
define([
|
||
|
"./Deferred",
|
||
|
"./promise/Promise"
|
||
|
], function(Deferred, Promise){
|
||
|
"use strict";
|
||
|
|
||
|
// module:
|
||
|
// dojo/when
|
||
|
|
||
|
return function when(valueOrPromise, callback, errback, progback){
|
||
|
// summary:
|
||
|
// Transparently applies callbacks to values and/or promises.
|
||
|
// description:
|
||
|
// Accepts promises but also transparently handles non-promises. If no
|
||
|
// callbacks are provided returns a promise, regardless of the initial
|
||
|
// value. Foreign promises are converted.
|
||
|
//
|
||
|
// If callbacks are provided and the initial value is not a promise,
|
||
|
// the callback is executed immediately with no error handling. Returns
|
||
|
// a promise if the initial value is a promise, or the result of the
|
||
|
// callback otherwise.
|
||
|
// valueOrPromise:
|
||
|
// Either a regular value or an object with a `then()` method that
|
||
|
// follows the Promises/A specification.
|
||
|
// callback: Function?
|
||
|
// Callback to be invoked when the promise is resolved, or a non-promise
|
||
|
// is received.
|
||
|
// errback: Function?
|
||
|
// Callback to be invoked when the promise is rejected.
|
||
|
// progback: Function?
|
||
|
// Callback to be invoked when the promise emits a progress update.
|
||
|
// returns: dojo/promise/Promise
|
||
|
// Promise, or if a callback is provided, the result of the callback.
|
||
|
|
||
|
var receivedPromise = valueOrPromise && typeof valueOrPromise.then === "function";
|
||
|
var nativePromise = receivedPromise && valueOrPromise instanceof Promise;
|
||
|
|
||
|
if(!receivedPromise){
|
||
|
if(arguments.length > 1){
|
||
|
return callback ? callback(valueOrPromise) : valueOrPromise;
|
||
|
}else{
|
||
|
return new Deferred().resolve(valueOrPromise);
|
||
|
}
|
||
|
}else if(!nativePromise){
|
||
|
var deferred = new Deferred(valueOrPromise.cancel);
|
||
|
valueOrPromise.then(deferred.resolve, deferred.reject, deferred.progress);
|
||
|
valueOrPromise = deferred.promise;
|
||
|
}
|
||
|
|
||
|
if(callback || errback || progback){
|
||
|
return valueOrPromise.then(callback, errback, progback);
|
||
|
}
|
||
|
return valueOrPromise;
|
||
|
};
|
||
|
});
|
||
|
|
||
|
},
|
||
|
'dojo/_base/json':function(){
|
||
|
define(["./kernel", "../json"], function(dojo, json){
|
||
|
|
||
|
// module:
|
||
|
// dojo/_base/json
|
||
|
|
||
|
/*=====
|
||
|
return {
|
||
|
// summary:
|
||
|
// This module defines the dojo JSON API.
|
||
|
};
|
||
|
=====*/
|
||
|
|
||
|
dojo.fromJson = function(/*String*/ js){
|
||
|
// summary:
|
||
|
// Parses a JavaScript expression and returns a JavaScript value.
|
||
|
// description:
|
||
|
// Throws for invalid JavaScript expressions. It does not use a strict JSON parser. It
|
||
|
// always delegates to eval(). The content passed to this method must therefore come
|
||
|
// from a trusted source.
|
||
|
// It is recommend that you use dojo/json's parse function for an
|
||
|
// implementation uses the (faster) native JSON parse when available.
|
||
|
// js:
|
||
|
// a string literal of a JavaScript expression, for instance:
|
||
|
// `'{ "foo": [ "bar", 1, { "baz": "thud" } ] }'`
|
||
|
|
||
|
return eval("(" + js + ")"); // Object
|
||
|
};
|
||
|
|
||
|
/*=====
|
||
|
dojo._escapeString = function(){
|
||
|
// summary:
|
||
|
// Adds escape sequences for non-visual characters, double quote and
|
||
|
// backslash and surrounds with double quotes to form a valid string
|
||
|
// literal.
|
||
|
};
|
||
|
=====*/
|
||
|
dojo._escapeString = json.stringify; // just delegate to json.stringify
|
||
|
|
||
|
dojo.toJsonIndentStr = "\t";
|
||
|
dojo.toJson = function(/*Object*/ it, /*Boolean?*/ prettyPrint){
|
||
|
// summary:
|
||
|
// Returns a [JSON](http://json.org) serialization of an object.
|
||
|
// description:
|
||
|
// Returns a [JSON](http://json.org) serialization of an object.
|
||
|
// Note that this doesn't check for infinite recursion, so don't do that!
|
||
|
// It is recommend that you use dojo/json's stringify function for an lighter
|
||
|
// and faster implementation that matches the native JSON API and uses the
|
||
|
// native JSON serializer when available.
|
||
|
// it:
|
||
|
// an object to be serialized. Objects may define their own
|
||
|
// serialization via a special "__json__" or "json" function
|
||
|
// property. If a specialized serializer has been defined, it will
|
||
|
// be used as a fallback.
|
||
|
// Note that in 1.6, toJson would serialize undefined, but this no longer supported
|
||
|
// since it is not supported by native JSON serializer.
|
||
|
// prettyPrint:
|
||
|
// if true, we indent objects and arrays to make the output prettier.
|
||
|
// The variable `dojo.toJsonIndentStr` is used as the indent string --
|
||
|
// to use something other than the default (tab), change that variable
|
||
|
// before calling dojo.toJson().
|
||
|
// Note that if native JSON support is available, it will be used for serialization,
|
||
|
// and native implementations vary on the exact spacing used in pretty printing.
|
||
|
// returns:
|
||
|
// A JSON string serialization of the passed-in object.
|
||
|
// example:
|
||
|
// simple serialization of a trivial object
|
||
|
// | var jsonStr = dojo.toJson({ howdy: "stranger!", isStrange: true });
|
||
|
// | doh.is('{"howdy":"stranger!","isStrange":true}', jsonStr);
|
||
|
// example:
|
||
|
// a custom serializer for an objects of a particular class:
|
||
|
// | dojo.declare("Furby", null, {
|
||
|
// | furbies: "are strange",
|
||
|
// | furbyCount: 10,
|
||
|
// | __json__: function(){
|
||
|
// | },
|
||
|
// | });
|
||
|
|
||
|
// use dojo/json
|
||
|
return json.stringify(it, function(key, value){
|
||
|
if(value){
|
||
|
var tf = value.__json__||value.json;
|
||
|
if(typeof tf == "function"){
|
||
|
return tf.call(value);
|
||
|
}
|
||
|
}
|
||
|
return value;
|
||
|
}, prettyPrint && dojo.toJsonIndentStr); // String
|
||
|
};
|
||
|
|
||
|
return dojo;
|
||
|
});
|
||
|
|
||
|
},
|
||
|
'dojo/request/watch':function(){
|
||
|
define([
|
||
|
'./util',
|
||
|
'../errors/RequestTimeoutError',
|
||
|
'../errors/CancelError',
|
||
|
'../_base/array',
|
||
|
'../_base/window',
|
||
|
'../has!host-browser?dom-addeventlistener?:../on:'
|
||
|
], function(util, RequestTimeoutError, CancelError, array, win, on){
|
||
|
// avoid setting a timer per request. It degrades performance on IE
|
||
|
// something fierece if we don't use unified loops.
|
||
|
var _inFlightIntvl = null,
|
||
|
_inFlight = [];
|
||
|
|
||
|
function watchInFlight(){
|
||
|
// summary:
|
||
|
// internal method that checks each inflight XMLHttpRequest to see
|
||
|
// if it has completed or if the timeout situation applies.
|
||
|
|
||
|
var now = +(new Date);
|
||
|
|
||
|
// we need manual loop because we often modify _inFlight (and therefore 'i') while iterating
|
||
|
for(var i = 0, dfd; i < _inFlight.length && (dfd = _inFlight[i]); i++){
|
||
|
var response = dfd.response,
|
||
|
options = response.options;
|
||
|
if((dfd.isCanceled && dfd.isCanceled()) || (dfd.isValid && !dfd.isValid(response))){
|
||
|
_inFlight.splice(i--, 1);
|
||
|
watch._onAction && watch._onAction();
|
||
|
}else if(dfd.isReady && dfd.isReady(response)){
|
||
|
_inFlight.splice(i--, 1);
|
||
|
dfd.handleResponse(response);
|
||
|
watch._onAction && watch._onAction();
|
||
|
}else if(dfd.startTime){
|
||
|
// did we timeout?
|
||
|
if(dfd.startTime + (options.timeout || 0) < now){
|
||
|
_inFlight.splice(i--, 1);
|
||
|
// Cancel the request so the io module can do appropriate cleanup.
|
||
|
dfd.cancel(new RequestTimeoutError('Timeout exceeded', response));
|
||
|
watch._onAction && watch._onAction();
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
|
||
|
watch._onInFlight && watch._onInFlight(dfd);
|
||
|
|
||
|
if(!_inFlight.length){
|
||
|
clearInterval(_inFlightIntvl);
|
||
|
_inFlightIntvl = null;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
function watch(dfd){
|
||
|
// summary:
|
||
|
// Watches the io request represented by dfd to see if it completes.
|
||
|
// dfd: Deferred
|
||
|
// The Deferred object to watch.
|
||
|
// response: Object
|
||
|
// The object used as the value of the request promise.
|
||
|
// validCheck: Function
|
||
|
// Function used to check if the IO request is still valid. Gets the dfd
|
||
|
// object as its only argument.
|
||
|
// ioCheck: Function
|
||
|
// Function used to check if basic IO call worked. Gets the dfd
|
||
|
// object as its only argument.
|
||
|
// resHandle: Function
|
||
|
// Function used to process response. Gets the dfd
|
||
|
// object as its only argument.
|
||
|
if(dfd.response.options.timeout){
|
||
|
dfd.startTime = +(new Date);
|
||
|
}
|
||
|
|
||
|
if(dfd.isFulfilled()){
|
||
|
// bail out if the deferred is already fulfilled
|
||
|
return;
|
||
|
}
|
||
|
|
||
|
_inFlight.push(dfd);
|
||
|
if(!_inFlightIntvl){
|
||
|
_inFlightIntvl = setInterval(watchInFlight, 50);
|
||
|
}
|
||
|
|
||
|
// handle sync requests separately from async:
|
||
|
// http://bugs.dojotoolkit.org/ticket/8467
|
||
|
if(dfd.response.options.sync){
|
||
|
watchInFlight();
|
||
|
}
|
||
|
}
|
||
|
|
||
|
watch.cancelAll = function cancelAll(){
|
||
|
// summary:
|
||
|
// Cancels all pending IO requests, regardless of IO type
|
||
|
try{
|
||
|
array.forEach(_inFlight, function(dfd){
|
||
|
try{
|
||
|
dfd.cancel(new CancelError('All requests canceled.'));
|
||
|
}catch(e){}
|
||
|
});
|
||
|
}catch(e){}
|
||
|
};
|
||
|
|
||
|
if(win && on && win.doc.attachEvent){
|
||
|
// Automatically call cancel all io calls on unload in IE
|
||
|
// http://bugs.dojotoolkit.org/ticket/2357
|
||
|
on(win.global, 'unload', function(){
|
||
|
watch.cancelAll();
|
||
|
});
|
||
|
}
|
||
|
|
||
|
return watch;
|
||
|
});
|
||
|
|
||
|
},
|
||
|
'dojo/request/util':function(){
|
||
|
define([
|
||
|
'exports',
|
||
|
'../errors/RequestError',
|
||
|
'../errors/CancelError',
|
||
|
'../Deferred',
|
||
|
'../io-query',
|
||
|
'../_base/array',
|
||
|
'../_base/lang',
|
||
|
'../promise/Promise',
|
||
|
'../has'
|
||
|
], function(exports, RequestError, CancelError, Deferred, ioQuery, array, lang, Promise, has){
|
||
|
|
||
|
function isArrayBuffer(value) {
|
||
|
return has('native-arraybuffer') && value instanceof ArrayBuffer
|
||
|
}
|
||
|
|
||
|
function isBlob(value) {
|
||
|
return has('native-blob') && value instanceof Blob
|
||
|
}
|
||
|
|
||
|
function isElement(value) {
|
||
|
if(typeof Element !== 'undefined') { //all other
|
||
|
return value instanceof Element;
|
||
|
}
|
||
|
|
||
|
//IE<=7
|
||
|
return value.nodeType === 1;
|
||
|
}
|
||
|
|
||
|
function isFormData(value) {
|
||
|
return has('native-formdata') && value instanceof FormData;
|
||
|
}
|
||
|
|
||
|
function shouldDeepCopy(value) {
|
||
|
return value &&
|
||
|
typeof value === 'object' &&
|
||
|
!isFormData(value) &&
|
||
|
!isElement(value) &&
|
||
|
!isBlob(value) &&
|
||
|
!isArrayBuffer(value)
|
||
|
}
|
||
|
|
||
|
exports.deepCopy = function(target, source) {
|
||
|
for (var name in source) {
|
||
|
var tval = target[name],
|
||
|
sval = source[name];
|
||
|
if (name !== '__proto__' && tval !== sval) {
|
||
|
if (shouldDeepCopy(sval)) {
|
||
|
if (Object.prototype.toString.call(sval) === '[object Date]') { // use this date test to handle crossing frame boundaries
|
||
|
target[name] = new Date(sval);
|
||
|
} else if (lang.isArray(sval)) {
|
||
|
target[name] = exports.deepCopyArray(sval);
|
||
|
} else {
|
||
|
if (tval && typeof tval === 'object') {
|
||
|
exports.deepCopy(tval, sval);
|
||
|
} else {
|
||
|
target[name] = exports.deepCopy({}, sval);
|
||
|
}
|
||
|
}
|
||
|
} else {
|
||
|
target[name] = sval;
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
return target;
|
||
|
};
|
||
|
|
||
|
exports.deepCopyArray = function(source) {
|
||
|
var clonedArray = [];
|
||
|
for (var i = 0, l = source.length; i < l; i++) {
|
||
|
var svalItem = source[i];
|
||
|
if (typeof svalItem === 'object') {
|
||
|
clonedArray.push(exports.deepCopy({}, svalItem));
|
||
|
} else {
|
||
|
clonedArray.push(svalItem);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
return clonedArray;
|
||
|
};
|
||
|
|
||
|
exports.deepCreate = function deepCreate(source, properties){
|
||
|
properties = properties || {};
|
||
|
var target = lang.delegate(source),
|
||
|
name, value;
|
||
|
|
||
|
for(name in source){
|
||
|
value = source[name];
|
||
|
|
||
|
if(value && typeof value === 'object'){
|
||
|
target[name] = exports.deepCreate(value, properties[name]);
|
||
|
}
|
||
|
}
|
||
|
return exports.deepCopy(target, properties);
|
||
|
};
|
||
|
|
||
|
var freeze = Object.freeze || function(obj){ return obj; };
|
||
|
function okHandler(response){
|
||
|
return freeze(response);
|
||
|
}
|
||
|
function dataHandler (response) {
|
||
|
return response.data !== undefined ? response.data : response.text;
|
||
|
}
|
||
|
|
||
|
exports.deferred = function deferred(response, cancel, isValid, isReady, handleResponse, last){
|
||
|
var def = new Deferred(function(reason){
|
||
|
cancel && cancel(def, response);
|
||
|
|
||
|
if(!reason || !(reason instanceof RequestError) && !(reason instanceof CancelError)){
|
||
|
return new CancelError('Request canceled', response);
|
||
|
}
|
||
|
return reason;
|
||
|
});
|
||
|
|
||
|
def.response = response;
|
||
|
def.isValid = isValid;
|
||
|
def.isReady = isReady;
|
||
|
def.handleResponse = handleResponse;
|
||
|
|
||
|
function errHandler(error){
|
||
|
error.response = response;
|
||
|
throw error;
|
||
|
}
|
||
|
var responsePromise = def.then(okHandler).otherwise(errHandler);
|
||
|
|
||
|
if(exports.notify){
|
||
|
responsePromise.then(
|
||
|
lang.hitch(exports.notify, 'emit', 'load'),
|
||
|
lang.hitch(exports.notify, 'emit', 'error')
|
||
|
);
|
||
|
}
|
||
|
|
||
|
var dataPromise = responsePromise.then(dataHandler);
|
||
|
|
||
|
// http://bugs.dojotoolkit.org/ticket/16794
|
||
|
// The following works around a leak in IE9 through the
|
||
|
// prototype using lang.delegate on dataPromise and
|
||
|
// assigning the result a property with a reference to
|
||
|
// responsePromise.
|
||
|
var promise = new Promise();
|
||
|
for (var prop in dataPromise) {
|
||
|
if (dataPromise.hasOwnProperty(prop)) {
|
||
|
promise[prop] = dataPromise[prop];
|
||
|
}
|
||
|
}
|
||
|
promise.response = responsePromise;
|
||
|
freeze(promise);
|
||
|
// End leak fix
|
||
|
|
||
|
|
||
|
if(last){
|
||
|
def.then(function(response){
|
||
|
last.call(def, response);
|
||
|
}, function(error){
|
||
|
last.call(def, response, error);
|
||
|
});
|
||
|
}
|
||
|
|
||
|
def.promise = promise;
|
||
|
def.then = promise.then;
|
||
|
|
||
|
return def;
|
||
|
};
|
||
|
|
||
|
exports.addCommonMethods = function addCommonMethods(provider, methods){
|
||
|
array.forEach(methods||['GET', 'POST', 'PUT', 'DELETE'], function(method){
|
||
|
provider[(method === 'DELETE' ? 'DEL' : method).toLowerCase()] = function(url, options){
|
||
|
options = lang.delegate(options||{});
|
||
|
options.method = method;
|
||
|
return provider(url, options);
|
||
|
};
|
||
|
});
|
||
|
};
|
||
|
|
||
|
exports.parseArgs = function parseArgs(url, options, skipData){
|
||
|
var data = options.data,
|
||
|
query = options.query;
|
||
|
|
||
|
if(data && !skipData){
|
||
|
if(typeof data === 'object' && (!(has('native-xhr2')) || !(isArrayBuffer(data) || isBlob(data) ))){
|
||
|
options.data = ioQuery.objectToQuery(data);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
if(query){
|
||
|
if(typeof query === 'object'){
|
||
|
query = ioQuery.objectToQuery(query);
|
||
|
}
|
||
|
if(options.preventCache){
|
||
|
query += (query ? '&' : '') + 'request.preventCache=' + (+(new Date));
|
||
|
}
|
||
|
}else if(options.preventCache){
|
||
|
query = 'request.preventCache=' + (+(new Date));
|
||
|
}
|
||
|
|
||
|
if(url && query){
|
||
|
url += (~url.indexOf('?') ? '&' : '?') + query;
|
||
|
}
|
||
|
|
||
|
return {
|
||
|
url: url,
|
||
|
options: options,
|
||
|
getHeader: function(headerName){ return null; }
|
||
|
};
|
||
|
};
|
||
|
|
||
|
exports.checkStatus = function(stat){
|
||
|
stat = stat || 0;
|
||
|
return (stat >= 200 && stat < 300) || // allow any 2XX response code
|
||
|
stat === 304 || // or, get it out of the cache
|
||
|
stat === 1223 || // or, Internet Explorer mangled the status code
|
||
|
!stat; // or, we're Titanium/browser chrome/chrome extension requesting a local file
|
||
|
};
|
||
|
});
|
||
|
|
||
|
},
|
||
|
'dojo/errors/RequestError':function(){
|
||
|
define(['./create'], function(create){
|
||
|
// module:
|
||
|
// dojo/errors/RequestError
|
||
|
|
||
|
/*=====
|
||
|
return function(){
|
||
|
// summary:
|
||
|
// TODOC
|
||
|
};
|
||
|
=====*/
|
||
|
|
||
|
return create("RequestError", function(message, response){
|
||
|
this.response = response;
|
||
|
});
|
||
|
});
|
||
|
|
||
|
},
|
||
|
'dojo/errors/RequestTimeoutError':function(){
|
||
|
define(['./create', './RequestError'], function(create, RequestError){
|
||
|
// module:
|
||
|
// dojo/errors/RequestTimeoutError
|
||
|
|
||
|
/*=====
|
||
|
return function(){
|
||
|
// summary:
|
||
|
// TODOC
|
||
|
};
|
||
|
=====*/
|
||
|
|
||
|
return create("RequestTimeoutError", null, RequestError, {
|
||
|
dojoType: "timeout"
|
||
|
});
|
||
|
});
|
||
|
|
||
|
},
|
||
|
'dojo/request/xhr':function(){
|
||
|
define([
|
||
|
'../errors/RequestError',
|
||
|
'./watch',
|
||
|
'./handlers',
|
||
|
'./util',
|
||
|
'../has'/*=====,
|
||
|
'../request',
|
||
|
'../_base/declare' =====*/
|
||
|
], function(RequestError, watch, handlers, util, has/*=====, request, declare =====*/){
|
||
|
has.add('native-xhr', function(){
|
||
|
// if true, the environment has a native XHR implementation
|
||
|
return typeof XMLHttpRequest !== 'undefined';
|
||
|
});
|
||
|
has.add('dojo-force-activex-xhr', function(){
|
||
|
return has('activex') && window.location.protocol === 'file:';
|
||
|
});
|
||
|
|
||
|
has.add('native-xhr2', function(){
|
||
|
if(!has('native-xhr') || has('dojo-force-activex-xhr')){ return; }
|
||
|
var x = new XMLHttpRequest();
|
||
|
return typeof x['addEventListener'] !== 'undefined' &&
|
||
|
(typeof opera === 'undefined' || typeof x['upload'] !== 'undefined');
|
||
|
});
|
||
|
|
||
|
has.add('native-formdata', function(){
|
||
|
// if true, the environment has a native FormData implementation
|
||
|
return typeof FormData !== 'undefined';
|
||
|
});
|
||
|
|
||
|
has.add('native-blob', function(){
|
||
|
// if true, the environment has a native Blob implementation
|
||
|
return typeof Blob !== 'undefined';
|
||
|
});
|
||
|
|
||
|
has.add('native-arraybuffer', function(){
|
||
|
// if true, the environment has a native ArrayBuffer implementation
|
||
|
return typeof ArrayBuffer !== 'undefined';
|
||
|
});
|
||
|
|
||
|
has.add('native-response-type', function(){
|
||
|
return has('native-xhr') && typeof new XMLHttpRequest().responseType !== 'undefined';
|
||
|
});
|
||
|
|
||
|
has.add('native-xhr2-blob', function(){
|
||
|
if(!has('native-response-type')){ return; }
|
||
|
var x = new XMLHttpRequest();
|
||
|
// The URL used here does not have to be reachable as the XHR's `send` method is never called.
|
||
|
// It does need to be parsable/resolvable in all cases, so it should be an absolute URL.
|
||
|
// XMLHttpRequest within a Worker created from a Blob does not support relative URL paths.
|
||
|
x.open('GET', 'https://dojotoolkit.org/', true);
|
||
|
x.responseType = 'blob';
|
||
|
// will not be set if unsupported
|
||
|
var responseType = x.responseType;
|
||
|
x.abort();
|
||
|
return responseType === 'blob';
|
||
|
});
|
||
|
|
||
|
// Google Chrome doesn't support "json" response type
|
||
|
// up to version 30, so it's intentionally not included here
|
||
|
var nativeResponseTypes = {
|
||
|
'blob': has('native-xhr2-blob') ? 'blob' : 'arraybuffer',
|
||
|
'document': 'document',
|
||
|
'arraybuffer': 'arraybuffer'
|
||
|
};
|
||
|
|
||
|
function handleResponse(response, error){
|
||
|
var _xhr = response.xhr;
|
||
|
response.status = response.xhr.status;
|
||
|
|
||
|
try {
|
||
|
// Firefox throws an error when trying to access
|
||
|
// xhr.responseText if response isn't text
|
||
|
response.text = _xhr.responseText;
|
||
|
} catch (e) {}
|
||
|
|
||
|
if(response.options.handleAs === 'xml'){
|
||
|
response.data = _xhr.responseXML;
|
||
|
}
|
||
|
|
||
|
var handleError;
|
||
|
if(error){
|
||
|
this.reject(error);
|
||
|
}else{
|
||
|
try{
|
||
|
handlers(response);
|
||
|
}catch(e){
|
||
|
handleError = e;
|
||
|
}
|
||
|
if(util.checkStatus(_xhr.status)){
|
||
|
if(!handleError){
|
||
|
this.resolve(response);
|
||
|
}else{
|
||
|
this.reject(handleError);
|
||
|
}
|
||
|
}else{
|
||
|
if(!handleError){
|
||
|
error = new RequestError('Unable to load ' + response.url + ' status: ' + _xhr.status, response);
|
||
|
this.reject(error);
|
||
|
}else{
|
||
|
error = new RequestError('Unable to load ' + response.url + ' status: ' + _xhr.status +
|
||
|
' and an error in handleAs: transformation of response', response);
|
||
|
this.reject(error);
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
|
||
|
var isValid, isReady, addListeners, cancel;
|
||
|
if(has('native-xhr2')){
|
||
|
// Any platform with XHR2 will only use the watch mechanism for timeout.
|
||
|
|
||
|
isValid = function(response){
|
||
|
// summary:
|
||
|
// Check to see if the request should be taken out of the watch queue
|
||
|
return !this.isFulfilled();
|
||
|
};
|
||
|
cancel = function(dfd, response){
|
||
|
// summary:
|
||
|
// Canceler for deferred
|
||
|
response.xhr.abort();
|
||
|
};
|
||
|
addListeners = function(_xhr, dfd, response, uploadProgress){
|
||
|
// summary:
|
||
|
// Adds event listeners to the XMLHttpRequest object
|
||
|
function onLoad(evt){
|
||
|
dfd.handleResponse(response);
|
||
|
}
|
||
|
function onError(evt){
|
||
|
var _xhr = evt.target;
|
||
|
var error = new RequestError('Unable to load ' + response.url + ' status: ' + _xhr.status, response);
|
||
|
dfd.handleResponse(response, error);
|
||
|
}
|
||
|
|
||
|
function onProgress(transferType, evt){
|
||
|
response.transferType = transferType;
|
||
|
if(evt.lengthComputable){
|
||
|
response.loaded = evt.loaded;
|
||
|
response.total = evt.total;
|
||
|
dfd.progress(response);
|
||
|
} else if(response.xhr.readyState === 3){
|
||
|
response.loaded = ('loaded' in evt) ? evt.loaded : evt.position;
|
||
|
dfd.progress(response);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
function onDownloadProgress(evt) {
|
||
|
return onProgress('download', evt);
|
||
|
}
|
||
|
|
||
|
function onUploadProgress(evt) {
|
||
|
return onProgress('upload', evt);
|
||
|
}
|
||
|
|
||
|
_xhr.addEventListener('load', onLoad, false);
|
||
|
_xhr.addEventListener('error', onError, false);
|
||
|
_xhr.addEventListener('progress', onDownloadProgress, false);
|
||
|
|
||
|
if (uploadProgress && _xhr.upload) {
|
||
|
_xhr.upload.addEventListener('progress', onUploadProgress, false);
|
||
|
}
|
||
|
|
||
|
return function(){
|
||
|
_xhr.removeEventListener('load', onLoad, false);
|
||
|
_xhr.removeEventListener('error', onError, false);
|
||
|
_xhr.removeEventListener('progress', onDownloadProgress, false);
|
||
|
_xhr.upload.removeEventListener('progress', onUploadProgress, false);
|
||
|
_xhr = null;
|
||
|
};
|
||
|
};
|
||
|
}else{
|
||
|
isValid = function(response){
|
||
|
return response.xhr.readyState; //boolean
|
||
|
};
|
||
|
isReady = function(response){
|
||
|
return 4 === response.xhr.readyState; //boolean
|
||
|
};
|
||
|
cancel = function(dfd, response){
|
||
|
// summary:
|
||
|
// canceller function for util.deferred call.
|
||
|
var xhr = response.xhr;
|
||
|
var _at = typeof xhr.abort;
|
||
|
if(_at === 'function' || _at === 'object' || _at === 'unknown'){
|
||
|
xhr.abort();
|
||
|
}
|
||
|
};
|
||
|
}
|
||
|
|
||
|
function getHeader(headerName){
|
||
|
return this.xhr.getResponseHeader(headerName);
|
||
|
}
|
||
|
|
||
|
var undefined,
|
||
|
defaultOptions = {
|
||
|
data: null,
|
||
|
query: null,
|
||
|
sync: false,
|
||
|
method: 'GET'
|
||
|
};
|
||
|
function xhr(url, options, returnDeferred){
|
||
|
var isFormData = has('native-formdata') && options && options.data && options.data instanceof FormData;
|
||
|
var response = util.parseArgs(
|
||
|
url,
|
||
|
util.deepCreate(defaultOptions, options),
|
||
|
isFormData
|
||
|
);
|
||
|
url = response.url;
|
||
|
options = response.options;
|
||
|
var hasNoData = !options.data && options.method !== 'POST' && options.method !== 'PUT';
|
||
|
|
||
|
if(has('ie') <= 10){
|
||
|
// older IE breaks point 9 in http://www.w3.org/TR/XMLHttpRequest/#the-open()-method and sends fragment, so strip it
|
||
|
url = url.split('#')[0];
|
||
|
}
|
||
|
|
||
|
var remover,
|
||
|
last = function(){
|
||
|
remover && remover();
|
||
|
};
|
||
|
|
||
|
//Make the Deferred object for this xhr request.
|
||
|
var dfd = util.deferred(
|
||
|
response,
|
||
|
cancel,
|
||
|
isValid,
|
||
|
isReady,
|
||
|
handleResponse,
|
||
|
last
|
||
|
);
|
||
|
var _xhr = response.xhr = xhr._create();
|
||
|
|
||
|
if(!_xhr){
|
||
|
// If XHR factory somehow returns nothings,
|
||
|
// cancel the deferred.
|
||
|
dfd.cancel(new RequestError('XHR was not created'));
|
||
|
return returnDeferred ? dfd : dfd.promise;
|
||
|
}
|
||
|
|
||
|
response.getHeader = getHeader;
|
||
|
|
||
|
if(addListeners){
|
||
|
remover = addListeners(_xhr, dfd, response, options.uploadProgress);
|
||
|
}
|
||
|
|
||
|
// IE11 treats data: undefined different than other browsers
|
||
|
var data = typeof(options.data) === 'undefined' ? null : options.data,
|
||
|
async = !options.sync,
|
||
|
method = options.method;
|
||
|
|
||
|
try{
|
||
|
// IE6 won't let you call apply() on the native function.
|
||
|
_xhr.open(method, url, async, options.user || undefined, options.password || undefined);
|
||
|
|
||
|
if(options.withCredentials){
|
||
|
_xhr.withCredentials = options.withCredentials;
|
||
|
}
|
||
|
|
||
|
if(has('native-response-type') && options.handleAs in nativeResponseTypes) {
|
||
|
_xhr.responseType = nativeResponseTypes[options.handleAs];
|
||
|
}
|
||
|
|
||
|
var headers = options.headers,
|
||
|
contentType = (isFormData || hasNoData) ? false : 'application/x-www-form-urlencoded';
|
||
|
if(headers){
|
||
|
for(var hdr in headers){
|
||
|
if(hdr.toLowerCase() === 'content-type'){
|
||
|
contentType = headers[hdr];
|
||
|
}else if(headers[hdr]){
|
||
|
//Only add header if it has a value. This allows for instance, skipping
|
||
|
//insertion of X-Requested-With by specifying empty value.
|
||
|
_xhr.setRequestHeader(hdr, headers[hdr]);
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
|
||
|
if(contentType && contentType !== false){
|
||
|
_xhr.setRequestHeader('Content-Type', contentType);
|
||
|
}
|
||
|
if(!headers || !('X-Requested-With' in headers)){
|
||
|
_xhr.setRequestHeader('X-Requested-With', 'XMLHttpRequest');
|
||
|
}
|
||
|
|
||
|
if(util.notify){
|
||
|
util.notify.emit('send', response, dfd.promise.cancel);
|
||
|
}
|
||
|
_xhr.send(data);
|
||
|
}catch(e){
|
||
|
dfd.reject(e);
|
||
|
}
|
||
|
|
||
|
watch(dfd);
|
||
|
_xhr = null;
|
||
|
|
||
|
return returnDeferred ? dfd : dfd.promise;
|
||
|
}
|
||
|
|
||
|
/*=====
|
||
|
xhr = function(url, options){
|
||
|
// summary:
|
||
|
// Sends a request using XMLHttpRequest with the given URL and options.
|
||
|
// url: String
|
||
|
// URL to request
|
||
|
// options: dojo/request/xhr.__Options?
|
||
|
// Options for the request.
|
||
|
// returns: dojo/request.__Promise
|
||
|
};
|
||
|
xhr.__BaseOptions = declare(request.__BaseOptions, {
|
||
|
// sync: Boolean?
|
||
|
// Whether to make a synchronous request or not. Default
|
||
|
// is `false` (asynchronous).
|
||
|
// data: String|Object|FormData?
|
||
|
// Data to transfer. This is ignored for GET and DELETE
|
||
|
// requests.
|
||
|
// headers: Object?
|
||
|
// Headers to use for the request.
|
||
|
// user: String?
|
||
|
// Username to use during the request.
|
||
|
// password: String?
|
||
|
// Password to use during the request.
|
||
|
// withCredentials: Boolean?
|
||
|
// For cross-site requests, whether to send credentials
|
||
|
// or not.
|
||
|
// uploadProgress: Boolean?
|
||
|
// Upload progress events cause preflighted requests. This
|
||
|
// option enables upload progress event support but also
|
||
|
// causes all requests to be preflighted.
|
||
|
});
|
||
|
xhr.__MethodOptions = declare(null, {
|
||
|
// method: String?
|
||
|
// The HTTP method to use to make the request. Must be
|
||
|
// uppercase. Default is `"GET"`.
|
||
|
});
|
||
|
xhr.__Options = declare([xhr.__BaseOptions, xhr.__MethodOptions]);
|
||
|
|
||
|
xhr.get = function(url, options){
|
||
|
// summary:
|
||
|
// Send an HTTP GET request using XMLHttpRequest with the given URL and options.
|
||
|
// url: String
|
||
|
// URL to request
|
||
|
// options: dojo/request/xhr.__BaseOptions?
|
||
|
// Options for the request.
|
||
|
// returns: dojo/request.__Promise
|
||
|
};
|
||
|
xhr.post = function(url, options){
|
||
|
// summary:
|
||
|
// Send an HTTP POST request using XMLHttpRequest with the given URL and options.
|
||
|
// url: String
|
||
|
// URL to request
|
||
|
// options: dojo/request/xhr.__BaseOptions?
|
||
|
// Options for the request.
|
||
|
// returns: dojo/request.__Promise
|
||
|
};
|
||
|
xhr.put = function(url, options){
|
||
|
// summary:
|
||
|
// Send an HTTP PUT request using XMLHttpRequest with the given URL and options.
|
||
|
// url: String
|
||
|
// URL to request
|
||
|
// options: dojo/request/xhr.__BaseOptions?
|
||
|
// Options for the request.
|
||
|
// returns: dojo/request.__Promise
|
||
|
};
|
||
|
xhr.del = function(url, options){
|
||
|
// summary:
|
||
|
// Send an HTTP DELETE request using XMLHttpRequest with the given URL and options.
|
||
|
// url: String
|
||
|
// URL to request
|
||
|
// options: dojo/request/xhr.__BaseOptions?
|
||
|
// Options for the request.
|
||
|
// returns: dojo/request.__Promise
|
||
|
};
|
||
|
=====*/
|
||
|
xhr._create = function(){
|
||
|
// summary:
|
||
|
// does the work of portably generating a new XMLHTTPRequest object.
|
||
|
throw new Error('XMLHTTP not available');
|
||
|
};
|
||
|
if(has('native-xhr') && !has('dojo-force-activex-xhr')){
|
||
|
xhr._create = function(){
|
||
|
return new XMLHttpRequest();
|
||
|
};
|
||
|
}else if(has('activex')){
|
||
|
try{
|
||
|
new ActiveXObject('Msxml2.XMLHTTP');
|
||
|
xhr._create = function(){
|
||
|
return new ActiveXObject('Msxml2.XMLHTTP');
|
||
|
};
|
||
|
}catch(e){
|
||
|
try{
|
||
|
new ActiveXObject('Microsoft.XMLHTTP');
|
||
|
xhr._create = function(){
|
||
|
return new ActiveXObject('Microsoft.XMLHTTP');
|
||
|
};
|
||
|
}catch(e){}
|
||
|
}
|
||
|
}
|
||
|
|
||
|
util.addCommonMethods(xhr);
|
||
|
|
||
|
return xhr;
|
||
|
});
|
||
|
|
||
|
},
|
||
|
'dojo/request/handlers':function(){
|
||
|
define([
|
||
|
'../json',
|
||
|
'../_base/kernel',
|
||
|
'../_base/array',
|
||
|
'../has',
|
||
|
'../selector/_loader' // only included for has() qsa tests
|
||
|
], function(JSON, kernel, array, has){
|
||
|
has.add('activex', typeof ActiveXObject !== 'undefined');
|
||
|
has.add('dom-parser', function(global){
|
||
|
return 'DOMParser' in global;
|
||
|
});
|
||
|
|
||
|
var handleXML;
|
||
|
if(has('activex')){
|
||
|
// GUIDs obtained from http://msdn.microsoft.com/en-us/library/ms757837(VS.85).aspx
|
||
|
var dp = [
|
||
|
'Msxml2.DOMDocument.6.0',
|
||
|
'Msxml2.DOMDocument.4.0',
|
||
|
'MSXML2.DOMDocument.3.0',
|
||
|
'MSXML.DOMDocument' // 2.0
|
||
|
];
|
||
|
var lastParser;
|
||
|
|
||
|
handleXML = function(response){
|
||
|
var result = response.data;
|
||
|
var text = response.text;
|
||
|
|
||
|
if(result && has('dom-qsa2.1') && !result.querySelectorAll && has('dom-parser')){
|
||
|
// http://bugs.dojotoolkit.org/ticket/15631
|
||
|
// IE9 supports a CSS3 querySelectorAll implementation, but the DOM implementation
|
||
|
// returned by IE9 xhr.responseXML does not. Manually create the XML DOM to gain
|
||
|
// the fuller-featured implementation and avoid bugs caused by the inconsistency
|
||
|
result = new DOMParser().parseFromString(text, 'application/xml');
|
||
|
}
|
||
|
|
||
|
function createDocument(p) {
|
||
|
try{
|
||
|
var dom = new ActiveXObject(p);
|
||
|
dom.async = false;
|
||
|
dom.loadXML(text);
|
||
|
result = dom;
|
||
|
lastParser = p;
|
||
|
}catch(e){ return false; }
|
||
|
return true;
|
||
|
}
|
||
|
|
||
|
if(!result || !result.documentElement){
|
||
|
// The creation of an ActiveX object is expensive, so we cache the
|
||
|
// parser type to avoid trying all parser types each time we handle a
|
||
|
// document. There is some concern that some parser types might fail
|
||
|
// depending on the document being parsed. If parsing using the cached
|
||
|
// parser type fails, we do the more expensive operation of finding one
|
||
|
// that works for the given document.
|
||
|
// https://bugs.dojotoolkit.org/ticket/15246
|
||
|
if(!lastParser || !createDocument(lastParser)) {
|
||
|
array.some(dp, createDocument);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
return result;
|
||
|
};
|
||
|
}
|
||
|
|
||
|
var handleNativeResponse = function(response) {
|
||
|
if(!has('native-xhr2-blob') && response.options.handleAs === 'blob' && typeof Blob !== 'undefined'){
|
||
|
return new Blob([ response.xhr.response ], { type: response.xhr.getResponseHeader('Content-Type') });
|
||
|
}
|
||
|
|
||
|
return response.xhr.response;
|
||
|
}
|
||
|
|
||
|
var handlers = {
|
||
|
'javascript': function(response){
|
||
|
return kernel.eval(response.text || '');
|
||
|
},
|
||
|
'json': function(response){
|
||
|
return JSON.parse(response.text || null);
|
||
|
},
|
||
|
'xml': handleXML,
|
||
|
'blob': handleNativeResponse,
|
||
|
'arraybuffer': handleNativeResponse,
|
||
|
'document': handleNativeResponse
|
||
|
};
|
||
|
|
||
|
function handle(response){
|
||
|
var handler = handlers[response.options.handleAs];
|
||
|
|
||
|
response.data = handler ? handler(response) : (response.data || response.text);
|
||
|
|
||
|
return response;
|
||
|
}
|
||
|
|
||
|
handle.register = function(name, handler){
|
||
|
handlers[name] = handler;
|
||
|
};
|
||
|
|
||
|
return handle;
|
||
|
});
|
||
|
|
||
|
},
|
||
|
'dojo/selector/_loader':function(){
|
||
|
define(["../has", "require"],
|
||
|
function(has, require){
|
||
|
|
||
|
"use strict";
|
||
|
if (typeof document !== "undefined") {
|
||
|
var testDiv = document.createElement("div");
|
||
|
has.add("dom-qsa2.1", !!testDiv.querySelectorAll);
|
||
|
has.add("dom-qsa3", function(){
|
||
|
// test to see if we have a reasonable native selector engine available
|
||
|
try{
|
||
|
testDiv.innerHTML = "<p class='TEST'></p>"; // test kind of from sizzle
|
||
|
// Safari can't handle uppercase or unicode characters when
|
||
|
// in quirks mode, IE8 can't handle pseudos like :empty
|
||
|
return testDiv.querySelectorAll(".TEST:empty").length == 1;
|
||
|
}catch(e){}
|
||
|
});
|
||
|
}
|
||
|
|
||
|
var fullEngine;
|
||
|
var acme = "./acme", lite = "./lite";
|
||
|
return {
|
||
|
// summary:
|
||
|
// This module handles loading the appropriate selector engine for the given browser
|
||
|
|
||
|
load: function(id, parentRequire, loaded, config){
|
||
|
if (config && config.isBuild) {
|
||
|
//Indicate that the optimizer should not wait
|
||
|
//for this resource any more and complete optimization.
|
||
|
//This resource will be resolved dynamically during
|
||
|
//run time in the web browser.
|
||
|
loaded();
|
||
|
return;
|
||
|
}
|
||
|
|
||
|
var req = require;
|
||
|
// here we implement the default logic for choosing a selector engine
|
||
|
id = id == "default" ? has("config-selectorEngine") || "css3" : id;
|
||
|
id = id == "css2" || id == "lite" ? lite :
|
||
|
id == "css2.1" ? has("dom-qsa2.1") ? lite : acme :
|
||
|
id == "css3" ? has("dom-qsa3") ? lite : acme :
|
||
|
id == "acme" ? acme : (req = parentRequire) && id;
|
||
|
if(id.charAt(id.length-1) == '?'){
|
||
|
id = id.substring(0,id.length - 1);
|
||
|
var optionalLoad = true;
|
||
|
}
|
||
|
// the query engine is optional, only load it if a native one is not available or existing one has not been loaded
|
||
|
if(optionalLoad && (has("dom-compliant-qsa") || fullEngine)){
|
||
|
return loaded(fullEngine);
|
||
|
}
|
||
|
// load the referenced selector engine
|
||
|
req([id], function(engine){
|
||
|
if(id != "./lite"){
|
||
|
fullEngine = engine;
|
||
|
}
|
||
|
loaded(engine);
|
||
|
});
|
||
|
}
|
||
|
};
|
||
|
});
|
||
|
|
||
|
},
|
||
|
'dojo/main':function(){
|
||
|
define([
|
||
|
"./_base/kernel", // kernel.isAsync
|
||
|
"./has",
|
||
|
"require",
|
||
|
"./sniff",
|
||
|
"./_base/lang",
|
||
|
"./_base/array",
|
||
|
"./_base/config",
|
||
|
"./ready",
|
||
|
"./_base/declare",
|
||
|
"./_base/connect",
|
||
|
"./_base/Deferred",
|
||
|
"./_base/json",
|
||
|
"./_base/Color",
|
||
|
"./has!dojo-firebug?./_firebug/firebug",
|
||
|
"./_base/browser",
|
||
|
"./_base/loader"
|
||
|
], function(kernel, has, require, sniff, lang, array, config, ready){
|
||
|
// module:
|
||
|
// dojo/main
|
||
|
// summary:
|
||
|
// This is the package main module for the dojo package; it loads dojo base appropriate for the execution environment.
|
||
|
|
||
|
// Load code to fix IE's console
|
||
|
if(config.isDebug){
|
||
|
require(["./_firebug/firebug"]);
|
||
|
}
|
||
|
|
||
|
// dojoConfig.require is deprecated; use the loader configuration property deps
|
||
|
1 || has.add("dojo-config-require", 1);
|
||
|
if( 1 ){
|
||
|
var deps= config.require;
|
||
|
if(deps){
|
||
|
// config.require may be dot notation
|
||
|
deps= array.map(lang.isArray(deps) ? deps : [deps], function(item){ return item.replace(/\./g, "/"); });
|
||
|
if(kernel.isAsync){
|
||
|
require(deps);
|
||
|
}else{
|
||
|
// this is a bit janky; in 1.6- dojo is defined before these requires are applied; but in 1.7+
|
||
|
// dojo isn't defined until returning from this module; this is only a problem in sync mode
|
||
|
// since we're in sync mode, we know we've got our loader with its priority ready queue
|
||
|
ready(1, function(){require(deps);});
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
|
||
|
return kernel;
|
||
|
});
|
||
|
|
||
|
},
|
||
|
'dojo/ready':function(){
|
||
|
define(["./_base/kernel", "./has", "require", "./domReady", "./_base/lang"], function(dojo, has, require, domReady, lang){
|
||
|
// module:
|
||
|
// dojo/ready
|
||
|
// note:
|
||
|
// This module should be unnecessary in dojo 2.0
|
||
|
|
||
|
var
|
||
|
// truthy if DOMContentLoaded or better (e.g., window.onload fired) has been achieved
|
||
|
isDomReady = 0,
|
||
|
|
||
|
// The queue of functions waiting to execute as soon as dojo.ready conditions satisfied
|
||
|
loadQ = [],
|
||
|
|
||
|
// prevent recursion in onLoad
|
||
|
onLoadRecursiveGuard = 0,
|
||
|
|
||
|
handleDomReady = function(){
|
||
|
isDomReady = 1;
|
||
|
dojo._postLoad = dojo.config.afterOnLoad = true;
|
||
|
onEvent();
|
||
|
},
|
||
|
|
||
|
onEvent = function(){
|
||
|
// Called when some state changes:
|
||
|
// - dom ready
|
||
|
// - dojo/domReady has finished processing everything in its queue
|
||
|
// - task added to loadQ
|
||
|
// - require() has finished loading all currently requested modules
|
||
|
//
|
||
|
// Run the functions queued with dojo.ready if appropriate.
|
||
|
|
||
|
|
||
|
//guard against recursions into this function
|
||
|
if(onLoadRecursiveGuard){
|
||
|
return;
|
||
|
}
|
||
|
onLoadRecursiveGuard = 1;
|
||
|
|
||
|
// Run tasks in queue if require() is finished loading modules, the dom is ready, and there are no
|
||
|
// pending tasks registered via domReady().
|
||
|
// The last step is necessary so that a user defined dojo.ready() callback is delayed until after the
|
||
|
// domReady() calls inside of dojo. Failure can be seen on dijit/tests/robot/Dialog_ally.html on IE8
|
||
|
// because the dijit/focus.js domReady() callback doesn't execute until after the test starts running.
|
||
|
while(isDomReady && (!domReady || domReady._Q.length == 0) && (require.idle ? require.idle() : true) && loadQ.length){
|
||
|
var f = loadQ.shift();
|
||
|
try{
|
||
|
f();
|
||
|
}catch(e){
|
||
|
// force the dojo.js on("error") handler do display the message
|
||
|
e.info = e.message;
|
||
|
if(require.signal){
|
||
|
require.signal("error", e);
|
||
|
}else{
|
||
|
throw e;
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
|
||
|
onLoadRecursiveGuard = 0;
|
||
|
};
|
||
|
|
||
|
// Check if we should run the next queue operation whenever require() finishes loading modules or domReady
|
||
|
// finishes processing it's queue.
|
||
|
require.on && require.on("idle", onEvent);
|
||
|
if(domReady){
|
||
|
domReady._onQEmpty = onEvent;
|
||
|
}
|
||
|
|
||
|
var ready = dojo.ready = dojo.addOnLoad = function(priority, context, callback){
|
||
|
// summary:
|
||
|
// Add a function to execute on DOM content loaded and all requested modules have arrived and been evaluated.
|
||
|
// In most cases, the `domReady` plug-in should suffice and this method should not be needed.
|
||
|
//
|
||
|
// When called in a non-browser environment, just checks that all requested modules have arrived and been
|
||
|
// evaluated.
|
||
|
// priority: Integer?
|
||
|
// The order in which to exec this callback relative to other callbacks, defaults to 1000
|
||
|
// context: Object?|Function
|
||
|
// The context in which to run execute callback, or a callback if not using context
|
||
|
// callback: Function?
|
||
|
// The function to execute.
|
||
|
//
|
||
|
// example:
|
||
|
// Simple DOM and Modules ready syntax
|
||
|
// | require(["dojo/ready"], function(ready){
|
||
|
// | ready(function(){ alert("Dom ready!"); });
|
||
|
// | });
|
||
|
//
|
||
|
// example:
|
||
|
// Using a priority
|
||
|
// | require(["dojo/ready"], function(ready){
|
||
|
// | ready(2, function(){ alert("low priority ready!"); })
|
||
|
// | });
|
||
|
//
|
||
|
// example:
|
||
|
// Using context
|
||
|
// | require(["dojo/ready"], function(ready){
|
||
|
// | ready(foo, function(){
|
||
|
// | // in here, this == foo
|
||
|
// | });
|
||
|
// | });
|
||
|
//
|
||
|
// example:
|
||
|
// Using dojo/hitch style args:
|
||
|
// | require(["dojo/ready"], function(ready){
|
||
|
// | var foo = { dojoReady: function(){ console.warn(this, "dojo dom and modules ready."); } };
|
||
|
// | ready(foo, "dojoReady");
|
||
|
// | });
|
||
|
|
||
|
var hitchArgs = lang._toArray(arguments);
|
||
|
if(typeof priority != "number"){
|
||
|
callback = context;
|
||
|
context = priority;
|
||
|
priority = 1000;
|
||
|
}else{
|
||
|
hitchArgs.shift();
|
||
|
}
|
||
|
callback = callback ?
|
||
|
lang.hitch.apply(dojo, hitchArgs) :
|
||
|
function(){
|
||
|
context();
|
||
|
};
|
||
|
callback.priority = priority;
|
||
|
for(var i = 0; i < loadQ.length && priority >= loadQ[i].priority; i++){}
|
||
|
loadQ.splice(i, 0, callback);
|
||
|
onEvent();
|
||
|
};
|
||
|
|
||
|
1 || has.add("dojo-config-addOnLoad", 1);
|
||
|
if( 1 ){
|
||
|
var dca = dojo.config.addOnLoad;
|
||
|
if(dca){
|
||
|
ready[(lang.isArray(dca) ? "apply" : "call")](dojo, dca);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
if( 1 && dojo.config.parseOnLoad && !dojo.isAsync){
|
||
|
ready(99, function(){
|
||
|
if(!dojo.parser){
|
||
|
dojo.deprecated("Add explicit require(['dojo/parser']);", "", "2.0");
|
||
|
require(["dojo/parser"]);
|
||
|
}
|
||
|
});
|
||
|
}
|
||
|
|
||
|
if(domReady){
|
||
|
domReady(handleDomReady);
|
||
|
}else{
|
||
|
handleDomReady();
|
||
|
}
|
||
|
|
||
|
return ready;
|
||
|
});
|
||
|
|
||
|
},
|
||
|
'dojo/domReady':function(){
|
||
|
define(['./global', './has'], function(global, has){
|
||
|
var doc = document,
|
||
|
readyStates = { 'loaded': 1, 'complete': 1 },
|
||
|
fixReadyState = typeof doc.readyState != "string",
|
||
|
ready = !!readyStates[doc.readyState],
|
||
|
readyQ = [],
|
||
|
recursiveGuard;
|
||
|
|
||
|
function domReady(callback){
|
||
|
// summary:
|
||
|
// Plugin to delay require()/define() callback from firing until the DOM has finished loading.
|
||
|
readyQ.push(callback);
|
||
|
if(ready){ processQ(); }
|
||
|
}
|
||
|
domReady.load = function(id, req, load){
|
||
|
domReady(load);
|
||
|
};
|
||
|
|
||
|
// Export queue so that ready() can check if it's empty or not.
|
||
|
domReady._Q = readyQ;
|
||
|
domReady._onQEmpty = function(){
|
||
|
// summary:
|
||
|
// Private method overridden by dojo/ready, to notify when everything in the
|
||
|
// domReady queue has been processed. Do not use directly.
|
||
|
// Will be removed in 2.0, along with domReady._Q.
|
||
|
};
|
||
|
|
||
|
// For FF <= 3.5
|
||
|
if(fixReadyState){ doc.readyState = "loading"; }
|
||
|
|
||
|
function processQ(){
|
||
|
// Calls all functions in the queue in order, unless processQ() is already running, in which case just return
|
||
|
|
||
|
if(recursiveGuard){ return; }
|
||
|
recursiveGuard = true;
|
||
|
|
||
|
while(readyQ.length){
|
||
|
try{
|
||
|
(readyQ.shift())(doc);
|
||
|
}catch(err){
|
||
|
console.error(err, "in domReady callback", err.stack);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
recursiveGuard = false;
|
||
|
|
||
|
// Notification for dojo/ready. Remove for 2.0.
|
||
|
// Note that this could add more tasks to the ready queue.
|
||
|
domReady._onQEmpty();
|
||
|
}
|
||
|
|
||
|
if(!ready){
|
||
|
var tests = [],
|
||
|
detectReady = function(evt){
|
||
|
evt = evt || global.event;
|
||
|
if(ready || (evt.type == "readystatechange" && !readyStates[doc.readyState])){ return; }
|
||
|
|
||
|
// For FF <= 3.5
|
||
|
if(fixReadyState){ doc.readyState = "complete"; }
|
||
|
|
||
|
ready = 1;
|
||
|
processQ();
|
||
|
},
|
||
|
on = function(node, event){
|
||
|
node.addEventListener(event, detectReady, false);
|
||
|
readyQ.push(function(){ node.removeEventListener(event, detectReady, false); });
|
||
|
};
|
||
|
|
||
|
if(!has("dom-addeventlistener")){
|
||
|
on = function(node, event){
|
||
|
event = "on" + event;
|
||
|
node.attachEvent(event, detectReady);
|
||
|
readyQ.push(function(){ node.detachEvent(event, detectReady); });
|
||
|
};
|
||
|
|
||
|
var div = doc.createElement("div");
|
||
|
try{
|
||
|
if(div.doScroll && global.frameElement === null){
|
||
|
// the doScroll test is only useful if we're in the top-most frame
|
||
|
tests.push(function(){
|
||
|
// Derived with permission from Diego Perini's IEContentLoaded
|
||
|
// http://javascript.nwbox.com/IEContentLoaded/
|
||
|
try{
|
||
|
div.doScroll("left");
|
||
|
return 1;
|
||
|
}catch(e){}
|
||
|
});
|
||
|
}
|
||
|
}catch(e){}
|
||
|
}
|
||
|
|
||
|
on(doc, "DOMContentLoaded");
|
||
|
on(global, "load");
|
||
|
|
||
|
if("onreadystatechange" in doc){
|
||
|
on(doc, "readystatechange");
|
||
|
}else if(!fixReadyState){
|
||
|
// if the ready state property exists and there's
|
||
|
// no readystatechange event, poll for the state
|
||
|
// to change
|
||
|
tests.push(function(){
|
||
|
return readyStates[doc.readyState];
|
||
|
});
|
||
|
}
|
||
|
|
||
|
if(tests.length){
|
||
|
var poller = function(){
|
||
|
if(ready){ return; }
|
||
|
var i = tests.length;
|
||
|
while(i--){
|
||
|
if(tests[i]()){
|
||
|
detectReady("poller");
|
||
|
return;
|
||
|
}
|
||
|
}
|
||
|
setTimeout(poller, 30);
|
||
|
};
|
||
|
poller();
|
||
|
}
|
||
|
}
|
||
|
|
||
|
return domReady;
|
||
|
});
|
||
|
|
||
|
},
|
||
|
'dojo/_base/declare':function(){
|
||
|
define(["./kernel", "../has", "./lang"], function(dojo, has, lang){
|
||
|
// module:
|
||
|
// dojo/_base/declare
|
||
|
|
||
|
var mix = lang.mixin, op = Object.prototype, opts = op.toString,
|
||
|
xtor, counter = 0, cname = "constructor";
|
||
|
|
||
|
if(!has("csp-restrictions")){
|
||
|
// 'new Function()' is preferable when available since it does not create a closure
|
||
|
xtor = new Function;
|
||
|
}else{
|
||
|
xtor = function(){};
|
||
|
}
|
||
|
|
||
|
function err(msg, cls){ throw new Error("declare" + (cls ? " " + cls : "") + ": " + msg); }
|
||
|
|
||
|
// C3 Method Resolution Order (see http://www.python.org/download/releases/2.3/mro/)
|
||
|
function c3mro(bases, className){
|
||
|
var result = [], roots = [{cls: 0, refs: []}], nameMap = {}, clsCount = 1,
|
||
|
l = bases.length, i = 0, j, lin, base, top, proto, rec, name, refs;
|
||
|
|
||
|
// build a list of bases naming them if needed
|
||
|
for(; i < l; ++i){
|
||
|
base = bases[i];
|
||
|
if(!base){
|
||
|
err("mixin #" + i + " is unknown. Did you use dojo.require to pull it in?", className);
|
||
|
}else if(opts.call(base) != "[object Function]"){
|
||
|
err("mixin #" + i + " is not a callable constructor.", className);
|
||
|
}
|
||
|
lin = base._meta ? base._meta.bases : [base];
|
||
|
top = 0;
|
||
|
// add bases to the name map
|
||
|
for(j = lin.length - 1; j >= 0; --j){
|
||
|
proto = lin[j].prototype;
|
||
|
if(!proto.hasOwnProperty("declaredClass")){
|
||
|
proto.declaredClass = "uniqName_" + (counter++);
|
||
|
}
|
||
|
name = proto.declaredClass;
|
||
|
if(!nameMap.hasOwnProperty(name)){
|
||
|
nameMap[name] = {count: 0, refs: [], cls: lin[j]};
|
||
|
++clsCount;
|
||
|
}
|
||
|
rec = nameMap[name];
|
||
|
if(top && top !== rec){
|
||
|
rec.refs.push(top);
|
||
|
++top.count;
|
||
|
}
|
||
|
top = rec;
|
||
|
}
|
||
|
++top.count;
|
||
|
roots[0].refs.push(top);
|
||
|
}
|
||
|
|
||
|
// remove classes without external references recursively
|
||
|
while(roots.length){
|
||
|
top = roots.pop();
|
||
|
result.push(top.cls);
|
||
|
--clsCount;
|
||
|
// optimization: follow a single-linked chain
|
||
|
while(refs = top.refs, refs.length == 1){
|
||
|
top = refs[0];
|
||
|
if(!top || --top.count){
|
||
|
// branch or end of chain => do not end to roots
|
||
|
top = 0;
|
||
|
break;
|
||
|
}
|
||
|
result.push(top.cls);
|
||
|
--clsCount;
|
||
|
}
|
||
|
if(top){
|
||
|
// branch
|
||
|
for(i = 0, l = refs.length; i < l; ++i){
|
||
|
top = refs[i];
|
||
|
if(!--top.count){
|
||
|
roots.push(top);
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
if(clsCount){
|
||
|
err("can't build consistent linearization", className);
|
||
|
}
|
||
|
|
||
|
// calculate the superclass offset
|
||
|
base = bases[0];
|
||
|
result[0] = base ?
|
||
|
base._meta && base === result[result.length - base._meta.bases.length] ?
|
||
|
base._meta.bases.length : 1 : 0;
|
||
|
|
||
|
return result;
|
||
|
}
|
||
|
|
||
|
function inherited(args, a, f, g){
|
||
|
var name, chains, bases, caller, meta, base, proto, opf, pos,
|
||
|
cache = this._inherited = this._inherited || {};
|
||
|
|
||
|
// crack arguments
|
||
|
if(typeof args === "string"){
|
||
|
name = args;
|
||
|
args = a;
|
||
|
a = f;
|
||
|
f = g;
|
||
|
}
|
||
|
|
||
|
if(typeof args === "function"){
|
||
|
// support strict mode
|
||
|
caller = args;
|
||
|
args = a;
|
||
|
a = f;
|
||
|
}else{
|
||
|
try{
|
||
|
caller = args.callee;
|
||
|
}catch (e){
|
||
|
if(e instanceof TypeError){
|
||
|
// caller was defined in a strict-mode context
|
||
|
err("strict mode inherited() requires the caller function to be passed before arguments", this.declaredClass);
|
||
|
}else{
|
||
|
throw e;
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
|
||
|
name = name || caller.nom;
|
||
|
if(!name){
|
||
|
err("can't deduce a name to call inherited()", this.declaredClass);
|
||
|
}
|
||
|
f = g = 0;
|
||
|
|
||
|
meta = this.constructor._meta;
|
||
|
bases = meta.bases;
|
||
|
|
||
|
pos = cache.p;
|
||
|
if(name != cname){
|
||
|
// method
|
||
|
if(cache.c !== caller){
|
||
|
// cache bust
|
||
|
pos = 0;
|
||
|
base = bases[0];
|
||
|
meta = base._meta;
|
||
|
if(meta.hidden[name] !== caller){
|
||
|
// error detection
|
||
|
chains = meta.chains;
|
||
|
if(chains && typeof chains[name] == "string"){
|
||
|
err("calling chained method with inherited: " + name, this.declaredClass);
|
||
|
}
|
||
|
// find caller
|
||
|
do{
|
||
|
meta = base._meta;
|
||
|
proto = base.prototype;
|
||
|
if(meta && (proto[name] === caller && proto.hasOwnProperty(name) || meta.hidden[name] === caller)){
|
||
|
break;
|
||
|
}
|
||
|
}while(base = bases[++pos]); // intentional assignment
|
||
|
pos = base ? pos : -1;
|
||
|
}
|
||
|
}
|
||
|
// find next
|
||
|
base = bases[++pos];
|
||
|
if(base){
|
||
|
proto = base.prototype;
|
||
|
if(base._meta && proto.hasOwnProperty(name)){
|
||
|
f = proto[name];
|
||
|
}else{
|
||
|
opf = op[name];
|
||
|
do{
|
||
|
proto = base.prototype;
|
||
|
f = proto[name];
|
||
|
if(f && (base._meta ? proto.hasOwnProperty(name) : f !== opf)){
|
||
|
break;
|
||
|
}
|
||
|
}while(base = bases[++pos]); // intentional assignment
|
||
|
}
|
||
|
}
|
||
|
f = base && f || op[name];
|
||
|
}else{
|
||
|
// constructor
|
||
|
if(cache.c !== caller){
|
||
|
// cache bust
|
||
|
pos = 0;
|
||
|
meta = bases[0]._meta;
|
||
|
if(meta && meta.ctor !== caller){
|
||
|
// error detection
|
||
|
chains = meta.chains;
|
||
|
if(!chains || chains.constructor !== "manual"){
|
||
|
err("calling chained constructor with inherited", this.declaredClass);
|
||
|
}
|
||
|
// find caller
|
||
|
while(base = bases[++pos]){ // intentional assignment
|
||
|
meta = base._meta;
|
||
|
if(meta && meta.ctor === caller){
|
||
|
break;
|
||
|
}
|
||
|
}
|
||
|
pos = base ? pos : -1;
|
||
|
}
|
||
|
}
|
||
|
// find next
|
||
|
while(base = bases[++pos]){ // intentional assignment
|
||
|
meta = base._meta;
|
||
|
f = meta ? meta.ctor : base;
|
||
|
if(f){
|
||
|
break;
|
||
|
}
|
||
|
}
|
||
|
f = base && f;
|
||
|
}
|
||
|
|
||
|
// cache the found super method
|
||
|
cache.c = f;
|
||
|
cache.p = pos;
|
||
|
|
||
|
// now we have the result
|
||
|
if(f){
|
||
|
return a === true ? f : f.apply(this, a || args);
|
||
|
}
|
||
|
// intentionally no return if a super method was not found
|
||
|
}
|
||
|
|
||
|
function getInherited(name, args, a){
|
||
|
if(typeof name === "string"){
|
||
|
if (typeof args === "function") {
|
||
|
return this.__inherited(name, args, a, true);
|
||
|
}
|
||
|
return this.__inherited(name, args, true);
|
||
|
}
|
||
|
else if (typeof name === "function") {
|
||
|
return this.__inherited(name, args, true);
|
||
|
}
|
||
|
return this.__inherited(name, true);
|
||
|
}
|
||
|
|
||
|
function inherited__debug(args, a1, a2, a3){
|
||
|
var f = this.getInherited(args, a1, a2);
|
||
|
if(f){
|
||
|
return f.apply(this, a3 || a2 || a1 || args);
|
||
|
}
|
||
|
// intentionally no return if a super method was not found
|
||
|
}
|
||
|
|
||
|
var inheritedImpl = dojo.config.isDebug ? inherited__debug : inherited;
|
||
|
|
||
|
// emulation of "instanceof"
|
||
|
function isInstanceOf(cls){
|
||
|
var bases = this.constructor._meta.bases;
|
||
|
for(var i = 0, l = bases.length; i < l; ++i){
|
||
|
if(bases[i] === cls){
|
||
|
return true;
|
||
|
}
|
||
|
}
|
||
|
return this instanceof cls;
|
||
|
}
|
||
|
|
||
|
function mixOwn(target, source){
|
||
|
// add props adding metadata for incoming functions skipping a constructor
|
||
|
for(var name in source){
|
||
|
if(name != cname && source.hasOwnProperty(name)){
|
||
|
target[name] = source[name];
|
||
|
}
|
||
|
}
|
||
|
if(has("bug-for-in-skips-shadowed")){
|
||
|
for(var extraNames= lang._extraNames, i= extraNames.length; i;){
|
||
|
name = extraNames[--i];
|
||
|
if(name != cname && source.hasOwnProperty(name)){
|
||
|
target[name] = source[name];
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
|
||
|
// implementation of safe mixin function
|
||
|
function safeMixin(target, source){
|
||
|
// summary:
|
||
|
// Mix in properties skipping a constructor and decorating functions
|
||
|
// like it is done by declare().
|
||
|
// target: Object
|
||
|
// Target object to accept new properties.
|
||
|
// source: Object
|
||
|
// Source object for new properties.
|
||
|
// description:
|
||
|
// This function is used to mix in properties like lang.mixin does,
|
||
|
// but it skips a constructor property and decorates functions like
|
||
|
// declare() does.
|
||
|
//
|
||
|
// It is meant to be used with classes and objects produced with
|
||
|
// declare. Functions mixed in with dojo.safeMixin can use
|
||
|
// this.inherited() like normal methods.
|
||
|
//
|
||
|
// This function is used to implement extend() method of a constructor
|
||
|
// produced with declare().
|
||
|
//
|
||
|
// example:
|
||
|
// | var A = declare(null, {
|
||
|
// | m1: function(){
|
||
|
// | console.log("A.m1");
|
||
|
// | },
|
||
|
// | m2: function(){
|
||
|
// | console.log("A.m2");
|
||
|
// | }
|
||
|
// | });
|
||
|
// | var B = declare(A, {
|
||
|
// | m1: function(){
|
||
|
// | this.inherited(arguments);
|
||
|
// | console.log("B.m1");
|
||
|
// | }
|
||
|
// | });
|
||
|
// | B.extend({
|
||
|
// | m2: function(){
|
||
|
// | this.inherited(arguments);
|
||
|
// | console.log("B.m2");
|
||
|
// | }
|
||
|
// | });
|
||
|
// | var x = new B();
|
||
|
// | dojo.safeMixin(x, {
|
||
|
// | m1: function(){
|
||
|
// | this.inherited(arguments);
|
||
|
// | console.log("X.m1");
|
||
|
// | },
|
||
|
// | m2: function(){
|
||
|
// | this.inherited(arguments);
|
||
|
// | console.log("X.m2");
|
||
|
// | }
|
||
|
// | });
|
||
|
// | x.m2();
|
||
|
// | // prints:
|
||
|
// | // A.m1
|
||
|
// | // B.m1
|
||
|
// | // X.m1
|
||
|
|
||
|
var name, t;
|
||
|
// add props adding metadata for incoming functions skipping a constructor
|
||
|
for(name in source){
|
||
|
t = source[name];
|
||
|
if((t !== op[name] || !(name in op)) && name != cname){
|
||
|
if(opts.call(t) == "[object Function]"){
|
||
|
// non-trivial function method => attach its name
|
||
|
t.nom = name;
|
||
|
}
|
||
|
target[name] = t;
|
||
|
}
|
||
|
}
|
||
|
if(has("bug-for-in-skips-shadowed") && source){
|
||
|
for(var extraNames= lang._extraNames, i= extraNames.length; i;){
|
||
|
name = extraNames[--i];
|
||
|
t = source[name];
|
||
|
if((t !== op[name] || !(name in op)) && name != cname){
|
||
|
if(opts.call(t) == "[object Function]"){
|
||
|
// non-trivial function method => attach its name
|
||
|
t.nom = name;
|
||
|
}
|
||
|
target[name] = t;
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
return target;
|
||
|
}
|
||
|
|
||
|
function extend(source){
|
||
|
declare.safeMixin(this.prototype, source);
|
||
|
return this;
|
||
|
}
|
||
|
|
||
|
function createSubclass(mixins, props){
|
||
|
// crack parameters
|
||
|
if(!(mixins instanceof Array || typeof mixins === 'function')){
|
||
|
props = mixins;
|
||
|
mixins = undefined;
|
||
|
}
|
||
|
|
||
|
props = props || {};
|
||
|
mixins = mixins || [];
|
||
|
|
||
|
return declare([this].concat(mixins), props);
|
||
|
}
|
||
|
|
||
|
// chained constructor compatible with the legacy declare()
|
||
|
function chainedConstructor(bases, ctorSpecial){
|
||
|
return function(){
|
||
|
var a = arguments, args = a, a0 = a[0], f, i, m,
|
||
|
l = bases.length, preArgs;
|
||
|
|
||
|
if(!(this instanceof a.callee)){
|
||
|
// not called via new, so force it
|
||
|
return applyNew(a);
|
||
|
}
|
||
|
|
||
|
//this._inherited = {};
|
||
|
// perform the shaman's rituals of the original declare()
|
||
|
// 1) call two types of the preamble
|
||
|
if(ctorSpecial && (a0 && a0.preamble || this.preamble)){
|
||
|
// full blown ritual
|
||
|
preArgs = new Array(bases.length);
|
||
|
// prepare parameters
|
||
|
preArgs[0] = a;
|
||
|
for(i = 0;;){
|
||
|
// process the preamble of the 1st argument
|
||
|
a0 = a[0];
|
||
|
if(a0){
|
||
|
f = a0.preamble;
|
||
|
if(f){
|
||
|
a = f.apply(this, a) || a;
|
||
|
}
|
||
|
}
|
||
|
// process the preamble of this class
|
||
|
f = bases[i].prototype;
|
||
|
f = f.hasOwnProperty("preamble") && f.preamble;
|
||
|
if(f){
|
||
|
a = f.apply(this, a) || a;
|
||
|
}
|
||
|
// one peculiarity of the preamble:
|
||
|
// it is called if it is not needed,
|
||
|
// e.g., there is no constructor to call
|
||
|
// let's watch for the last constructor
|
||
|
// (see ticket #9795)
|
||
|
if(++i == l){
|
||
|
break;
|
||
|
}
|
||
|
preArgs[i] = a;
|
||
|
}
|
||
|
}
|
||
|
// 2) call all non-trivial constructors using prepared arguments
|
||
|
for(i = l - 1; i >= 0; --i){
|
||
|
f = bases[i];
|
||
|
m = f._meta;
|
||
|
f = m ? m.ctor : f;
|
||
|
if(f){
|
||
|
f.apply(this, preArgs ? preArgs[i] : a);
|
||
|
}
|
||
|
}
|
||
|
// 3) continue the original ritual: call the postscript
|
||
|
f = this.postscript;
|
||
|
if(f){
|
||
|
f.apply(this, args);
|
||
|
}
|
||
|
};
|
||
|
}
|
||
|
|
||
|
|
||
|
// chained constructor compatible with the legacy declare()
|
||
|
function singleConstructor(ctor, ctorSpecial){
|
||
|
return function(){
|
||
|
var a = arguments, t = a, a0 = a[0], f;
|
||
|
|
||
|
if(!(this instanceof a.callee)){
|
||
|
// not called via new, so force it
|
||
|
return applyNew(a);
|
||
|
}
|
||
|
|
||
|
//this._inherited = {};
|
||
|
// perform the shaman's rituals of the original declare()
|
||
|
// 1) call two types of the preamble
|
||
|
if(ctorSpecial){
|
||
|
// full blown ritual
|
||
|
if(a0){
|
||
|
// process the preamble of the 1st argument
|
||
|
f = a0.preamble;
|
||
|
if(f){
|
||
|
t = f.apply(this, t) || t;
|
||
|
}
|
||
|
}
|
||
|
f = this.preamble;
|
||
|
if(f){
|
||
|
// process the preamble of this class
|
||
|
f.apply(this, t);
|
||
|
// one peculiarity of the preamble:
|
||
|
// it is called even if it is not needed,
|
||
|
// e.g., there is no constructor to call
|
||
|
// let's watch for the last constructor
|
||
|
// (see ticket #9795)
|
||
|
}
|
||
|
}
|
||
|
// 2) call a constructor
|
||
|
if(ctor){
|
||
|
ctor.apply(this, a);
|
||
|
}
|
||
|
// 3) continue the original ritual: call the postscript
|
||
|
f = this.postscript;
|
||
|
if(f){
|
||
|
f.apply(this, a);
|
||
|
}
|
||
|
};
|
||
|
}
|
||
|
|
||
|
// plain vanilla constructor (can use inherited() to call its base constructor)
|
||
|
function simpleConstructor(bases){
|
||
|
return function(){
|
||
|
var a = arguments, i = 0, f, m;
|
||
|
|
||
|
if(!(this instanceof a.callee)){
|
||
|
// not called via new, so force it
|
||
|
return applyNew(a);
|
||
|
}
|
||
|
|
||
|
//this._inherited = {};
|
||
|
// perform the shaman's rituals of the original declare()
|
||
|
// 1) do not call the preamble
|
||
|
// 2) call the top constructor (it can use this.inherited())
|
||
|
for(; f = bases[i]; ++i){ // intentional assignment
|
||
|
m = f._meta;
|
||
|
f = m ? m.ctor : f;
|
||
|
if(f){
|
||
|
f.apply(this, a);
|
||
|
break;
|
||
|
}
|
||
|
}
|
||
|
// 3) call the postscript
|
||
|
f = this.postscript;
|
||
|
if(f){
|
||
|
f.apply(this, a);
|
||
|
}
|
||
|
};
|
||
|
}
|
||
|
|
||
|
function chain(name, bases, reversed){
|
||
|
return function(){
|
||
|
var b, m, f, i = 0, step = 1;
|
||
|
if(reversed){
|
||
|
i = bases.length - 1;
|
||
|
step = -1;
|
||
|
}
|
||
|
for(; b = bases[i]; i += step){ // intentional assignment
|
||
|
m = b._meta;
|
||
|
f = (m ? m.hidden : b.prototype)[name];
|
||
|
if(f){
|
||
|
f.apply(this, arguments);
|
||
|
}
|
||
|
}
|
||
|
};
|
||
|
}
|
||
|
|
||
|
// forceNew(ctor)
|
||
|
// return a new object that inherits from ctor.prototype but
|
||
|
// without actually running ctor on the object.
|
||
|
function forceNew(ctor){
|
||
|
// create object with correct prototype using a do-nothing
|
||
|
// constructor
|
||
|
xtor.prototype = ctor.prototype;
|
||
|
var t = new xtor;
|
||
|
xtor.prototype = null; // clean up
|
||
|
return t;
|
||
|
}
|
||
|
|
||
|
// applyNew(args)
|
||
|
// just like 'new ctor()' except that the constructor and its arguments come
|
||
|
// from args, which must be an array or an arguments object
|
||
|
function applyNew(args){
|
||
|
// create an object with ctor's prototype but without
|
||
|
// calling ctor on it.
|
||
|
var ctor = args.callee, t = forceNew(ctor);
|
||
|
// execute the real constructor on the new object
|
||
|
ctor.apply(t, args);
|
||
|
return t;
|
||
|
}
|
||
|
|
||
|
function declare(className, superclass, props){
|
||
|
// summary:
|
||
|
// Create a feature-rich constructor from compact notation.
|
||
|
// className: String?
|
||
|
// The optional name of the constructor (loosely, a "class")
|
||
|
// stored in the "declaredClass" property in the created prototype.
|
||
|
// It will be used as a global name for a created constructor.
|
||
|
// superclass: Function|Function[]
|
||
|
// May be null, a Function, or an Array of Functions. This argument
|
||
|
// specifies a list of bases (the left-most one is the most deepest
|
||
|
// base).
|
||
|
// props: Object
|
||
|
// An object whose properties are copied to the created prototype.
|
||
|
// Add an instance-initialization function by making it a property
|
||
|
// named "constructor".
|
||
|
// returns: dojo/_base/declare.__DeclareCreatedObject
|
||
|
// New constructor function.
|
||
|
// description:
|
||
|
// Create a constructor using a compact notation for inheritance and
|
||
|
// prototype extension.
|
||
|
//
|
||
|
// Mixin ancestors provide a type of multiple inheritance.
|
||
|
// Prototypes of mixin ancestors are copied to the new class:
|
||
|
// changes to mixin prototypes will not affect classes to which
|
||
|
// they have been mixed in.
|
||
|
//
|
||
|
// Ancestors can be compound classes created by this version of
|
||
|
// declare(). In complex cases all base classes are going to be
|
||
|
// linearized according to C3 MRO algorithm
|
||
|
// (see http://www.python.org/download/releases/2.3/mro/ for more
|
||
|
// details).
|
||
|
//
|
||
|
// "className" is cached in "declaredClass" property of the new class,
|
||
|
// if it was supplied. The immediate super class will be cached in
|
||
|
// "superclass" property of the new class.
|
||
|
//
|
||
|
// Methods in "props" will be copied and modified: "nom" property
|
||
|
// (the declared name of the method) will be added to all copied
|
||
|
// functions to help identify them for the internal machinery. Be
|
||
|
// very careful, while reusing methods: if you use the same
|
||
|
// function under different names, it can produce errors in some
|
||
|
// cases.
|
||
|
//
|
||
|
// It is possible to use constructors created "manually" (without
|
||
|
// declare()) as bases. They will be called as usual during the
|
||
|
// creation of an instance, their methods will be chained, and even
|
||
|
// called by "this.inherited()".
|
||
|
//
|
||
|
// Special property "-chains-" governs how to chain methods. It is
|
||
|
// a dictionary, which uses method names as keys, and hint strings
|
||
|
// as values. If a hint string is "after", this method will be
|
||
|
// called after methods of its base classes. If a hint string is
|
||
|
// "before", this method will be called before methods of its base
|
||
|
// classes.
|
||
|
//
|
||
|
// If "constructor" is not mentioned in "-chains-" property, it will
|
||
|
// be chained using the legacy mode: using "after" chaining,
|
||
|
// calling preamble() method before each constructor, if available,
|
||
|
// and calling postscript() after all constructors were executed.
|
||
|
// If the hint is "after", it is chained as a regular method, but
|
||
|
// postscript() will be called after the chain of constructors.
|
||
|
// "constructor" cannot be chained "before", but it allows
|
||
|
// a special hint string: "manual", which means that constructors
|
||
|
// are not going to be chained in any way, and programmer will call
|
||
|
// them manually using this.inherited(). In the latter case
|
||
|
// postscript() will be called after the construction.
|
||
|
//
|
||
|
// All chaining hints are "inherited" from base classes and
|
||
|
// potentially can be overridden. Be very careful when overriding
|
||
|
// hints! Make sure that all chained methods can work in a proposed
|
||
|
// manner of chaining.
|
||
|
//
|
||
|
// Once a method was chained, it is impossible to unchain it. The
|
||
|
// only exception is "constructor". You don't need to define a
|
||
|
// method in order to supply a chaining hint.
|
||
|
//
|
||
|
// If a method is chained, it cannot use this.inherited() because
|
||
|
// all other methods in the hierarchy will be called automatically.
|
||
|
//
|
||
|
// Usually constructors and initializers of any kind are chained
|
||
|
// using "after" and destructors of any kind are chained as
|
||
|
// "before". Note that chaining assumes that chained methods do not
|
||
|
// return any value: any returned value will be discarded.
|
||
|
//
|
||
|
// example:
|
||
|
// | declare("my.classes.bar", my.classes.foo, {
|
||
|
// | // properties to be added to the class prototype
|
||
|
// | someValue: 2,
|
||
|
// | // initialization function
|
||
|
// | constructor: function(){
|
||
|
// | this.myComplicatedObject = new ReallyComplicatedObject();
|
||
|
// | },
|
||
|
// | // other functions
|
||
|
// | someMethod: function(){
|
||
|
// | doStuff();
|
||
|
// | }
|
||
|
// | });
|
||
|
//
|
||
|
// example:
|
||
|
// | var MyBase = declare(null, {
|
||
|
// | // constructor, properties, and methods go here
|
||
|
// | // ...
|
||
|
// | });
|
||
|
// | var MyClass1 = declare(MyBase, {
|
||
|
// | // constructor, properties, and methods go here
|
||
|
// | // ...
|
||
|
// | });
|
||
|
// | var MyClass2 = declare(MyBase, {
|
||
|
// | // constructor, properties, and methods go here
|
||
|
// | // ...
|
||
|
// | });
|
||
|
// | var MyDiamond = declare([MyClass1, MyClass2], {
|
||
|
// | // constructor, properties, and methods go here
|
||
|
// | // ...
|
||
|
// | });
|
||
|
//
|
||
|
// example:
|
||
|
// | var F = function(){ console.log("raw constructor"); };
|
||
|
// | F.prototype.method = function(){
|
||
|
// | console.log("raw method");
|
||
|
// | };
|
||
|
// | var A = declare(F, {
|
||
|
// | constructor: function(){
|
||
|
// | console.log("A.constructor");
|
||
|
// | },
|
||
|
// | method: function(){
|
||
|
// | console.log("before calling F.method...");
|
||
|
// | this.inherited(arguments);
|
||
|
// | console.log("...back in A");
|
||
|
// | }
|
||
|
// | });
|
||
|
// | new A().method();
|
||
|
// | // will print:
|
||
|
// | // raw constructor
|
||
|
// | // A.constructor
|
||
|
// | // before calling F.method...
|
||
|
// | // raw method
|
||
|
// | // ...back in A
|
||
|
//
|
||
|
// example:
|
||
|
// | var A = declare(null, {
|
||
|
// | "-chains-": {
|
||
|
// | destroy: "before"
|
||
|
// | }
|
||
|
// | });
|
||
|
// | var B = declare(A, {
|
||
|
// | constructor: function(){
|
||
|
// | console.log("B.constructor");
|
||
|
// | },
|
||
|
// | destroy: function(){
|
||
|
// | console.log("B.destroy");
|
||
|
// | }
|
||
|
// | });
|
||
|
// | var C = declare(B, {
|
||
|
// | constructor: function(){
|
||
|
// | console.log("C.constructor");
|
||
|
// | },
|
||
|
// | destroy: function(){
|
||
|
// | console.log("C.destroy");
|
||
|
// | }
|
||
|
// | });
|
||
|
// | new C().destroy();
|
||
|
// | // prints:
|
||
|
// | // B.constructor
|
||
|
// | // C.constructor
|
||
|
// | // C.destroy
|
||
|
// | // B.destroy
|
||
|
//
|
||
|
// example:
|
||
|
// | var A = declare(null, {
|
||
|
// | "-chains-": {
|
||
|
// | constructor: "manual"
|
||
|
// | }
|
||
|
// | });
|
||
|
// | var B = declare(A, {
|
||
|
// | constructor: function(){
|
||
|
// | // ...
|
||
|
// | // call the base constructor with new parameters
|
||
|
// | this.inherited(arguments, [1, 2, 3]);
|
||
|
// | // ...
|
||
|
// | }
|
||
|
// | });
|
||
|
//
|
||
|
// example:
|
||
|
// | var A = declare(null, {
|
||
|
// | "-chains-": {
|
||
|
// | m1: "before"
|
||
|
// | },
|
||
|
// | m1: function(){
|
||
|
// | console.log("A.m1");
|
||
|
// | },
|
||
|
// | m2: function(){
|
||
|
// | console.log("A.m2");
|
||
|
// | }
|
||
|
// | });
|
||
|
// | var B = declare(A, {
|
||
|
// | "-chains-": {
|
||
|
// | m2: "after"
|
||
|
// | },
|
||
|
// | m1: function(){
|
||
|
// | console.log("B.m1");
|
||
|
// | },
|
||
|
// | m2: function(){
|
||
|
// | console.log("B.m2");
|
||
|
// | }
|
||
|
// | });
|
||
|
// | var x = new B();
|
||
|
// | x.m1();
|
||
|
// | // prints:
|
||
|
// | // B.m1
|
||
|
// | // A.m1
|
||
|
// | x.m2();
|
||
|
// | // prints:
|
||
|
// | // A.m2
|
||
|
// | // B.m2
|
||
|
|
||
|
// crack parameters
|
||
|
if(typeof className != "string"){
|
||
|
props = superclass;
|
||
|
superclass = className;
|
||
|
className = "";
|
||
|
}
|
||
|
props = props || {};
|
||
|
|
||
|
var proto, i, t, ctor, name, bases, chains, mixins = 1, parents = superclass;
|
||
|
|
||
|
// build a prototype
|
||
|
if(opts.call(superclass) == "[object Array]"){
|
||
|
// C3 MRO
|
||
|
bases = c3mro(superclass, className);
|
||
|
t = bases[0];
|
||
|
mixins = bases.length - t;
|
||
|
superclass = bases[mixins];
|
||
|
}else{
|
||
|
bases = [0];
|
||
|
if(superclass){
|
||
|
if(opts.call(superclass) == "[object Function]"){
|
||
|
t = superclass._meta;
|
||
|
bases = bases.concat(t ? t.bases : superclass);
|
||
|
}else{
|
||
|
err("base class is not a callable constructor.", className);
|
||
|
}
|
||
|
}else if(superclass !== null){
|
||
|
err("unknown base class. Did you use dojo.require to pull it in?", className);
|
||
|
}
|
||
|
}
|
||
|
if(superclass){
|
||
|
for(i = mixins - 1;; --i){
|
||
|
proto = forceNew(superclass);
|
||
|
if(!i){
|
||
|
// stop if nothing to add (the last base)
|
||
|
break;
|
||
|
}
|
||
|
// mix in properties
|
||
|
t = bases[i];
|
||
|
(t._meta ? mixOwn : mix)(proto, t.prototype);
|
||
|
// chain in new constructor
|
||
|
if (has("csp-restrictions")) {
|
||
|
ctor = function () {};
|
||
|
}
|
||
|
else {
|
||
|
ctor = new Function;
|
||
|
}
|
||
|
ctor.superclass = superclass;
|
||
|
ctor.prototype = proto;
|
||
|
superclass = proto.constructor = ctor;
|
||
|
}
|
||
|
}else{
|
||
|
proto = {};
|
||
|
}
|
||
|
// add all properties
|
||
|
declare.safeMixin(proto, props);
|
||
|
// add constructor
|
||
|
t = props.constructor;
|
||
|
if(t !== op.constructor){
|
||
|
t.nom = cname;
|
||
|
proto.constructor = t;
|
||
|
}
|
||
|
|
||
|
// collect chains and flags
|
||
|
for(i = mixins - 1; i; --i){ // intentional assignment
|
||
|
t = bases[i]._meta;
|
||
|
if(t && t.chains){
|
||
|
chains = mix(chains || {}, t.chains);
|
||
|
}
|
||
|
}
|
||
|
if(proto["-chains-"]){
|
||
|
chains = mix(chains || {}, proto["-chains-"]);
|
||
|
}
|
||
|
|
||
|
if(superclass && superclass.prototype && superclass.prototype["-chains-"]) {
|
||
|
chains = mix(chains || {}, superclass.prototype["-chains-"]);
|
||
|
}
|
||
|
|
||
|
// build ctor
|
||
|
t = !chains || !chains.hasOwnProperty(cname);
|
||
|
bases[0] = ctor = (chains && chains.constructor === "manual") ? simpleConstructor(bases) :
|
||
|
(bases.length == 1 ? singleConstructor(props.constructor, t) : chainedConstructor(bases, t));
|
||
|
|
||
|
// add meta information to the constructor
|
||
|
ctor._meta = {bases: bases, hidden: props, chains: chains,
|
||
|
parents: parents, ctor: props.constructor};
|
||
|
ctor.superclass = superclass && superclass.prototype;
|
||
|
ctor.extend = extend;
|
||
|
ctor.createSubclass = createSubclass;
|
||
|
ctor.prototype = proto;
|
||
|
proto.constructor = ctor;
|
||
|
|
||
|
// add "standard" methods to the prototype
|
||
|
proto.getInherited = getInherited;
|
||
|
proto.isInstanceOf = isInstanceOf;
|
||
|
proto.inherited = inheritedImpl;
|
||
|
proto.__inherited = inherited;
|
||
|
|
||
|
// add name if specified
|
||
|
if(className){
|
||
|
proto.declaredClass = className;
|
||
|
lang.setObject(className, ctor);
|
||
|
}
|
||
|
|
||
|
// build chains and add them to the prototype
|
||
|
if(chains){
|
||
|
for(name in chains){
|
||
|
if(proto[name] && typeof chains[name] == "string" && name != cname){
|
||
|
t = proto[name] = chain(name, bases, chains[name] === "after");
|
||
|
t.nom = name;
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
// chained methods do not return values
|
||
|
// no need to chain "invisible" functions
|
||
|
|
||
|
return ctor; // Function
|
||
|
}
|
||
|
|
||
|
/*=====
|
||
|
declare.__DeclareCreatedObject = {
|
||
|
// summary:
|
||
|
// dojo/_base/declare() returns a constructor `C`. `new C()` returns an Object with the following
|
||
|
// methods, in addition to the methods and properties specified via the arguments passed to declare().
|
||
|
|
||
|
inherited: function(name, caller, args, newArgs){
|
||
|
// summary:
|
||
|
// Calls a super method.
|
||
|
// name: String?
|
||
|
// The optional method name. Should be the same as the caller's
|
||
|
// name. Usually "name" is specified in complex dynamic cases, when
|
||
|
// the calling method was dynamically added, undecorated by
|
||
|
// declare(), and it cannot be determined.
|
||
|
// caller: Function?
|
||
|
// The reference to the calling function. Required only if the
|
||
|
// call to "this.inherited" occurs from within strict-mode code.
|
||
|
// If the caller is omitted within strict-mode code, an error will
|
||
|
// be thrown.
|
||
|
// The best way to obtain a reference to the calling function is to
|
||
|
// use a named function expression (i.e. place a function name
|
||
|
// after the "function" keyword and before the open paren, as in
|
||
|
// "function fn(a, b)"). If the function is parsed as an expression
|
||
|
// and not a statement (i.e. it's not by itself on its own line),
|
||
|
// the function name will only be accessible as an identifier from
|
||
|
// within the body of the function.
|
||
|
// args: Arguments
|
||
|
// The caller supply this argument, which should be the original
|
||
|
// "arguments".
|
||
|
// newArgs: Object?
|
||
|
// If "true", the found function will be returned without
|
||
|
// executing it.
|
||
|
// If Array, it will be used to call a super method. Otherwise
|
||
|
// "args" will be used.
|
||
|
// returns:
|
||
|
// Whatever is returned by a super method, or a super method itself,
|
||
|
// if "true" was specified as newArgs.
|
||
|
// description:
|
||
|
// This method is used inside method of classes produced with
|
||
|
// declare() to call a super method (next in the chain). It is
|
||
|
// used for manually controlled chaining. Consider using the regular
|
||
|
// chaining, because it is faster. Use "this.inherited()" only in
|
||
|
// complex cases.
|
||
|
//
|
||
|
// This method cannot me called from automatically chained
|
||
|
// constructors including the case of a special (legacy)
|
||
|
// constructor chaining. It cannot be called from chained methods.
|
||
|
//
|
||
|
// If "this.inherited()" cannot find the next-in-chain method, it
|
||
|
// does nothing and returns "undefined". The last method in chain
|
||
|
// can be a default method implemented in Object, which will be
|
||
|
// called last.
|
||
|
//
|
||
|
// If "name" is specified, it is assumed that the method that
|
||
|
// received "args" is the parent method for this call. It is looked
|
||
|
// up in the chain list and if it is found the next-in-chain method
|
||
|
// is called. If it is not found, the first-in-chain method is
|
||
|
// called.
|
||
|
//
|
||
|
// If "name" is not specified, it will be derived from the calling
|
||
|
// method (using a methoid property "nom").
|
||
|
//
|
||
|
// example:
|
||
|
// | var B = declare(A, {
|
||
|
// | method1: function(a, b, c){
|
||
|
// | this.inherited(arguments);
|
||
|
// | },
|
||
|
// | method2: function(a, b){
|
||
|
// | return this.inherited(arguments, [a + b]);
|
||
|
// | }
|
||
|
// | });
|
||
|
// | // next method is not in the chain list because it is added
|
||
|
// | // manually after the class was created.
|
||
|
// | B.prototype.method3 = function(){
|
||
|
// | console.log("This is a dynamically-added method.");
|
||
|
// | this.inherited("method3", arguments);
|
||
|
// | };
|
||
|
// example:
|
||
|
// | var B = declare(A, {
|
||
|
// | method: function(a, b){
|
||
|
// | var super = this.inherited(arguments, true);
|
||
|
// | // ...
|
||
|
// | if(!super){
|
||
|
// | console.log("there is no super method");
|
||
|
// | return 0;
|
||
|
// | }
|
||
|
// | return super.apply(this, arguments);
|
||
|
// | }
|
||
|
// | });
|
||
|
// example:
|
||
|
// | "use strict";
|
||
|
// | // class is defined in strict-mode code,
|
||
|
// | // so caller must be passed before arguments.
|
||
|
// | var B = declare(A, {
|
||
|
// | // using a named function expression with "fn" as the name.
|
||
|
// | method: function fn(a, b) {
|
||
|
// | this.inherited(fn, arguments);
|
||
|
// | }
|
||
|
// | });
|
||
|
return {}; // Object
|
||
|
},
|
||
|
|
||
|
getInherited: function(name, caller, args){
|
||
|
// summary:
|
||
|
// Returns a super method.
|
||
|
// name: String?
|
||
|
// The optional method name. Should be the same as the caller's
|
||
|
// name. Usually "name" is specified in complex dynamic cases, when
|
||
|
// the calling method was dynamically added, undecorated by
|
||
|
// declare(), and it cannot be determined.
|
||
|
// caller: Function?
|
||
|
// The caller function. This is required when running in
|
||
|
// strict-mode code. A reference to the caller function
|
||
|
// can be obtained by using a named function expression
|
||
|
// (e.g. function fn(a,b) {...}).
|
||
|
// args: Arguments
|
||
|
// The caller supply this argument, which should be the original
|
||
|
// "arguments".
|
||
|
// returns:
|
||
|
// Returns a super method (Function) or "undefined".
|
||
|
// description:
|
||
|
// This method is a convenience method for "this.inherited()".
|
||
|
// It uses the same algorithm but instead of executing a super
|
||
|
// method, it returns it, or "undefined" if not found.
|
||
|
//
|
||
|
// example:
|
||
|
// | var B = declare(A, {
|
||
|
// | method: function(a, b){
|
||
|
// | var super = this.getInherited(arguments);
|
||
|
// | // ...
|
||
|
// | if(!super){
|
||
|
// | console.log("there is no super method");
|
||
|
// | return 0;
|
||
|
// | }
|
||
|
// | return super.apply(this, arguments);
|
||
|
// | }
|
||
|
// | });
|
||
|
// example:
|
||
|
// | "use strict;" // first line of function or file
|
||
|
// | //...
|
||
|
// | var B = declare(A, {
|
||
|
// | // Using a named function expression with "fn" as the name,
|
||
|
// | // since we're in strict mode.
|
||
|
// | method: function fn(a, b){
|
||
|
// | var super = this.getInherited(fn, arguments);
|
||
|
// | if(super){
|
||
|
// | return super.apply(this, arguments);
|
||
|
// | }
|
||
|
// | }
|
||
|
// | });
|
||
|
return {}; // Object
|
||
|
},
|
||
|
|
||
|
isInstanceOf: function(cls){
|
||
|
// summary:
|
||
|
// Checks the inheritance chain to see if it is inherited from this
|
||
|
// class.
|
||
|
// cls: Function
|
||
|
// Class constructor.
|
||
|
// returns:
|
||
|
// "true", if this object is inherited from this class, "false"
|
||
|
// otherwise.
|
||
|
// description:
|
||
|
// This method is used with instances of classes produced with
|
||
|
// declare() to determine of they support a certain interface or
|
||
|
// not. It models "instanceof" operator.
|
||
|
//
|
||
|
// example:
|
||
|
// | var A = declare(null, {
|
||
|
// | // constructor, properties, and methods go here
|
||
|
// | // ...
|
||
|
// | });
|
||
|
// | var B = declare(null, {
|
||
|
// | // constructor, properties, and methods go here
|
||
|
// | // ...
|
||
|
// | });
|
||
|
// | var C = declare([A, B], {
|
||
|
// | // constructor, properties, and methods go here
|
||
|
// | // ...
|
||
|
// | });
|
||
|
// | var D = declare(A, {
|
||
|
// | // constructor, properties, and methods go here
|
||
|
// | // ...
|
||
|
// | });
|
||
|
// |
|
||
|
// | var a = new A(), b = new B(), c = new C(), d = new D();
|
||
|
// |
|
||
|
// | console.log(a.isInstanceOf(A)); // true
|
||
|
// | console.log(b.isInstanceOf(A)); // false
|
||
|
// | console.log(c.isInstanceOf(A)); // true
|
||
|
// | console.log(d.isInstanceOf(A)); // true
|
||
|
// |
|
||
|
// | console.log(a.isInstanceOf(B)); // false
|
||
|
// | console.log(b.isInstanceOf(B)); // true
|
||
|
// | console.log(c.isInstanceOf(B)); // true
|
||
|
// | console.log(d.isInstanceOf(B)); // false
|
||
|
// |
|
||
|
// | console.log(a.isInstanceOf(C)); // false
|
||
|
// | console.log(b.isInstanceOf(C)); // false
|
||
|
// | console.log(c.isInstanceOf(C)); // true
|
||
|
// | console.log(d.isInstanceOf(C)); // false
|
||
|
// |
|
||
|
// | console.log(a.isInstanceOf(D)); // false
|
||
|
// | console.log(b.isInstanceOf(D)); // false
|
||
|
// | console.log(c.isInstanceOf(D)); // false
|
||
|
// | console.log(d.isInstanceOf(D)); // true
|
||
|
return {}; // Object
|
||
|
},
|
||
|
|
||
|
extend: function(source){
|
||
|
// summary:
|
||
|
// Adds all properties and methods of source to constructor's
|
||
|
// prototype, making them available to all instances created with
|
||
|
// constructor. This method is specific to constructors created with
|
||
|
// declare().
|
||
|
// source: Object
|
||
|
// Source object which properties are going to be copied to the
|
||
|
// constructor's prototype.
|
||
|
// description:
|
||
|
// Adds source properties to the constructor's prototype. It can
|
||
|
// override existing properties.
|
||
|
//
|
||
|
// This method is similar to dojo.extend function, but it is specific
|
||
|
// to constructors produced by declare(). It is implemented
|
||
|
// using dojo.safeMixin, and it skips a constructor property,
|
||
|
// and properly decorates copied functions.
|
||
|
//
|
||
|
// example:
|
||
|
// | var A = declare(null, {
|
||
|
// | m1: function(){},
|
||
|
// | s1: "Popokatepetl"
|
||
|
// | });
|
||
|
// | A.extend({
|
||
|
// | m1: function(){},
|
||
|
// | m2: function(){},
|
||
|
// | f1: true,
|
||
|
// | d1: 42
|
||
|
// | });
|
||
|
},
|
||
|
|
||
|
createSubclass: function(mixins, props){
|
||
|
// summary:
|
||
|
// Create a subclass of the declared class from a list of base classes.
|
||
|
// mixins: Function[]
|
||
|
// Specifies a list of bases (the left-most one is the most deepest
|
||
|
// base).
|
||
|
// props: Object?
|
||
|
// An optional object whose properties are copied to the created prototype.
|
||
|
// returns: dojo/_base/declare.__DeclareCreatedObject
|
||
|
// New constructor function.
|
||
|
// description:
|
||
|
// Create a constructor using a compact notation for inheritance and
|
||
|
// prototype extension.
|
||
|
//
|
||
|
// Mixin ancestors provide a type of multiple inheritance.
|
||
|
// Prototypes of mixin ancestors are copied to the new class:
|
||
|
// changes to mixin prototypes will not affect classes to which
|
||
|
// they have been mixed in.
|
||
|
//
|
||
|
// example:
|
||
|
// | var A = declare(null, {
|
||
|
// | m1: function(){},
|
||
|
// | s1: "bar"
|
||
|
// | });
|
||
|
// | var B = declare(null, {
|
||
|
// | m2: function(){},
|
||
|
// | s2: "foo"
|
||
|
// | });
|
||
|
// | var C = declare(null, {
|
||
|
// | });
|
||
|
// | var D1 = A.createSubclass([B, C], {
|
||
|
// | m1: function(){},
|
||
|
// | d1: 42
|
||
|
// | });
|
||
|
// | var d1 = new D1();
|
||
|
// |
|
||
|
// | // this is equivalent to:
|
||
|
// | var D2 = declare([A, B, C], {
|
||
|
// | m1: function(){},
|
||
|
// | d1: 42
|
||
|
// | });
|
||
|
// | var d2 = new D2();
|
||
|
}
|
||
|
};
|
||
|
=====*/
|
||
|
|
||
|
// For back-compat, remove for 2.0
|
||
|
dojo.safeMixin = declare.safeMixin = safeMixin;
|
||
|
dojo.declare = declare;
|
||
|
|
||
|
return declare;
|
||
|
});
|
||
|
|
||
|
},
|
||
|
'dojo/_base/connect':function(){
|
||
|
define(["./kernel", "../on", "../topic", "../aspect", "./event", "../mouse", "./sniff", "./lang", "../keys"], function(dojo, on, hub, aspect, eventModule, mouse, has, lang){
|
||
|
// module:
|
||
|
// dojo/_base/connect
|
||
|
|
||
|
has.add("events-keypress-typed", function(){ // keypresses should only occur a printable character is hit
|
||
|
var testKeyEvent = {charCode: 0};
|
||
|
try{
|
||
|
testKeyEvent = document.createEvent("KeyboardEvent");
|
||
|
(testKeyEvent.initKeyboardEvent || testKeyEvent.initKeyEvent).call(testKeyEvent, "keypress", true, true, null, false, false, false, false, 9, 3);
|
||
|
}catch(e){}
|
||
|
return testKeyEvent.charCode == 0 && !has("opera");
|
||
|
});
|
||
|
|
||
|
function connect_(obj, event, context, method, dontFix){
|
||
|
method = lang.hitch(context, method);
|
||
|
if(!obj || !(obj.addEventListener || obj.attachEvent)){
|
||
|
// it is a not a DOM node and we are using the dojo.connect style of treating a
|
||
|
// method like an event, must go right to aspect
|
||
|
return aspect.after(obj || dojo.global, event, method, true);
|
||
|
}
|
||
|
if(typeof event == "string" && event.substring(0, 2) == "on"){
|
||
|
event = event.substring(2);
|
||
|
}
|
||
|
if(!obj){
|
||
|
obj = dojo.global;
|
||
|
}
|
||
|
if(!dontFix){
|
||
|
switch(event){
|
||
|
// dojo.connect has special handling for these event types
|
||
|
case "keypress":
|
||
|
event = keypress;
|
||
|
break;
|
||
|
case "mouseenter":
|
||
|
event = mouse.enter;
|
||
|
break;
|
||
|
case "mouseleave":
|
||
|
event = mouse.leave;
|
||
|
break;
|
||
|
}
|
||
|
}
|
||
|
return on(obj, event, method, dontFix);
|
||
|
}
|
||
|
|
||
|
var _punctMap = {
|
||
|
106:42,
|
||
|
111:47,
|
||
|
186:59,
|
||
|
187:43,
|
||
|
188:44,
|
||
|
189:45,
|
||
|
190:46,
|
||
|
191:47,
|
||
|
192:96,
|
||
|
219:91,
|
||
|
220:92,
|
||
|
221:93,
|
||
|
222:39,
|
||
|
229:113
|
||
|
};
|
||
|
var evtCopyKey = has("mac") ? "metaKey" : "ctrlKey";
|
||
|
|
||
|
|
||
|
var _synthesizeEvent = function(evt, props){
|
||
|
var faux = lang.mixin({}, evt, props);
|
||
|
setKeyChar(faux);
|
||
|
// FIXME: would prefer to use lang.hitch: lang.hitch(evt, evt.preventDefault);
|
||
|
// but it throws an error when preventDefault is invoked on Safari
|
||
|
// does Event.preventDefault not support "apply" on Safari?
|
||
|
faux.preventDefault = function(){ evt.preventDefault(); };
|
||
|
faux.stopPropagation = function(){ evt.stopPropagation(); };
|
||
|
return faux;
|
||
|
};
|
||
|
function setKeyChar(evt){
|
||
|
evt.keyChar = evt.charCode ? String.fromCharCode(evt.charCode) : '';
|
||
|
evt.charOrCode = evt.keyChar || evt.keyCode;
|
||
|
}
|
||
|
var keypress;
|
||
|
if(has("events-keypress-typed")){
|
||
|
// this emulates Firefox's keypress behavior where every keydown can correspond to a keypress
|
||
|
var _trySetKeyCode = function(e, code){
|
||
|
try{
|
||
|
// squelch errors when keyCode is read-only
|
||
|
// (e.g. if keyCode is ctrl or shift)
|
||
|
return (e.keyCode = code);
|
||
|
}catch(e){
|
||
|
return 0;
|
||
|
}
|
||
|
};
|
||
|
keypress = function(object, listener){
|
||
|
var keydownSignal = on(object, "keydown", function(evt){
|
||
|
// munge key/charCode
|
||
|
var k=evt.keyCode;
|
||
|
// These are Windows Virtual Key Codes
|
||
|
// http://msdn.microsoft.com/library/default.asp?url=/library/en-us/winui/WinUI/WindowsUserInterface/UserInput/VirtualKeyCodes.asp
|
||
|
var unprintable = (k!=13) && k!=32 && (k!=27||!has("ie")) && (k<48||k>90) && (k<96||k>111) && (k<186||k>192) && (k<219||k>222) && k!=229;
|
||
|
// synthesize keypress for most unprintables and CTRL-keys
|
||
|
if(unprintable||evt.ctrlKey){
|
||
|
var c = unprintable ? 0 : k;
|
||
|
if(evt.ctrlKey){
|
||
|
if(k==3 || k==13){
|
||
|
return listener.call(evt.currentTarget, evt); // IE will post CTRL-BREAK, CTRL-ENTER as keypress natively
|
||
|
}else if(c>95 && c<106){
|
||
|
c -= 48; // map CTRL-[numpad 0-9] to ASCII
|
||
|
}else if((!evt.shiftKey)&&(c>=65&&c<=90)){
|
||
|
c += 32; // map CTRL-[A-Z] to lowercase
|
||
|
}else{
|
||
|
c = _punctMap[c] || c; // map other problematic CTRL combinations to ASCII
|
||
|
}
|
||
|
}
|
||
|
// simulate a keypress event
|
||
|
var faux = _synthesizeEvent(evt, {type: 'keypress', faux: true, charCode: c});
|
||
|
listener.call(evt.currentTarget, faux);
|
||
|
if(has("ie")){
|
||
|
_trySetKeyCode(evt, faux.keyCode);
|
||
|
}
|
||
|
}
|
||
|
});
|
||
|
var keypressSignal = on(object, "keypress", function(evt){
|
||
|
var c = evt.charCode;
|
||
|
c = c>=32 ? c : 0;
|
||
|
evt = _synthesizeEvent(evt, {charCode: c, faux: true});
|
||
|
return listener.call(this, evt);
|
||
|
});
|
||
|
return {
|
||
|
remove: function(){
|
||
|
keydownSignal.remove();
|
||
|
keypressSignal.remove();
|
||
|
}
|
||
|
};
|
||
|
};
|
||
|
}else{
|
||
|
if(has("opera")){
|
||
|
keypress = function(object, listener){
|
||
|
return on(object, "keypress", function(evt){
|
||
|
var c = evt.which;
|
||
|
if(c==3){
|
||
|
c=99; // Mozilla maps CTRL-BREAK to CTRL-c
|
||
|
}
|
||
|
// can't trap some keys at all, like INSERT and DELETE
|
||
|
// there is no differentiating info between DELETE and ".", or INSERT and "-"
|
||
|
c = c<32 && !evt.shiftKey ? 0 : c;
|
||
|
if(evt.ctrlKey && !evt.shiftKey && c>=65 && c<=90){
|
||
|
// lowercase CTRL-[A-Z] keys
|
||
|
c += 32;
|
||
|
}
|
||
|
return listener.call(this, _synthesizeEvent(evt, { charCode: c }));
|
||
|
});
|
||
|
};
|
||
|
}else{
|
||
|
keypress = function(object, listener){
|
||
|
return on(object, "keypress", function(evt){
|
||
|
setKeyChar(evt);
|
||
|
return listener.call(this, evt);
|
||
|
});
|
||
|
};
|
||
|
}
|
||
|
}
|
||
|
|
||
|
var connect = {
|
||
|
// summary:
|
||
|
// This module defines the dojo.connect API.
|
||
|
// This modules also provides keyboard event handling helpers.
|
||
|
// This module exports an extension event for emulating Firefox's keypress handling.
|
||
|
// However, this extension event exists primarily for backwards compatibility and
|
||
|
// is not recommended. WebKit and IE uses an alternate keypress handling (only
|
||
|
// firing for printable characters, to distinguish from keydown events), and most
|
||
|
// consider the WebKit/IE behavior more desirable.
|
||
|
|
||
|
_keypress:keypress,
|
||
|
|
||
|
connect:function(obj, event, context, method, dontFix){
|
||
|
// summary:
|
||
|
// `dojo.connect` is a deprecated event handling and delegation method in
|
||
|
// Dojo. It allows one function to "listen in" on the execution of
|
||
|
// any other, triggering the second whenever the first is called. Many
|
||
|
// listeners may be attached to a function, and source functions may
|
||
|
// be either regular function calls or DOM events.
|
||
|
//
|
||
|
// description:
|
||
|
// Connects listeners to actions, so that after event fires, a
|
||
|
// listener is called with the same arguments passed to the original
|
||
|
// function.
|
||
|
//
|
||
|
// Since `dojo.connect` allows the source of events to be either a
|
||
|
// "regular" JavaScript function or a DOM event, it provides a uniform
|
||
|
// interface for listening to all the types of events that an
|
||
|
// application is likely to deal with though a single, unified
|
||
|
// interface. DOM programmers may want to think of it as
|
||
|
// "addEventListener for everything and anything".
|
||
|
//
|
||
|
// When setting up a connection, the `event` parameter must be a
|
||
|
// string that is the name of the method/event to be listened for. If
|
||
|
// `obj` is null, `kernel.global` is assumed, meaning that connections
|
||
|
// to global methods are supported but also that you may inadvertently
|
||
|
// connect to a global by passing an incorrect object name or invalid
|
||
|
// reference.
|
||
|
//
|
||
|
// `dojo.connect` generally is forgiving. If you pass the name of a
|
||
|
// function or method that does not yet exist on `obj`, connect will
|
||
|
// not fail, but will instead set up a stub method. Similarly, null
|
||
|
// arguments may simply be omitted such that fewer than 4 arguments
|
||
|
// may be required to set up a connection See the examples for details.
|
||
|
//
|
||
|
// The return value is a handle that is needed to
|
||
|
// remove this connection with `dojo.disconnect`.
|
||
|
//
|
||
|
// obj: Object?
|
||
|
// The source object for the event function.
|
||
|
// Defaults to `kernel.global` if null.
|
||
|
// If obj is a DOM node, the connection is delegated
|
||
|
// to the DOM event manager (unless dontFix is true).
|
||
|
//
|
||
|
// event: String
|
||
|
// String name of the event function in obj.
|
||
|
// I.e. identifies a property `obj[event]`.
|
||
|
//
|
||
|
// context: Object|null
|
||
|
// The object that method will receive as "this".
|
||
|
//
|
||
|
// If context is null and method is a function, then method
|
||
|
// inherits the context of event.
|
||
|
//
|
||
|
// If method is a string then context must be the source
|
||
|
// object object for method (context[method]). If context is null,
|
||
|
// kernel.global is used.
|
||
|
//
|
||
|
// method: String|Function
|
||
|
// A function reference, or name of a function in context.
|
||
|
// The function identified by method fires after event does.
|
||
|
// method receives the same arguments as the event.
|
||
|
// See context argument comments for information on method's scope.
|
||
|
//
|
||
|
// dontFix: Boolean?
|
||
|
// If obj is a DOM node, set dontFix to true to prevent delegation
|
||
|
// of this connection to the DOM event manager.
|
||
|
//
|
||
|
// example:
|
||
|
// When obj.onchange(), do ui.update():
|
||
|
// | dojo.connect(obj, "onchange", ui, "update");
|
||
|
// | dojo.connect(obj, "onchange", ui, ui.update); // same
|
||
|
//
|
||
|
// example:
|
||
|
// Using return value for disconnect:
|
||
|
// | var link = dojo.connect(obj, "onchange", ui, "update");
|
||
|
// | ...
|
||
|
// | dojo.disconnect(link);
|
||
|
//
|
||
|
// example:
|
||
|
// When onglobalevent executes, watcher.handler is invoked:
|
||
|
// | dojo.connect(null, "onglobalevent", watcher, "handler");
|
||
|
//
|
||
|
// example:
|
||
|
// When ob.onCustomEvent executes, customEventHandler is invoked:
|
||
|
// | dojo.connect(ob, "onCustomEvent", null, "customEventHandler");
|
||
|
// | dojo.connect(ob, "onCustomEvent", "customEventHandler"); // same
|
||
|
//
|
||
|
// example:
|
||
|
// When ob.onCustomEvent executes, customEventHandler is invoked
|
||
|
// with the same scope (this):
|
||
|
// | dojo.connect(ob, "onCustomEvent", null, customEventHandler);
|
||
|
// | dojo.connect(ob, "onCustomEvent", customEventHandler); // same
|
||
|
//
|
||
|
// example:
|
||
|
// When globalEvent executes, globalHandler is invoked
|
||
|
// with the same scope (this):
|
||
|
// | dojo.connect(null, "globalEvent", null, globalHandler);
|
||
|
// | dojo.connect("globalEvent", globalHandler); // same
|
||
|
|
||
|
// normalize arguments
|
||
|
var a=arguments, args=[], i=0;
|
||
|
// if a[0] is a String, obj was omitted
|
||
|
args.push(typeof a[0] == "string" ? null : a[i++], a[i++]);
|
||
|
// if the arg-after-next is a String or Function, context was NOT omitted
|
||
|
var a1 = a[i+1];
|
||
|
args.push(typeof a1 == "string" || typeof a1 == "function" ? a[i++] : null, a[i++]);
|
||
|
// absorb any additional arguments
|
||
|
for(var l=a.length; i<l; i++){ args.push(a[i]); }
|
||
|
return connect_.apply(this, args);
|
||
|
},
|
||
|
|
||
|
disconnect:function(handle){
|
||
|
// summary:
|
||
|
// Remove a link created by dojo.connect.
|
||
|
// description:
|
||
|
// Removes the connection between event and the method referenced by handle.
|
||
|
// handle: Handle
|
||
|
// the return value of the dojo.connect call that created the connection.
|
||
|
|
||
|
if(handle){
|
||
|
handle.remove();
|
||
|
}
|
||
|
},
|
||
|
|
||
|
subscribe:function(topic, context, method){
|
||
|
// summary:
|
||
|
// Attach a listener to a named topic. The listener function is invoked whenever the
|
||
|
// named topic is published (see: dojo.publish).
|
||
|
// Returns a handle which is needed to unsubscribe this listener.
|
||
|
// topic: String
|
||
|
// The topic to which to subscribe.
|
||
|
// context: Object?
|
||
|
// Scope in which method will be invoked, or null for default scope.
|
||
|
// method: String|Function
|
||
|
// The name of a function in context, or a function reference. This is the function that
|
||
|
// is invoked when topic is published.
|
||
|
// example:
|
||
|
// | dojo.subscribe("alerts", null, function(caption, message){ alert(caption + "\n" + message); });
|
||
|
// | dojo.publish("alerts", [ "read this", "hello world" ]);
|
||
|
return hub.subscribe(topic, lang.hitch(context, method));
|
||
|
},
|
||
|
|
||
|
publish:function(topic, args){
|
||
|
// summary:
|
||
|
// Invoke all listener method subscribed to topic.
|
||
|
// topic: String
|
||
|
// The name of the topic to publish.
|
||
|
// args: Array?
|
||
|
// An array of arguments. The arguments will be applied
|
||
|
// to each topic subscriber (as first class parameters, via apply).
|
||
|
// example:
|
||
|
// | dojo.subscribe("alerts", null, function(caption, message){ alert(caption + "\n" + message); };
|
||
|
// | dojo.publish("alerts", [ "read this", "hello world" ]);
|
||
|
return hub.publish.apply(hub, [topic].concat(args));
|
||
|
},
|
||
|
|
||
|
connectPublisher:function(topic, obj, event){
|
||
|
// summary:
|
||
|
// Ensure that every time obj.event() is called, a message is published
|
||
|
// on the topic. Returns a handle which can be passed to
|
||
|
// dojo.disconnect() to disable subsequent automatic publication on
|
||
|
// the topic.
|
||
|
// topic: String
|
||
|
// The name of the topic to publish.
|
||
|
// obj: Object?
|
||
|
// The source object for the event function. Defaults to kernel.global
|
||
|
// if null.
|
||
|
// event: String
|
||
|
// The name of the event function in obj.
|
||
|
// I.e. identifies a property obj[event].
|
||
|
// example:
|
||
|
// | dojo.connectPublisher("/ajax/start", dojo, "xhrGet");
|
||
|
var pf = function(){ connect.publish(topic, arguments); };
|
||
|
return event ? connect.connect(obj, event, pf) : connect.connect(obj, pf); //Handle
|
||
|
},
|
||
|
|
||
|
isCopyKey: function(e){
|
||
|
// summary:
|
||
|
// Checks an event for the copy key (meta on Mac, and ctrl anywhere else)
|
||
|
// e: Event
|
||
|
// Event object to examine
|
||
|
return e[evtCopyKey]; // Boolean
|
||
|
}
|
||
|
};
|
||
|
|
||
|
connect.unsubscribe = connect.disconnect;
|
||
|
/*=====
|
||
|
connect.unsubscribe = function(handle){
|
||
|
// summary:
|
||
|
// Remove a topic listener.
|
||
|
// handle: Handle
|
||
|
// The handle returned from a call to subscribe.
|
||
|
// example:
|
||
|
// | var alerter = dojo.subscribe("alerts", null, function(caption, message){ alert(caption + "\n" + message); };
|
||
|
// | ...
|
||
|
// | dojo.unsubscribe(alerter);
|
||
|
};
|
||
|
=====*/
|
||
|
|
||
|
1 && lang.mixin(dojo, connect);
|
||
|
return connect;
|
||
|
|
||
|
});
|
||
|
|
||
|
|
||
|
|
||
|
},
|
||
|
'dojo/topic':function(){
|
||
|
define(["./Evented"], function(Evented){
|
||
|
|
||
|
// module:
|
||
|
// dojo/topic
|
||
|
|
||
|
var hub = new Evented;
|
||
|
return {
|
||
|
// summary:
|
||
|
// Pubsub hub.
|
||
|
// example:
|
||
|
// | topic.subscribe("some/topic", function(event){
|
||
|
// | ... do something with event
|
||
|
// | });
|
||
|
// | topic.publish("some/topic", {name:"some event", ...});
|
||
|
|
||
|
publish: function(topic, event){
|
||
|
// summary:
|
||
|
// Publishes a message to a topic on the pub/sub hub. All arguments after
|
||
|
// the first will be passed to the subscribers, so any number of arguments
|
||
|
// can be provided (not just event).
|
||
|
// topic: String
|
||
|
// The name of the topic to publish to
|
||
|
// event: Object
|
||
|
// An event to distribute to the topic listeners
|
||
|
return hub.emit.apply(hub, arguments);
|
||
|
},
|
||
|
|
||
|
subscribe: function(topic, listener){
|
||
|
// summary:
|
||
|
// Subscribes to a topic on the pub/sub hub
|
||
|
// topic: String
|
||
|
// The topic to subscribe to
|
||
|
// listener: Function
|
||
|
// A function to call when a message is published to the given topic
|
||
|
return hub.on.apply(hub, arguments);
|
||
|
}
|
||
|
};
|
||
|
});
|
||
|
|
||
|
},
|
||
|
'dojo/_base/event':function(){
|
||
|
define(["./kernel", "../on", "../has", "../dom-geometry"], function(dojo, on, has, dom){
|
||
|
// module:
|
||
|
// dojo/_base/event
|
||
|
|
||
|
if(on._fixEvent){
|
||
|
var fixEvent = on._fixEvent;
|
||
|
on._fixEvent = function(evt, se){
|
||
|
// add some additional normalization for back-compat, this isn't in on.js because it is somewhat more expensive
|
||
|
evt = fixEvent(evt, se);
|
||
|
if(evt){
|
||
|
dom.normalizeEvent(evt);
|
||
|
}
|
||
|
return evt;
|
||
|
};
|
||
|
}
|
||
|
|
||
|
var ret = {
|
||
|
// summary:
|
||
|
// This module defines dojo DOM event API. Usually you should use dojo/on, and evt.stopPropagation() +
|
||
|
// evt.preventDefault(), rather than this module.
|
||
|
|
||
|
fix: function(/*Event*/ evt, /*DOMNode*/ sender){
|
||
|
// summary:
|
||
|
// normalizes properties on the event object including event
|
||
|
// bubbling methods, keystroke normalization, and x/y positions
|
||
|
// evt: Event
|
||
|
// native event object
|
||
|
// sender: DOMNode
|
||
|
// node to treat as "currentTarget"
|
||
|
if(on._fixEvent){
|
||
|
return on._fixEvent(evt, sender);
|
||
|
}
|
||
|
return evt; // Event
|
||
|
},
|
||
|
|
||
|
stop: function(/*Event*/ evt){
|
||
|
// summary:
|
||
|
// prevents propagation and clobbers the default action of the
|
||
|
// passed event
|
||
|
// evt: Event
|
||
|
// The event object. If omitted, window.event is used on IE.
|
||
|
if(has("dom-addeventlistener") || (evt && evt.preventDefault)){
|
||
|
evt.preventDefault();
|
||
|
evt.stopPropagation();
|
||
|
}else{
|
||
|
evt = evt || window.event;
|
||
|
evt.cancelBubble = true;
|
||
|
on._preventDefault.call(evt);
|
||
|
}
|
||
|
}
|
||
|
};
|
||
|
|
||
|
if( 1 ){
|
||
|
dojo.fixEvent = ret.fix;
|
||
|
dojo.stopEvent = ret.stop;
|
||
|
}
|
||
|
|
||
|
return ret;
|
||
|
});
|
||
|
|
||
|
},
|
||
|
'dojo/dom-geometry':function(){
|
||
|
define(["./sniff", "./_base/window","./dom", "./dom-style"],
|
||
|
function(has, win, dom, style){
|
||
|
// module:
|
||
|
// dojo/dom-geometry
|
||
|
|
||
|
// the result object
|
||
|
var geom = {
|
||
|
// summary:
|
||
|
// This module defines the core dojo DOM geometry API.
|
||
|
};
|
||
|
|
||
|
// Box functions will assume this model.
|
||
|
// On IE/Opera, BORDER_BOX will be set if the primary document is in quirks mode.
|
||
|
// Can be set to change behavior of box setters.
|
||
|
|
||
|
// can be either:
|
||
|
// "border-box"
|
||
|
// "content-box" (default)
|
||
|
geom.boxModel = "content-box";
|
||
|
|
||
|
// We punt per-node box mode testing completely.
|
||
|
// If anybody cares, we can provide an additional (optional) unit
|
||
|
// that overrides existing code to include per-node box sensitivity.
|
||
|
|
||
|
// Opera documentation claims that Opera 9 uses border-box in BackCompat mode.
|
||
|
// but experiments (Opera 9.10.8679 on Windows Vista) indicate that it actually continues to use content-box.
|
||
|
// IIRC, earlier versions of Opera did in fact use border-box.
|
||
|
// Opera guys, this is really confusing. Opera being broken in quirks mode is not our fault.
|
||
|
|
||
|
if(has("ie") /*|| has("opera")*/){
|
||
|
// client code may have to adjust if compatMode varies across iframes
|
||
|
geom.boxModel = document.compatMode == "BackCompat" ? "border-box" : "content-box";
|
||
|
}
|
||
|
|
||
|
geom.getPadExtents = function getPadExtents(/*DomNode*/ node, /*Object*/ computedStyle){
|
||
|
// summary:
|
||
|
// Returns object with special values specifically useful for node
|
||
|
// fitting.
|
||
|
// description:
|
||
|
// Returns an object with `w`, `h`, `l`, `t` properties:
|
||
|
// | l/t/r/b = left/top/right/bottom padding (respectively)
|
||
|
// | w = the total of the left and right padding
|
||
|
// | h = the total of the top and bottom padding
|
||
|
// If 'node' has position, l/t forms the origin for child nodes.
|
||
|
// The w/h are used for calculating boxes.
|
||
|
// Normally application code will not need to invoke this
|
||
|
// directly, and will use the ...box... functions instead.
|
||
|
// node: DOMNode
|
||
|
// computedStyle: Object?
|
||
|
// This parameter accepts computed styles object.
|
||
|
// If this parameter is omitted, the functions will call
|
||
|
// dojo/dom-style.getComputedStyle to get one. It is a better way, calling
|
||
|
// dojo/dom-style.getComputedStyle once, and then pass the reference to this
|
||
|
// computedStyle parameter. Wherever possible, reuse the returned
|
||
|
// object of dojo/dom-style.getComputedStyle().
|
||
|
|
||
|
node = dom.byId(node);
|
||
|
var s = computedStyle || style.getComputedStyle(node), px = style.toPixelValue,
|
||
|
l = px(node, s.paddingLeft), t = px(node, s.paddingTop), r = px(node, s.paddingRight), b = px(node, s.paddingBottom);
|
||
|
return {l: l, t: t, r: r, b: b, w: l + r, h: t + b};
|
||
|
};
|
||
|
|
||
|
var none = "none";
|
||
|
|
||
|
geom.getBorderExtents = function getBorderExtents(/*DomNode*/ node, /*Object*/ computedStyle){
|
||
|
// summary:
|
||
|
// returns an object with properties useful for noting the border
|
||
|
// dimensions.
|
||
|
// description:
|
||
|
// - l/t/r/b = the sum of left/top/right/bottom border (respectively)
|
||
|
// - w = the sum of the left and right border
|
||
|
// - h = the sum of the top and bottom border
|
||
|
//
|
||
|
// The w/h are used for calculating boxes.
|
||
|
// Normally application code will not need to invoke this
|
||
|
// directly, and will use the ...box... functions instead.
|
||
|
// node: DOMNode
|
||
|
// computedStyle: Object?
|
||
|
// This parameter accepts computed styles object.
|
||
|
// If this parameter is omitted, the functions will call
|
||
|
// dojo/dom-style.getComputedStyle to get one. It is a better way, calling
|
||
|
// dojo/dom-style.getComputedStyle once, and then pass the reference to this
|
||
|
// computedStyle parameter. Wherever possible, reuse the returned
|
||
|
// object of dojo/dom-style.getComputedStyle().
|
||
|
|
||
|
node = dom.byId(node);
|
||
|
var px = style.toPixelValue, s = computedStyle || style.getComputedStyle(node),
|
||
|
l = s.borderLeftStyle != none ? px(node, s.borderLeftWidth) : 0,
|
||
|
t = s.borderTopStyle != none ? px(node, s.borderTopWidth) : 0,
|
||
|
r = s.borderRightStyle != none ? px(node, s.borderRightWidth) : 0,
|
||
|
b = s.borderBottomStyle != none ? px(node, s.borderBottomWidth) : 0;
|
||
|
return {l: l, t: t, r: r, b: b, w: l + r, h: t + b};
|
||
|
};
|
||
|
|
||
|
geom.getPadBorderExtents = function getPadBorderExtents(/*DomNode*/ node, /*Object*/ computedStyle){
|
||
|
// summary:
|
||
|
// Returns object with properties useful for box fitting with
|
||
|
// regards to padding.
|
||
|
// description:
|
||
|
// - l/t/r/b = the sum of left/top/right/bottom padding and left/top/right/bottom border (respectively)
|
||
|
// - w = the sum of the left and right padding and border
|
||
|
// - h = the sum of the top and bottom padding and border
|
||
|
//
|
||
|
// The w/h are used for calculating boxes.
|
||
|
// Normally application code will not need to invoke this
|
||
|
// directly, and will use the ...box... functions instead.
|
||
|
// node: DOMNode
|
||
|
// computedStyle: Object?
|
||
|
// This parameter accepts computed styles object.
|
||
|
// If this parameter is omitted, the functions will call
|
||
|
// dojo/dom-style.getComputedStyle to get one. It is a better way, calling
|
||
|
// dojo/dom-style.getComputedStyle once, and then pass the reference to this
|
||
|
// computedStyle parameter. Wherever possible, reuse the returned
|
||
|
// object of dojo/dom-style.getComputedStyle().
|
||
|
|
||
|
node = dom.byId(node);
|
||
|
var s = computedStyle || style.getComputedStyle(node),
|
||
|
p = geom.getPadExtents(node, s),
|
||
|
b = geom.getBorderExtents(node, s);
|
||
|
return {
|
||
|
l: p.l + b.l,
|
||
|
t: p.t + b.t,
|
||
|
r: p.r + b.r,
|
||
|
b: p.b + b.b,
|
||
|
w: p.w + b.w,
|
||
|
h: p.h + b.h
|
||
|
};
|
||
|
};
|
||
|
|
||
|
geom.getMarginExtents = function getMarginExtents(node, computedStyle){
|
||
|
// summary:
|
||
|
// returns object with properties useful for box fitting with
|
||
|
// regards to box margins (i.e., the outer-box).
|
||
|
//
|
||
|
// - l/t = marginLeft, marginTop, respectively
|
||
|
// - w = total width, margin inclusive
|
||
|
// - h = total height, margin inclusive
|
||
|
//
|
||
|
// The w/h are used for calculating boxes.
|
||
|
// Normally application code will not need to invoke this
|
||
|
// directly, and will use the ...box... functions instead.
|
||
|
// node: DOMNode
|
||
|
// computedStyle: Object?
|
||
|
// This parameter accepts computed styles object.
|
||
|
// If this parameter is omitted, the functions will call
|
||
|
// dojo/dom-style.getComputedStyle to get one. It is a better way, calling
|
||
|
// dojo/dom-style.getComputedStyle once, and then pass the reference to this
|
||
|
// computedStyle parameter. Wherever possible, reuse the returned
|
||
|
// object of dojo/dom-style.getComputedStyle().
|
||
|
|
||
|
node = dom.byId(node);
|
||
|
var s = computedStyle || style.getComputedStyle(node), px = style.toPixelValue,
|
||
|
l = px(node, s.marginLeft), t = px(node, s.marginTop), r = px(node, s.marginRight), b = px(node, s.marginBottom);
|
||
|
return {l: l, t: t, r: r, b: b, w: l + r, h: t + b};
|
||
|
};
|
||
|
|
||
|
// Box getters work in any box context because offsetWidth/clientWidth
|
||
|
// are invariant wrt box context
|
||
|
//
|
||
|
// They do *not* work for display: inline objects that have padding styles
|
||
|
// because the user agent ignores padding (it's bogus styling in any case)
|
||
|
//
|
||
|
// Be careful with IMGs because they are inline or block depending on
|
||
|
// browser and browser mode.
|
||
|
|
||
|
// Although it would be easier to read, there are not separate versions of
|
||
|
// _getMarginBox for each browser because:
|
||
|
// 1. the branching is not expensive
|
||
|
// 2. factoring the shared code wastes cycles (function call overhead)
|
||
|
// 3. duplicating the shared code wastes bytes
|
||
|
|
||
|
geom.getMarginBox = function getMarginBox(/*DomNode*/ node, /*Object*/ computedStyle){
|
||
|
// summary:
|
||
|
// returns an object that encodes the width, height, left and top
|
||
|
// positions of the node's margin box.
|
||
|
// node: DOMNode
|
||
|
// computedStyle: Object?
|
||
|
// This parameter accepts computed styles object.
|
||
|
// If this parameter is omitted, the functions will call
|
||
|
// dojo/dom-style.getComputedStyle to get one. It is a better way, calling
|
||
|
// dojo/dom-style.getComputedStyle once, and then pass the reference to this
|
||
|
// computedStyle parameter. Wherever possible, reuse the returned
|
||
|
// object of dojo/dom-style.getComputedStyle().
|
||
|
|
||
|
node = dom.byId(node);
|
||
|
var s = computedStyle || style.getComputedStyle(node), me = geom.getMarginExtents(node, s),
|
||
|
l = node.offsetLeft - me.l, t = node.offsetTop - me.t, p = node.parentNode, px = style.toPixelValue, pcs;
|
||
|
|
||
|
if((has("ie") == 8 && !has("quirks"))){
|
||
|
// IE 8 offsetLeft/Top includes the parent's border
|
||
|
if(p){
|
||
|
pcs = style.getComputedStyle(p);
|
||
|
l -= pcs.borderLeftStyle != none ? px(node, pcs.borderLeftWidth) : 0;
|
||
|
t -= pcs.borderTopStyle != none ? px(node, pcs.borderTopWidth) : 0;
|
||
|
}
|
||
|
}
|
||
|
return {l: l, t: t, w: node.offsetWidth + me.w, h: node.offsetHeight + me.h};
|
||
|
};
|
||
|
|
||
|
geom.getContentBox = function getContentBox(node, computedStyle){
|
||
|
// summary:
|
||
|
// Returns an object that encodes the width, height, left and top
|
||
|
// positions of the node's content box, irrespective of the
|
||
|
// current box model.
|
||
|
// node: DOMNode
|
||
|
// computedStyle: Object?
|
||
|
// This parameter accepts computed styles object.
|
||
|
// If this parameter is omitted, the functions will call
|
||
|
// dojo/dom-style.getComputedStyle to get one. It is a better way, calling
|
||
|
// dojo/dom-style.getComputedStyle once, and then pass the reference to this
|
||
|
// computedStyle parameter. Wherever possible, reuse the returned
|
||
|
// object of dojo/dom-style.getComputedStyle().
|
||
|
|
||
|
// clientWidth/Height are important since the automatically account for scrollbars
|
||
|
// fallback to offsetWidth/Height for special cases (see #3378)
|
||
|
node = dom.byId(node);
|
||
|
var s = computedStyle || style.getComputedStyle(node), w = node.clientWidth, h,
|
||
|
pe = geom.getPadExtents(node, s), be = geom.getBorderExtents(node, s), l = node.offsetLeft + pe.l + be.l,
|
||
|
t = node.offsetTop + pe.t + be.t;
|
||
|
if(!w){
|
||
|
w = node.offsetWidth - be.w;
|
||
|
h = node.offsetHeight - be.h;
|
||
|
}else{
|
||
|
h = node.clientHeight;
|
||
|
}
|
||
|
|
||
|
if((has("ie") == 8 && !has("quirks"))){
|
||
|
// IE 8 offsetLeft/Top includes the parent's border
|
||
|
var p = node.parentNode, px = style.toPixelValue, pcs;
|
||
|
if(p){
|
||
|
pcs = style.getComputedStyle(p);
|
||
|
l -= pcs.borderLeftStyle != none ? px(node, pcs.borderLeftWidth) : 0;
|
||
|
t -= pcs.borderTopStyle != none ? px(node, pcs.borderTopWidth) : 0;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
return {l: l, t: t, w: w - pe.w, h: h - pe.h};
|
||
|
};
|
||
|
|
||
|
// Box setters depend on box context because interpretation of width/height styles
|
||
|
// vary wrt box context.
|
||
|
//
|
||
|
// The value of boxModel is used to determine box context.
|
||
|
// boxModel can be set directly to change behavior.
|
||
|
//
|
||
|
// Beware of display: inline objects that have padding styles
|
||
|
// because the user agent ignores padding (it's a bogus setup anyway)
|
||
|
//
|
||
|
// Be careful with IMGs because they are inline or block depending on
|
||
|
// browser and browser mode.
|
||
|
//
|
||
|
// Elements other than DIV may have special quirks, like built-in
|
||
|
// margins or padding, or values not detectable via computedStyle.
|
||
|
// In particular, margins on TABLE do not seems to appear
|
||
|
// at all in computedStyle on Mozilla.
|
||
|
|
||
|
function setBox(/*DomNode*/ node, /*Number?*/ l, /*Number?*/ t, /*Number?*/ w, /*Number?*/ h, /*String?*/ u){
|
||
|
// summary:
|
||
|
// sets width/height/left/top in the current (native) box-model
|
||
|
// dimensions. Uses the unit passed in u.
|
||
|
// node:
|
||
|
// DOM Node reference. Id string not supported for performance
|
||
|
// reasons.
|
||
|
// l:
|
||
|
// left offset from parent.
|
||
|
// t:
|
||
|
// top offset from parent.
|
||
|
// w:
|
||
|
// width in current box model.
|
||
|
// h:
|
||
|
// width in current box model.
|
||
|
// u:
|
||
|
// unit measure to use for other measures. Defaults to "px".
|
||
|
u = u || "px";
|
||
|
var s = node.style;
|
||
|
if(!isNaN(l)){
|
||
|
s.left = l + u;
|
||
|
}
|
||
|
if(!isNaN(t)){
|
||
|
s.top = t + u;
|
||
|
}
|
||
|
if(w >= 0){
|
||
|
s.width = w + u;
|
||
|
}
|
||
|
if(h >= 0){
|
||
|
s.height = h + u;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
function isButtonTag(/*DomNode*/ node){
|
||
|
// summary:
|
||
|
// True if the node is BUTTON or INPUT.type="button".
|
||
|
return node.tagName.toLowerCase() == "button" ||
|
||
|
node.tagName.toLowerCase() == "input" && (node.getAttribute("type") || "").toLowerCase() == "button"; // boolean
|
||
|
}
|
||
|
|
||
|
function usesBorderBox(/*DomNode*/ node){
|
||
|
// summary:
|
||
|
// True if the node uses border-box layout.
|
||
|
|
||
|
// We could test the computed style of node to see if a particular box
|
||
|
// has been specified, but there are details and we choose not to bother.
|
||
|
|
||
|
// TABLE and BUTTON (and INPUT type=button) are always border-box by default.
|
||
|
// If you have assigned a different box to either one via CSS then
|
||
|
// box functions will break.
|
||
|
|
||
|
return geom.boxModel == "border-box" || node.tagName.toLowerCase() == "table" || isButtonTag(node); // boolean
|
||
|
}
|
||
|
|
||
|
function getBoundingClientRect(/*DomNode*/ node) {
|
||
|
// summary:
|
||
|
// Gets the bounding client rectangle for a dom node.
|
||
|
// node: DOMNode
|
||
|
|
||
|
// This will return the result of node.getBoundingClientRect if node is in the dom, and
|
||
|
// {x:0, y:0, width:0, height:0, top:0, right:0, bottom:0, left:0} if it throws an error or the node is not on the dom
|
||
|
// This will handle when IE throws an error or Edge returns an empty object when node is not on the dom
|
||
|
|
||
|
var retEmpty = { x: 0, y: 0, width: 0, height: 0, top: 0, right: 0, bottom: 0, left: 0 },
|
||
|
ret;
|
||
|
|
||
|
try {
|
||
|
ret = node.getBoundingClientRect();
|
||
|
} catch (e) {
|
||
|
// IE throws an Unspecified Error if the node is not in the dom. Handle this by returning an object with 0 values
|
||
|
return retEmpty;
|
||
|
}
|
||
|
|
||
|
// Edge returns an empty object if the node is not in the dom. Handle this by returning an object with 0 values
|
||
|
if (typeof ret.left === "undefined") { return retEmpty; }
|
||
|
|
||
|
return ret;
|
||
|
}
|
||
|
|
||
|
geom.setContentSize = function setContentSize(/*DomNode*/ node, /*Object*/ box, /*Object*/ computedStyle){
|
||
|
// summary:
|
||
|
// Sets the size of the node's contents, irrespective of margins,
|
||
|
// padding, or borders.
|
||
|
// node: DOMNode
|
||
|
// box: Object
|
||
|
// hash with optional "w", and "h" properties for "width", and "height"
|
||
|
// respectively. All specified properties should have numeric values in whole pixels.
|
||
|
// computedStyle: Object?
|
||
|
// This parameter accepts computed styles object.
|
||
|
// If this parameter is omitted, the functions will call
|
||
|
// dojo/dom-style.getComputedStyle to get one. It is a better way, calling
|
||
|
// dojo/dom-style.getComputedStyle once, and then pass the reference to this
|
||
|
// computedStyle parameter. Wherever possible, reuse the returned
|
||
|
// object of dojo/dom-style.getComputedStyle().
|
||
|
|
||
|
node = dom.byId(node);
|
||
|
var w = box.w, h = box.h;
|
||
|
if(usesBorderBox(node)){
|
||
|
var pb = geom.getPadBorderExtents(node, computedStyle);
|
||
|
if(w >= 0){
|
||
|
w += pb.w;
|
||
|
}
|
||
|
if(h >= 0){
|
||
|
h += pb.h;
|
||
|
}
|
||
|
}
|
||
|
setBox(node, NaN, NaN, w, h);
|
||
|
};
|
||
|
|
||
|
var nilExtents = {l: 0, t: 0, w: 0, h: 0};
|
||
|
|
||
|
geom.setMarginBox = function setMarginBox(/*DomNode*/ node, /*Object*/ box, /*Object*/ computedStyle){
|
||
|
// summary:
|
||
|
// sets the size of the node's margin box and placement
|
||
|
// (left/top), irrespective of box model. Think of it as a
|
||
|
// passthrough to setBox that handles box-model vagaries for
|
||
|
// you.
|
||
|
// node: DOMNode
|
||
|
// box: Object
|
||
|
// hash with optional "l", "t", "w", and "h" properties for "left", "right", "width", and "height"
|
||
|
// respectively. All specified properties should have numeric values in whole pixels.
|
||
|
// computedStyle: Object?
|
||
|
// This parameter accepts computed styles object.
|
||
|
// If this parameter is omitted, the functions will call
|
||
|
// dojo/dom-style.getComputedStyle to get one. It is a better way, calling
|
||
|
// dojo/dom-style.getComputedStyle once, and then pass the reference to this
|
||
|
// computedStyle parameter. Wherever possible, reuse the returned
|
||
|
// object of dojo/dom-style.getComputedStyle().
|
||
|
|
||
|
node = dom.byId(node);
|
||
|
var s = computedStyle || style.getComputedStyle(node), w = box.w, h = box.h,
|
||
|
// Some elements have special padding, margin, and box-model settings.
|
||
|
// To use box functions you may need to set padding, margin explicitly.
|
||
|
// Controlling box-model is harder, in a pinch you might set dojo/dom-geometry.boxModel.
|
||
|
pb = usesBorderBox(node) ? nilExtents : geom.getPadBorderExtents(node, s),
|
||
|
mb = geom.getMarginExtents(node, s);
|
||
|
if(has("webkit")){
|
||
|
// on Safari (3.1.2), button nodes with no explicit size have a default margin
|
||
|
// setting an explicit size eliminates the margin.
|
||
|
// We have to swizzle the width to get correct margin reading.
|
||
|
if(isButtonTag(node)){
|
||
|
var ns = node.style;
|
||
|
if(w >= 0 && !ns.width){
|
||
|
ns.width = "4px";
|
||
|
}
|
||
|
if(h >= 0 && !ns.height){
|
||
|
ns.height = "4px";
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
if(w >= 0){
|
||
|
w = Math.max(w - pb.w - mb.w, 0);
|
||
|
}
|
||
|
if(h >= 0){
|
||
|
h = Math.max(h - pb.h - mb.h, 0);
|
||
|
}
|
||
|
setBox(node, box.l, box.t, w, h);
|
||
|
};
|
||
|
|
||
|
// =============================
|
||
|
// Positioning
|
||
|
// =============================
|
||
|
|
||
|
geom.isBodyLtr = function isBodyLtr(/*Document?*/ doc){
|
||
|
// summary:
|
||
|
// Returns true if the current language is left-to-right, and false otherwise.
|
||
|
// doc: Document?
|
||
|
// Optional document to query. If unspecified, use win.doc.
|
||
|
// returns: Boolean
|
||
|
|
||
|
doc = doc || win.doc;
|
||
|
return (win.body(doc).dir || doc.documentElement.dir || "ltr").toLowerCase() == "ltr"; // Boolean
|
||
|
};
|
||
|
|
||
|
geom.docScroll = function docScroll(/*Document?*/ doc){
|
||
|
// summary:
|
||
|
// Returns an object with {node, x, y} with corresponding offsets.
|
||
|
// doc: Document?
|
||
|
// Optional document to query. If unspecified, use win.doc.
|
||
|
// returns: Object
|
||
|
|
||
|
doc = doc || win.doc;
|
||
|
var node = doc.parentWindow || doc.defaultView; // use UI window, not dojo.global window. TODO: use dojo/window::get() except for circular dependency problem
|
||
|
return "pageXOffset" in node ? {x: node.pageXOffset, y: node.pageYOffset } :
|
||
|
(node = has("quirks") ? win.body(doc) : doc.documentElement) &&
|
||
|
{x: geom.fixIeBiDiScrollLeft(node.scrollLeft || 0, doc), y: node.scrollTop || 0 };
|
||
|
};
|
||
|
|
||
|
geom.getIeDocumentElementOffset = function(/*Document?*/ doc){
|
||
|
// summary:
|
||
|
// Deprecated method previously used for IE6-IE7. Now, just returns `{x:0, y:0}`.
|
||
|
return {
|
||
|
x: 0,
|
||
|
y: 0
|
||
|
};
|
||
|
};
|
||
|
|
||
|
geom.fixIeBiDiScrollLeft = function fixIeBiDiScrollLeft(/*Integer*/ scrollLeft, /*Document?*/ doc){
|
||
|
// summary:
|
||
|
// In RTL direction, scrollLeft should be a negative value, but IE
|
||
|
// returns a positive one. All codes using documentElement.scrollLeft
|
||
|
// must call this function to fix this error, otherwise the position
|
||
|
// will offset to right when there is a horizontal scrollbar.
|
||
|
// scrollLeft: Number
|
||
|
// doc: Document?
|
||
|
// Optional document to query. If unspecified, use win.doc.
|
||
|
// returns: Number
|
||
|
|
||
|
// In RTL direction, scrollLeft should be a negative value, but IE
|
||
|
// returns a positive one. All codes using documentElement.scrollLeft
|
||
|
// must call this function to fix this error, otherwise the position
|
||
|
// will offset to right when there is a horizontal scrollbar.
|
||
|
|
||
|
doc = doc || win.doc;
|
||
|
var ie = has("ie");
|
||
|
if(ie && !geom.isBodyLtr(doc)){
|
||
|
var qk = has("quirks"),
|
||
|
de = qk ? win.body(doc) : doc.documentElement,
|
||
|
pwin = win.global; // TODO: use winUtils.get(doc) after resolving circular dependency b/w dom-geometry.js and dojo/window.js
|
||
|
if(ie == 6 && !qk && pwin.frameElement && de.scrollHeight > de.clientHeight){
|
||
|
scrollLeft += de.clientLeft; // workaround ie6+strict+rtl+iframe+vertical-scrollbar bug where clientWidth is too small by clientLeft pixels
|
||
|
}
|
||
|
return (ie < 8 || qk) ? (scrollLeft + de.clientWidth - de.scrollWidth) : -scrollLeft; // Integer
|
||
|
}
|
||
|
return scrollLeft; // Integer
|
||
|
};
|
||
|
|
||
|
geom.position = function(/*DomNode*/ node, /*Boolean?*/ includeScroll){
|
||
|
// summary:
|
||
|
// Gets the position and size of the passed element relative to
|
||
|
// the viewport (if includeScroll==false), or relative to the
|
||
|
// document root (if includeScroll==true).
|
||
|
//
|
||
|
// description:
|
||
|
// Returns an object of the form:
|
||
|
// `{ x: 100, y: 300, w: 20, h: 15 }`.
|
||
|
// If includeScroll==true, the x and y values will include any
|
||
|
// document offsets that may affect the position relative to the
|
||
|
// viewport.
|
||
|
// Uses the border-box model (inclusive of border and padding but
|
||
|
// not margin). Does not act as a setter.
|
||
|
// node: DOMNode|String
|
||
|
// includeScroll: Boolean?
|
||
|
// returns: Object
|
||
|
|
||
|
node = dom.byId(node);
|
||
|
var db = win.body(node.ownerDocument),
|
||
|
ret= getBoundingClientRect(node);
|
||
|
ret = {x: ret.left, y: ret.top, w: ret.right - ret.left, h: ret.bottom - ret.top};
|
||
|
|
||
|
if(has("ie") < 9){
|
||
|
// fixes the position in IE, quirks mode
|
||
|
ret.x -= (has("quirks") ? db.clientLeft + db.offsetLeft : 0);
|
||
|
ret.y -= (has("quirks") ? db.clientTop + db.offsetTop : 0);
|
||
|
}
|
||
|
|
||
|
// account for document scrolling
|
||
|
// if offsetParent is used, ret value already includes scroll position
|
||
|
// so we may have to actually remove that value if !includeScroll
|
||
|
if(includeScroll){
|
||
|
var scroll = geom.docScroll(node.ownerDocument);
|
||
|
ret.x += scroll.x;
|
||
|
ret.y += scroll.y;
|
||
|
}
|
||
|
|
||
|
return ret; // Object
|
||
|
};
|
||
|
|
||
|
// random "private" functions wildly used throughout the toolkit
|
||
|
|
||
|
geom.getMarginSize = function getMarginSize(/*DomNode*/ node, /*Object*/ computedStyle){
|
||
|
// summary:
|
||
|
// returns an object that encodes the width and height of
|
||
|
// the node's margin box
|
||
|
// node: DOMNode|String
|
||
|
// computedStyle: Object?
|
||
|
// This parameter accepts computed styles object.
|
||
|
// If this parameter is omitted, the functions will call
|
||
|
// dojo/dom-style.getComputedStyle to get one. It is a better way, calling
|
||
|
// dojo/dom-style.getComputedStyle once, and then pass the reference to this
|
||
|
// computedStyle parameter. Wherever possible, reuse the returned
|
||
|
// object of dojo/dom-style.getComputedStyle().
|
||
|
|
||
|
node = dom.byId(node);
|
||
|
var me = geom.getMarginExtents(node, computedStyle || style.getComputedStyle(node));
|
||
|
var size = getBoundingClientRect(node);
|
||
|
return {
|
||
|
w: (size.right - size.left) + me.w,
|
||
|
h: (size.bottom - size.top) + me.h
|
||
|
};
|
||
|
};
|
||
|
|
||
|
geom.normalizeEvent = function(event){
|
||
|
// summary:
|
||
|
// Normalizes the geometry of a DOM event, normalizing the pageX, pageY,
|
||
|
// offsetX, offsetY, layerX, and layerX properties
|
||
|
// event: Object
|
||
|
if(!("layerX" in event)){
|
||
|
event.layerX = event.offsetX;
|
||
|
event.layerY = event.offsetY;
|
||
|
}
|
||
|
|
||
|
if(!("pageX" in event)){
|
||
|
// FIXME: scroll position query is duped from dojo/_base/html to
|
||
|
// avoid dependency on that entire module. Now that HTML is in
|
||
|
// Base, we should convert back to something similar there.
|
||
|
var se = event.target;
|
||
|
var doc = (se && se.ownerDocument) || document;
|
||
|
// DO NOT replace the following to use dojo/_base/window.body(), in IE, document.documentElement should be used
|
||
|
// here rather than document.body
|
||
|
var docBody = has("quirks") ? doc.body : doc.documentElement;
|
||
|
event.pageX = event.clientX + geom.fixIeBiDiScrollLeft(docBody.scrollLeft || 0, doc);
|
||
|
event.pageY = event.clientY + (docBody.scrollTop || 0);
|
||
|
}
|
||
|
};
|
||
|
|
||
|
// TODO: evaluate separate getters/setters for position and sizes?
|
||
|
|
||
|
return geom;
|
||
|
});
|
||
|
|
||
|
},
|
||
|
'dojo/dom-style':function(){
|
||
|
define(["./sniff", "./dom", "./_base/window"], function(has, dom, win){
|
||
|
// module:
|
||
|
// dojo/dom-style
|
||
|
|
||
|
// =============================
|
||
|
// Style Functions
|
||
|
// =============================
|
||
|
|
||
|
// getComputedStyle drives most of the style code.
|
||
|
// Wherever possible, reuse the returned object.
|
||
|
//
|
||
|
// API functions below that need to access computed styles accept an
|
||
|
// optional computedStyle parameter.
|
||
|
// If this parameter is omitted, the functions will call getComputedStyle themselves.
|
||
|
// This way, calling code can access computedStyle once, and then pass the reference to
|
||
|
// multiple API functions.
|
||
|
|
||
|
// Although we normally eschew argument validation at this
|
||
|
// level, here we test argument 'node' for (duck)type,
|
||
|
// by testing nodeType, ecause 'document' is the 'parentNode' of 'body'
|
||
|
// it is frequently sent to this function even
|
||
|
// though it is not Element.
|
||
|
var getComputedStyle, style = {
|
||
|
// summary:
|
||
|
// This module defines the core dojo DOM style API.
|
||
|
};
|
||
|
if(has("webkit")){
|
||
|
getComputedStyle = function(/*DomNode*/ node){
|
||
|
var s;
|
||
|
if(node.nodeType == 1){
|
||
|
var dv = node.ownerDocument.defaultView;
|
||
|
s = dv.getComputedStyle(node, null);
|
||
|
if(!s && node.style){
|
||
|
node.style.display = "";
|
||
|
s = dv.getComputedStyle(node, null);
|
||
|
}
|
||
|
}
|
||
|
return s || {};
|
||
|
};
|
||
|
}else if(has("ie") && (has("ie") < 9 || has("quirks"))){
|
||
|
getComputedStyle = function(node){
|
||
|
// IE (as of 7) doesn't expose Element like sane browsers
|
||
|
// currentStyle can be null on IE8!
|
||
|
return node.nodeType == 1 /* ELEMENT_NODE*/ && node.currentStyle ? node.currentStyle : {};
|
||
|
};
|
||
|
}else{
|
||
|
getComputedStyle = function(node){
|
||
|
if(node.nodeType === 1 /* ELEMENT_NODE*/){
|
||
|
var dv = node.ownerDocument.defaultView,
|
||
|
w = dv.opener ? dv : win.global.window;
|
||
|
return w.getComputedStyle(node, null);
|
||
|
}
|
||
|
return {};
|
||
|
};
|
||
|
}
|
||
|
style.getComputedStyle = getComputedStyle;
|
||
|
/*=====
|
||
|
style.getComputedStyle = function(node){
|
||
|
// summary:
|
||
|
// Returns a "computed style" object.
|
||
|
//
|
||
|
// description:
|
||
|
// Gets a "computed style" object which can be used to gather
|
||
|
// information about the current state of the rendered node.
|
||
|
//
|
||
|
// Note that this may behave differently on different browsers.
|
||
|
// Values may have different formats and value encodings across
|
||
|
// browsers.
|
||
|
//
|
||
|
// Note also that this method is expensive. Wherever possible,
|
||
|
// reuse the returned object.
|
||
|
//
|
||
|
// Use the dojo/dom-style.get() method for more consistent (pixelized)
|
||
|
// return values.
|
||
|
//
|
||
|
// node: DOMNode
|
||
|
// A reference to a DOM node. Does NOT support taking an
|
||
|
// ID string for speed reasons.
|
||
|
// example:
|
||
|
// | require(["dojo/dom-style", "dojo/dom"], function(domStyle, dom){
|
||
|
// | domStyle.getComputedStyle(dom.byId('foo')).borderWidth;
|
||
|
// | });
|
||
|
//
|
||
|
// example:
|
||
|
// Reusing the returned object, avoiding multiple lookups:
|
||
|
// | require(["dojo/dom-style", "dojo/dom"], function(domStyle, dom){
|
||
|
// | var cs = domStyle.getComputedStyle(dom.byId("someNode"));
|
||
|
// | var w = cs.width, h = cs.height;
|
||
|
// | });
|
||
|
return; // CSS2Properties
|
||
|
};
|
||
|
=====*/
|
||
|
|
||
|
var toPixel;
|
||
|
if(!has("ie")){
|
||
|
toPixel = function(element, value){
|
||
|
// style values can be floats, client code may want
|
||
|
// to round for integer pixels.
|
||
|
return parseFloat(value) || 0;
|
||
|
};
|
||
|
}else{
|
||
|
toPixel = function(element, avalue){
|
||
|
if(!avalue){ return 0; }
|
||
|
// on IE7, medium is usually 4 pixels
|
||
|
if(avalue == "medium"){ return 4; }
|
||
|
// style values can be floats, client code may
|
||
|
// want to round this value for integer pixels.
|
||
|
if(avalue.slice && avalue.slice(-2) == 'px'){ return parseFloat(avalue); }
|
||
|
var s = element.style, rs = element.runtimeStyle, cs = element.currentStyle,
|
||
|
sLeft = s.left, rsLeft = rs.left;
|
||
|
rs.left = cs.left;
|
||
|
try{
|
||
|
// 'avalue' may be incompatible with style.left, which can cause IE to throw
|
||
|
// this has been observed for border widths using "thin", "medium", "thick" constants
|
||
|
// those particular constants could be trapped by a lookup
|
||
|
// but perhaps there are more
|
||
|
s.left = avalue;
|
||
|
avalue = s.pixelLeft;
|
||
|
}catch(e){
|
||
|
avalue = 0;
|
||
|
}
|
||
|
s.left = sLeft;
|
||
|
rs.left = rsLeft;
|
||
|
return avalue;
|
||
|
};
|
||
|
}
|
||
|
style.toPixelValue = toPixel;
|
||
|
/*=====
|
||
|
style.toPixelValue = function(node, value){
|
||
|
// summary:
|
||
|
// converts style value to pixels on IE or return a numeric value.
|
||
|
// node: DOMNode
|
||
|
// value: String
|
||
|
// returns: Number
|
||
|
};
|
||
|
=====*/
|
||
|
|
||
|
// FIXME: there opacity quirks on FF that we haven't ported over. Hrm.
|
||
|
|
||
|
var astr = "DXImageTransform.Microsoft.Alpha";
|
||
|
var af = function(n, f){
|
||
|
try{
|
||
|
return n.filters.item(astr);
|
||
|
}catch(e){
|
||
|
return f ? {} : null;
|
||
|
}
|
||
|
};
|
||
|
|
||
|
var _getOpacity =
|
||
|
has("ie") < 9 || (has("ie") < 10 && has("quirks")) ? function(node){
|
||
|
try{
|
||
|
return af(node).Opacity / 100; // Number
|
||
|
}catch(e){
|
||
|
return 1; // Number
|
||
|
}
|
||
|
} :
|
||
|
function(node){
|
||
|
return getComputedStyle(node).opacity;
|
||
|
};
|
||
|
|
||
|
var _setOpacity =
|
||
|
has("ie") < 9 || (has("ie") < 10 && has("quirks")) ? function(/*DomNode*/ node, /*Number*/ opacity){
|
||
|
if(opacity === ""){ opacity = 1; }
|
||
|
var ov = opacity * 100, fullyOpaque = opacity === 1;
|
||
|
|
||
|
// on IE7 Alpha(Filter opacity=100) makes text look fuzzy so disable it altogether (bug #2661),
|
||
|
// but still update the opacity value so we can get a correct reading if it is read later:
|
||
|
// af(node, 1).Enabled = !fullyOpaque;
|
||
|
|
||
|
if(fullyOpaque){
|
||
|
node.style.zoom = "";
|
||
|
if(af(node)){
|
||
|
node.style.filter = node.style.filter.replace(
|
||
|
new RegExp("\\s*progid:" + astr + "\\([^\\)]+?\\)", "i"), "");
|
||
|
}
|
||
|
}else{
|
||
|
node.style.zoom = 1;
|
||
|
if(af(node)){
|
||
|
af(node, 1).Opacity = ov;
|
||
|
}else{
|
||
|
node.style.filter += " progid:" + astr + "(Opacity=" + ov + ")";
|
||
|
}
|
||
|
af(node, 1).Enabled = true;
|
||
|
}
|
||
|
|
||
|
if(node.tagName.toLowerCase() == "tr"){
|
||
|
for(var td = node.firstChild; td; td = td.nextSibling){
|
||
|
if(td.tagName.toLowerCase() == "td"){
|
||
|
_setOpacity(td, opacity);
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
return opacity;
|
||
|
} :
|
||
|
function(node, opacity){
|
||
|
return node.style.opacity = opacity;
|
||
|
};
|
||
|
|
||
|
var _pixelNamesCache = {
|
||
|
left: true, top: true
|
||
|
};
|
||
|
var _pixelRegExp = /margin|padding|width|height|max|min|offset/; // |border
|
||
|
function _toStyleValue(node, type, value){
|
||
|
//TODO: should we really be doing string case conversion here? Should we cache it? Need to profile!
|
||
|
type = type.toLowerCase();
|
||
|
|
||
|
// Adjustments for IE and Edge
|
||
|
if(value == "auto"){
|
||
|
if(type == "height"){ return node.offsetHeight; }
|
||
|
if(type == "width"){ return node.offsetWidth; }
|
||
|
}
|
||
|
if(type == "fontweight"){
|
||
|
switch(value){
|
||
|
case 700: return "bold";
|
||
|
case 400:
|
||
|
default: return "normal";
|
||
|
}
|
||
|
}
|
||
|
|
||
|
if(!(type in _pixelNamesCache)){
|
||
|
_pixelNamesCache[type] = _pixelRegExp.test(type);
|
||
|
}
|
||
|
return _pixelNamesCache[type] ? toPixel(node, value) : value;
|
||
|
}
|
||
|
|
||
|
var _floatAliases = {cssFloat: 1, styleFloat: 1, "float": 1};
|
||
|
|
||
|
// public API
|
||
|
|
||
|
style.get = function getStyle(/*DOMNode|String*/ node, /*String?*/ name){
|
||
|
// summary:
|
||
|
// Accesses styles on a node.
|
||
|
// description:
|
||
|
// Getting the style value uses the computed style for the node, so the value
|
||
|
// will be a calculated value, not just the immediate node.style value.
|
||
|
// Also when getting values, use specific style names,
|
||
|
// like "borderBottomWidth" instead of "border" since compound values like
|
||
|
// "border" are not necessarily reflected as expected.
|
||
|
// If you want to get node dimensions, use `dojo/dom-geometry.getMarginBox()`,
|
||
|
// `dojo/dom-geometry.getContentBox()` or `dojo/dom-geometry.getPosition()`.
|
||
|
// node: DOMNode|String
|
||
|
// id or reference to node to get style for
|
||
|
// name: String?
|
||
|
// the style property to get
|
||
|
// example:
|
||
|
// Passing only an ID or node returns the computed style object of
|
||
|
// the node:
|
||
|
// | require(["dojo/dom-style", "dojo/dom"], function(domStyle, dom){
|
||
|
// | domStyle.get("thinger");
|
||
|
// | });
|
||
|
// example:
|
||
|
// Passing a node and a style property returns the current
|
||
|
// normalized, computed value for that property:
|
||
|
// | require(["dojo/dom-style", "dojo/dom"], function(domStyle, dom){
|
||
|
// | domStyle.get("thinger", "opacity"); // 1 by default
|
||
|
// | });
|
||
|
|
||
|
var n = dom.byId(node), l = arguments.length, op = (name == "opacity");
|
||
|
if(l == 2 && op){
|
||
|
return _getOpacity(n);
|
||
|
}
|
||
|
name = _floatAliases[name] ? "cssFloat" in n.style ? "cssFloat" : "styleFloat" : name;
|
||
|
var s = style.getComputedStyle(n);
|
||
|
return (l == 1) ? s : _toStyleValue(n, name, s[name] || n.style[name]); /* CSS2Properties||String||Number */
|
||
|
};
|
||
|
|
||
|
style.set = function setStyle(/*DOMNode|String*/ node, /*String|Object*/ name, /*String?*/ value){
|
||
|
// summary:
|
||
|
// Sets styles on a node.
|
||
|
// node: DOMNode|String
|
||
|
// id or reference to node to set style for
|
||
|
// name: String|Object
|
||
|
// the style property to set in DOM-accessor format
|
||
|
// ("borderWidth", not "border-width") or an object with key/value
|
||
|
// pairs suitable for setting each property.
|
||
|
// value: String?
|
||
|
// If passed, sets value on the node for style, handling
|
||
|
// cross-browser concerns. When setting a pixel value,
|
||
|
// be sure to include "px" in the value. For instance, top: "200px".
|
||
|
// Otherwise, in some cases, some browsers will not apply the style.
|
||
|
//
|
||
|
// example:
|
||
|
// Passing a node, a style property, and a value changes the
|
||
|
// current display of the node and returns the new computed value
|
||
|
// | require(["dojo/dom-style"], function(domStyle){
|
||
|
// | domStyle.set("thinger", "opacity", 0.5); // == 0.5
|
||
|
// | });
|
||
|
//
|
||
|
// example:
|
||
|
// Passing a node, an object-style style property sets each of the values in turn and returns the computed style object of the node:
|
||
|
// | require(["dojo/dom-style"], function(domStyle){
|
||
|
// | domStyle.set("thinger", {
|
||
|
// | "opacity": 0.5,
|
||
|
// | "border": "3px solid black",
|
||
|
// | "height": "300px"
|
||
|
// | });
|
||
|
// | });
|
||
|
//
|
||
|
// example:
|
||
|
// When the CSS style property is hyphenated, the JavaScript property is camelCased.
|
||
|
// font-size becomes fontSize, and so on.
|
||
|
// | require(["dojo/dom-style", "dojo/dom"], function(domStyle, dom){
|
||
|
// | domStyle.set("thinger",{
|
||
|
// | fontSize:"14pt",
|
||
|
// | letterSpacing:"1.2em"
|
||
|
// | });
|
||
|
// | });
|
||
|
//
|
||
|
// example:
|
||
|
// dojo/NodeList implements .style() using the same syntax, omitting the "node" parameter, calling
|
||
|
// dojo/dom-style.get() on every element of the list. See: `dojo/query` and `dojo/NodeList`
|
||
|
// | require(["dojo/dom-style", "dojo/query", "dojo/NodeList-dom"],
|
||
|
// | function(domStyle, query){
|
||
|
// | query(".someClassName").style("visibility","hidden");
|
||
|
// | // or
|
||
|
// | query("#baz > div").style({
|
||
|
// | opacity:0.75,
|
||
|
// | fontSize:"13pt"
|
||
|
// | });
|
||
|
// | });
|
||
|
|
||
|
var n = dom.byId(node), l = arguments.length, op = (name == "opacity");
|
||
|
name = _floatAliases[name] ? "cssFloat" in n.style ? "cssFloat" : "styleFloat" : name;
|
||
|
if(l == 3){
|
||
|
return op ? _setOpacity(n, value) : n.style[name] = value; // Number
|
||
|
}
|
||
|
for(var x in name){
|
||
|
style.set(node, x, name[x]);
|
||
|
}
|
||
|
return style.getComputedStyle(n);
|
||
|
};
|
||
|
|
||
|
return style;
|
||
|
});
|
||
|
|
||
|
},
|
||
|
'dojo/mouse':function(){
|
||
|
define(["./_base/kernel", "./on", "./has", "./dom", "./_base/window"], function(dojo, on, has, dom, win){
|
||
|
|
||
|
// module:
|
||
|
// dojo/mouse
|
||
|
|
||
|
has.add("dom-quirks", win.doc && win.doc.compatMode == "BackCompat");
|
||
|
has.add("events-mouseenter", win.doc && "onmouseenter" in win.doc.createElement("div"));
|
||
|
has.add("events-mousewheel", win.doc && 'onmousewheel' in win.doc);
|
||
|
|
||
|
var mouseButtons;
|
||
|
if((has("dom-quirks") && has("ie")) || !has("dom-addeventlistener")){
|
||
|
mouseButtons = {
|
||
|
LEFT: 1,
|
||
|
MIDDLE: 4,
|
||
|
RIGHT: 2,
|
||
|
// helper functions
|
||
|
isButton: function(e, button){ return e.button & button; },
|
||
|
isLeft: function(e){ return e.button & 1; },
|
||
|
isMiddle: function(e){ return e.button & 4; },
|
||
|
isRight: function(e){ return e.button & 2; }
|
||
|
};
|
||
|
}else{
|
||
|
mouseButtons = {
|
||
|
LEFT: 0,
|
||
|
MIDDLE: 1,
|
||
|
RIGHT: 2,
|
||
|
// helper functions
|
||
|
isButton: function(e, button){ return e.button == button; },
|
||
|
isLeft: function(e){ return e.button == 0; },
|
||
|
isMiddle: function(e){ return e.button == 1; },
|
||
|
isRight: function(e){ return e.button == 2; }
|
||
|
};
|
||
|
}
|
||
|
dojo.mouseButtons = mouseButtons;
|
||
|
|
||
|
/*=====
|
||
|
dojo.mouseButtons = {
|
||
|
// LEFT: Number
|
||
|
// Numeric value of the left mouse button for the platform.
|
||
|
LEFT: 0,
|
||
|
// MIDDLE: Number
|
||
|
// Numeric value of the middle mouse button for the platform.
|
||
|
MIDDLE: 1,
|
||
|
// RIGHT: Number
|
||
|
// Numeric value of the right mouse button for the platform.
|
||
|
RIGHT: 2,
|
||
|
|
||
|
isButton: function(e, button){
|
||
|
// summary:
|
||
|
// Checks an event object for a pressed button
|
||
|
// e: Event
|
||
|
// Event object to examine
|
||
|
// button: Number
|
||
|
// The button value (example: dojo.mouseButton.LEFT)
|
||
|
return e.button == button; // Boolean
|
||
|
},
|
||
|
isLeft: function(e){
|
||
|
// summary:
|
||
|
// Checks an event object for the pressed left button
|
||
|
// e: Event
|
||
|
// Event object to examine
|
||
|
return e.button == 0; // Boolean
|
||
|
},
|
||
|
isMiddle: function(e){
|
||
|
// summary:
|
||
|
// Checks an event object for the pressed middle button
|
||
|
// e: Event
|
||
|
// Event object to examine
|
||
|
return e.button == 1; // Boolean
|
||
|
},
|
||
|
isRight: function(e){
|
||
|
// summary:
|
||
|
// Checks an event object for the pressed right button
|
||
|
// e: Event
|
||
|
// Event object to examine
|
||
|
return e.button == 2; // Boolean
|
||
|
}
|
||
|
};
|
||
|
=====*/
|
||
|
|
||
|
function eventHandler(type, selectHandler){
|
||
|
// emulation of mouseenter/leave with mouseover/out using descendant checking
|
||
|
var handler = function(node, listener){
|
||
|
return on(node, type, function(evt){
|
||
|
if(selectHandler){
|
||
|
return selectHandler(evt, listener);
|
||
|
}
|
||
|
if(!dom.isDescendant(evt.relatedTarget, node)){
|
||
|
return listener.call(this, evt);
|
||
|
}
|
||
|
});
|
||
|
};
|
||
|
handler.bubble = function(select){
|
||
|
return eventHandler(type, function(evt, listener){
|
||
|
// using a selector, use the select function to determine if the mouse moved inside the selector and was previously outside the selector
|
||
|
var target = select(evt.target);
|
||
|
var relatedTarget = evt.relatedTarget;
|
||
|
if(target && (target != (relatedTarget && relatedTarget.nodeType == 1 && select(relatedTarget)))){
|
||
|
return listener.call(target, evt);
|
||
|
}
|
||
|
});
|
||
|
};
|
||
|
return handler;
|
||
|
}
|
||
|
var wheel;
|
||
|
if(has("events-mousewheel")){
|
||
|
wheel = 'mousewheel';
|
||
|
}else{ //firefox
|
||
|
wheel = function(node, listener){
|
||
|
return on(node, 'DOMMouseScroll', function(evt){
|
||
|
evt.wheelDelta = -evt.detail;
|
||
|
listener.call(this, evt);
|
||
|
});
|
||
|
};
|
||
|
}
|
||
|
return {
|
||
|
// summary:
|
||
|
// This module provide mouse event handling utility functions and exports
|
||
|
// mouseenter and mouseleave event emulation.
|
||
|
// example:
|
||
|
// To use these events, you register a mouseenter like this:
|
||
|
// | define(["dojo/on", "dojo/mouse"], function(on, mouse){
|
||
|
// | on(targetNode, mouse.enter, function(event){
|
||
|
// | dojo.addClass(targetNode, "highlighted");
|
||
|
// | });
|
||
|
// | on(targetNode, mouse.leave, function(event){
|
||
|
// | dojo.removeClass(targetNode, "highlighted");
|
||
|
// | });
|
||
|
|
||
|
_eventHandler: eventHandler, // for dojo/touch
|
||
|
|
||
|
// enter: Synthetic Event
|
||
|
// This is an extension event for the mouseenter that IE provides, emulating the
|
||
|
// behavior on other browsers.
|
||
|
enter: eventHandler("mouseover"),
|
||
|
|
||
|
// leave: Synthetic Event
|
||
|
// This is an extension event for the mouseleave that IE provides, emulating the
|
||
|
// behavior on other browsers.
|
||
|
leave: eventHandler("mouseout"),
|
||
|
|
||
|
// wheel: Normalized Mouse Wheel Event
|
||
|
// This is an extension event for the mousewheel that non-Mozilla browsers provide,
|
||
|
// emulating the behavior on Mozilla based browsers.
|
||
|
wheel: wheel,
|
||
|
|
||
|
isLeft: mouseButtons.isLeft,
|
||
|
/*=====
|
||
|
isLeft: function(){
|
||
|
// summary:
|
||
|
// Test an event object (from a mousedown event) to see if the left button was pressed.
|
||
|
},
|
||
|
=====*/
|
||
|
|
||
|
isMiddle: mouseButtons.isMiddle,
|
||
|
/*=====
|
||
|
isMiddle: function(){
|
||
|
// summary:
|
||
|
// Test an event object (from a mousedown event) to see if the middle button was pressed.
|
||
|
},
|
||
|
=====*/
|
||
|
|
||
|
isRight: mouseButtons.isRight
|
||
|
/*=====
|
||
|
, isRight: function(){
|
||
|
// summary:
|
||
|
// Test an event object (from a mousedown event) to see if the right button was pressed.
|
||
|
}
|
||
|
=====*/
|
||
|
};
|
||
|
});
|
||
|
|
||
|
},
|
||
|
'dojo/keys':function(){
|
||
|
define(["./_base/kernel", "./sniff"], function(dojo, has){
|
||
|
|
||
|
// module:
|
||
|
// dojo/keys
|
||
|
|
||
|
return dojo.keys = {
|
||
|
// summary:
|
||
|
// Definitions for common key values. Client code should test keyCode against these named constants,
|
||
|
// as the actual codes can vary by browser.
|
||
|
|
||
|
BACKSPACE: 8,
|
||
|
TAB: 9,
|
||
|
CLEAR: 12,
|
||
|
ENTER: 13,
|
||
|
SHIFT: 16,
|
||
|
CTRL: 17,
|
||
|
ALT: 18,
|
||
|
META: has("webkit") ? 91 : 224, // the apple key on macs
|
||
|
PAUSE: 19,
|
||
|
CAPS_LOCK: 20,
|
||
|
ESCAPE: 27,
|
||
|
SPACE: 32,
|
||
|
PAGE_UP: 33,
|
||
|
PAGE_DOWN: 34,
|
||
|
END: 35,
|
||
|
HOME: 36,
|
||
|
LEFT_ARROW: 37,
|
||
|
UP_ARROW: 38,
|
||
|
RIGHT_ARROW: 39,
|
||
|
DOWN_ARROW: 40,
|
||
|
INSERT: 45,
|
||
|
DELETE: 46,
|
||
|
HELP: 47,
|
||
|
LEFT_WINDOW: 91,
|
||
|
RIGHT_WINDOW: 92,
|
||
|
SELECT: 93,
|
||
|
NUMPAD_0: 96,
|
||
|
NUMPAD_1: 97,
|
||
|
NUMPAD_2: 98,
|
||
|
NUMPAD_3: 99,
|
||
|
NUMPAD_4: 100,
|
||
|
NUMPAD_5: 101,
|
||
|
NUMPAD_6: 102,
|
||
|
NUMPAD_7: 103,
|
||
|
NUMPAD_8: 104,
|
||
|
NUMPAD_9: 105,
|
||
|
NUMPAD_MULTIPLY: 106,
|
||
|
NUMPAD_PLUS: 107,
|
||
|
NUMPAD_ENTER: 108,
|
||
|
NUMPAD_MINUS: 109,
|
||
|
NUMPAD_PERIOD: 110,
|
||
|
NUMPAD_DIVIDE: 111,
|
||
|
F1: 112,
|
||
|
F2: 113,
|
||
|
F3: 114,
|
||
|
F4: 115,
|
||
|
F5: 116,
|
||
|
F6: 117,
|
||
|
F7: 118,
|
||
|
F8: 119,
|
||
|
F9: 120,
|
||
|
F10: 121,
|
||
|
F11: 122,
|
||
|
F12: 123,
|
||
|
F13: 124,
|
||
|
F14: 125,
|
||
|
F15: 126,
|
||
|
NUM_LOCK: 144,
|
||
|
SCROLL_LOCK: 145,
|
||
|
UP_DPAD: 175,
|
||
|
DOWN_DPAD: 176,
|
||
|
LEFT_DPAD: 177,
|
||
|
RIGHT_DPAD: 178,
|
||
|
// virtual key mapping
|
||
|
copyKey: has("mac") && !has("air") ? (has("safari") ? 91 : 224 ) : 17
|
||
|
};
|
||
|
});
|
||
|
|
||
|
},
|
||
|
'dojo/_base/Color':function(){
|
||
|
define(["./kernel", "./lang", "./array", "./config"], function(dojo, lang, ArrayUtil, config){
|
||
|
|
||
|
var Color = dojo.Color = function(/*Array|String|Object*/ color){
|
||
|
// summary:
|
||
|
// Takes a named string, hex string, array of rgb or rgba values,
|
||
|
// an object with r, g, b, and a properties, or another `Color` object
|
||
|
// and creates a new Color instance to work from.
|
||
|
//
|
||
|
// example:
|
||
|
// Work with a Color instance:
|
||
|
// | require(["dojo/_base/color"], function(Color){
|
||
|
// | var c = new Color();
|
||
|
// | c.setColor([0,0,0]); // black
|
||
|
// | var hex = c.toHex(); // #000000
|
||
|
// | });
|
||
|
//
|
||
|
// example:
|
||
|
// Work with a node's color:
|
||
|
// |
|
||
|
// | require(["dojo/_base/color", "dojo/dom-style"], function(Color, domStyle){
|
||
|
// | var color = domStyle("someNode", "backgroundColor");
|
||
|
// | var n = new Color(color);
|
||
|
// | // adjust the color some
|
||
|
// | n.r *= .5;
|
||
|
// | console.log(n.toString()); // rgb(128, 255, 255);
|
||
|
// | });
|
||
|
if(color){ this.setColor(color); }
|
||
|
};
|
||
|
|
||
|
// FIXME:
|
||
|
// there's got to be a more space-efficient way to encode or discover
|
||
|
// these!! Use hex?
|
||
|
Color.named = {
|
||
|
// summary:
|
||
|
// Dictionary list of all CSS named colors, by name. Values are 3-item arrays with corresponding RG and B values.
|
||
|
"black": [0,0,0],
|
||
|
"silver": [192,192,192],
|
||
|
"gray": [128,128,128],
|
||
|
"white": [255,255,255],
|
||
|
"maroon": [128,0,0],
|
||
|
"red": [255,0,0],
|
||
|
"purple": [128,0,128],
|
||
|
"fuchsia":[255,0,255],
|
||
|
"green": [0,128,0],
|
||
|
"lime": [0,255,0],
|
||
|
"olive": [128,128,0],
|
||
|
"yellow": [255,255,0],
|
||
|
"navy": [0,0,128],
|
||
|
"blue": [0,0,255],
|
||
|
"teal": [0,128,128],
|
||
|
"aqua": [0,255,255],
|
||
|
"transparent": config.transparentColor || [0,0,0,0]
|
||
|
};
|
||
|
|
||
|
lang.extend(Color, {
|
||
|
r: 255, g: 255, b: 255, a: 1,
|
||
|
_set: function(r, g, b, a){
|
||
|
var t = this; t.r = r; t.g = g; t.b = b; t.a = a;
|
||
|
},
|
||
|
setColor: function(/*Array|String|Object*/ color){
|
||
|
// summary:
|
||
|
// Takes a named string, hex string, array of rgb or rgba values,
|
||
|
// an object with r, g, b, and a properties, or another `Color` object
|
||
|
// and sets this color instance to that value.
|
||
|
//
|
||
|
// example:
|
||
|
// | require(["dojo/_base/color"], function(Color){
|
||
|
// | var c = new Color(); // no color
|
||
|
// | c.setColor("#ededed"); // greyish
|
||
|
// | });
|
||
|
if(lang.isString(color)){
|
||
|
Color.fromString(color, this);
|
||
|
}else if(lang.isArray(color)){
|
||
|
Color.fromArray(color, this);
|
||
|
}else{
|
||
|
this._set(color.r, color.g, color.b, color.a);
|
||
|
if(!(color instanceof Color)){ this.sanitize(); }
|
||
|
}
|
||
|
return this; // Color
|
||
|
},
|
||
|
sanitize: function(){
|
||
|
// summary:
|
||
|
// Ensures the object has correct attributes
|
||
|
// description:
|
||
|
// the default implementation does nothing, include dojo.colors to
|
||
|
// augment it with real checks
|
||
|
return this; // Color
|
||
|
},
|
||
|
toRgb: function(){
|
||
|
// summary:
|
||
|
// Returns 3 component array of rgb values
|
||
|
// example:
|
||
|
// | require(["dojo/_base/color"], function(Color){
|
||
|
// | var c = new Color("#000000");
|
||
|
// | console.log(c.toRgb()); // [0,0,0]
|
||
|
// | });
|
||
|
var t = this;
|
||
|
return [t.r, t.g, t.b]; // Array
|
||
|
},
|
||
|
toRgba: function(){
|
||
|
// summary:
|
||
|
// Returns a 4 component array of rgba values from the color
|
||
|
// represented by this object.
|
||
|
var t = this;
|
||
|
return [t.r, t.g, t.b, t.a]; // Array
|
||
|
},
|
||
|
toHex: function(){
|
||
|
// summary:
|
||
|
// Returns a CSS color string in hexadecimal representation
|
||
|
// example:
|
||
|
// | require(["dojo/_base/color"], function(Color){
|
||
|
// | console.log(new Color([0,0,0]).toHex()); // #000000
|
||
|
// | });
|
||
|
var arr = ArrayUtil.map(["r", "g", "b"], function(x){
|
||
|
var s = this[x].toString(16);
|
||
|
return s.length < 2 ? "0" + s : s;
|
||
|
}, this);
|
||
|
return "#" + arr.join(""); // String
|
||
|
},
|
||
|
toCss: function(/*Boolean?*/ includeAlpha){
|
||
|
// summary:
|
||
|
// Returns a css color string in rgb(a) representation
|
||
|
// example:
|
||
|
// | require(["dojo/_base/color"], function(Color){
|
||
|
// | var c = new Color("#FFF").toCss();
|
||
|
// | console.log(c); // rgb('255','255','255')
|
||
|
// | });
|
||
|
var t = this, rgb = t.r + ", " + t.g + ", " + t.b;
|
||
|
return (includeAlpha ? "rgba(" + rgb + ", " + t.a : "rgb(" + rgb) + ")"; // String
|
||
|
},
|
||
|
toString: function(){
|
||
|
// summary:
|
||
|
// Returns a visual representation of the color
|
||
|
return this.toCss(true); // String
|
||
|
}
|
||
|
});
|
||
|
|
||
|
Color.blendColors = dojo.blendColors = function(
|
||
|
/*Color*/ start,
|
||
|
/*Color*/ end,
|
||
|
/*Number*/ weight,
|
||
|
/*Color?*/ obj
|
||
|
){
|
||
|
// summary:
|
||
|
// Blend colors end and start with weight from 0 to 1, 0.5 being a 50/50 blend,
|
||
|
// can reuse a previously allocated Color object for the result
|
||
|
var t = obj || new Color();
|
||
|
t.r = Math.round(start.r + (end.r - start.r) * weight);
|
||
|
t.g = Math.round(start.g + (end.g - start.g) * weight);
|
||
|
t.b = Math.round(start.b + (end.b - start.b) * weight);
|
||
|
t.a = start.a + (end.a - start.a) * weight;
|
||
|
return t.sanitize(); // Color
|
||
|
};
|
||
|
|
||
|
Color.fromRgb = dojo.colorFromRgb = function(/*String*/ color, /*Color?*/ obj){
|
||
|
// summary:
|
||
|
// Returns a `Color` instance from a string of the form
|
||
|
// "rgb(...)" or "rgba(...)". Optionally accepts a `Color`
|
||
|
// object to update with the parsed value and return instead of
|
||
|
// creating a new object.
|
||
|
// returns:
|
||
|
// A Color object. If obj is passed, it will be the return value.
|
||
|
var m = color.toLowerCase().match(/^rgba?\(([\s\.,0-9]+)\)/);
|
||
|
return m && Color.fromArray(m[1].split(/\s*,\s*/), obj); // Color
|
||
|
};
|
||
|
|
||
|
Color.fromHex = dojo.colorFromHex = function(/*String*/ color, /*Color?*/ obj){
|
||
|
// summary:
|
||
|
// Converts a hex string with a '#' prefix to a color object.
|
||
|
// Supports 12-bit #rgb shorthand. Optionally accepts a
|
||
|
// `Color` object to update with the parsed value.
|
||
|
//
|
||
|
// returns:
|
||
|
// A Color object. If obj is passed, it will be the return value.
|
||
|
//
|
||
|
// example:
|
||
|
// | require(["dojo/_base/color"], function(Color){
|
||
|
// | var thing = new Color().fromHex("#ededed"); // grey, longhand
|
||
|
// | var thing2 = new Color().fromHex("#000"); // black, shorthand
|
||
|
// | });
|
||
|
var t = obj || new Color(),
|
||
|
bits = (color.length == 4) ? 4 : 8,
|
||
|
mask = (1 << bits) - 1;
|
||
|
color = Number("0x" + color.substr(1));
|
||
|
if(isNaN(color)){
|
||
|
return null; // Color
|
||
|
}
|
||
|
ArrayUtil.forEach(["b", "g", "r"], function(x){
|
||
|
var c = color & mask;
|
||
|
color >>= bits;
|
||
|
t[x] = bits == 4 ? 17 * c : c;
|
||
|
});
|
||
|
t.a = 1;
|
||
|
return t; // Color
|
||
|
};
|
||
|
|
||
|
Color.fromArray = dojo.colorFromArray = function(/*Array*/ a, /*Color?*/ obj){
|
||
|
// summary:
|
||
|
// Builds a `Color` from a 3 or 4 element array, mapping each
|
||
|
// element in sequence to the rgb(a) values of the color.
|
||
|
// example:
|
||
|
// | require(["dojo/_base/color"], function(Color){
|
||
|
// | var myColor = new Color().fromArray([237,237,237,0.5]); // grey, 50% alpha
|
||
|
// | });
|
||
|
// returns:
|
||
|
// A Color object. If obj is passed, it will be the return value.
|
||
|
var t = obj || new Color();
|
||
|
t._set(Number(a[0]), Number(a[1]), Number(a[2]), Number(a[3]));
|
||
|
if(isNaN(t.a)){ t.a = 1; }
|
||
|
return t.sanitize(); // Color
|
||
|
};
|
||
|
|
||
|
Color.fromString = dojo.colorFromString = function(/*String*/ str, /*Color?*/ obj){
|
||
|
// summary:
|
||
|
// Parses `str` for a color value. Accepts hex, rgb, and rgba
|
||
|
// style color values.
|
||
|
// description:
|
||
|
// Acceptable input values for str may include arrays of any form
|
||
|
// accepted by dojo.colorFromArray, hex strings such as "#aaaaaa", or
|
||
|
// rgb or rgba strings such as "rgb(133, 200, 16)" or "rgba(10, 10,
|
||
|
// 10, 50)"
|
||
|
// returns:
|
||
|
// A Color object. If obj is passed, it will be the return value.
|
||
|
var a = Color.named[str];
|
||
|
return a && Color.fromArray(a, obj) || Color.fromRgb(str, obj) || Color.fromHex(str, obj); // Color
|
||
|
};
|
||
|
|
||
|
return Color;
|
||
|
});
|
||
|
|
||
|
},
|
||
|
'dojo/_base/browser':function(){
|
||
|
if(require.has){
|
||
|
require.has.add("config-selectorEngine", "acme");
|
||
|
}
|
||
|
define([
|
||
|
"../ready",
|
||
|
"./kernel",
|
||
|
"./connect", // until we decide if connect is going back into non-browser environments
|
||
|
"./unload",
|
||
|
"./window",
|
||
|
"./event",
|
||
|
"./html",
|
||
|
"./NodeList",
|
||
|
"../query",
|
||
|
"./xhr",
|
||
|
"./fx"], function(dojo){
|
||
|
|
||
|
// module:
|
||
|
// dojo/_base/browser
|
||
|
|
||
|
/*=====
|
||
|
return {
|
||
|
// summary:
|
||
|
// This module causes the browser-only base modules to be loaded.
|
||
|
};
|
||
|
=====*/
|
||
|
|
||
|
return dojo;
|
||
|
});
|
||
|
|
||
|
},
|
||
|
'dojo/_base/unload':function(){
|
||
|
define(["./kernel", "./lang", "../on"], function(dojo, lang, on){
|
||
|
|
||
|
// module:
|
||
|
// dojo/unload
|
||
|
|
||
|
var win = window;
|
||
|
|
||
|
var unload = {
|
||
|
// summary:
|
||
|
// This module contains the document and window unload detection API.
|
||
|
// This module is deprecated. Use on(window, "unload", func)
|
||
|
// and on(window, "beforeunload", func) instead.
|
||
|
|
||
|
addOnWindowUnload: function(/*Object|Function?*/ obj, /*String|Function?*/ functionName){
|
||
|
// summary:
|
||
|
// Registers a function to be triggered when window.onunload fires.
|
||
|
// Deprecated, use on(window, "unload", lang.hitch(obj, functionName)) instead.
|
||
|
// description:
|
||
|
// The first time that addOnWindowUnload is called Dojo
|
||
|
// will register a page listener to trigger your unload
|
||
|
// handler with. Note that registering these handlers may
|
||
|
// destroy "fastback" page caching in browsers that support
|
||
|
// it. Be careful trying to modify the DOM or access
|
||
|
// JavaScript properties during this phase of page unloading:
|
||
|
// they may not always be available. Consider
|
||
|
// addOnUnload() if you need to modify the DOM or do
|
||
|
// heavy JavaScript work since it fires at the equivalent of
|
||
|
// the page's "onbeforeunload" event.
|
||
|
// example:
|
||
|
// | var afunc = function() {console.log("global function");};
|
||
|
// | require(["dojo/_base/unload"], function(unload) {
|
||
|
// | var foo = {bar: function(){ console.log("bar unloading...");},
|
||
|
// | data: "mydata"};
|
||
|
// | unload.addOnWindowUnload(afunc);
|
||
|
// | unload.addOnWindowUnload(foo, "bar");
|
||
|
// | unload.addOnWindowUnload(foo, function(){console.log("", this.data);});
|
||
|
// | });
|
||
|
|
||
|
if (!dojo.windowUnloaded){
|
||
|
on(win, "unload", (dojo.windowUnloaded = function(){
|
||
|
// summary:
|
||
|
// signal fired by impending window destruction. You may use
|
||
|
// dojo.addOnWindowUnload() to register a listener for this
|
||
|
// event. NOTE: if you wish to dojo.connect() to this method
|
||
|
// to perform page/application cleanup, be aware that this
|
||
|
// event WILL NOT fire if no handler has been registered with
|
||
|
// addOnWindowUnload(). This behavior started in Dojo 1.3.
|
||
|
// Previous versions always triggered windowUnloaded(). See
|
||
|
// addOnWindowUnload for more info.
|
||
|
}));
|
||
|
}
|
||
|
on(win, "unload", lang.hitch(obj, functionName));
|
||
|
},
|
||
|
|
||
|
addOnUnload: function(/*Object?|Function?*/ obj, /*String|Function?*/ functionName){
|
||
|
// summary:
|
||
|
// Registers a function to be triggered when the page unloads.
|
||
|
// Deprecated, use on(window, "beforeunload", lang.hitch(obj, functionName)) instead.
|
||
|
// description:
|
||
|
// The first time that addOnUnload is called Dojo will
|
||
|
// register a page listener to trigger your unload handler
|
||
|
// with.
|
||
|
//
|
||
|
// In a browser environment, the functions will be triggered
|
||
|
// during the window.onbeforeunload event. Be careful of doing
|
||
|
// too much work in an unload handler. onbeforeunload can be
|
||
|
// triggered if a link to download a file is clicked, or if
|
||
|
// the link is a javascript: link. In these cases, the
|
||
|
// onbeforeunload event fires, but the document is not
|
||
|
// actually destroyed. So be careful about doing destructive
|
||
|
// operations in a dojo.addOnUnload callback.
|
||
|
//
|
||
|
// Further note that calling dojo.addOnUnload will prevent
|
||
|
// browsers from using a "fast back" cache to make page
|
||
|
// loading via back button instantaneous.
|
||
|
// example:
|
||
|
// | var afunc = function() {console.log("global function");};
|
||
|
// | require(["dojo/_base/unload"], function(unload) {
|
||
|
// | var foo = {bar: function(){ console.log("bar unloading...");},
|
||
|
// | data: "mydata"};
|
||
|
// | unload.addOnUnload(afunc);
|
||
|
// | unload.addOnUnload(foo, "bar");
|
||
|
// | unload.addOnUnload(foo, function(){console.log("", this.data);});
|
||
|
// | });
|
||
|
|
||
|
on(win, "beforeunload", lang.hitch(obj, functionName));
|
||
|
}
|
||
|
};
|
||
|
|
||
|
dojo.addOnWindowUnload = unload.addOnWindowUnload;
|
||
|
dojo.addOnUnload = unload.addOnUnload;
|
||
|
|
||
|
return unload;
|
||
|
|
||
|
});
|
||
|
|
||
|
},
|
||
|
'dojo/_base/html':function(){
|
||
|
define(["./kernel", "../dom", "../dom-style", "../dom-attr", "../dom-prop", "../dom-class", "../dom-construct", "../dom-geometry"], function(dojo, dom, style, attr, prop, cls, ctr, geom){
|
||
|
// module:
|
||
|
// dojo/dom
|
||
|
|
||
|
/*=====
|
||
|
return {
|
||
|
// summary:
|
||
|
// This module is a stub for the core dojo DOM API.
|
||
|
};
|
||
|
=====*/
|
||
|
|
||
|
// mix-in dom
|
||
|
dojo.byId = dom.byId;
|
||
|
dojo.isDescendant = dom.isDescendant;
|
||
|
dojo.setSelectable = dom.setSelectable;
|
||
|
|
||
|
// mix-in dom-attr
|
||
|
dojo.getAttr = attr.get;
|
||
|
dojo.setAttr = attr.set;
|
||
|
dojo.hasAttr = attr.has;
|
||
|
dojo.removeAttr = attr.remove;
|
||
|
dojo.getNodeProp = attr.getNodeProp;
|
||
|
|
||
|
dojo.attr = function(node, name, value){
|
||
|
// summary:
|
||
|
// Gets or sets an attribute on an HTML element.
|
||
|
// description:
|
||
|
// Handles normalized getting and setting of attributes on DOM
|
||
|
// Nodes. If 2 arguments are passed, and a the second argument is a
|
||
|
// string, acts as a getter.
|
||
|
//
|
||
|
// If a third argument is passed, or if the second argument is a
|
||
|
// map of attributes, acts as a setter.
|
||
|
//
|
||
|
// When passing functions as values, note that they will not be
|
||
|
// directly assigned to slots on the node, but rather the default
|
||
|
// behavior will be removed and the new behavior will be added
|
||
|
// using `dojo.connect()`, meaning that event handler properties
|
||
|
// will be normalized and that some caveats with regards to
|
||
|
// non-standard behaviors for onsubmit apply. Namely that you
|
||
|
// should cancel form submission using `dojo.stopEvent()` on the
|
||
|
// passed event object instead of returning a boolean value from
|
||
|
// the handler itself.
|
||
|
// node: DOMNode|String
|
||
|
// id or reference to the element to get or set the attribute on
|
||
|
// name: String|Object
|
||
|
// the name of the attribute to get or set.
|
||
|
// value: String?
|
||
|
// The value to set for the attribute
|
||
|
// returns:
|
||
|
// when used as a getter, the value of the requested attribute
|
||
|
// or null if that attribute does not have a specified or
|
||
|
// default value;
|
||
|
//
|
||
|
// when used as a setter, the DOM node
|
||
|
//
|
||
|
// example:
|
||
|
// | // get the current value of the "foo" attribute on a node
|
||
|
// | dojo.attr(dojo.byId("nodeId"), "foo");
|
||
|
// | // or we can just pass the id:
|
||
|
// | dojo.attr("nodeId", "foo");
|
||
|
//
|
||
|
// example:
|
||
|
// | // use attr() to set the tab index
|
||
|
// | dojo.attr("nodeId", "tabIndex", 3);
|
||
|
// |
|
||
|
//
|
||
|
// example:
|
||
|
// Set multiple values at once, including event handlers:
|
||
|
// | dojo.attr("formId", {
|
||
|
// | "foo": "bar",
|
||
|
// | "tabIndex": -1,
|
||
|
// | "method": "POST",
|
||
|
// | "onsubmit": function(e){
|
||
|
// | // stop submitting the form. Note that the IE behavior
|
||
|
// | // of returning true or false will have no effect here
|
||
|
// | // since our handler is connect()ed to the built-in
|
||
|
// | // onsubmit behavior and so we need to use
|
||
|
// | // dojo.stopEvent() to ensure that the submission
|
||
|
// | // doesn't proceed.
|
||
|
// | dojo.stopEvent(e);
|
||
|
// |
|
||
|
// | // submit the form with Ajax
|
||
|
// | dojo.xhrPost({ form: "formId" });
|
||
|
// | }
|
||
|
// | });
|
||
|
//
|
||
|
// example:
|
||
|
// Style is s special case: Only set with an object hash of styles
|
||
|
// | dojo.attr("someNode",{
|
||
|
// | id:"bar",
|
||
|
// | style:{
|
||
|
// | width:"200px", height:"100px", color:"#000"
|
||
|
// | }
|
||
|
// | });
|
||
|
//
|
||
|
// example:
|
||
|
// Again, only set style as an object hash of styles:
|
||
|
// | var obj = { color:"#fff", backgroundColor:"#000" };
|
||
|
// | dojo.attr("someNode", "style", obj);
|
||
|
// |
|
||
|
// | // though shorter to use `dojo.style()` in this case:
|
||
|
// | dojo.style("someNode", obj);
|
||
|
|
||
|
if(arguments.length == 2){
|
||
|
return attr[typeof name == "string" ? "get" : "set"](node, name);
|
||
|
}
|
||
|
return attr.set(node, name, value);
|
||
|
};
|
||
|
|
||
|
// mix-in dom-class
|
||
|
dojo.hasClass = cls.contains;
|
||
|
dojo.addClass = cls.add;
|
||
|
dojo.removeClass = cls.remove;
|
||
|
dojo.toggleClass = cls.toggle;
|
||
|
dojo.replaceClass = cls.replace;
|
||
|
|
||
|
// mix-in dom-construct
|
||
|
dojo._toDom = dojo.toDom = ctr.toDom;
|
||
|
dojo.place = ctr.place;
|
||
|
dojo.create = ctr.create;
|
||
|
dojo.empty = function(node){ ctr.empty(node); };
|
||
|
dojo._destroyElement = dojo.destroy = function(node){ ctr.destroy(node); };
|
||
|
|
||
|
// mix-in dom-geometry
|
||
|
dojo._getPadExtents = dojo.getPadExtents = geom.getPadExtents;
|
||
|
dojo._getBorderExtents = dojo.getBorderExtents = geom.getBorderExtents;
|
||
|
dojo._getPadBorderExtents = dojo.getPadBorderExtents = geom.getPadBorderExtents;
|
||
|
dojo._getMarginExtents = dojo.getMarginExtents = geom.getMarginExtents;
|
||
|
dojo._getMarginSize = dojo.getMarginSize = geom.getMarginSize;
|
||
|
dojo._getMarginBox = dojo.getMarginBox = geom.getMarginBox;
|
||
|
dojo.setMarginBox = geom.setMarginBox;
|
||
|
dojo._getContentBox = dojo.getContentBox = geom.getContentBox;
|
||
|
dojo.setContentSize = geom.setContentSize;
|
||
|
dojo._isBodyLtr = dojo.isBodyLtr = geom.isBodyLtr;
|
||
|
dojo._docScroll = dojo.docScroll = geom.docScroll;
|
||
|
dojo._getIeDocumentElementOffset = dojo.getIeDocumentElementOffset = geom.getIeDocumentElementOffset;
|
||
|
dojo._fixIeBiDiScrollLeft = dojo.fixIeBiDiScrollLeft = geom.fixIeBiDiScrollLeft;
|
||
|
dojo.position = geom.position;
|
||
|
|
||
|
dojo.marginBox = function marginBox(/*DomNode|String*/node, /*Object?*/box){
|
||
|
// summary:
|
||
|
// Getter/setter for the margin-box of node.
|
||
|
// description:
|
||
|
// Getter/setter for the margin-box of node.
|
||
|
// Returns an object in the expected format of box (regardless
|
||
|
// if box is passed). The object might look like:
|
||
|
// `{ l: 50, t: 200, w: 300: h: 150 }`
|
||
|
// for a node offset from its parent 50px to the left, 200px from
|
||
|
// the top with a margin width of 300px and a margin-height of
|
||
|
// 150px.
|
||
|
// node:
|
||
|
// id or reference to DOM Node to get/set box for
|
||
|
// box:
|
||
|
// If passed, denotes that dojo.marginBox() should
|
||
|
// update/set the margin box for node. Box is an object in the
|
||
|
// above format. All properties are optional if passed.
|
||
|
// example:
|
||
|
// Retrieve the margin box of a passed node
|
||
|
// | var box = dojo.marginBox("someNodeId");
|
||
|
// | console.dir(box);
|
||
|
//
|
||
|
// example:
|
||
|
// Set a node's margin box to the size of another node
|
||
|
// | var box = dojo.marginBox("someNodeId");
|
||
|
// | dojo.marginBox("someOtherNode", box);
|
||
|
return box ? geom.setMarginBox(node, box) : geom.getMarginBox(node); // Object
|
||
|
};
|
||
|
|
||
|
dojo.contentBox = function contentBox(/*DomNode|String*/node, /*Object?*/box){
|
||
|
// summary:
|
||
|
// Getter/setter for the content-box of node.
|
||
|
// description:
|
||
|
// Returns an object in the expected format of box (regardless if box is passed).
|
||
|
// The object might look like:
|
||
|
// `{ l: 50, t: 200, w: 300: h: 150 }`
|
||
|
// for a node offset from its parent 50px to the left, 200px from
|
||
|
// the top with a content width of 300px and a content-height of
|
||
|
// 150px. Note that the content box may have a much larger border
|
||
|
// or margin box, depending on the box model currently in use and
|
||
|
// CSS values set/inherited for node.
|
||
|
// While the getter will return top and left values, the
|
||
|
// setter only accepts setting the width and height.
|
||
|
// node:
|
||
|
// id or reference to DOM Node to get/set box for
|
||
|
// box:
|
||
|
// If passed, denotes that dojo.contentBox() should
|
||
|
// update/set the content box for node. Box is an object in the
|
||
|
// above format, but only w (width) and h (height) are supported.
|
||
|
// All properties are optional if passed.
|
||
|
return box ? geom.setContentSize(node, box) : geom.getContentBox(node); // Object
|
||
|
};
|
||
|
|
||
|
dojo.coords = function(/*DomNode|String*/node, /*Boolean?*/includeScroll){
|
||
|
// summary:
|
||
|
// Deprecated: Use position() for border-box x/y/w/h
|
||
|
// or marginBox() for margin-box w/h/l/t.
|
||
|
//
|
||
|
// Returns an object that measures margin-box (w)idth/(h)eight
|
||
|
// and absolute position x/y of the border-box. Also returned
|
||
|
// is computed (l)eft and (t)op values in pixels from the
|
||
|
// node's offsetParent as returned from marginBox().
|
||
|
// Return value will be in the form:
|
||
|
//| { l: 50, t: 200, w: 300: h: 150, x: 100, y: 300 }
|
||
|
// Does not act as a setter. If includeScroll is passed, the x and
|
||
|
// y params are affected as one would expect in dojo.position().
|
||
|
dojo.deprecated("dojo.coords()", "Use dojo.position() or dojo.marginBox().");
|
||
|
node = dom.byId(node);
|
||
|
var s = style.getComputedStyle(node), mb = geom.getMarginBox(node, s);
|
||
|
var abs = geom.position(node, includeScroll);
|
||
|
mb.x = abs.x;
|
||
|
mb.y = abs.y;
|
||
|
return mb; // Object
|
||
|
};
|
||
|
|
||
|
// mix-in dom-prop
|
||
|
dojo.getProp = prop.get;
|
||
|
dojo.setProp = prop.set;
|
||
|
|
||
|
dojo.prop = function(/*DomNode|String*/node, /*String|Object*/name, /*String?*/value){
|
||
|
// summary:
|
||
|
// Gets or sets a property on an HTML element.
|
||
|
// description:
|
||
|
// Handles normalized getting and setting of properties on DOM
|
||
|
// Nodes. If 2 arguments are passed, and a the second argument is a
|
||
|
// string, acts as a getter.
|
||
|
//
|
||
|
// If a third argument is passed, or if the second argument is a
|
||
|
// map of attributes, acts as a setter.
|
||
|
//
|
||
|
// When passing functions as values, note that they will not be
|
||
|
// directly assigned to slots on the node, but rather the default
|
||
|
// behavior will be removed and the new behavior will be added
|
||
|
// using `dojo.connect()`, meaning that event handler properties
|
||
|
// will be normalized and that some caveats with regards to
|
||
|
// non-standard behaviors for onsubmit apply. Namely that you
|
||
|
// should cancel form submission using `dojo.stopEvent()` on the
|
||
|
// passed event object instead of returning a boolean value from
|
||
|
// the handler itself.
|
||
|
// node:
|
||
|
// id or reference to the element to get or set the property on
|
||
|
// name:
|
||
|
// the name of the property to get or set.
|
||
|
// value:
|
||
|
// The value to set for the property
|
||
|
// returns:
|
||
|
// when used as a getter, the value of the requested property
|
||
|
// or null if that attribute does not have a specified or
|
||
|
// default value;
|
||
|
//
|
||
|
// when used as a setter, the DOM node
|
||
|
//
|
||
|
// example:
|
||
|
// | // get the current value of the "foo" property on a node
|
||
|
// | dojo.prop(dojo.byId("nodeId"), "foo");
|
||
|
// | // or we can just pass the id:
|
||
|
// | dojo.prop("nodeId", "foo");
|
||
|
//
|
||
|
// example:
|
||
|
// | // use prop() to set the tab index
|
||
|
// | dojo.prop("nodeId", "tabIndex", 3);
|
||
|
// |
|
||
|
//
|
||
|
// example:
|
||
|
// Set multiple values at once, including event handlers:
|
||
|
// | dojo.prop("formId", {
|
||
|
// | "foo": "bar",
|
||
|
// | "tabIndex": -1,
|
||
|
// | "method": "POST",
|
||
|
// | "onsubmit": function(e){
|
||
|
// | // stop submitting the form. Note that the IE behavior
|
||
|
// | // of returning true or false will have no effect here
|
||
|
// | // since our handler is connect()ed to the built-in
|
||
|
// | // onsubmit behavior and so we need to use
|
||
|
// | // dojo.stopEvent() to ensure that the submission
|
||
|
// | // doesn't proceed.
|
||
|
// | dojo.stopEvent(e);
|
||
|
// |
|
||
|
// | // submit the form with Ajax
|
||
|
// | dojo.xhrPost({ form: "formId" });
|
||
|
// | }
|
||
|
// | });
|
||
|
//
|
||
|
// example:
|
||
|
// Style is s special case: Only set with an object hash of styles
|
||
|
// | dojo.prop("someNode",{
|
||
|
// | id:"bar",
|
||
|
// | style:{
|
||
|
// | width:"200px", height:"100px", color:"#000"
|
||
|
// | }
|
||
|
// | });
|
||
|
//
|
||
|
// example:
|
||
|
// Again, only set style as an object hash of styles:
|
||
|
// | var obj = { color:"#fff", backgroundColor:"#000" };
|
||
|
// | dojo.prop("someNode", "style", obj);
|
||
|
// |
|
||
|
// | // though shorter to use `dojo.style()` in this case:
|
||
|
// | dojo.style("someNode", obj);
|
||
|
|
||
|
if(arguments.length == 2){
|
||
|
return prop[typeof name == "string" ? "get" : "set"](node, name);
|
||
|
}
|
||
|
// setter
|
||
|
return prop.set(node, name, value);
|
||
|
};
|
||
|
|
||
|
// mix-in dom-style
|
||
|
dojo.getStyle = style.get;
|
||
|
dojo.setStyle = style.set;
|
||
|
dojo.getComputedStyle = style.getComputedStyle;
|
||
|
dojo.__toPixelValue = dojo.toPixelValue = style.toPixelValue;
|
||
|
|
||
|
dojo.style = function(node, name, value){
|
||
|
// summary:
|
||
|
// Accesses styles on a node. If 2 arguments are
|
||
|
// passed, acts as a getter. If 3 arguments are passed, acts
|
||
|
// as a setter.
|
||
|
// description:
|
||
|
// Getting the style value uses the computed style for the node, so the value
|
||
|
// will be a calculated value, not just the immediate node.style value.
|
||
|
// Also when getting values, use specific style names,
|
||
|
// like "borderBottomWidth" instead of "border" since compound values like
|
||
|
// "border" are not necessarily reflected as expected.
|
||
|
// If you want to get node dimensions, use `dojo.marginBox()`,
|
||
|
// `dojo.contentBox()` or `dojo.position()`.
|
||
|
// node: DOMNode|String
|
||
|
// id or reference to node to get/set style for
|
||
|
// name: String|Object?
|
||
|
// the style property to set in DOM-accessor format
|
||
|
// ("borderWidth", not "border-width") or an object with key/value
|
||
|
// pairs suitable for setting each property.
|
||
|
// value: String?
|
||
|
// If passed, sets value on the node for style, handling
|
||
|
// cross-browser concerns. When setting a pixel value,
|
||
|
// be sure to include "px" in the value. For instance, top: "200px".
|
||
|
// Otherwise, in some cases, some browsers will not apply the style.
|
||
|
// returns:
|
||
|
// when used as a getter, return the computed style of the node if passing in an ID or node,
|
||
|
// or return the normalized, computed value for the property when passing in a node and a style property
|
||
|
// example:
|
||
|
// Passing only an ID or node returns the computed style object of
|
||
|
// the node:
|
||
|
// | dojo.style("thinger");
|
||
|
// example:
|
||
|
// Passing a node and a style property returns the current
|
||
|
// normalized, computed value for that property:
|
||
|
// | dojo.style("thinger", "opacity"); // 1 by default
|
||
|
//
|
||
|
// example:
|
||
|
// Passing a node, a style property, and a value changes the
|
||
|
// current display of the node and returns the new computed value
|
||
|
// | dojo.style("thinger", "opacity", 0.5); // == 0.5
|
||
|
//
|
||
|
// example:
|
||
|
// Passing a node, an object-style style property sets each of the values in turn and returns the computed style object of the node:
|
||
|
// | dojo.style("thinger", {
|
||
|
// | "opacity": 0.5,
|
||
|
// | "border": "3px solid black",
|
||
|
// | "height": "300px"
|
||
|
// | });
|
||
|
//
|
||
|
// example:
|
||
|
// When the CSS style property is hyphenated, the JavaScript property is camelCased.
|
||
|
// font-size becomes fontSize, and so on.
|
||
|
// | dojo.style("thinger",{
|
||
|
// | fontSize:"14pt",
|
||
|
// | letterSpacing:"1.2em"
|
||
|
// | });
|
||
|
//
|
||
|
// example:
|
||
|
// dojo/NodeList implements .style() using the same syntax, omitting the "node" parameter, calling
|
||
|
// dojo.style() on every element of the list. See: `dojo/query` and `dojo/NodeList`
|
||
|
// | dojo.query(".someClassName").style("visibility","hidden");
|
||
|
// | // or
|
||
|
// | dojo.query("#baz > div").style({
|
||
|
// | opacity:0.75,
|
||
|
// | fontSize:"13pt"
|
||
|
// | });
|
||
|
|
||
|
switch(arguments.length){
|
||
|
case 1:
|
||
|
return style.get(node);
|
||
|
case 2:
|
||
|
return style[typeof name == "string" ? "get" : "set"](node, name);
|
||
|
}
|
||
|
// setter
|
||
|
return style.set(node, name, value);
|
||
|
};
|
||
|
|
||
|
return dojo;
|
||
|
});
|
||
|
|
||
|
},
|
||
|
'dojo/dom-attr':function(){
|
||
|
define(["exports", "./sniff", "./_base/lang", "./dom", "./dom-style", "./dom-prop"],
|
||
|
function(exports, has, lang, dom, style, prop){
|
||
|
// module:
|
||
|
// dojo/dom-attr
|
||
|
// summary:
|
||
|
// This module defines the core dojo DOM attributes API.
|
||
|
|
||
|
// TODOC: summary not showing up in output see https://github.com/csnover/js-doc-parse/issues/42
|
||
|
|
||
|
// =============================
|
||
|
// Element attribute Functions
|
||
|
// =============================
|
||
|
|
||
|
// This module will be obsolete soon. Use dojo/prop instead.
|
||
|
|
||
|
// dojo/dom-attr.get() should conform to http://www.w3.org/TR/DOM-Level-2-Core/
|
||
|
|
||
|
// attribute-related functions (to be obsolete soon)
|
||
|
var forcePropNames = {
|
||
|
innerHTML: 1,
|
||
|
textContent:1,
|
||
|
className: 1,
|
||
|
htmlFor: has("ie") ? 1 : 0,
|
||
|
value: 1
|
||
|
},
|
||
|
attrNames = {
|
||
|
// original attribute names
|
||
|
classname: "class",
|
||
|
htmlfor: "for",
|
||
|
// for IE
|
||
|
tabindex: "tabIndex",
|
||
|
readonly: "readOnly"
|
||
|
};
|
||
|
|
||
|
function _hasAttr(node, name){
|
||
|
var attr = node.getAttributeNode && node.getAttributeNode(name);
|
||
|
return !!attr && attr.specified; // Boolean
|
||
|
}
|
||
|
|
||
|
// There is a difference in the presence of certain properties and their default values
|
||
|
// between browsers. For example, on IE "disabled" is present on all elements,
|
||
|
// but it is value is "false"; "tabIndex" of <div> returns 0 by default on IE, yet other browsers
|
||
|
// can return -1.
|
||
|
|
||
|
exports.has = function hasAttr(/*DOMNode|String*/ node, /*String*/ name){
|
||
|
// summary:
|
||
|
// Returns true if the requested attribute is specified on the
|
||
|
// given element, and false otherwise.
|
||
|
// node: DOMNode|String
|
||
|
// id or reference to the element to check
|
||
|
// name: String
|
||
|
// the name of the attribute
|
||
|
// returns: Boolean
|
||
|
// true if the requested attribute is specified on the
|
||
|
// given element, and false otherwise
|
||
|
|
||
|
var lc = name.toLowerCase();
|
||
|
return !!forcePropNames[prop.names[lc] || name] || _hasAttr(dom.byId(node), attrNames[lc] || name); // Boolean
|
||
|
};
|
||
|
|
||
|
exports.get = function getAttr(/*DOMNode|String*/ node, /*String*/ name){
|
||
|
// summary:
|
||
|
// Gets an attribute on an HTML element.
|
||
|
// description:
|
||
|
// Handles normalized getting of attributes on DOM Nodes.
|
||
|
// node: DOMNode|String
|
||
|
// id or reference to the element to get the attribute on
|
||
|
// name: String
|
||
|
// the name of the attribute to get.
|
||
|
// returns:
|
||
|
// the value of the requested attribute or null if that attribute does not have a specified or
|
||
|
// default value;
|
||
|
//
|
||
|
// example:
|
||
|
// | // get the current value of the "foo" attribute on a node
|
||
|
// | require(["dojo/dom-attr", "dojo/dom"], function(domAttr, dom){
|
||
|
// | domAttr.get(dom.byId("nodeId"), "foo");
|
||
|
// | // or we can just pass the id:
|
||
|
// | domAttr.get("nodeId", "foo");
|
||
|
// | });
|
||
|
// |
|
||
|
|
||
|
node = dom.byId(node);
|
||
|
var lc = name.toLowerCase(),
|
||
|
propName = prop.names[lc] || name,
|
||
|
forceProp = forcePropNames[propName],
|
||
|
value = node[propName]; // should we access this attribute via a property or via getAttribute()?
|
||
|
|
||
|
if(forceProp && typeof value != "undefined"){
|
||
|
// node's property
|
||
|
return value; // Anything
|
||
|
}
|
||
|
|
||
|
if(propName == "textContent"){
|
||
|
return prop.get(node, propName);
|
||
|
}
|
||
|
|
||
|
if(propName != "href" && (typeof value == "boolean" || lang.isFunction(value))){
|
||
|
// node's property
|
||
|
return value; // Anything
|
||
|
}
|
||
|
// node's attribute
|
||
|
// we need _hasAttr() here to guard against IE returning a default value
|
||
|
var attrName = attrNames[lc] || name;
|
||
|
return _hasAttr(node, attrName) ? node.getAttribute(attrName) : null; // Anything
|
||
|
};
|
||
|
|
||
|
exports.set = function setAttr(/*DOMNode|String*/ node, /*String|Object*/ name, /*String?*/ value){
|
||
|
// summary:
|
||
|
// Sets an attribute on an HTML element.
|
||
|
// description:
|
||
|
// Handles normalized setting of attributes on DOM Nodes.
|
||
|
//
|
||
|
// When passing functions as values, note that they will not be
|
||
|
// directly assigned to slots on the node, but rather the default
|
||
|
// behavior will be removed and the new behavior will be added
|
||
|
// using `dojo.connect()`, meaning that event handler properties
|
||
|
// will be normalized and that some caveats with regards to
|
||
|
// non-standard behaviors for onsubmit apply. Namely that you
|
||
|
// should cancel form submission using `dojo.stopEvent()` on the
|
||
|
// passed event object instead of returning a boolean value from
|
||
|
// the handler itself.
|
||
|
// node: DOMNode|String
|
||
|
// id or reference to the element to set the attribute on
|
||
|
// name: String|Object
|
||
|
// the name of the attribute to set, or a hash of key-value pairs to set.
|
||
|
// value: String?
|
||
|
// the value to set for the attribute, if the name is a string.
|
||
|
// returns:
|
||
|
// the DOM node
|
||
|
//
|
||
|
// example:
|
||
|
// | // use attr() to set the tab index
|
||
|
// | require(["dojo/dom-attr"], function(domAttr){
|
||
|
// | domAttr.set("nodeId", "tabIndex", 3);
|
||
|
// | });
|
||
|
//
|
||
|
// example:
|
||
|
// Set multiple values at once, including event handlers:
|
||
|
// | require(["dojo/dom-attr"],
|
||
|
// | function(domAttr){
|
||
|
// | domAttr.set("formId", {
|
||
|
// | "foo": "bar",
|
||
|
// | "tabIndex": -1,
|
||
|
// | "method": "POST"
|
||
|
// | }
|
||
|
// | });
|
||
|
|
||
|
node = dom.byId(node);
|
||
|
if(arguments.length == 2){ // inline'd type check
|
||
|
// the object form of setter: the 2nd argument is a dictionary
|
||
|
for(var x in name){
|
||
|
exports.set(node, x, name[x]);
|
||
|
}
|
||
|
return node; // DomNode
|
||
|
}
|
||
|
var lc = name.toLowerCase(),
|
||
|
propName = prop.names[lc] || name,
|
||
|
forceProp = forcePropNames[propName];
|
||
|
if(propName == "style" && typeof value != "string"){ // inline'd type check
|
||
|
// special case: setting a style
|
||
|
style.set(node, value);
|
||
|
return node; // DomNode
|
||
|
}
|
||
|
if(forceProp || typeof value == "boolean" || lang.isFunction(value)){
|
||
|
return prop.set(node, name, value);
|
||
|
}
|
||
|
// node's attribute
|
||
|
node.setAttribute(attrNames[lc] || name, value);
|
||
|
return node; // DomNode
|
||
|
};
|
||
|
|
||
|
exports.remove = function removeAttr(/*DOMNode|String*/ node, /*String*/ name){
|
||
|
// summary:
|
||
|
// Removes an attribute from an HTML element.
|
||
|
// node: DOMNode|String
|
||
|
// id or reference to the element to remove the attribute from
|
||
|
// name: String
|
||
|
// the name of the attribute to remove
|
||
|
|
||
|
dom.byId(node).removeAttribute(attrNames[name.toLowerCase()] || name);
|
||
|
};
|
||
|
|
||
|
exports.getNodeProp = function getNodeProp(/*DomNode|String*/ node, /*String*/ name){
|
||
|
// summary:
|
||
|
// Returns an effective value of a property or an attribute.
|
||
|
// node: DOMNode|String
|
||
|
// id or reference to the element to remove the attribute from
|
||
|
// name: String
|
||
|
// the name of the attribute
|
||
|
// returns:
|
||
|
// the value of the attribute
|
||
|
|
||
|
node = dom.byId(node);
|
||
|
var lc = name.toLowerCase(), propName = prop.names[lc] || name;
|
||
|
if((propName in node) && propName != "href"){
|
||
|
// node's property
|
||
|
return node[propName]; // Anything
|
||
|
}
|
||
|
// node's attribute
|
||
|
var attrName = attrNames[lc] || name;
|
||
|
return _hasAttr(node, attrName) ? node.getAttribute(attrName) : null; // Anything
|
||
|
};
|
||
|
});
|
||
|
|
||
|
},
|
||
|
'dojo/dom-prop':function(){
|
||
|
define(["exports", "./_base/kernel", "./sniff", "./_base/lang", "./dom", "./dom-style", "./dom-construct", "./_base/connect"],
|
||
|
function(exports, dojo, has, lang, dom, style, ctr, conn){
|
||
|
// module:
|
||
|
// dojo/dom-prop
|
||
|
// summary:
|
||
|
// This module defines the core dojo DOM properties API.
|
||
|
|
||
|
// TODOC: summary not showing up in output, see https://github.com/csnover/js-doc-parse/issues/42
|
||
|
|
||
|
// =============================
|
||
|
// Element properties Functions
|
||
|
// =============================
|
||
|
|
||
|
// helper to connect events
|
||
|
var _evtHdlrMap = {}, _ctr = 1, _attrId = dojo._scopeName + "attrid";
|
||
|
has.add('dom-textContent', function (global, doc, element) { return 'textContent' in element; });
|
||
|
|
||
|
exports.names = {
|
||
|
// properties renamed to avoid clashes with reserved words
|
||
|
"class": "className",
|
||
|
"for": "htmlFor",
|
||
|
// properties written as camelCase
|
||
|
tabindex: "tabIndex",
|
||
|
readonly: "readOnly",
|
||
|
colspan: "colSpan",
|
||
|
frameborder: "frameBorder",
|
||
|
rowspan: "rowSpan",
|
||
|
textcontent: "textContent",
|
||
|
valuetype: "valueType"
|
||
|
};
|
||
|
|
||
|
function getText(/*DOMNode*/node){
|
||
|
// summary:
|
||
|
// recursion method for get('textContent') to use. Gets text value for a node.
|
||
|
// description:
|
||
|
// Juse uses nodedValue so things like <br/> tags do not end up in
|
||
|
// the text as any sort of line return.
|
||
|
var text = "", ch = node.childNodes;
|
||
|
for(var i = 0, n; n = ch[i]; i++){
|
||
|
//Skip comments.
|
||
|
if(n.nodeType != 8){
|
||
|
if(n.nodeType == 1){
|
||
|
text += getText(n);
|
||
|
}else{
|
||
|
text += n.nodeValue;
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
return text;
|
||
|
}
|
||
|
|
||
|
exports.get = function getProp(/*DOMNode|String*/ node, /*String*/ name){
|
||
|
// summary:
|
||
|
// Gets a property on an HTML element.
|
||
|
// description:
|
||
|
// Handles normalized getting of properties on DOM nodes.
|
||
|
//
|
||
|
// node: DOMNode|String
|
||
|
// id or reference to the element to get the property on
|
||
|
// name: String
|
||
|
// the name of the property to get.
|
||
|
// returns:
|
||
|
// the value of the requested property or its default value
|
||
|
//
|
||
|
// example:
|
||
|
// | // get the current value of the "foo" property on a node
|
||
|
// | require(["dojo/dom-prop", "dojo/dom"], function(domProp, dom){
|
||
|
// | domProp.get(dom.byId("nodeId"), "foo");
|
||
|
// | // or we can just pass the id:
|
||
|
// | domProp.get("nodeId", "foo");
|
||
|
// | });
|
||
|
|
||
|
node = dom.byId(node);
|
||
|
var lc = name.toLowerCase(), propName = exports.names[lc] || name;
|
||
|
|
||
|
if(propName == "textContent" && !has("dom-textContent")){
|
||
|
return getText(node);
|
||
|
}
|
||
|
|
||
|
return node[propName]; // Anything
|
||
|
};
|
||
|
|
||
|
exports.set = function setProp(/*DOMNode|String*/ node, /*String|Object*/ name, /*String?*/ value){
|
||
|
// summary:
|
||
|
// Sets a property on an HTML element.
|
||
|
// description:
|
||
|
// Handles normalized setting of properties on DOM nodes.
|
||
|
//
|
||
|
// When passing functions as values, note that they will not be
|
||
|
// directly assigned to slots on the node, but rather the default
|
||
|
// behavior will be removed and the new behavior will be added
|
||
|
// using `dojo.connect()`, meaning that event handler properties
|
||
|
// will be normalized and that some caveats with regards to
|
||
|
// non-standard behaviors for onsubmit apply. Namely that you
|
||
|
// should cancel form submission using `dojo.stopEvent()` on the
|
||
|
// passed event object instead of returning a boolean value from
|
||
|
// the handler itself.
|
||
|
// node: DOMNode|String
|
||
|
// id or reference to the element to set the property on
|
||
|
// name: String|Object
|
||
|
// the name of the property to set, or a hash object to set
|
||
|
// multiple properties at once.
|
||
|
// value: String?
|
||
|
// The value to set for the property
|
||
|
// returns:
|
||
|
// the DOM node
|
||
|
//
|
||
|
// example:
|
||
|
// | // use prop() to set the tab index
|
||
|
// | require(["dojo/dom-prop"], function(domProp){
|
||
|
// | domProp.set("nodeId", "tabIndex", 3);
|
||
|
// | });
|
||
|
//
|
||
|
// example:
|
||
|
// Set multiple values at once, including event handlers:
|
||
|
// | require(["dojo/dom-prop"], function(domProp){
|
||
|
// | domProp.set("formId", {
|
||
|
// | "foo": "bar",
|
||
|
// | "tabIndex": -1,
|
||
|
// | "method": "POST",
|
||
|
// | });
|
||
|
// | });
|
||
|
|
||
|
node = dom.byId(node);
|
||
|
var l = arguments.length;
|
||
|
if(l == 2 && typeof name != "string"){ // inline'd type check
|
||
|
// the object form of setter: the 2nd argument is a dictionary
|
||
|
for(var x in name){
|
||
|
exports.set(node, x, name[x]);
|
||
|
}
|
||
|
return node; // DomNode
|
||
|
}
|
||
|
var lc = name.toLowerCase(), propName = exports.names[lc] || name;
|
||
|
if(propName == "style" && typeof value != "string"){ // inline'd type check
|
||
|
// special case: setting a style
|
||
|
style.set(node, value);
|
||
|
return node; // DomNode
|
||
|
}
|
||
|
if(propName == "innerHTML"){
|
||
|
// special case: assigning HTML
|
||
|
// the hash lists elements with read-only innerHTML on IE
|
||
|
if(has("ie") && node.tagName.toLowerCase() in {col: 1, colgroup: 1,
|
||
|
table: 1, tbody: 1, tfoot: 1, thead: 1, tr: 1, title: 1}){
|
||
|
ctr.empty(node);
|
||
|
node.appendChild(ctr.toDom(value, node.ownerDocument));
|
||
|
}else{
|
||
|
node[propName] = value;
|
||
|
}
|
||
|
return node; // DomNode
|
||
|
}
|
||
|
if(propName == "textContent" && !has("dom-textContent")) {
|
||
|
ctr.empty(node);
|
||
|
node.appendChild(node.ownerDocument.createTextNode(value));
|
||
|
return node;
|
||
|
}
|
||
|
if(lang.isFunction(value)){
|
||
|
// special case: assigning an event handler
|
||
|
// clobber if we can
|
||
|
var attrId = node[_attrId];
|
||
|
if(!attrId){
|
||
|
attrId = _ctr++;
|
||
|
node[_attrId] = attrId;
|
||
|
}
|
||
|
if(!_evtHdlrMap[attrId]){
|
||
|
_evtHdlrMap[attrId] = {};
|
||
|
}
|
||
|
var h = _evtHdlrMap[attrId][propName];
|
||
|
if(h){
|
||
|
//h.remove();
|
||
|
conn.disconnect(h);
|
||
|
}else{
|
||
|
try{
|
||
|
delete node[propName];
|
||
|
}catch(e){}
|
||
|
}
|
||
|
// ensure that event objects are normalized, etc.
|
||
|
if(value){
|
||
|
//_evtHdlrMap[attrId][propName] = on(node, propName, value);
|
||
|
_evtHdlrMap[attrId][propName] = conn.connect(node, propName, value);
|
||
|
}else{
|
||
|
node[propName] = null;
|
||
|
}
|
||
|
return node; // DomNode
|
||
|
}
|
||
|
node[propName] = value;
|
||
|
return node; // DomNode
|
||
|
};
|
||
|
});
|
||
|
|
||
|
},
|
||
|
'dojo/dom-construct':function(){
|
||
|
define(["exports", "./_base/kernel", "./sniff", "./_base/window", "./dom", "./dom-attr"],
|
||
|
function(exports, dojo, has, win, dom, attr){
|
||
|
// module:
|
||
|
// dojo/dom-construct
|
||
|
// summary:
|
||
|
// This module defines the core dojo DOM construction API.
|
||
|
|
||
|
// TODOC: summary not showing up in output, see https://github.com/csnover/js-doc-parse/issues/42
|
||
|
|
||
|
// support stuff for toDom()
|
||
|
var tagWrap = {
|
||
|
option: ["select"],
|
||
|
tbody: ["table"],
|
||
|
thead: ["table"],
|
||
|
tfoot: ["table"],
|
||
|
tr: ["table", "tbody"],
|
||
|
td: ["table", "tbody", "tr"],
|
||
|
th: ["table", "thead", "tr"],
|
||
|
legend: ["fieldset"],
|
||
|
caption: ["table"],
|
||
|
colgroup: ["table"],
|
||
|
col: ["table", "colgroup"],
|
||
|
li: ["ul"]
|
||
|
},
|
||
|
reTag = /<\s*([\w\:]+)/,
|
||
|
masterNode = {}, masterNum = 0,
|
||
|
masterName = "__" + dojo._scopeName + "ToDomId";
|
||
|
|
||
|
// generate start/end tag strings to use
|
||
|
// for the injection for each special tag wrap case.
|
||
|
for(var param in tagWrap){
|
||
|
if(tagWrap.hasOwnProperty(param)){
|
||
|
var tw = tagWrap[param];
|
||
|
tw.pre = param == "option" ? '<select multiple="multiple">' : "<" + tw.join("><") + ">";
|
||
|
tw.post = "</" + tw.reverse().join("></") + ">";
|
||
|
// the last line is destructive: it reverses the array,
|
||
|
// but we don't care at this point
|
||
|
}
|
||
|
}
|
||
|
|
||
|
var html5domfix;
|
||
|
if(has("ie") <= 8){
|
||
|
html5domfix = function(doc){
|
||
|
doc.__dojo_html5_tested = "yes";
|
||
|
var div = create('div', {innerHTML: "<nav>a</nav>", style: {visibility: "hidden"}}, doc.body);
|
||
|
if(div.childNodes.length !== 1){
|
||
|
('abbr article aside audio canvas details figcaption figure footer header ' +
|
||
|
'hgroup mark meter nav output progress section summary time video').replace(
|
||
|
/\b\w+\b/g, function(n){
|
||
|
doc.createElement(n);
|
||
|
}
|
||
|
);
|
||
|
}
|
||
|
destroy(div);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
function _insertBefore(/*DomNode*/ node, /*DomNode*/ ref){
|
||
|
var parent = ref.parentNode;
|
||
|
if(parent){
|
||
|
parent.insertBefore(node, ref);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
function _insertAfter(/*DomNode*/ node, /*DomNode*/ ref){
|
||
|
// summary:
|
||
|
// Try to insert node after ref
|
||
|
var parent = ref.parentNode;
|
||
|
if(parent){
|
||
|
if(parent.lastChild == ref){
|
||
|
parent.appendChild(node);
|
||
|
}else{
|
||
|
parent.insertBefore(node, ref.nextSibling);
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
|
||
|
exports.toDom = function toDom(frag, doc){
|
||
|
// summary:
|
||
|
// instantiates an HTML fragment returning the corresponding DOM.
|
||
|
// frag: String
|
||
|
// the HTML fragment
|
||
|
// doc: DocumentNode?
|
||
|
// optional document to use when creating DOM nodes, defaults to
|
||
|
// dojo/_base/window.doc if not specified.
|
||
|
// returns:
|
||
|
// Document fragment, unless it's a single node in which case it returns the node itself
|
||
|
// example:
|
||
|
// Create a table row:
|
||
|
// | require(["dojo/dom-construct"], function(domConstruct){
|
||
|
// | var tr = domConstruct.toDom("<tr><td>First!</td></tr>");
|
||
|
// | });
|
||
|
|
||
|
doc = doc || win.doc;
|
||
|
var masterId = doc[masterName];
|
||
|
if(!masterId){
|
||
|
doc[masterName] = masterId = ++masterNum + "";
|
||
|
masterNode[masterId] = doc.createElement("div");
|
||
|
}
|
||
|
|
||
|
if(has("ie") <= 8){
|
||
|
if(!doc.__dojo_html5_tested && doc.body){
|
||
|
html5domfix(doc);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
// make sure the frag is a string.
|
||
|
frag += "";
|
||
|
|
||
|
// find the starting tag, and get node wrapper
|
||
|
var match = frag.match(reTag),
|
||
|
tag = match ? match[1].toLowerCase() : "",
|
||
|
master = masterNode[masterId],
|
||
|
wrap, i, fc, df;
|
||
|
if(match && tagWrap[tag]){
|
||
|
wrap = tagWrap[tag];
|
||
|
master.innerHTML = wrap.pre + frag + wrap.post;
|
||
|
for(i = wrap.length; i; --i){
|
||
|
master = master.firstChild;
|
||
|
}
|
||
|
}else{
|
||
|
master.innerHTML = frag;
|
||
|
}
|
||
|
|
||
|
// one node shortcut => return the node itself
|
||
|
if(master.childNodes.length == 1){
|
||
|
return master.removeChild(master.firstChild); // DOMNode
|
||
|
}
|
||
|
|
||
|
// return multiple nodes as a document fragment
|
||
|
df = doc.createDocumentFragment();
|
||
|
while((fc = master.firstChild)){ // intentional assignment
|
||
|
df.appendChild(fc);
|
||
|
}
|
||
|
return df; // DocumentFragment
|
||
|
};
|
||
|
|
||
|
exports.place = function place(node, refNode, position){
|
||
|
// summary:
|
||
|
// Attempt to insert node into the DOM, choosing from various positioning options.
|
||
|
// Returns the first argument resolved to a DOM node.
|
||
|
// node: DOMNode|DocumentFragment|String
|
||
|
// id or node reference, or HTML fragment starting with "<" to place relative to refNode
|
||
|
// refNode: DOMNode|String
|
||
|
// id or node reference to use as basis for placement
|
||
|
// position: String|Number?
|
||
|
// string noting the position of node relative to refNode or a
|
||
|
// number indicating the location in the childNodes collection of refNode.
|
||
|
// Accepted string values are:
|
||
|
//
|
||
|
// - before
|
||
|
// - after
|
||
|
// - replace
|
||
|
// - only
|
||
|
// - first
|
||
|
// - last
|
||
|
//
|
||
|
// "first" and "last" indicate positions as children of refNode, "replace" replaces refNode,
|
||
|
// "only" replaces all children. position defaults to "last" if not specified
|
||
|
// returns: DOMNode
|
||
|
// Returned values is the first argument resolved to a DOM node.
|
||
|
//
|
||
|
// .place() is also a method of `dojo/NodeList`, allowing `dojo/query` node lookups.
|
||
|
// example:
|
||
|
// Place a node by string id as the last child of another node by string id:
|
||
|
// | require(["dojo/dom-construct"], function(domConstruct){
|
||
|
// | domConstruct.place("someNode", "anotherNode");
|
||
|
// | });
|
||
|
// example:
|
||
|
// Place a node by string id before another node by string id
|
||
|
// | require(["dojo/dom-construct"], function(domConstruct){
|
||
|
// | domConstruct.place("someNode", "anotherNode", "before");
|
||
|
// | });
|
||
|
// example:
|
||
|
// Create a Node, and place it in the body element (last child):
|
||
|
// | require(["dojo/dom-construct", "dojo/_base/window"
|
||
|
// | ], function(domConstruct, win){
|
||
|
// | domConstruct.place("<div></div>", win.body());
|
||
|
// | });
|
||
|
// example:
|
||
|
// Put a new LI as the first child of a list by id:
|
||
|
// | require(["dojo/dom-construct"], function(domConstruct){
|
||
|
// | domConstruct.place("<li></li>", "someUl", "first");
|
||
|
// | });
|
||
|
|
||
|
refNode = dom.byId(refNode);
|
||
|
if(typeof node == "string"){ // inline'd type check
|
||
|
node = /^\s*</.test(node) ? exports.toDom(node, refNode.ownerDocument) : dom.byId(node);
|
||
|
}
|
||
|
if(typeof position == "number"){ // inline'd type check
|
||
|
var cn = refNode.childNodes;
|
||
|
if(!cn.length || cn.length <= position){
|
||
|
refNode.appendChild(node);
|
||
|
}else{
|
||
|
_insertBefore(node, cn[position < 0 ? 0 : position]);
|
||
|
}
|
||
|
}else{
|
||
|
switch(position){
|
||
|
case "before":
|
||
|
_insertBefore(node, refNode);
|
||
|
break;
|
||
|
case "after":
|
||
|
_insertAfter(node, refNode);
|
||
|
break;
|
||
|
case "replace":
|
||
|
refNode.parentNode.replaceChild(node, refNode);
|
||
|
break;
|
||
|
case "only":
|
||
|
exports.empty(refNode);
|
||
|
refNode.appendChild(node);
|
||
|
break;
|
||
|
case "first":
|
||
|
if(refNode.firstChild){
|
||
|
_insertBefore(node, refNode.firstChild);
|
||
|
break;
|
||
|
}
|
||
|
// else fallthrough...
|
||
|
default: // aka: last
|
||
|
refNode.appendChild(node);
|
||
|
}
|
||
|
}
|
||
|
return node; // DomNode
|
||
|
};
|
||
|
|
||
|
var create = exports.create = function create(/*DOMNode|String*/ tag, /*Object*/ attrs, /*DOMNode|String?*/ refNode, /*String?*/ pos){
|
||
|
// summary:
|
||
|
// Create an element, allowing for optional attribute decoration
|
||
|
// and placement.
|
||
|
// description:
|
||
|
// A DOM Element creation function. A shorthand method for creating a node or
|
||
|
// a fragment, and allowing for a convenient optional attribute setting step,
|
||
|
// as well as an optional DOM placement reference.
|
||
|
//
|
||
|
// Attributes are set by passing the optional object through `dojo/dom-attr.set`.
|
||
|
// See `dojo/dom-attr.set` for noted caveats and nuances, and API if applicable.
|
||
|
//
|
||
|
// Placement is done via `dojo/dom-construct.place`, assuming the new node to be
|
||
|
// the action node, passing along the optional reference node and position.
|
||
|
// tag: DOMNode|String
|
||
|
// A string of the element to create (eg: "div", "a", "p", "li", "script", "br"),
|
||
|
// or an existing DOM node to process.
|
||
|
// attrs: Object
|
||
|
// An object-hash of attributes to set on the newly created node.
|
||
|
// Can be null, if you don't want to set any attributes/styles.
|
||
|
// See: `dojo/dom-attr.set` for a description of available attributes.
|
||
|
// refNode: DOMNode|String?
|
||
|
// Optional reference node. Used by `dojo/dom-construct.place` to place the newly created
|
||
|
// node somewhere in the dom relative to refNode. Can be a DomNode reference
|
||
|
// or String ID of a node.
|
||
|
// pos: String?
|
||
|
// Optional positional reference. Defaults to "last" by way of `dojo/domConstruct.place`,
|
||
|
// though can be set to "first","after","before","last", "replace" or "only"
|
||
|
// to further control the placement of the new node relative to the refNode.
|
||
|
// 'refNode' is required if a 'pos' is specified.
|
||
|
// example:
|
||
|
// Create a DIV:
|
||
|
// | require(["dojo/dom-construct"], function(domConstruct){
|
||
|
// | var n = domConstruct.create("div");
|
||
|
// | });
|
||
|
//
|
||
|
// example:
|
||
|
// Create a DIV with content:
|
||
|
// | require(["dojo/dom-construct"], function(domConstruct){
|
||
|
// | var n = domConstruct.create("div", { innerHTML:"<p>hi</p>" });
|
||
|
// | });
|
||
|
//
|
||
|
// example:
|
||
|
// Place a new DIV in the BODY, with no attributes set
|
||
|
// | require(["dojo/dom-construct", "dojo/_base/window"], function(domConstruct, win){
|
||
|
// | var n = domConstruct.create("div", null, win.body());
|
||
|
// | });
|
||
|
//
|
||
|
// example:
|
||
|
// Create an UL, and populate it with LI's. Place the list as the first-child of a
|
||
|
// node with id="someId":
|
||
|
// | require(["dojo/dom-construct", "dojo/_base/array"],
|
||
|
// | function(domConstruct, arrayUtil){
|
||
|
// | var ul = domConstruct.create("ul", null, "someId", "first");
|
||
|
// | var items = ["one", "two", "three", "four"];
|
||
|
// | arrayUtil.forEach(items, function(data){
|
||
|
// | domConstruct.create("li", { innerHTML: data }, ul);
|
||
|
// | });
|
||
|
// | });
|
||
|
//
|
||
|
// example:
|
||
|
// Create an anchor, with an href. Place in BODY:
|
||
|
// | require(["dojo/dom-construct", "dojo/_base/window"], function(domConstruct, win){
|
||
|
// | domConstruct.create("a", { href:"foo.html", title:"Goto FOO!" }, win.body());
|
||
|
// | });
|
||
|
|
||
|
var doc = win.doc;
|
||
|
if(refNode){
|
||
|
refNode = dom.byId(refNode);
|
||
|
doc = refNode.ownerDocument;
|
||
|
}
|
||
|
if(typeof tag == "string"){ // inline'd type check
|
||
|
tag = doc.createElement(tag);
|
||
|
}
|
||
|
if(attrs){ attr.set(tag, attrs); }
|
||
|
if(refNode){ exports.place(tag, refNode, pos); }
|
||
|
return tag; // DomNode
|
||
|
};
|
||
|
|
||
|
function _empty(/*DomNode*/ node){
|
||
|
// TODO: remove this if() block in 2.0 when we no longer have to worry about IE memory leaks,
|
||
|
// and then uncomment the emptyGrandchildren() test case from html.html.
|
||
|
// Note that besides fixing #16957, using removeChild() is actually faster than setting node.innerHTML,
|
||
|
// see http://jsperf.com/clear-dom-node.
|
||
|
if("innerHTML" in node){
|
||
|
try{
|
||
|
// fast path
|
||
|
node.innerHTML = "";
|
||
|
return;
|
||
|
}catch(e){
|
||
|
// innerHTML is readOnly (e.g. TABLE (sub)elements in quirks mode)
|
||
|
// Fall through (saves bytes)
|
||
|
}
|
||
|
}
|
||
|
|
||
|
// SVG/strict elements don't support innerHTML
|
||
|
for(var c; c = node.lastChild;){ // intentional assignment
|
||
|
node.removeChild(c);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
exports.empty = function empty(/*DOMNode|String*/ node){
|
||
|
// summary:
|
||
|
// safely removes all children of the node.
|
||
|
// node: DOMNode|String
|
||
|
// a reference to a DOM node or an id.
|
||
|
// example:
|
||
|
// Destroy node's children byId:
|
||
|
// | require(["dojo/dom-construct"], function(domConstruct){
|
||
|
// | domConstruct.empty("someId");
|
||
|
// | });
|
||
|
|
||
|
_empty(dom.byId(node));
|
||
|
};
|
||
|
|
||
|
|
||
|
function _destroy(/*DomNode*/ node, /*DomNode*/ parent){
|
||
|
// in IE quirks, node.canHaveChildren can be false but firstChild can be non-null (OBJECT/APPLET)
|
||
|
if(node.firstChild){
|
||
|
_empty(node);
|
||
|
}
|
||
|
if(parent){
|
||
|
// removeNode(false) doesn't leak in IE 6+, but removeChild() and removeNode(true) are known to leak under IE 8- while 9+ is TBD.
|
||
|
// In IE quirks mode, PARAM nodes as children of OBJECT/APPLET nodes have a removeNode method that does nothing and
|
||
|
// the parent node has canHaveChildren=false even though removeChild correctly removes the PARAM children.
|
||
|
// In IE, SVG/strict nodes don't have a removeNode method nor a canHaveChildren boolean.
|
||
|
has("ie") && parent.canHaveChildren && "removeNode" in node ? node.removeNode(false) : parent.removeChild(node);
|
||
|
}
|
||
|
}
|
||
|
var destroy = exports.destroy = function destroy(/*DOMNode|String*/ node){
|
||
|
// summary:
|
||
|
// Removes a node from its parent, clobbering it and all of its
|
||
|
// children.
|
||
|
//
|
||
|
// description:
|
||
|
// Removes a node from its parent, clobbering it and all of its
|
||
|
// children. Function only works with DomNodes, and returns nothing.
|
||
|
//
|
||
|
// node: DOMNode|String
|
||
|
// A String ID or DomNode reference of the element to be destroyed
|
||
|
//
|
||
|
// example:
|
||
|
// Destroy a node byId:
|
||
|
// | require(["dojo/dom-construct"], function(domConstruct){
|
||
|
// | domConstruct.destroy("someId");
|
||
|
// | });
|
||
|
|
||
|
node = dom.byId(node);
|
||
|
if(!node){ return; }
|
||
|
_destroy(node, node.parentNode);
|
||
|
};
|
||
|
});
|
||
|
|
||
|
},
|
||
|
'dojo/dom-class':function(){
|
||
|
define(["./_base/lang", "./_base/array", "./dom"], function(lang, array, dom){
|
||
|
// module:
|
||
|
// dojo/dom-class
|
||
|
|
||
|
var className = "className";
|
||
|
|
||
|
/* Part I of classList-based implementation is preserved here for posterity
|
||
|
var classList = "classList";
|
||
|
has.add("dom-classList", function(){
|
||
|
return classList in document.createElement("p");
|
||
|
});
|
||
|
*/
|
||
|
|
||
|
// =============================
|
||
|
// (CSS) Class Functions
|
||
|
// =============================
|
||
|
|
||
|
var cls, // exports object
|
||
|
spaces = /\s+/, a1 = [""];
|
||
|
|
||
|
function str2array(s){
|
||
|
if(typeof s == "string" || s instanceof String){
|
||
|
if(s && !spaces.test(s)){
|
||
|
a1[0] = s;
|
||
|
return a1;
|
||
|
}
|
||
|
var a = s.split(spaces);
|
||
|
if(a.length && !a[0]){
|
||
|
a.shift();
|
||
|
}
|
||
|
if(a.length && !a[a.length - 1]){
|
||
|
a.pop();
|
||
|
}
|
||
|
return a;
|
||
|
}
|
||
|
// assumed to be an array
|
||
|
if(!s){
|
||
|
return [];
|
||
|
}
|
||
|
return array.filter(s, function(x){ return x; });
|
||
|
}
|
||
|
|
||
|
/* Part II of classList-based implementation is preserved here for posterity
|
||
|
if(has("dom-classList")){
|
||
|
// new classList version
|
||
|
cls = {
|
||
|
contains: function containsClass(node, classStr){
|
||
|
var clslst = classStr && dom.byId(node)[classList];
|
||
|
return clslst && clslst.contains(classStr); // Boolean
|
||
|
},
|
||
|
|
||
|
add: function addClass(node, classStr){
|
||
|
node = dom.byId(node);
|
||
|
classStr = str2array(classStr);
|
||
|
for(var i = 0, len = classStr.length; i < len; ++i){
|
||
|
node[classList].add(classStr[i]);
|
||
|
}
|
||
|
},
|
||
|
|
||
|
remove: function removeClass(node, classStr){
|
||
|
node = dom.byId(node);
|
||
|
if(classStr === undefined){
|
||
|
node[className] = "";
|
||
|
}else{
|
||
|
classStr = str2array(classStr);
|
||
|
for(var i = 0, len = classStr.length; i < len; ++i){
|
||
|
node[classList].remove(classStr[i]);
|
||
|
}
|
||
|
}
|
||
|
},
|
||
|
|
||
|
replace: function replaceClass(node, addClassStr, removeClassStr){
|
||
|
node = dom.byId(node);
|
||
|
if(removeClassStr === undefined){
|
||
|
node[className] = "";
|
||
|
}else{
|
||
|
removeClassStr = str2array(removeClassStr);
|
||
|
for(var i = 0, len = removeClassStr.length; i < len; ++i){
|
||
|
node[classList].remove(removeClassStr[i]);
|
||
|
}
|
||
|
}
|
||
|
addClassStr = str2array(addClassStr);
|
||
|
for(i = 0, len = addClassStr.length; i < len; ++i){
|
||
|
node[classList].add(addClassStr[i]);
|
||
|
}
|
||
|
},
|
||
|
|
||
|
toggle: function toggleClass(node, classStr, condition){
|
||
|
node = dom.byId(node);
|
||
|
if(condition === undefined){
|
||
|
classStr = str2array(classStr);
|
||
|
for(var i = 0, len = classStr.length; i < len; ++i){
|
||
|
node[classList].toggle(classStr[i]);
|
||
|
}
|
||
|
}else{
|
||
|
cls[condition ? "add" : "remove"](node, classStr);
|
||
|
}
|
||
|
return condition; // Boolean
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
*/
|
||
|
|
||
|
// regular DOM version
|
||
|
var fakeNode = {}; // for effective replacement
|
||
|
cls = {
|
||
|
// summary:
|
||
|
// This module defines the core dojo DOM class API.
|
||
|
|
||
|
contains: function containsClass(/*DomNode|String*/ node, /*String*/ classStr){
|
||
|
// summary:
|
||
|
// Returns whether or not the specified classes are a portion of the
|
||
|
// class list currently applied to the node.
|
||
|
// node: String|DOMNode
|
||
|
// String ID or DomNode reference to check the class for.
|
||
|
// classStr: String
|
||
|
// A string class name to look for.
|
||
|
// example:
|
||
|
// Do something if a node with id="someNode" has class="aSillyClassName" present
|
||
|
// | if(domClass.contains("someNode","aSillyClassName")){ ... }
|
||
|
|
||
|
return ((" " + dom.byId(node)[className] + " ").indexOf(" " + classStr + " ") >= 0); // Boolean
|
||
|
},
|
||
|
|
||
|
add: function addClass(/*DomNode|String*/ node, /*String|Array*/ classStr){
|
||
|
// summary:
|
||
|
// Adds the specified classes to the end of the class list on the
|
||
|
// passed node. Will not re-apply duplicate classes.
|
||
|
//
|
||
|
// node: String|DOMNode
|
||
|
// String ID or DomNode reference to add a class string too
|
||
|
//
|
||
|
// classStr: String|Array
|
||
|
// A String class name to add, or several space-separated class names,
|
||
|
// or an array of class names.
|
||
|
//
|
||
|
// example:
|
||
|
// Add a class to some node:
|
||
|
// | require(["dojo/dom-class"], function(domClass){
|
||
|
// | domClass.add("someNode", "anewClass");
|
||
|
// | });
|
||
|
//
|
||
|
// example:
|
||
|
// Add two classes at once:
|
||
|
// | require(["dojo/dom-class"], function(domClass){
|
||
|
// | domClass.add("someNode", "firstClass secondClass");
|
||
|
// | });
|
||
|
//
|
||
|
// example:
|
||
|
// Add two classes at once (using array):
|
||
|
// | require(["dojo/dom-class"], function(domClass){
|
||
|
// | domClass.add("someNode", ["firstClass", "secondClass"]);
|
||
|
// | });
|
||
|
//
|
||
|
// example:
|
||
|
// Available in `dojo/NodeList` for multiple additions
|
||
|
// | require(["dojo/query"], function(query){
|
||
|
// | query("ul > li").addClass("firstLevel");
|
||
|
// | });
|
||
|
|
||
|
node = dom.byId(node);
|
||
|
classStr = str2array(classStr);
|
||
|
var cls = node[className], oldLen;
|
||
|
cls = cls ? " " + cls + " " : " ";
|
||
|
oldLen = cls.length;
|
||
|
for(var i = 0, len = classStr.length, c; i < len; ++i){
|
||
|
c = classStr[i];
|
||
|
if(c && cls.indexOf(" " + c + " ") < 0){
|
||
|
cls += c + " ";
|
||
|
}
|
||
|
}
|
||
|
if(oldLen < cls.length){
|
||
|
node[className] = cls.substr(1, cls.length - 2);
|
||
|
}
|
||
|
},
|
||
|
|
||
|
remove: function removeClass(/*DomNode|String*/ node, /*String|Array?*/ classStr){
|
||
|
// summary:
|
||
|
// Removes the specified classes from node. No `contains()`
|
||
|
// check is required.
|
||
|
//
|
||
|
// node: String|DOMNode
|
||
|
// String ID or DomNode reference to remove the class from.
|
||
|
//
|
||
|
// classStr: String|Array
|
||
|
// An optional String class name to remove, or several space-separated
|
||
|
// class names, or an array of class names. If omitted, all class names
|
||
|
// will be deleted.
|
||
|
//
|
||
|
// example:
|
||
|
// Remove a class from some node:
|
||
|
// | require(["dojo/dom-class"], function(domClass){
|
||
|
// | domClass.remove("someNode", "firstClass");
|
||
|
// | });
|
||
|
//
|
||
|
// example:
|
||
|
// Remove two classes from some node:
|
||
|
// | require(["dojo/dom-class"], function(domClass){
|
||
|
// | domClass.remove("someNode", "firstClass secondClass");
|
||
|
// | });
|
||
|
//
|
||
|
// example:
|
||
|
// Remove two classes from some node (using array):
|
||
|
// | require(["dojo/dom-class"], function(domClass){
|
||
|
// | domClass.remove("someNode", ["firstClass", "secondClass"]);
|
||
|
// | });
|
||
|
//
|
||
|
// example:
|
||
|
// Remove all classes from some node:
|
||
|
// | require(["dojo/dom-class"], function(domClass){
|
||
|
// | domClass.remove("someNode");
|
||
|
// | });
|
||
|
//
|
||
|
// example:
|
||
|
// Available in `dojo/NodeList` for multiple removal
|
||
|
// | require(["dojo/query"], function(query){
|
||
|
// | query("ul > li").removeClass("foo");
|
||
|
// | });
|
||
|
|
||
|
node = dom.byId(node);
|
||
|
var cls;
|
||
|
if(classStr !== undefined){
|
||
|
classStr = str2array(classStr);
|
||
|
cls = " " + node[className] + " ";
|
||
|
for(var i = 0, len = classStr.length; i < len; ++i){
|
||
|
cls = cls.replace(" " + classStr[i] + " ", " ");
|
||
|
}
|
||
|
cls = lang.trim(cls);
|
||
|
}else{
|
||
|
cls = "";
|
||
|
}
|
||
|
if(node[className] != cls){ node[className] = cls; }
|
||
|
},
|
||
|
|
||
|
replace: function replaceClass(/*DomNode|String*/ node, /*String|Array*/ addClassStr, /*String|Array?*/ removeClassStr){
|
||
|
// summary:
|
||
|
// Replaces one or more classes on a node if not present.
|
||
|
// Operates more quickly than calling domClass.remove and domClass.add
|
||
|
//
|
||
|
// node: String|DOMNode
|
||
|
// String ID or DomNode reference to remove the class from.
|
||
|
//
|
||
|
// addClassStr: String|Array
|
||
|
// A String class name to add, or several space-separated class names,
|
||
|
// or an array of class names.
|
||
|
//
|
||
|
// removeClassStr: String|Array?
|
||
|
// A String class name to remove, or several space-separated class names,
|
||
|
// or an array of class names.
|
||
|
//
|
||
|
// example:
|
||
|
// | require(["dojo/dom-class"], function(domClass){
|
||
|
// | domClass.replace("someNode", "add1 add2", "remove1 remove2");
|
||
|
// | });
|
||
|
//
|
||
|
// example:
|
||
|
// Replace all classes with addMe
|
||
|
// | require(["dojo/dom-class"], function(domClass){
|
||
|
// | domClass.replace("someNode", "addMe");
|
||
|
// | });
|
||
|
//
|
||
|
// example:
|
||
|
// Available in `dojo/NodeList` for multiple toggles
|
||
|
// | require(["dojo/query"], function(query){
|
||
|
// | query(".findMe").replaceClass("addMe", "removeMe");
|
||
|
// | });
|
||
|
|
||
|
node = dom.byId(node);
|
||
|
fakeNode[className] = node[className];
|
||
|
cls.remove(fakeNode, removeClassStr);
|
||
|
cls.add(fakeNode, addClassStr);
|
||
|
if(node[className] !== fakeNode[className]){
|
||
|
node[className] = fakeNode[className];
|
||
|
}
|
||
|
},
|
||
|
|
||
|
toggle: function toggleClass(/*DomNode|String*/ node, /*String|Array*/ classStr, /*Boolean?*/ condition){
|
||
|
// summary:
|
||
|
// Adds a class to node if not present, or removes if present.
|
||
|
// Pass a boolean condition if you want to explicitly add or remove.
|
||
|
// Returns the condition that was specified directly or indirectly.
|
||
|
//
|
||
|
// node: String|DOMNode
|
||
|
// String ID or DomNode reference to toggle a class string
|
||
|
//
|
||
|
// classStr: String|Array
|
||
|
// A String class name to toggle, or several space-separated class names,
|
||
|
// or an array of class names.
|
||
|
//
|
||
|
// condition:
|
||
|
// If passed, true means to add the class, false means to remove.
|
||
|
// Otherwise domClass.contains(node, classStr) is used to detect the class presence.
|
||
|
//
|
||
|
// example:
|
||
|
// | require(["dojo/dom-class"], function(domClass){
|
||
|
// | domClass.toggle("someNode", "hovered");
|
||
|
// | });
|
||
|
//
|
||
|
// example:
|
||
|
// Forcefully add a class
|
||
|
// | require(["dojo/dom-class"], function(domClass){
|
||
|
// | domClass.toggle("someNode", "hovered", true);
|
||
|
// | });
|
||
|
//
|
||
|
// example:
|
||
|
// Available in `dojo/NodeList` for multiple toggles
|
||
|
// | require(["dojo/query"], function(query){
|
||
|
// | query(".toggleMe").toggleClass("toggleMe");
|
||
|
// | });
|
||
|
|
||
|
node = dom.byId(node);
|
||
|
if(condition === undefined){
|
||
|
classStr = str2array(classStr);
|
||
|
for(var i = 0, len = classStr.length, c; i < len; ++i){
|
||
|
c = classStr[i];
|
||
|
cls[cls.contains(node, c) ? "remove" : "add"](node, c);
|
||
|
}
|
||
|
}else{
|
||
|
cls[condition ? "add" : "remove"](node, classStr);
|
||
|
}
|
||
|
return condition; // Boolean
|
||
|
}
|
||
|
};
|
||
|
|
||
|
return cls;
|
||
|
});
|
||
|
|
||
|
},
|
||
|
'dojo/_base/NodeList':function(){
|
||
|
define(["./kernel", "../query", "./array", "./html", "../NodeList-dom"], function(dojo, query, array){
|
||
|
// module:
|
||
|
// dojo/_base/NodeList
|
||
|
|
||
|
/*=====
|
||
|
return {
|
||
|
// summary:
|
||
|
// This module extends dojo/NodeList with the legacy connect(), coords(),
|
||
|
// blur(), focus(), change(), click(), error(), keydown(), keypress(),
|
||
|
// keyup(), load(), mousedown(), mouseenter(), mouseleave(), mousemove(),
|
||
|
// mouseout(), mouseover(), mouseup(), and submit() methods.
|
||
|
};
|
||
|
=====*/
|
||
|
|
||
|
var NodeList = query.NodeList,
|
||
|
nlp = NodeList.prototype;
|
||
|
|
||
|
nlp.connect = NodeList._adaptAsForEach(function(){
|
||
|
// don't bind early to dojo.connect since we no longer explicitly depend on it
|
||
|
return dojo.connect.apply(this, arguments);
|
||
|
});
|
||
|
/*=====
|
||
|
nlp.connect = function(methodName, objOrFunc, funcName){
|
||
|
// summary:
|
||
|
// Attach event handlers to every item of the NodeList. Uses dojo.connect()
|
||
|
// so event properties are normalized.
|
||
|
//
|
||
|
// Application must manually require() "dojo/_base/connect" before using this method.
|
||
|
// methodName: String
|
||
|
// the name of the method to attach to. For DOM events, this should be
|
||
|
// the lower-case name of the event
|
||
|
// objOrFunc: Object|Function|String
|
||
|
// if 2 arguments are passed (methodName, objOrFunc), objOrFunc should
|
||
|
// reference a function or be the name of the function in the global
|
||
|
// namespace to attach. If 3 arguments are provided
|
||
|
// (methodName, objOrFunc, funcName), objOrFunc must be the scope to
|
||
|
// locate the bound function in
|
||
|
// funcName: String?
|
||
|
// optional. A string naming the function in objOrFunc to bind to the
|
||
|
// event. May also be a function reference.
|
||
|
// example:
|
||
|
// add an onclick handler to every button on the page
|
||
|
// | query("div:nth-child(odd)").connect("onclick", function(e){
|
||
|
// | console.log("clicked!");
|
||
|
// | });
|
||
|
// example:
|
||
|
// attach foo.bar() to every odd div's onmouseover
|
||
|
// | query("div:nth-child(odd)").connect("onmouseover", foo, "bar");
|
||
|
|
||
|
return null; // NodeList
|
||
|
};
|
||
|
=====*/
|
||
|
|
||
|
nlp.coords = NodeList._adaptAsMap(dojo.coords);
|
||
|
/*=====
|
||
|
nlp.coords = function(){
|
||
|
// summary:
|
||
|
// Deprecated: Use position() for border-box x/y/w/h
|
||
|
// or marginBox() for margin-box w/h/l/t.
|
||
|
// Returns the box objects of all elements in a node list as
|
||
|
// an Array (*not* a NodeList). Acts like `domGeom.coords`, though assumes
|
||
|
// the node passed is each node in this list.
|
||
|
|
||
|
return []; // Array
|
||
|
};
|
||
|
=====*/
|
||
|
|
||
|
NodeList.events = [
|
||
|
// summary:
|
||
|
// list of all DOM events used in NodeList
|
||
|
"blur", "focus", "change", "click", "error", "keydown", "keypress",
|
||
|
"keyup", "load", "mousedown", "mouseenter", "mouseleave", "mousemove",
|
||
|
"mouseout", "mouseover", "mouseup", "submit"
|
||
|
];
|
||
|
|
||
|
// FIXME: pseudo-doc the above automatically generated on-event functions
|
||
|
|
||
|
// syntactic sugar for DOM events
|
||
|
array.forEach(NodeList.events, function(evt){
|
||
|
var _oe = "on" + evt;
|
||
|
nlp[_oe] = function(a, b){
|
||
|
return this.connect(_oe, a, b);
|
||
|
};
|
||
|
// FIXME: should these events trigger publishes?
|
||
|
/*
|
||
|
return (a ? this.connect(_oe, a, b) :
|
||
|
this.forEach(function(n){
|
||
|
// FIXME:
|
||
|
// listeners get buried by
|
||
|
// addEventListener and can't be dug back
|
||
|
// out to be triggered externally.
|
||
|
// see:
|
||
|
// http://developer.mozilla.org/en/docs/DOM:element
|
||
|
|
||
|
console.log(n, evt, _oe);
|
||
|
|
||
|
// FIXME: need synthetic event support!
|
||
|
var _e = { target: n, faux: true, type: evt };
|
||
|
// dojo._event_listener._synthesizeEvent({}, { target: n, faux: true, type: evt });
|
||
|
try{ n[evt](_e); }catch(e){ console.log(e); }
|
||
|
try{ n[_oe](_e); }catch(e){ console.log(e); }
|
||
|
})
|
||
|
);
|
||
|
*/
|
||
|
}
|
||
|
);
|
||
|
|
||
|
dojo.NodeList = NodeList;
|
||
|
return NodeList;
|
||
|
});
|
||
|
|
||
|
},
|
||
|
'dojo/query':function(){
|
||
|
define(["./_base/kernel", "./has", "./dom", "./on", "./_base/array", "./_base/lang", "./selector/_loader", "./selector/_loader!default"],
|
||
|
function(dojo, has, dom, on, array, lang, loader, defaultEngine){
|
||
|
|
||
|
"use strict";
|
||
|
|
||
|
has.add("array-extensible", function(){
|
||
|
// test to see if we can extend an array (not supported in old IE)
|
||
|
return lang.delegate([], {length: 1}).length == 1 && !has("bug-for-in-skips-shadowed");
|
||
|
});
|
||
|
|
||
|
var ap = Array.prototype, aps = ap.slice, apc = ap.concat, forEach = array.forEach;
|
||
|
|
||
|
var tnl = function(/*Array*/ a, /*dojo/NodeList?*/ parent, /*Function?*/ NodeListCtor){
|
||
|
// summary:
|
||
|
// decorate an array to make it look like a `dojo/NodeList`.
|
||
|
// a:
|
||
|
// Array of nodes to decorate.
|
||
|
// parent:
|
||
|
// An optional parent NodeList that generated the current
|
||
|
// list of nodes. Used to call _stash() so the parent NodeList
|
||
|
// can be accessed via end() later.
|
||
|
// NodeListCtor:
|
||
|
// An optional constructor function to use for any
|
||
|
// new NodeList calls. This allows a certain chain of
|
||
|
// NodeList calls to use a different object than dojo/NodeList.
|
||
|
var nodeList = new (NodeListCtor || this._NodeListCtor || nl)(a);
|
||
|
return parent ? nodeList._stash(parent) : nodeList;
|
||
|
};
|
||
|
|
||
|
var loopBody = function(f, a, o){
|
||
|
a = [0].concat(aps.call(a, 0));
|
||
|
o = o || dojo.global;
|
||
|
return function(node){
|
||
|
a[0] = node;
|
||
|
return f.apply(o, a);
|
||
|
};
|
||
|
};
|
||
|
|
||
|
// adapters
|
||
|
|
||
|
var adaptAsForEach = function(f, o){
|
||
|
// summary:
|
||
|
// adapts a single node function to be used in the forEach-type
|
||
|
// actions. The initial object is returned from the specialized
|
||
|
// function.
|
||
|
// f: Function
|
||
|
// a function to adapt
|
||
|
// o: Object?
|
||
|
// an optional context for f
|
||
|
return function(){
|
||
|
this.forEach(loopBody(f, arguments, o));
|
||
|
return this; // Object
|
||
|
};
|
||
|
};
|
||
|
|
||
|
var adaptAsMap = function(f, o){
|
||
|
// summary:
|
||
|
// adapts a single node function to be used in the map-type
|
||
|
// actions. The return is a new array of values, as via `dojo/_base/array.map`
|
||
|
// f: Function
|
||
|
// a function to adapt
|
||
|
// o: Object?
|
||
|
// an optional context for f
|
||
|
return function(){
|
||
|
return this.map(loopBody(f, arguments, o));
|
||
|
};
|
||
|
};
|
||
|
|
||
|
var adaptAsFilter = function(f, o){
|
||
|
// summary:
|
||
|
// adapts a single node function to be used in the filter-type actions
|
||
|
// f: Function
|
||
|
// a function to adapt
|
||
|
// o: Object?
|
||
|
// an optional context for f
|
||
|
return function(){
|
||
|
return this.filter(loopBody(f, arguments, o));
|
||
|
};
|
||
|
};
|
||
|
|
||
|
var adaptWithCondition = function(f, g, o){
|
||
|
// summary:
|
||
|
// adapts a single node function to be used in the map-type
|
||
|
// actions, behaves like forEach() or map() depending on arguments
|
||
|
// f: Function
|
||
|
// a function to adapt
|
||
|
// g: Function
|
||
|
// a condition function, if true runs as map(), otherwise runs as forEach()
|
||
|
// o: Object?
|
||
|
// an optional context for f and g
|
||
|
return function(){
|
||
|
var a = arguments, body = loopBody(f, a, o);
|
||
|
if(g.call(o || dojo.global, a)){
|
||
|
return this.map(body); // self
|
||
|
}
|
||
|
this.forEach(body);
|
||
|
return this; // self
|
||
|
};
|
||
|
};
|
||
|
|
||
|
var NodeList = function(array){
|
||
|
// summary:
|
||
|
// Array-like object which adds syntactic
|
||
|
// sugar for chaining, common iteration operations, animation, and
|
||
|
// node manipulation. NodeLists are most often returned as the
|
||
|
// result of dojo/query() calls.
|
||
|
// description:
|
||
|
// NodeList instances provide many utilities that reflect
|
||
|
// core Dojo APIs for Array iteration and manipulation, DOM
|
||
|
// manipulation, and event handling. Instead of needing to dig up
|
||
|
// functions in the dojo package, NodeLists generally make the
|
||
|
// full power of Dojo available for DOM manipulation tasks in a
|
||
|
// simple, chainable way.
|
||
|
// example:
|
||
|
// create a node list from a node
|
||
|
// | require(["dojo/query", "dojo/dom"
|
||
|
// | ], function(query, dom){
|
||
|
// | query.NodeList(dom.byId("foo"));
|
||
|
// | });
|
||
|
// example:
|
||
|
// get a NodeList from a CSS query and iterate on it
|
||
|
// | require(["dojo/on", "dojo/dom"
|
||
|
// | ], function(on, dom){
|
||
|
// | var l = query(".thinger");
|
||
|
// | l.forEach(function(node, index, nodeList){
|
||
|
// | console.log(index, node.innerHTML);
|
||
|
// | });
|
||
|
// | });
|
||
|
// example:
|
||
|
// use native and Dojo-provided array methods to manipulate a
|
||
|
// NodeList without needing to use dojo.* functions explicitly:
|
||
|
// | require(["dojo/query", "dojo/dom-construct", "dojo/dom"
|
||
|
// | ], function(query, domConstruct, dom){
|
||
|
// | var l = query(".thinger");
|
||
|
// | // since NodeLists are real arrays, they have a length
|
||
|
// | // property that is both readable and writable and
|
||
|
// | // push/pop/shift/unshift methods
|
||
|
// | console.log(l.length);
|
||
|
// | l.push(domConstruct.create("span"));
|
||
|
// |
|
||
|
// | // dojo's normalized array methods work too:
|
||
|
// | console.log( l.indexOf(dom.byId("foo")) );
|
||
|
// | // ...including the special "function as string" shorthand
|
||
|
// | console.log( l.every("item.nodeType == 1") );
|
||
|
// |
|
||
|
// | // NodeLists can be [..] indexed, or you can use the at()
|
||
|
// | // function to get specific items wrapped in a new NodeList:
|
||
|
// | var node = l[3]; // the 4th element
|
||
|
// | var newList = l.at(1, 3); // the 2nd and 4th elements
|
||
|
// | });
|
||
|
// example:
|
||
|
// chainability is a key advantage of NodeLists:
|
||
|
// | require(["dojo/query", "dojo/NodeList-dom"
|
||
|
// | ], function(query){
|
||
|
// | query(".thinger")
|
||
|
// | .onclick(function(e){ /* ... */ })
|
||
|
// | .at(1, 3, 8) // get a subset
|
||
|
// | .style("padding", "5px")
|
||
|
// | .forEach(console.log);
|
||
|
// | });
|
||
|
|
||
|
var isNew = this instanceof nl && has("array-extensible");
|
||
|
if(typeof array == "number"){
|
||
|
array = Array(array);
|
||
|
}
|
||
|
var nodeArray = (array && "length" in array) ? array : arguments;
|
||
|
if(isNew || !nodeArray.sort){
|
||
|
// make sure it's a real array before we pass it on to be wrapped
|
||
|
var target = isNew ? this : [],
|
||
|
l = target.length = nodeArray.length;
|
||
|
for(var i = 0; i < l; i++){
|
||
|
target[i] = nodeArray[i];
|
||
|
}
|
||
|
if(isNew){
|
||
|
// called with new operator, this means we are going to use this instance and push
|
||
|
// the nodes on to it. This is usually much faster since the NodeList properties
|
||
|
// don't need to be copied (unless the list of nodes is extremely large).
|
||
|
return target;
|
||
|
}
|
||
|
nodeArray = target;
|
||
|
}
|
||
|
// called without new operator, use a real array and copy prototype properties,
|
||
|
// this is slower and exists for back-compat. Should be removed in 2.0.
|
||
|
lang._mixin(nodeArray, nlp);
|
||
|
nodeArray._NodeListCtor = function(array){
|
||
|
// call without new operator to preserve back-compat behavior
|
||
|
return nl(array);
|
||
|
};
|
||
|
return nodeArray;
|
||
|
};
|
||
|
|
||
|
var nl = NodeList, nlp = nl.prototype =
|
||
|
has("array-extensible") ? [] : {};// extend an array if it is extensible
|
||
|
|
||
|
// expose adapters and the wrapper as private functions
|
||
|
|
||
|
nl._wrap = nlp._wrap = tnl;
|
||
|
nl._adaptAsMap = adaptAsMap;
|
||
|
nl._adaptAsForEach = adaptAsForEach;
|
||
|
nl._adaptAsFilter = adaptAsFilter;
|
||
|
nl._adaptWithCondition = adaptWithCondition;
|
||
|
|
||
|
// mass assignment
|
||
|
|
||
|
// add array redirectors
|
||
|
forEach(["slice", "splice"], function(name){
|
||
|
var f = ap[name];
|
||
|
//Use a copy of the this array via this.slice() to allow .end() to work right in the splice case.
|
||
|
// CANNOT apply ._stash()/end() to splice since it currently modifies
|
||
|
// the existing this array -- it would break backward compatibility if we copy the array before
|
||
|
// the splice so that we can use .end(). So only doing the stash option to this._wrap for slice.
|
||
|
nlp[name] = function(){ return this._wrap(f.apply(this, arguments), name == "slice" ? this : null); };
|
||
|
});
|
||
|
// concat should be here but some browsers with native NodeList have problems with it
|
||
|
|
||
|
// add array.js redirectors
|
||
|
forEach(["indexOf", "lastIndexOf", "every", "some"], function(name){
|
||
|
var f = array[name];
|
||
|
nlp[name] = function(){ return f.apply(dojo, [this].concat(aps.call(arguments, 0))); };
|
||
|
});
|
||
|
|
||
|
lang.extend(NodeList, {
|
||
|
// copy the constructors
|
||
|
constructor: nl,
|
||
|
_NodeListCtor: nl,
|
||
|
toString: function(){
|
||
|
// Array.prototype.toString can't be applied to objects, so we use join
|
||
|
return this.join(",");
|
||
|
},
|
||
|
_stash: function(parent){
|
||
|
// summary:
|
||
|
// private function to hold to a parent NodeList. end() to return the parent NodeList.
|
||
|
//
|
||
|
// example:
|
||
|
// How to make a `dojo/NodeList` method that only returns the third node in
|
||
|
// the dojo/NodeList but allows access to the original NodeList by using this._stash:
|
||
|
// | require(["dojo/query", "dojo/_base/lang", "dojo/NodeList", "dojo/NodeList-dom"
|
||
|
// | ], function(query, lang){
|
||
|
// | lang.extend(NodeList, {
|
||
|
// | third: function(){
|
||
|
// | var newNodeList = NodeList(this[2]);
|
||
|
// | return newNodeList._stash(this);
|
||
|
// | }
|
||
|
// | });
|
||
|
// | // then see how _stash applies a sub-list, to be .end()'ed out of
|
||
|
// | query(".foo")
|
||
|
// | .third()
|
||
|
// | .addClass("thirdFoo")
|
||
|
// | .end()
|
||
|
// | // access to the orig .foo list
|
||
|
// | .removeClass("foo")
|
||
|
// | });
|
||
|
//
|
||
|
this._parent = parent;
|
||
|
return this; // dojo/NodeList
|
||
|
},
|
||
|
|
||
|
on: function(eventName, listener){
|
||
|
// summary:
|
||
|
// Listen for events on the nodes in the NodeList. Basic usage is:
|
||
|
//
|
||
|
// example:
|
||
|
// | require(["dojo/query"
|
||
|
// | ], function(query){
|
||
|
// | query(".my-class").on("click", listener);
|
||
|
// This supports event delegation by using selectors as the first argument with the event names as
|
||
|
// pseudo selectors. For example:
|
||
|
// | query("#my-list").on("li:click", listener);
|
||
|
// This will listen for click events within `<li>` elements that are inside the `#my-list` element.
|
||
|
// Because on supports CSS selector syntax, we can use comma-delimited events as well:
|
||
|
// | query("#my-list").on("li button:mouseover, li:click", listener);
|
||
|
// | });
|
||
|
var handles = this.map(function(node){
|
||
|
return on(node, eventName, listener); // TODO: apply to the NodeList so the same selector engine is used for matches
|
||
|
});
|
||
|
handles.remove = function(){
|
||
|
for(var i = 0; i < handles.length; i++){
|
||
|
handles[i].remove();
|
||
|
}
|
||
|
};
|
||
|
return handles;
|
||
|
},
|
||
|
|
||
|
end: function(){
|
||
|
// summary:
|
||
|
// Ends use of the current `NodeList` by returning the previous NodeList
|
||
|
// that generated the current NodeList.
|
||
|
// description:
|
||
|
// Returns the `NodeList` that generated the current `NodeList`. If there
|
||
|
// is no parent NodeList, an empty NodeList is returned.
|
||
|
// example:
|
||
|
// | require(["dojo/query", "dojo/NodeList-dom"
|
||
|
// | ], function(query){
|
||
|
// | query("a")
|
||
|
// | .filter(".disabled")
|
||
|
// | // operate on the anchors that only have a disabled class
|
||
|
// | .style("color", "grey")
|
||
|
// | .end()
|
||
|
// | // jump back to the list of anchors
|
||
|
// | .style(...)
|
||
|
// | });
|
||
|
//
|
||
|
if(this._parent){
|
||
|
return this._parent;
|
||
|
}else{
|
||
|
//Just return empty list.
|
||
|
return new this._NodeListCtor(0);
|
||
|
}
|
||
|
},
|
||
|
|
||
|
// http://developer.mozilla.org/en/docs/Core_JavaScript_1.5_Reference:Global_Objects:Array#Methods
|
||
|
|
||
|
// FIXME: handle return values for #3244
|
||
|
// http://trac.dojotoolkit.org/ticket/3244
|
||
|
|
||
|
// FIXME:
|
||
|
// need to wrap or implement:
|
||
|
// join (perhaps w/ innerHTML/outerHTML overload for toString() of items?)
|
||
|
// reduce
|
||
|
// reduceRight
|
||
|
|
||
|
/*=====
|
||
|
slice: function(begin, end){
|
||
|
// summary:
|
||
|
// Returns a new NodeList, maintaining this one in place
|
||
|
// description:
|
||
|
// This method behaves exactly like the Array.slice method
|
||
|
// with the caveat that it returns a `dojo/NodeList` and not a
|
||
|
// raw Array. For more details, see Mozilla's [slice
|
||
|
// documentation](https://developer.mozilla.org/en/JavaScript/Reference/Global_Objects/Array/slice)
|
||
|
// begin: Integer
|
||
|
// Can be a positive or negative integer, with positive
|
||
|
// integers noting the offset to begin at, and negative
|
||
|
// integers denoting an offset from the end (i.e., to the left
|
||
|
// of the end)
|
||
|
// end: Integer?
|
||
|
// Optional parameter to describe what position relative to
|
||
|
// the NodeList's zero index to end the slice at. Like begin,
|
||
|
// can be positive or negative.
|
||
|
return this._wrap(a.slice.apply(this, arguments));
|
||
|
},
|
||
|
|
||
|
splice: function(index, howmany, item){
|
||
|
// summary:
|
||
|
// Returns a new NodeList, manipulating this NodeList based on
|
||
|
// the arguments passed, potentially splicing in new elements
|
||
|
// at an offset, optionally deleting elements
|
||
|
// description:
|
||
|
// This method behaves exactly like the Array.splice method
|
||
|
// with the caveat that it returns a `dojo/NodeList` and not a
|
||
|
// raw Array. For more details, see Mozilla's [splice
|
||
|
// documentation](https://developer.mozilla.org/en/JavaScript/Reference/Global_Objects/Array/splice)
|
||
|
// For backwards compatibility, calling .end() on the spliced NodeList
|
||
|
// does not return the original NodeList -- splice alters the NodeList in place.
|
||
|
// index: Integer
|
||
|
// begin can be a positive or negative integer, with positive
|
||
|
// integers noting the offset to begin at, and negative
|
||
|
// integers denoting an offset from the end (i.e., to the left
|
||
|
// of the end)
|
||
|
// howmany: Integer?
|
||
|
// Optional parameter to describe what position relative to
|
||
|
// the NodeList's zero index to end the slice at. Like begin,
|
||
|
// can be positive or negative.
|
||
|
// item: Object...?
|
||
|
// Any number of optional parameters may be passed in to be
|
||
|
// spliced into the NodeList
|
||
|
return this._wrap(a.splice.apply(this, arguments)); // dojo/NodeList
|
||
|
},
|
||
|
|
||
|
indexOf: function(value, fromIndex){
|
||
|
// summary:
|
||
|
// see `dojo/_base/array.indexOf()`. The primary difference is that the acted-on
|
||
|
// array is implicitly this NodeList
|
||
|
// value: Object
|
||
|
// The value to search for.
|
||
|
// fromIndex: Integer?
|
||
|
// The location to start searching from. Optional. Defaults to 0.
|
||
|
// description:
|
||
|
// For more details on the behavior of indexOf, see Mozilla's
|
||
|
// [indexOf
|
||
|
// docs](https://developer.mozilla.org/en/JavaScript/Reference/Global_Objects/Array/indexOf)
|
||
|
// returns:
|
||
|
// Positive Integer or 0 for a match, -1 of not found.
|
||
|
return d.indexOf(this, value, fromIndex); // Integer
|
||
|
},
|
||
|
|
||
|
lastIndexOf: function(value, fromIndex){
|
||
|
// summary:
|
||
|
// see `dojo/_base/array.lastIndexOf()`. The primary difference is that the
|
||
|
// acted-on array is implicitly this NodeList
|
||
|
// description:
|
||
|
// For more details on the behavior of lastIndexOf, see
|
||
|
// Mozilla's [lastIndexOf
|
||
|
// docs](https://developer.mozilla.org/en/JavaScript/Reference/Global_Objects/Array/lastIndexOf)
|
||
|
// value: Object
|
||
|
// The value to search for.
|
||
|
// fromIndex: Integer?
|
||
|
// The location to start searching from. Optional. Defaults to 0.
|
||
|
// returns:
|
||
|
// Positive Integer or 0 for a match, -1 of not found.
|
||
|
return d.lastIndexOf(this, value, fromIndex); // Integer
|
||
|
},
|
||
|
|
||
|
every: function(callback, thisObject){
|
||
|
// summary:
|
||
|
// see `dojo/_base/array.every()` and the [Array.every
|
||
|
// docs](https://developer.mozilla.org/en/JavaScript/Reference/Global_Objects/Array/every).
|
||
|
// Takes the same structure of arguments and returns as
|
||
|
// dojo/_base/array.every() with the caveat that the passed array is
|
||
|
// implicitly this NodeList
|
||
|
// callback: Function
|
||
|
// the callback
|
||
|
// thisObject: Object?
|
||
|
// the context
|
||
|
return d.every(this, callback, thisObject); // Boolean
|
||
|
},
|
||
|
|
||
|
some: function(callback, thisObject){
|
||
|
// summary:
|
||
|
// Takes the same structure of arguments and returns as
|
||
|
// `dojo/_base/array.some()` with the caveat that the passed array is
|
||
|
// implicitly this NodeList. See `dojo/_base/array.some()` and Mozilla's
|
||
|
// [Array.some
|
||
|
// documentation](https://developer.mozilla.org/en/JavaScript/Reference/Global_Objects/Array/some).
|
||
|
// callback: Function
|
||
|
// the callback
|
||
|
// thisObject: Object?
|
||
|
// the context
|
||
|
return d.some(this, callback, thisObject); // Boolean
|
||
|
},
|
||
|
=====*/
|
||
|
|
||
|
concat: function(item){
|
||
|
// summary:
|
||
|
// Returns a new NodeList comprised of items in this NodeList
|
||
|
// as well as items passed in as parameters
|
||
|
// description:
|
||
|
// This method behaves exactly like the Array.concat method
|
||
|
// with the caveat that it returns a `NodeList` and not a
|
||
|
// raw Array. For more details, see the [Array.concat
|
||
|
// docs](https://developer.mozilla.org/en/JavaScript/Reference/Global_Objects/Array/concat)
|
||
|
// item: Object?
|
||
|
// Any number of optional parameters may be passed in to be
|
||
|
// spliced into the NodeList
|
||
|
|
||
|
//return this._wrap(apc.apply(this, arguments));
|
||
|
// the line above won't work for the native NodeList, or for Dojo NodeLists either :-(
|
||
|
|
||
|
// implementation notes:
|
||
|
// Array.concat() doesn't recognize native NodeLists or Dojo NodeLists
|
||
|
// as arrays, and so does not inline them into a unioned array, but
|
||
|
// appends them as single entities. Both the original NodeList and the
|
||
|
// items passed in as parameters must be converted to raw Arrays
|
||
|
// and then the concatenation result may be re-_wrap()ed as a Dojo NodeList.
|
||
|
|
||
|
var t = aps.call(this, 0),
|
||
|
m = array.map(arguments, function(a){
|
||
|
return aps.call(a, 0);
|
||
|
});
|
||
|
return this._wrap(apc.apply(t, m), this); // dojo/NodeList
|
||
|
},
|
||
|
|
||
|
map: function(/*Function*/ func, /*Function?*/ obj){
|
||
|
// summary:
|
||
|
// see `dojo/_base/array.map()`. The primary difference is that the acted-on
|
||
|
// array is implicitly this NodeList and the return is a
|
||
|
// NodeList (a subclass of Array)
|
||
|
return this._wrap(array.map(this, func, obj), this); // dojo/NodeList
|
||
|
},
|
||
|
|
||
|
forEach: function(callback, thisObj){
|
||
|
// summary:
|
||
|
// see `dojo/_base/array.forEach()`. The primary difference is that the acted-on
|
||
|
// array is implicitly this NodeList. If you want the option to break out
|
||
|
// of the forEach loop, use every() or some() instead.
|
||
|
forEach(this, callback, thisObj);
|
||
|
// non-standard return to allow easier chaining
|
||
|
return this; // dojo/NodeList
|
||
|
},
|
||
|
filter: function(/*String|Function*/ filter){
|
||
|
// summary:
|
||
|
// "masks" the built-in javascript filter() method (supported
|
||
|
// in Dojo via `dojo/_base/array.filter`) to support passing a simple
|
||
|
// string filter in addition to supporting filtering function
|
||
|
// objects.
|
||
|
// filter:
|
||
|
// If a string, a CSS rule like ".thinger" or "div > span".
|
||
|
// example:
|
||
|
// "regular" JS filter syntax as exposed in `dojo/_base/array.filter`:
|
||
|
// | require(["dojo/query", "dojo/NodeList-dom"
|
||
|
// | ], function(query){
|
||
|
// | query("*").filter(function(item){
|
||
|
// | // highlight every paragraph
|
||
|
// | return (item.nodeName == "p");
|
||
|
// | }).style("backgroundColor", "yellow");
|
||
|
// | });
|
||
|
// example:
|
||
|
// the same filtering using a CSS selector
|
||
|
// | require(["dojo/query", "dojo/NodeList-dom"
|
||
|
// | ], function(query){
|
||
|
// | query("*").filter("p").styles("backgroundColor", "yellow");
|
||
|
// | });
|
||
|
|
||
|
var a = arguments, items = this, start = 0;
|
||
|
if(typeof filter == "string"){ // inline'd type check
|
||
|
items = query._filterResult(this, a[0]);
|
||
|
if(a.length == 1){
|
||
|
// if we only got a string query, pass back the filtered results
|
||
|
return items._stash(this); // dojo/NodeList
|
||
|
}
|
||
|
// if we got a callback, run it over the filtered items
|
||
|
start = 1;
|
||
|
}
|
||
|
return this._wrap(array.filter(items, a[start], a[start + 1]), this); // dojo/NodeList
|
||
|
},
|
||
|
instantiate: function(/*String|Object*/ declaredClass, /*Object?*/ properties){
|
||
|
// summary:
|
||
|
// Create a new instance of a specified class, using the
|
||
|
// specified properties and each node in the NodeList as a
|
||
|
// srcNodeRef.
|
||
|
// example:
|
||
|
// Grabs all buttons in the page and converts them to dijit/form/Button's.
|
||
|
// | var buttons = query("button").instantiate(Button, {showLabel: true});
|
||
|
var c = lang.isFunction(declaredClass) ? declaredClass : lang.getObject(declaredClass);
|
||
|
properties = properties || {};
|
||
|
return this.forEach(function(node){
|
||
|
new c(properties, node);
|
||
|
}); // dojo/NodeList
|
||
|
},
|
||
|
at: function(/*===== index =====*/){
|
||
|
// summary:
|
||
|
// Returns a new NodeList comprised of items in this NodeList
|
||
|
// at the given index or indices.
|
||
|
//
|
||
|
// index: Integer...
|
||
|
// One or more 0-based indices of items in the current
|
||
|
// NodeList. A negative index will start at the end of the
|
||
|
// list and go backwards.
|
||
|
//
|
||
|
// example:
|
||
|
// Shorten the list to the first, second, and third elements
|
||
|
// | require(["dojo/query"
|
||
|
// | ], function(query){
|
||
|
// | query("a").at(0, 1, 2).forEach(fn);
|
||
|
// | });
|
||
|
//
|
||
|
// example:
|
||
|
// Retrieve the first and last elements of a unordered list:
|
||
|
// | require(["dojo/query"
|
||
|
// | ], function(query){
|
||
|
// | query("ul > li").at(0, -1).forEach(cb);
|
||
|
// | });
|
||
|
//
|
||
|
// example:
|
||
|
// Do something for the first element only, but end() out back to
|
||
|
// the original list and continue chaining:
|
||
|
// | require(["dojo/query"
|
||
|
// | ], function(query){
|
||
|
// | query("a").at(0).onclick(fn).end().forEach(function(n){
|
||
|
// | console.log(n); // all anchors on the page.
|
||
|
// | })
|
||
|
// | });
|
||
|
|
||
|
var t = new this._NodeListCtor(0);
|
||
|
forEach(arguments, function(i){
|
||
|
if(i < 0){ i = this.length + i; }
|
||
|
if(this[i]){ t.push(this[i]); }
|
||
|
}, this);
|
||
|
return t._stash(this); // dojo/NodeList
|
||
|
}
|
||
|
});
|
||
|
|
||
|
function queryForEngine(engine, NodeList){
|
||
|
var query = function(/*String*/ query, /*String|DOMNode?*/ root){
|
||
|
// summary:
|
||
|
// Returns nodes which match the given CSS selector, searching the
|
||
|
// entire document by default but optionally taking a node to scope
|
||
|
// the search by. Returns an instance of NodeList.
|
||
|
if(typeof root == "string"){
|
||
|
root = dom.byId(root);
|
||
|
if(!root){
|
||
|
return new NodeList([]);
|
||
|
}
|
||
|
}
|
||
|
var results = typeof query == "string" ? engine(query, root) : query ? (query.end && query.on) ? query : [query] : [];
|
||
|
if(results.end && results.on){
|
||
|
// already wrapped
|
||
|
return results;
|
||
|
}
|
||
|
return new NodeList(results);
|
||
|
};
|
||
|
query.matches = engine.match || function(node, selector, root){
|
||
|
// summary:
|
||
|
// Test to see if a node matches a selector
|
||
|
return query.filter([node], selector, root).length > 0;
|
||
|
};
|
||
|
// the engine provides a filtering function, use it to for matching
|
||
|
query.filter = engine.filter || function(nodes, selector, root){
|
||
|
// summary:
|
||
|
// Filters an array of nodes. Note that this does not guarantee to return a NodeList, just an array.
|
||
|
return query(selector, root).filter(function(node){
|
||
|
return array.indexOf(nodes, node) > -1;
|
||
|
});
|
||
|
};
|
||
|
if(typeof engine != "function"){
|
||
|
var search = engine.search;
|
||
|
engine = function(selector, root){
|
||
|
// Slick does it backwards (or everyone else does it backwards, probably the latter)
|
||
|
return search(root || document, selector);
|
||
|
};
|
||
|
}
|
||
|
return query;
|
||
|
}
|
||
|
var query = queryForEngine(defaultEngine, NodeList);
|
||
|
/*=====
|
||
|
query = function(selector, context){
|
||
|
// summary:
|
||
|
// This modules provides DOM querying functionality. The module export is a function
|
||
|
// that can be used to query for DOM nodes by CSS selector and returns a NodeList
|
||
|
// representing the matching nodes.
|
||
|
// selector: String
|
||
|
// A CSS selector to search for.
|
||
|
// context: String|DomNode?
|
||
|
// An optional context to limit the searching scope. Only nodes under `context` will be
|
||
|
// scanned.
|
||
|
// example:
|
||
|
// add an onclick handler to every submit button in the document
|
||
|
// which causes the form to be sent via Ajax instead:
|
||
|
// | require(["dojo/query", "dojo/request", "dojo/dom-form", "dojo/dom-construct", "dojo/dom-style"
|
||
|
// | ], function(query, request, domForm, domConstruct, domStyle){
|
||
|
// | query("input[type='submit']").on("click", function(e){
|
||
|
// | e.preventDefault(); // prevent sending the form
|
||
|
// | var btn = e.target;
|
||
|
// | request.post("http://example.com/", {
|
||
|
// | data: domForm.toObject(btn.form)
|
||
|
// | }).then(function(response){
|
||
|
// | // replace the form with the response
|
||
|
// | domConstruct.create(div, {innerHTML: response}, btn.form, "after");
|
||
|
// | domStyle.set(btn.form, "display", "none");
|
||
|
// | });
|
||
|
// | });
|
||
|
// | });
|
||
|
//
|
||
|
// description:
|
||
|
// dojo/query is responsible for loading the appropriate query engine and wrapping
|
||
|
// its results with a `NodeList`. You can use dojo/query with a specific selector engine
|
||
|
// by using it as a plugin. For example, if you installed the sizzle package, you could
|
||
|
// use it as the selector engine with:
|
||
|
// | require(["dojo/query!sizzle"], function(query){
|
||
|
// | query("div")...
|
||
|
//
|
||
|
// The id after the ! can be a module id of the selector engine or one of the following values:
|
||
|
//
|
||
|
// - acme: This is the default engine used by Dojo base, and will ensure that the full
|
||
|
// Acme engine is always loaded.
|
||
|
//
|
||
|
// - css2: If the browser has a native selector engine, this will be used, otherwise a
|
||
|
// very minimal lightweight selector engine will be loaded that can do simple CSS2 selectors
|
||
|
// (by #id, .class, tag, and [name=value] attributes, with standard child or descendant (>)
|
||
|
// operators) and nothing more.
|
||
|
//
|
||
|
// - css2.1: If the browser has a native selector engine, this will be used, otherwise the
|
||
|
// full Acme engine will be loaded.
|
||
|
//
|
||
|
// - css3: If the browser has a native selector engine with support for CSS3 pseudo
|
||
|
// selectors (most modern browsers except IE8), this will be used, otherwise the
|
||
|
// full Acme engine will be loaded.
|
||
|
//
|
||
|
// - Or the module id of a selector engine can be used to explicitly choose the selector engine
|
||
|
//
|
||
|
// For example, if you are using CSS3 pseudo selectors in module, you can specify that
|
||
|
// you will need support them with:
|
||
|
// | require(["dojo/query!css3"], function(query){
|
||
|
// | query('#t > h3:nth-child(odd)')...
|
||
|
//
|
||
|
// You can also choose the selector engine/load configuration by setting the query-selector:
|
||
|
// For example:
|
||
|
// | <script data-dojo-config="query-selector:'css3'" src="dojo.js"></script>
|
||
|
//
|
||
|
return new NodeList(); // dojo/NodeList
|
||
|
};
|
||
|
=====*/
|
||
|
|
||
|
// the query that is returned from this module is slightly different than dojo.query,
|
||
|
// because dojo.query has to maintain backwards compatibility with returning a
|
||
|
// true array which has performance problems. The query returned from the module
|
||
|
// does not use true arrays, but rather inherits from Array, making it much faster to
|
||
|
// instantiate.
|
||
|
dojo.query = queryForEngine(defaultEngine, function(array){
|
||
|
// call it without the new operator to invoke the back-compat behavior that returns a true array
|
||
|
return NodeList(array); // dojo/NodeList
|
||
|
});
|
||
|
|
||
|
query.load = function(id, parentRequire, loaded){
|
||
|
// summary:
|
||
|
// can be used as AMD plugin to conditionally load new query engine
|
||
|
// example:
|
||
|
// | require(["dojo/query!custom"], function(qsa){
|
||
|
// | // loaded selector/custom.js as engine
|
||
|
// | qsa("#foobar").forEach(...);
|
||
|
// | });
|
||
|
loader.load(id, parentRequire, function(engine){
|
||
|
loaded(queryForEngine(engine, NodeList));
|
||
|
});
|
||
|
};
|
||
|
|
||
|
dojo._filterQueryResult = query._filterResult = function(nodes, selector, root){
|
||
|
return new NodeList(query.filter(nodes, selector, root));
|
||
|
};
|
||
|
dojo.NodeList = query.NodeList = NodeList;
|
||
|
return query;
|
||
|
});
|
||
|
|
||
|
},
|
||
|
'dojo/selector/acme':function(){
|
||
|
define([
|
||
|
"../dom", "../sniff", "../_base/array", "../_base/lang", "../_base/window"
|
||
|
], function(dom, has, array, lang, win){
|
||
|
|
||
|
// module:
|
||
|
// dojo/selector/acme
|
||
|
|
||
|
/*
|
||
|
acme architectural overview:
|
||
|
|
||
|
acme is a relatively full-featured CSS3 query library. It is
|
||
|
designed to take any valid CSS3 selector and return the nodes matching
|
||
|
the selector. To do this quickly, it processes queries in several
|
||
|
steps, applying caching where profitable.
|
||
|
|
||
|
The steps (roughly in reverse order of the way they appear in the code):
|
||
|
1.) check to see if we already have a "query dispatcher"
|
||
|
- if so, use that with the given parameterization. Skip to step 4.
|
||
|
2.) attempt to determine which branch to dispatch the query to:
|
||
|
- JS (optimized DOM iteration)
|
||
|
- native (FF3.1+, Safari 3.1+, IE 8+)
|
||
|
3.) tokenize and convert to executable "query dispatcher"
|
||
|
- this is where the lion's share of the complexity in the
|
||
|
system lies. In the DOM version, the query dispatcher is
|
||
|
assembled as a chain of "yes/no" test functions pertaining to
|
||
|
a section of a simple query statement (".blah:nth-child(odd)"
|
||
|
but not "div div", which is 2 simple statements). Individual
|
||
|
statement dispatchers are cached (to prevent re-definition)
|
||
|
as are entire dispatch chains (to make re-execution of the
|
||
|
same query fast)
|
||
|
4.) the resulting query dispatcher is called in the passed scope
|
||
|
(by default the top-level document)
|
||
|
- for DOM queries, this results in a recursive, top-down
|
||
|
evaluation of nodes based on each simple query section
|
||
|
- for native implementations, this may mean working around spec
|
||
|
bugs. So be it.
|
||
|
5.) matched nodes are pruned to ensure they are unique (if necessary)
|
||
|
*/
|
||
|
|
||
|
|
||
|
////////////////////////////////////////////////////////////////////////
|
||
|
// Toolkit aliases
|
||
|
////////////////////////////////////////////////////////////////////////
|
||
|
|
||
|
// if you are extracting acme for use in your own system, you will
|
||
|
// need to provide these methods and properties. No other porting should be
|
||
|
// necessary, save for configuring the system to use a class other than
|
||
|
// dojo/NodeList as the return instance instantiator
|
||
|
var trim = lang.trim;
|
||
|
var each = array.forEach;
|
||
|
|
||
|
var getDoc = function(){ return win.doc; };
|
||
|
// NOTE(alex): the spec is idiotic. CSS queries should ALWAYS be case-sensitive, but nooooooo
|
||
|
var cssCaseBug = (getDoc().compatMode) == "BackCompat";
|
||
|
|
||
|
////////////////////////////////////////////////////////////////////////
|
||
|
// Global utilities
|
||
|
////////////////////////////////////////////////////////////////////////
|
||
|
|
||
|
|
||
|
var specials = ">~+";
|
||
|
|
||
|
// global thunk to determine whether we should treat the current query as
|
||
|
// case sensitive or not. This switch is flipped by the query evaluator
|
||
|
// based on the document passed as the context to search.
|
||
|
var caseSensitive = false;
|
||
|
|
||
|
// how high?
|
||
|
var yesman = function(){ return true; };
|
||
|
|
||
|
////////////////////////////////////////////////////////////////////////
|
||
|
// Tokenizer
|
||
|
////////////////////////////////////////////////////////////////////////
|
||
|
|
||
|
var getQueryParts = function(query){
|
||
|
// summary:
|
||
|
// state machine for query tokenization
|
||
|
// description:
|
||
|
// instead of using a brittle and slow regex-based CSS parser,
|
||
|
// acme implements an AST-style query representation. This
|
||
|
// representation is only generated once per query. For example,
|
||
|
// the same query run multiple times or under different root nodes
|
||
|
// does not re-parse the selector expression but instead uses the
|
||
|
// cached data structure. The state machine implemented here
|
||
|
// terminates on the last " " (space) character and returns an
|
||
|
// ordered array of query component structures (or "parts"). Each
|
||
|
// part represents an operator or a simple CSS filtering
|
||
|
// expression. The structure for parts is documented in the code
|
||
|
// below.
|
||
|
|
||
|
|
||
|
// NOTE:
|
||
|
// this code is designed to run fast and compress well. Sacrifices
|
||
|
// to readability and maintainability have been made. Your best
|
||
|
// bet when hacking the tokenizer is to put The Donnas on *really*
|
||
|
// loud (may we recommend their "Spend The Night" release?) and
|
||
|
// just assume you're gonna make mistakes. Keep the unit tests
|
||
|
// open and run them frequently. Knowing is half the battle ;-)
|
||
|
if(specials.indexOf(query.slice(-1)) >= 0){
|
||
|
// if we end with a ">", "+", or "~", that means we're implicitly
|
||
|
// searching all children, so make it explicit
|
||
|
query += " * ";
|
||
|
}else{
|
||
|
// if you have not provided a terminator, one will be provided for
|
||
|
// you...
|
||
|
query += " ";
|
||
|
}
|
||
|
|
||
|
var ts = function(/*Integer*/ s, /*Integer*/ e){
|
||
|
// trim and slice.
|
||
|
|
||
|
// take an index to start a string slice from and an end position
|
||
|
// and return a trimmed copy of that sub-string
|
||
|
return trim(query.slice(s, e));
|
||
|
};
|
||
|
|
||
|
// the overall data graph of the full query, as represented by queryPart objects
|
||
|
var queryParts = [];
|
||
|
|
||
|
|
||
|
// state keeping vars
|
||
|
var inBrackets = -1, inParens = -1, inMatchFor = -1,
|
||
|
inPseudo = -1, inClass = -1, inId = -1, inTag = -1, currentQuoteChar,
|
||
|
lc = "", cc = "", pStart;
|
||
|
|
||
|
// iteration vars
|
||
|
var x = 0, // index in the query
|
||
|
ql = query.length,
|
||
|
currentPart = null, // data structure representing the entire clause
|
||
|
_cp = null; // the current pseudo or attr matcher
|
||
|
|
||
|
// several temporary variables are assigned to this structure during a
|
||
|
// potential sub-expression match:
|
||
|
// attr:
|
||
|
// a string representing the current full attribute match in a
|
||
|
// bracket expression
|
||
|
// type:
|
||
|
// if there's an operator in a bracket expression, this is
|
||
|
// used to keep track of it
|
||
|
// value:
|
||
|
// the internals of parenthetical expression for a pseudo. for
|
||
|
// :nth-child(2n+1), value might be "2n+1"
|
||
|
|
||
|
var endTag = function(){
|
||
|
// called when the tokenizer hits the end of a particular tag name.
|
||
|
// Re-sets state variables for tag matching and sets up the matcher
|
||
|
// to handle the next type of token (tag or operator).
|
||
|
if(inTag >= 0){
|
||
|
var tv = (inTag == x) ? null : ts(inTag, x); // .toLowerCase();
|
||
|
currentPart[ (specials.indexOf(tv) < 0) ? "tag" : "oper" ] = tv;
|
||
|
inTag = -1;
|
||
|
}
|
||
|
};
|
||
|
|
||
|
var endId = function(){
|
||
|
// called when the tokenizer might be at the end of an ID portion of a match
|
||
|
if(inId >= 0){
|
||
|
currentPart.id = ts(inId, x).replace(/\\/g, "");
|
||
|
inId = -1;
|
||
|
}
|
||
|
};
|
||
|
|
||
|
var endClass = function(){
|
||
|
// called when the tokenizer might be at the end of a class name
|
||
|
// match. CSS allows for multiple classes, so we augment the
|
||
|
// current item with another class in its list
|
||
|
if(inClass >= 0){
|
||
|
currentPart.classes.push(ts(inClass + 1, x).replace(/\\/g, ""));
|
||
|
inClass = -1;
|
||
|
}
|
||
|
};
|
||
|
|
||
|
var endAll = function(){
|
||
|
// at the end of a simple fragment, so wall off the matches
|
||
|
endId();
|
||
|
endTag();
|
||
|
endClass();
|
||
|
};
|
||
|
|
||
|
var endPart = function(){
|
||
|
endAll();
|
||
|
if(inPseudo >= 0){
|
||
|
currentPart.pseudos.push({ name: ts(inPseudo + 1, x) });
|
||
|
}
|
||
|
// hint to the selector engine to tell it whether or not it
|
||
|
// needs to do any iteration. Many simple selectors don't, and
|
||
|
// we can avoid significant construction-time work by advising
|
||
|
// the system to skip them
|
||
|
currentPart.loops = (
|
||
|
currentPart.pseudos.length ||
|
||
|
currentPart.attrs.length ||
|
||
|
currentPart.classes.length );
|
||
|
|
||
|
currentPart.oquery = currentPart.query = ts(pStart, x); // save the full expression as a string
|
||
|
|
||
|
|
||
|
// otag/tag are hints to suggest to the system whether or not
|
||
|
// it's an operator or a tag. We save a copy of otag since the
|
||
|
// tag name is cast to upper-case in regular HTML matches. The
|
||
|
// system has a global switch to figure out if the current
|
||
|
// expression needs to be case sensitive or not and it will use
|
||
|
// otag or tag accordingly
|
||
|
currentPart.otag = currentPart.tag = (currentPart["oper"]) ? null : (currentPart.tag || "*");
|
||
|
|
||
|
if(currentPart.tag){
|
||
|
// if we're in a case-insensitive HTML doc, we likely want
|
||
|
// the toUpperCase when matching on element.tagName. If we
|
||
|
// do it here, we can skip the string op per node
|
||
|
// comparison
|
||
|
currentPart.tag = currentPart.tag.toUpperCase();
|
||
|
}
|
||
|
|
||
|
// add the part to the list
|
||
|
if(queryParts.length && (queryParts[queryParts.length-1].oper)){
|
||
|
// operators are always infix, so we remove them from the
|
||
|
// list and attach them to the next match. The evaluator is
|
||
|
// responsible for sorting out how to handle them.
|
||
|
currentPart.infixOper = queryParts.pop();
|
||
|
currentPart.query = currentPart.infixOper.query + " " + currentPart.query;
|
||
|
/*
|
||
|
console.debug( "swapping out the infix",
|
||
|
currentPart.infixOper,
|
||
|
"and attaching it to",
|
||
|
currentPart);
|
||
|
*/
|
||
|
}
|
||
|
queryParts.push(currentPart);
|
||
|
|
||
|
currentPart = null;
|
||
|
};
|
||
|
|
||
|
// iterate over the query, character by character, building up a
|
||
|
// list of query part objects
|
||
|
for(; lc=cc, cc=query.charAt(x), x < ql; x++){
|
||
|
// cc: the current character in the match
|
||
|
// lc: the last character (if any)
|
||
|
|
||
|
// someone is trying to escape something, so don't try to match any
|
||
|
// fragments. We assume we're inside a literal.
|
||
|
if(lc == "\\"){ continue; }
|
||
|
if(!currentPart){ // a part was just ended or none has yet been created
|
||
|
// NOTE: I hate all this alloc, but it's shorter than writing tons of if's
|
||
|
pStart = x;
|
||
|
// rules describe full CSS sub-expressions, like:
|
||
|
// #someId
|
||
|
// .className:first-child
|
||
|
// but not:
|
||
|
// thinger > div.howdy[type=thinger]
|
||
|
// the indidual components of the previous query would be
|
||
|
// split into 3 parts that would be represented a structure like:
|
||
|
// [
|
||
|
// {
|
||
|
// query: "thinger",
|
||
|
// tag: "thinger",
|
||
|
// },
|
||
|
// {
|
||
|
// query: "div.howdy[type=thinger]",
|
||
|
// classes: ["howdy"],
|
||
|
// infixOper: {
|
||
|
// query: ">",
|
||
|
// oper: ">",
|
||
|
// }
|
||
|
// },
|
||
|
// ]
|
||
|
currentPart = {
|
||
|
query: null, // the full text of the part's rule
|
||
|
pseudos: [], // CSS supports multiple pseud-class matches in a single rule
|
||
|
attrs: [], // CSS supports multi-attribute match, so we need an array
|
||
|
classes: [], // class matches may be additive, e.g.: .thinger.blah.howdy
|
||
|
tag: null, // only one tag...
|
||
|
oper: null, // ...or operator per component. Note that these wind up being exclusive.
|
||
|
id: null, // the id component of a rule
|
||
|
getTag: function(){
|
||
|
return caseSensitive ? this.otag : this.tag;
|
||
|
}
|
||
|
};
|
||
|
|
||
|
// if we don't have a part, we assume we're going to start at
|
||
|
// the beginning of a match, which should be a tag name. This
|
||
|
// might fault a little later on, but we detect that and this
|
||
|
// iteration will still be fine.
|
||
|
inTag = x;
|
||
|
}
|
||
|
|
||
|
// Skip processing all quoted characters.
|
||
|
// If we are inside quoted text then currentQuoteChar stores the character that began the quote,
|
||
|
// thus that character that will end it.
|
||
|
if(currentQuoteChar){
|
||
|
if(cc == currentQuoteChar){
|
||
|
currentQuoteChar = null;
|
||
|
}
|
||
|
continue;
|
||
|
}else if (cc == "'" || cc == '"'){
|
||
|
currentQuoteChar = cc;
|
||
|
continue;
|
||
|
}
|
||
|
|
||
|
if(inBrackets >= 0){
|
||
|
// look for a the close first
|
||
|
if(cc == "]"){ // if we're in a [...] clause and we end, do assignment
|
||
|
if(!_cp.attr){
|
||
|
// no attribute match was previously begun, so we
|
||
|
// assume this is an attribute existence match in the
|
||
|
// form of [someAttributeName]
|
||
|
_cp.attr = ts(inBrackets+1, x);
|
||
|
}else{
|
||
|
// we had an attribute already, so we know that we're
|
||
|
// matching some sort of value, as in [attrName=howdy]
|
||
|
_cp.matchFor = ts((inMatchFor||inBrackets+1), x);
|
||
|
}
|
||
|
var cmf = _cp.matchFor;
|
||
|
if(cmf){
|
||
|
// try to strip quotes from the matchFor value. We want
|
||
|
// [attrName=howdy] to match the same
|
||
|
// as [attrName = 'howdy' ]
|
||
|
if( (cmf.charAt(0) == '"') || (cmf.charAt(0) == "'") ){
|
||
|
_cp.matchFor = cmf.slice(1, -1);
|
||
|
}
|
||
|
}
|
||
|
// remove backslash escapes from an attribute match, since DOM
|
||
|
// querying will get attribute values without backslashes
|
||
|
if(_cp.matchFor){
|
||
|
_cp.matchFor = _cp.matchFor.replace(/\\/g, "");
|
||
|
}
|
||
|
|
||
|
// end the attribute by adding it to the list of attributes.
|
||
|
currentPart.attrs.push(_cp);
|
||
|
_cp = null; // necessary?
|
||
|
inBrackets = inMatchFor = -1;
|
||
|
}else if(cc == "="){
|
||
|
// if the last char was an operator prefix, make sure we
|
||
|
// record it along with the "=" operator.
|
||
|
var addToCc = ("|~^$*".indexOf(lc) >=0 ) ? lc : "";
|
||
|
_cp.type = addToCc+cc;
|
||
|
_cp.attr = ts(inBrackets+1, x-addToCc.length);
|
||
|
inMatchFor = x+1;
|
||
|
}
|
||
|
// now look for other clause parts
|
||
|
}else if(inParens >= 0){
|
||
|
// if we're in a parenthetical expression, we need to figure
|
||
|
// out if it's attached to a pseudo-selector rule like
|
||
|
// :nth-child(1)
|
||
|
if(cc == ")"){
|
||
|
if(inPseudo >= 0){
|
||
|
_cp.value = ts(inParens+1, x);
|
||
|
}
|
||
|
inPseudo = inParens = -1;
|
||
|
}
|
||
|
}else if(cc == "#"){
|
||
|
// start of an ID match
|
||
|
endAll();
|
||
|
inId = x+1;
|
||
|
}else if(cc == "."){
|
||
|
// start of a class match
|
||
|
endAll();
|
||
|
inClass = x;
|
||
|
}else if(cc == ":"){
|
||
|
// start of a pseudo-selector match
|
||
|
endAll();
|
||
|
inPseudo = x;
|
||
|
}else if(cc == "["){
|
||
|
// start of an attribute match.
|
||
|
endAll();
|
||
|
inBrackets = x;
|
||
|
// provide a new structure for the attribute match to fill-in
|
||
|
_cp = {
|
||
|
/*=====
|
||
|
attr: null, type: null, matchFor: null
|
||
|
=====*/
|
||
|
};
|
||
|
}else if(cc == "("){
|
||
|
// we really only care if we've entered a parenthetical
|
||
|
// expression if we're already inside a pseudo-selector match
|
||
|
if(inPseudo >= 0){
|
||
|
// provide a new structure for the pseudo match to fill-in
|
||
|
_cp = {
|
||
|
name: ts(inPseudo+1, x),
|
||
|
value: null
|
||
|
};
|
||
|
currentPart.pseudos.push(_cp);
|
||
|
}
|
||
|
inParens = x;
|
||
|
}else if(
|
||
|
(cc == " ") &&
|
||
|
// if it's a space char and the last char is too, consume the
|
||
|
// current one without doing more work
|
||
|
(lc != cc)
|
||
|
){
|
||
|
endPart();
|
||
|
}
|
||
|
}
|
||
|
return queryParts;
|
||
|
};
|
||
|
|
||
|
|
||
|
////////////////////////////////////////////////////////////////////////
|
||
|
// DOM query infrastructure
|
||
|
////////////////////////////////////////////////////////////////////////
|
||
|
|
||
|
var agree = function(first, second){
|
||
|
// the basic building block of the yes/no chaining system. agree(f1,
|
||
|
// f2) generates a new function which returns the boolean results of
|
||
|
// both of the passed functions to a single logical-anded result. If
|
||
|
// either are not passed, the other is used exclusively.
|
||
|
if(!first){ return second; }
|
||
|
if(!second){ return first; }
|
||
|
|
||
|
return function(){
|
||
|
return first.apply(window, arguments) && second.apply(window, arguments);
|
||
|
};
|
||
|
};
|
||
|
|
||
|
var getArr = function(i, arr){
|
||
|
// helps us avoid array alloc when we don't need it
|
||
|
var r = arr||[]; // FIXME: should this be 'new d._NodeListCtor()' ?
|
||
|
if(i){ r.push(i); }
|
||
|
return r;
|
||
|
};
|
||
|
|
||
|
var _isElement = function(n){ return (1 == n.nodeType); };
|
||
|
|
||
|
// FIXME: need to coalesce _getAttr with defaultGetter
|
||
|
var blank = "";
|
||
|
var _getAttr = function(elem, attr){
|
||
|
if(!elem){ return blank; }
|
||
|
if(attr == "class"){
|
||
|
return elem.className || blank;
|
||
|
}
|
||
|
if(attr == "for"){
|
||
|
return elem.htmlFor || blank;
|
||
|
}
|
||
|
if(attr == "style"){
|
||
|
return elem.style.cssText || blank;
|
||
|
}
|
||
|
return (caseSensitive ? elem.getAttribute(attr) : elem.getAttribute(attr, 2)) || blank;
|
||
|
};
|
||
|
|
||
|
var attrs = {
|
||
|
"*=": function(attr, value){
|
||
|
return function(elem){
|
||
|
// E[foo*="bar"]
|
||
|
// an E element whose "foo" attribute value contains
|
||
|
// the substring "bar"
|
||
|
return (_getAttr(elem, attr).indexOf(value)>=0);
|
||
|
};
|
||
|
},
|
||
|
"^=": function(attr, value){
|
||
|
// E[foo^="bar"]
|
||
|
// an E element whose "foo" attribute value begins exactly
|
||
|
// with the string "bar"
|
||
|
return function(elem){
|
||
|
return (_getAttr(elem, attr).indexOf(value)==0);
|
||
|
};
|
||
|
},
|
||
|
"$=": function(attr, value){
|
||
|
// E[foo$="bar"]
|
||
|
// an E element whose "foo" attribute value ends exactly
|
||
|
// with the string "bar"
|
||
|
return function(elem){
|
||
|
var ea = " "+_getAttr(elem, attr);
|
||
|
var lastIndex = ea.lastIndexOf(value);
|
||
|
return lastIndex > -1 && (lastIndex==(ea.length-value.length));
|
||
|
};
|
||
|
},
|
||
|
"~=": function(attr, value){
|
||
|
// E[foo~="bar"]
|
||
|
// an E element whose "foo" attribute value is a list of
|
||
|
// space-separated values, one of which is exactly equal
|
||
|
// to "bar"
|
||
|
|
||
|
// return "[contains(concat(' ',@"+attr+",' '), ' "+ value +" ')]";
|
||
|
var tval = " "+value+" ";
|
||
|
return function(elem){
|
||
|
var ea = " "+_getAttr(elem, attr)+" ";
|
||
|
return (ea.indexOf(tval)>=0);
|
||
|
};
|
||
|
},
|
||
|
"|=": function(attr, value){
|
||
|
// E[hreflang|="en"]
|
||
|
// an E element whose "hreflang" attribute has a
|
||
|
// hyphen-separated list of values beginning (from the
|
||
|
// left) with "en"
|
||
|
var valueDash = value+"-";
|
||
|
return function(elem){
|
||
|
var ea = _getAttr(elem, attr);
|
||
|
return (
|
||
|
(ea == value) ||
|
||
|
(ea.indexOf(valueDash)==0)
|
||
|
);
|
||
|
};
|
||
|
},
|
||
|
"=": function(attr, value){
|
||
|
return function(elem){
|
||
|
return (_getAttr(elem, attr) == value);
|
||
|
};
|
||
|
}
|
||
|
};
|
||
|
|
||
|
// avoid testing for node type if we can. Defining this in the negative
|
||
|
// here to avoid negation in the fast path.
|
||
|
// NOTE: Firefox versions 25-27 implemented an incompatible change
|
||
|
// to the spec, https://bugzilla.mozilla.org/show_bug.cgi?id=932501
|
||
|
// and https://www.w3.org/Bugs/Public/show_bug.cgi?id=23691 ,
|
||
|
// where nextElementSibling was implemented on the DocumentType
|
||
|
var htmlElement = getDoc().documentElement;
|
||
|
var _noNES = !(htmlElement.nextElementSibling ||
|
||
|
"nextElementSibling" in htmlElement);
|
||
|
var _ns = !_noNES ? "nextElementSibling" : "nextSibling";
|
||
|
var _ps = !_noNES ? "previousElementSibling" : "previousSibling";
|
||
|
var _simpleNodeTest = (_noNES ? _isElement : yesman);
|
||
|
|
||
|
var _lookLeft = function(node){
|
||
|
// look left
|
||
|
while(node = node[_ps]){
|
||
|
if(_simpleNodeTest(node)){ return false; }
|
||
|
}
|
||
|
return true;
|
||
|
};
|
||
|
|
||
|
var _lookRight = function(node){
|
||
|
// look right
|
||
|
while(node = node[_ns]){
|
||
|
if(_simpleNodeTest(node)){ return false; }
|
||
|
}
|
||
|
return true;
|
||
|
};
|
||
|
|
||
|
var getNodeIndex = function(node){
|
||
|
var root = node.parentNode;
|
||
|
root = root.nodeType != 7 ? root : root.nextSibling; // PROCESSING_INSTRUCTION_NODE
|
||
|
var i = 0,
|
||
|
tret = root.children || root.childNodes,
|
||
|
ci = (node["_i"]||node.getAttribute("_i")||-1),
|
||
|
cl = (root["_l"]|| (typeof root.getAttribute !== "undefined" ? root.getAttribute("_l") : -1));
|
||
|
|
||
|
if(!tret){ return -1; }
|
||
|
var l = tret.length;
|
||
|
|
||
|
// we calculate the parent length as a cheap way to invalidate the
|
||
|
// cache. It's not 100% accurate, but it's much more honest than what
|
||
|
// other libraries do
|
||
|
if( cl == l && ci >= 0 && cl >= 0 ){
|
||
|
// if it's legit, tag and release
|
||
|
return ci;
|
||
|
}
|
||
|
|
||
|
// else re-key things
|
||
|
if(has("ie") && typeof root.setAttribute !== "undefined"){
|
||
|
root.setAttribute("_l", l);
|
||
|
}else{
|
||
|
root["_l"] = l;
|
||
|
}
|
||
|
ci = -1;
|
||
|
for(var te = root["firstElementChild"]||root["firstChild"]; te; te = te[_ns]){
|
||
|
if(_simpleNodeTest(te)){
|
||
|
if(has("ie")){
|
||
|
te.setAttribute("_i", ++i);
|
||
|
}else{
|
||
|
te["_i"] = ++i;
|
||
|
}
|
||
|
if(node === te){
|
||
|
// NOTE:
|
||
|
// shortcutting the return at this step in indexing works
|
||
|
// very well for benchmarking but we avoid it here since
|
||
|
// it leads to potential O(n^2) behavior in sequential
|
||
|
// getNodexIndex operations on a previously un-indexed
|
||
|
// parent. We may revisit this at a later time, but for
|
||
|
// now we just want to get the right answer more often
|
||
|
// than not.
|
||
|
ci = i;
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
return ci;
|
||
|
};
|
||
|
|
||
|
var isEven = function(elem){
|
||
|
return !((getNodeIndex(elem)) % 2);
|
||
|
};
|
||
|
|
||
|
var isOdd = function(elem){
|
||
|
return ((getNodeIndex(elem)) % 2);
|
||
|
};
|
||
|
|
||
|
var pseudos = {
|
||
|
"checked": function(name, condition){
|
||
|
return function(elem){
|
||
|
return !!("checked" in elem ? elem.checked : elem.selected);
|
||
|
};
|
||
|
},
|
||
|
"disabled": function(name, condition){
|
||
|
return function(elem){
|
||
|
return elem.disabled;
|
||
|
};
|
||
|
},
|
||
|
"enabled": function(name, condition){
|
||
|
return function(elem){
|
||
|
return !elem.disabled;
|
||
|
};
|
||
|
},
|
||
|
"first-child": function(){ return _lookLeft; },
|
||
|
"last-child": function(){ return _lookRight; },
|
||
|
"only-child": function(name, condition){
|
||
|
return function(node){
|
||
|
return _lookLeft(node) && _lookRight(node);
|
||
|
};
|
||
|
},
|
||
|
"empty": function(name, condition){
|
||
|
return function(elem){
|
||
|
// DomQuery and jQuery get this wrong, oddly enough.
|
||
|
// The CSS 3 selectors spec is pretty explicit about it, too.
|
||
|
var cn = elem.childNodes;
|
||
|
var cnl = elem.childNodes.length;
|
||
|
// if(!cnl){ return true; }
|
||
|
for(var x=cnl-1; x >= 0; x--){
|
||
|
var nt = cn[x].nodeType;
|
||
|
if((nt === 1)||(nt == 3)){ return false; }
|
||
|
}
|
||
|
return true;
|
||
|
};
|
||
|
},
|
||
|
"contains": function(name, condition){
|
||
|
var cz = condition.charAt(0);
|
||
|
if( cz == '"' || cz == "'" ){ //remove quote
|
||
|
condition = condition.slice(1, -1);
|
||
|
}
|
||
|
return function(elem){
|
||
|
return (elem.innerHTML.indexOf(condition) >= 0);
|
||
|
};
|
||
|
},
|
||
|
"not": function(name, condition){
|
||
|
var p = getQueryParts(condition)[0];
|
||
|
var ignores = { el: 1 };
|
||
|
if(p.tag != "*"){
|
||
|
ignores.tag = 1;
|
||
|
}
|
||
|
if(!p.classes.length){
|
||
|
ignores.classes = 1;
|
||
|
}
|
||
|
var ntf = getSimpleFilterFunc(p, ignores);
|
||
|
return function(elem){
|
||
|
return (!ntf(elem));
|
||
|
};
|
||
|
},
|
||
|
"nth-child": function(name, condition){
|
||
|
var pi = parseInt;
|
||
|
// avoid re-defining function objects if we can
|
||
|
if(condition == "odd"){
|
||
|
return isOdd;
|
||
|
}else if(condition == "even"){
|
||
|
return isEven;
|
||
|
}
|
||
|
// FIXME: can we shorten this?
|
||
|
if(condition.indexOf("n") != -1){
|
||
|
var tparts = condition.split("n", 2);
|
||
|
var pred = tparts[0] ? ((tparts[0] == '-') ? -1 : pi(tparts[0])) : 1;
|
||
|
var idx = tparts[1] ? pi(tparts[1]) : 0;
|
||
|
var lb = 0, ub = -1;
|
||
|
if(pred > 0){
|
||
|
if(idx < 0){
|
||
|
idx = (idx % pred) && (pred + (idx % pred));
|
||
|
}else if(idx>0){
|
||
|
if(idx >= pred){
|
||
|
lb = idx - idx % pred;
|
||
|
}
|
||
|
idx = idx % pred;
|
||
|
}
|
||
|
}else if(pred<0){
|
||
|
pred *= -1;
|
||
|
// idx has to be greater than 0 when pred is negative;
|
||
|
// shall we throw an error here?
|
||
|
if(idx > 0){
|
||
|
ub = idx;
|
||
|
idx = idx % pred;
|
||
|
}
|
||
|
}
|
||
|
if(pred > 0){
|
||
|
return function(elem){
|
||
|
var i = getNodeIndex(elem);
|
||
|
return (i>=lb) && (ub<0 || i<=ub) && ((i % pred) == idx);
|
||
|
};
|
||
|
}else{
|
||
|
condition = idx;
|
||
|
}
|
||
|
}
|
||
|
var ncount = pi(condition);
|
||
|
return function(elem){
|
||
|
return (getNodeIndex(elem) == ncount);
|
||
|
};
|
||
|
}
|
||
|
};
|
||
|
|
||
|
var defaultGetter = (has("ie") < 9 || has("ie") == 9 && has("quirks")) ? function(cond){
|
||
|
var clc = cond.toLowerCase();
|
||
|
if(clc == "class"){ cond = "className"; }
|
||
|
return function(elem){
|
||
|
return (caseSensitive ? elem.getAttribute(cond) : elem[cond]||elem[clc]);
|
||
|
};
|
||
|
} : function(cond){
|
||
|
return function(elem){
|
||
|
return (elem && elem.getAttribute && elem.hasAttribute(cond));
|
||
|
};
|
||
|
};
|
||
|
|
||
|
var getSimpleFilterFunc = function(query, ignores){
|
||
|
// generates a node tester function based on the passed query part. The
|
||
|
// query part is one of the structures generated by the query parser
|
||
|
// when it creates the query AST. The "ignores" object specifies which
|
||
|
// (if any) tests to skip, allowing the system to avoid duplicating
|
||
|
// work where it may have already been taken into account by other
|
||
|
// factors such as how the nodes to test were fetched in the first
|
||
|
// place
|
||
|
if(!query){ return yesman; }
|
||
|
ignores = ignores||{};
|
||
|
|
||
|
var ff = null;
|
||
|
|
||
|
if(!("el" in ignores)){
|
||
|
ff = agree(ff, _isElement);
|
||
|
}
|
||
|
|
||
|
if(!("tag" in ignores)){
|
||
|
if(query.tag != "*"){
|
||
|
ff = agree(ff, function(elem){
|
||
|
return (elem && ((caseSensitive ? elem.tagName : elem.tagName.toUpperCase()) == query.getTag()));
|
||
|
});
|
||
|
}
|
||
|
}
|
||
|
|
||
|
if(!("classes" in ignores)){
|
||
|
each(query.classes, function(cname, idx, arr){
|
||
|
// get the class name
|
||
|
/*
|
||
|
var isWildcard = cname.charAt(cname.length-1) == "*";
|
||
|
if(isWildcard){
|
||
|
cname = cname.substr(0, cname.length-1);
|
||
|
}
|
||
|
// I dislike the regex thing, even if memoized in a cache, but it's VERY short
|
||
|
var re = new RegExp("(?:^|\\s)" + cname + (isWildcard ? ".*" : "") + "(?:\\s|$)");
|
||
|
*/
|
||
|
var re = new RegExp("(?:^|\\s)" + cname + "(?:\\s|$)");
|
||
|
ff = agree(ff, function(elem){
|
||
|
return re.test(elem.className);
|
||
|
});
|
||
|
ff.count = idx;
|
||
|
});
|
||
|
}
|
||
|
|
||
|
if(!("pseudos" in ignores)){
|
||
|
each(query.pseudos, function(pseudo){
|
||
|
var pn = pseudo.name;
|
||
|
if(pseudos[pn]){
|
||
|
ff = agree(ff, pseudos[pn](pn, pseudo.value));
|
||
|
}
|
||
|
});
|
||
|
}
|
||
|
|
||
|
if(!("attrs" in ignores)){
|
||
|
each(query.attrs, function(attr){
|
||
|
var matcher;
|
||
|
var a = attr.attr;
|
||
|
// type, attr, matchFor
|
||
|
if(attr.type && attrs[attr.type]){
|
||
|
matcher = attrs[attr.type](a, attr.matchFor);
|
||
|
}else if(a.length){
|
||
|
matcher = defaultGetter(a);
|
||
|
}
|
||
|
if(matcher){
|
||
|
ff = agree(ff, matcher);
|
||
|
}
|
||
|
});
|
||
|
}
|
||
|
|
||
|
if(!("id" in ignores)){
|
||
|
if(query.id){
|
||
|
ff = agree(ff, function(elem){
|
||
|
return (!!elem && (elem.id == query.id));
|
||
|
});
|
||
|
}
|
||
|
}
|
||
|
|
||
|
if(!ff){
|
||
|
if(!("default" in ignores)){
|
||
|
ff = yesman;
|
||
|
}
|
||
|
}
|
||
|
return ff;
|
||
|
};
|
||
|
|
||
|
var _nextSibling = function(filterFunc){
|
||
|
return function(node, ret, bag){
|
||
|
while(node = node[_ns]){
|
||
|
if(_noNES && (!_isElement(node))){ continue; }
|
||
|
if(
|
||
|
(!bag || _isUnique(node, bag)) &&
|
||
|
filterFunc(node)
|
||
|
){
|
||
|
ret.push(node);
|
||
|
}
|
||
|
break;
|
||
|
}
|
||
|
return ret;
|
||
|
};
|
||
|
};
|
||
|
|
||
|
var _nextSiblings = function(filterFunc){
|
||
|
return function(root, ret, bag){
|
||
|
var te = root[_ns];
|
||
|
while(te){
|
||
|
if(_simpleNodeTest(te)){
|
||
|
if(bag && !_isUnique(te, bag)){
|
||
|
break;
|
||
|
}
|
||
|
if(filterFunc(te)){
|
||
|
ret.push(te);
|
||
|
}
|
||
|
}
|
||
|
te = te[_ns];
|
||
|
}
|
||
|
return ret;
|
||
|
};
|
||
|
};
|
||
|
|
||
|
// get an array of child *elements*, skipping text and comment nodes
|
||
|
var _childElements = function(filterFunc, recursive){
|
||
|
|
||
|
var _toArray = function (iterable) {
|
||
|
var result = [];
|
||
|
|
||
|
try {
|
||
|
result = Array.prototype.slice.call(iterable);
|
||
|
} catch(e) {
|
||
|
// IE8- throws an error when we try convert HTMLCollection
|
||
|
// to array using Array.prototype.slice.call
|
||
|
for(var i = 0, len = iterable.length; i < len; i++) {
|
||
|
result.push(iterable[i]);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
return result;
|
||
|
};
|
||
|
|
||
|
filterFunc = filterFunc||yesman;
|
||
|
return function(root, ret, bag){
|
||
|
// get an array of child elements, skipping text and comment nodes
|
||
|
var te, x = 0, tret = []; tret = _toArray(root.children || root.childNodes);
|
||
|
|
||
|
if(recursive) {
|
||
|
array.forEach(tret, function (node) {
|
||
|
if(node.nodeType === 1) {
|
||
|
tret = tret.concat(_toArray(node.getElementsByTagName("*")));
|
||
|
}
|
||
|
});
|
||
|
}
|
||
|
|
||
|
while(te = tret[x++]){
|
||
|
if(
|
||
|
_simpleNodeTest(te) &&
|
||
|
(!bag || _isUnique(te, bag)) &&
|
||
|
(filterFunc(te, x))
|
||
|
){
|
||
|
ret.push(te);
|
||
|
}
|
||
|
}
|
||
|
return ret;
|
||
|
};
|
||
|
};
|
||
|
|
||
|
// test to see if node is below root
|
||
|
var _isDescendant = function(node, root){
|
||
|
var pn = node.parentNode;
|
||
|
while(pn){
|
||
|
if(pn == root){
|
||
|
break;
|
||
|
}
|
||
|
pn = pn.parentNode;
|
||
|
}
|
||
|
return !!pn;
|
||
|
};
|
||
|
|
||
|
var _getElementsFuncCache = {};
|
||
|
|
||
|
var getElementsFunc = function(query){
|
||
|
var retFunc = _getElementsFuncCache[query.query];
|
||
|
// if we've got a cached dispatcher, just use that
|
||
|
if(retFunc){ return retFunc; }
|
||
|
// else, generate a new on
|
||
|
|
||
|
// NOTE:
|
||
|
// this function returns a function that searches for nodes and
|
||
|
// filters them. The search may be specialized by infix operators
|
||
|
// (">", "~", or "+") else it will default to searching all
|
||
|
// descendants (the " " selector). Once a group of children is
|
||
|
// found, a test function is applied to weed out the ones we
|
||
|
// don't want. Many common cases can be fast-pathed. We spend a
|
||
|
// lot of cycles to create a dispatcher that doesn't do more work
|
||
|
// than necessary at any point since, unlike this function, the
|
||
|
// dispatchers will be called every time. The logic of generating
|
||
|
// efficient dispatchers looks like this in pseudo code:
|
||
|
//
|
||
|
// # if it's a purely descendant query (no ">", "+", or "~" modifiers)
|
||
|
// if infixOperator == " ":
|
||
|
// if only(id):
|
||
|
// return def(root):
|
||
|
// return d.byId(id, root);
|
||
|
//
|
||
|
// elif id:
|
||
|
// return def(root):
|
||
|
// return filter(d.byId(id, root));
|
||
|
//
|
||
|
// elif cssClass && getElementsByClassName:
|
||
|
// return def(root):
|
||
|
// return filter(root.getElementsByClassName(cssClass));
|
||
|
//
|
||
|
// elif only(tag):
|
||
|
// return def(root):
|
||
|
// return root.getElementsByTagName(tagName);
|
||
|
//
|
||
|
// else:
|
||
|
// # search by tag name, then filter
|
||
|
// return def(root):
|
||
|
// return filter(root.getElementsByTagName(tagName||"*"));
|
||
|
//
|
||
|
// elif infixOperator == ">":
|
||
|
// # search direct children
|
||
|
// return def(root):
|
||
|
// return filter(root.children);
|
||
|
//
|
||
|
// elif infixOperator == "+":
|
||
|
// # search next sibling
|
||
|
// return def(root):
|
||
|
// return filter(root.nextElementSibling);
|
||
|
//
|
||
|
// elif infixOperator == "~":
|
||
|
// # search rightward siblings
|
||
|
// return def(root):
|
||
|
// return filter(nextSiblings(root));
|
||
|
|
||
|
var io = query.infixOper;
|
||
|
var oper = (io ? io.oper : "");
|
||
|
// the default filter func which tests for all conditions in the query
|
||
|
// part. This is potentially inefficient, so some optimized paths may
|
||
|
// re-define it to test fewer things.
|
||
|
var filterFunc = getSimpleFilterFunc(query, { el: 1 });
|
||
|
var qt = query.tag;
|
||
|
var wildcardTag = ("*" == qt);
|
||
|
var ecs = getDoc()["getElementsByClassName"];
|
||
|
|
||
|
if(!oper){
|
||
|
// if there's no infix operator, then it's a descendant query. ID
|
||
|
// and "elements by class name" variants can be accelerated so we
|
||
|
// call them out explicitly:
|
||
|
if(query.id){
|
||
|
// testing shows that the overhead of yesman() is acceptable
|
||
|
// and can save us some bytes vs. re-defining the function
|
||
|
// everywhere.
|
||
|
filterFunc = (!query.loops && wildcardTag) ?
|
||
|
yesman :
|
||
|
getSimpleFilterFunc(query, { el: 1, id: 1 });
|
||
|
|
||
|
retFunc = function(root, arr){
|
||
|
var te = dom.byId(query.id, (root.ownerDocument||root));
|
||
|
|
||
|
// We can't look for ID inside a detached dom.
|
||
|
// loop over all elements searching for specified id.
|
||
|
if(root.ownerDocument && !_isDescendant(root, root.ownerDocument)) {
|
||
|
|
||
|
// document-fragment or regular HTMLElement
|
||
|
var roots = root.nodeType === 11? root.childNodes: [root];
|
||
|
|
||
|
array.some(roots, function (currentRoot) {
|
||
|
var elems = _childElements(function (node) {
|
||
|
return node.id === query.id;
|
||
|
}, true)(currentRoot, []);
|
||
|
|
||
|
if(elems.length) {
|
||
|
te = elems[0];
|
||
|
return false;
|
||
|
}
|
||
|
});
|
||
|
}
|
||
|
|
||
|
if(!te || !filterFunc(te)){ return; }
|
||
|
if(9 == root.nodeType){ // if root's a doc, we just return directly
|
||
|
return getArr(te, arr);
|
||
|
}else{ // otherwise check ancestry
|
||
|
if(_isDescendant(te, root)){
|
||
|
return getArr(te, arr);
|
||
|
}
|
||
|
}
|
||
|
};
|
||
|
}else if(
|
||
|
ecs &&
|
||
|
// isAlien check. Workaround for Prototype.js being totally evil/dumb.
|
||
|
/\{\s*\[native code\]\s*\}/.test(String(ecs)) &&
|
||
|
query.classes.length &&
|
||
|
!cssCaseBug
|
||
|
){
|
||
|
// it's a class-based query and we've got a fast way to run it.
|
||
|
|
||
|
// ignore class and ID filters since we will have handled both
|
||
|
filterFunc = getSimpleFilterFunc(query, { el: 1, classes: 1, id: 1 });
|
||
|
var classesString = query.classes.join(" ");
|
||
|
retFunc = function(root, arr, bag){
|
||
|
var ret = getArr(0, arr), te, x=0;
|
||
|
var tret = root.getElementsByClassName(classesString);
|
||
|
while((te = tret[x++])){
|
||
|
if(filterFunc(te, root) && _isUnique(te, bag)){
|
||
|
ret.push(te);
|
||
|
}
|
||
|
}
|
||
|
return ret;
|
||
|
};
|
||
|
|
||
|
}else if(!wildcardTag && !query.loops){
|
||
|
// it's tag only. Fast-path it.
|
||
|
retFunc = function(root, arr, bag){
|
||
|
var ret = getArr(0, arr), te, x=0;
|
||
|
var tag = query.getTag(),
|
||
|
tret = tag ? root.getElementsByTagName(tag) : [];
|
||
|
while((te = tret[x++])){
|
||
|
if(_isUnique(te, bag)){
|
||
|
ret.push(te);
|
||
|
}
|
||
|
}
|
||
|
return ret;
|
||
|
};
|
||
|
}else{
|
||
|
// the common case:
|
||
|
// a descendant selector without a fast path. By now it's got
|
||
|
// to have a tag selector, even if it's just "*" so we query
|
||
|
// by that and filter
|
||
|
filterFunc = getSimpleFilterFunc(query, { el: 1, tag: 1, id: 1 });
|
||
|
retFunc = function(root, arr, bag){
|
||
|
var ret = getArr(0, arr), te, x=0;
|
||
|
// we use getTag() to avoid case sensitivity issues
|
||
|
var tag = query.getTag(),
|
||
|
tret = tag ? root.getElementsByTagName(tag) : [];
|
||
|
while((te = tret[x++])){
|
||
|
if(filterFunc(te, root) && _isUnique(te, bag)){
|
||
|
ret.push(te);
|
||
|
}
|
||
|
}
|
||
|
return ret;
|
||
|
};
|
||
|
}
|
||
|
}else{
|
||
|
// the query is scoped in some way. Instead of querying by tag we
|
||
|
// use some other collection to find candidate nodes
|
||
|
var skipFilters = { el: 1 };
|
||
|
if(wildcardTag){
|
||
|
skipFilters.tag = 1;
|
||
|
}
|
||
|
filterFunc = getSimpleFilterFunc(query, skipFilters);
|
||
|
if("+" == oper){
|
||
|
retFunc = _nextSibling(filterFunc);
|
||
|
}else if("~" == oper){
|
||
|
retFunc = _nextSiblings(filterFunc);
|
||
|
}else if(">" == oper){
|
||
|
retFunc = _childElements(filterFunc);
|
||
|
}
|
||
|
}
|
||
|
// cache it and return
|
||
|
return _getElementsFuncCache[query.query] = retFunc;
|
||
|
};
|
||
|
|
||
|
var filterDown = function(root, queryParts){
|
||
|
// NOTE:
|
||
|
// this is the guts of the DOM query system. It takes a list of
|
||
|
// parsed query parts and a root and finds children which match
|
||
|
// the selector represented by the parts
|
||
|
var candidates = getArr(root), qp, x, te, qpl = queryParts.length, bag, ret;
|
||
|
|
||
|
for(var i = 0; i < qpl; i++){
|
||
|
ret = [];
|
||
|
qp = queryParts[i];
|
||
|
x = candidates.length - 1;
|
||
|
if(x > 0){
|
||
|
// if we have more than one root at this level, provide a new
|
||
|
// hash to use for checking group membership but tell the
|
||
|
// system not to post-filter us since we will already have been
|
||
|
// guaranteed to be unique
|
||
|
bag = {};
|
||
|
ret.nozip = true;
|
||
|
}
|
||
|
var gef = getElementsFunc(qp);
|
||
|
for(var j = 0; (te = candidates[j]); j++){
|
||
|
// for every root, get the elements that match the descendant
|
||
|
// selector, adding them to the "ret" array and filtering them
|
||
|
// via membership in this level's bag. If there are more query
|
||
|
// parts, then this level's return will be used as the next
|
||
|
// level's candidates
|
||
|
gef(te, ret, bag);
|
||
|
}
|
||
|
if(!ret.length){ break; }
|
||
|
candidates = ret;
|
||
|
}
|
||
|
return ret;
|
||
|
};
|
||
|
|
||
|
////////////////////////////////////////////////////////////////////////
|
||
|
// the query runner
|
||
|
////////////////////////////////////////////////////////////////////////
|
||
|
|
||
|
// these are the primary caches for full-query results. The query
|
||
|
// dispatcher functions are generated then stored here for hash lookup in
|
||
|
// the future
|
||
|
var _queryFuncCacheDOM = {},
|
||
|
_queryFuncCacheQSA = {};
|
||
|
|
||
|
// this is the second level of splitting, from full-length queries (e.g.,
|
||
|
// "div.foo .bar") into simple query expressions (e.g., ["div.foo",
|
||
|
// ".bar"])
|
||
|
var getStepQueryFunc = function(query){
|
||
|
var qparts = getQueryParts(trim(query));
|
||
|
|
||
|
// if it's trivial, avoid iteration and zipping costs
|
||
|
if(qparts.length == 1){
|
||
|
// we optimize this case here to prevent dispatch further down the
|
||
|
// chain, potentially slowing things down. We could more elegantly
|
||
|
// handle this in filterDown(), but it's slower for simple things
|
||
|
// that need to be fast (e.g., "#someId").
|
||
|
var tef = getElementsFunc(qparts[0]);
|
||
|
return function(root){
|
||
|
var r = tef(root, []);
|
||
|
if(r){ r.nozip = true; }
|
||
|
return r;
|
||
|
};
|
||
|
}
|
||
|
|
||
|
// otherwise, break it up and return a runner that iterates over the parts recursively
|
||
|
return function(root){
|
||
|
return filterDown(root, qparts);
|
||
|
};
|
||
|
};
|
||
|
|
||
|
// NOTES:
|
||
|
// * we can't trust QSA for anything but document-rooted queries, so
|
||
|
// caching is split into DOM query evaluators and QSA query evaluators
|
||
|
// * caching query results is dirty and leak-prone (or, at a minimum,
|
||
|
// prone to unbounded growth). Other toolkits may go this route, but
|
||
|
// they totally destroy their own ability to manage their memory
|
||
|
// footprint. If we implement it, it should only ever be with a fixed
|
||
|
// total element reference # limit and an LRU-style algorithm since JS
|
||
|
// has no weakref support. Caching compiled query evaluators is also
|
||
|
// potentially problematic, but even on large documents the size of the
|
||
|
// query evaluators is often < 100 function objects per evaluator (and
|
||
|
// LRU can be applied if it's ever shown to be an issue).
|
||
|
// * since IE's QSA support is currently only for HTML documents and even
|
||
|
// then only in IE 8's "standards mode", we have to detect our dispatch
|
||
|
// route at query time and keep 2 separate caches. Ugg.
|
||
|
|
||
|
// we need to determine if we think we can run a given query via
|
||
|
// querySelectorAll or if we'll need to fall back on DOM queries to get
|
||
|
// there. We need a lot of information about the environment and the query
|
||
|
// to make the determination (e.g. does it support QSA, does the query in
|
||
|
// question work in the native QSA impl, etc.).
|
||
|
|
||
|
// IE QSA queries may incorrectly include comment nodes, so we throw the
|
||
|
// zipping function into "remove" comments mode instead of the normal "skip
|
||
|
// it" which every other QSA-clued browser enjoys
|
||
|
var noZip = has("ie") ? "commentStrip" : "nozip";
|
||
|
|
||
|
var qsa = "querySelectorAll";
|
||
|
var qsaAvail = !!getDoc()[qsa];
|
||
|
|
||
|
//Don't bother with n+3 type of matches, IE complains if we modify those.
|
||
|
var infixSpaceRe = /\\[>~+]|n\+\d|([^ \\])?([>~+])([^ =])?/g;
|
||
|
var infixSpaceFunc = function(match, pre, ch, post){
|
||
|
return ch ? (pre ? pre + " " : "") + ch + (post ? " " + post : "") : /*n+3*/ match;
|
||
|
};
|
||
|
|
||
|
//Don't apply the infixSpaceRe to attribute value selectors
|
||
|
var attRe = /([^[]*)([^\]]*])?/g;
|
||
|
var attFunc = function(match, nonAtt, att){
|
||
|
return nonAtt.replace(infixSpaceRe, infixSpaceFunc) + (att||"");
|
||
|
};
|
||
|
var getQueryFunc = function(query, forceDOM){
|
||
|
//Normalize query. The CSS3 selectors spec allows for omitting spaces around
|
||
|
//infix operators, >, ~ and +
|
||
|
//Do the work here since detection for spaces is used as a simple "not use QSA"
|
||
|
//test below.
|
||
|
query = query.replace(attRe, attFunc);
|
||
|
|
||
|
if(qsaAvail){
|
||
|
// if we've got a cached variant and we think we can do it, run it!
|
||
|
var qsaCached = _queryFuncCacheQSA[query];
|
||
|
if(qsaCached && !forceDOM){ return qsaCached; }
|
||
|
}
|
||
|
|
||
|
// else if we've got a DOM cached variant, assume that we already know
|
||
|
// all we need to and use it
|
||
|
var domCached = _queryFuncCacheDOM[query];
|
||
|
if(domCached){ return domCached; }
|
||
|
|
||
|
// TODO:
|
||
|
// today we're caching DOM and QSA branches separately so we
|
||
|
// recalc useQSA every time. If we had a way to tag root+query
|
||
|
// efficiently, we'd be in good shape to do a global cache.
|
||
|
|
||
|
var qcz = query.charAt(0);
|
||
|
var nospace = (-1 == query.indexOf(" "));
|
||
|
|
||
|
// byId searches are wicked fast compared to QSA, even when filtering
|
||
|
// is required
|
||
|
if( (query.indexOf("#") >= 0) && (nospace) ){
|
||
|
forceDOM = true;
|
||
|
}
|
||
|
|
||
|
var useQSA = (
|
||
|
qsaAvail && (!forceDOM) &&
|
||
|
// as per CSS 3, we can't currently start w/ combinator:
|
||
|
// http://www.w3.org/TR/css3-selectors/#w3cselgrammar
|
||
|
(specials.indexOf(qcz) == -1) &&
|
||
|
// IE's QSA impl sucks on pseudos
|
||
|
(!has("ie") || (query.indexOf(":") == -1)) &&
|
||
|
|
||
|
(!(cssCaseBug && (query.indexOf(".") >= 0))) &&
|
||
|
|
||
|
// FIXME:
|
||
|
// need to tighten up browser rules on ":contains" and "|=" to
|
||
|
// figure out which aren't good
|
||
|
// Latest webkit (around 531.21.8) does not seem to do well with :checked on option
|
||
|
// elements, even though according to spec, selected options should
|
||
|
// match :checked. So go nonQSA for it:
|
||
|
// http://bugs.dojotoolkit.org/ticket/5179
|
||
|
(query.indexOf(":contains") == -1) && (query.indexOf(":checked") == -1) &&
|
||
|
(query.indexOf("|=") == -1) // some browsers don't grok it
|
||
|
);
|
||
|
|
||
|
// TODO:
|
||
|
// if we've got a descendant query (e.g., "> .thinger" instead of
|
||
|
// just ".thinger") in a QSA-able doc, but are passed a child as a
|
||
|
// root, it should be possible to give the item a synthetic ID and
|
||
|
// trivially rewrite the query to the form "#synid > .thinger" to
|
||
|
// use the QSA branch
|
||
|
|
||
|
|
||
|
if(useQSA){
|
||
|
var tq = (specials.indexOf(query.charAt(query.length-1)) >= 0) ?
|
||
|
(query + " *") : query;
|
||
|
return _queryFuncCacheQSA[query] = function(root){
|
||
|
// the QSA system contains an egregious spec bug which
|
||
|
// limits us, effectively, to only running QSA queries over
|
||
|
// entire documents. See:
|
||
|
// http://ejohn.org/blog/thoughts-on-queryselectorall/
|
||
|
// despite this, we can also handle QSA runs on simple
|
||
|
// selectors, but we don't want detection to be expensive
|
||
|
// so we're just checking for the presence of a space char
|
||
|
// right now. Not elegant, but it's cheaper than running
|
||
|
// the query parser when we might not need to
|
||
|
if(9 == root.nodeType || nospace){
|
||
|
try{
|
||
|
var r = root[qsa](tq);
|
||
|
// skip expensive duplication checks and just wrap in a NodeList
|
||
|
r[noZip] = true;
|
||
|
return r;
|
||
|
}catch(e){
|
||
|
// if root[qsa](tq), fall through to getQueryFunc() branch below
|
||
|
}
|
||
|
}
|
||
|
// else run the DOM branch on this query, ensuring that we
|
||
|
// default that way in the future
|
||
|
return getQueryFunc(query, true)(root);
|
||
|
};
|
||
|
}else{
|
||
|
// DOM branch
|
||
|
var parts = query.match(/([^\s,](?:"(?:\\.|[^"])+"|'(?:\\.|[^'])+'|[^,])*)/g);
|
||
|
return _queryFuncCacheDOM[query] = ((parts.length < 2) ?
|
||
|
// if not a compound query (e.g., ".foo, .bar"), cache and return a dispatcher
|
||
|
getStepQueryFunc(query) :
|
||
|
// if it *is* a complex query, break it up into its
|
||
|
// constituent parts and return a dispatcher that will
|
||
|
// merge the parts when run
|
||
|
function(root){
|
||
|
var pindex = 0, // avoid array alloc for every invocation
|
||
|
ret = [],
|
||
|
tp;
|
||
|
while((tp = parts[pindex++])){
|
||
|
ret = ret.concat(getStepQueryFunc(tp)(root));
|
||
|
}
|
||
|
return ret;
|
||
|
}
|
||
|
);
|
||
|
}
|
||
|
};
|
||
|
|
||
|
var _zipIdx = 0;
|
||
|
|
||
|
// NOTE:
|
||
|
// this function is Moo inspired, but our own impl to deal correctly
|
||
|
// with XML in IE
|
||
|
var _nodeUID = has("ie") ? function(node){
|
||
|
if(caseSensitive){
|
||
|
// XML docs don't have uniqueID on their nodes
|
||
|
return (node.getAttribute("_uid") || node.setAttribute("_uid", ++_zipIdx) || _zipIdx);
|
||
|
|
||
|
}else{
|
||
|
return node.uniqueID;
|
||
|
}
|
||
|
} :
|
||
|
function(node){
|
||
|
return (node._uid || (node._uid = ++_zipIdx));
|
||
|
};
|
||
|
|
||
|
// determine if a node in is unique in a "bag". In this case we don't want
|
||
|
// to flatten a list of unique items, but rather just tell if the item in
|
||
|
// question is already in the bag. Normally we'd just use hash lookup to do
|
||
|
// this for us but IE's DOM is busted so we can't really count on that. On
|
||
|
// the upside, it gives us a built in unique ID function.
|
||
|
var _isUnique = function(node, bag){
|
||
|
if(!bag){ return 1; }
|
||
|
var id = _nodeUID(node);
|
||
|
if(!bag[id]){ return bag[id] = 1; }
|
||
|
return 0;
|
||
|
};
|
||
|
|
||
|
// attempt to efficiently determine if an item in a list is a dupe,
|
||
|
// returning a list of "uniques", hopefully in document order
|
||
|
var _zipIdxName = "_zipIdx";
|
||
|
var _zip = function(arr){
|
||
|
if(arr && arr.nozip){ return arr; }
|
||
|
|
||
|
if(!arr || !arr.length){ return []; }
|
||
|
if(arr.length < 2){ return [arr[0]]; }
|
||
|
|
||
|
var ret = [];
|
||
|
|
||
|
_zipIdx++;
|
||
|
|
||
|
// we have to fork here for IE and XML docs because we can't set
|
||
|
// expandos on their nodes (apparently). *sigh*
|
||
|
var x, te;
|
||
|
if(has("ie") && caseSensitive){
|
||
|
var szidx = _zipIdx+"";
|
||
|
for(x = 0; x < arr.length; x++){
|
||
|
if((te = arr[x]) && te.getAttribute(_zipIdxName) != szidx){
|
||
|
ret.push(te);
|
||
|
te.setAttribute(_zipIdxName, szidx);
|
||
|
}
|
||
|
}
|
||
|
}else if(has("ie") && arr.commentStrip){
|
||
|
try{
|
||
|
for(x = 0; x < arr.length; x++){
|
||
|
if((te = arr[x]) && _isElement(te)){
|
||
|
ret.push(te);
|
||
|
}
|
||
|
}
|
||
|
}catch(e){ /* squelch */ }
|
||
|
}else{
|
||
|
for(x = 0; x < arr.length; x++){
|
||
|
if((te = arr[x]) && te[_zipIdxName] != _zipIdx){
|
||
|
ret.push(te);
|
||
|
te[_zipIdxName] = _zipIdx;
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
return ret;
|
||
|
};
|
||
|
|
||
|
// the main executor
|
||
|
var query = function(/*String*/ query, /*String|DOMNode?*/ root){
|
||
|
// summary:
|
||
|
// Returns nodes which match the given CSS3 selector, searching the
|
||
|
// entire document by default but optionally taking a node to scope
|
||
|
// the search by. Returns an array.
|
||
|
// description:
|
||
|
// dojo.query() is the swiss army knife of DOM node manipulation in
|
||
|
// Dojo. Much like Prototype's "$$" (bling-bling) function or JQuery's
|
||
|
// "$" function, dojo.query provides robust, high-performance
|
||
|
// CSS-based node selector support with the option of scoping searches
|
||
|
// to a particular sub-tree of a document.
|
||
|
//
|
||
|
// Supported Selectors:
|
||
|
// --------------------
|
||
|
//
|
||
|
// acme supports a rich set of CSS3 selectors, including:
|
||
|
//
|
||
|
// - class selectors (e.g., `.foo`)
|
||
|
// - node type selectors like `span`
|
||
|
// - ` ` descendant selectors
|
||
|
// - `>` child element selectors
|
||
|
// - `#foo` style ID selectors
|
||
|
// - `*` universal selector
|
||
|
// - `~`, the preceded-by sibling selector
|
||
|
// - `+`, the immediately preceded-by sibling selector
|
||
|
// - attribute queries:
|
||
|
// - `[foo]` attribute presence selector
|
||
|
// - `[foo='bar']` attribute value exact match
|
||
|
// - `[foo~='bar']` attribute value list item match
|
||
|
// - `[foo^='bar']` attribute start match
|
||
|
// - `[foo$='bar']` attribute end match
|
||
|
// - `[foo*='bar']` attribute substring match
|
||
|
// - `:first-child`, `:last-child`, and `:only-child` positional selectors
|
||
|
// - `:empty` content emtpy selector
|
||
|
// - `:checked` pseudo selector
|
||
|
// - `:nth-child(n)`, `:nth-child(2n+1)` style positional calculations
|
||
|
// - `:nth-child(even)`, `:nth-child(odd)` positional selectors
|
||
|
// - `:not(...)` negation pseudo selectors
|
||
|
//
|
||
|
// Any legal combination of these selectors will work with
|
||
|
// `dojo.query()`, including compound selectors ("," delimited).
|
||
|
// Very complex and useful searches can be constructed with this
|
||
|
// palette of selectors and when combined with functions for
|
||
|
// manipulation presented by dojo/NodeList, many types of DOM
|
||
|
// manipulation operations become very straightforward.
|
||
|
//
|
||
|
// Unsupported Selectors:
|
||
|
// ----------------------
|
||
|
//
|
||
|
// While dojo.query handles many CSS3 selectors, some fall outside of
|
||
|
// what's reasonable for a programmatic node querying engine to
|
||
|
// handle. Currently unsupported selectors include:
|
||
|
//
|
||
|
// - namespace-differentiated selectors of any form
|
||
|
// - all `::` pseduo-element selectors
|
||
|
// - certain pseudo-selectors which don't get a lot of day-to-day use:
|
||
|
// - `:root`, `:lang()`, `:target`, `:focus`
|
||
|
// - all visual and state selectors:
|
||
|
// - `:root`, `:active`, `:hover`, `:visited`, `:link`,
|
||
|
// `:enabled`, `:disabled`
|
||
|
// - `:*-of-type` pseudo selectors
|
||
|
//
|
||
|
// dojo.query and XML Documents:
|
||
|
// -----------------------------
|
||
|
//
|
||
|
// `dojo.query` (as of dojo 1.2) supports searching XML documents
|
||
|
// in a case-sensitive manner. If an HTML document is served with
|
||
|
// a doctype that forces case-sensitivity (e.g., XHTML 1.1
|
||
|
// Strict), dojo.query() will detect this and "do the right
|
||
|
// thing". Case sensitivity is dependent upon the document being
|
||
|
// searched and not the query used. It is therefore possible to
|
||
|
// use case-sensitive queries on strict sub-documents (iframes,
|
||
|
// etc.) or XML documents while still assuming case-insensitivity
|
||
|
// for a host/root document.
|
||
|
//
|
||
|
// Non-selector Queries:
|
||
|
// ---------------------
|
||
|
//
|
||
|
// If something other than a String is passed for the query,
|
||
|
// `dojo.query` will return a new `dojo/NodeList` instance
|
||
|
// constructed from that parameter alone and all further
|
||
|
// processing will stop. This means that if you have a reference
|
||
|
// to a node or NodeList, you can quickly construct a new NodeList
|
||
|
// from the original by calling `dojo.query(node)` or
|
||
|
// `dojo.query(list)`.
|
||
|
//
|
||
|
// query:
|
||
|
// The CSS3 expression to match against. For details on the syntax of
|
||
|
// CSS3 selectors, see <http://www.w3.org/TR/css3-selectors/#selectors>
|
||
|
// root:
|
||
|
// A DOMNode (or node id) to scope the search from. Optional.
|
||
|
// returns: Array
|
||
|
// example:
|
||
|
// search the entire document for elements with the class "foo":
|
||
|
// | require(["dojo/query"], function(query) {
|
||
|
// | query(".foo").forEach(function(q) { console.log(q); });
|
||
|
// | });
|
||
|
// these elements will match:
|
||
|
// | <span class="foo"></span>
|
||
|
// | <span class="foo bar"></span>
|
||
|
// | <p class="thud foo"></p>
|
||
|
// example:
|
||
|
// search the entire document for elements with the classes "foo" *and* "bar":
|
||
|
// | require(["dojo/query"], function(query) {
|
||
|
// | query(".foo.bar").forEach(function(q) { console.log(q); });
|
||
|
// | });
|
||
|
|
||
|
// these elements will match:
|
||
|
// | <span class="foo bar"></span>
|
||
|
// while these will not:
|
||
|
// | <span class="foo"></span>
|
||
|
// | <p class="thud foo"></p>
|
||
|
// example:
|
||
|
// find `<span>` elements which are descendants of paragraphs and
|
||
|
// which have a "highlighted" class:
|
||
|
// | require(["dojo/query"], function(query) {
|
||
|
// | query("p span.highlighted").forEach(function(q) { console.log(q); });
|
||
|
// | });
|
||
|
// the innermost span in this fragment matches:
|
||
|
// | <p class="foo">
|
||
|
// | <span>...
|
||
|
// | <span class="highlighted foo bar">...</span>
|
||
|
// | </span>
|
||
|
// | </p>
|
||
|
// example:
|
||
|
// set an "odd" class on all odd table rows inside of the table
|
||
|
// `#tabular_data`, using the `>` (direct child) selector to avoid
|
||
|
// affecting any nested tables:
|
||
|
// | require(["dojo/query"], function(query) {
|
||
|
// | query("#tabular_data > tbody > tr:nth-child(odd)").addClass("odd");
|
||
|
// | );
|
||
|
// example:
|
||
|
// remove all elements with the class "error" from the document:
|
||
|
// | require(["dojo/query"], function(query) {
|
||
|
// | query(".error").orphan();
|
||
|
// | );
|
||
|
// example:
|
||
|
// add an onclick handler to every submit button in the document
|
||
|
// which causes the form to be sent via Ajax instead:
|
||
|
// | require(["dojo/query", "dojo/request", "dojo/dom-construct", "dojo/dom-style"
|
||
|
// | ], function (query, request, domConstruct, domStyle) {
|
||
|
// | query("input[type='submit']").on("click", function (e) {
|
||
|
// | e.stopPropagation();
|
||
|
// | e.preventDefault();
|
||
|
// | var btn = e.target;
|
||
|
// | request.post("", { data: btn.form, timeout: 2000 })
|
||
|
// | .then(function (data) {
|
||
|
// | // replace the form with the response
|
||
|
// | domConstruct.create("div", { innerHTML: data }, btn.form, "after");
|
||
|
// | domStyle.set(btn.form, "display", "none");
|
||
|
// | });
|
||
|
// | });
|
||
|
// | });
|
||
|
|
||
|
|
||
|
root = root || getDoc();
|
||
|
|
||
|
// throw the big case sensitivity switch
|
||
|
var od = root.ownerDocument || root; // root is either Document or a node inside the document
|
||
|
caseSensitive = (od.createElement("div").tagName === "div");
|
||
|
|
||
|
// NOTE:
|
||
|
// adding "true" as the 2nd argument to getQueryFunc is useful for
|
||
|
// testing the DOM branch without worrying about the
|
||
|
// behavior/performance of the QSA branch.
|
||
|
var r = getQueryFunc(query)(root);
|
||
|
|
||
|
// FIXME:
|
||
|
// need to investigate this branch WRT #8074 and #8075
|
||
|
if(r && r.nozip){
|
||
|
return r;
|
||
|
}
|
||
|
return _zip(r); // dojo/NodeList
|
||
|
};
|
||
|
query.filter = function(/*Node[]*/ nodeList, /*String*/ filter, /*String|DOMNode?*/ root){
|
||
|
// summary:
|
||
|
// function for filtering a NodeList based on a selector, optimized for simple selectors
|
||
|
var tmpNodeList = [],
|
||
|
parts = getQueryParts(filter),
|
||
|
filterFunc =
|
||
|
(parts.length == 1 && !/[^\w#\.]/.test(filter)) ?
|
||
|
getSimpleFilterFunc(parts[0]) :
|
||
|
function(node){
|
||
|
return array.indexOf(query(filter, dom.byId(root)), node) != -1;
|
||
|
};
|
||
|
for(var x = 0, te; te = nodeList[x]; x++){
|
||
|
if(filterFunc(te)){ tmpNodeList.push(te); }
|
||
|
}
|
||
|
return tmpNodeList;
|
||
|
};
|
||
|
return query;
|
||
|
});
|
||
|
|
||
|
},
|
||
|
'dojo/NodeList-dom':function(){
|
||
|
define(["./_base/kernel", "./query", "./_base/array", "./_base/lang", "./dom-class", "./dom-construct", "./dom-geometry", "./dom-attr", "./dom-style"], function(dojo, query, array, lang, domCls, domCtr, domGeom, domAttr, domStyle){
|
||
|
|
||
|
// module:
|
||
|
// dojo/NodeList-dom.js
|
||
|
|
||
|
/*=====
|
||
|
return function(){
|
||
|
// summary:
|
||
|
// Adds DOM related methods to NodeList, and returns NodeList constructor.
|
||
|
};
|
||
|
=====*/
|
||
|
|
||
|
var magicGuard = function(a){
|
||
|
// summary:
|
||
|
// the guard function for dojo/dom-attr() and dojo/dom-style()
|
||
|
return a.length == 1 && (typeof a[0] == "string"); // inline'd type check
|
||
|
};
|
||
|
|
||
|
var orphan = function(node){
|
||
|
// summary:
|
||
|
// function to orphan nodes
|
||
|
var p = node.parentNode;
|
||
|
if(p){
|
||
|
p.removeChild(node);
|
||
|
}
|
||
|
};
|
||
|
// FIXME: should we move orphan() to dojo/_base/html?
|
||
|
|
||
|
var NodeList = query.NodeList,
|
||
|
awc = NodeList._adaptWithCondition,
|
||
|
aafe = NodeList._adaptAsForEach,
|
||
|
aam = NodeList._adaptAsMap;
|
||
|
|
||
|
function getSet(module){
|
||
|
return function(node, name, value){
|
||
|
if(arguments.length == 2){
|
||
|
return module[typeof name == "string" ? "get" : "set"](node, name);
|
||
|
}
|
||
|
// setter
|
||
|
return module.set(node, name, value);
|
||
|
};
|
||
|
}
|
||
|
|
||
|
lang.extend(NodeList, {
|
||
|
_normalize: function(/*String||Element||Object||NodeList*/content, /*DOMNode?*/refNode){
|
||
|
// summary:
|
||
|
// normalizes data to an array of items to insert.
|
||
|
// description:
|
||
|
// If content is an object, it can have special properties "template" and
|
||
|
// "parse". If "template" is defined, then the template value is run through
|
||
|
// dojo/string.substitute (if dojo/string.substitute() has been required elsewhere),
|
||
|
// or if templateFunc is a function on the content, that function will be used to
|
||
|
// transform the template into a final string to be used for for passing to dojo/dom-construct.toDom().
|
||
|
// If content.parse is true, then it is remembered for later, for when the content
|
||
|
// nodes are inserted into the DOM. At that point, the nodes will be parsed for widgets
|
||
|
// (if dojo/parser has been required elsewhere).
|
||
|
|
||
|
//Wanted to just use a DocumentFragment, but for the array/NodeList
|
||
|
//case that meant using cloneNode, but we may not want that.
|
||
|
//Cloning should only happen if the node operations span
|
||
|
//multiple refNodes. Also, need a real array, not a NodeList from the
|
||
|
//DOM since the node movements could change those NodeLists.
|
||
|
|
||
|
var parse = content.parse === true;
|
||
|
|
||
|
//Do we have an object that needs to be run through a template?
|
||
|
if(typeof content.template == "string"){
|
||
|
var templateFunc = content.templateFunc || (dojo.string && dojo.string.substitute);
|
||
|
content = templateFunc ? templateFunc(content.template, content) : content;
|
||
|
}
|
||
|
|
||
|
var type = (typeof content);
|
||
|
if(type == "string" || type == "number"){
|
||
|
content = domCtr.toDom(content, (refNode && refNode.ownerDocument));
|
||
|
if(content.nodeType == 11){
|
||
|
//DocumentFragment. It cannot handle cloneNode calls, so pull out the children.
|
||
|
content = lang._toArray(content.childNodes);
|
||
|
}else{
|
||
|
content = [content];
|
||
|
}
|
||
|
}else if(!lang.isArrayLike(content)){
|
||
|
content = [content];
|
||
|
}else if(!lang.isArray(content)){
|
||
|
//To get to this point, content is array-like, but
|
||
|
//not an array, which likely means a DOM NodeList. Convert it now.
|
||
|
content = lang._toArray(content);
|
||
|
}
|
||
|
|
||
|
//Pass around the parse info
|
||
|
if(parse){
|
||
|
content._runParse = true;
|
||
|
}
|
||
|
return content; //Array
|
||
|
},
|
||
|
|
||
|
_cloneNode: function(/*DOMNode*/ node){
|
||
|
// summary:
|
||
|
// private utility to clone a node. Not very interesting in the vanilla
|
||
|
// dojo/NodeList case, but delegates could do interesting things like
|
||
|
// clone event handlers if that is derivable from the node.
|
||
|
return node.cloneNode(true);
|
||
|
},
|
||
|
|
||
|
_place: function(/*Array*/ary, /*DOMNode*/refNode, /*String*/position, /*Boolean*/useClone){
|
||
|
// summary:
|
||
|
// private utility to handle placing an array of nodes relative to another node.
|
||
|
// description:
|
||
|
// Allows for cloning the nodes in the array, and for
|
||
|
// optionally parsing widgets, if ary._runParse is true.
|
||
|
|
||
|
//Avoid a disallowed operation if trying to do an innerHTML on a non-element node.
|
||
|
if(refNode.nodeType != 1 && position == "only"){
|
||
|
return;
|
||
|
}
|
||
|
var rNode = refNode, tempNode;
|
||
|
|
||
|
//Always cycle backwards in case the array is really a
|
||
|
//DOM NodeList and the DOM operations take it out of the live collection.
|
||
|
var length = ary.length;
|
||
|
for(var i = length - 1; i >= 0; i--){
|
||
|
var node = (useClone ? this._cloneNode(ary[i]) : ary[i]);
|
||
|
|
||
|
//If need widget parsing, use a temp node, instead of waiting after inserting into
|
||
|
//real DOM because we need to start widget parsing at one node up from current node,
|
||
|
//which could cause some already parsed widgets to be parsed again.
|
||
|
if(ary._runParse && dojo.parser && dojo.parser.parse){
|
||
|
if(!tempNode){
|
||
|
tempNode = rNode.ownerDocument.createElement("div");
|
||
|
}
|
||
|
tempNode.appendChild(node);
|
||
|
dojo.parser.parse(tempNode);
|
||
|
node = tempNode.firstChild;
|
||
|
while(tempNode.firstChild){
|
||
|
tempNode.removeChild(tempNode.firstChild);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
if(i == length - 1){
|
||
|
domCtr.place(node, rNode, position);
|
||
|
}else{
|
||
|
rNode.parentNode.insertBefore(node, rNode);
|
||
|
}
|
||
|
rNode = node;
|
||
|
}
|
||
|
},
|
||
|
|
||
|
|
||
|
position: aam(domGeom.position),
|
||
|
/*=====
|
||
|
position: function(){
|
||
|
// summary:
|
||
|
// Returns border-box objects (x/y/w/h) of all elements in a node list
|
||
|
// as an Array (*not* a NodeList). Acts like `dojo/dom-geometry-position`, though
|
||
|
// assumes the node passed is each node in this list.
|
||
|
|
||
|
return dojo.map(this, dojo.position); // Array
|
||
|
},
|
||
|
=====*/
|
||
|
|
||
|
attr: awc(getSet(domAttr), magicGuard),
|
||
|
/*=====
|
||
|
attr: function(property, value){
|
||
|
// summary:
|
||
|
// gets or sets the DOM attribute for every element in the
|
||
|
// NodeList. See also `dojo/dom-attr`
|
||
|
// property: String
|
||
|
// the attribute to get/set
|
||
|
// value: String?
|
||
|
// optional. The value to set the property to
|
||
|
// returns:
|
||
|
// if no value is passed, the result is an array of attribute values
|
||
|
// If a value is passed, the return is this NodeList
|
||
|
// example:
|
||
|
// Make all nodes with a particular class focusable:
|
||
|
// | require(["dojo/query", "dojo/NodeList-dom"], function(query){
|
||
|
// | query(".focusable").attr("tabIndex", -1);
|
||
|
// | });
|
||
|
// example:
|
||
|
// Disable a group of buttons:
|
||
|
// | require(["dojo/query", "dojo/NodeList-dom"], function(query){
|
||
|
// | query("button.group").attr("disabled", true);
|
||
|
// | });
|
||
|
// example:
|
||
|
// innerHTML can be assigned or retrieved as well:
|
||
|
// | // get the innerHTML (as an array) for each list item
|
||
|
// | require(["dojo/query", "dojo/NodeList-dom"], function(query){
|
||
|
// | var ih = query("li.replaceable").attr("innerHTML");
|
||
|
// | });
|
||
|
return; // dojo/NodeList|Array
|
||
|
},
|
||
|
=====*/
|
||
|
|
||
|
style: awc(getSet(domStyle), magicGuard),
|
||
|
/*=====
|
||
|
style: function(property, value){
|
||
|
// summary:
|
||
|
// gets or sets the CSS property for every element in the NodeList
|
||
|
// property: String
|
||
|
// the CSS property to get/set, in JavaScript notation
|
||
|
// ("lineHieght" instead of "line-height")
|
||
|
// value: String?
|
||
|
// optional. The value to set the property to
|
||
|
// returns:
|
||
|
// if no value is passed, the result is an array of strings.
|
||
|
// If a value is passed, the return is this NodeList
|
||
|
return; // dojo/NodeList
|
||
|
return; // Array
|
||
|
},
|
||
|
=====*/
|
||
|
|
||
|
addClass: aafe(domCls.add),
|
||
|
/*=====
|
||
|
addClass: function(className){
|
||
|
// summary:
|
||
|
// adds the specified class to every node in the list
|
||
|
// className: String|Array
|
||
|
// A String class name to add, or several space-separated class names,
|
||
|
// or an array of class names.
|
||
|
return; // dojo/NodeList
|
||
|
},
|
||
|
=====*/
|
||
|
|
||
|
removeClass: aafe(domCls.remove),
|
||
|
/*=====
|
||
|
removeClass: function(className){
|
||
|
// summary:
|
||
|
// removes the specified class from every node in the list
|
||
|
// className: String|Array?
|
||
|
// An optional String class name to remove, or several space-separated
|
||
|
// class names, or an array of class names. If omitted, all class names
|
||
|
// will be deleted.
|
||
|
// returns:
|
||
|
// this list
|
||
|
return; // dojo/NodeList
|
||
|
},
|
||
|
=====*/
|
||
|
|
||
|
toggleClass: aafe(domCls.toggle),
|
||
|
/*=====
|
||
|
toggleClass: function(className, condition){
|
||
|
// summary:
|
||
|
// Adds a class to node if not present, or removes if present.
|
||
|
// Pass a boolean condition if you want to explicitly add or remove.
|
||
|
// condition: Boolean?
|
||
|
// If passed, true means to add the class, false means to remove.
|
||
|
// className: String
|
||
|
// the CSS class to add
|
||
|
return; // dojo/NodeList
|
||
|
},
|
||
|
=====*/
|
||
|
|
||
|
replaceClass: aafe(domCls.replace),
|
||
|
/*=====
|
||
|
replaceClass: function(addClassStr, removeClassStr){
|
||
|
// summary:
|
||
|
// Replaces one or more classes on a node if not present.
|
||
|
// Operates more quickly than calling `removeClass()` and `addClass()`
|
||
|
// addClassStr: String|Array
|
||
|
// A String class name to add, or several space-separated class names,
|
||
|
// or an array of class names.
|
||
|
// removeClassStr: String|Array?
|
||
|
// A String class name to remove, or several space-separated class names,
|
||
|
// or an array of class names.
|
||
|
return; // dojo/NodeList
|
||
|
},
|
||
|
=====*/
|
||
|
|
||
|
empty: aafe(domCtr.empty),
|
||
|
/*=====
|
||
|
empty: function(){
|
||
|
// summary:
|
||
|
// clears all content from each node in the list. Effectively
|
||
|
// equivalent to removing all child nodes from every item in
|
||
|
// the list.
|
||
|
return this.forEach("item.innerHTML='';"); // dojo/NodeList
|
||
|
// FIXME: should we be checking for and/or disposing of widgets below these nodes?
|
||
|
},
|
||
|
=====*/
|
||
|
|
||
|
removeAttr: aafe(domAttr.remove),
|
||
|
/*=====
|
||
|
removeAttr: function(name){
|
||
|
// summary:
|
||
|
// Removes an attribute from each node in the list.
|
||
|
// name: String
|
||
|
// the name of the attribute to remove
|
||
|
return; // dojo/NodeList
|
||
|
},
|
||
|
=====*/
|
||
|
|
||
|
marginBox: aam(domGeom.getMarginBox),
|
||
|
/*=====
|
||
|
marginBox: function(){
|
||
|
// summary:
|
||
|
// Returns margin-box size of nodes
|
||
|
return; // dojo/NodeList
|
||
|
},
|
||
|
=====*/
|
||
|
|
||
|
// FIXME: connectPublisher()? connectRunOnce()?
|
||
|
|
||
|
/*
|
||
|
destroy: function(){
|
||
|
// summary:
|
||
|
// destroys every item in the list.
|
||
|
this.forEach(d.destroy);
|
||
|
// FIXME: should we be checking for and/or disposing of widgets below these nodes?
|
||
|
},
|
||
|
*/
|
||
|
|
||
|
place: function(/*String||Node*/ queryOrNode, /*String*/ position){
|
||
|
// summary:
|
||
|
// places elements of this node list relative to the first element matched
|
||
|
// by queryOrNode. Returns the original NodeList. See: `dojo/dom-construct.place`
|
||
|
// queryOrNode:
|
||
|
// may be a string representing any valid CSS3 selector or a DOM node.
|
||
|
// In the selector case, only the first matching element will be used
|
||
|
// for relative positioning.
|
||
|
// position:
|
||
|
// can be one of:
|
||
|
//
|
||
|
// - "last" (default)
|
||
|
// - "first"
|
||
|
// - "before"
|
||
|
// - "after"
|
||
|
// - "only"
|
||
|
// - "replace"
|
||
|
//
|
||
|
// or an offset in the childNodes property
|
||
|
var item = query(queryOrNode)[0];
|
||
|
return this.forEach(function(node){ domCtr.place(node, item, position); }); // dojo/NodeList
|
||
|
},
|
||
|
|
||
|
orphan: function(/*String?*/ filter){
|
||
|
// summary:
|
||
|
// removes elements in this list that match the filter
|
||
|
// from their parents and returns them as a new NodeList.
|
||
|
// filter:
|
||
|
// CSS selector like ".foo" or "div > span"
|
||
|
// returns:
|
||
|
// NodeList containing the orphaned elements
|
||
|
return (filter ? query._filterResult(this, filter) : this).forEach(orphan); // dojo/NodeList
|
||
|
},
|
||
|
|
||
|
adopt: function(/*String||Array||DomNode*/ queryOrListOrNode, /*String?*/ position){
|
||
|
// summary:
|
||
|
// places any/all elements in queryOrListOrNode at a
|
||
|
// position relative to the first element in this list.
|
||
|
// Returns a dojo/NodeList of the adopted elements.
|
||
|
// queryOrListOrNode:
|
||
|
// a DOM node or a query string or a query result.
|
||
|
// Represents the nodes to be adopted relative to the
|
||
|
// first element of this NodeList.
|
||
|
// position:
|
||
|
// can be one of:
|
||
|
//
|
||
|
// - "last" (default)
|
||
|
// - "first"
|
||
|
// - "before"
|
||
|
// - "after"
|
||
|
// - "only"
|
||
|
// - "replace"
|
||
|
//
|
||
|
// or an offset in the childNodes property
|
||
|
return query(queryOrListOrNode).place(this[0], position)._stash(this); // dojo/NodeList
|
||
|
},
|
||
|
|
||
|
// FIXME: do we need this?
|
||
|
query: function(/*String*/ queryStr){
|
||
|
// summary:
|
||
|
// Returns a new list whose members match the passed query,
|
||
|
// assuming elements of the current NodeList as the root for
|
||
|
// each search.
|
||
|
// example:
|
||
|
// assume a DOM created by this markup:
|
||
|
// | <div id="foo">
|
||
|
// | <p>
|
||
|
// | bacon is tasty, <span>dontcha think?</span>
|
||
|
// | </p>
|
||
|
// | </div>
|
||
|
// | <div id="bar">
|
||
|
// | <p>great comedians may not be funny <span>in person</span></p>
|
||
|
// | </div>
|
||
|
// If we are presented with the following definition for a NodeList:
|
||
|
// | require(["dojo/dom", "dojo/query", "dojo/NodeList-dom"
|
||
|
// | ], function(dom, query){
|
||
|
// | var l = new NodeList(dom.byId("foo"), dom.byId("bar"));
|
||
|
// it's possible to find all span elements under paragraphs
|
||
|
// contained by these elements with this sub-query:
|
||
|
// | var spans = l.query("p span");
|
||
|
// | });
|
||
|
|
||
|
// FIXME: probably slow
|
||
|
if(!queryStr){ return this; }
|
||
|
var ret = new NodeList;
|
||
|
this.map(function(node){
|
||
|
// FIXME: why would we ever get undefined here?
|
||
|
query(queryStr, node).forEach(function(subNode){
|
||
|
if(subNode !== undefined){
|
||
|
ret.push(subNode);
|
||
|
}
|
||
|
});
|
||
|
});
|
||
|
return ret._stash(this); // dojo/NodeList
|
||
|
},
|
||
|
|
||
|
filter: function(/*String|Function*/ filter){
|
||
|
// summary:
|
||
|
// "masks" the built-in javascript filter() method (supported
|
||
|
// in Dojo via `dojo.filter`) to support passing a simple
|
||
|
// string filter in addition to supporting filtering function
|
||
|
// objects.
|
||
|
// filter:
|
||
|
// If a string, a CSS rule like ".thinger" or "div > span".
|
||
|
// example:
|
||
|
// "regular" JS filter syntax as exposed in dojo.filter:
|
||
|
// | require(["dojo/query", "dojo/NodeList-dom"
|
||
|
// | ], function(query){
|
||
|
// | query("*").filter(function(item){
|
||
|
// | // highlight every paragraph
|
||
|
// | return (item.nodeName == "p");
|
||
|
// | }).style("backgroundColor", "yellow");
|
||
|
// | });
|
||
|
// example:
|
||
|
// the same filtering using a CSS selector
|
||
|
// | require(["dojo/query", "dojo/NodeList-dom"
|
||
|
// | ], function(query){
|
||
|
// | query("*").filter("p").styles("backgroundColor", "yellow");
|
||
|
// | });
|
||
|
var a = arguments, items = this, start = 0;
|
||
|
if(typeof filter == "string"){ // inline'd type check
|
||
|
items = query._filterResult(this, a[0]);
|
||
|
if(a.length == 1){
|
||
|
// if we only got a string query, pass back the filtered results
|
||
|
return items._stash(this); // dojo/NodeList
|
||
|
}
|
||
|
// if we got a callback, run it over the filtered items
|
||
|
start = 1;
|
||
|
}
|
||
|
return this._wrap(array.filter(items, a[start], a[start + 1]), this); // dojo/NodeList
|
||
|
},
|
||
|
|
||
|
/*
|
||
|
// FIXME: should this be "copyTo" and include parenting info?
|
||
|
clone: function(){
|
||
|
// summary:
|
||
|
// creates node clones of each element of this list
|
||
|
// and returns a new list containing the clones
|
||
|
},
|
||
|
*/
|
||
|
|
||
|
addContent: function(/*String||DomNode||Object||dojo/NodeList*/ content, /*String||Integer?*/ position){
|
||
|
// summary:
|
||
|
// add a node, NodeList or some HTML as a string to every item in the
|
||
|
// list. Returns the original list.
|
||
|
// description:
|
||
|
// a copy of the HTML content is added to each item in the
|
||
|
// list, with an optional position argument. If no position
|
||
|
// argument is provided, the content is appended to the end of
|
||
|
// each item.
|
||
|
// content:
|
||
|
// DOM node, HTML in string format, a NodeList or an Object. If a DOM node or
|
||
|
// NodeList, the content will be cloned if the current NodeList has more than one
|
||
|
// element. Only the DOM nodes are cloned, no event handlers. If it is an Object,
|
||
|
// it should be an object with at "template" String property that has the HTML string
|
||
|
// to insert. If dojo.string has already been dojo.required, then dojo.string.substitute
|
||
|
// will be used on the "template" to generate the final HTML string. Other allowed
|
||
|
// properties on the object are: "parse" if the HTML
|
||
|
// string should be parsed for widgets (dojo.require("dojo.parser") to get that
|
||
|
// option to work), and "templateFunc" if a template function besides dojo.string.substitute
|
||
|
// should be used to transform the "template".
|
||
|
// position:
|
||
|
// can be one of:
|
||
|
//
|
||
|
// - "last"||"end" (default)
|
||
|
// - "first||"start"
|
||
|
// - "before"
|
||
|
// - "after"
|
||
|
// - "replace" (replaces nodes in this NodeList with new content)
|
||
|
// - "only" (removes other children of the nodes so new content is the only child)
|
||
|
//
|
||
|
// or an offset in the childNodes property
|
||
|
// example:
|
||
|
// appends content to the end if the position is omitted
|
||
|
// | require(["dojo/query", "dojo/NodeList-dom"
|
||
|
// | ], function(query){
|
||
|
// | query("h3 > p").addContent("hey there!");
|
||
|
// | });
|
||
|
// example:
|
||
|
// add something to the front of each element that has a
|
||
|
// "thinger" property:
|
||
|
// | require(["dojo/query", "dojo/NodeList-dom"
|
||
|
// | ], function(query){
|
||
|
// | query("[thinger]").addContent("...", "first");
|
||
|
// | });
|
||
|
// example:
|
||
|
// adds a header before each element of the list
|
||
|
// | require(["dojo/query", "dojo/NodeList-dom"
|
||
|
// | ], function(query){
|
||
|
// | query(".note").addContent("<h4>NOTE:</h4>", "before");
|
||
|
// | });
|
||
|
// example:
|
||
|
// add a clone of a DOM node to the end of every element in
|
||
|
// the list, removing it from its existing parent.
|
||
|
// | require(["dojo/dom", "dojo/query", "dojo/NodeList-dom"
|
||
|
// | ], function(dom, query){
|
||
|
// | query(".note").addContent(dom.byId("foo"));
|
||
|
// | });
|
||
|
// example:
|
||
|
// Append nodes from a templatized string.
|
||
|
// | require(["dojo/string", "dojo/query", "dojo/NodeList-dom"
|
||
|
// | ], function(string, query){
|
||
|
// | query(".note").addContent({
|
||
|
// | template: '<b>${id}: </b><span>${name}</span>',
|
||
|
// | id: "user332",
|
||
|
// | name: "Mr. Anderson"
|
||
|
// | });
|
||
|
// | });
|
||
|
// example:
|
||
|
// Append nodes from a templatized string that also has widgets parsed.
|
||
|
// | require(["dojo/string", "dojo/parser", "dojo/query", "dojo/NodeList-dom"
|
||
|
// | ], function(string, parser, query){
|
||
|
// | var notes = query(".note").addContent({
|
||
|
// | template: '<button dojoType="dijit/form/Button">${text}</button>',
|
||
|
// | parse: true,
|
||
|
// | text: "Send"
|
||
|
// | });
|
||
|
// | });
|
||
|
content = this._normalize(content, this[0]);
|
||
|
for(var i = 0, node; (node = this[i]); i++){
|
||
|
if(content.length){
|
||
|
this._place(content, node, position, i > 0);
|
||
|
}else{
|
||
|
// if it is an empty array, we empty the target node
|
||
|
domCtr.empty(node);
|
||
|
}
|
||
|
}
|
||
|
return this; // dojo/NodeList
|
||
|
}
|
||
|
});
|
||
|
|
||
|
return NodeList;
|
||
|
});
|
||
|
|
||
|
},
|
||
|
'dojo/_base/fx':function(){
|
||
|
define(["./kernel", "./config", /*===== "./declare", =====*/ "./lang", "../Evented", "./Color", "../aspect", "../sniff", "../dom", "../dom-style"],
|
||
|
function(dojo, config, /*===== declare, =====*/ lang, Evented, Color, aspect, has, dom, style){
|
||
|
// module:
|
||
|
// dojo/_base/fx
|
||
|
// notes:
|
||
|
// Animation loosely package based on Dan Pupius' work, contributed under CLA; see
|
||
|
// http://pupius.co.uk/js/Toolkit.Drawing.js
|
||
|
|
||
|
var _mixin = lang.mixin;
|
||
|
|
||
|
// Module export
|
||
|
var basefx = {
|
||
|
// summary:
|
||
|
// This module defines the base dojo/_base/fx implementation.
|
||
|
};
|
||
|
|
||
|
var _Line = basefx._Line = function(/*int*/ start, /*int*/ end){
|
||
|
// summary:
|
||
|
// Object used to generate values from a start value to an end value
|
||
|
// start: int
|
||
|
// Beginning value for range
|
||
|
// end: int
|
||
|
// Ending value for range
|
||
|
this.start = start;
|
||
|
this.end = end;
|
||
|
};
|
||
|
|
||
|
_Line.prototype.getValue = function(/*float*/ n){
|
||
|
// summary:
|
||
|
// Returns the point on the line
|
||
|
// n:
|
||
|
// a floating point number greater than 0 and less than 1
|
||
|
return ((this.end - this.start) * n) + this.start; // Decimal
|
||
|
};
|
||
|
|
||
|
var Animation = basefx.Animation = function(args){
|
||
|
// summary:
|
||
|
// A generic animation class that fires callbacks into its handlers
|
||
|
// object at various states.
|
||
|
// description:
|
||
|
// A generic animation class that fires callbacks into its handlers
|
||
|
// object at various states. Nearly all dojo animation functions
|
||
|
// return an instance of this method, usually without calling the
|
||
|
// .play() method beforehand. Therefore, you will likely need to
|
||
|
// call .play() on instances of `Animation` when one is
|
||
|
// returned.
|
||
|
// args: Object
|
||
|
// The 'magic argument', mixing all the properties into this
|
||
|
// animation instance.
|
||
|
|
||
|
_mixin(this, args);
|
||
|
if(lang.isArray(this.curve)){
|
||
|
this.curve = new _Line(this.curve[0], this.curve[1]);
|
||
|
}
|
||
|
|
||
|
};
|
||
|
Animation.prototype = new Evented();
|
||
|
|
||
|
lang.extend(Animation, {
|
||
|
// duration: Integer
|
||
|
// The time in milliseconds the animation will take to run
|
||
|
duration: 350,
|
||
|
|
||
|
/*=====
|
||
|
// curve: _Line|Array
|
||
|
// A two element array of start and end values, or a `_Line` instance to be
|
||
|
// used in the Animation.
|
||
|
curve: null,
|
||
|
|
||
|
// easing: Function?
|
||
|
// A Function to adjust the acceleration (or deceleration) of the progress
|
||
|
// across a _Line
|
||
|
easing: null,
|
||
|
=====*/
|
||
|
|
||
|
// repeat: Integer?
|
||
|
// The number of times to loop the animation
|
||
|
repeat: 0,
|
||
|
|
||
|
// rate: Integer?
|
||
|
// the time in milliseconds to wait before advancing to next frame
|
||
|
// (used as a fps timer: 1000/rate = fps)
|
||
|
rate: 20 /* 50 fps */,
|
||
|
|
||
|
/*=====
|
||
|
// delay: Integer?
|
||
|
// The time in milliseconds to wait before starting animation after it
|
||
|
// has been .play()'ed
|
||
|
delay: null,
|
||
|
|
||
|
// beforeBegin: Event?
|
||
|
// Synthetic event fired before a Animation begins playing (synchronous)
|
||
|
beforeBegin: null,
|
||
|
|
||
|
// onBegin: Event?
|
||
|
// Synthetic event fired as a Animation begins playing (useful?)
|
||
|
onBegin: null,
|
||
|
|
||
|
// onAnimate: Event?
|
||
|
// Synthetic event fired at each interval of the Animation
|
||
|
onAnimate: null,
|
||
|
|
||
|
// onEnd: Event?
|
||
|
// Synthetic event fired after the final frame of the Animation
|
||
|
onEnd: null,
|
||
|
|
||
|
// onPlay: Event?
|
||
|
// Synthetic event fired any time the Animation is play()'ed
|
||
|
onPlay: null,
|
||
|
|
||
|
// onPause: Event?
|
||
|
// Synthetic event fired when the Animation is paused
|
||
|
onPause: null,
|
||
|
|
||
|
// onStop: Event
|
||
|
// Synthetic event fires when the Animation is stopped
|
||
|
onStop: null,
|
||
|
|
||
|
=====*/
|
||
|
|
||
|
_percent: 0,
|
||
|
_startRepeatCount: 0,
|
||
|
|
||
|
_getStep: function(){
|
||
|
var _p = this._percent,
|
||
|
_e = this.easing
|
||
|
;
|
||
|
return _e ? _e(_p) : _p;
|
||
|
},
|
||
|
_fire: function(/*Event*/ evt, /*Array?*/ args){
|
||
|
// summary:
|
||
|
// Convenience function. Fire event "evt" and pass it the
|
||
|
// arguments specified in "args".
|
||
|
// description:
|
||
|
// Convenience function. Fire event "evt" and pass it the
|
||
|
// arguments specified in "args".
|
||
|
// Fires the callback in the scope of this Animation
|
||
|
// instance.
|
||
|
// evt:
|
||
|
// The event to fire.
|
||
|
// args:
|
||
|
// The arguments to pass to the event.
|
||
|
var a = args||[];
|
||
|
if(this[evt]){
|
||
|
if(config.debugAtAllCosts){
|
||
|
this[evt].apply(this, a);
|
||
|
}else{
|
||
|
try{
|
||
|
this[evt].apply(this, a);
|
||
|
}catch(e){
|
||
|
// squelch and log because we shouldn't allow exceptions in
|
||
|
// synthetic event handlers to cause the internal timer to run
|
||
|
// amuck, potentially pegging the CPU. I'm not a fan of this
|
||
|
// squelch, but hopefully logging will make it clear what's
|
||
|
// going on
|
||
|
console.error("exception in animation handler for:", evt);
|
||
|
console.error(e);
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
return this; // Animation
|
||
|
},
|
||
|
|
||
|
play: function(/*int?*/ delay, /*Boolean?*/ gotoStart){
|
||
|
// summary:
|
||
|
// Start the animation.
|
||
|
// delay:
|
||
|
// How many milliseconds to delay before starting.
|
||
|
// gotoStart:
|
||
|
// If true, starts the animation from the beginning; otherwise,
|
||
|
// starts it from its current position.
|
||
|
// returns: Animation
|
||
|
// The instance to allow chaining.
|
||
|
|
||
|
var _t = this;
|
||
|
if(_t._delayTimer){ _t._clearTimer(); }
|
||
|
if(gotoStart){
|
||
|
_t._stopTimer();
|
||
|
_t._active = _t._paused = false;
|
||
|
_t._percent = 0;
|
||
|
}else if(_t._active && !_t._paused){
|
||
|
return _t;
|
||
|
}
|
||
|
|
||
|
_t._fire("beforeBegin", [_t.node]);
|
||
|
|
||
|
var de = delay || _t.delay,
|
||
|
_p = lang.hitch(_t, "_play", gotoStart);
|
||
|
|
||
|
if(de > 0){
|
||
|
_t._delayTimer = setTimeout(_p, de);
|
||
|
return _t;
|
||
|
}
|
||
|
_p();
|
||
|
return _t; // Animation
|
||
|
},
|
||
|
|
||
|
_play: function(gotoStart){
|
||
|
var _t = this;
|
||
|
if(_t._delayTimer){ _t._clearTimer(); }
|
||
|
_t._startTime = new Date().valueOf();
|
||
|
if(_t._paused){
|
||
|
_t._startTime -= _t.duration * _t._percent;
|
||
|
}
|
||
|
|
||
|
_t._active = true;
|
||
|
_t._paused = false;
|
||
|
var value = _t.curve.getValue(_t._getStep());
|
||
|
if(!_t._percent){
|
||
|
if(!_t._startRepeatCount){
|
||
|
_t._startRepeatCount = _t.repeat;
|
||
|
}
|
||
|
_t._fire("onBegin", [value]);
|
||
|
}
|
||
|
|
||
|
_t._fire("onPlay", [value]);
|
||
|
|
||
|
_t._cycle();
|
||
|
return _t; // Animation
|
||
|
},
|
||
|
|
||
|
pause: function(){
|
||
|
// summary:
|
||
|
// Pauses a running animation.
|
||
|
var _t = this;
|
||
|
if(_t._delayTimer){ _t._clearTimer(); }
|
||
|
_t._stopTimer();
|
||
|
if(!_t._active){ return _t; /*Animation*/ }
|
||
|
_t._paused = true;
|
||
|
_t._fire("onPause", [_t.curve.getValue(_t._getStep())]);
|
||
|
return _t; // Animation
|
||
|
},
|
||
|
|
||
|
gotoPercent: function(/*Decimal*/ percent, /*Boolean?*/ andPlay){
|
||
|
// summary:
|
||
|
// Sets the progress of the animation.
|
||
|
// percent:
|
||
|
// A percentage in decimal notation (between and including 0.0 and 1.0).
|
||
|
// andPlay:
|
||
|
// If true, play the animation after setting the progress.
|
||
|
var _t = this;
|
||
|
_t._stopTimer();
|
||
|
_t._active = _t._paused = true;
|
||
|
_t._percent = percent;
|
||
|
if(andPlay){ _t.play(); }
|
||
|
return _t; // Animation
|
||
|
},
|
||
|
|
||
|
stop: function(/*boolean?*/ gotoEnd){
|
||
|
// summary:
|
||
|
// Stops a running animation.
|
||
|
// gotoEnd:
|
||
|
// If true, the animation will end.
|
||
|
var _t = this;
|
||
|
if(_t._delayTimer){ _t._clearTimer(); }
|
||
|
if(!_t._timer){ return _t; /* Animation */ }
|
||
|
_t._stopTimer();
|
||
|
if(gotoEnd){
|
||
|
_t._percent = 1;
|
||
|
}
|
||
|
_t._fire("onStop", [_t.curve.getValue(_t._getStep())]);
|
||
|
_t._active = _t._paused = false;
|
||
|
return _t; // Animation
|
||
|
},
|
||
|
|
||
|
destroy: function(){
|
||
|
// summary:
|
||
|
// cleanup the animation
|
||
|
this.stop();
|
||
|
},
|
||
|
|
||
|
status: function(){
|
||
|
// summary:
|
||
|
// Returns a string token representation of the status of
|
||
|
// the animation, one of: "paused", "playing", "stopped"
|
||
|
if(this._active){
|
||
|
return this._paused ? "paused" : "playing"; // String
|
||
|
}
|
||
|
return "stopped"; // String
|
||
|
},
|
||
|
|
||
|
_cycle: function(){
|
||
|
var _t = this;
|
||
|
if(_t._active){
|
||
|
var curr = new Date().valueOf();
|
||
|
// Allow durations of 0 (instant) by setting step to 1 - see #13798
|
||
|
var step = _t.duration === 0 ? 1 : (curr - _t._startTime) / (_t.duration);
|
||
|
|
||
|
if(step >= 1){
|
||
|
step = 1;
|
||
|
}
|
||
|
_t._percent = step;
|
||
|
|
||
|
// Perform easing
|
||
|
if(_t.easing){
|
||
|
step = _t.easing(step);
|
||
|
}
|
||
|
|
||
|
_t._fire("onAnimate", [_t.curve.getValue(step)]);
|
||
|
|
||
|
if(_t._percent < 1){
|
||
|
_t._startTimer();
|
||
|
}else{
|
||
|
_t._active = false;
|
||
|
|
||
|
if(_t.repeat > 0){
|
||
|
_t.repeat--;
|
||
|
_t.play(null, true);
|
||
|
}else if(_t.repeat == -1){
|
||
|
_t.play(null, true);
|
||
|
}else{
|
||
|
if(_t._startRepeatCount){
|
||
|
_t.repeat = _t._startRepeatCount;
|
||
|
_t._startRepeatCount = 0;
|
||
|
}
|
||
|
}
|
||
|
_t._percent = 0;
|
||
|
_t._fire("onEnd", [_t.node]);
|
||
|
!_t.repeat && _t._stopTimer();
|
||
|
}
|
||
|
}
|
||
|
return _t; // Animation
|
||
|
},
|
||
|
|
||
|
_clearTimer: function(){
|
||
|
// summary:
|
||
|
// Clear the play delay timer
|
||
|
clearTimeout(this._delayTimer);
|
||
|
delete this._delayTimer;
|
||
|
}
|
||
|
|
||
|
});
|
||
|
|
||
|
// the local timer, stubbed into all Animation instances
|
||
|
var ctr = 0,
|
||
|
timer = null,
|
||
|
runner = {
|
||
|
run: function(){}
|
||
|
};
|
||
|
|
||
|
lang.extend(Animation, {
|
||
|
|
||
|
_startTimer: function(){
|
||
|
if(!this._timer){
|
||
|
this._timer = aspect.after(runner, "run", lang.hitch(this, "_cycle"), true);
|
||
|
ctr++;
|
||
|
}
|
||
|
if(!timer){
|
||
|
timer = setInterval(lang.hitch(runner, "run"), this.rate);
|
||
|
}
|
||
|
},
|
||
|
|
||
|
_stopTimer: function(){
|
||
|
if(this._timer){
|
||
|
this._timer.remove();
|
||
|
this._timer = null;
|
||
|
ctr--;
|
||
|
}
|
||
|
if(ctr <= 0){
|
||
|
clearInterval(timer);
|
||
|
timer = null;
|
||
|
ctr = 0;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
});
|
||
|
|
||
|
var _makeFadeable =
|
||
|
has("ie") ? function(node){
|
||
|
// only set the zoom if the "tickle" value would be the same as the
|
||
|
// default
|
||
|
var ns = node.style;
|
||
|
// don't set the width to auto if it didn't already cascade that way.
|
||
|
// We don't want to f anyones designs
|
||
|
if(!ns.width.length && style.get(node, "width") == "auto"){
|
||
|
ns.width = "auto";
|
||
|
}
|
||
|
} :
|
||
|
function(){};
|
||
|
|
||
|
basefx._fade = function(/*Object*/ args){
|
||
|
// summary:
|
||
|
// Returns an animation that will fade the node defined by
|
||
|
// args.node from the start to end values passed (args.start
|
||
|
// args.end) (end is mandatory, start is optional)
|
||
|
|
||
|
args.node = dom.byId(args.node);
|
||
|
var fArgs = _mixin({ properties: {} }, args),
|
||
|
props = (fArgs.properties.opacity = {});
|
||
|
|
||
|
props.start = !("start" in fArgs) ?
|
||
|
function(){
|
||
|
return +style.get(fArgs.node, "opacity")||0;
|
||
|
} : fArgs.start;
|
||
|
props.end = fArgs.end;
|
||
|
|
||
|
var anim = basefx.animateProperty(fArgs);
|
||
|
aspect.after(anim, "beforeBegin", lang.partial(_makeFadeable, fArgs.node), true);
|
||
|
|
||
|
return anim; // Animation
|
||
|
};
|
||
|
|
||
|
/*=====
|
||
|
var __FadeArgs = declare(null, {
|
||
|
// node: DOMNode|String
|
||
|
// The node referenced in the animation
|
||
|
// duration: Integer?
|
||
|
// Duration of the animation in milliseconds.
|
||
|
// easing: Function?
|
||
|
// An easing function.
|
||
|
});
|
||
|
=====*/
|
||
|
|
||
|
basefx.fadeIn = function(/*__FadeArgs*/ args){
|
||
|
// summary:
|
||
|
// Returns an animation that will fade node defined in 'args' from
|
||
|
// its current opacity to fully opaque.
|
||
|
return basefx._fade(_mixin({ end: 1 }, args)); // Animation
|
||
|
};
|
||
|
|
||
|
basefx.fadeOut = function(/*__FadeArgs*/ args){
|
||
|
// summary:
|
||
|
// Returns an animation that will fade node defined in 'args'
|
||
|
// from its current opacity to fully transparent.
|
||
|
return basefx._fade(_mixin({ end: 0 }, args)); // Animation
|
||
|
};
|
||
|
|
||
|
basefx._defaultEasing = function(/*Decimal?*/ n){
|
||
|
// summary:
|
||
|
// The default easing function for Animation(s)
|
||
|
return 0.5 + ((Math.sin((n + 1.5) * Math.PI)) / 2); // Decimal
|
||
|
};
|
||
|
|
||
|
var PropLine = function(properties){
|
||
|
// PropLine is an internal class which is used to model the values of
|
||
|
// an a group of CSS properties across an animation lifecycle. In
|
||
|
// particular, the "getValue" function handles getting interpolated
|
||
|
// values between start and end for a particular CSS value.
|
||
|
this._properties = properties;
|
||
|
for(var p in properties){
|
||
|
var prop = properties[p];
|
||
|
if(prop.start instanceof Color){
|
||
|
// create a reusable temp color object to keep intermediate results
|
||
|
prop.tempColor = new Color();
|
||
|
}
|
||
|
}
|
||
|
};
|
||
|
|
||
|
PropLine.prototype.getValue = function(r){
|
||
|
var ret = {};
|
||
|
for(var p in this._properties){
|
||
|
var prop = this._properties[p],
|
||
|
start = prop.start;
|
||
|
if(start instanceof Color){
|
||
|
ret[p] = Color.blendColors(start, prop.end, r, prop.tempColor).toCss();
|
||
|
}else if(!lang.isArray(start)){
|
||
|
ret[p] = ((prop.end - start) * r) + start + (p != "opacity" ? prop.units || "px" : 0);
|
||
|
}
|
||
|
}
|
||
|
return ret;
|
||
|
};
|
||
|
|
||
|
/*=====
|
||
|
var __AnimArgs = declare(__FadeArgs, {
|
||
|
// properties: Object?
|
||
|
// A hash map of style properties to Objects describing the transition,
|
||
|
// such as the properties of _Line with an additional 'units' property
|
||
|
properties: {}
|
||
|
|
||
|
//TODOC: add event callbacks
|
||
|
});
|
||
|
=====*/
|
||
|
|
||
|
basefx.animateProperty = function(/*__AnimArgs*/ args){
|
||
|
// summary:
|
||
|
// Returns an animation that will transition the properties of
|
||
|
// node defined in `args` depending how they are defined in
|
||
|
// `args.properties`
|
||
|
//
|
||
|
// description:
|
||
|
// Foundation of most `dojo/_base/fx`
|
||
|
// animations. It takes an object of "properties" corresponding to
|
||
|
// style properties, and animates them in parallel over a set
|
||
|
// duration.
|
||
|
//
|
||
|
// example:
|
||
|
// A simple animation that changes the width of the specified node.
|
||
|
// | basefx.animateProperty({
|
||
|
// | node: "nodeId",
|
||
|
// | properties: { width: 400 },
|
||
|
// | }).play();
|
||
|
// Dojo figures out the start value for the width and converts the
|
||
|
// integer specified for the width to the more expressive but
|
||
|
// verbose form `{ width: { end: '400', units: 'px' } }` which you
|
||
|
// can also specify directly. Defaults to 'px' if omitted.
|
||
|
//
|
||
|
// example:
|
||
|
// Animate width, height, and padding over 2 seconds... the
|
||
|
// pedantic way:
|
||
|
// | basefx.animateProperty({ node: node, duration:2000,
|
||
|
// | properties: {
|
||
|
// | width: { start: '200', end: '400', units:"px" },
|
||
|
// | height: { start:'200', end: '400', units:"px" },
|
||
|
// | paddingTop: { start:'5', end:'50', units:"px" }
|
||
|
// | }
|
||
|
// | }).play();
|
||
|
// Note 'paddingTop' is used over 'padding-top'. Multi-name CSS properties
|
||
|
// are written using "mixed case", as the hyphen is illegal as an object key.
|
||
|
//
|
||
|
// example:
|
||
|
// Plug in a different easing function and register a callback for
|
||
|
// when the animation ends. Easing functions accept values between
|
||
|
// zero and one and return a value on that basis. In this case, an
|
||
|
// exponential-in curve.
|
||
|
// | basefx.animateProperty({
|
||
|
// | node: "nodeId",
|
||
|
// | // dojo figures out the start value
|
||
|
// | properties: { width: { end: 400 } },
|
||
|
// | easing: function(n){
|
||
|
// | return (n==0) ? 0 : Math.pow(2, 10 * (n - 1));
|
||
|
// | },
|
||
|
// | onEnd: function(node){
|
||
|
// | // called when the animation finishes. The animation
|
||
|
// | // target is passed to this function
|
||
|
// | }
|
||
|
// | }).play(500); // delay playing half a second
|
||
|
//
|
||
|
// example:
|
||
|
// Like all `Animation`s, animateProperty returns a handle to the
|
||
|
// Animation instance, which fires the events common to Dojo FX. Use `aspect.after`
|
||
|
// to access these events outside of the Animation definition:
|
||
|
// | var anim = basefx.animateProperty({
|
||
|
// | node:"someId",
|
||
|
// | properties:{
|
||
|
// | width:400, height:500
|
||
|
// | }
|
||
|
// | });
|
||
|
// | aspect.after(anim, "onEnd", function(){
|
||
|
// | console.log("animation ended");
|
||
|
// | }, true);
|
||
|
// | // play the animation now:
|
||
|
// | anim.play();
|
||
|
//
|
||
|
// example:
|
||
|
// Each property can be a function whose return value is substituted along.
|
||
|
// Additionally, each measurement (eg: start, end) can be a function. The node
|
||
|
// reference is passed directly to callbacks.
|
||
|
// | basefx.animateProperty({
|
||
|
// | node:"mine",
|
||
|
// | properties:{
|
||
|
// | height:function(node){
|
||
|
// | // shrink this node by 50%
|
||
|
// | return domGeom.position(node).h / 2
|
||
|
// | },
|
||
|
// | width:{
|
||
|
// | start:function(node){ return 100; },
|
||
|
// | end:function(node){ return 200; }
|
||
|
// | }
|
||
|
// | }
|
||
|
// | }).play();
|
||
|
//
|
||
|
|
||
|
var n = args.node = dom.byId(args.node);
|
||
|
if(!args.easing){ args.easing = dojo._defaultEasing; }
|
||
|
|
||
|
var anim = new Animation(args);
|
||
|
aspect.after(anim, "beforeBegin", lang.hitch(anim, function(){
|
||
|
var pm = {};
|
||
|
for(var p in this.properties){
|
||
|
// Make shallow copy of properties into pm because we overwrite
|
||
|
// some values below. In particular if start/end are functions
|
||
|
// we don't want to overwrite them or the functions won't be
|
||
|
// called if the animation is reused.
|
||
|
if(p == "width" || p == "height"){
|
||
|
this.node.display = "block";
|
||
|
}
|
||
|
var prop = this.properties[p];
|
||
|
if(lang.isFunction(prop)){
|
||
|
prop = prop(n);
|
||
|
}
|
||
|
prop = pm[p] = _mixin({}, (lang.isObject(prop) ? prop: { end: prop }));
|
||
|
|
||
|
if(lang.isFunction(prop.start)){
|
||
|
prop.start = prop.start(n);
|
||
|
}
|
||
|
if(lang.isFunction(prop.end)){
|
||
|
prop.end = prop.end(n);
|
||
|
}
|
||
|
var isColor = (p.toLowerCase().indexOf("color") >= 0);
|
||
|
var getStyle = function getStyle(node, p){
|
||
|
// domStyle.get(node, "height") can return "auto" or "" on IE; this is more reliable:
|
||
|
var v = { height: node.offsetHeight, width: node.offsetWidth }[p];
|
||
|
if(v !== undefined){ return v; }
|
||
|
v = style.get(node, p);
|
||
|
return (p == "opacity") ? +v : (isColor ? v : parseFloat(v));
|
||
|
};
|
||
|
if(!("end" in prop)){
|
||
|
prop.end = getStyle(n, p);
|
||
|
}else if(!("start" in prop)){
|
||
|
prop.start = getStyle(n, p);
|
||
|
}
|
||
|
|
||
|
if(isColor){
|
||
|
prop.start = new Color(prop.start);
|
||
|
prop.end = new Color(prop.end);
|
||
|
}else{
|
||
|
prop.start = (p == "opacity") ? +prop.start : parseFloat(prop.start);
|
||
|
}
|
||
|
}
|
||
|
this.curve = new PropLine(pm);
|
||
|
}), true);
|
||
|
aspect.after(anim, "onAnimate", lang.hitch(style, "set", anim.node), true);
|
||
|
return anim; // Animation
|
||
|
};
|
||
|
|
||
|
basefx.anim = function( /*DOMNode|String*/ node,
|
||
|
/*Object*/ properties,
|
||
|
/*Integer?*/ duration,
|
||
|
/*Function?*/ easing,
|
||
|
/*Function?*/ onEnd,
|
||
|
/*Integer?*/ delay){
|
||
|
// summary:
|
||
|
// A simpler interface to `animateProperty()`, also returns
|
||
|
// an instance of `Animation` but begins the animation
|
||
|
// immediately, unlike nearly every other Dojo animation API.
|
||
|
// description:
|
||
|
// Simpler (but somewhat less powerful) version
|
||
|
// of `animateProperty`. It uses defaults for many basic properties
|
||
|
// and allows for positional parameters to be used in place of the
|
||
|
// packed "property bag" which is used for other Dojo animation
|
||
|
// methods.
|
||
|
//
|
||
|
// The `Animation` object returned will be already playing, so
|
||
|
// calling play() on it again is (usually) a no-op.
|
||
|
// node:
|
||
|
// a DOM node or the id of a node to animate CSS properties on
|
||
|
// duration:
|
||
|
// The number of milliseconds over which the animation
|
||
|
// should run. Defaults to the global animation default duration
|
||
|
// (350ms).
|
||
|
// easing:
|
||
|
// An easing function over which to calculate acceleration
|
||
|
// and deceleration of the animation through its duration.
|
||
|
// A default easing algorithm is provided, but you may
|
||
|
// plug in any you wish. A large selection of easing algorithms
|
||
|
// are available in `dojo/fx/easing`.
|
||
|
// onEnd:
|
||
|
// A function to be called when the animation finishes
|
||
|
// running.
|
||
|
// delay:
|
||
|
// The number of milliseconds to delay beginning the
|
||
|
// animation by. The default is 0.
|
||
|
// example:
|
||
|
// Fade out a node
|
||
|
// | basefx.anim("id", { opacity: 0 });
|
||
|
// example:
|
||
|
// Fade out a node over a full second
|
||
|
// | basefx.anim("id", { opacity: 0 }, 1000);
|
||
|
return basefx.animateProperty({ // Animation
|
||
|
node: node,
|
||
|
duration: duration || Animation.prototype.duration,
|
||
|
properties: properties,
|
||
|
easing: easing,
|
||
|
onEnd: onEnd
|
||
|
}).play(delay || 0);
|
||
|
};
|
||
|
|
||
|
|
||
|
if( 1 ){
|
||
|
_mixin(dojo, basefx);
|
||
|
// Alias to drop come 2.0:
|
||
|
dojo._Animation = Animation;
|
||
|
}
|
||
|
|
||
|
return basefx;
|
||
|
});
|
||
|
|
||
|
}}});
|
||
|
(function(){
|
||
|
// must use this.require to make this work in node.js
|
||
|
var require = this.require;
|
||
|
// consume the cached dojo layer
|
||
|
require({cache:{}});
|
||
|
!require.async && require(["dojo"]);
|
||
|
require.boot && require.apply(null, require.boot);
|
||
|
})();
|