/*===== // note: // 'djConfig' does not exist under 'dojo.*' so that it can be set before the // 'dojo' variable exists. // note: // Setting any of these variables *after* the library has loaded does // nothing at all.
djConfig={ // summary: // Application code can set the global 'djConfig' prior to loading // the library to override certain global settings for how dojo works. // // isDebug: Boolean // Defaults to `false`. If set to `true`, ensures that Dojo provides // extended debugging feedback via Firebug. If Firebug is not available // on your platform, setting `isDebug` to `true` will force Dojo to // pull in (and display) the version of Firebug Lite which is // integrated into the Dojo distribution, thereby always providing a // debugging/logging console when `isDebug` is enabled. Note that // Firebug's `console.*` methods are ALWAYS defined by Dojo. If // `isDebug` is false and you are on a platform without Firebug, these // methods will be defined as no-ops. isDebug:false, // debugAtAllCosts: Boolean // Defaults to `false`. If set to `true`, this triggers an alternate // mode of the package system in which dependencies are detected and // only then are resources evaluated in dependency order via // `<script>` tag inclusion. This may double-request resources and // cause problems with scripts which expect `dojo.require()` to // preform synchronously. `debugAtAllCosts` can be an invaluable // debugging aid, but when using it, ensure that all code which // depends on Dojo modules is wrapped in `dojo.addOnLoad()` handlers. // Due to the somewhat unpredictable side-effects of using // `debugAtAllCosts`, it is strongly recommended that you enable this // flag as a last resort. `debugAtAllCosts` has no effect when loading // resources across domains. For usage information, see the // [Dojo Book](http://dojotoolkit.org/book/book-dojo/part-4-meta-dojo-making-your-dojo-code-run-faster-and-better/debugging-facilities/deb) debugAtAllCosts: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. baseUrl:undefined, // modulePaths: 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. Specifiying // `djConfig.modulePaths = { "foo": "../../bar" }` is the equivalent // of calling `dojo.registerModulePath("foo", "../../bar");`. Multiple // modules may be configured via `djConfig.modulePaths`. modulePaths:{}, // afterOnLoad: Boolean // Indicates Dojo was added to the page after the page load. In this case // Dojo will not wait for the page DOMContentLoad/load events and fire // its dojo.addOnLoad callbacks after making sure all outstanding // dojo.required modules have loaded. afterOnLoad:false, // addOnLoad: Function or Array // Adds a callback via dojo.addOnLoad. Useful when Dojo is added after // the page loads and djConfig.afterOnLoad is true. Supports the same // arguments as dojo.addOnLoad. 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, // require: Array // An array of module names to be loaded immediately after dojo.js has been included // in a page. require:[] }
=====*/
(function(){ // firebug stubs
// if((!this["console"])||(!console["firebug"])){
if(!this["console"]){ this.console = {
};
}
// 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 i=0, tn; while((tn=cn[i++])){ if(!console[tn]){
(function(){ var tcn = tn+"";
console[tcn] = ('log' in console) ? function(){ var a = Array.apply({}, arguments);
a.unshift(tcn+":");
console["log"](a.join(" "));
} : function(){}
})();
}
}
//TODOC: HOW TO DOC THIS? // dojo is the root variable of (almost all) our public symbols -- make sure it is defined. if(typeof dojo == "undefined"){ this.dojo = {
_scopeName: "dojo",
_scopePrefix: "",
_scopePrefixArgs: "",
_scopeSuffix: "",
_scopeMap: {},
_scopeMapRev: {}
};
}
var d = dojo;
//Need placeholders for dijit and dojox for scoping code. if(typeof dijit == "undefined"){ this.dijit = {_scopeName: "dijit"};
} if(typeof dojox == "undefined"){ this.dojox = {_scopeName: "dojox"};
}
/*===== dojo.global={ // summary: // Alias for the global scope // (e.g. the window object in a browser). // description: // Refer to 'dojo.global' rather than referring to window to ensure your // code runs correctly in contexts other than web browsers (e.g. Rhino on a server). }
=====*/
d.global = this;
var _platforms = ["Browser", "Rhino", "Spidermonkey", "Mobile"]; var t; while((t=_platforms.shift())){
d["is"+t] = false;
}
/*===== // Override locale setting, if specified dojo.locale={ // summary: the locale as defined by Dojo (read-only) };
=====*/
dojo.locale = d.config.locale;
var rev = "$Rev: 15729 $".match(/\d+/);
dojo.version = { // summary: // version number of dojo // 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 SVN rev from which dojo was pulled
major: 1, minor: 2, patch: 2, flag: "",
revision: rev ? +rev[0] : 999999, //FIXME: use NaN?
toString: function(){
with(d.version){ return major + "." + minor + "." + patch + flag + " (" + revision + ")"; // String
}
}
}
// Register with the OpenAjax hub if(typeof OpenAjax != "undefined"){
OpenAjax.hub.registerLibrary(dojo._scopeName, "http://dojotoolkit.org", d.version.toString());
}
dojo._mixin = function(/*Object*/ obj, /*Object*/ props){ // summary: // Adds all properties and methods of props to obj. This addition // is "prototype extension safe", so that instances of objects // will not pass along prototype defaults. var tobj = {}; for(var x in props){ // the "tobj" condition avoid copying properties in "props" // inherited from Object.prototype. For example, if obj has a custom // toString() method, don't overwrite it with the toString() method // that props inherited from Object.prototype if(tobj[x] === undefined || tobj[x] != props[x]){
obj[x] = props[x];
}
} // IE doesn't recognize custom toStrings in for..in if(d["isIE"] && props){ var p = props.toString; if(typeof p == "function" && p != obj.toString && p != tobj.toString &&
p != "\nfunction toString() {\n [native code]\n}\n"){
obj.toString = props.toString;
}
} return obj; // Object
}
dojo.mixin = function(/*Object*/obj, /*Object...*/props){ // summary: // Adds all properties and methods of props to obj and returns the // (now modified) obj. // description: // `dojo.mixin` can mix multiple source objects into a // destionation object which is then returned. Unlike regular // `for...in` iteration, `dojo.mixin` is also smart about avoiding // extensions which other toolkits may unwisely add to the root // object prototype // obj: // The object to mix properties into. Also the return value. // props: // One or more objects whose values are successively copied into // obj. If more than one of these objects contain the same value, // the one specified last in the function call will "win". // example: // make a shallow copy of an object // | var copy = dojo.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 `dojo.mixin` on the `this` object: // | dojo.declare("acme.Base", null, { // | constructor: function(properties){ // | // property configuration: // | dojo.mixin(this, properties); // | // | // | // ... // | }, // | 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 = dojo.mixin( // | { // | name: "Frylock", // | braces: true // | }, // | { // | name: "Carl Brutanananadilewski" // | } // | ); // | // | // will print "Carl Brutanananadilewski" // | // | // will print "true" // | for(var i=1, l=arguments.length; i<l; i++){
d._mixin(obj, arguments[i]);
} return obj; // Object
}
dojo.setObject = function(/*String*/name, /*Object*/value, /*Object?*/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: // Path to a property, in the form "A.B.C". // context: // 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: // | dojo.setObject("foo.bar.baz", value); // example: // without `dojo.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"; // wheras with `dojo.setObject`, we can shorten that to: // | dojo.setObject("parent.child.prop", "some value", obj); var parts=name.split("."), p=parts.pop(), obj=d._getProp(parts, true, context); return obj && p ? (obj[p]=value) : undefined; // Object
}
dojo.getObject = function(/*String*/name, /*Boolean*/create, /*Object*/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: // Path to an property, in the form "A.B.C". // context: // Optional. Object to use as root of path. Defaults to // 'dojo.global'. Null may be passed. // create: // Optional. Defaults to `false`. If `true`, Objects will be // created at any point along the 'path' that is undefined. return d._getProp(name.split("."), create, context); // Object
}
dojo.exists = function(/*String*/name, /*Object?*/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 // name: // Path to an object, in the form "A.B.C". // obj: // 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 // | dojo.exists("foo.bar"); // true // | dojo.exists("foo.bar.baz"); // false // | // | // search from a particular scope // | dojo.exists("bar", foo); // true // | dojo.exists("bar.baz", foo); // false return !!d.getObject(name, false, obj); // Boolean
}
dojo["eval"] = function(/*String*/ scriptFragment){ // summary: // Perform an evaluation in the global scope. Use this rather than // calling 'eval()' directly. // description: // Placed in a separate function to minimize size of trapped // exceptions. Calling eval() directly from some other scope may // complicate tracebacks on some platforms. // returns: // The result of the evaluation. Often `undefined`
// note: // - JSC eval() takes an optional second argument which can be 'unsafe'. // - Mozilla/SpiderMonkey eval() takes an optional second argument which is the // scope object for new symbols.
/*===== dojo.deprecated=function(behaviour,extra,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"); }
dojo.experimental=function(moduleName,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"); }
=====*/
//Real functions declared in dojo._firebug.firebug.
d.deprecated = d.experimental = function(){};
_moduleHasPrefix: function(/*String*/module){ // summary: checks to see if module has been established var mp = this._modulePrefixes; return !!(mp[module] && mp[module].value); // Boolean
},
_getModulePrefix: function(/*String*/module){ // summary: gets the prefix associated with module var mp = this._modulePrefixes; if(this._moduleHasPrefix(module)){ return mp[module].value; // String
} return module; // String
},
_loadedUrls: [],
//WARNING: // This variable is referenced by packages outside of bootstrap: // FloatingPane.js and undo/browser.js
_postLoad: false,
//Egad! Lots of test files push on this directly instead of using dojo.addOnLoad.
_loaders: [],
_unloaders: [],
_loadNotifying: false
});
dojo._loadPath = function(/*String*/relpath, /*String?*/module, /*Function?*/cb){ // summary: // Load a Javascript module given a relative path // // description: // Loads and interprets the script located at relpath, which is // relative to the script root directory. If the script is found but // its interpretation causes a runtime exception, that exception is // not caught by us, so the caller will see it. We return a true // value if and only if the script is found. // // relpath: // A relative path to a script (no leading '/', and typically ending // in '.js'). // module: // A module whose existance to check for after loading a path. Can be // used to determine success or failure of the load. // cb: // a callback function to pass the result of evaluating the script
dojo._loadUri = function(/*String*/uri, /*Function?*/cb){ // summary: // Loads JavaScript from a URI // description: // Reads the contents of the URI, and evaluates the contents. This is // used to load modules as well as resource bundles. Returns true if // it succeeded. Returns false if the URI reading failed. Throws if // the evaluation throws. // uri: a uri which points at the script to be loaded // cb: // a callback function to process the result of evaluating the script // as an expression, typically used by the resource bundle loader to // load JSON-style resources
if(this._loadedUrls[uri]){ returntrue; // Boolean
} var contents = this._getText(uri, true); if(!contents){ returnfalse; } // Boolean this._loadedUrls[uri] = true; this._loadedUrls.push(uri); if(cb){
contents = '('+contents+')';
}else{ //Only do the scoping if no callback. If a callback is specified, //it is most likely the i18n bundle stuff.
contents = this._scopePrefix + contents + this._scopeSuffix;
} if(d.isMoz){ contents += "\r\n//@ sourceURL=" + uri; } // debugging assist for Firebug var value = d["eval"](contents); if(cb){ cb(value); } returntrue; // Boolean
}
// FIXME: probably need to add logging to this method
dojo._loadUriAndCheck = function(/*String*/uri, /*String*/moduleName, /*Function?*/cb){ // summary: calls loadUri then findModule and returns true if both succeed var ok = false; try{
ok = this._loadUri(uri, cb);
}catch(e){
console.error("failed loading " + uri + " with error: " + e);
} return !!(ok && this._loadedModules[moduleName]); // Boolean
}
dojo.loaded = function(){ // summary: // signal fired when initial environment and package loading is // complete. You may use dojo.addOnLoad() or dojo.connect() to // this method in order to handle initialization tasks that // require the environment to be initialized. In a browser host, // declarative widgets will be constructed when this function // finishes runing. this._loadNotifying = true; this._postLoad = true; var mll = d._loaders;
//Clear listeners so new ones can be added //For other xdomain package loads after the initial load. this._loaders = [];
for(var x = 0; x < mll.length; x++){
mll[x]();
}
this._loadNotifying = false;
//Make sure nothing else got added to the onload queue //after this first run. If something did, and we are not waiting for any //more inflight resources, run again. if(d._postLoad && d._inFlightCount == 0 && mll.length){
d._callLoaded();
}
}
dojo.unloaded = function(){ // summary: // signal fired by impending environment destruction. You may use // dojo.addOnUnload() or dojo.connect() to this method to perform // page/application cleanup methods. See dojo.addOnUnload for more info. var mll = this._unloaders; while(mll.length){
(mll.pop())();
}
}
dojo.addOnLoad = function(/*Object?*/obj, /*String|Function*/functionName){ // summary: // Registers a function to be triggered after the DOM has finished // loading and widgets declared in markup have been instantiated. // Images and CSS files may or may not have finished downloading when // the specified function is called. (Note that widgets' CSS and HTML // code is guaranteed to be downloaded before said widgets are // instantiated.) // example: // | dojo.addOnLoad(functionPointer); // | dojo.addOnLoad(object, "functionName"); // | dojo.addOnLoad(object, function(){ /* ... */});
d._onto(d._loaders, obj, functionName);
//Added for xdomain loading. dojo.addOnLoad is used to //indicate callbacks after doing some dojo.require() statements. //In the xdomain case, if all the requires are loaded (after initial //page load), then immediately call any listeners. if(d._postLoad && d._inFlightCount == 0 && !d._loadNotifying){
d._callLoaded();
}
}
//Support calling dojo.addOnLoad via djConfig.addOnLoad. Support all the //call permutations of dojo.addOnLoad. Mainly useful when dojo is added //to the page after the page has loaded. var dca = d.config.addOnLoad; if(dca){
d.addOnLoad[(dca instanceof Array ? "apply" : "call")](d, dca);
}
dojo.addOnUnload = function(/*Object?*/obj, /*String|Function?*/functionName){ // summary: // registers a function to be triggered when the page unloads. In a browser // enviroment, the functions will be triggered during the window.onbeforeunload // event. Be careful doing work during window.onbeforeunload. 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. // example: // | dojo.addOnUnload(functionPointer) // | dojo.addOnUnload(object, "functionName") // | dojo.addOnUnload(object, function(){ /* ... */});
d._onto(d._unloaders, obj, functionName);
}
dojo._modulesLoaded = function(){ if(d._postLoad){ return; } if(d._inFlightCount > 0){
console.warn("files still in flight!"); return;
}
d._callLoaded();
}
dojo._callLoaded = function(){
// The "object" check is for IE, and the other opera check fixes an // issue in Opera where it could not find the body element in some // widget test cases. For 0.9, maybe route all browsers through the // setTimeout (need protection still for non-browser environments // though). This might also help the issue with FF 2.0 and freezing // issues where we try to do sync xhr while background css images are // being loaded (trac #2572)? Consider for 0.9. if(typeof setTimeout == "object" || (dojo.config.useXDomain && d.isOpera)){ if(dojo.isAIR){
setTimeout(function(){dojo.loaded();}, 0);
}else{
setTimeout(dojo._scopeName + ".loaded();", 0);
}
}else{
d.loaded();
}
}
dojo._getModuleSymbols = function(/*String*/modulename){ // summary: // Converts a module name in dotted JS notation to an array // representing the path in the source tree var syms = modulename.split("."); for(var i = syms.length; i>0; i--){ var parentModule = syms.slice(0, i).join("."); if((i==1) && !this._moduleHasPrefix(parentModule)){ // Support default module directory (sibling of dojo) for top-level modules
syms[0] = "../" + syms[0];
}else{ var parentModulePath = this._getModulePrefix(parentModule); if(parentModulePath != parentModule){
syms.splice(0, i, parentModulePath); break;
}
}
} // return syms; // Array
}
dojo._global_omit_module_check = false;
dojo.loadInit = function(/*Function*/init){ // summary: // Executes a function that needs to be executed for the loader's dojo.requireIf // resolutions to work. This is needed mostly for the xdomain loader case where // a function needs to be executed to set up the possible values for a dojo.requireIf // call. // init: // a function reference. Executed immediately. // description: This function is mainly a marker for the xdomain loader to know parts of // code that needs be executed outside the function wrappper that is placed around modules. // The init function could be executed more than once, and it should make no assumptions // on what is loaded, or what modules are available. Only the functionality in Dojo Base // is allowed to be used. Avoid using this method. For a valid use case, // see the source for dojox.gfx.
init();
}
dojo._loadModule = dojo.require = function(/*String*/moduleName, /*Boolean?*/omitModuleCheck){ // summary: // loads a Javascript module from the appropriate URI // moduleName: // 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: // 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: // `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 excpetion 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`. // // `dojo.require()` does nothing about importing symbols into // the current namespace. It is presumed that the caller will // take care of that. For example, to import all symbols into a // local block, you might write: // // | with (dojo.require("A.B")) { // | ... // | } // // And to import just the leaf symbol to a local variable: // // | var B = dojo.require("A.B"); // | ... // returns: the required namespace object
omitModuleCheck = this._global_omit_module_check || omitModuleCheck;
//Check if it is already loaded. var module = this._loadedModules[moduleName]; if(module){ return module;
}
// convert periods to slashes var relpath = this._getModuleSymbols(moduleName).join("/") + '.js';
var modArg = (!omitModuleCheck) ? moduleName : null; var ok = this._loadPath(relpath, modArg);
if(!ok && !omitModuleCheck){ thrownew Error("Could not load '" + moduleName + "'; last tried '" + relpath + "'");
}
// check that the symbol was defined // Don't bother if we're doing xdomain (asynchronous) loading. if(!omitModuleCheck && !this._isXDomain){ // pass in false so we can give better error
module = this._loadedModules[moduleName]; if(!module){ thrownew Error("symbol '" + moduleName + "' is not defined after loading '" + relpath + "'");
}
}
return module;
}
dojo.provide = function(/*String*/ resourceName){ // summary: // Each javascript source file must have at least one // `dojo.provide()` call at the top of the file, corresponding to // the file name. For example, `js/dojo/foo.js` must have // `dojo.provide("dojo.foo");` before any calls to // `dojo.require()` are made. // description: // Each javascript source file is called a resource. When a // resource is loaded by the browser, `dojo.provide()` registers // that it has been loaded. // // For backwards compatibility reasons, in addition to registering // the resource, `dojo.provide()` also ensures that the javascript // object for the module exists. For example, // `dojo.provide("dojox.data.FlickrStore")`, in addition to // registering that `FlickrStore.js` is a resource for the // `dojox.data` module, will ensure that the `dojox.data` // javascript object exists, so that calls like // `dojo.data.foo = function(){ ... }` don't fail. // // In the case of a build where multiple javascript source files // are combined into one bigger file (similar to a .lib or .jar // file), that file may contain multiple dojo.provide() calls, to // note that it includes multiple resources.
//Make sure we have a string.
resourceName = resourceName + ""; return (d._loadedModules[resourceName] = d.getObject(resourceName, true)); // Object
}
//Start of old bootstrap2:
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 choosen 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 common = modMap.common || []; var result = common.concat(modMap[d._name] || modMap["default"] || []);
dojo.requireIf = function(/*Boolean*/ condition, /*String*/ resourceName){ // summary: // If the condition is true then call dojo.require() for the specified // resource if(condition === true){ // FIXME: why do we support chained require()'s here? does the build system? var args = []; for(var i = 1; i < arguments.length; i++){
args.push(arguments[i]);
}
d.require.apply(d, args);
}
}
dojo.requireAfterIf = d.requireIf;
dojo.registerModulePath = function(/*String*/module, /*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>
d._modulePrefixes[module] = { name: module, value: prefix };
}
dojo.requireLocalization = function(/*String*/moduleName, /*String*/bundleName, /*String?*/locale, /*String?*/availableFlatLocales){ // summary: // Declares translated resources and loads them if necessary, in the // same style as dojo.require. Contents of the resource bundle are // typically strings, but may be any name/value pair, represented in // JSON format. See also `dojo.i18n.getLocalization`. // // description: // Load translated resource bundles provided underneath the "nls" // directory within a package. Translated resources may be located in // different packages throughout the source tree. // // Each directory is named for a locale as specified by RFC 3066, // (http://www.ietf.org/rfc/rfc3066.txt), normalized in lowercase. // Note that the two bundles in the example do not define all the // same variants. For a given locale, bundles will be loaded for // that locale and all more general locales above it, including a // fallback at the root directory. For example, a declaration for // the "de-at" locale will first load `nls/de-at/bundleone.js`, // then `nls/de/bundleone.js` and finally `nls/bundleone.js`. The // data will be flattened into a single Object so that lookups // will follow this cascading pattern. An optional build step can // preload the bundles to avoid data redundancy and the multiple // network hits normally required to load these resources. // // moduleName: // name of the package containing the "nls" directory in which the // bundle is found // // bundleName: // bundle name, i.e. the filename without the '.js' suffix // // locale: // the locale to load (optional) By default, the browser's user // locale as defined by dojo.locale // // availableFlatLocales: // A comma-separated list of the available, flattened locales for this // bundle. This argument should only be set by the build process. // // example: // A particular widget may define one or more resource bundles, // structured in a program as follows, where moduleName is // mycode.mywidget and bundleNames available include bundleone and // bundletwo: // | ... // | mycode/ // | mywidget/ // | nls/ // | bundleone.js (the fallback translation, English in this example) // | bundletwo.js (also a fallback translation) // | de/ // | bundleone.js // | bundletwo.js // | de-at/ // | bundleone.js // | en/ // | (empty; use the fallback translation) // | en-us/ // | bundleone.js // | en-gb/ // | bundleone.js // | es/ // | bundleone.js // | bundletwo.js // | ...etc // | ... //
var ore = new RegExp("^(([^:/?#]+):)?(//([^/?#]*))?([^?#]*)(\\?([^#]*))?(#(.*))?$"); var ire = new RegExp("^((([^\\[:]+):)?([^@]+)@)?(\\[([^\\]]+)\\]|([^\\[:]*))(:([0-9]+))?$");
dojo._Url = function(/*dojo._Url||String...*/){ // summary: // Constructor to create an object representing a URL. // It is marked as private, since we might consider removing // or simplifying it. // description: // Each argument is evaluated in order relative to the next until // a canonical uri is produced. To get an absolute Uri relative to // the current document use: // new dojo._Url(document.baseURI, url)
var n = null;
var _a = arguments; var uri = [_a[0]]; // resolve uri components relative to each other for(var i = 1; i<_a.length; i++){ if(!_a[i]){ continue; }
// Safari doesn't support this.constructor so we have to be explicit // FIXME: Tracked (and fixed) in Webkit bug 3537. // http://bugs.webkit.org/show_bug.cgi?id=3537 var relobj = new d._Url(_a[i]+""); var uriobj = new d._Url(uri[0]+"");
dojo.moduleUrl = function(/*String*/module, /*dojo._Url||String*/url){ // summary: // Returns a `dojo._Url` object relative to a module. // example: // | var pngPath = dojo.moduleUrl("acme","images/small.png"); // | // list the object properties // | // create an image and set it's source to pngPath's value: // | var img = document.createElement("img"); // | // NOTE: we assign the string representation of the url object // | img.src = pngPath.toString(); // | // 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 lenghty 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");
var loc = d._getModuleSymbols(module).join('/'); if(!loc){ returnnull; } if(loc.lastIndexOf("/") != loc.length-1){
loc += "/";
}
//If the path is an absolute path (starts with a / or is on another //domain/xdomain) then don't add the baseUrl. var colonIndex = loc.indexOf(":"); if(loc.charAt(0) != "/" && (colonIndex == -1 || colonIndex > loc.indexOf("/"))){
loc = d.baseUrl + loc;
}
dojo.isIE={ // example: // | if(dojo.isIE > 6){ // | // we are IE7 // | } };
dojo.isSafari={ // example: // | if(dojo.isSafari){ ... } // example: // Detect iPhone: // | if(dojo.isSafari && navigator.userAgent.indexOf("iPhone") != -1){ // | // we are iPhone. Note, iPod touch reports "iPod" above and fails this test. // | } };
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:2, // 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:6, // isKhtml: Number | undefined // Version as a Number if client is a KTHML-derived browser (Konqueror, // Safari, etc.). undefined otherwise. Corresponds to major detected version. isKhtml:0, // isMozilla: Number | undefined // Version as a Number if client is a Mozilla-based browser (Firefox, // SeaMonkey). undefined otherwise. Corresponds to major detected version. isMozilla:0, // isOpera: Number | undefined // Version as a Number if client is Opera. undefined otherwise. Corresponds to // major detected version. isOpera:0, // isSafari: Number | undefined // Version as a Number if client is Safari or iPhone. undefined otherwise. isSafari:0 }
=====*/
// attempt to figure out the path to dojo if it isn't set in the config
(function(){ var d = dojo; // this is a scope protection closure. We set browser versions and grab // the URL we were loaded from here.
// grab the node we were loaded from if(document && document.getElementsByTagName){ var scripts = document.getElementsByTagName("script"); var rePkg = /dojo(\.xd)?\.js(\W|$)/i; for(var i = 0; i < scripts.length; i++){ var src = scripts[i].getAttribute("src"); if(!src){ continue; } var m = src.match(rePkg); if(m){ // find out where we came from if(!d.config.baseUrl){
d.config.baseUrl = src.substring(0, m.index);
} // and find out if we need to modify our behavior var cfg = scripts[i].getAttribute("djConfig"); if(cfg){ var cfgo = eval("({ "+cfg+" })"); for(var x in cfgo){
dojo.config[x] = cfgo[x];
}
} break; // "first Dojo wins"
}
}
}
d.baseUrl = d.config.baseUrl;
// fill in the rendering support information in dojo.render.* var n = navigator; var dua = n.userAgent; var dav = n.appVersion; var tv = parseFloat(dav);
if(dua.indexOf("Opera") >= 0){ d.isOpera = tv; } // safari detection derived from: // http://developer.apple.com/internet/safari/faq.html#anchor2 // http://developer.apple.com/internet/safari/uamatrix.html var index = Math.max(dav.indexOf("WebKit"), dav.indexOf("Safari"), 0); if(index){ // try to grab the explicit Safari version first. If we don't get // one, look for 419.3+ as the indication that we're on something // "Safari 3-ish". Lastly, default to "Safari 2" handling.
d.isSafari = parseFloat(dav.split("Version/")[1]) ||
(parseFloat(dav.substr(index + 7)) > 419.3) ? 3 : 2;
} if(dua.indexOf("AdobeAIR") >= 0){ d.isAIR = 1; } if(dav.indexOf("Konqueror") >= 0 || d.isSafari){ d.isKhtml = tv; } if(dua.indexOf("Gecko") >= 0 && !d.isKhtml){ d.isMozilla = d.isMoz = tv; } if(d.isMoz){
d.isFF = parseFloat(dua.split("Firefox/")[1]) || undefined;
} if(document.all && !d.isOpera){
d.isIE = parseFloat(dav.split("MSIE ")[1]) || undefined;
}
//Workaround to get local file loads of dojo to work on IE 7 //by forcing to not use native xhr. if(dojo.isIE && window.location.protocol === "file:"){
dojo.config.ieForceActiveXXhr=true;
}
var cm = document.compatMode;
d.isQuirks = cm == "BackCompat" || cm == "QuirksMode" || d.isIE < 6;
// TODO: is the HTML LANG attribute relevant?
d.locale = dojo.config.locale || (d.isIE ? n.userLanguage : n.language).toLowerCase();
// These are in order of decreasing likelihood; this will change in time.
d._XMLHTTP_PROGIDS = ['Msxml2.XMLHTTP', 'Microsoft.XMLHTTP', 'Msxml2.XMLHTTP.4.0'];
d._xhrObj = function(){ // summary: // does the work of portably generating a new XMLHTTPRequest // object. var http = null; var last_e = null; if(!dojo.isIE || !dojo.config.ieForceActiveXXhr){ try{ http = new XMLHttpRequest(); }catch(e){}
} if(!http){ for(var i=0; i<3; ++i){ var progid = d._XMLHTTP_PROGIDS[i]; try{
http = new ActiveXObject(progid);
}catch(e){
last_e = e;
}
if(http){
d._XMLHTTP_PROGIDS = [progid]; // so faster next time break;
}
}
}
if(!http){ thrownew Error("XMLHTTP not available: "+last_e);
}
return http; // XMLHTTPRequest instance
}
d._isDocumentOk = function(http){ var stat = http.status || 0; return (stat >= 200 && stat < 300) || // Boolean
stat == 304 || // allow any 2XX response code
stat == 1223 || // get it out of the cache
(!stat && (location.protocol=="file:" || location.protocol=="chrome:") ); // Internet Explorer mangled the status code
}
//See if base tag is in use. //This is to fix http://trac.dojotoolkit.org/ticket/3973, //but really, we need to find out how to get rid of the dojo._Url reference //below and still have DOH work with the dojo.i18n test following some other //test that uses the test frame to load a document (trac #2757). //Opera still has problems, but perhaps a larger issue of base tag support //with XHR requests (hasBase is true, but the request is still made to document //path, not base path). var owloc = window.location+""; var base = document.getElementsByTagName("base"); var hasBase = (base && base.length > 0);
d._getText = function(/*URI*/ uri, /*Boolean*/ fail_ok){ // summary: Read the contents of the specified uri and return those contents. // uri: // A relative or absolute uri. If absolute, it still must be in // the same "domain" as we are. // fail_ok: // Default false. If fail_ok and loading fails, return null // instead of throwing. // returns: The response text. null is returned when there is a // failure and failure is okay (an exception otherwise)
// alert("_getText: " + uri);
// NOTE: must be declared before scope switches ie. this._xhrObj() var http = this._xhrObj();
if(!hasBase && dojo._Url){
uri = (new dojo._Url(owloc, uri)).toString();
} /* alert(uri);
*/
if(d.config.cacheBust){ //Make sure we have a string before string methods are used on uri
uri += "";
uri += (uri.indexOf("?") == -1 ? "?" : "&") + String(d.config.cacheBust).replace(/\W+/g,"");
}
d.windowUnloaded = function(){ // summary: // signal fired by impending window destruction. You may use // dojo.addOnWIndowUnload() or dojo.connect() to this method to perform // page/application cleanup methods. See dojo.addOnWindowUnload for more info. var mll = this._windowUnloaders; while(mll.length){
(mll.pop())();
}
}
d.addOnWindowUnload = function(/*Object?*/obj, /*String|Function?*/functionName){ // summary: // registers a function to be triggered when window.onunload fires. // Be careful trying to modify the DOM or access JavaScript properties // during this phase of page unloading: they may not always be available. // Consider dojo.addOnUnload() if you need to modify the DOM or do heavy // JavaScript work. // example: // | dojo.addOnWindowUnload(functionPointer) // | dojo.addOnWindowUnload(object, "functionName") // | dojo.addOnWindowUnload(object, function(){ /* ... */});
dojo._initFired = false; // BEGIN DOMContentLoaded, from Dean Edwards (http://dean.edwards.name/weblog/2006/06/again/)
dojo._loadInit = function(e){
dojo._initFired = true; // allow multiple calls, only first one will take effect // A bug in khtml calls events callbacks for document for event which isnt supported // for example a created contextmenu event calls DOMContentLoaded, workaround var type = (e && e.type) ? e.type.toLowerCase() : "load"; if(arguments.callee.initialized || (type != "domcontentloaded" && type != "load")){ return; }
arguments.callee.initialized = true; if("_khtmlTimer" in dojo){
clearInterval(dojo._khtmlTimer); delete dojo._khtmlTimer;
}
if(!dojo.config.afterOnLoad){ // START DOMContentLoaded // Mozilla and Opera 9 expose the event we could use if(document.addEventListener){ // NOTE: // due to a threading issue in Firefox 2.0, we can't enable // DOMContentLoaded on that platform. For more information, see: // http://trac.dojotoolkit.org/ticket/1704 if(dojo.isOpera || dojo.isFF >= 3 || (dojo.isMoz && dojo.config.enableMozDomContentLoaded === true)){
document.addEventListener("DOMContentLoaded", dojo._loadInit, null);
}
// mainly for Opera 8.5, won't be fired if DOMContentLoaded fired already. // also used for Mozilla because of trac #1640
window.addEventListener("load", dojo._loadInit, null);
}
(function(){ var _w = window; var _handleNodeEvent = function(/*String*/evtName, /*Function*/fp){ // summary: // non-destructively adds the specified function to the node's // evtName handler. // evtName: should be in the form "onclick" for "onclick" handlers. // Make sure you pass in the "on" part. var oldHandler = _w[evtName] || function(){};
_w[evtName] = function(){
fp.apply(_w, arguments);
oldHandler.apply(_w, arguments);
};
};
if(dojo.isIE){ // for Internet Explorer. readyState will not be achieved on init // call, but dojo doesn't need it however, we'll include it // because we don't know if there are other functions added that // might. Note that this has changed because the build process // strips all comments -- including conditional ones. if(!dojo.config.afterOnLoad){
document.write('<scr'+'ipt defer src="//:" '
+ 'onreadystatechange="if(this.readyState==\'complete\'){' + dojo._scopeName + '._loadInit();}">'
+ '</scr'+'ipt>'
);
}
//Register any module paths set up in djConfig. Need to do this //in the hostenvs since hostenv_browser can read djConfig from a //script tag's attribute.
(function(){ var mp = dojo.config["modulePaths"]; if(mp){ for(var param in mp){
dojo.registerModulePath(param, mp[param]);
}
}
})();
//Load debug code if necessary. if(dojo.config.isDebug){
dojo.require("dojo._firebug.firebug");
}
if(!dojo._hasResource["dojo._base.lang"]){ //_hasResource checks added by build. Do not use _hasResource directly in your code.
dojo._hasResource["dojo._base.lang"] = true;
dojo.provide("dojo._base.lang");
// Crockford (ish) functions
dojo.isString = function(/*anything*/ it){ // summary: // Return true if it is a String return !!arguments.length && it != null && (typeof it == "string" || it instanceof String); // Boolean
}
dojo.isArray = function(/*anything*/ it){ // summary: // Return true if it is an Array return it && (it instanceof Array || typeof it == "array"); // Boolean
}
/*===== dojo.isFunction=function(it){ // summary: Return true if it is a Function // it: anything return;// Boolean }
=====*/
dojo.isFunction = (function(){ var _isFunction = function(/*anything*/ it){ return it && (typeof it == "function" || it instanceofFunction); // Boolean
};
return dojo.isSafari ? // only slow this down w/ gratuitious casting in Safari since it's what's b0rken function(/*anything*/ it){ if(typeof it == "function" && it == "[object NodeList]"){ returnfalse; } return _isFunction(it); // Boolean
} : _isFunction;
})();
dojo.isObject = function(/*anything*/ it){ // summary: // Returns true if it is a JavaScript object (or an Array, a Function // or null) return it !== undefined &&
(it === null || typeof it == "object" || dojo.isArray(it) || dojo.isFunction(it)); // Boolean
}
dojo.isArrayLike = function(/*anything*/ it){ // summary: // similar to dojo.isArray() but more permissive // 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 // dojo.isArrayLike(), but will return false when passed to // dojo.isArray(). // returns: // If it walks like a duck and quicks like a duck, return `true` var d = dojo; return it && it !== undefined && // Boolean // keep out built-in constructors (Number, String, ...) which have length // properties
!d.isString(it) && !d.isFunction(it) &&
!(it.tagName && it.tagName.toLowerCase() == 'form') &&
(d.isArray(it) || isFinite(it.length));
}
dojo.isAlien = function(/*anything*/ 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 && !dojo.isFunction(it) && /\{\s*\[native code\]\s*\}/.test(String(it)); // Boolean
}
dojo.extend = function(/*Object*/ constructor, /*Object...*/ props){ // summary: // Adds all properties and methods of props to constructor's // prototype, making them available to all instances created with // constructor. for(var i=1, l=arguments.length; i<l; i++){
dojo._mixin(constructor.prototype, arguments[i]);
} return constructor; // Object
}
dojo._hitchArgs = function(scope, method /*,...*/){ var pre = dojo._toArray(arguments, 2); var named = dojo.isString(method); returnfunction(){ // arrayify arguments var args = dojo._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
}
dojo.hitch = function(/*Object*/scope, /*Function|String*/method /*,...*/){ // summary: // Returns a function that will only ever execute in the a 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: // The scope to use when method executes. If method is a string, // scope is also the object containing method. // method: // A function to be hitched to scope, or the name of the method in // scope to be hitched. // example: // | dojo.hitch(foo, "bar")(); // runs foo.bar() in the scope of foo // example: // | dojo.hitch(foo, myFunction); // returns a function that runs myFunction in the scope of foo if(arguments.length > 2){ return dojo._hitchArgs.apply(dojo, arguments); // Function
} if(!method){
method = scope;
scope = null;
} if(dojo.isString(method)){
scope = scope || dojo.global; if(!scope[method]){ throw(['dojo.hitch: scope["', method, '"] is null (scope="', scope, '")'].join('')); } returnfunction(){ return scope[method].apply(scope, arguments || []); }; // Function
} return !scope ? method : function(){ return method.apply(scope, arguments || []); }; // Function
}
/*===== dojo.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 implementaton 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: // The object to delegate to for properties not found directly on the // return object or in props. // props: // an object containing properties to assign to the returned object // returns: // an Object of anonymous type // example: // | var foo = { bar: "baz" }; // | var thinger = dojo.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 } =====*/
/*===== dojo._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. }
=====*/
dojo.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 dojo.partial is the functional equivalent of calling: // | dojo.hitch(null, funcName, ...);
var arr = [ null ]; return dojo.hitch.apply(dojo, arr.concat(dojo._toArray(arguments))); // Function
}
dojo.clone = function(/*anything*/ o){ // summary: // Clones objects (including DOM nodes) and all children. // Warning: do not clone cyclic structures. if(!o){ return o; } if(dojo.isArray(o)){
var r = []; for(var i = 0; i < o.length; ++i){
r.push(dojo.clone(o[i]));
} return r; // Array
} if(!dojo.isObject(o)){ return o; /*anything*/
} if(o.nodeType && o.cloneNode){ // isNode return o.cloneNode(true); // Node
} if(o instanceof Date){ returnnew Date(o.getTime()); // Date
} // Generic objects
var r = new o.constructor(); // specific to dojo.declare()'d classes! for(var i in o){ if(!(i in r) || r[i] != o[i]){
r[i] = dojo.clone(o[i]);
}
} return r; // Object
}
dojo.trim = function(/*String*/ str){ // summary: // trims whitespaces from both sides of the 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). // The fastest but longest version of this function is located at // dojo.string.trim() return str.replace(/^\s\s*/, '').replace(/\s\s*$/, ''); // String
}
}
if(!dojo._hasResource["dojo._base.declare"]){ //_hasResource checks added by build. Do not use _hasResource directly in your code.
dojo._hasResource["dojo._base.declare"] = true;
dojo.provide("dojo._base.declare");
// this file courtesy of the TurboAjax Group, licensed under a Dojo CLA
dojo.declare = function(/*String*/ className, /*Function|Function[]*/ superclass, /*Object*/ props){ // summary: // Create a feature-rich constructor from compact notation // className: // The name of the constructor (loosely, a "class") // stored in the "declaredClass" property in the created prototype // superclass: // May be null, a Function, or an Array of Functions. If an array, // the first element is used as the prototypical ancestor and // any following Functions become mixin ancestors. // props: // An object whose properties are copied to the // created prototype. // Add an instance-initialization function by making it a property // named "constructor". // description: // Create a constructor using a compact notation for inheritance and // prototype extension. // // All superclasses (including mixins) must be Functions (not simple Objects). // // 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. // // "className" is cached in "declaredClass" property of the new class. // // example: // | dojo.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(); // | } // | );
// process superclass argument
var dd = arguments.callee, mixins; if(dojo.isArray(superclass)){
mixins = superclass;
superclass = mixins.shift();
} // construct intermediate classes for mixins if(mixins){
dojo.forEach(mixins, function(m){ if(!m){ throw(className + ": mixin #" + i + " is null"); } // It's likely a required module is not loaded
superclass = dd._delegate(superclass, m);
});
} // create constructor
var ctor = dd._delegate(superclass); // extend with "props"
props = props || {};
ctor.extend(props); // more prototype decoration
dojo.extend(ctor, {declaredClass: className, _constructor: props.constructor/*, preamble: null*/}); // special help for IE
ctor.prototype.constructor = ctor; // create named reference return dojo.setObject(className, ctor); // Function
};
dojo.mixin(dojo.declare, {
_delegate: function(base, mixin){
var bp = (base||0).prototype, mp = (mixin||0).prototype, dd=dojo.declare; // fresh constructor, fresh prototype
var ctor = dd._makeCtor(); // cache ancestry
dojo.mixin(ctor, {superclass: bp, mixin: mp, extend: dd._extend}); // chain prototypes if(base){ctor.prototype = dojo._delegate(bp);} // add mixin and core
dojo.extend(ctor, dd._core, mp||0, {_constructor: null, preamble: null}); // special help for IE
ctor.prototype.constructor = ctor; // name this class for debugging
ctor.prototype.declaredClass = (bp||0).declaredClass + '_' + (mp||0).declaredClass; return ctor;
},
_extend: function(props){
var i, fn; for(i in props){ if(dojo.isFunction(fn=props[i]) && !0[i]){fn.nom=i;fn.ctor=this;} }
dojo.extend(this, props);
},
_makeCtor: function(){ // we have to make a function, but don't want to close over anything return function(){ this._construct(arguments); };
},
_core: {
_construct: function(args){
var c=args.callee, s=c.superclass, ct=s&&s.constructor, m=c.mixin, mct=m&&m.constructor, a=args, ii, fn; // side-effect of = used on purpose here, lint may complain, don't try this at home if(a[0]){ // FIXME: preambles for each mixin should be allowed // FIXME: // should we allow the preamble here NOT to modify the // default args, but instead to act on each mixin // independently of the class instance being constructed // (for impedence matching)?
// allow any first argument w/ a "preamble" property to act as a // class preamble (not exclusive of the prototype preamble) if(/*dojo.isFunction*/((fn = a[0].preamble))){
a = fn.apply(this, a) || a;
}
} // prototype preamble if((fn = c.prototype.preamble)){a = fn.apply(this, a) || a;} // FIXME: // need to provide an optional prototype-settable // "_explicitSuper" property which disables this // initialize superclass if(ct&&ct.apply){ct.apply(this, a);} // initialize mixin if(mct&&mct.apply){mct.apply(this, a);} // initialize self if((ii=c.prototype._constructor)){ii.apply(this, args);} // post construction if(this.constructor.prototype==c.prototype && (ct=this.postscript)){ ct.apply(this, args); }
},
_findMixin: function(mixin){
var c = this.constructor, p, m; while(c){
p = c.superclass;
m = c.mixin; if(m==mixin || (m instanceof mixin.constructor)){return p;} if(m && m._findMixin && (m=m._findMixin(mixin))){return m;}
c = p && p.constructor;
}
},
_findMethod: function(name, method, ptype, has){ // consciously trading readability for bytes and speed in this low-level method
var p=ptype, c, m, f; do{
c = p.constructor;
m = c.mixin; // find method by name in our mixin ancestor if(m && (m=this._findMethod(name, method, m, has))){return m;} // if we found a named method that either exactly-is or exactly-is-not 'method' if((f=p[name])&&(has==(f==method))){return p;} // ascend chain
p = c.superclass;
}while(p); // if we couldn't find an ancestor in our primary chain, try a mixin chain return !has && (p=this._findMixin(ptype)) && this._findMethod(name, method, p, has);
},
inherited: function(name, args, newArgs){ // optionalize name argument
var a = arguments; if(!dojo.isString(a[0])){newArgs=args; args=name; name=args.callee.nom;}
a = newArgs||args;
var c = args.callee, p = this.constructor.prototype, fn, mp; // if not an instance override if(this[name] != c || p[name] == c){ // start from memoized prototype, or // find a prototype that has property 'name' == 'c'
mp = (c.ctor||0).superclass || this._findMethod(name, c, p, true); if(!mp){throw(this.declaredClass + ': inherited method "' + name + '" mismatch');} // find a prototype that has property 'name' != 'c'
p = this._findMethod(name, c, mp, false);
} // we expect 'name' to be in prototype 'p'
fn = p && p[name]; if(!fn){throw(mp.declaredClass + ': inherited method "' + name + '" not found');} // if the function exists, invoke it in our scope return fn.apply(this, a);
}
}
});
}
if(!dojo._hasResource["dojo._base.connect"]){ //_hasResource checks added by build. Do not use _hasResource directly in your code.
dojo._hasResource["dojo._base.connect"] = true;
dojo.provide("dojo._base.connect");
// this file courtesy of the TurboAjax Group, licensed under a Dojo CLA
// low-level delegation machinery
dojo._listener = { // create a dispatcher function
getDispatcher: function(){ // following comments pulled out-of-line to prevent cloning them // in the returned function. // - indices (i) that are really in the array of listeners (ls) will // not be in Array.prototype. This is the 'sparse array' trick // that keeps us safe from libs that take liberties with built-in // objects // - listener is invoked with current scope (this) return function(){
var ap=Array.prototype, c=arguments.callee, ls=c._listeners, t=c.target; // return value comes from original target function
var r = t && t.apply(this, arguments); // make local copy of listener array so it is immutable during processing
var lls;
lls = [].concat(ls);
// invoke listeners after target function for(var i in lls){ if(!(i in ap)){
lls[i].apply(this, arguments);
}
} // return value comes from original target function return r;
}
}, // add a listener to an object
add: function(/*Object*/ source, /*String*/ method, /*Function*/ listener){ // Whenever 'method' is invoked, 'listener' will have the same scope. // Trying to supporting a context object for the listener led to // complexity. // Non trivial to provide 'once' functionality here // because listener could be the result of a dojo.hitch call, // in which case two references to the same hitch target would not // be equivalent.
source = source || dojo.global; // The source method is either null, a dispatcher, or some other function
var f = source[method]; // Ensure a dispatcher if(!f||!f._listeners){
var d = dojo._listener.getDispatcher(); // original target function is special
d.target = f; // dispatcher holds a list of listeners
d._listeners = []; // redirect source to dispatcher
f = source[method] = d;
} // The contract is that a handle is returned that can // identify this listener for disconnect. // // The type of the handle is private. Here is it implemented as Integer. // DOM event code has this same contract but handle is Function // in non-IE browsers. // // We could have separate lists of before and after listeners. return f._listeners.push(listener) ; /*Handle*/
}, // remove a listener from an object
remove: function(/*Object*/ source, /*String*/ method, /*Handle*/ handle){
var f = (source||dojo.global)[method]; // remember that handle is the index+1 (0 is not a valid handle) if(f && f._listeners && handle--){ delete f._listeners[handle];
}
}
};
// Multiple delegation for arbitrary methods.
// This unit knows nothing about DOM, // but we include DOM aware // documentation and dontFix // argument here to help the autodocs. // Actual DOM aware code is in event.js.
dojo.connect = function(/*Object|null*/ obj, /*String*/ event, /*Object|null*/ context, /*String|Function*/ method, /*Boolean*/ dontFix){ // summary: // Create a link that calls one function when another executes. // // description: // Connects method to event, so that after event fires, method // does too. All connected functions are passed the same arguments as // the event function was initially called with. You may connect as // many methods to event as needed. // // event must be a string. If obj is null, dojo.global is used. // // null arguments may simply be omitted. // // obj[event] can resolve to a function or undefined (null). // If obj[event] is null, it is assigned a function. // // The return value is a handle that is needed to // remove this connection with dojo.disconnect. // // obj: // The source object for the event function. // Defaults to dojo.global if null. // If obj is a DOM node, the connection is delegated // to the DOM event manager (unless dontFix is true). // // event: // String name of the event function in obj. // I.e. identifies a property obj[event]. // // context: // 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, // dojo.global is used. // // method: // 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: // 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 ommited
args.push(dojo.isString(a[0]) ? 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(dojo.isString(a1)||dojo.isFunction(a1) ? a[i++] : null, a[i++]); // absorb any additional arguments for(var l=a.length; i<l; i++){ args.push(a[i]); } // do the actual work return dojo._connect.apply(this, args); /*Handle*/
}
// used by non-browser hostenvs. always overriden by event.js
dojo._connect = function(obj, event, context, method){
var l=dojo._listener, h=l.add(obj, event, dojo.hitch(context, method)); return [obj, event, h, l]; // Handle
}
dojo.disconnect = function(/*Handle*/ handle){ // summary: // Remove a link created by dojo.connect. // description: // Removes the connection between event and the method referenced by handle. // handle: // the return value of the dojo.connect call that created the connection. if(handle && handle[0] !== undefined){
dojo._disconnect.apply(this, handle); // let's not keep this reference delete handle[0];
}
}
dojo.subscribe = function(/*String*/ topic, /*Object|null*/ context, /*String|Function*/ 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. // context: // Scope in which method will be invoked, or null for default scope. // method: // 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" ]);
// support for 2 argument invocation (omitting context) depends on hitch return [topic, dojo._listener.add(dojo._topics, topic, dojo.hitch(context, method))]; /*Handle*/
}
dojo.unsubscribe = function(/*Handle*/ handle){ // summary: // Remove a topic listener. // 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); if(handle){
dojo._listener.remove(dojo._topics, handle[0], handle[1]);
}
}
dojo.publish = function(/*String*/ topic, /*Array*/ args){ // summary: // Invoke all listener method subscribed to topic. // topic: // The name of the topic to publish. // args: // 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" ]);
// Note that args is an array, which is more efficient vs variable length // argument list. Ideally, var args would be implemented via Array // throughout the APIs.
var f = dojo._topics[topic]; if(f){
f.apply(this, args||[]);
}
}
dojo.connectPublisher = function( /*String*/ topic, /*Object|null*/ obj, /*String*/ event){ // summary: // Ensure that everytime 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: // The name of the topic to publish. // obj: // The source object for the event function. Defaults to dojo.global // if null. // event: // 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(){ dojo.publish(topic, arguments); } return (event) ? dojo.connect(obj, event, pf) : dojo.connect(obj, pf); //Handle
};
}
if(!dojo._hasResource["dojo._base.Deferred"]){ //_hasResource checks added by build. Do not use _hasResource directly in your code.
dojo._hasResource["dojo._base.Deferred"] = true;
dojo.provide("dojo._base.Deferred");
dojo.Deferred = function(/*Function?*/ canceller){ // summary: // Encapsulates a sequence of callbacks in response to a value that // may not yet be available. This is modeled after the Deferred class // from Twisted <http://twistedmatrix.com>. // description: // JavaScript has no threads, and even if it did, threads are hard. // Deferreds are a way of abstracting non-blocking events, such as the // final response to an XMLHttpRequest. Deferreds create a promise to // return a response a some point in the future and an easy way to // register your interest in receiving that response. // // The most important methods for Deffered users are: // // * addCallback(handler) // * addErrback(handler) // * callback(result) // * errback(result) // // In general, when a function returns a Deferred, users then "fill // in" the second half of the contract by registering callbacks and // error handlers. You may register as many callback and errback // handlers as you like and they will be executed in the order // registered when a result is provided. Usually this result is // provided as the result of an asynchronous operation. The code // "managing" the Deferred (the code that made the promise to provide // an answer later) will use the callback() and errback() methods to // communicate with registered listeners about the result of the // operation. At this time, all registered result handlers are called // *with the most recent result value*. // // Deferred callback handlers are treated as a chain, and each item in // the chain is required to return a value that will be fed into // successive handlers. The most minimal callback may be registered // like this: // // | var d = new dojo.Deferred(); // | d.addCallback(function(result){ return result; }); // // Perhaps the most common mistake when first using Deferreds is to // forget to return a value (in most cases, the value you were // passed). // // The sequence of callbacks is internally represented as a list of // 2-tuples containing the callback/errback pair. For example, the // following call sequence: // // | var d = new dojo.Deferred(); // | d.addCallback(myCallback); // | d.addErrback(myErrback); // | d.addBoth(myBoth); // | d.addCallbacks(myCallback, myErrback); // // is translated into a Deferred with the following internal // representation: // // | [ // | [myCallback, null], // | [null, myErrback], // | [myBoth, myBoth], // | [myCallback, myErrback] // | ] // // The Deferred also keeps track of its current status (fired). Its // status may be one of three things: // // * -1: no value yet (initial condition) // * 0: success // * 1: error // // A Deferred will be in the error state if one of the following three // conditions are met: // // 1. The result given to callback or errback is "instanceof" Error // 2. The previous callback or errback raised an exception while // executing // 3. The previous callback or errback returned a value // "instanceof" Error // // Otherwise, the Deferred will be in the success state. The state of // the Deferred determines the next element in the callback sequence // to run. // // When a callback or errback occurs with the example deferred chain, // something equivalent to the following will happen (imagine // that exceptions are caught and returned): // // | // d.callback(result) or d.errback(result) // | if(!(result instanceof Error)){ // | result = myCallback(result); // | } // | if(result instanceof Error){ // | result = myErrback(result); // | } // | result = myBoth(result); // | if(result instanceof Error){ // | result = myErrback(result); // | }else{ // | result = myCallback(result); // | } // // The result is then stored away in case another step is added to the // callback sequence. Since the Deferred already has a value // available, any new callbacks added will be called immediately. // // There are two other "advanced" details about this implementation // that are useful: // // Callbacks are allowed to return Deferred instances 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 dojo.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 dojo.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).addErrback(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 syncrhonous 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 dojo.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).addErrback(function(){ // | promptUserToRecover(); // | }); // // Note that the caller doesn't have to change his code at all to // handle the asynchronous case.
dojo.extend(dojo.Deferred, { /* makeCalled:function(){ // summary: // returns a new, empty deferred, which is already in the called // state. Calling callback() or errback() on this deferred will // yeild an error and adding new handlers to it will result in // them being called immediately. vardeferred=newdojo.Deferred(); deferred.callback(); returndeferred; },
_nextId: (function(){
var n = 1; return function(){ return n++; };
})(),
cancel: function(){ // summary: // Cancels a Deferred that has not yet received a value, or is // waiting on another Deferred as its value. // description: // If a canceller is defined, the canceller is called. If the // canceller did not return an error, or there was no canceller, // then the errback chain is started.
var err; if(this.fired == -1){ if(this.canceller){
err = this.canceller(this);
}else{
this.silentlyCancelled = true;
} if(this.fired == -1){ if(!(err instanceof Error)){
var res = err;
err = new Error("Deferred Cancelled");
err.dojoType = "cancel";
err.cancelResult = res;
}
this.errback(err);
}
}elseif( (this.fired == 0) &&
(this.results[0] instanceof dojo.Deferred)
){
this.results[0].cancel();
}
},
_resback: function(res){ // summary: // The private primitive that means either callback or errback
this.fired = ((res instanceof Error) ? 1 : 0);
this.results[this.fired] = res;
this._fire();
},
errback: function(/*Error*/res){ // summary: // Begin the callback sequence with an error result.
this._check(); if(!(res instanceof Error)){
res = new Error(res);
}
this._resback(res);
},
addBoth: function(/*Function|Object*/cb, /*String?*/cbfn){ // summary: // Add the same function as both a callback and an errback as the // next element on the callback sequence.This is useful for code // that you want to guarantee to run, e.g. a finalizer.
var enclosed = dojo.hitch.apply(dojo, arguments); return this.addCallbacks(enclosed, enclosed); // dojo.Deferred
},
addCallback: function(/*Function|Object*/cb, /*String?*/cbfn /*...*/){ // summary: // Add a single callback to the end of the callback sequence. return this.addCallbacks(dojo.hitch.apply(dojo, arguments)); // dojo.Deferred
},
addErrback: function(cb, cbfn){ // summary: // Add a single callback to the end of the callback sequence. return this.addCallbacks(null, dojo.hitch.apply(dojo, arguments)); // dojo.Deferred
},
addCallbacks: function(cb, eb){ // summary: // Add separate callback and errback to the end of the callback // sequence.
this.chain.push([cb, eb]) if(this.fired >= 0){
this._fire();
} return this; // dojo.Deferred
},
_fire: function(){ // summary: // Used internally to exhaust the callback sequence when a result // is available.
var chain = this.chain;
var fired = this.fired;
var res = this.results[fired];
var self = this;
var cb = null; while(
(chain.length > 0) &&
(this.paused == 0)
){ // Array
var f = chain.shift()[fired]; if(!f){ continue; }
var func = function(){
var ret = f(res); //If no response, then use previous response. if(typeof ret != "undefined"){
res = ret;
}
fired = ((res instanceof Error) ? 1 : 0); if(res instanceof dojo.Deferred){
cb = function(res){
self._resback(res); // inlined from _pause()
self.paused--; if(
(self.paused == 0) &&
(self.fired >= 0)
){
self._fire();
}
} // inlined from _unpause
this.paused++;
}
}; if(dojo.config.isDebug){
func.call(this);
}else{
try{
func.call(this);
}catch(err){
fired = 1;
res = err;
}
}
}
this.fired = fired;
this.results[fired] = res; if((cb)&&(this.paused)){ // this is for "tail recursion" in case the dependent // deferred is already fired
res.addBoth(cb);
}
}
});
}
if(!dojo._hasResource["dojo._base.json"]){ //_hasResource checks added by build. Do not use _hasResource directly in your code.
dojo._hasResource["dojo._base.json"] = true;
dojo.provide("dojo._base.json");
dojo.fromJson = function(/*String*/ json){ // summary: // Parses a [JSON](http://json.org) string to return a JavaScript object. Throws for invalid JSON strings. // json: // a string literal of a JSON item, for instance: // `'{ "foo": [ "bar", 1, { "baz": "thud" } ] }'`
return eval("(" + json + ")"); // Object
}
dojo._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
}
dojo.toJsonIndentStr = "\t";
dojo.toJson = function(/*Object*/ it, /*Boolean?*/ prettyPrint, /*String?*/ _indentStr){ // 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: // 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. // // 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(). // // _indentStr: // private variable for recursive calls when pretty printing, do not use.
if(it === undefined){ return"undefined";
}
var objtype = typeof it; if(objtype == "number" || objtype == "boolean"){ return it + "";
} if(it === null){ return"null";
} if(dojo.isString(it)){ return dojo._escapeString(it);
} // recurse
var recurse = arguments.callee; // short-circuit for objects that support "json" serialization // if they return "self" then just pass-through...
var newObj;
_indentStr = _indentStr || "";
var nextIndent = prettyPrint ? _indentStr + dojo.toJsonIndentStr : "";
var tf = it.__json__||it.json; if(dojo.isFunction(tf)){
newObj = tf.call(it); if(it !== newObj){ return recurse(newObj, prettyPrint, nextIndent);
}
} if(it.nodeType && it.cloneNode){ // isNode // we can't seriailize DOM nodes as regular objects because they have cycles // DOM nodes could be serialized with something like outerHTML, but // that can be provided by users in the form of .json or .__json__ function. thrownew Error("Can't serialize DOM nodes");
}
var sep = prettyPrint ? " " : "";
var newLine = prettyPrint ? "\n" : "";
// array if(dojo.isArray(it)){
var res = dojo.map(it, function(obj){
var val = recurse(obj, prettyPrint, nextIndent); if(typeof val != "string"){
val = "undefined";
} return newLine + nextIndent + val;
}); return"[" + res.join("," + sep) + newLine + _indentStr + "]";
} /* // look in the registry try{ window.o=it; newObj=dojo.json.jsonRegistry.match(it); returnrecurse(newObj,prettyPrint,nextIndent); }catch(e){ // } // it's a function with no adapter, skip it
*/ if(objtype == "function"){ return null; // null
} // generic object code path
var output = [], key; for(key in it){
var keyStr, val; if(typeof key == "number"){
keyStr = '"' + key + '"';
}elseif(typeof key == "string"){
keyStr = dojo._escapeString(key);
}else{ // skip non-string or number keys continue;
}
val = recurse(it[key], prettyPrint, nextIndent); if(typeof val != "string"){ // skip non-serializable values continue;
} // FIXME: use += on Moz!! // MOW NOTE: using += is a pain because you have to account for the dangling comma...
output.push(newLine + nextIndent + keyStr + ":" + sep + val);
} return"{" + output.join("," + sep) + newLine + _indentStr + "}"; // String
}
}
if(!dojo._hasResource["dojo._base.array"]){ //_hasResource checks added by build. Do not use _hasResource directly in your code.
dojo._hasResource["dojo._base.array"] = true;
dojo.provide("dojo._base.array");
(function(){
var _getParts = function(arr, obj, cb){ return [
dojo.isString(arr) ? arr.split("") : arr,
obj || dojo.global, // FIXME: cache the anonymous functions we create here?
dojo.isString(cb) ? new Function("item", "index", "array", cb) : cb
];
};
dojo.mixin(dojo, {
indexOf: function( /*Array*/ array, /*Object*/ value, /*Integer?*/ fromIndex, /*Boolean?*/ findLast){ // summary: // locates the first index of the provided value in the // passed array. If the value is not found, -1 is returned. // description: // For details on this method, see: // http://developer.mozilla.org/en/docs/Core_JavaScript_1.5_Reference:Global_Objects:Array:indexOf
var step = 1, end = array.length || 0, i = 0; if(findLast){
i = end - 1;
step = end = -1;
} if(fromIndex != undefined){ i = fromIndex; } if((findLast && i > end) || i < end){ for(; i != end; i += step){ if(array[i] == value){ return i; }
}
} return -1; // Number
},
lastIndexOf: function(/*Array*/array, /*Object*/value, /*Integer?*/fromIndex){ // summary: // locates the last index of the provided value in the passed // array. If the value is not found, -1 is returned. // description: // For details on this method, see: // http://developer.mozilla.org/en/docs/Core_JavaScript_1.5_Reference:Global_Objects:Array:lastIndexOf return dojo.indexOf(array, value, fromIndex, true); // Number
},
forEach: function(/*Array|String*/arr, /*Function|String*/callback, /*Object?*/thisObject){ // summary: // for every item in arr, callback is invoked. Return values are ignored. // 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. For more details, see: // http://developer.mozilla.org/en/docs/Core_JavaScript_1.5_Reference:Global_Objects:Array:forEach // example: // | // log out all members of the array: // | dojo.forEach( // | [ "thinger", "blah", "howdy", 10 ], // | function(item){ // | // | } // | ); // example: // | // log out the members and their indexes // | dojo.forEach( // | [ "thinger", "blah", "howdy", 10 ], // | function(item, idx, arr){ // | // | } // | ); // example: // | // use a scoped object member as the callback // | // | var obj = { // | prefix: "logged via obj.callback:", // | callback: function(item){ // | // | } // | }; // | // | // specifying the scope function executes the callback in that scope // | dojo.forEach( // | [ "thinger", "blah", "howdy", 10 ], // | obj.callback, // | obj // | ); // | // | // alternately, we can accomplish the same thing with dojo.hitch() // | dojo.forEach( // | [ "thinger", "blah", "howdy", 10 ], // | dojo.hitch(obj, "callback") // | );
// match the behavior of the built-in forEach WRT empty arrs if(!arr || !arr.length){ return; }
// FIXME: there are several ways of handilng thisObject. Is // dojo.global always the default context?
var _p = _getParts(arr, thisObject, callback); arr = _p[0]; for(var i=0,l=arr.length; i<l; ++i){
_p[2].call(_p[1], arr[i], i, arr);
}
},
_everyOrSome: function(/*Boolean*/every, /*Array|String*/arr, /*Function|String*/callback, /*Object?*/thisObject){
var _p = _getParts(arr, thisObject, callback); arr = _p[0]; for(var i=0,l=arr.length; i<l; ++i){
var result = !!_p[2].call(_p[1], arr[i], i, arr); if(every ^ result){ return result; // Boolean
}
} return every; // Boolean
},
every: function(/*Array|String*/arr, /*Function|String*/callback, /*Object?*/thisObject){ // summary: // Determines whether or not every item in arr satisfies the // condition implemented by callback. // arr: // the array to iterate on. If a string, operates on individual characters. // callback: // a function is invoked with three arguments: item, index, // and array and returns true if the condition is met. // thisObject: // may be used to scope the call to callback // description: // This function corresponds to the JavaScript 1.6 // Array.every() method. For more details, see: // http://developer.mozilla.org/en/docs/Core_JavaScript_1.5_Reference:Global_Objects:Array:every // example: // | // returns false // | dojo.every([1, 2, 3, 4], function(item){ return item>1; }); // example: // | // returns true // | dojo.every([1, 2, 3, 4], function(item){ return item>0; }); return this._everyOrSome(true, arr, callback, thisObject); // Boolean
},
some: function(/*Array|String*/arr, /*Function|String*/callback, /*Object?*/thisObject){ // summary: // Determines whether or not any item in arr satisfies the // condition implemented by callback. // 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 and returns true if the condition is met. // thisObject: // may be used to scope the call to callback // description: // This function corresponds to the JavaScript 1.6 // Array.some() method. For more details, see: // http://developer.mozilla.org/en/docs/Core_JavaScript_1.5_Reference:Global_Objects:Array:some // example: // | // is true // | dojo.some([1, 2, 3, 4], function(item){ return item>1; }); // example: // | // is false // | dojo.some([1, 2, 3, 4], function(item){ return item<1; }); return this._everyOrSome(false, arr, callback, thisObject); // Boolean
},
map: function(/*Array|String*/arr, /*Function|String*/callback, /*Function?*/thisObject){ // summary: // applies callback to each element of arr and returns // an Array with the results // arr: // the array to iterate on. If a string, operates on // individual characters. // callback: // a function is invoked with three arguments, (item, index, // array), and returns a value // thisObject: // may be used to scope the call to callback // description: // This function corresponds to the JavaScript 1.6 Array.map() // method. For more details, see: // http://developer.mozilla.org/en/docs/Core_JavaScript_1.5_Reference:Global_Objects:Array:map // example: // | // returns [2, 3, 4, 5] // | dojo.map([1, 2, 3, 4], function(item){ return item+1 });
var _p = _getParts(arr, thisObject, callback); arr = _p[0];
var outArr = (arguments[3] ? (new arguments[3]()) : []); for(var i=0,l=arr.length; i<l; ++i){
outArr.push(_p[2].call(_p[1], arr[i], i, arr));
} return outArr; // Array
},
filter: function(/*Array*/arr, /*Function|String*/callback, /*Object?*/thisObject){ // summary: // Returns a new Array with those items from arr that match the // condition implemented by callback. // arr: // the array to iterate over. // callback: // 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: // may be used to scope the call to callback // description: // This function corresponds to the JavaScript 1.6 // Array.filter() method. For more details, see: // http://developer.mozilla.org/en/docs/Core_JavaScript_1.5_Reference:Global_Objects:Array:filter // example: // | // returns [2, 3, 4] // | dojo.filter([1, 2, 3, 4], function(item){ return item>1; });
if(!dojo._hasResource["dojo._base.Color"]){ //_hasResource checks added by build. Do not use _hasResource directly in your code.
dojo._hasResource["dojo._base.Color"] = true;
dojo.provide("dojo._base.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 dojo.Color object if(color){ this.setColor(color); }
};
// FIXME: there's got to be a more space-efficient way to encode or discover these!! Use hex?
dojo.Color.named = {
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]
};
dojo.extend(dojo.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 dojo.Color object
var d = dojo; if(d.isString(color)){
d.colorFromString(color, this);
}elseif(d.isArray(color)){
d.colorFromArray(color, this);
}else{
this._set(color.r, color.g, color.b, color.a); if(!(color instanceof d.Color)){ this.sanitize(); }
} return this; // dojo.Color
},
sanitize: function(){ // summary: // makes sure that the object has correct attributes // description: // the default implementation does nothing, include dojo.colors to // augment it to real checks return this; // dojo.Color
},
toRgb: function(){ // summary: returns 3 component array of rgb values
var t = this; return [t.r, t.g, t.b]; // Array
},
toRgba: function(){ // summary: returns a 4 component array of rgba values
var t = this; return [t.r, t.g, t.b, t.a]; // Array
},
toHex: function(){ // summary: returns a css color string in hexadecimal representation
var arr = dojo.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
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
}
});
dojo.blendColors = function( /*dojo.Color*/ start, /*dojo.Color*/ end, /*Number*/ weight, /*dojo.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 dojo.Color object for the result
var d = dojo, t = obj || new dojo.Color();
d.forEach(["r", "g", "b", "a"], function(x){
t[x] = start[x] + (end[x] - start[x]) * weight; if(x != "a"){ t[x] = Math.round(t[x]); }
}); return t.sanitize(); // dojo.Color
};
dojo.colorFromRgb = function(/*String*/ color, /*dojo.Color?*/ obj){ // summary: get rgb(a) array from css-style color declarations
var m = color.toLowerCase().match(/^rgba?\(([\s\.,0-9]+)\)/); return m && dojo.colorFromArray(m[1].split(/\s*,\s*/), obj); // dojo.Color
};
dojo.colorFromHex = function(/*String*/ color, /*dojo.Color?*/ obj){ // summary: converts a hex string with a '#' prefix to a color object. // Supports 12-bit #rgb shorthand.
var d = dojo, t = obj || new d.Color(),
bits = (color.length == 4) ? 4 : 8,
mask = (1 << bits) - 1;
color = Number("0x" + color.substr(1)); if(isNaN(color)){ return null; // dojo.Color
}
d.forEach(["b", "g", "r"], function(x){
var c = color & mask;
color >>= bits;
t[x] = bits == 4 ? 17 * c : c;
});
t.a = 1; return t; // dojo.Color
};
dojo.colorFromArray = function(/*Array*/ a, /*dojo.Color?*/ obj){ // summary: builds a color from 1, 2, 3, or 4 element array
var t = obj || new dojo.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(); // dojo.Color
};
dojo.colorFromString = function(/*String*/ str, /*dojo.Color?*/ obj){ // summary: // parses str for a color value. // 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 dojo.Color object. If obj is passed, it will be the return value.
var a = dojo.Color.named[str]; return a && dojo.colorFromArray(a, obj) || dojo.colorFromRgb(str, obj) || dojo.colorFromHex(str, obj);
};
}
if(!dojo._hasResource["dojo._base"]){ //_hasResource checks added by build. Do not use _hasResource directly in your code.
dojo._hasResource["dojo._base"] = true;
dojo.provide("dojo._base");
}
if(!dojo._hasResource["dojo._base.window"]){ //_hasResource checks added by build. Do not use _hasResource directly in your code.
dojo._hasResource["dojo._base.window"] = true;
dojo.provide("dojo._base.window");
/*===== dojo.doc={ // summary: // Alias for the current document. 'dojo.doc' can be modified // for temporary context shifting. Also see dojo.withDoc(). // description: // Refer to dojo.doc rather // than referring to 'window.document' to ensure your code runs // correctly in managed contexts. // example: // | n.appendChild(dojo.doc.createElement('div')); }
=====*/
dojo.doc = window["document"] || null;
dojo.body = function(){ // summary: // Return the body element of the document // return the body object associated with dojo.doc // example: // | dojo.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(). return dojo.doc.body || dojo.doc.getElementsByTagName("body")[0]; // Node
}
dojo.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 = globalObject;
dojo.doc = globalDocument;
};
dojo.withGlobal = function( /*Object*/globalObject, /*Function*/callback, /*Object?*/thisObject, /*Array?*/cbArguments){ // summary: // Call callback with globalObject as dojo.global and // globalObject.document as dojo.doc. If provided, globalObject // will be executed in the context of object thisObject // description: // When callback() returns or throws an error, the dojo.global // and dojo.doc will be restored to its previous state.
var rval;
var oldGlob = dojo.global;
var oldDoc = dojo.doc;
try{
dojo.setContext(globalObject, globalObject.document);
rval = dojo._fireCallback(callback, thisObject, cbArguments);
}finally{
dojo.setContext(oldGlob, oldDoc);
} return rval;
}
dojo.withDoc = function( /*Object*/documentObject, /*Function*/callback, /*Object?*/thisObject, /*Array?*/cbArguments){ // summary: // Call callback with documentObject as dojo.doc. If provided, // callback will be executed in the context of object thisObject // description: // When callback() returns or throws an error, the dojo.doc will // be restored to its previous state.
var rval;
var oldDoc = dojo.doc;
try{
dojo.doc = documentObject;
rval = dojo._fireCallback(callback, thisObject, cbArguments);
}finally{
dojo.doc = oldDoc;
} return rval;
};
}
if(!dojo._hasResource["dojo._base.event"]){ //_hasResource checks added by build. Do not use _hasResource directly in your code.
dojo._hasResource["dojo._base.event"] = true;
dojo.provide("dojo._base.event");
// this file courtesy of the TurboAjax Group, licensed under a Dojo CLA
(function(){ // DOM event listener machinery
var del = (dojo._event_listener = {
add: function(/*DOMNode*/node, /*String*/name, /*Function*/fp){ if(!node){return;}
name = del._normalizeEventName(name);
fp = del._fixCallback(name, fp);
var oname = name; if(!dojo.isIE && (name == "mouseenter" || name == "mouseleave")){
var ofp = fp; //oname = name;
name = (name == "mouseenter") ? "mouseover" : "mouseout";
fp = function(e){ // check tagName to fix a FF2 bug with invalid nodes (hidden child DIV of INPUT) // which causes isDecendant to return false which causes // spurious, and more importantly, incorrect mouse events to fire. // TODO: remove tagName check when Firefox 2 is no longer supported
try{ e.relatedTarget.tagName; } catch(e2){ return; } if(!dojo.isDescendant(e.relatedTarget, node)){ // e.type = oname; // FIXME: doesn't take? SJM: event.type is generally immutable. return ofp.call(this, e);
}
}
}
node.addEventListener(name, fp, false); return fp; /*Handle*/
},
remove: function(/*DOMNode*/node, /*String*/event, /*Handle*/handle){ // summary: // clobbers the listener from the node // node: // DOM node to attach the event to // event: // the name of the handler to remove the function from // handle: // the handle returned from add if (node){
event = del._normalizeEventName(event); if(!dojo.isIE && (event == "mouseenter" || event == "mouseleave")){
event = (event == "mouseenter") ? "mouseover" : "mouseout";
}
node.removeEventListener(event, handle, false);
}
},
_normalizeEventName: function(/*String*/name){ // Generally, name should be lower case, unless it is special // somehow (e.g. a Mozilla DOM event). // Remove 'on'. return name.slice(0,2) =="on" ? name.slice(2) : name;
},
_fixCallback: function(/*String*/name, fp){ // By default, we only invoke _fixEvent for 'keypress' // If code is added to _fixEvent for other events, we have // to revisit this optimization. // This also applies to _fixEvent overrides for Safari and Opera // below. return name != "keypress" ? fp : function(e){ return fp.call(this, del._fixEvent(e, this)); };
},
_fixEvent: function(evt, sender){ // _fixCallback only attaches us to keypress. // Switch on evt.type anyway because we might // be called directly from dojo.fixEvent. switch(evt.type){ case"keypress":
del._setKeyChar(evt); break;
} return evt;
},
_setKeyChar: function(evt){
evt.keyChar = evt.charCode ? String.fromCharCode(evt.charCode) : '';
evt.charOrCode = evt.keyChar || evt.keyCode;
}, // For IE and Safari: some ctrl-key combinations (mostly w/punctuation) do not emit a char code in IE // we map those virtual key codes to ascii here // not valid for all (non-US) keyboards, so maybe we shouldn't bother
_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
}
});
// DOM events
dojo.fixEvent = 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" return del._fixEvent(evt, sender);
}
dojo.stopEvent = 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.
evt.preventDefault();
evt.stopPropagation(); // NOTE: below, this method is overridden for IE
}
// the default listener to use on dontFix nodes, overriden for IE
var node_listener = dojo._listener;
// Unify connect and event listeners
dojo._connect = function(obj, event, context, method, dontFix){ // FIXME: need a more strict test
var isNode = obj && (obj.nodeType||obj.attachEvent||obj.addEventListener); // choose one of three listener options: raw (connect.js), DOM event on a Node, custom event on a Node // we need the third option to provide leak prevention on broken browsers (IE)
var lid = !isNode ? 0 : (!dontFix ? 1 : 2), l = [dojo._listener, del, node_listener][lid]; // create a listener
var h = l.add(obj, event, dojo.hitch(context, method)); // formerly, the disconnect package contained "l" directly, but if client code // leaks the disconnect package (by connecting it to a node), referencing "l" // compounds the problem. // instead we return a listener id, which requires custom _disconnect below. // return disconnect package return [ obj, event, h, lid ];
}
// IE event normalization if(dojo.isIE){
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){ return0;
}
}
// by default, use the standard listener
var iel = dojo._listener;
var listenersName = dojo._ieListenersName = "_" + dojo._scopeName + "_listeners"; // dispatcher tracking property if(!dojo.config._allow_leaks){ // custom listener that handles leak protection for DOM events
node_listener = iel = dojo._ie_listener = { // support handler indirection: event handler functions are // referenced here. Event dispatchers hold only indices.
handlers: [], // add a listener to an object
add: function(/*Object*/ source, /*String*/ method, /*Function*/ listener){
source = source || dojo.global;
var f = source[method]; if(!f||!f[listenersName]){
var d = dojo._getIeDispatcher(); // original target function is special
d.target = f && (ieh.push(f) - 1); // dispatcher holds a list of indices into handlers table
d[listenersName] = []; // redirect source to dispatcher
f = source[method] = d;
} return f[listenersName].push(ieh.push(listener) - 1) ; /*Handle*/
}, // remove a listener from an object
remove: function(/*Object*/ source, /*String*/ method, /*Handle*/ handle){
var f = (source||dojo.global)[method], l = f && f[listenersName]; if(f && l && handle--){ delete ieh[l[handle]]; delete l[handle];
}
}
}; // alias used above
var ieh = iel.handlers;
}
dojo.mixin(del, {
add: function(/*DOMNode*/node, /*String*/event, /*Function*/fp){ if(!node){return;} // undefined
event = del._normalizeEventName(event); if(event=="onkeypress"){ // we need to listen to onkeydown to synthesize // keypress events that otherwise won't fire // on IE
var kd = node.onkeydown; if(!kd || !kd[listenersName] || !kd._stealthKeydownHandle){
var h = del.add(node, "onkeydown", del._stealthKeyDown);
kd = node.onkeydown;
kd._stealthKeydownHandle = h;
kd._stealthKeydownRefs = 1;
}else{
kd._stealthKeydownRefs++;
}
} return iel.add(node, event, del._fixCallback(fp));
},
remove: function(/*DOMNode*/node, /*String*/event, /*Handle*/handle){
event = del._normalizeEventName(event);
iel.remove(node, event, handle); if(event=="onkeypress"){
var kd = node.onkeydown; if(--kd._stealthKeydownRefs <= 0){
iel.remove(node, "onkeydown", kd._stealthKeydownHandle); delete kd._stealthKeydownHandle;
}
}
},
_normalizeEventName: function(/*String*/eventName){ // Generally, eventName should be lower case, unless it is // special somehow (e.g. a Mozilla event) // ensure 'on' return eventName.slice(0,2) != "on" ? "on" + eventName : eventName;
},
_nop: function(){},
_fixEvent: function(/*Event*/evt, /*DOMNode*/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);}
evt.target = evt.srcElement;
evt.currentTarget = (sender || evt.srcElement);
evt.layerX = evt.offsetX;
evt.layerY = evt.offsetY; // FIXME: scroll position query is duped from dojo.html to // avoid dependency on that entire module. Now that HTML is in // Base, we should convert back to something similar there.
var se = evt.srcElement, doc = (se && se.ownerDocument) || document; // DO NOT replace the following to use dojo.body(), in IE, document.documentElement should be used // here rather than document.body
var docBody = ((dojo.isIE < 6) || (doc["compatMode"] == "BackCompat")) ? doc.body : doc.documentElement;
var offset = dojo._getIeDocumentElementOffset();
evt.pageX = evt.clientX + dojo._fixIeBiDiScrollLeft(docBody.scrollLeft || 0) - offset.x;
evt.pageY = evt.clientY + (docBody.scrollTop || 0) - offset.y; if(evt.type == "mouseover"){
evt.relatedTarget = evt.fromElement;
} if(evt.type == "mouseout"){
evt.relatedTarget = evt.toElement;
}
evt.stopPropagation = del._stopPropagation;
evt.preventDefault = del._preventDefault; return del._fixKeys(evt);
},
_fixKeys: function(evt){ 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;
}elseif(c==13||c==27){
c=0; // Mozilla considers ENTER and ESC non-printable
}elseif(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;
del._setKeyChar(evt); break;
} return evt;
},
_stealthKeyDown: function(evt){ // IE doesn't fire keypress for most non-printable characters. // other browsers do, we simulate it here.
var kp = evt.currentTarget.onkeypress; // only works if kp exists and is a dispatcher if(!kp || !kp[listenersName]){ return; } // 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)&&(k<48||k>90)&&(k<96||k>111)&&(k<186||k>192)&&(k<219||k>222); // 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; // IE will post CTRL-BREAK, CTRL-ENTER as keypress natively
}elseif(c>95 && c<106){
c -= 48; // map CTRL-[numpad 0-9] to ASCII
}elseif((!evt.shiftKey)&&(c>=65&&c<=90)){
c += 32; // map CTRL-[A-Z] to lowercase
}else{
c = del._punctMap[c] || c; // map other problematic CTRL combinations to ASCII
}
} // simulate a keypress event
var faux = del._synthesizeEvent(evt, {type: 'keypress', faux: true, charCode: c});
kp.call(evt.currentTarget, faux);
evt.cancelBubble = faux.cancelBubble;
evt.returnValue = faux.returnValue;
_trySetKeyCode(evt, faux.keyCode);
}
}, // Called in Event scope
_stopPropagation: function(){
this.cancelBubble = true;
},
_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){_trySetKeyCode(this, 0);}
this.returnValue = false;
}
});
del._synthesizeEvent = function(evt, props){
var faux = dojo.mixin({}, evt, props);
del._setKeyChar(faux); // FIXME: would prefer to use dojo.hitch: dojo.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;
}
// Opera event normalization if(dojo.isOpera){
dojo.mixin(del, {
_fixEvent: function(evt, sender){ switch(evt.type){ case"keypress":
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<41)&&(!evt.shiftKey) ? 0 : c); if((evt.ctrlKey)&&(!evt.shiftKey)&&(c>=65)&&(c<=90)){ // lowercase CTRL-[A-Z] keys
c += 32;
} return del._synthesizeEvent(evt, { charCode: c });
} return evt;
}
});
}
dojo.mixin(del, {
add: function(/*DOMNode*/node, /*String*/event, /*Function*/fp){ if(!node){return;} // undefined
var handle = del._add(node, event, fp); if(del._normalizeEventName(event) == "keypress"){ // we need to listen to onkeydown to synthesize // keypress events that otherwise won't fire // in Safari 3.1+: https://lists.webkit.org/pipermail/webkit-dev/2007-December/002992.html
handle._stealthKeyDownHandle = del._add(node, "keydown", function(evt){ //A variation on the IE _stealthKeydown function //Synthesize an onkeypress event, but only for unprintable characters.
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)&&(k<48||k>90)&&(k<96||k>111)&&(k<186||k>192)&&(k<219||k>222); // 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; // IE will post CTRL-BREAK, CTRL-ENTER as keypress natively
}elseif(c>95 && c<106){
c -= 48; // map CTRL-[numpad 0-9] to ASCII
}elseif((!evt.shiftKey)&&(c>=65&&c<=90)){
c += 32; // map CTRL-[A-Z] to lowercase
}else{
c = del._punctMap[c] || c; // map other problematic CTRL combinations to ASCII
}
} // simulate a keypress event
var faux = del._synthesizeEvent(evt, {type: 'keypress', faux: true, charCode: c});
fp.call(evt.currentTarget, faux);
}
});
} return handle; /*Handle*/
},
if(dojo.isIE){ // keep this out of the closure // closing over 'iel' or 'ieh' b0rks leak prevention // ls[i] is an index into the master handler array
dojo._ieDispatcher = function(args, sender){
var ap=Array.prototype, h=dojo._ie_listener.handlers, c=args.callee, ls=c[dojo._ieListenersName], t=h[c.target]; // return value comes from original target function
var r = t && t.apply(sender, args); // make local copy of listener array so it's immutable during processing
var lls = [].concat(ls); // invoke listeners after target function for(var i in lls){ if(!(i in ap)){
h[lls[i]].apply(sender, args);
}
} return r;
}
dojo._getIeDispatcher = function(){ // ensure the returned function closes over nothing ("new Function" apparently doesn't close) returnnew Function(dojo._scopeName + "._ieDispatcher(arguments, this)"); // function
} // keep this out of the closure to reduce RAM allocation
dojo._event_listener._fixCallback = function(fp){
var f = dojo._event_listener._fixEvent; return function(e){ return fp.call(this, f(e, this)); };
}
}
}
if(!dojo._hasResource["dojo._base.html"]){ //_hasResource checks added by build. Do not use _hasResource directly in your code.
dojo._hasResource["dojo._base.html"] = true;
dojo.provide("dojo._base.html");
// FIXME: need to add unit tests for all the semi-public methods
// ============================= // DOM Functions // =============================
/*===== dojo.byId=function(id,doc){ // summary: // Returns DOM node with matching `id` attribute or `null` // if not found, similar to "$" function in another library. // 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.doc. Can be used to retrieve // node references from other documents.
=====*/ if(dojo.isIE || dojo.isOpera){
dojo.byId = function(id, doc){ if(dojo.isString(id)){
var _d = doc || dojo.doc;
var te = _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){ return te;
}else{
var eles = _d.all[id]; if(!eles || !eles.length){ return eles; } // if more than 1, choose first with the correct id
var i=0; while((te=eles[i++])){ if(te.attributes.id.value == id){ return te; }
}
}
}else{ return id; // DomNode
}
}
}else{
dojo.byId = function(id, doc){ return dojo.isString(id) ? (doc || dojo.doc).getElementById(id) : id; // DomNode
}
} /*===== }
=====*/
(function(){
var d = dojo;
var _destroyContainer = null;
dojo.addOnWindowUnload(function(){
_destroyContainer=null; //prevent IE leak
});
dojo._destroyElement = function(/*String||DomNode*/node){ // summary: // removes node from its parent, clobbers it and all of its // children. // node: // the element to be destroyed, either as an ID or a reference
node = d.byId(node);
try{ if(!_destroyContainer || _destroyContainer.ownerDocument != node.ownerDocument){
_destroyContainer = node.ownerDocument.createElement("div");
}
_destroyContainer.appendChild(node.parentNode ? node.parentNode.removeChild(node) : node); // NOTE: see http://trac.dojotoolkit.org/ticket/2931. This may be a bug and not a feature
_destroyContainer.innerHTML = "";
}catch(e){ /* squelch */
}
};
dojo.isDescendant = function(/*DomNode|String*/node, /*DomNode|String*/ancestor){ // summary: // Returns true if node is a descendant of ancestor // node: id or node reference to test // ancestor: id or node reference of potential parent to test against
try{
node = d.byId(node);
ancestor = d.byId(ancestor); while(node){ if(node === ancestor){ return true; // Boolean
}
node = node.parentNode;
}
}catch(e){ /* squelch, return false */ } returnfalse; // Boolean
};
dojo.setSelectable = function(/*DomNode|String*/node, /*Boolean*/selectable){ // summary: enable or disable selection on a node // node: // id or reference to node // selectable:
node = d.byId(node); if(d.isMozilla){
node.style.MozUserSelect = selectable ? "" : "none";
}elseif(d.isKhtml){
node.style.KhtmlUserSelect = selectable ? "auto" : "none";
}elseif(d.isIE){
var v = (node.unselectable = selectable ? "" : "on");
d.query("*", node).forEach("item.unselectable = '"+v+"'");
} //FIXME: else? Opera?
};
var _insertAfter = function(/*Node*/node, /*Node*/ref){ // summary: // Try to insert node after ref
var pn = ref.parentNode; if(ref == pn.lastChild){
pn.appendChild(node);
}else{ return _insertBefore(node, ref.nextSibling); // boolean
} return true; // boolean
}
dojo.place = function(/*String|DomNode*/node, /*String|DomNode*/refNode, /*String?|Number?*/position){ // summary: // Attempt to insert node into the DOM, choosing from various positioning options. // Returns true if successful, false otherwise. // node: // id or node reference to place relative to refNode // refNode: // id or node reference to use as basis for placement // position: // 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 // * first // * last // // "first" and "last" indicate positions as children of refNode. position defaults // to "last" if not specified
// 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)
dojo.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(d.isIE /*|| dojo.isOpera*/){
var _dcm = document.compatMode; // client code may have to adjust if compatMode varies across iframes
d.boxModel = _dcm == "BackCompat" || _dcm == "QuirksMode" || d.isIE<6 ? "border-box" : "content-box"; // FIXME: remove IE < 6 support?
}
// 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.
/*===== dojo.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.style() 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: // | dojo.getComputedStyle(dojo.byId('foo')).borderWidth; return;// CSS2Properties }
=====*/
// Although we normally eschew argument validation at this // level, here we test argument 'node' for (duck)type. // Argument node must also implement Element. (Note: we check // against HTMLElement rather than Element for interop with prototype.js) // Because 'document' is the 'parentNode' of 'body' // it is frequently sent to this function even // though it is not Element.
var gcs; if(d.isSafari){
gcs = function(/*DomNode*/node){
var s; if(node instanceof HTMLElement){
var dv = node.ownerDocument.defaultView;
s = dv.getComputedStyle(node, null); if(!s && node.style){
node.style.display = "";
s = dv.getComputedStyle(node, null);
}
} return s || {};
};
}elseif(d.isIE){
gcs = function(node){ // IE (as of 7) doesn't expose Element like sane browsers return node.nodeType == 1/* ELEMENT_NODE*/ ? node.currentStyle : {};
};
}else{
gcs = function(node){ return node instanceof HTMLElement ?
node.ownerDocument.defaultView.getComputedStyle(node, null) : {};
};
}
dojo.getComputedStyle = gcs;
if(!d.isIE){
dojo._toPixelValue = function(element, value){ // style values can be floats, client code may want // to round for integer pixels. return parseFloat(value) || 0;
};
}else{
dojo._toPixelValue = function(element, avalue){ if(!avalue){ return0; } // on IE7, medium is usually 4 pixels if(avalue=="medium"){ return4; } // 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); }
with(element){
var sLeft = style.left;
var rsLeft = runtimeStyle.left;
runtimeStyle.left = currentStyle.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
style.left = avalue;
avalue = style.pixelLeft;
}catch(e){
avalue = 0;
}
style.left = sLeft;
runtimeStyle.left = rsLeft;
} return avalue;
}
}
var px = d._toPixelValue;
// FIXME: there opacity quirks on FF that we haven't ported over. Hrm. /*===== dojo._getOpacity=function(node){ // summary: // Returns the current opacity of the passed node as a // floating-point value between 0 and 1. // node: DomNode // a reference to a DOM node. Does NOT support taking an // ID string for speed reasons. // returns: Number between 0 and 1 return;// Number }
=====*/
var astr = "DXImageTransform.Microsoft.Alpha";
var af = function(n, f){
try{ return n.filters.item(astr);
}catch(e){ return f ? {} : null;
}
}
/*===== dojo._setOpacity=function(node,opacity){ // summary: // set the opacity of the passed node portably. Returns the // new opacity of the node. // node: DOMNode // a reference to a DOM node. Does NOT support taking an // ID string for performance reasons. // opacity: Number // A Number between 0 and 1. 0 specifies transparent. // returns: Number between 0 and 1 return;// Number }
=====*/
dojo._setOpacity = d.isIE ? function(/*DomNode*/node, /*Number*/opacity){
var ov = opacity * 100;
node.style.zoom = 1.0;
// 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 = (opacity == 1 ? false : true);
var _pixelNamesCache = {
left: true, top: true
};
var _pixelRegExp = /margin|padding|width|height|max|min|offset/; // |border
var _toStyleValue = function(node, type, value){
type = type.toLowerCase(); // FIXME: should we really be doing string case conversion here? Should we cache it? Need to profile! if(d.isIE){ if(value == "auto"){ if(type == "height"){ return node.offsetHeight; } if(type == "width"){ return node.offsetWidth; }
} if(type == "fontweight"){ switch(value){ case700: return"bold"; case400: default: return"normal";
}
}
} if(!(type in _pixelNamesCache)){
_pixelNamesCache[type] = _pixelRegExp.test(type);
} return _pixelNamesCache[type] ? px(node, value) : value;
}
var _floatStyle = d.isIE ? "styleFloat" : "cssFloat";
var _floatAliases = { "cssFloat": _floatStyle, "styleFloat": _floatStyle, "float": _floatStyle };
// public API
dojo.style = function( /*DomNode|String*/ node, /*String?|Object?*/ style, /*String?*/ 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. // node: // id or reference to node to get/set style for // style: // 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: // If passed, sets value on the node for style, handling // cross-browser concerns. // 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": 300 // | }); // // 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" // | });
var n = d.byId(node), args = arguments.length, op = (style=="opacity");
style = _floatAliases[style] || style; if(args == 3){ return op ? d._setOpacity(n, value) : n.style[style] = value; /*Number*/
} if(args == 2 && op){ return d._getOpacity(n);
}
var s = gcs(n); if(args == 2 && !d.isString(style)){ for(var x in style){
d.style(node, x, style[x]);
} return s;
} return (args == 1) ? s : _toStyleValue(n, style, s[style]||n.style[style]); /* CSS2Properties||String||Number */
}
dojo._getPadExtents = function(/*DomNode*/n, /*Object*/computedStyle){ // summary: // Returns object with special values specifically useful for node // fitting. // // * l/t = left/top 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.
var
s = computedStyle||gcs(n),
l = px(n, s.paddingLeft),
t = px(n, s.paddingTop); return {
l: l,
t: t,
w: l+px(n, s.paddingRight),
h: t+px(n, s.paddingBottom)
};
}
dojo._getBorderExtents = function(/*DomNode*/n, /*Object*/computedStyle){ // summary: // returns an object with properties useful for noting the border // dimensions. // // * l/t = the sum of left/top 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.
var
ne = "none",
s = computedStyle||gcs(n),
bl = (s.borderLeftStyle != ne ? px(n, s.borderLeftWidth) : 0),
bt = (s.borderTopStyle != ne ? px(n, s.borderTopWidth) : 0); return {
l: bl,
t: bt,
w: bl + (s.borderRightStyle!=ne ? px(n, s.borderRightWidth) : 0),
h: bt + (s.borderBottomStyle!=ne ? px(n, s.borderBottomWidth) : 0)
};
}
dojo._getPadBorderExtents = function(/*DomNode*/n, /*Object*/computedStyle){ // summary: // returns object with properties useful for box fitting with // regards to padding. // // * l/t = the sum of left/top padding and left/top 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.
var
s = computedStyle||gcs(n),
p = d._getPadExtents(n, s),
b = d._getBorderExtents(n, s); return {
l: p.l + b.l,
t: p.t + b.t,
w: p.w + b.w,
h: p.h + b.h
};
}
dojo._getMarginExtents = function(n, 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.
var
s = computedStyle||gcs(n),
l = px(n, s.marginLeft),
t = px(n, s.marginTop),
r = px(n, s.marginRight),
b = px(n, s.marginBottom); if(d.isSafari && (s.position != "absolute")){ // FIXME: Safari's version of the computed right margin // is the space between our right edge and the right edge // of our offsetParent. // What we are looking for is the actual margin value as // determined by CSS. // Hack solution is to assume left/right margins are the same.
r = l;
} return {
l: l,
t: t,
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
dojo._getMarginBox = function(/*DomNode*/node, /*Object*/computedStyle){ // summary: // returns an object that encodes the width, height, left and top // positions of the node's margin box.
var s = computedStyle||gcs(node), me = d._getMarginExtents(node, s);
var l = node.offsetLeft - me.l, t = node.offsetTop - me.t, p = node.parentNode; if(d.isMoz){ // Mozilla: // If offsetParent has a computed overflow != visible, the offsetLeft is decreased // by the parent's border. // We don't want to compute the parent's style, so instead we examine node's // computed left/top which is more stable.
var sl = parseFloat(s.left), st = parseFloat(s.top); if(!isNaN(sl) && !isNaN(st)){
l = sl, t = st;
}else{ // If child's computed left/top are not parseable as a number (e.g. "auto"), we // have no choice but to examine the parent's computed style. if(p && p.style){
var pcs = gcs(p); if(pcs.overflow != "visible"){
var be = d._getBorderExtents(p, pcs);
l += be.l, t += be.t;
}
}
}
}elseif(d.isOpera){ // On Opera, offsetLeft includes the parent's border if(p){
var be = d._getBorderExtents(p);
l -= be.l;
t -= be.t;
}
} return {
l: l,
t: t,
w: node.offsetWidth + me.w,
h: node.offsetHeight + me.h
};
}
dojo._getContentBox = function(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.
// clientWidth/Height are important since the automatically account for scrollbars // fallback to offsetWidth/Height for special cases (see #3378)
var s=computedStyle||gcs(node), pe=d._getPadExtents(node, s), be=d._getBorderExtents(node, s), w=node.clientWidth, h; if(!w){
w=node.offsetWidth, h=node.offsetHeight;
}else{
h=node.clientHeight, be.w = be.h = 0;
} // On Opera, offsetLeft includes the parent's border if(d.isOpera){ pe.l += be.l; pe.t += be.t; }; return {
l: pe.l,
t: pe.t,
w: w - pe.w - be.w,
h: h - pe.h - be.h
};
}
// Box setters depend on box context because interpretation of width/height styles // vary wrt box context. // // The value of dojo.boxModel is used to determine box context. // dojo.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.
dojo._setBox = function(/*DomNode*/node, /*Number?*/l, /*Number?*/t, /*Number?*/w, /*Number?*/h, /*String?*/u){ // summary: // sets width/height/left/top in the current (native) box-model // dimentions. Uses the unit passed in u. // node: DOM Node reference. Id string not supported for performance reasons. // l: optional. left offset from parent. // t: optional. top offset from parent. // w: optional. width in current box model. // h: optional. width in current box model. // u: optional. 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; }
}
dojo._isButtonTag = function(/*DomNode*/node) { // summary: // True if the node is BUTTON or INPUT.type="button". return node.tagName == "BUTTON"
|| node.tagName=="INPUT" && node.getAttribute("type").toUpperCase() == "BUTTON"; // boolean
}
dojo._usesBorderBox = function(/*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.
var n = node.tagName; return d.boxModel=="border-box" || n=="TABLE" || dojo._isButtonTag(node); // boolean
}
dojo._setContentSize = function(/*DomNode*/node, /*Number*/widthPx, /*Number*/heightPx, /*Object*/computedStyle){ // summary: // Sets the size of the node's contents, irrespective of margins, // padding, or borders. if(d._usesBorderBox(node)){
var pb = d._getPadBorderExtents(node, computedStyle); if(widthPx >= 0){ widthPx += pb.w; } if(heightPx >= 0){ heightPx += pb.h; }
}
d._setBox(node, NaN, NaN, widthPx, heightPx);
}
dojo._setMarginBox = function(/*DomNode*/node, /*Number?*/leftPx, /*Number?*/topPx, /*Number?*/widthPx, /*Number?*/heightPx, /*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 dojo._setBox that handles box-model vagaries for // you.
var s = computedStyle||gcs(node); // 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.boxModel.
var bb=d._usesBorderBox(node),
pb=bb ? _nilExtents : d._getPadBorderExtents(node, s); if (dojo.isSafari) { // 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 (dojo._isButtonTag(node)){
var ns = node.style; if (widthPx>=0 && !ns.width) { ns.width = "4px"; } if (heightPx>=0 && !ns.height) { ns.height = "4px"; }
}
}
var mb=d._getMarginExtents(node, s); if(widthPx>=0){ widthPx = Math.max(widthPx - pb.w - mb.w, 0); } if(heightPx>=0){ heightPx = Math.max(heightPx - pb.h - mb.h, 0); }
d._setBox(node, leftPx, topPx, widthPx, heightPx);
}
var _nilExtents = { l:0, t:0, w:0, h:0 };
// public API
dojo.marginBox = function(/*DomNode|String*/node, /*Object?*/box){ // summary: // Getter/setter for the margin-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 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.
var n=d.byId(node), s=gcs(n), b=box; return !b ? d._getMarginBox(n, s) : d._setMarginBox(n, b.l, b.t, b.w, b.h, s); // Object
}
dojo.contentBox = function(/*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. // 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. All properties are optional if passed.
var n=d.byId(node), s=gcs(n), b=box; return !b ? d._getContentBox(n, s) : d._setContentSize(n, b.w, b.h, s); // Object
}
var _sumAncestorProperties = function(node, prop){ if(!(node = (node||0).parentNode)){return0};
var val, retVal = 0, _b = d.body(); while(node && node.style){ if(gcs(node).position == "fixed"){ return0;
}
val = node[prop]; if(val){
retVal += val - 0; // opera and khtml #body & #html has the same values, we only // need one value if(node == _b){ break; }
}
node = node.parentNode;
} return retVal; // integer
}
dojo._isBodyLtr = function(){ //FIXME: could check html and body tags directly instead of computed style? need to ignore case, accept empty values return !("_bodyLtr" in d) ?
d._bodyLtr = gcs(d.body()).direction == "ltr" :
d._bodyLtr; // Boolean
}
dojo._getIeDocumentElementOffset = function(){ // summary // The following values in IE contain an offset: // event.clientX // event.clientY // node.getBoundingClientRect().left // node.getBoundingClientRect().top // But other position related values do not contain this offset, such as // node.offsetLeft, node.offsetTop, node.style.left and node.style.top. // The offset is always (2, 2) in LTR direction. When the body is in RTL // direction, the offset counts the width of left scroll bar's width. // This function computes the actual offset.
//NOTE: assumes we're being called in an IE browser
var de = d.doc.documentElement; //FIXME: use this instead? var de = d.compatMode == "BackCompat" ? d.body : d.documentElement;
dojo._fixIeBiDiScrollLeft = function(/*Integer*/ scrollLeft){ // 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.
var dd = d.doc; if(d.isIE && !dojo._isBodyLtr()){
var de = dd.compatMode == "BackCompat" ? dd.body : dd.documentElement; return scrollLeft + de.clientWidth - de.scrollWidth; // Integer
} return scrollLeft; // Integer
}
dojo._abs = function(/*DomNode*/node, /*Boolean?*/includeScroll){ // summary: // Gets the position of the passed element relative to // the viewport (if includeScroll==false), or relative to the // document root (if includeScroll==true). // // Returns an object of the form: // { x: 100, y: 300 } // if includeScroll is passed, the x and y values will include any // document offsets that may affect the position relative to the // viewport.
// FIXME: need to decide in the brave-new-world if we're going to be // margin-box or border-box.
var ownerDocument = node.ownerDocument;
var ret = {
x: 0,
y: 0
};
// targetBoxType == "border-box"
var db = d.body(); if(d.isIE || (d.isFF >= 3)){
var client = node.getBoundingClientRect();
var cs; if(d.isFF){ // in FF3 you have to subract the document element margins
var dv = node.ownerDocument.defaultView;
cs=dv.getComputedStyle(db.parentNode, null);
}
var offset = (d.isIE) ? d._getIeDocumentElementOffset() : { x: px(db.parentNode,cs.marginLeft), y: px(db.parentNode,cs.marginTop)};
ret.x = client.left - offset.x;
ret.y = client.top - offset.y;
}else{ if(node["offsetParent"]){
var endNode; // in Safari, if the node is an absolutely positioned child of // the body and the body has a margin the offset of the child // and the body contain the body's margins, so we need to end // at the body // FIXME: getting contrary results to the above in latest WebKit. if(d.isSafari && //(node.style.getPropertyValue("position") == "absolute") &&
(gcs(node).position == "absolute") &&
(node.parentNode == db)){
endNode = db;
}else{
endNode = db.parentNode;
} // Opera seems to be double counting for some elements
var cs=gcs(node);
var n=node; if(d.isOpera&&cs.position!="absolute"){
n=n.offsetParent;
}
ret.x -= _sumAncestorProperties(n, "scrollLeft");
ret.y -= _sumAncestorProperties(n, "scrollTop");
var curnode = node; do{
var n = curnode.offsetLeft; //FIXME: ugly hack to workaround the submenu in //popupmenu2 does not shown up correctly in opera. //Someone have a better workaround? if(!d.isOpera || n > 0){
ret.x += isNaN(n) ? 0 : n;
}
var t = curnode.offsetTop;
ret.y += isNaN(t) ? 0 : t;
var cs = gcs(curnode); if(curnode != node){ if(d.isSafari){
ret.x += px(curnode, cs.borderLeftWidth);
ret.y += px(curnode, cs.borderTopWidth);
}elseif(d.isFF){ // tried left+right with differently sized left/right borders // it really is 2xleft border in FF, not left+right, even in RTL!
ret.x += 2*px(curnode,cs.borderLeftWidth);
ret.y += 2*px(curnode,cs.borderTopWidth);
}
} // static children in a static div in FF2 are affected by the div's border as well // but offsetParent will skip this div! if(d.isFF&&cs.position=="static"){
var parent=curnode.parentNode; while(parent!=curnode.offsetParent){
var pcs=gcs(parent); if(pcs.position=="static"){
ret.x += px(curnode,pcs.borderLeftWidth);
ret.y += px(curnode,pcs.borderTopWidth);
}
parent=parent.parentNode;
}
}
curnode = curnode.offsetParent;
}while((curnode != endNode) && curnode);
}elseif(node.x && node.y){
ret.x += isNaN(node.x) ? 0 : node.x;
ret.y += isNaN(node.y) ? 0 : node.y;
}
} // 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 = d._docScroll();
ret.y += scroll.y;
ret.x += scroll.x;
}
return ret; // object
}
// FIXME: need a setter for coords or a moveTo!!
dojo.coords = function(/*DomNode|String*/node, /*Boolean?*/includeScroll){ // summary: // Returns an object that measures margin box width/height and // absolute positioning data from dojo._abs(). // // description: // Returns an object that measures margin box width/height and // absolute positioning data from dojo._abs(). // 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._abs().
var n=d.byId(node), s=gcs(n), mb=d._getMarginBox(n, s);
var abs = d._abs(n, includeScroll);
mb.x = abs.x;
mb.y = abs.y; return mb;
}
// ============================= // Element attribute Functions // =============================
var ieLT8 = d.isIE < 8;
var _fixAttrName = function(/*String*/name){ switch(name.toLowerCase()){ case"tabindex": // Internet Explorer will only set or remove tabindex // if it is spelled "tabIndex" // return ieLT8 ? "tabIndex" : "tabindex"; case"for": case"htmlfor": // to pick up for attrib set in markup via getAttribute() IE<8 uses "htmlFor" and others use "for" // get/setAttribute works in all as long use same value for both get/set return ieLT8 ? "htmlFor" : "for"; case"class" : return d.isIE ? "className" : "class"; default: return name;
}
}
// non-deprecated HTML4 attributes with default values // http://www.w3.org/TR/html401/index/attributes.html // FF and Safari will return the default values if you // access the attributes via a property but not // via getAttribute()
var _attrProps = {
colspan: "colSpan",
enctype: "enctype",
frameborder: "frameborder",
method: "method",
rowspan: "rowSpan",
scrolling: "scrolling",
shape: "shape",
span: "span",
type: "type",
valuetype: "valueType"
}
dojo.hasAttr = function(/*DomNode|String*/node, /*String*/name){ // summary: // Returns true if the requested attribute is specified on the // given element, and false otherwise. // node: // id or reference to the element to check // name: // the name of the attribute // returns: // true if the requested attribute is specified on the // given element, and false otherwise
node = d.byId(node);
var fixName = _fixAttrName(name);
fixName = fixName == "htmlFor" ? "for" : fixName; //IE<8 uses htmlFor except in this case
var attr = node.getAttributeNode && node.getAttributeNode(fixName); return attr ? attr.specified : false; // Boolean
}
var _evtHdlrMap = {
}
var _ctr = 0;
var _attrId = dojo._scopeName + "attrid";
dojo.attr = function(/*DomNode|String*/node, /*String|Object*/name, /*String?*/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 argumnt is a // string, acts as a getter. // // If a third argument is passed, or if the second argumnt 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 attribute on // name: // the name of the attribute to get or set. // value: // 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 user as a setter, undefined // // 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" }); // | } // | });
var args = arguments.length; if(args == 2 && !d.isString(name)){ for(var x in name){ d.attr(node, x, name[x]); } return;
}
node = d.byId(node);
name = _fixAttrName(name); if(args == 3){ // FIXME: // what about when the name is "style" and value is an object? // It seems natural to pass it in to dojo.style(node, // value)...should we support this? if(d.isFunction(value)){ // clobber if we can
var attrId = d.attr(node, _attrId); if(!attrId){
attrId = _ctr++;
d.attr(node, _attrId, attrId);
} if(!_evtHdlrMap[attrId]){
_evtHdlrMap[attrId] = {};
}
var h = _evtHdlrMap[attrId][name]; if(h){
d.disconnect(h);
}else{
try{ delete node[name];
}catch(e){}
}
// ensure that event objects are normalized, etc.
_evtHdlrMap[attrId][name] = d.connect(node, name, value);
}elseif(
(typeof value == "boolean")|| // e.g. onsubmit, disabled
(name == "innerHTML")
){
node[name] = value;
}elseif((name == "style")&&(!d.isString(value))){
d.style(node, value);
}else{
node.setAttribute(name, value);
} return;
}else{ // should we access this attribute via a property or // via getAttribute()?
var prop = _attrProps[name.toLowerCase()]; if(prop){ return node[prop];
}else{
var attrValue = node[name]; return (typeof attrValue == 'boolean' || typeof attrValue == 'function') ? attrValue
: (d.hasAttr(node, name) ? node.getAttribute(name) : null);
}
}
}
dojo.removeAttr = function(/*DomNode|String*/node, /*String*/name){ // summary: // Removes an attribute from an HTML element. // node: // id or reference to the element to remove the attribute from // name: // the name of the attribute to remove
d.byId(node).removeAttribute(_fixAttrName(name));
}
/* dojo.createElement=function(type,attrs,parent,position){ // TODO: need to finish this! }
*/
// ============================= // (CSS) Class Functions // =============================
var _className = "className";
dojo.hasClass = function(/*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. return ((" "+ d.byId(node)[_className] +" ").indexOf(" "+ classStr +" ") >= 0); // Boolean
};
dojo.addClass = function(/*DomNode|String*/node, /*String*/classStr){ // summary: // Adds the specified classes to the end of the class list on the // passed node.
node = d.byId(node);
var cls = node[_className]; if((" "+ cls +" ").indexOf(" " + classStr + " ") < 0){
node[_className] = cls + (cls ? ' ' : '') + classStr;
}
};
dojo.toggleClass = function(/*DomNode|String*/node, /*String*/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. // condition: // If passed, true means to add the class, false means to remove. if(condition === undefined){
condition = !d.hasClass(node, classStr);
}
d[condition ? "addClass" : "removeClass"](node, classStr);
};
})();
}
if(!dojo._hasResource["dojo._base.NodeList"]){ //_hasResource checks added by build. Do not use _hasResource directly in your code.
dojo._hasResource["dojo._base.NodeList"] = true;
dojo.provide("dojo._base.NodeList");
(function(){
var d = dojo;
var tnl = function(arr){ // decorate an array to make it look like a NodeList
arr.constructor = dojo.NodeList;
dojo._mixin(arr, dojo.NodeList.prototype); return arr;
}
var _mapIntoDojo = function(func, alwaysThis){ // returns a function which, when executed in the scope of its caller, // applies the passed arguments to a particular dojo.* function (named // in func) and aggregates the returns. if alwaysThis is true, it // always returns the scope object and not the collected returns from // the Dojo method return function(){
var _a = arguments;
var aa = d._toArray(_a, 0, [null]);
var s = this.map(function(i){
aa[0] = i; return d[func].apply(d, aa);
}); return (alwaysThis || ( (_a.length > 1) || !d.isString(_a[0]) )) ? this : s; // String||dojo.NodeList
}
};
dojo.NodeList = function(){ // summary: // dojo.NodeList is as subclass of Array 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. // example: // create a node list from a node // | new dojo.NodeList(dojo.byId("foo"));
// 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: // http://developer.mozilla.org/en/docs/Core_JavaScript_1.5_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.
var a = d._toArray(arguments); return tnl(a.slice.apply(this, a));
},
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: // <http://developer.mozilla.org/en/docs/Core_JavaScript_1.5_Reference:Global_Objects:Array:splice> // 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 // returns: // dojo.NodeList
var a = d._toArray(arguments); return tnl(a.splice.apply(this, a));
},
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 dojo.NodeList and not a // raw Array. For more details, see: // <http://developer.mozilla.org/en/docs/Core_JavaScript_1.5_Reference:Global_Objects:Array:concat> // item: Object...? // Any number of optional parameters may be passed in to be // spliced into the NodeList // returns: // dojo.NodeList
var a = d._toArray(arguments, 0, [this]); return tnl(a.concat.apply([], a));
},
indexOf: function(/*Object*/ value, /*Integer?*/ fromIndex){ // summary: // see dojo.indexOf(). The primary difference is that the acted-on // array is implicitly this NodeList // value: // The value to search for. // fromIndex: // The loction to start searching from. Optional. Defaults to 0. // description: // For more details on the behavior of indexOf, see: // <http://developer.mozilla.org/en/docs/Core_JavaScript_1.5_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.lastIndexOf(). The primary difference is that the // acted-on array is implicitly this NodeList // description: // For more details on the behavior of lastIndexOf, see: // <http://developer.mozilla.org/en/docs/Core_JavaScript_1.5_Reference:Global_Objects:Array:lastIndexOf> // value: Object // The value to search for. // fromIndex: Integer? // The loction to start searching from. Optional. Defaults to 0. // returns: // Positive Integer or 0 for a match, -1 of not found. return d.lastIndexOf.apply(d, d._toArray(arguments, 0, [this])); // Integer
},
every: function(/*Function*/callback, /*Object?*/thisObject){ // summary: // see `dojo.every()` and: // <http://developer.mozilla.org/en/docs/Core_JavaScript_1.5_Reference:Global_Objects:Array:every> // Takes the same structure of arguments and returns as // dojo.every() with the caveat that the passed array is // implicitly this NodeList return d.every(this, callback, thisObject); // Boolean
},
some: function(/*Function*/callback, /*Object?*/thisObject){ // summary: // see dojo.some() and: // http://developer.mozilla.org/en/docs/Core_JavaScript_1.5_Reference:Global_Objects:Array:some // Takes the same structure of arguments and returns as // dojo.some() with the caveat that the passed array is // implicitly this NodeList return d.some(this, callback, thisObject); // Boolean
},
map: function(/*Function*/ func, /*Function?*/ obj){ // summary: // see dojo.map(). The primary difference is that the acted-on // array is implicitly this NodeList and the return is a // dojo.NodeList (a subclass of Array)
forEach: function(callback, thisObj){ // summary: // see dojo.forEach(). The primary difference is that the acted-on // array is implicitly this NodeList
coords: function(){ // summary: // Returns the box objects all elements in a node list as // an Array (*not* a NodeList)
return d.map(this, d.coords); // Array
},
/*===== attr:function(property,value){ // summary: // gets or sets the DOM attribute for every element in the // NodeList // 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 return;// dojo.NodeList return;// Array },
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:function(className){ // summary: // adds the specified class to every node in the list // className: String // the CSS class to add return;// dojo.NodeList },
removeClass:function(className){ // summary: // removes the specified class from every node in the list // className: String // the CSS class to add // returns: // dojo.NodeList, this list return;// dojo.NodeList },
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 },
connect:function(methodName,objOrFunc,funcName){ // summary: // attach event handlers to every item of the NodeList. Uses dojo.connect() // so event properties are normalized // 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 // | dojo.query("div:nth-child(odd)").connect("onclick", function(e){ // | // | }); // example: // attach foo.bar() to every odd div's onmouseover // | dojo.query("div:nth-child(odd)").connect("onmouseover", foo, "bar"); },
=====*/
attr: _mapIntoDojo("attr"),
style: _mapIntoDojo("style"),
addClass: _mapIntoDojo("addClass", true),
removeClass: _mapIntoDojo("removeClass", true),
toggleClass: _mapIntoDojo("toggleClass", true),
connect: _mapIntoDojo("connect", true),
// FIXME: connectPublisher()? connectRunOnce()?
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. // 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"||"end" (default) // * "first||"start" // * "before" // * "after" // or an offset in the childNodes property
var item = d.query(queryOrNode)[0]; return this.forEach(function(i){ d.place(i, item, position); }); // dojo.NodeList
},
orphan: function(/*String?*/ simpleFilter){ // summary: // removes elements in this list that match the simple // filter from their parents and returns them as a new // NodeList. // simpleFilter: // single-expression CSS filter // returns: // `dojo.NodeList` containing the orpahned elements return (simpleFilter ? d._filterQueryResult(this, simpleFilter) : this). // dojo.NodeList
forEach("if(item.parentNode){ item.parentNode.removeChild(item); }");
},
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"||"end" (default) // * "first||"start" // * "before" // * "after" // or an offset in the childNodes property
var item = this[0]; return d.query(queryOrListOrNode).forEach(function(ai){ // dojo.NodeList
d.place(ai, item, position || "last");
});
},
// FIXME: do we need this?
query: function(/*String*/ queryStr){ // summary: // Returns a new, flattened NodeList. Elements of the new list // satisfy the passed query but use elements of the // current NodeList as query roots.
if(!queryStr){ return this; }
// FIXME: probably slow // FIXME: use map?
var ret = d.NodeList();
this.forEach(function(item){ // FIXME: why would we ever get undefined here?
ret = ret.concat(d.query(queryStr, item).filter(function(subItem){ return (subItem !== undefined); }));
}); return ret; // dojo.NodeList
},
filter: function(/*String*/ simpleQuery){ // summary: // "masks" the built-in javascript filter() method to support // passing a simple string filter in addition to supporting // filtering function objects. // example: // "regular" JS filter syntax as exposed in dojo.filter: // | dojo.query("*").filter(function(item){ // | // highlight every paragraph // | return (item.nodeName == "p"); // | }).styles("backgroundColor", "yellow"); // example: // the same filtering using a CSS selector // | dojo.query("*").filter("p").styles("backgroundColor", "yellow");
var items = this;
var _a = arguments;
var r = d.NodeList();
var rp = function(t){ if(t !== undefined){
r.push(t);
}
} if(d.isString(simpleQuery)){
items = d._filterQueryResult(this, _a[0]); if(_a.length == 1){ // if we only got a string query, pass back the filtered results return items; // dojo.NodeList
} // if we got a callback, run it over the filtered items
_a.shift();
} // handle the (callback, [thisObject]) case
d.forEach(d.filter(items, _a[0], _a[1]), rp); return r; // 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*/ content, /*String||Integer?*/ position){ // summary: // add a node 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: // the HTML in string format to add at position to every item // position: // can be one of: // * "last"||"end" (default) // * "first||"start" // * "before" // * "after" // or an offset in the childNodes property // example: // appends content to the end if the position is ommitted // | dojo.query("h3 > p").addContent("hey there!"); // example: // add something to the front of each element that has a "thinger" property: // | dojo.query("[thinger]").addContent("...", "first"); // example: // adds a header before each element of the list // | dojo.query(".note").addContent("<h4>NOTE:</h4>", "before");
var ta = d.doc.createElement("span"); if(d.isString(content)){
ta.innerHTML = content;
}else{
ta.appendChild(content);
} if(position === undefined){
position = "last";
}
var ct = (position == "first" || position == "after") ? "lastChild" : "firstChild";
this.forEach(function(item){
var tn = ta.cloneNode(true); while(tn[ct]){
d.place(tn[ct], item, position);
}
}); return this; // dojo.NodeList
},
empty: function(){ // summary: // clears all content from each node in the list return this.forEach("item.innerHTML='';"); // dojo.NodeList
// FIXME: should we be checking for and/or disposing of widgets below these nodes?
},
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 //
var c = d.isFunction(declaredClass) ? declaredClass : d.getObject(declaredClass); return this.forEach(function(i){ new c(properties||{},i);
}) // 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. // returns: // dojo.NodeList
var nl = new dojo.NodeList();
dojo.forEach(arguments, function(i) { if(this[i]) { nl.push(this[i]); } }, this); return nl; // dojo.NodeList
}
});
// syntactic sugar for DOM events
d.forEach([ "blur", "focus", "click", "keydown", "keypress", "keyup", "mousedown", "mouseenter", "mouseleave", "mousemove", "mouseout", "mouseover", "mouseup", "submit", "load", "error"
], function(evt){
var _oe = "on"+evt;
d.NodeList.prototype[_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
if(!dojo._hasResource["dojo._base.query"]){//_hasResource checks added by build. Do not use _hasResource directly in your code. dojo._hasResource["dojo._base.query"]=true; dojo.provide("dojo._base.query");
;(function(){ // define everything in a closure for compressability reasons. "d" is an // alias to "dojo" since it's so frequently used. This seems a // transformation that the build system could perform on a per-file basis.
var d = dojo;
var childNodesName = dojo.isIE ? "children" : "childNodes";
var caseSensitive = false;
var getQueryParts = function(query){ // summary: state machine for query tokenization if(">~+".indexOf(query.charAt(query.length-1)) >= 0){
query += " *"
}
query += " "; // ensure that we terminate the state machine
var ts = function(s, e){ return d.trim(query.slice(s, e));
}
// the overall data graph of the full query, as represented by queryPart objects
var qparts = []; // state keeping vars
var inBrackets = -1;
var inParens = -1;
var inMatchFor = -1;
var inPseudo = -1;
var inClass = -1;
var inId = -1;
var inTag = -1;
var lc = ""; // the last character
var cc = ""; // the current character
var pStart; // iteration vars
var x = 0; // index in the query
var ql = query.length;
var currentPart = null; // data structure representing the entire clause
var _cp = null; // the current pseudo or attr matcher
// this array is a lookup used to generate an attribute matching function. // There is a similar lookup/generator list for the DOM branch with similar // calling semantics.
var xPathAttrs = { "*=": function(attr, value){ return"[contains(@"+attr+", '"+ value +"')]";
}, "^=": function(attr, value){ return"[starts-with(@"+attr+", '"+ value +"')]";
}, "$=": function(attr, value){ return"[substring(@"+attr+", string-length(@"+attr+")-"+(value.length-1)+")='"+value+"']";
}, "~=": function(attr, value){ return"[contains(concat(' ',@"+attr+",' '), ' "+ value +" ')]";
}, "|=": function(attr, value){ return"[contains(concat(' ',@"+attr+",' '), ' "+ value +"-')]";
}, "=": function(attr, value){ return"[@"+attr+"='"+ value +"']";
}
};
// takes a list of attribute searches, the overall query, a function to // generate a default matcher, and a closure-bound method for providing a // matching function that generates whatever type of yes/no distinguisher // the query method needs. The method is a bit tortured and hard to read // because it needs to be used in both the XPath and DOM branches.
var handleAttrs = function( attrList,
query,
getDefault,
handleMatch){
d.forEach(query.attrs, function(attr){
var matcher; // type, attr, matchFor if(attr.type && attrList[attr.type]){
matcher = attrList[attr.type](attr.attr, attr.matchFor);
}elseif(attr.attr.length){
matcher = getDefault(attr.attr);
} if(matcher){ handleMatch(matcher); }
});
}
var buildPath = function(query){
var xpath = ".";
var qparts = getQueryParts(d.trim(query)); while(qparts.length){
var tqp = qparts.shift();
var prefix;
var postfix = ""; if(tqp.oper == ">"){
prefix = "/"; // prefix = "/child::*";
tqp = qparts.shift();
}elseif(tqp.oper == "~"){
prefix = "/following-sibling::"; // get element following siblings
tqp = qparts.shift();
}elseif(tqp.oper == "+"){ // FIXME: // fails when selecting subsequent siblings by node type // because the position() checks the position in the list // of matching elements and not the localized siblings
prefix = "/following-sibling::";
postfix = "[position()=1]";
tqp = qparts.shift();
}else{
prefix = "//"; // prefix = "/descendant::*"
}
// get the tag name (if any)
xpath += prefix + tqp.tag + postfix;
// check to see if it's got an id. Needs to come first in xpath. if(tqp.id){
xpath += "[@id='"+tqp.id+"'][1]";
}
// FIXME: need to implement pseudo-class checks!!
}; return xpath;
};
var _xpathFuncCache = {};
var getXPathFunc = function(path){ if(_xpathFuncCache[path]){ return _xpathFuncCache[path];
}
var doc = d.doc; // don't need to memoize. The closure scope handles it for us.
var xpath = buildPath(path);
var tf = function(parent){ // XPath query strings are memoized.
var ret = [];
var xpathResult;
var tdoc = doc; if(parent){
tdoc = (parent.nodeType == 9) ? parent : parent.ownerDocument;
}
try{
xpathResult = tdoc.evaluate(xpath, parent, null, // XPathResult.UNORDERED_NODE_ITERATOR_TYPE, null);
XPathResult.ANY_TYPE, null);
}catch(e){
}
var result = xpathResult.iterateNext(); while(result){
ret.push(result);
result = xpathResult.iterateNext();
} return ret;
} return _xpathFuncCache[path] = tf;
};
/* d.xPathMatch=function(query){ // XPath based DOM query system. Handles a small subset of CSS // selectors, subset is identical to the non-XPath version of this // function.
returngetXPathFunc(query)(); }
*/
//////////////////////////////////////////////////////////////////////// // DOM query code ////////////////////////////////////////////////////////////////////////
var _filtersCache = {};
var _simpleFiltersCache = {};
// 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.
var agree = function(first, second){ if(!first){ return second; } if(!second){ return first; }
var _childElements = function(root){
var ret = [];
var te, x = 0, tret = root[childNodesName]; while((te = tret[x++])){ if(te.nodeType == 1){ ret.push(te); }
} return ret;
}
var _nextSiblings = function(root, single){
var ret = [];
var te = root; while(te = te.nextSibling){ if(te.nodeType == 1){
ret.push(te); if(single){ break; }
}
} return ret;
}
// FIXME: // we need to re-write the way "~" and "+" selectors are handled since // the left-hand selector simply modifies the right (which is the // actual search selector). We need to locate on search selector // instead of modifier to speed up these searches.
var _filterDown = function(element, queryParts, matchArr, idx){ // NOTE: // in the fast path! this function is called recursively and for // every run of a query.
var nidx = idx+1;
var isFinal = (queryParts.length == nidx);
var tqp = queryParts[idx];
// see if we can constrain our next level to direct children if(tqp.oper){ // find some eligable children to search
var ecn = (tqp.oper == ">") ?
_childElements(element) :
_nextSiblings(element, (tqp.oper == "+"));
// otherwise, keep going down, unless we'er at the end
var candidates = getElementsFunc(tqp)(element); if(isFinal){ while(candidates.length){
matchArr.push(candidates.shift());
} /* candidates.unshift(0,matchArr.length-1); matchArr.splice.apply(matchArr,candidates);
*/
}else{ // if we're not yet at the bottom, keep going! while(candidates.length){
_filterDown(candidates.shift(), queryParts, matchArr, nidx);
}
}
}
var filterDown = function(elements, queryParts){
var ret = [];
// for every root, get the elements that match the descendant selector // for(var x=elements.length-1, te; x>=0, te=elements[x]; x--){
var x = elements.length - 1, te; while((te = elements[x--])){
_filterDown(te, queryParts, ret, 0);
} return ret;
}
var getFilterFunc = function(q){ // note: query can't have spaces! if(_filtersCache[q.query]){ return _filtersCache[q.query];
}
var ff = null;
// does it have a tagName component? if(q.tag){ if(q.tag == "*"){
ff = agree(ff,
function(elem){ return (elem.nodeType == 1);
}
);
}else{ // tag name match
ff = agree(ff,
function(elem){ return (
(elem.nodeType == 1) &&
(q[ caseSensitive ? "otag" : "tag" ] == elem.tagName) // (q.tag == elem.tagName.toLowerCase())
); // return isTn;
}
);
}
}
// does the node have an ID? if(q.id){
ff = agree(ff,
function(elem){ return (
(elem.nodeType == 1) &&
(elem.id == q.id)
);
}
);
}
if(q.hasLoops){ // if we have other query param parts, make sure we add them to the // filter chain
ff = agree(ff, getSimpleFilterFunc(q));
}
return _filtersCache[q.query] = ff;
}
var getNodeIndex = function(node){ // NOTE: // we could have a more accurate caching mechanism by invalidating // caches after the query has finished, but I think that'd lead to // significantly more cache churn than the cache would provide // value for in the common case. Generally, we're more // conservative (and therefore, more accurate) than jQuery and // DomQuery WRT node node indexes, but there may be corner cases // in which we fall down. How much we care about them is TBD.
var pn = node.parentNode;
var pnc = pn.childNodes;
// check to see if we can trust the cache. If not, re-key the whole // thing and return our node match from that.
var nidx = -1;
var child = pn.firstChild; if(!child){ return nidx;
}
var ci = node["__cachedIndex"];
var cl = pn["__cachedLength"];
// only handle cache building if we've gone out of sync if(((typeof cl == "number")&&(cl != pnc.length))||(typeof ci != "number")){ // rip though the whole set, building cache indexes as we go
pn["__cachedLength"] = pnc.length;
var idx = 1; do{ // we only assign indexes for nodes with nodeType == 1, as per: // http://www.w3.org/TR/css3-selectors/#nth-child-pseudo // only elements are counted in the search order, and they // begin at 1 for the first child's index
if(child === node){
nidx = idx;
} if(child.nodeType == 1){
child["__cachedIndex"] = idx;
idx++;
}
child = child.nextSibling;
}while(child);
}else{ // NOTE: // could be incorrect in some cases (node swaps involving the // passed node, etc.), but we ignore those due to the relative // unlikelihood of that occuring
nidx = ci;
} return nidx;
}
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"
var tval = " "+value; return function(elem){
var ea = " "+_getAttr(elem, attr); return (ea.lastIndexOf(value)==(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 = " "+(elem.getAttribute(attr, 2) || ""); return (
(ea == value) ||
(ea.indexOf(valueDash)==0)
);
}
}, "=": function(attr, value){ return function(elem){ return (_getAttr(elem, attr) == value);
}
}
};
var pseudos = { "checked": function(name, condition){ return function(elem){ return !!d.attr(elem, "checked");
}
}, "first-child": function(name, condition){ return function(elem){ if(elem.nodeType != 1){ returnfalse; } // check to see if any of the previous siblings are elements
var fc = elem.previousSibling; while(fc && (fc.nodeType != 1)){
fc = fc.previousSibling;
} return (!fc);
}
}, "last-child": function(name, condition){ return function(elem){ if(elem.nodeType != 1){ returnfalse; } // check to see if any of the next siblings are elements
var nc = elem.nextSibling; while(nc && (nc.nodeType != 1)){
nc = nc.nextSibling;
} return (!nc);
}
}, "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)){ returnfalse; }
} return true;
}
}, "contains": function(name, condition){ return function(elem){ // FIXME: I dislike this version of "contains", as // whimsical attribute could set it off. An inner-text // based version might be more accurate, but since // jQuery and DomQuery also potentially get this wrong, // I'm leaving it for now. if(condition.charAt(0)=='"' || condition.charAt(0)=="'"){//remove quote
condition=condition.substr(1,condition.length-2);
} return (elem.innerHTML.indexOf(condition) >= 0);
}
}, "not": function(name, condition){
var ntf = getFilterFunc(getQueryParts(condition)[0]); return function(elem){ return (!ntf(elem));
}
}, "nth-child": function(name, condition){
var pi = parseInt; if(condition == "odd"){
condition = "2n+1";
}elseif(condition == "even"){
condition = "2n";
} 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));
}elseif(idx>0){ if(idx >= pred){
lb = idx - idx % pred;
}
idx = idx % pred;
}
}elseif(pred<0){
pred *= -1; if(idx>0){
ub = idx;
idx = idx % pred;
} //idx has to be greater than 0 when pred is negative; shall we throw an error here?
} if(pred>0){ return function(elem){
var i=getNodeIndex(elem); return (i>=lb) && (ub<0 || i<=ub) && ((i % pred) == idx);
}
}else{
condition=idx;
}
} //if(condition.indexOf("n") == -1){
var ncount = pi(condition); return function(elem){ return (getNodeIndex(elem) == ncount);
}
}
};
var fcHit = (_simpleFiltersCache[query.query]||_filtersCache[query.query]); if(fcHit){ return fcHit; }
var ff = null;
// the only case where we'll need the tag name is if we came from an ID query if(query.id){ // do we have an ID component? if(query.tag != "*"){
ff = agree(ff, function(elem){ return (elem.tagName == query[ caseSensitive ? "otag" : "tag" ]);
});
}
}
// if there's a class in our query, generate a match function for it
d.forEach(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 memozied in a cache, but it's VERY short
var re = new RegExp("(?:^|\\s)" + cname + (isWildcard ? ".*" : "") + "(?:\\s|$)");
ff = agree(ff, function(elem){ return re.test(elem.className);
});
ff.count = idx;
});
var retFunc; if(query.tag && query.id && !query.hasLoops){ // we got a filtered ID search (e.g., "h4#thinger")
retFunc = function(root){
var te = d.byId(query.id, (root.ownerDocument||root)); //root itself may be a document if(filterFunc(te)){ return [ te ];
}
}
}else{
var tret;
if(!query.hasLoops){ // it's just a plain-ol elements-by-tag-name query from the root
retFunc = function(root){
var ret = [];
var te, x=0, tret = root.getElementsByTagName(query[ caseSensitive ? "otag" : "tag"]); while((te = tret[x++])){
ret.push(te);
} return ret;
}
}else{
retFunc = function(root){
var ret = [];
var te, x = 0, tret = root.getElementsByTagName(query[ caseSensitive ? "otag" : "tag"]); while((te = tret[x++])){ if(filterFunc(te)){
ret.push(te);
}
} return ret;
}
}
} return _getElementsFuncCache[query.query] = retFunc;
}
var _partsCache = {};
//////////////////////////////////////////////////////////////////////// // the query runner ////////////////////////////////////////////////////////////////////////
// this is the second level of spliting, from full-length queries (e.g., // "div.foo .bar") into simple query expressions (e.g., ["div.foo", // ".bar"])
var _queryFuncCache = { "*": d.isIE ?
function(root){ return root.all;
} :
function(root){ return root.getElementsByTagName("*");
}, "~": _nextSiblings, "+": function(root){ return _nextSiblings(root, true); }, ">": _childElements
};
var getStepQueryFunc = function(query){ // if it's trivial, get a fast-path dispatcher
var qparts = getQueryParts(d.trim(query)); // if(query[query.length-1] == ">"){ query += " *"; } if(qparts.length == 1){
var tt = getElementsFunc(qparts[0]);
tt.nozip = true; // FIXME: is this right? Shouldn't this be wrapped in a closure to mark the return? return tt;
}
// otherwise, break it up and return a runner that iterates over the parts recursively
var sqf = function(root){
var localQueryParts = qparts.slice(0); // clone the src arr
var candidates; if(localQueryParts[0].oper == ">"){ // FIXME: what if it's + or ~?
candidates = [ root ]; // root = document;
}else{
candidates = getElementsFunc(localQueryParts.shift())(root);
} return filterDown(candidates, localQueryParts);
} return sqf;
}
// a specialized method that implements our primoridal "query optimizer". // This allows us to dispatch queries to the fastest subsystem we can get.
var _getQueryFunc = ( // NOTE: // XPath on the Webkit is slower than it's DOM iteration for most // test cases // FIXME: // we should try to capture some runtime speed data for each query // function to determine on the fly if we should stick w/ the // potentially optimized variant or if we should try something // new.
(document["evaluate"] && !d.isSafari) ?
function(query, root){ // has xpath support that's faster than DOM
var qparts = query.split(" "); // can we handle it? if( (!caseSensitive) && // not strictly necessaray, but simplifies lots of stuff
(document["evaluate"]) &&
(query.indexOf(":") == -1) &&
(query.indexOf("+") == -1) // skip direct sibling matches. See line ~344
){ // dojo.debug(query); // should we handle it?
// kind of a lame heuristic, but it works if( // a "div div div" style query
((qparts.length > 2)&&(query.indexOf(">") == -1))|| // or something else with moderate complexity. kinda janky
(qparts.length > 3)||
(query.indexOf("[")>=0)|| // or if it's a ".thinger" query
((1 == qparts.length)&&(0 <= query.indexOf(".")))
){ // use get and cache a xpath runner for this selector return getXPathFunc(query);
}
}
// fallthrough return getStepQueryFunc(query);
} : getStepQueryFunc
); // uncomment to disable XPath for testing and tuning the DOM path // _getQueryFunc = getStepQueryFunc;
// FIXME: we've got problems w/ the NodeList query()/filter() functions if we go XPath for everything
// uncomment to disable DOM queries for testing and tuning XPath // _getQueryFunc = getXPathFunc;
// this is the primary caching for full-query results. The query dispatcher // functions are generated here and then pickled for hash lookup in the // future
var getQueryFunc = function(query){ // return a cached version if one is available
var qcz = query.charAt(0); if(d.doc["querySelectorAll"] &&
( (!d.isSafari) || (d.isSafari > 3.1) ) && // see #5832 // as per CSS 3, we can't currently start w/ combinator: // http://www.w3.org/TR/css3-selectors/#w3cselgrammar
(">+~".indexOf(qcz) == -1)
){ return function(root){
var r = root.querySelectorAll(query);
r.nozip = true; // skip expensive duplication checks and just wrap in a NodeList return r;
};
} if(_queryFuncCache[query]){ return _queryFuncCache[query]; } if(0 > query.indexOf(",")){ // if it's not a compound query (e.g., ".foo, .bar"), cache and return a dispatcher return _queryFuncCache[query] = _getQueryFunc(query);
}else{ // if it's a complex query, break it up into it's constituent parts // and return a dispatcher that will merge the parts when run
// var parts = query.split(", ");
var parts = query.split(/\s*,\s*/);
var tf = function(root){
var pindex = 0; // avoid array alloc for every invocation
var ret = [];
var tp; while((tp = parts[pindex++])){
ret = ret.concat(_getQueryFunc(tp, tp.indexOf(" "))(root));
} return ret;
} // ...cache and return return _queryFuncCache[query] = tf;
}
}
// FIXME: // Dean's Base2 uses a system whereby queries themselves note if // they'll need duplicate filtering. We need to get on that plan!!
// attempt to efficiently determine if an item in a list is a dupe, // returning a list of "uniques", hopefully in doucment order
var _zipIdx = 0;
var _zip = function(arr){ if(arr && arr.nozip){ return d.NodeList._wrap(arr); }
var ret = new d.NodeList(); if(!arr){ return ret; } if(arr[0]){
ret.push(arr[0]);
} if(arr.length < 2){ return ret; }
_zipIdx++;
// we have to fork here for IE and XML docs because we can't set // expandos on their nodes (apparently). *sigh* if(d.isIE && caseSensitive){
var szidx = _zipIdx+"";
arr[0].setAttribute("_zipIdx", szidx); for(var x = 1, te; te = arr[x]; x++){ if(arr[x].getAttribute("_zipIdx") != szidx){
ret.push(te);
}
te.setAttribute("_zipIdx", szidx);
}
}else{
arr[0]["_zipIdx"] = _zipIdx; for(var x = 1, te; te = arr[x]; x++){ if(arr[x]["_zipIdx"] != _zipIdx){
ret.push(te);
}
te["_zipIdx"] = _zipIdx;
}
} // FIXME: should we consider stripping these properties? return ret;
}
// the main executor
d.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 instance of dojo.NodeList. // 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: // -------------------- // // dojo.query() 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 immediately preceeded-by sibling selector // * `+`, the preceeded-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` positional selectors // * `:empty` content emtpy selector // * `: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 // maniplation 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 resaonable for a programmatic node querying engine to // handle. Currently unsupported selectors include: // // * namespace-differentiated selectors of any form // * all `::` pseduo-element selectors
// * certain pseduo-selectors which don't get a lot of day-to-day use:
// | * `:root`, `:lang()`, `:target`, `:focus`
// * all visual and state selectors:
// | * `:root`, `:active`, `:hover`, `:visisted`, `:link`,
// `:enabled`, `:disabled`
// * `:*-of-type` pseudo selectors
//
// dojo.query and XML Documents:
// -----------------------------
//
// `dojo.query` currently only supports searching XML documents
// whose tags and attributes are 100% lower-case. This is a known
// limitation and will [be addressed soon](http://trac.dojotoolkit.org/ticket/3866)
// Non-selector Queries:
// ---------------------
//
// If something other than a String is passed for the query,
// `dojo.query` will return a new `dojo.NodeList` 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: dojo.NodeList
// An instance of `dojo.NodeList`. Many methods are available on
// NodeLists for searching, iterating, manipulating, and handling
// events on the matched nodes in the returned list.
// example:
// search the entire document for elements with the class "foo":
// | dojo.query(".foo");
// 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":
// | dojo.query(".foo.bar");
// 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:
// | dojo.query("p span.highlighted");
// 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:
// | dojo.query("#tabular_data > tbody > tr:nth-child(odd)").addClass("odd");
// example:
// remove all elements with the class "error" from the document
// and store them in a list:
// | var errors = dojo.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:
// | dojo.query("input[type='submit']").onclick(function(e){
// | dojo.stopEvent(e); // prevent sending the form
// | var btn = e.target;
// | dojo.xhrPost({
// | form: btn.form,
// | load: function(data){
// | // replace the form with the response
// | vardiv = dojo.doc.createElement("div");
// | dojo.place(div, btn.form, "after");
// | div.innerHTML = data;
// | dojo.style(btn.form, "display", "none");
// | }
// | });
// | });
// NOTE: elementsById is not currently supported
// NOTE: ignores xpath-ish queries for now
/*
// exposing this was a mistake
d.query.attrs = attrs;
*/
// exposing this because new pseudo matches are only executed through the
// DOM query path (never through the xpath optimizing branch)
d.query.pseudos = pseudos;
// one-off function for filtering a NodeList based on a simple selector
d._filterQueryResult = function(nodeList, simpleFilter){ var tnl = new d.NodeList(); var ff = (simpleFilter) ? getFilterFunc(getQueryParts(simpleFilter)[0]) : function(){ return true; };
for(var x = 0, te; te = nodeList[x]; x++){
if(ff(te)){ tnl.push(te); }
}
return tnl;
}
})();
}
if(!dojo._hasResource["dojo._base.xhr"]){ //_hasResource checks added by build. Do not use _hasResource directly in your code.
dojo._hasResource["dojo._base.xhr"] = true;
dojo.provide("dojo._base.xhr");
(function(){ var _d = dojo;
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. var val = obj[name];
if(_d.isString(val)){
obj[name] = [val, value];
}else if(_d.isArray(val)){
val.push(value);
}else{
obj[name] = value;
}
}
dojo.formToObject = function(/*DOMNode||String*/ formNode){
// summary:
// dojo.formToObject returns the values encoded in an HTMLform 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.
// description:
// 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 = {}; var exclude = "file|submit|image|reset|button|";
_d.forEach(dojo.byId(formNode).elements, function(item){ var _in = item.name; var type = (item.type||"").toLowerCase();
if(_in && type && exclude.indexOf(type) == -1 && !item.disabled){
if(type == "radio" || type == "checkbox"){
if(item.checked){ setValue(ret, _in, item.value); }
}else if(item.multiple){
ret[_in] = [];
_d.query("option", item).forEach(function(opt){
if(opt.selected){
setValue(ret, _in, opt.value);
}
});
}else{
setValue(ret, _in, item.value);
if(type == "image"){
ret[_in+".x"] = ret[_in+".y"] = ret[_in].x = ret[_in].y = 0;
}
}
}
});
return ret; // Object
}
dojo.objectToQuery = function(/*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; var pairs = []; var backstop = {};
for(var name in map){ var value = map[name];
if(value != backstop[name]){ var assign = enc(name) + "=";
if(_d.isArray(value)){
for(vari=0; i < value.length; i++){
pairs.push(assign + enc(value[i]));
}
}else{
pairs.push(assign + enc(value));
}
}
}
return pairs.join("&"); // String
}
dojo.formToQuery = function(/*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
return _d.objectToQuery(_d.formToObject(formNode)); // String
}
dojo.formToJson = function(/*DOMNode||String*/ formNode, /*Boolean?*/prettyPrint){
// summary:
// return a serialized JSON string from aform node or string
// ID identifying the form to serialize
return _d.toJson(_d.formToObject(formNode), prettyPrint); // String
}
dojo.queryToObject = function(/*String*/ str){
// summary:
// returns an object representing a de-serialized query section of a
// URL. Query keys with multiple values are returned in an array.
// description:
// 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.
// FIXME: should we grab the URL string if we're not passed one? var ret = {}; var qp = str.split("&"); var dec = decodeURIComponent;
_d.forEach(qp, function(item){
if(item.length){ var parts = item.split("="); var name = dec(parts.shift()); var val = dec(parts.join("="));
if(_d.isString(ret[name])){
ret[name] = [ret[name]];
}
if(_d.isArray(ret[name])){
ret[name].push(val);
}else{
ret[name] = val;
}
}
});
return ret; // Object
}
/*
from refactor.txt:
all bind() replacement APIs take the following argument structure:
{
url: "blah.html",
// all below are optional, but must be supported in some form by
// every IO API
timeout: 1000, // milliseconds
handleAs: "text", // replaces the always-wrong "mimetype"
content: {
key: "value"
},
// browser-specific, MAY be unsupported
sync: true, // defaults to false form: dojo.byId("someForm")
}
*/
// 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;
dojo._contentHandlers = { "text": function(xhr){ return xhr.responseText; }, "json": function(xhr){
return _d.fromJson(xhr.responseText || null);
}, "json-comment-filtered": function(xhr){
// NOTE: 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.
if(!dojo.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 _d.fromJson(value.substring(cStartIdx+2, cEndIdx));
}, "javascript": function(xhr){
// FIXME: try Moz and IE specific eval variants?
return _d.eval(xhr.responseText);
}, "xml": function(xhr){ var result = xhr.responseXML;
if(_d.isIE && (!result || result.documentElement == null)){
_d.forEach(["MSXML2", "Microsoft", "MSXML", "MSXML3"], function(prefix){
try{ var dom = new ActiveXObject(prefix + ".XMLDOM");
dom.async = false;
dom.loadXML(xhr.responseText);
result = dom;
}catch(e){ /* Not available. Squelch and try next one. */ }
});
}
return result; // DOMDocument
}
};
/*=====
dojo.__IoArgs = function(){
// 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 aform. 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).
// load: Function?
// function(response, ioArgs){} response is of type Object, ioArgs
// is of type dojo.__IoCallbackArgs. This function will be
// called on a successful HTTP response code.
// error: Function?
// function(response, ioArgs){} response is of type Object, ioArgs
// is of type dojo.__IoCallbackArgs. 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.isDebug 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.
// handle: Function?
// function(response, ioArgs){} response is of type Object, ioArgs
// is of type dojo.__IoCallbackArgs. This function will
// be called at the end of every request, whether or not an error occurs.
this.url = url;
this.content = content;
this.timeout = timeout;
this.form = form;
this.preventCache = preventCache;
this.handleAs = handleAs;
this.load = load;
this.error = error;
this.handle = handle;
}
=====*/
/*=====
dojo.__IoCallbackArgs = function(args, xhr, url, query, handleAs, id, canDelete, json){
// 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.
this.args = args;
this.xhr = xhr;
this.url = url;
this.query = query;
this.handleAs = handleAs;
this.id = id;
this.canDelete = canDelete;
this.json = json;
}
=====*/
dojo._ioSetArgs = function(/*dojo.__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 requestd. var formObject = null;
if(args.form){ varform = _d.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 : null);
formObject = _d.formToObject(form);
}
// set up the query params var miArgs = [{}];
if(formObject){
// potentially over-ride url-provided params w/ form values
miArgs.push(formObject);
}
if(args.content){
// stuff in content over-rides what's set by form
miArgs.push(args.content);
}
if(args.preventCache){
miArgs.push({"dojo.preventCache": new Date().valueOf()});
}
ioArgs.query = _d.objectToQuery(_d.mixin.apply(null, miArgs));
// .. and the real work of getting the deferred in order, etc.
ioArgs.handleAs = args.handleAs || "text"; var d = new _d.Deferred(canceller);
d.addCallbacks(okHandler, function(error){
return errHandler(error, d);
});
//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 && _d.isFunction(ld)){
d.addCallback(function(value){
return ld.call(args, value, ioArgs);
});
} var err = args.error;
if(err && _d.isFunction(err)){
d.addErrback(function(value){
return err.call(args, value, ioArgs);
});
} var handle = args.handle;
if(handle && _d.isFunction(handle)){
d.addBoth(function(value){
return handle.call(args, value, ioArgs);
});
}
d.ioArgs = ioArgs;
// FIXME: need to wire up the xhr object's abort method to something
// analagous in the Deferred
return d;
}
var _deferredCancel = function(/*Deferred*/dfd){
//summary: canceller function for dojo._ioSetArgs call.
dfd.canceled = true; var xhr = dfd.ioArgs.xhr; var _at = typeof xhr.abort;
if(_at == "function" || _at == "object" || _at == "unknown"){
xhr.abort();
} var err = dfd.ioArgs.error;
if(!err){
err = new Error("xhr cancelled");
err.dojoType="cancel";
}
return err;
} var _deferredOk = function(/*Deferred*/dfd){
//summary: okHandler function for dojo._ioSetArgs call.
var ret = _d._contentHandlers[dfd.ioArgs.handleAs](dfd.ioArgs.xhr);
return (typeof ret == "undefined") ? null : ret;
} var _deferError = function(/*Error*/error, /*Deferred*/dfd){
//summary: errHandler function for dojo._ioSetArgs call.
return error;
}
// avoid setting a timer per request. It degrades performance on IE
// something fierece if we don't use unified loops. var _inFlightIntvl = null; var _inFlight = []; var _watchInFlight = function(){
//summary:
// internal method that checks each inflight XMLHttpRequest to see
// if it has completed or if the timeout situation applies.
var now = (new Date()).getTime();
// make sure sync calls stay thread safe, if this callback is called
// during a sync call and this results in another sync call before the
// first sync call ends the browser hangs
if(!_d._blockAsync){
// we need manual loop because we often modify _inFlight (and therefore 'i') while iterating
// note: the second clause is an assigment on purpose, lint may complain
for(vari = 0, tif; i < _inFlight.length && (tif = _inFlight[i]); i++){ var dfd = tif.dfd; var func = function(){
if(!dfd || dfd.canceled || !tif.validCheck(dfd)){
_inFlight.splice(i--, 1);
}else if(tif.ioCheck(dfd)){
_inFlight.splice(i--, 1);
tif.resHandle(dfd);
}else if(dfd.startTime){
//did we timeout?
if(dfd.startTime + (dfd.ioArgs.args.timeout || 0) < now){
_inFlight.splice(i--, 1); var err = new Error("timeout exceeded");
err.dojoType = "timeout";
dfd.errback(err);
//Cancel the request so the io module can do appropriate cleanup.
dfd.cancel();
}
}
};
if(dojo.config.isDebug){
func.call(this);
}else{
try{
func.call(this);
}catch(e){
dfd.errback(e);
}
}
}
}
dojo._ioCancelAll = function(){
//summary: Cancels all pending IO requests, regardless of IO type
//(xhr, script, iframe).
try{
_d.forEach(_inFlight, function(i){
try{ i.dfd.cancel();
}catch(e){/*squelch*/}
});
}catch(e){/*squelch*/}
}
//Automatically call cancel all io calls on unload
//in IE for trac issue #2357.
if(_d.isIE){
_d.addOnWindowUnload(_d._ioCancelAll);
}
_d._ioWatch = function(/*Deferred*/dfd,
/*Function*/validCheck,
/*Function*/ioCheck,
/*Function*/resHandle){
//summary: watches the io request represented by dfd to see if it completes.
//dfd:
// The Deferred object to watch.
//validCheck:
// Function used to check if the IO request is still valid. Gets the dfd
// object as its only argument.
//ioCheck:
// Function used to check if basic IO call worked. Gets the dfd
// object as its only argument.
//resHandle:
// Function used to process response. Gets the dfd
// object as its only argument.
if(dfd.ioArgs.args.timeout){
dfd.startTime = (new Date()).getTime();
}
_inFlight.push({dfd: dfd, validCheck: validCheck, ioCheck: ioCheck, resHandle: resHandle});
if(!_inFlightIntvl){
_inFlightIntvl = setInterval(_watchInFlight, 50);
}
_watchInFlight(); // handle sync requests
}
var _defaultContentType = "application/x-www-form-urlencoded";
var _validCheck = function(/*Deferred*/dfd){
return dfd.ioArgs.xhr.readyState; //boolean
} var _ioCheck = function(/*Deferred*/dfd){
return 4 == dfd.ioArgs.xhr.readyState; //boolean
} var _resHandle = function(/*Deferred*/dfd){ var xhr = dfd.ioArgs.xhr;
if(_d._isDocumentOk(xhr)){
dfd.callback(dfd);
}else{ var err = new Error("Unable to load " + dfd.ioArgs.url + " status:" + xhr.status);
err.status = xhr.status;
err.responseText = xhr.responseText;
dfd.errback(err);
}
}
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.declare("dojo.__XhrArgs", dojo.__IoArgs, {
constructor: function(){
// 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
// 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.
this.handleAs = handleAs;
this.sync = sync;
this.headers = headers;
}
});
=====*/
dojo.xhr = function(/*String*/ method, /*dojo.__XhrArgs*/ args, /*Boolean?*/ hasBody){
// summary:
// Sends an HTTP request with the given method.
// 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.
//Make the Deferred object for this xhr request. var dfd = _d._ioSetArgs(args, _deferredCancel, _deferredOk, _deferError);
//Pass the args to _xhrObj, to allow xhr iframe proxy interceptions.
dfd.ioArgs.xhr = _d._xhrObj(dfd.ioArgs.args);
if(hasBody){
if("postData" in args){
dfd.ioArgs.query = args.postData;
}else if("putData" in args){
dfd.ioArgs.query = args.putData;
}
}else{
_d._ioAddQueryToUrl(dfd.ioArgs);
}
// IE 6 is a steaming pile. It won't let you call apply() on the native function (xhr.open).
// workaround for IE6's apply() "issues" var ioArgs = dfd.ioArgs; var xhr = ioArgs.xhr;
xhr.open(method, ioArgs.url, args.sync !== true, args.user || undefined, args.password || undefined);
if(args.headers){
for(var hdr in args.headers){
if(hdr.toLowerCase() === "content-type" && !args.contentType){
args.contentType = args.headers[hdr];
}else{
xhr.setRequestHeader(hdr, args.headers[hdr]);
}
}
}
// FIXME: is this appropriate for all content types?
xhr.setRequestHeader("Content-Type", args.contentType || _defaultContentType);
if(!args.headers || !args.headers["X-Requested-With"]){
xhr.setRequestHeader("X-Requested-With", "XMLHttpRequest");
}
// FIXME: set other headers here!
if(dojo.config.isDebug){
xhr.send(ioArgs.query);
}else{
try{
xhr.send(ioArgs.query);
}catch(e){
dfd.ioArgs.error = e;
dfd.cancel();
}
}
_d._ioWatch(dfd, _validCheck, _ioCheck, _resHandle);
xhr = null;
return dfd; // dojo.Deferred
}
dojo.xhrGet = function(/*dojo.__XhrArgs*/ args){
// summary:
// Sends an HTTP GET request to the server.
return _d.xhr("GET", args); // dojo.Deferred
}
dojo.rawXhrPost = dojo.xhrPost = function(/*dojo.__XhrArgs*/ args){
// summary:
// Sends an HTTP POST request to the server. In addtion 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 _d.xhr("POST", args, true); // dojo.Deferred
}
dojo.rawXhrPut = dojo.xhrPut = function(/*dojo.__XhrArgs*/ args){
// summary:
// Sends an HTTP PUT request to the server. In addtion 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 _d.xhr("PUT", args, true); // dojo.Deferred
}
dojo.xhrDelete = function(/*dojo.__XhrArgs*/ args){
// summary:
// Sends an HTTP DELETE request to the server.
return _d.xhr("DELETE", args); //dojo.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");
}
*/
})();
}
if(!dojo._hasResource["dojo._base.fx"]){ //_hasResource checks added by build. Do not use _hasResource directly in your code.
dojo._hasResource["dojo._base.fx"] = true;
dojo.provide("dojo._base.fx");
dojo._Line = function(/*int*/ start, /*int*/ end){
// summary:
// dojo._Line is the 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;
this.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
}
}
d.declare("dojo._Animation", null, {
// summary
// 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 dojo._Animation when one is
// returned.
constructor: function(/*Object*/ args){
d.mixin(this, args);
if(d.isArray(this.curve)){
/* curve: Array
pId: a */
this.curve = new d._Line(this.curve[0], this.curve[1]);
}
},
// duration: Integer
// The time in milliseonds the animation will take to run
duration: 350,
/*=====
// curve: dojo._Line||Array
// A two element array of start and end values, or a dojo._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 dojo._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: rate/1000 = fps)
rate: 10 /* 100 fps */,
/*=====
// delay: Integer
// The time in milliseconds to wait before starting animation after it has been .play()'ed
delay: null,
// events
//
// beforeBegin: Event
// Synthetic event fired before a dojo._Animation begins playing (synchronous)
beforeBegin: null,
// onBegin: Event
// Synthetic event fired as a dojo._Animation begins playing (useful?)
onBegin: null,
// onAnimate: Event
// Synthetic event fired at each interval of a dojo._Animation
onAnimate: null,
// onEnd: Event
// Synthetic event fired after the final frame of a dojo._Animation
onEnd: null,
// onPlay: Event
// Synthetic event fired any timea dojo._Animation is play()'ed
onPlay: null,
// onPause: Event
// Synthetic event fired when a dojo._Animation is paused
onPause: null,
// onStop: Event
// Synthetic event fires when a dojo._Animation is stopped
onStop: null,
=====*/
_percent: 0,
_startRepeatCount: 0,
_fire: function(/*Event*/ evt, /*Array?*/ args){
// summary:
// Convenience function. Fire event "evt" and pass it the
// arguments specified in "args".
// evt:
// The event to fire.
// args:
// The arguments to pass to the event.
if(this[evt]){
if(dojo.config.isDebug){
this[evt].apply(this, args||[]);
}else{
try{
this[evt].apply(this, args||[]);
}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; // dojo._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. var _t = this;
if(gotoStart){
_t._stopTimer();
_t._active = _t._paused = false;
_t._percent = 0;
}else if(_t._active && !_t._paused){
return _t; // dojo._Animation
}
_t._fire("beforeBegin");
var de = delay||_t.delay; var _p = dojo.hitch(_t, "_play", gotoStart);
if(de > 0){
setTimeout(_p, de);
return _t; // dojo._Animation
}
_p();
return _t;
},
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.
this._stopTimer();
this._active = this._paused = true;
this._percent = percent;
if(andPlay){ this.play(); }
return this; // dojo._Animation
},
var _makeFadeable = (d.isIE) ? 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 && d.style(node, "width") == "auto"){
ns.width = "auto";
}
} : function(){};
dojo._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)
var anim = d.animateProperty(fArgs);
d.connect(anim, "beforeBegin", d.partial(_makeFadeable, fArgs.node));
return anim; // dojo._Animation
}
/*=====
dojo.__FadeArgs = function(node, duration, easing){
// node: DOMNode|String
// The node referenced in the animation
// duration: Integer?
// Duration of the animation in milliseconds.
// easing: Function?
// An easing function.
this.node = node;
this.duration = duration;
this.easing = easing;
}
=====*/
dojo.fadeIn = function(/*dojo.__FadeArgs*/ args){
// summary:
// Returns an animation that will fade node defined in 'args' from
// its current opacity to fully opaque.
return d._fade(d.mixin({ end: 1 }, args)); // dojo._Animation
}
dojo.fadeOut = function(/*dojo.__FadeArgs*/ args){
// summary:
// Returns an animation that will fade node defined in 'args'
// from its current opacity to fully transparent.
return d._fade(d.mixin({ end: 0 }, args)); // dojo._Animation
}
dojo._defaultEasing = function(/*Decimal?*/ n){
// summary: The default easing function for dojo._Animation(s)
return 0.5 + ((Math.sin((n + 1.5) * Math.PI))/2);
}
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(varp in properties){ var prop = properties[p];
if(prop.start instanceof d.Color){
// create a reusable temp color object to keep intermediate results
prop.tempColor = new d.Color();
}
}
this.getValue = function(r){ var ret = {};
for(varp in this._properties){ var prop = this._properties[p]; var start = prop.start;
if(start instanceof d.Color){
ret[p] = d.blendColors(start, prop.end, r, prop.tempColor).toCss();
}else if(!d.isArray(start)){
ret[p] = ((prop.end - start) * r) + start + (p != "opacity" ? prop.units||"px" : "");
}
}
return ret;
}
}
/*=====
dojo.declare("dojo.__AnimArgs", [dojo.__FadeArgs], {
// Properties: Object?
// A hash map of style properties to Objects describing the transition,
// such as the properties of dojo._Line with an additional 'unit' property
properties: {}
//TODOC: add event callbacks
});
=====*/
dojo.animateProperty = function(/*dojo.__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:
// dojo.animateProperty is the foundation of most dojo.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.
// | dojo.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
//
// example:
// Animate width, height, and padding over 2 seconds... the
// pedantic way:
// | dojo.animateProperty({ node: node, duration:2000,
// | properties: {
// | width: { start: '200', end: '400', unit:"px" },
// | height: { start:'200', end: '400', unit:"px" },
// | paddingTop: { start:'5', end:'50', unit:"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.
// | dojo.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(){
// | // called when the animation finishes
// | }
// | }).play(500); // delay playing half a second
//
// example:
// Like all `dojo._Animation`s, animateProperty returns a handle to the
// Animation instance, which fires the events common to Dojo FX. Use `dojo.connect`
// to access these events outside of the Animation definiton:
// | var anim = dojo.animateProperty({
// | node:"someId",
// | properties:{
// | width:400, height:500
// | }
// | });
// | dojo.connect(anim,"onEnd", function(){
// |
// | });
// | // play the animation now:
// | anim.play();
var anim = new d._Animation(args);
d.connect(anim, "beforeBegin", anim, function(){ var pm = {};
for(varp 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];
prop = pm[p] = d.mixin({}, (d.isObject(prop) ? prop: { end: prop }));
if(d.isFunction(prop.start)){
prop.start = prop.start();
}
if(d.isFunction(prop.end)){
prop.end = prop.end();
} var isColor = (p.toLowerCase().indexOf("color") >= 0);
function getStyle(node, p){
// dojo.style(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 = d.style(node, p);
return (p=="opacity") ? Number(v) : (isColor ? v : parseFloat(v));
}
if(!("end" in prop)){
prop.end = getStyle(this.node, p);
}else if(!("start" in prop)){
prop.start = getStyle(this.node, p);
}
dojo.anim = function( /*DOMNode|String*/ node,
/*Object*/ properties,
/*Integer?*/ duration,
/*Function?*/ easing,
/*Function?*/ onEnd,
/*Integer?*/ delay){
// summary:
// A simpler interface to `dojo.animateProperty()`, also returns
// an instance of `dojo._Animation` but begins the animation
// immediately, unlike nearly every other Dojo animation API.
// description:
// `dojo.anim` is a simpler (but somewhat less powerful) version
// of `dojo.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 `dojo._Animation` object returned from `dojo.anim` will be
// already playing when it is returned from this function, 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 // | dojo.anim("id", { opacity: 0 }); // example: // Fade out a node over a full second // | dojo.anim("id", { opacity: 0 }, 1000); return d.animateProperty({
node: node,
duration: duration||d._Animation.prototype.duration,
properties: properties,
easing: easing,
onEnd: onEnd
}).play(delay||0);
}
})();
}
if(!dojo._hasResource["dojo._base.browser"]){ //_hasResource checks added by build. Do not use _hasResource directly in your code.
dojo._hasResource["dojo._base.browser"] = true;
dojo.provide("dojo._base.browser");
//Need this to be the last code segment in base, so do not place any //dojo.requireIf calls in this file. Otherwise, due to how the build system //puts all requireIf dependencies after the current file, the require calls //could be called before all of base is defined. if(dojo.config.require){
dojo.forEach(dojo.config.require, "dojo['require'](item);");
}
}
//INSERT dojo.i18n._preloadLocalizations HERE
if(dojo.config.afterOnLoad && dojo.isBrowser){ //Dojo is being added to the page after page load, so just trigger //the init sequence after a timeout. Using a timeout so the rest of this //script gets evaluated properly. This work needs to happen after the //dojo.config.require work done in dojo._base.
window.setTimeout(dojo._fakeLoadInit, 1000);
}
})();
Messung V0.5 in Prozent
¤ Die Informationen auf dieser Webseite wurden
nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit,
noch Qualität der bereit gestellten Informationen zugesichert.0.261Bemerkung:
(vorverarbeitet am 2026-08-26)
¤
Die Informationen auf dieser Webseite wurden
nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit,
noch Qualität der bereit gestellten Informationen zugesichert.
Bemerkung:
Die farbliche Syntaxdarstellung und die Messung sind noch experimentell.