/* Copyright (c) 2004-2010, The Dojo Foundation All Rights Reserved. Available via Academic Free License >= 2.1 OR the modified BSD license. see: http://dojotoolkit.org/license for details */ /* This is an optimized version of Dojo, built for deployment and not for development. To get sources and documentation, please visit: http://dojotoolkit.org */ ;(function(){ /* dojo, dijit, and dojox must always be the first three, and in that order. djConfig.scopeMap = [ ["dojo", "fojo"], ["dijit", "fijit"], ["dojox", "fojox"] ] */ /**Build will replace this comment with a scoped djConfig **/ //The null below can be relaced by a build-time value used instead of djConfig.scopeMap. var sMap = null; //See if new scopes need to be defined. if((sMap || (typeof djConfig != "undefined" && djConfig.scopeMap)) && (typeof window != "undefined")){ var scopeDef = "", scopePrefix = "", scopeSuffix = "", scopeMap = {}, scopeMapRev = {}; sMap = sMap || djConfig.scopeMap; for(var i = 0; i < sMap.length; i++){ //Make local variables, then global variables that use the locals. var newScope = sMap[i]; scopeDef += "var " + newScope[0] + " = {}; " + newScope[1] + " = " + newScope[0] + ";" + newScope[1] + "._scopeName = '" + newScope[1] + "';"; scopePrefix += (i == 0 ? "" : ",") + newScope[0]; scopeSuffix += (i == 0 ? "" : ",") + newScope[1]; scopeMap[newScope[0]] = newScope[1]; scopeMapRev[newScope[1]] = newScope[0]; } eval(scopeDef + "dojo._scopeArgs = [" + scopeSuffix + "];"); dojo._scopePrefixArgs = scopePrefix; dojo._scopePrefix = "(function(" + scopePrefix + "){"; dojo._scopeSuffix = "})(" + scopeSuffix + ")"; dojo._scopeMap = scopeMap; dojo._scopeMapRev = scopeMapRev; } /*===== // 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 // ` // // This type of syntax works with both xdomain and normal loaders, so it is good // practice to always use this idiom for on-the-fly code loading and in HTML script // blocks. If at some point you change loaders and where the code is loaded from, // it will all still work. // // More on how dojo.require // `dojo.require("A.B")` first checks to see if symbol A.B is // defined. If it is, it is simply returned (nothing to do). // // If it is not defined, it will look for `A/B.js` in the script root // directory. // // `dojo.require` throws an 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`, but note the caveats above about on-the-fly loading and // HTML script blocks when the xdomain loader is loading a module. // // `dojo.require()` does nothing about importing symbols into // the current namespace. It is presumed that the caller will // take care of that. For example, to import all symbols into a // local block, you might write: // // | with (dojo.require("A.B")) { // | ... // | } // // And to import just the leaf symbol to a local variable: // // | var B = dojo.require("A.B"); // | ... // returns: the required namespace object omitModuleCheck = d._global_omit_module_check || omitModuleCheck; //Check if it is already loaded. var module = d._loadedModules[moduleName]; if(module){ return module; } // convert periods to slashes var relpath = d._getModuleSymbols(moduleName).join("/") + '.js'; var modArg = !omitModuleCheck ? moduleName : null; var ok = d._loadPath(relpath, modArg); if(!ok && !omitModuleCheck){ throw new Error("Could not load '" + moduleName + "'; last tried '" + relpath + "'"); } // check that the symbol was defined // Don't bother if we're doing xdomain (asynchronous) loading. if(!omitModuleCheck && !d._isXDomain){ // pass in false so we can give better error module = d._loadedModules[moduleName]; if(!module){ throw new Error("symbol '" + moduleName + "' is not defined after loading '" + relpath + "'"); } } return module; } dojo.provide = function(/*String*/ resourceName){ // summary: // Register a resource with the package system. Works in conjunction with `dojo.require` // // description: // Each javascript source file is called a resource. When a // resource is loaded by the browser, `dojo.provide()` registers // that it has been loaded. // // Each javascript source file must have at least one // `dojo.provide()` call at the top of the file, corresponding to // the file name. For example, `js/dojo/foo.js` must have // `dojo.provide("dojo.foo");` before any calls to // `dojo.require()` are made. // // For backwards compatibility reasons, in addition to registering // the resource, `dojo.provide()` also ensures that the javascript // object for the module exists. For example, // `dojo.provide("dojox.data.FlickrStore")`, in addition to // registering that `FlickrStore.js` is a resource for the // `dojox.data` module, will ensure that the `dojox.data` // javascript object exists, so that calls like // `dojo.data.foo = function(){ ... }` don't fail. // // In the case of a build where multiple javascript source files // are combined into one bigger file (similar to a .lib or .jar // file), that file may contain multiple dojo.provide() calls, to // note that it includes multiple resources. // // resourceName: String // A dot-sperated string identifying a resource. // // example: // Safely create a `my` object, and make dojo.require("my.CustomModule") work // | dojo.provide("my.CustomModule"); //Make sure we have a string. resourceName = resourceName + ""; return (d._loadedModules[resourceName] = d.getObject(resourceName, true)); // Object } //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"] || []); for(var x=0; x // | 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. Using "nls" as a // a bundle name is not supported, since "nls" is the name of the folder // that holds bundles. Using "nls" as the bundle name will cause problems // with the custom build. // // 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 // | ... // d.require("dojo.i18n"); d.i18n._requireLocalization.apply(d.hostenv, arguments); }; var ore = new RegExp("^(([^:/?#]+):)?(//([^/?#]*))?([^?#]*)(\\?([^#]*))?(#(.*))?$"), 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, _a = arguments, 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]+""), uriobj = new d._Url(uri[0]+""); if( relobj.path == "" && !relobj.scheme && !relobj.authority && !relobj.query ){ if(relobj.fragment != n){ uriobj.fragment = relobj.fragment; } relobj = uriobj; }else if(!relobj.scheme){ relobj.scheme = uriobj.scheme; if(!relobj.authority){ relobj.authority = uriobj.authority; if(relobj.path.charAt(0) != "/"){ var path = uriobj.path.substring(0, uriobj.path.lastIndexOf("/") + 1) + relobj.path; var segs = path.split("/"); for(var j = 0; j < segs.length; j++){ if(segs[j] == "."){ // flatten "./" references if(j == segs.length - 1){ segs[j] = ""; }else{ segs.splice(j, 1); j--; } }else if(j > 0 && !(j == 1 && segs[0] == "") && segs[j] == ".." && segs[j-1] != ".."){ // flatten "../" references if(j == (segs.length - 1)){ segs.splice(j, 1); segs[j - 1] = ""; }else{ segs.splice(j - 1, 2); j -= 2; } } } relobj.path = segs.join("/"); } } } uri = []; if(relobj.scheme){ uri.push(relobj.scheme, ":"); } if(relobj.authority){ uri.push("//", relobj.authority); } uri.push(relobj.path); if(relobj.query){ uri.push("?", relobj.query); } if(relobj.fragment){ uri.push("#", relobj.fragment); } } this.uri = uri.join(""); // break the uri into its main components var r = this.uri.match(ore); this.scheme = r[2] || (r[1] ? "" : n); this.authority = r[4] || (r[3] ? "" : n); this.path = r[5]; // can never be undefined this.query = r[7] || (r[6] ? "" : n); this.fragment = r[9] || (r[8] ? "" : n); if(this.authority != n){ // server based naming authority r = this.authority.match(ire); this.user = r[3] || n; this.password = r[4] || n; this.host = r[6] || r[7]; // ipv6 || ipv4 this.port = r[9] || n; } } dojo._Url.prototype.toString = function(){ return this.uri; }; 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"); // | console.dir(pngPath); // 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){ return null; } 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; } return new d._Url(loc, url); // dojo._Url } })(); /*===== dojo.isBrowser = { // example: // | if(dojo.isBrowser){ ... } }; dojo.isFF = { // example: // | if(dojo.isFF > 1){ ... } }; 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 KHTML browser. undefined otherwise. Corresponds to major // detected version. isKhtml: 0, // isWebKit: Number | undefined // Version as a Number if client is a WebKit-derived browser (Konqueror, // Safari, Chrome, etc.). undefined otherwise. isWebKit: 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, // isChrome: Number | undefined // Version as a Number if client is Chrome browser. undefined otherwise. isChrome: 0 // isMac: Boolean // True if the client runs on Mac } =====*/ if(typeof window != 'undefined'){ dojo.isBrowser = true; dojo._name = "browser"; // 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, dav = n.appVersion, tv = parseFloat(dav); if(dua.indexOf("Opera") >= 0){ d.isOpera = tv; } if(dua.indexOf("AdobeAIR") >= 0){ d.isAIR = 1; } d.isKhtml = (dav.indexOf("Konqueror") >= 0) ? tv : 0; d.isWebKit = parseFloat(dua.split("WebKit/")[1]) || undefined; d.isChrome = parseFloat(dua.split("Chrome/")[1]) || undefined; d.isMac = dav.indexOf("Macintosh") >= 0; // 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 && !dojo.isChrome){ // try to grab the explicit Safari version first. If we don't get // one, look for less than 419.3 as the indication that we're on something // "Safari 2-ish". d.isSafari = parseFloat(dav.split("Version/")[1]); if(!d.isSafari || parseFloat(dav.substr(index + 7)) <= 419.3){ d.isSafari = 2; } } if(dua.indexOf("Gecko") >= 0 && !d.isKhtml && !d.isWebKit){ d.isMozilla = d.isMoz = tv; } if(d.isMoz){ //We really need to get away from this. Consider a sane isGecko approach for the future. d.isFF = parseFloat(dua.split("Firefox/")[1] || dua.split("Minefield/")[1]) || undefined; } if(document.all && !d.isOpera){ d.isIE = parseFloat(dav.split("MSIE ")[1]) || undefined; //In cases where the page has an HTTP header or META tag with //X-UA-Compatible, then it is in emulation mode. //Make sure isIE reflects the desired version. //document.documentMode of 5 means quirks mode. //Only switch the value if documentMode's major version //is different from isIE's major version. var mode = document.documentMode; if(mode && mode != 5 && Math.floor(d.isIE) != mode){ d.isIE = mode; } } //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; } d.isQuirks = document.compatMode == "BackCompat"; // 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, last_e; 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){ throw new Error("XMLHTTP not available: "+last_e); } return http; // XMLHTTPRequest instance } d._isDocumentOk = function(http){ var stat = http.status || 0, lp = location.protocol; return (stat >= 200 && stat < 300) || // Boolean stat == 304 || // allow any 2XX response code stat == 1223 || // get it out of the cache // Internet Explorer mangled the status code OR we're Titanium/browser chrome/chrome extension requesting a local file (!stat && (lp == "file:" || lp == "chrome:" || lp == "chrome-extension:" || lp == "app:") ); } //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) // NOTE: must be declared before scope switches ie. this._xhrObj() var http = d._xhrObj(); if(!hasBase && dojo._Url){ uri = (new dojo._Url(owloc, uri)).toString(); } 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,""); } http.open('GET', uri, false); try{ http.send(null); if(!d._isDocumentOk(http)){ var err = Error("Unable to load "+uri+" status:"+ http.status); err.status = http.status; err.responseText = http.responseText; throw err; } }catch(e){ if(fail_ok){ return null; } // null // rethrow the exception throw e; } return http.responseText; // String } 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 _a = _w.attachEvent || _w.addEventListener; evtName = _w.attachEvent ? evtName : evtName.substring(2); _a(evtName, function(){ fp.apply(_w, arguments); }, false); }; d._windowUnloaders = []; d.windowUnloaded = function(){ // summary: // signal fired by impending window destruction. You may use // dojo.addOnWindowUnload() to register a listener for this // event. NOTE: if you wish to dojo.connect() to this method // to perform page/application cleanup, be aware that this // event WILL NOT fire if no handler has been registered with // dojo.addOnWindowUnload. This behavior started in Dojo 1.3. // Previous versions always triggered dojo.windowUnloaded. See // dojo.addOnWindowUnload for more info. var mll = d._windowUnloaders; while(mll.length){ (mll.pop())(); } d = null; }; var _onWindowUnloadAttached = 0; d.addOnWindowUnload = function(/*Object?|Function?*/obj, /*String|Function?*/functionName){ // summary: // registers a function to be triggered when window.onunload // fires. // description: // The first time that addOnWindowUnload is called Dojo // will register a page listener to trigger your unload // handler with. Note that registering these handlers may // destory "fastback" page caching in browsers that support // it. Be careful trying to modify the DOM or access // JavaScript properties during this phase of page unloading: // they may not always be available. Consider // dojo.addOnUnload() if you need to modify the DOM or do // heavy JavaScript work since it fires at the eqivalent of // the page's "onbeforeunload" event. // example: // | dojo.addOnWindowUnload(functionPointer) // | dojo.addOnWindowUnload(object, "functionName"); // | dojo.addOnWindowUnload(object, function(){ /* ... */}); d._onto(d._windowUnloaders, obj, functionName); if(!_onWindowUnloadAttached){ _onWindowUnloadAttached = 1; _handleNodeEvent("onunload", d.windowUnloaded); } }; var _onUnloadAttached = 0; d.addOnUnload = function(/*Object?|Function?*/obj, /*String|Function?*/functionName){ // summary: // registers a function to be triggered when the page unloads. // description: // The first time that addOnUnload is called Dojo will // register a page listener to trigger your unload handler // with. // // In a browser enviroment, the functions will be triggered // during the window.onbeforeunload event. Be careful of doing // too much work in an unload handler. onbeforeunload can be // triggered if a link to download a file is clicked, or if // the link is a javascript: link. In these cases, the // onbeforeunload event fires, but the document is not // actually destroyed. So be careful about doing destructive // operations in a dojo.addOnUnload callback. // // Further note that calling dojo.addOnUnload will prevent // browsers from using a "fast back" cache to make page // loading via back button instantaneous. // example: // | dojo.addOnUnload(functionPointer) // | dojo.addOnUnload(object, "functionName") // | dojo.addOnUnload(object, function(){ /* ... */}); d._onto(d._unloaders, obj, functionName); if(!_onUnloadAttached){ _onUnloadAttached = 1; _handleNodeEvent("onbeforeunload", dojo.unloaded); } }; })(); //START DOMContentLoaded dojo._initFired = false; dojo._loadInit = function(e){ if(dojo._scrollIntervalId){ clearInterval(dojo._scrollIntervalId); dojo._scrollIntervalId = 0; } if(!dojo._initFired){ dojo._initFired = true; //Help out IE to avoid memory leak. if(!dojo.config.afterOnLoad && window.detachEvent){ window.detachEvent("onload", dojo._loadInit); } if(dojo._inFlightCount == 0){ dojo._modulesLoaded(); } } } if(!dojo.config.afterOnLoad){ if(document.addEventListener){ //Standards. Hooray! Assumption here that if standards based, //it knows about DOMContentLoaded. It is OK if it does not, the fall through //to window onload should be good enough. document.addEventListener("DOMContentLoaded", dojo._loadInit, false); window.addEventListener("load", dojo._loadInit, false); }else if(window.attachEvent){ window.attachEvent("onload", dojo._loadInit); //DOMContentLoaded approximation. Diego Perini found this MSDN article //that indicates doScroll is available after DOM ready, so do a setTimeout //to check when it is available. //http://msdn.microsoft.com/en-us/library/ms531426.aspx if(!dojo.config.skipIeDomLoaded && self === self.top){ dojo._scrollIntervalId = setInterval(function (){ try{ //When dojo is loaded into an iframe in an IE HTML Application //(HTA), such as in a selenium test, javascript in the iframe //can't see anything outside of it, so self===self.top is true, //but the iframe is not the top window and doScroll will be //available before document.body is set. Test document.body //before trying the doScroll trick if(document.body){ document.documentElement.doScroll("left"); dojo._loadInit(); } }catch (e){} }, 30); } } } if(dojo.isIE){ try{ (function(){ document.namespaces.add("v", "urn:schemas-microsoft-com:vml"); var vmlElems = ["*", "group", "roundrect", "oval", "shape", "rect", "imagedata", "path", "textpath", "text"], i = 0, l = 1, s = document.createStyleSheet(); if(dojo.isIE >= 8){ i = 1; l = vmlElems.length; } for(; i < l; ++i){ s.addRule("v\\:" + vmlElems[i], "behavior:url(#default#VML); display:inline-block"); } })(); }catch(e){} } //END DOMContentLoaded /* OpenAjax.subscribe("OpenAjax", "onload", function(){ if(dojo._inFlightCount == 0){ dojo._modulesLoaded(); } }); OpenAjax.subscribe("OpenAjax", "onunload", function(){ dojo.unloaded(); }); */ } //if (typeof window != 'undefined') //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.config.debugAtAllCosts){ dojo.config.useXDomain = true; dojo.require("dojo._base._loader.loader_xd"); dojo.require("dojo._base._loader.loader_debug"); dojo.require("dojo.i18n"); } 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"); (function(){ var d = dojo, opts = Object.prototype.toString; // Crockford (ish) functions dojo.isString = function(/*anything*/ it){ // summary: // Return true if it is a String return (typeof it == "string" || it instanceof String); // Boolean } dojo.isArray = function(/*anything*/ it){ // summary: // Return true if it is an Array. // Does not work on Arrays created in other windows. return it && (it instanceof Array || typeof it == "array"); // Boolean } dojo.isFunction = function(/*anything*/ it){ // summary: // Return true if it is a Function return opts.call(it) === "[object Function]"; }; 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" || d.isArray(it) || d.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 quacks like a duck, return `true` 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 && !d.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 2){ return d._hitchArgs.apply(d, arguments); // Function } if(!method){ method = scope; scope = null; } if(d.isString(method)){ scope = scope || d.global; if(!scope[method]){ throw(['dojo.hitch: scope["', method, '"] is null (scope="', scope, '")'].join('')); } return function(){ return scope[method].apply(scope, arguments || []); }; // Function } return !scope ? method : function(){ return method.apply(scope, arguments || []); }; // Function } /*===== 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.delegate = dojo._delegate = (function(){ // boodman/crockford delegation w/ cornford optimization function TMP(){} return function(obj, props){ TMP.prototype = obj; var tmp = new TMP(); TMP.prototype = null; if(props){ d._mixin(tmp, props); } return tmp; // Object } })(); /*===== 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. } =====*/ var efficient = function(obj, offset, startWith){ return (startWith||[]).concat(Array.prototype.slice.call(obj, offset||0)); }; var slow = function(obj, offset, startWith){ var arr = startWith||[]; for(var x = offset || 0; x < obj.length; x++){ arr.push(obj[x]); } return arr; }; dojo._toArray = d.isIE ? function(obj){ return ((obj.item) ? slow : efficient).apply(this, arguments); } : efficient; 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 d.hitch.apply(d, arr.concat(d._toArray(arguments))); // Function } var extraNames = d._extraNames, extraLen = extraNames.length, empty = {}; dojo.clone = function(/*anything*/ o){ // summary: // Clones objects (including DOM nodes) and all children. // Warning: do not clone cyclic structures. if(!o || typeof o != "object" || d.isFunction(o)){ // null, undefined, any non-object, or function return o; // anything } if(o.nodeType && "cloneNode" in o){ // DOM Node return o.cloneNode(true); // Node } if(o instanceof Date){ // Date return new Date(o.getTime()); // Date } var r, i, l, s, name; if(d.isArray(o)){ // array r = []; for(i = 0, l = o.length; i < l; ++i){ if(i in o){ r.push(d.clone(o[i])); } } // we don't clone functions for performance reasons // }else if(d.isFunction(o)){ // // function // r = function(){ return o.apply(this, arguments); }; }else{ // generic objects r = o.constructor ? new o.constructor() : {}; } for(name in o){ // the "tobj" condition avoid copying properties in "source" // inherited from Object.prototype. For example, if target has a custom // toString() method, don't overwrite it with the toString() method // that source inherited from Object.prototype s = o[name]; if(!(name in r) || (r[name] !== s && (!(name in empty) || empty[name] !== s))){ r[name] = d.clone(s); } } // IE doesn't recognize some custom functions in for..in if(extraLen){ for(i = 0; i < extraLen; ++i){ name = extraNames[i]; s = o[name]; if(!(name in r) || (r[name] !== s && (!(name in empty) || empty[name] !== s))){ r[name] = s; // functions only, we don't clone them } } } return r; // Object } /*===== dojo.trim = function(str){ // summary: // Trims whitespace from both sides of the string // str: String // String to be trimmed // returns: String // Returns the trimmed string // description: // This version of trim() was selected for inclusion into the base due // to its compact size and relatively good performance // (see [Steven Levithan's blog](http://blog.stevenlevithan.com/archives/faster-trim-javascript) // Uses String.prototype.trim instead, if available. // The fastest but longest version of this function is located at // dojo.string.trim() return ""; // String } =====*/ dojo.trim = String.prototype.trim ? function(str){ return str.trim(); } : function(str){ return str.replace(/^\s\s*/, '').replace(/\s\s*$/, ''); }; /*===== dojo.replace = function(tmpl, map, pattern){ // summary: // Performs parameterized substitutions on a string. Throws an // exception if any parameter is unmatched. // tmpl: String // String to be used as a template. // map: Object|Function // If an object, it is used as a dictionary to look up substitutions. // If a function, it is called for every substitution with following // parameters: a whole match, a name, an offset, and the whole template // string (see https://developer.mozilla.org/en/Core_JavaScript_1.5_Reference/Global_Objects/String/replace // for more details). // pattern: RegEx? // Optional regular expression objects that overrides the default pattern. // Must be global and match one item. The default is: /\{([^\}]+)\}/g, // which matches patterns like that: "{xxx}", where "xxx" is any sequence // of characters, which doesn't include "}". // returns: String // Returns the substituted string. // example: // | // uses a dictionary for substitutions: // | dojo.replace("Hello, {name.first} {name.last} AKA {nick}!", // | { // | nick: "Bob", // | name: { // | first: "Robert", // | middle: "X", // | last: "Cringely" // | } // | }); // | // returns: Hello, Robert Cringely AKA Bob! // example: // | // uses an array for substitutions: // | dojo.replace("Hello, {0} {2}!", // | ["Robert", "X", "Cringely"]); // | // returns: Hello, Robert Cringely! // example: // | // uses a function for substitutions: // | function sum(a){ // | var t = 0; // | dojo.forEach(a, function(x){ t += x; }); // | return t; // | } // | dojo.replace( // | "{count} payments averaging {avg} USD per payment.", // | dojo.hitch( // | { payments: [11, 16, 12] }, // | function(_, key){ // | switch(key){ // | case "count": return this.payments.length; // | case "min": return Math.min.apply(Math, this.payments); // | case "max": return Math.max.apply(Math, this.payments); // | case "sum": return sum(this.payments); // | case "avg": return sum(this.payments) / this.payments.length; // | } // | } // | ) // | ); // | // prints: 3 payments averaging 13 USD per payment. // example: // | // uses an alternative PHP-like pattern for substitutions: // | dojo.replace("Hello, ${0} ${2}!", // | ["Robert", "X", "Cringely"], /\$\{([^\}]+)\}/g); // | // returns: Hello, Robert Cringely! return ""; // String } =====*/ var _pattern = /\{([^\}]+)\}/g; dojo.replace = function(tmpl, map, pattern){ return tmpl.replace(pattern || _pattern, d.isFunction(map) ? map : function(_, k){ return d.getObject(k, false, map); }); }; })(); } 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 [ (typeof arr == "string") ? arr.split("") : arr, obj || dojo.global, // FIXME: cache the anonymous functions we create here? (typeof cb == "string") ? new Function("item", "index", "array", cb) : cb ]; }; var 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 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: // This method corresponds to the JavaScript 1.6 Array.lastIndexOf method, with one difference: when // run over sparse arrays, the Dojo function invokes the callback for every index whereas JavaScript // 1.6's lastIndexOf skips the holes in the sparse array. // For details on this method, see: // https://developer.mozilla.org/en/Core_JavaScript_1.5_Reference/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. // If you want to break out of the loop, consider using dojo.every() or dojo.some(). // forEach does not allow breaking out of the loop over the items in arr. // arr: // the array to iterate over. If a string, operates on individual characters. // callback: // a function is invoked with three arguments: item, index, and array // thisObject: // may be used to scope the call to callback // description: // This function corresponds to the JavaScript 1.6 Array.forEach() method, with one difference: when // run over sparse arrays, this implemenation passes the "holes" in the sparse array to // the callback function with a value of undefined. JavaScript 1.6's forEach skips the holes in the sparse array. // For more details, see: // https://developer.mozilla.org/en/Core_JavaScript_1.5_Reference/Objects/Array/forEach // example: // | // log out all members of the array: // | dojo.forEach( // | [ "thinger", "blah", "howdy", 10 ], // | function(item){ // | console.log(item); // | } // | ); // example: // | // log out the members and their indexes // | dojo.forEach( // | [ "thinger", "blah", "howdy", 10 ], // | function(item, idx, arr){ // | console.log(item, "at index:", idx); // | } // | ); // example: // | // use a scoped object member as the callback // | // | var obj = { // | prefix: "logged via obj.callback:", // | callback: function(item){ // | console.log(this.prefix, item); // | } // | }; // | // | // specifying the scope function executes the callback in that scope // | 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; i1; }); // example: // | // returns true // | dojo.every([1, 2, 3, 4], function(item){ return item>0; }); return 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, with one difference: when // run over sparse arrays, this implemenation passes the "holes" in the sparse array to // the callback function with a value of undefined. JavaScript 1.6's some skips the holes in the sparse array. // For more details, see: // https://developer.mozilla.org/en/Core_JavaScript_1.5_Reference/Objects/Array/some // example: // | // is true // | 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 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, with one difference: when // run over sparse arrays, this implemenation passes the "holes" in the sparse array to // the callback function with a value of undefined. JavaScript 1.6's map skips the holes in the sparse array. // For more details, see: // https://developer.mozilla.org/en/Core_JavaScript_1.5_Reference/Objects/Array/map // example: // | // returns [2, 3, 4, 5] // | 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; i1; }); var _p = _getParts(arr, thisObject, callback); arr = _p[0]; var outArr = []; for(var i=0,l=arr.length; i= 0; --j){ proto = lin[j].prototype; if(!proto.hasOwnProperty("declaredClass")){ proto.declaredClass = "uniqName_" + (counter++); } name = proto.declaredClass; if(!nameMap.hasOwnProperty(name)){ nameMap[name] = {count: 0, refs: [], cls: lin[j]}; ++clsCount; } rec = nameMap[name]; if(top && top !== rec){ rec.refs.push(top); ++top.count; } top = rec; } ++top.count; roots[0].refs.push(top); } // remove classes without external references recursively while(roots.length){ top = roots.pop(); result.push(top.cls); --clsCount; // optimization: follow a single-linked chain while(refs = top.refs, refs.length == 1){ top = refs[0]; if(!top || --top.count){ // branch or end of chain => do not end to roots top = 0; break; } result.push(top.cls); --clsCount; } if(top){ // branch for(i = 0, l = refs.length; i < l; ++i){ top = refs[i]; if(!--top.count){ roots.push(top); } } } } if(clsCount){ err("can't build consistent linearization"); } // calculate the superclass offset base = bases[0]; result[0] = base ? base._meta && base === result[result.length - base._meta.bases.length] ? base._meta.bases.length : 1 : 0; return result; } function inherited(args, a, f){ var name, chains, bases, caller, meta, base, proto, opf, pos, cache = this._inherited = this._inherited || {}; // crack arguments if(typeof args == "string"){ name = args; args = a; a = f; } f = 0; caller = args.callee; name = name || caller.nom; if(!name){ err("can't deduce a name to call inherited()"); } meta = this.constructor._meta; bases = meta.bases; pos = cache.p; if(name != cname){ // method if(cache.c !== caller){ // cache bust pos = 0; base = bases[0]; meta = base._meta; if(meta.hidden[name] !== caller){ // error detection chains = meta.chains; if(chains && typeof chains[name] == "string"){ err("calling chained method with inherited: " + name); } // find caller do{ meta = base._meta; proto = base.prototype; if(meta && (proto[name] === caller && proto.hasOwnProperty(name) || meta.hidden[name] === caller)){ break; } }while(base = bases[++pos]); // intentional assignment pos = base ? pos : -1; } } // find next base = bases[++pos]; if(base){ proto = base.prototype; if(base._meta && proto.hasOwnProperty(name)){ f = proto[name]; }else{ opf = op[name]; do{ proto = base.prototype; f = proto[name]; if(f && (base._meta ? proto.hasOwnProperty(name) : f !== opf)){ break; } }while(base = bases[++pos]); // intentional assignment } } f = base && f || op[name]; }else{ // constructor if(cache.c !== caller){ // cache bust pos = 0; meta = bases[0]._meta; if(meta && meta.ctor !== caller){ // error detection chains = meta.chains; if(!chains || chains.constructor !== "manual"){ err("calling chained constructor with inherited"); } // find caller while(base = bases[++pos]){ // intentional assignment meta = base._meta; if(meta && meta.ctor === caller){ break; } } pos = base ? pos : -1; } } // find next while(base = bases[++pos]){ // intentional assignment meta = base._meta; f = meta ? meta.ctor : base; if(f){ break; } } f = base && f; } // cache the found super method cache.c = f; cache.p = pos; // now we have the result if(f){ return a === true ? f : f.apply(this, a || args); } // intentionally if a super method was not found } function getInherited(name, args){ if(typeof name == "string"){ return this.inherited(name, args, true); } return this.inherited(name, true); } // emulation of "instanceof" function isInstanceOf(cls){ var bases = this.constructor._meta.bases; for(var i = 0, l = bases.length; i < l; ++i){ if(bases[i] === cls){ return true; } } return this instanceof cls; } function mixOwn(target, source){ var name, i = 0, l = d._extraNames.length; // add props adding metadata for incoming functions skipping a constructor for(name in source){ if(name != cname && source.hasOwnProperty(name)){ target[name] = source[name]; } } // process unenumerable methods on IE for(; i < l; ++i){ name = d._extraNames[i]; if(name != cname && source.hasOwnProperty(name)){ target[name] = source[name]; } } } // implementation of safe mixin function function safeMixin(target, source){ var name, t, i = 0, l = d._extraNames.length; // add props adding metadata for incoming functions skipping a constructor for(name in source){ t = source[name]; if((t !== op[name] || !(name in op)) && name != cname){ if(opts.call(t) == "[object Function]"){ // non-trivial function method => attach its name t.nom = name; } target[name] = t; } } // process unenumerable methods on IE for(; i < l; ++i){ name = d._extraNames[i]; t = source[name]; if((t !== op[name] || !(name in op)) && name != cname){ if(opts.call(t) == "[object Function]"){ // non-trivial function method => attach its name t.nom = name; } target[name] = t; } } return target; } function extend(source){ safeMixin(this.prototype, source); return this; } // chained constructor compatible with the legacy dojo.declare() function chainedConstructor(bases, ctorSpecial){ return function(){ var a = arguments, args = a, a0 = a[0], f, i, m, l = bases.length, preArgs; if(!(this instanceof a.callee)){ // not called via new, so force it return applyNew(a); } //this._inherited = {}; // perform the shaman's rituals of the original dojo.declare() // 1) call two types of the preamble if(ctorSpecial && (a0 && a0.preamble || this.preamble)){ // full blown ritual preArgs = new Array(bases.length); // prepare parameters preArgs[0] = a; for(i = 0;;){ // process the preamble of the 1st argument a0 = a[0]; if(a0){ f = a0.preamble; if(f){ a = f.apply(this, a) || a; } } // process the preamble of this class f = bases[i].prototype; f = f.hasOwnProperty("preamble") && f.preamble; if(f){ a = f.apply(this, a) || a; } // one peculiarity of the preamble: // it is called if it is not needed, // e.g., there is no constructor to call // let's watch for the last constructor // (see ticket #9795) if(++i == l){ break; } preArgs[i] = a; } } // 2) call all non-trivial constructors using prepared arguments for(i = l - 1; i >= 0; --i){ f = bases[i]; m = f._meta; f = m ? m.ctor : f; if(f){ f.apply(this, preArgs ? preArgs[i] : a); } } // 3) continue the original ritual: call the postscript f = this.postscript; if(f){ f.apply(this, args); } }; } // chained constructor compatible with the legacy dojo.declare() function singleConstructor(ctor, ctorSpecial){ return function(){ var a = arguments, t = a, a0 = a[0], f; if(!(this instanceof a.callee)){ // not called via new, so force it return applyNew(a); } //this._inherited = {}; // perform the shaman's rituals of the original dojo.declare() // 1) call two types of the preamble if(ctorSpecial){ // full blown ritual if(a0){ // process the preamble of the 1st argument f = a0.preamble; if(f){ t = f.apply(this, t) || t; } } f = this.preamble; if(f){ // process the preamble of this class f.apply(this, t); // one peculiarity of the preamble: // it is called even if it is not needed, // e.g., there is no constructor to call // let's watch for the last constructor // (see ticket #9795) } } // 2) call a constructor if(ctor){ ctor.apply(this, a); } // 3) continue the original ritual: call the postscript f = this.postscript; if(f){ f.apply(this, a); } }; } // plain vanilla constructor (can use inherited() to call its base constructor) function simpleConstructor(bases){ return function(){ var a = arguments, i = 0, f, m; if(!(this instanceof a.callee)){ // not called via new, so force it return applyNew(a); } //this._inherited = {}; // perform the shaman's rituals of the original dojo.declare() // 1) do not call the preamble // 2) call the top constructor (it can use this.inherited()) for(; f = bases[i]; ++i){ // intentional assignment m = f._meta; f = m ? m.ctor : f; if(f){ f.apply(this, a); break; } } // 3) call the postscript f = this.postscript; if(f){ f.apply(this, a); } }; } function chain(name, bases, reversed){ return function(){ var b, m, f, i = 0, step = 1; if(reversed){ i = bases.length - 1; step = -1; } for(; b = bases[i]; i += step){ // intentional assignment m = b._meta; f = (m ? m.hidden : b.prototype)[name]; if(f){ f.apply(this, arguments); } } }; } // forceNew(ctor) // return a new object that inherits from ctor.prototype but // without actually running ctor on the object. function forceNew(ctor){ // create object with correct prototype using a do-nothing // constructor xtor.prototype = ctor.prototype; var t = new xtor; xtor.prototype = null; // clean up return t; } // applyNew(args) // just like 'new ctor()' except that the constructor and its arguments come // from args, which must be an array or an arguments object function applyNew(args){ // create an object with ctor's prototype but without // calling ctor on it. var ctor = args.callee, t = forceNew(ctor); // execute the real constructor on the new object ctor.apply(t, args); return t; } d.declare = function(className, superclass, props){ // crack parameters if(typeof className != "string"){ props = superclass; superclass = className; className = ""; } props = props || {}; var proto, i, t, ctor, name, bases, chains, mixins = 1, parents = superclass; // build a prototype if(opts.call(superclass) == "[object Array]"){ // C3 MRO bases = c3mro(superclass); t = bases[0]; mixins = bases.length - t; superclass = bases[mixins]; }else{ bases = [0]; if(superclass){ if(opts.call(superclass) == "[object Function]"){ t = superclass._meta; bases = bases.concat(t ? t.bases : superclass); }else{ err("base class is not a callable constructor."); } }else if(superclass !== null){ err("unknown base class. Did you use dojo.require to pull it in?") } } if(superclass){ for(i = mixins - 1;; --i){ proto = forceNew(superclass); if(!i){ // stop if nothing to add (the last base) break; } // mix in properties t = bases[i]; (t._meta ? mixOwn : mix)(proto, t.prototype); // chain in new constructor ctor = new Function; ctor.superclass = superclass; ctor.prototype = proto; superclass = proto.constructor = ctor; } }else{ proto = {}; } // add all properties safeMixin(proto, props); // add constructor t = props.constructor; if(t !== op.constructor){ t.nom = cname; proto.constructor = t; } // collect chains and flags for(i = mixins - 1; i; --i){ // intentional assignment t = bases[i]._meta; if(t && t.chains){ chains = mix(chains || {}, t.chains); } } if(proto["-chains-"]){ chains = mix(chains || {}, proto["-chains-"]); } // build ctor t = !chains || !chains.hasOwnProperty(cname); bases[0] = ctor = (chains && chains.constructor === "manual") ? simpleConstructor(bases) : (bases.length == 1 ? singleConstructor(props.constructor, t) : chainedConstructor(bases, t)); // add meta information to the constructor ctor._meta = {bases: bases, hidden: props, chains: chains, parents: parents, ctor: props.constructor}; ctor.superclass = superclass && superclass.prototype; ctor.extend = extend; ctor.prototype = proto; proto.constructor = ctor; // add "standard" methods to the prototype proto.getInherited = getInherited; proto.inherited = inherited; proto.isInstanceOf = isInstanceOf; // add name if specified if(className){ proto.declaredClass = className; d.setObject(className, ctor); } // build chains and add them to the prototype if(chains){ for(name in chains){ if(proto[name] && typeof chains[name] == "string" && name != cname){ t = proto[name] = chain(name, bases, chains[name] === "after"); t.nom = name; } } } // chained methods do not return values // no need to chain "invisible" functions return ctor; // Function }; d.safeMixin = safeMixin; /*===== dojo.declare = function(className, superclass, props){ // summary: // Create a feature-rich constructor from compact notation. // className: String?: // The optional name of the constructor (loosely, a "class") // stored in the "declaredClass" property in the created prototype. // It will be used as a global name for a created constructor. // superclass: Function|Function[]: // May be null, a Function, or an Array of Functions. This argument // specifies a list of bases (the left-most one is the most deepest // base). // props: Object: // An object whose properties are copied to the created prototype. // Add an instance-initialization function by making it a property // named "constructor". // returns: // New constructor function. // description: // Create a constructor using a compact notation for inheritance and // prototype extension. // // Mixin ancestors provide a type of multiple inheritance. // Prototypes of mixin ancestors are copied to the new class: // changes to mixin prototypes will not affect classes to which // they have been mixed in. // // Ancestors can be compound classes created by this version of // dojo.declare. In complex cases all base classes are going to be // linearized according to C3 MRO algorithm // (see http://www.python.org/download/releases/2.3/mro/ for more // details). // // "className" is cached in "declaredClass" property of the new class, // if it was supplied. The immediate super class will be cached in // "superclass" property of the new class. // // Methods in "props" will be copied and modified: "nom" property // (the declared name of the method) will be added to all copied // functions to help identify them for the internal machinery. Be // very careful, while reusing methods: if you use the same // function under different names, it can produce errors in some // cases. // // It is possible to use constructors created "manually" (without // dojo.declare) as bases. They will be called as usual during the // creation of an instance, their methods will be chained, and even // called by "this.inherited()". // // Special property "-chains-" governs how to chain methods. It is // a dictionary, which uses method names as keys, and hint strings // as values. If a hint string is "after", this method will be // called after methods of its base classes. If a hint string is // "before", this method will be called before methods of its base // classes. // // If "constructor" is not mentioned in "-chains-" property, it will // be chained using the legacy mode: using "after" chaining, // calling preamble() method before each constructor, if available, // and calling postscript() after all constructors were executed. // If the hint is "after", it is chained as a regular method, but // postscript() will be called after the chain of constructors. // "constructor" cannot be chained "before", but it allows // a special hint string: "manual", which means that constructors // are not going to be chained in any way, and programmer will call // them manually using this.inherited(). In the latter case // postscript() will be called after the construction. // // All chaining hints are "inherited" from base classes and // potentially can be overridden. Be very careful when overriding // hints! Make sure that all chained methods can work in a proposed // manner of chaining. // // Once a method was chained, it is impossible to unchain it. The // only exception is "constructor". You don't need to define a // method in order to supply a chaining hint. // // If a method is chained, it cannot use this.inherited() because // all other methods in the hierarchy will be called automatically. // // Usually constructors and initializers of any kind are chained // using "after" and destructors of any kind are chained as // "before". Note that chaining assumes that chained methods do not // return any value: any returned value will be discarded. // // example: // | 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(); // | } // | }); // // example: // | var MyBase = dojo.declare(null, { // | // constructor, properties, and methods go here // | // ... // | }); // | var MyClass1 = dojo.declare(MyBase, { // | // constructor, properties, and methods go here // | // ... // | }); // | var MyClass2 = dojo.declare(MyBase, { // | // constructor, properties, and methods go here // | // ... // | }); // | var MyDiamond = dojo.declare([MyClass1, MyClass2], { // | // constructor, properties, and methods go here // | // ... // | }); // // example: // | var F = function(){ console.log("raw constructor"); }; // | F.prototype.method = function(){ // | console.log("raw method"); // | }; // | var A = dojo.declare(F, { // | constructor: function(){ // | console.log("A.constructor"); // | }, // | method: function(){ // | console.log("before calling F.method..."); // | this.inherited(arguments); // | console.log("...back in A"); // | } // | }); // | new A().method(); // | // will print: // | // raw constructor // | // A.constructor // | // before calling F.method... // | // raw method // | // ...back in A // // example: // | var A = dojo.declare(null, { // | "-chains-": { // | destroy: "before" // | } // | }); // | var B = dojo.declare(A, { // | constructor: function(){ // | console.log("B.constructor"); // | }, // | destroy: function(){ // | console.log("B.destroy"); // | } // | }); // | var C = dojo.declare(B, { // | constructor: function(){ // | console.log("C.constructor"); // | }, // | destroy: function(){ // | console.log("C.destroy"); // | } // | }); // | new C().destroy(); // | // prints: // | // B.constructor // | // C.constructor // | // C.destroy // | // B.destroy // // example: // | var A = dojo.declare(null, { // | "-chains-": { // | constructor: "manual" // | } // | }); // | var B = dojo.declare(A, { // | constructor: function(){ // | // ... // | // call the base constructor with new parameters // | this.inherited(arguments, [1, 2, 3]); // | // ... // | } // | }); // // example: // | var A = dojo.declare(null, { // | "-chains-": { // | m1: "before" // | }, // | m1: function(){ // | console.log("A.m1"); // | }, // | m2: function(){ // | console.log("A.m2"); // | } // | }); // | var B = dojo.declare(A, { // | "-chains-": { // | m2: "after" // | }, // | m1: function(){ // | console.log("B.m1"); // | }, // | m2: function(){ // | console.log("B.m2"); // | } // | }); // | var x = new B(); // | x.m1(); // | // prints: // | // B.m1 // | // A.m1 // | x.m2(); // | // prints: // | // A.m2 // | // B.m2 return new Function(); // Function }; =====*/ /*===== dojo.safeMixin = function(target, source){ // summary: // Mix in properties skipping a constructor and decorating functions // like it is done by dojo.declare. // target: Object // Target object to accept new properties. // source: Object // Source object for new properties. // description: // This function is used to mix in properties like dojo._mixin does, // but it skips a constructor property and decorates functions like // dojo.declare does. // // It is meant to be used with classes and objects produced with // dojo.declare. Functions mixed in with dojo.safeMixin can use // this.inherited() like normal methods. // // This function is used to implement extend() method of a constructor // produced with dojo.declare(). // // example: // | var A = dojo.declare(null, { // | m1: function(){ // | console.log("A.m1"); // | }, // | m2: function(){ // | console.log("A.m2"); // | } // | }); // | var B = dojo.declare(A, { // | m1: function(){ // | this.inherited(arguments); // | console.log("B.m1"); // | } // | }); // | B.extend({ // | m2: function(){ // | this.inherited(arguments); // | console.log("B.m2"); // | } // | }); // | var x = new B(); // | dojo.safeMixin(x, { // | m1: function(){ // | this.inherited(arguments); // | console.log("X.m1"); // | }, // | m2: function(){ // | this.inherited(arguments); // | console.log("X.m2"); // | } // | }); // | x.m2(); // | // prints: // | // A.m1 // | // B.m1 // | // X.m1 }; =====*/ /*===== Object.inherited = function(name, args, newArgs){ // summary: // Calls a super method. // name: String? // The optional method name. Should be the same as the caller's // name. Usually "name" is specified in complex dynamic cases, when // the calling method was dynamically added, undecorated by // dojo.declare, and it cannot be determined. // args: Arguments // The caller supply this argument, which should be the original // "arguments". // newArgs: Object? // If "true", the found function will be returned without // executing it. // If Array, it will be used to call a super method. Otherwise // "args" will be used. // returns: // Whatever is returned by a super method, or a super method itself, // if "true" was specified as newArgs. // description: // This method is used inside method of classes produced with // dojo.declare to call a super method (next in the chain). It is // used for manually controlled chaining. Consider using the regular // chaining, because it is faster. Use "this.inherited()" only in // complex cases. // // This method cannot me called from automatically chained // constructors including the case of a special (legacy) // constructor chaining. It cannot be called from chained methods. // // If "this.inherited()" cannot find the next-in-chain method, it // does nothing and returns "undefined". The last method in chain // can be a default method implemented in Object, which will be // called last. // // If "name" is specified, it is assumed that the method that // received "args" is the parent method for this call. It is looked // up in the chain list and if it is found the next-in-chain method // is called. If it is not found, the first-in-chain method is // called. // // If "name" is not specified, it will be derived from the calling // method (using a methoid property "nom"). // // example: // | var B = dojo.declare(A, { // | method1: function(a, b, c){ // | this.inherited(arguments); // | }, // | method2: function(a, b){ // | return this.inherited(arguments, [a + b]); // | } // | }); // | // next method is not in the chain list because it is added // | // manually after the class was created. // | B.prototype.method3 = function(){ // | console.log("This is a dynamically-added method."); // | this.inherited("method3", arguments); // | }; // example: // | var B = dojo.declare(A, { // | method: function(a, b){ // | var super = this.inherited(arguments, true); // | // ... // | if(!super){ // | console.log("there is no super method"); // | return 0; // | } // | return super.apply(this, arguments); // | } // | }); return {}; // Object } =====*/ /*===== Object.getInherited = function(name, args){ // summary: // Returns a super method. // name: String? // The optional method name. Should be the same as the caller's // name. Usually "name" is specified in complex dynamic cases, when // the calling method was dynamically added, undecorated by // dojo.declare, and it cannot be determined. // args: Arguments // The caller supply this argument, which should be the original // "arguments". // returns: // Returns a super method (Function) or "undefined". // description: // This method is a convenience method for "this.inherited()". // It uses the same algorithm but instead of executing a super // method, it returns it, or "undefined" if not found. // // example: // | var B = dojo.declare(A, { // | method: function(a, b){ // | var super = this.getInherited(arguments); // | // ... // | if(!super){ // | console.log("there is no super method"); // | return 0; // | } // | return super.apply(this, arguments); // | } // | }); return {}; // Object } =====*/ /*===== Object.isInstanceOf = function(cls){ // summary: // Checks the inheritance chain to see if it is inherited from this // class. // cls: Function // Class constructor. // returns: // "true", if this object is inherited from this class, "false" // otherwise. // description: // This method is used with instances of classes produced with // dojo.declare to determine of they support a certain interface or // not. It models "instanceof" operator. // // example: // | var A = dojo.declare(null, { // | // constructor, properties, and methods go here // | // ... // | }); // | var B = dojo.declare(null, { // | // constructor, properties, and methods go here // | // ... // | }); // | var C = dojo.declare([A, B], { // | // constructor, properties, and methods go here // | // ... // | }); // | var D = dojo.declare(A, { // | // constructor, properties, and methods go here // | // ... // | }); // | // | var a = new A(), b = new B(), c = new C(), d = new D(); // | // | console.log(a.isInstanceOf(A)); // true // | console.log(b.isInstanceOf(A)); // false // | console.log(c.isInstanceOf(A)); // true // | console.log(d.isInstanceOf(A)); // true // | // | console.log(a.isInstanceOf(B)); // false // | console.log(b.isInstanceOf(B)); // true // | console.log(c.isInstanceOf(B)); // true // | console.log(d.isInstanceOf(B)); // false // | // | console.log(a.isInstanceOf(C)); // false // | console.log(b.isInstanceOf(C)); // false // | console.log(c.isInstanceOf(C)); // true // | console.log(d.isInstanceOf(C)); // false // | // | console.log(a.isInstanceOf(D)); // false // | console.log(b.isInstanceOf(D)); // false // | console.log(c.isInstanceOf(D)); // false // | console.log(d.isInstanceOf(D)); // true return {}; // Object } =====*/ /*===== Object.extend = function(source){ // summary: // Adds all properties and methods of source to constructor's // prototype, making them available to all instances created with // constructor. This method is specific to constructors created with // dojo.declare. // source: Object // Source object which properties are going to be copied to the // constructor's prototype. // description: // Adds source properties to the constructor's prototype. It can // override existing properties. // // This method is similar to dojo.extend function, but it is specific // to constructors produced by dojo.declare. It is implemented // using dojo.safeMixin, and it skips a constructor property, // and properly decorates copied functions. // // example: // | var A = dojo.declare(null, { // | m1: function(){}, // | s1: "Popokatepetl" // | }); // | A.extend({ // | m1: function(){}, // | m2: function(){}, // | f1: true, // | d1: 42 // | }); }; =====*/ })(); } 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 i, lls; lls = [].concat(ls); // invoke listeners after target function for(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: // `dojo.connect` is the core event handling and delegation method in // Dojo. It allows one function to "listen in" on the execution of // any other, triggering the second whenever the first is called. Many // listeners may be attached to a function, and source functions may // be either regular function calls or DOM events. // // description: // Connects listeners to actions, so that after event fires, a // listener is called with the same arguments passed to the original // function. // // Since `dojo.connect` allows the source of events to be either a // "regular" JavaScript function or a DOM event, it provides a uniform // interface for listening to all the types of events that an // application is likely to deal with though a single, unified // interface. DOM programmers may want to think of it as // "addEventListener for everything and anything". // // When setting up a connection, the `event` parameter must be a // string that is the name of the method/event to be listened for. If // `obj` is null, `dojo.global` is assumed, meaning that connections // to global methods are supported but also that you may inadvertently // connect to a global by passing an incorrect object name or invalid // reference. // // `dojo.connect` generally is forgiving. If you pass the name of a // function or method that does not yet exist on `obj`, connect will // not fail, but will instead set up a stub method. Similarly, null // arguments may simply be omitted such that fewer than 4 arguments // may be required to set up a connection See the examples for details. // // The return value is a handle that is needed to // remove this connection with `dojo.disconnect`. // // obj: // 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 omitted 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; i44 // var returnDeferred = progressCallback == mutator ? this : new dojo.Deferred(promise.cancel); var listener = { resolved: resolvedCallback, error: errorCallback, progress: progressCallback, deferred: returnDeferred }; if(nextListener){ head = head.next = listener; } else{ nextListener = head = listener; } if(finished){ notify(); } return returnDeferred.promise; }; var deferred = this; this.cancel = promise.cancel = function () { // summary: // Cancels the asynchronous operation if(!finished){ var error = canceller && canceller(deferred); if(!finished){ if (!(error instanceof Error)) { error = new Error(error); } error.log = false; deferred.reject(error); } } } freeze(promise); }; dojo.extend(dojo.Deferred, { addCallback: function (/*Function*/callback) { return this.addCallbacks(dojo.hitch.apply(dojo, arguments)); }, addErrback: function (/*Function*/errback) { return this.addCallbacks(null, dojo.hitch.apply(dojo, arguments)); }, addBoth: function (/*Function*/callback) { var enclosed = dojo.hitch.apply(dojo, arguments); return this.addCallbacks(enclosed, enclosed); }, fired: -1 }); })(); dojo.when = function(promiseOrValue, /*Function?*/callback, /*Function?*/errback, /*Function?*/progressHandler){ // summary: // This provides normalization between normal synchronous values and // asynchronous promises, so you can interact with them in a common way // example: // | function printFirstAndList(items){ // | dojo.when(findFirst(items), console.log); // | dojo.when(findLast(items), console.log); // | } // | function findFirst(items){ // | return dojo.when(items, function(items){ // | return items[0]; // | }); // | } // | function findLast(items){ // | return dojo.when(items, function(items){ // | return items[items.length]; // | }); // | } // And now all three of his functions can be used sync or async. // | printFirstAndLast([1,2,3,4]) will work just as well as // | printFirstAndLast(dojo.xhrGet(...)); if(promiseOrValue && typeof promiseOrValue.then === "function"){ return promiseOrValue.then(callback, errback, progressHandler); } return callback(promiseOrValue); }; } 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. // description: // Throws for invalid JSON strings, but it does not use a strict JSON parser. It // delegates to eval(). The content passed to this method must therefore come // from a trusted source. // 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. // example: // simple serialization of a trivial object // | var jsonStr = dojo.toJson({ howdy: "stranger!", isStrange: true }); // | doh.is('{"howdy":"stranger!","isStrange":true}', jsonStr); // example: // a custom serializer for an objects of a particular class: // | dojo.declare("Furby", null, { // | furbies: "are strange", // | furbyCount: 10, // | __json__: function(){ // | }, // | }); 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. throw new 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); return recurse(newObj, prettyPrint, nextIndent); }catch(e){ // console.log(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 + '"'; }else if(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.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"); (function(){ var d = dojo; 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 // and creates a new Color instance to work from. // // example: // Work with a Color instance: // | var c = new dojo.Color(); // | c.setColor([0,0,0]); // black // | var hex = c.toHex(); // #000000 // // example: // Work with a node's color: // | var color = dojo.style("someNode", "backgroundColor"); // | var n = new dojo.Color(color); // | // adjust the color some // | n.r *= .5; // | console.log(n.toString()); // rgb(128, 255, 255); if(color){ this.setColor(color); } }; // FIXME: // there's got to be a more space-efficient way to encode or discover // these!! Use hex? 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], transparent: d.config.transparentColor || [255,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 // and sets this color instance to that value. // // example: // | var c = new dojo.Color(); // no color // | c.setColor("#ededed"); // greyish if(d.isString(color)){ d.colorFromString(color, this); }else if(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: // Ensures the object has correct attributes // description: // the default implementation does nothing, include dojo.colors to // augment it with real checks return this; // dojo.Color }, toRgb: function(){ // summary: // Returns 3 component array of rgb values // example: // | var c = new dojo.Color("#000000"); // | console.log(c.toRgb()); // [0,0,0] var t = this; return [t.r, t.g, t.b]; // Array }, toRgba: function(){ // summary: // Returns a 4 component array of rgba values from the color // represented by this object. var t = this; return [t.r, t.g, t.b, t.a]; // Array }, toHex: function(){ // summary: // Returns a CSS color string in hexadecimal representation // example: // | console.log(new dojo.Color([0,0,0]).toHex()); // #000000 var arr = d.map(["r", "g", "b"], function(x){ var s = this[x].toString(16); return s.length < 2 ? "0" + s : s; }, this); return "#" + arr.join(""); // String }, toCss: function(/*Boolean?*/ includeAlpha){ // summary: // Returns a css color string in rgb(a) representation // example: // | var c = new dojo.Color("#FFF").toCss(); // | console.log(c); // rgb('255','255','255') var t = this, rgb = t.r + ", " + t.g + ", " + t.b; return (includeAlpha ? "rgba(" + rgb + ", " + t.a : "rgb(" + rgb) + ")"; // String }, toString: function(){ // summary: // Returns a visual representation of the color return this.toCss(true); // String } }); 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 t = obj || new d.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: // Returns a `dojo.Color` instance from a string of the form // "rgb(...)" or "rgba(...)". Optionally accepts a `dojo.Color` // object to update with the parsed value and return instead of // creating a new object. // returns: // A dojo.Color object. If obj is passed, it will be the return value. 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. Optionally accepts a // `dojo.Color` object to update with the parsed value. // // returns: // A dojo.Color object. If obj is passed, it will be the return value. // // example: // | var thing = dojo.colorFromHex("#ededed"); // grey, longhand // // example: // | var thing = dojo.colorFromHex("#000"); // black, shorthand var 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 `dojo.Color` from a 3 or 4 element array, mapping each // element in sequence to the rgb(a) values of the color. // example: // | var myColor = dojo.colorFromArray([237,237,237,0.5]); // grey, 50% alpha // returns: // A dojo.Color object. If obj is passed, it will be the return value. var t = obj || new d.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. Accepts hex, rgb, and rgba // style color values. // description: // Acceptable input values for str may include arrays of any form // accepted by dojo.colorFromArray, hex strings such as "#aaaaaa", or // rgb or rgba strings such as "rgb(133, 200, 16)" or "rgba(10, 10, // 10, 50)" // returns: // A dojo.Color object. If obj is passed, it will be the return value. var a = d.Color.named[str]; return a && d.colorFromArray(a, obj) || d.colorFromRgb(str, obj) || d.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: // Invoke callback with globalObject as dojo.global and // globalObject.document as dojo.doc. // description: // Invoke callback with globalObject as dojo.global and // globalObject.document as dojo.doc. If provided, globalObject // will be executed in the context of object thisObject // When callback() returns or throws an error, the dojo.global // and dojo.doc will be restored to its previous state. var oldGlob = dojo.global; try{ dojo.global = globalObject; return dojo.withDoc.call(null, globalObject.document, callback, thisObject, cbArguments); }finally{ dojo.global = oldGlob; } } dojo.withDoc = function( /*DocumentElement*/documentObject, /*Function*/callback, /*Object?*/thisObject, /*Array?*/cbArguments){ // summary: // Invoke callback with documentObject as dojo.doc. // description: // Invoke callback with documentObject as dojo.doc. If provided, // callback will be executed in the context of object thisObject // When callback() returns or throws an error, the dojo.doc will // be restored to its previous state. var oldDoc = dojo.doc, oldLtr = dojo._bodyLtr, oldQ = dojo.isQuirks; try{ dojo.doc = documentObject; delete dojo._bodyLtr; // uncache dojo.isQuirks = dojo.doc.compatMode == "BackCompat"; // no need to check for QuirksMode which was Opera 7 only if(thisObject && typeof callback == "string"){ callback = thisObject[callback]; } return callback.apply(thisObject, cbArguments || []); }finally{ dojo.doc = oldDoc; delete dojo._bodyLtr; // in case it was undefined originally, and set to true/false by the alternate document if(oldLtr !== undefined){ dojo._bodyLtr = oldLtr; } dojo.isQuirks = oldQ; } }; } 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){ 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 ? (dontFix ? 2 : 1) : 0, 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 ]; } dojo._disconnect = function(obj, event, handle, listener){ ([dojo._listener, del, node_listener][listener]).remove(obj, event, handle); } // Constants // Public: client code should test // keyCode against these named constants, as the // actual codes can vary by browser. dojo.keys = { // summary: // Definitions for common key values BACKSPACE: 8, TAB: 9, CLEAR: 12, ENTER: 13, SHIFT: 16, CTRL: 17, ALT: 18, META: dojo.isSafari ? 91 : 224, // the apple key on macs PAUSE: 19, CAPS_LOCK: 20, ESCAPE: 27, SPACE: 32, PAGE_UP: 33, PAGE_DOWN: 34, END: 35, HOME: 36, LEFT_ARROW: 37, UP_ARROW: 38, RIGHT_ARROW: 39, DOWN_ARROW: 40, INSERT: 45, DELETE: 46, HELP: 47, LEFT_WINDOW: 91, RIGHT_WINDOW: 92, SELECT: 93, NUMPAD_0: 96, NUMPAD_1: 97, NUMPAD_2: 98, NUMPAD_3: 99, NUMPAD_4: 100, NUMPAD_5: 101, NUMPAD_6: 102, NUMPAD_7: 103, NUMPAD_8: 104, NUMPAD_9: 105, NUMPAD_MULTIPLY: 106, NUMPAD_PLUS: 107, NUMPAD_ENTER: 108, NUMPAD_MINUS: 109, NUMPAD_PERIOD: 110, NUMPAD_DIVIDE: 111, F1: 112, F2: 113, F3: 114, F4: 115, F5: 116, F6: 117, F7: 118, F8: 119, F9: 120, F10: 121, F11: 122, F12: 123, F13: 124, F14: 125, F15: 126, NUM_LOCK: 144, SCROLL_LOCK: 145, // virtual key mapping copyKey: dojo.isMac && !dojo.isAIR ? (dojo.isSafari ? 91 : 224 ) : 17 }; var evtCopyKey = dojo.isMac ? "metaKey" : "ctrlKey"; dojo.isCopyKey = function(e){ // summary: // Checks an event for the copy key (meta on Mac, and ctrl anywhere else) // e: Event // Event object to examine return e[evtCopyKey]; // Boolean }; // Public: decoding mouse buttons from events /*===== dojo.mouseButtons = { // LEFT: Number // Numeric value of the left mouse button for the platform. LEFT: 0, // MIDDLE: Number // Numeric value of the middle mouse button for the platform. MIDDLE: 1, // RIGHT: Number // Numeric value of the right mouse button for the platform. RIGHT: 2, isButton: function(e, button){ // summary: // Checks an event object for a pressed button // e: Event // Event object to examine // button: Number // The button value (example: dojo.mouseButton.LEFT) return e.button == button; // Boolean }, isLeft: function(e){ // summary: // Checks an event object for the pressed left button // e: Event // Event object to examine return e.button == 0; // Boolean }, isMiddle: function(e){ // summary: // Checks an event object for the pressed middle button // e: Event // Event object to examine return e.button == 1; // Boolean }, isRight: function(e){ // summary: // Checks an event object for the pressed right button // e: Event // Event object to examine return e.button == 2; // Boolean } }; =====*/ if(dojo.isIE){ dojo.mouseButtons = { LEFT: 1, MIDDLE: 4, RIGHT: 2, // helper functions isButton: function(e, button){ return e.button & button; }, isLeft: function(e){ return e.button & 1; }, isMiddle: function(e){ return e.button & 4; }, isRight: function(e){ return e.button & 2; } }; }else{ dojo.mouseButtons = { LEFT: 0, MIDDLE: 1, RIGHT: 2, // helper functions isButton: function(e, button){ return e.button == button; }, isLeft: function(e){ return e.button == 0; }, isMiddle: function(e){ return e.button == 1; }, isRight: function(e){ return e.button == 2; } }; } // 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){ return 0; } } // 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; }else if(c==13||c==27){ c=0; // Mozilla considers ENTER and ESC non-printable }else if(c==3){ c=99; // Mozilla maps CTRL-BREAK to CTRL-c } // Mozilla sets keyCode to 0 when there is a charCode // but that stops the event on IE. evt.charCode = c; 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 }else if(c>95 && c<106){ c -= 48; // map CTRL-[numpad 0-9] to ASCII }else if((!evt.shiftKey)&&(c>=65&&c<=90)){ c += 32; // map CTRL-[A-Z] to lowercase }else{ c = 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; } }); // override stopEvent for IE dojo.stopEvent = function(evt){ evt = evt || window.event; del._stopPropagation.call(evt); del._preventDefault.call(evt); } } 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; } }); } // Webkit event normalization if(dojo.isWebKit){ del._add = del.add; del._remove = del.remove; 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<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 }else if(c>95 && c<106){ c -= 48; // map CTRL-[numpad 0-9] to ASCII }else if(!evt.shiftKey && c>=65 && c<=90){ c += 32; // map CTRL-[A-Z] to lowercase }else{ c = 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*/ }, remove: function(/*DOMNode*/ node, /*String*/ event, /*Handle*/ handle){ if(node){ if(handle._stealthKeyDownHandle){ del._remove(node, "keydown", handle._stealthKeyDownHandle); } del._remove(node, event, handle); } }, _fixEvent: function(evt, sender){ switch(evt.type){ case "keypress": if(evt.faux){ return evt; } var c = evt.charCode; c = c>=32 ? c : 0; return del._synthesizeEvent(evt, {charCode: c, faux: true}); } return evt; } }); } })(); 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){ var f = h[lls[i]]; if(!(i in ap) && f){ f.apply(sender, args); } } return r; } dojo._getIeDispatcher = function(){ // ensure the returned function closes over nothing ("new Function" apparently doesn't close) return new 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 try{ document.execCommand("BackgroundImageCache", false, true); }catch(e){ // sane browsers don't have cache "issues" } // ============================= // DOM Functions // ============================= /*===== dojo.byId = function(id, doc){ // summary: // Returns DOM node with matching `id` attribute or `null` // if not found. If `id` is a DomNode, this function is a no-op. // // id: String|DOMNode // A string to match an HTML id attribute or a reference to a DOM Node // // doc: Document? // Document to work in. Defaults to the current value of // dojo.doc. Can be used to retrieve // node references from other documents. // // example: // Look up a node by ID: // | var n = dojo.byId("foo"); // // example: // Check if a node exists, and use it. // | var n = dojo.byId("bar"); // | if(n){ doStuff() ... } // // example: // Allow string or DomNode references to be passed to a custom function: // | var foo = function(nodeOrId){ // | nodeOrId = dojo.byId(nodeOrId); // | // ... more stuff // | } =====*/ if(dojo.isIE || dojo.isOpera){ dojo.byId = function(id, doc){ if(typeof id != "string"){ return id; } var _d = doc || dojo.doc, 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 || te.id == id)){ return te; }else{ var eles = _d.all[id]; if(!eles || eles.nodeName){ eles = [eles]; } // if more than 1, choose first with the correct id var i=0; while((te=eles[i++])){ if((te.attributes && te.attributes.id && te.attributes.id.value == id) || te.id == id){ return te; } } } }; }else{ dojo.byId = function(id, doc){ // inline'd type check return (typeof id == "string") ? (doc || dojo.doc).getElementById(id) : id; // DomNode }; } /*===== }; =====*/ (function(){ var d = dojo; var byId = d.byId; var _destroyContainer = null, _destroyDoc; d.addOnWindowUnload(function(){ _destroyContainer = null; //prevent IE leak }); /*===== dojo._destroyElement = function(node){ // summary: // Existing alias for `dojo.destroy`. Deprecated, will be removed // in 2.0 } =====*/ dojo._destroyElement = dojo.destroy = function(/*String|DomNode*/node){ // summary: // Removes a node from its parent, clobbering it and all of its // children. // // description: // Removes a node from its parent, clobbering it and all of its // children. Function only works with DomNodes, and returns nothing. // // node: // A String ID or DomNode reference of the element to be destroyed // // example: // Destroy a node byId: // | dojo.destroy("someId"); // // example: // Destroy all nodes in a list by reference: // | dojo.query(".someNode").forEach(dojo.destroy); node = byId(node); try{ var doc = node.ownerDocument; // cannot use _destroyContainer.ownerDocument since this can throw an exception on IE if(!_destroyContainer || _destroyDoc != doc){ _destroyContainer = doc.createElement("div"); _destroyDoc = doc; } _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: string id or node reference to test // ancestor: string id or node reference of potential parent to test against // // example: // Test is node id="bar" is a descendant of node id="foo" // | if(dojo.isDescendant("bar", "foo")){ ... } try{ node = byId(node); ancestor = byId(ancestor); while(node){ if(node == ancestor){ return true; // Boolean } node = node.parentNode; } }catch(e){ /* squelch, return false */ } return false; // Boolean }; dojo.setSelectable = function(/*DomNode|String*/node, /*Boolean*/selectable){ // summary: // Enable or disable selection on a node // node: // id or reference to node // selectable: // state to put the node in. false indicates unselectable, true // allows selection. // example: // Make the node id="bar" unselectable // | dojo.setSelectable("bar"); // example: // Make the node id="bar" selectable // | dojo.setSelectable("bar", true); node = byId(node); if(d.isMozilla){ node.style.MozUserSelect = selectable ? "" : "none"; }else if(d.isKhtml || d.isWebKit){ node.style.KhtmlUserSelect = selectable ? "auto" : "none"; }else if(d.isIE){ var v = (node.unselectable = selectable ? "" : "on"); d.query("*", node).forEach("item.unselectable = '"+v+"'"); } //FIXME: else? Opera? }; var _insertBefore = function(/*DomNode*/node, /*DomNode*/ref){ var parent = ref.parentNode; if(parent){ parent.insertBefore(node, ref); } }; var _insertAfter = function(/*DomNode*/node, /*DomNode*/ref){ // summary: // Try to insert node after ref var parent = ref.parentNode; if(parent){ if(parent.lastChild == ref){ parent.appendChild(node); }else{ parent.insertBefore(node, ref.nextSibling); } } }; dojo.place = function(node, refNode, position){ // summary: // Attempt to insert node into the DOM, choosing from various positioning options. // Returns the first argument resolved to a DOM node. // // node: String|DomNode // id or node reference, or HTML fragment starting with "<" to place relative to refNode // // refNode: String|DomNode // id or node reference to use as basis for placement // // position: String|Number? // string noting the position of node relative to refNode or a // number indicating the location in the childNodes collection of refNode. // Accepted string values are: // | * before // | * after // | * replace // | * only // | * first // | * last // "first" and "last" indicate positions as children of refNode, "replace" replaces refNode, // "only" replaces all children. position defaults to "last" if not specified // // returns: DomNode // Returned values is the first argument resolved to a DOM node. // // .place() is also a method of `dojo.NodeList`, allowing `dojo.query` node lookups. // // example: // Place a node by string id as the last child of another node by string id: // | dojo.place("someNode", "anotherNode"); // // example: // Place a node by string id before another node by string id // | dojo.place("someNode", "anotherNode", "before"); // // example: // Create a Node, and place it in the body element (last child): // | dojo.place("
", dojo.body()); // // example: // Put a new LI as the first child of a list by id: // | dojo.place("
  • ", "someUl", "first"); refNode = byId(refNode); if(typeof node == "string"){ // inline'd type check node = node.charAt(0) == "<" ? d._toDom(node, refNode.ownerDocument) : byId(node); } if(typeof position == "number"){ // inline'd type check var cn = refNode.childNodes; if(!cn.length || cn.length <= position){ refNode.appendChild(node); }else{ _insertBefore(node, cn[position < 0 ? 0 : position]); } }else{ switch(position){ case "before": _insertBefore(node, refNode); break; case "after": _insertAfter(node, refNode); break; case "replace": refNode.parentNode.replaceChild(node, refNode); break; case "only": d.empty(refNode); refNode.appendChild(node); break; case "first": if(refNode.firstChild){ _insertBefore(node, refNode.firstChild); break; } // else fallthrough... default: // aka: last refNode.appendChild(node); } } return node; // DomNode } // 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*/){ // client code may have to adjust if compatMode varies across iframes d.boxModel = document.compatMode == "BackCompat" ? "border-box" : "content-box"; } // ============================= // Style Functions // ============================= // getComputedStyle drives most of the style code. // Wherever possible, reuse the returned object. // // API functions below that need to access computed styles accept an // optional computedStyle parameter. // If this parameter is omitted, the functions will call getComputedStyle themselves. // This way, calling code can access computedStyle once, and then pass the reference to // multiple API functions. /*===== 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; // // example: // Reusing the returned object, avoiding multiple lookups: // | var cs = dojo.getComputedStyle(dojo.byId("someNode")); // | var w = cs.width, h = cs.height; return; // CSS2Properties } =====*/ // Although we normally eschew argument validation at this // level, here we test argument 'node' for (duck)type, // by testing nodeType, ecause 'document' is the 'parentNode' of 'body' // it is frequently sent to this function even // though it is not Element. var gcs; if(d.isWebKit){ gcs = function(/*DomNode*/node){ var s; if(node.nodeType == 1){ var dv = node.ownerDocument.defaultView; s = dv.getComputedStyle(node, null); if(!s && node.style){ node.style.display = ""; s = dv.getComputedStyle(node, null); } } return s || {}; }; }else if(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.nodeType == 1 ? node.ownerDocument.defaultView.getComputedStyle(node, null) : {}; }; } dojo.getComputedStyle = gcs; if(!d.isIE){ d._toPixelValue = function(element, value){ // style values can be floats, client code may want // to round for integer pixels. return parseFloat(value) || 0; }; }else{ d._toPixelValue = function(element, avalue){ if(!avalue){ return 0; } // on IE7, medium is usually 4 pixels if(avalue == "medium"){ return 4; } // style values can be floats, client code may // want to round this value for integer pixels. if(avalue.slice && avalue.slice(-2) == 'px'){ return parseFloat(avalue); } 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._getOpacity = d.isIE ? function(node){ try{ return af(node).Opacity / 100; // Number }catch(e){ return 1; // Number } } : function(node){ return gcs(node).opacity; }; /*===== 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, opaque = opacity == 1; node.style.zoom = opaque ? "" : 1; if(!af(node)){ if(opaque){ return opacity; } node.style.filter += " progid:" + astr + "(Opacity=" + ov + ")"; }else{ af(node, 1).Opacity = ov; } // 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 = !opaque; if(node.nodeName.toLowerCase() == "tr"){ d.query("> td", node).forEach(function(i){ d._setOpacity(i, opacity); }); } return opacity; } : function(node, opacity){ return node.style.opacity = opacity; }; var _pixelNamesCache = { left: true, top: true }; var _pixelRegExp = /margin|padding|width|height|max|min|offset/; // |border 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){ case 700: return "bold"; case 400: 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", _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. // description: // Getting the style value uses the computed style for the node, so the value // will be a calculated value, not just the immediate node.style value. // Also when getting values, use specific style names, // like "borderBottomWidth" instead of "border" since compound values like // "border" are not necessarily reflected as expected. // If you want to get node dimensions, use `dojo.marginBox()`, // `dojo.contentBox()` or `dojo.position()`. // node: // 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. When setting a pixel value, // be sure to include "px" in the value. For instance, top: "200px". // Otherwise, in some cases, some browsers will not apply the style. // example: // Passing only an ID or node returns the computed style object of // the node: // | dojo.style("thinger"); // example: // Passing a node and a style property returns the current // normalized, computed value for that property: // | dojo.style("thinger", "opacity"); // 1 by default // // example: // Passing a node, a style property, and a value changes the // current display of the node and returns the new computed value // | dojo.style("thinger", "opacity", 0.5); // == 0.5 // // example: // Passing a node, an object-style style property sets each of the values in turn and returns the computed style object of the node: // | dojo.style("thinger", { // | "opacity": 0.5, // | "border": "3px solid black", // | "height": "300px" // | }); // // example: // When the CSS style property is hyphenated, the JavaScript property is camelCased. // font-size becomes fontSize, and so on. // | dojo.style("thinger",{ // | fontSize:"14pt", // | letterSpacing:"1.2em" // | }); // // example: // dojo.NodeList implements .style() using the same syntax, omitting the "node" parameter, calling // dojo.style() on every element of the list. See: `dojo.query()` and `dojo.NodeList()` // | dojo.query(".someClassName").style("visibility","hidden"); // | // or // | dojo.query("#baz > div").style({ // | opacity:0.75, // | fontSize:"13pt" // | }); var n = 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 && typeof style != "string"){ // inline'd type check 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 */ } // ============================= // Box Functions // ============================= dojo._getPadExtents = function(/*DomNode*/n, /*Object*/computedStyle){ // summary: // Returns object with special values specifically useful for node // fitting. // description: // Returns an object with `w`, `h`, `l`, `t` properties: // | l/t = 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. // description: // * 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. // description: // * 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.isWebKit && (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; } } } }else if(d.isOpera || (d.isIE > 7 && !d.isQuirks)){ // On Opera and IE 8, offsetLeft/Top includes the parent's border if(p){ 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 }; } dojo._getBorderBox = function(node, computedStyle){ var s = computedStyle || gcs(node), pe = d._getPadExtents(node, s), cb = d._getContentBox(node, s) ; return { l: cb.l - pe.l, t: cb.t - pe.t, w: cb.w + pe.w, h: cb.h + pe.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: // left offset from parent. // t: // top offset from parent. // w: // width in current box model. // h: // width in current box model. // u: // unit measure to use for other measures. Defaults to "px". u = u || "px"; var s = node.style; if(!isNaN(l)){ s.left = l + u; } if(!isNaN(t)){ s.top = t + u; } if(w >= 0){ s.width = w + u; } if(h >= 0){ s.height = h + u; } } 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" || d._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. bb = d._usesBorderBox(node), pb = bb ? _nilExtents : d._getPadBorderExtents(node, s) ; if(d.isWebKit){ // 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(d._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: // Getter/setter for the margin-box of node. // Returns an object in the expected format of box (regardless // if box is passed). The object might look like: // `{ l: 50, t: 200, w: 300: h: 150 }` // for a node offset from its parent 50px to the left, 200px from // the top with a margin width of 300px and a margin-height of // 150px. // node: // id or reference to DOM Node to get/set box for // box: // If passed, denotes that dojo.marginBox() should // update/set the margin box for node. Box is an object in the // above format. All properties are optional if passed. // example: // Retrieve the marginbox of a passed node // | var box = dojo.marginBox("someNodeId"); // | console.dir(box); // // example: // Set a node's marginbox to the size of another node // | var box = dojo.marginBox("someNodeId"); // | dojo.marginBox("someOtherNode", box); var n = 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. // While the getter will return top and left values, the // setter only accepts setting the width and height. // node: // id or reference to DOM Node to get/set box for // box: // If passed, denotes that dojo.contentBox() should // update/set the content box for node. Box is an object in the // above format, but only w (width) and h (height) are supported. // All properties are optional if passed. var n = byId(node), s = gcs(n), b = box; return !b ? d._getContentBox(n, s) : d._setContentSize(n, b.w, b.h, s); // Object } // ============================= // Positioning // ============================= var _sumAncestorProperties = function(node, prop){ if(!(node = (node||0).parentNode)){return 0} var val, retVal = 0, _b = d.body(); while(node && node.style){ if(gcs(node).position == "fixed"){ return 0; } 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._docScroll = function(){ var n = d.global; return "pageXOffset" in n? { x:n.pageXOffset, y:n.pageYOffset } : (n=d.doc.documentElement, n.clientHeight? { x:d._fixIeBiDiScrollLeft(n.scrollLeft), y:n.scrollTop } : (n=d.body(), { x:n.scrollLeft||0, y:n.scrollTop||0 })); }; dojo._isBodyLtr = function(){ return "_bodyLtr" in d? d._bodyLtr : d._bodyLtr = (d.body().dir || d.doc.documentElement.dir || "ltr").toLowerCase() == "ltr"; // Boolean } dojo._getIeDocumentElementOffset = function(){ // summary: // returns the offset in x and y from the document body to the // visual edge of the page // description: // 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; // only deal with HTML element here, _abs handles body/quirks if(d.isIE < 8){ var r = de.getBoundingClientRect(); // works well for IE6+ //console.debug('rect left,top = ' + r.left+','+r.top + ', html client left/top = ' + de.clientLeft+','+de.clientTop + ', rtl = ' + (!d._isBodyLtr()) + ', quirks = ' + d.isQuirks); var l = r.left, t = r.top; if(d.isIE < 7){ l += de.clientLeft; // scrollbar size in strict/RTL, or, t += de.clientTop; // HTML border size in strict } return { x: l < 0? 0 : l, // FRAME element border size can lead to inaccurate negative values y: t < 0? 0 : t }; }else{ return { x: 0, y: 0 }; } }; dojo._fixIeBiDiScrollLeft = function(/*Integer*/ scrollLeft){ // In RTL direction, scrollLeft should be a negative value, but IE < 8 // 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 < 8 && !d._isBodyLtr()){ var de = d.isQuirks ? dd.body : dd.documentElement; return scrollLeft + de.clientWidth - de.scrollWidth; // Integer } return scrollLeft; // Integer } // FIXME: need a setter for coords or a moveTo!! dojo._abs = dojo.position = function(/*DomNode*/node, /*Boolean?*/includeScroll){ // summary: // Gets the position and size of the passed element relative to // the viewport (if includeScroll==false), or relative to the // document root (if includeScroll==true). // // description: // Returns an object of the form: // { x: 100, y: 300, w: 20, h: 15 } // If includeScroll==true, the x and y values will include any // document offsets that may affect the position relative to the // viewport. // Uses the border-box model (inclusive of border and padding but // not margin). Does not act as a setter. var db = d.body(), dh = db.parentNode, ret; node = byId(node); if(node["getBoundingClientRect"]){ // IE6+, FF3+, super-modern WebKit, and Opera 9.6+ all take this branch ret = node.getBoundingClientRect(); ret = { x: ret.left, y: ret.top, w: ret.right - ret.left, h: ret.bottom - ret.top }; if(d.isIE){ // On IE there's a 2px offset that we need to adjust for, see _getIeDocumentElementOffset() var offset = d._getIeDocumentElementOffset(); // fixes the position in IE, quirks mode ret.x -= offset.x + (d.isQuirks ? db.clientLeft+db.offsetLeft : 0); ret.y -= offset.y + (d.isQuirks ? db.clientTop+db.offsetTop : 0); }else if(d.isFF == 3){ // In FF3 you have to subtract the document element margins. // Fixed in FF3.5 though. var cs = gcs(dh); ret.x -= px(dh, cs.marginLeft) + px(dh, cs.borderLeftWidth); ret.y -= px(dh, cs.marginTop) + px(dh, cs.borderTopWidth); } }else{ // FF2 and older WebKit ret = { x: 0, y: 0, w: node.offsetWidth, h: node.offsetHeight }; if(node["offsetParent"]){ ret.x -= _sumAncestorProperties(node, "scrollLeft"); ret.y -= _sumAncestorProperties(node, "scrollTop"); var curnode = node; do{ var n = curnode.offsetLeft, t = curnode.offsetTop; ret.x += isNaN(n) ? 0 : n; ret.y += isNaN(t) ? 0 : t; cs = gcs(curnode); if(curnode != node){ if(d.isMoz){ // 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); }else{ ret.x += px(curnode, cs.borderLeftWidth); ret.y += 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.isMoz && 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 != dh) && curnode); }else if(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.x += scroll.x; ret.y += scroll.y; } return ret; // Object } dojo.coords = function(/*DomNode|String*/node, /*Boolean?*/includeScroll){ // summary: // Deprecated: Use position() for border-box x/y/w/h // or marginBox() for margin-box w/h/l/t. // Returns an object representing a node's size and position. // // description: // Returns an object that measures margin-box (w)idth/(h)eight // and absolute position x/y of the border-box. Also returned // is computed (l)eft and (t)op values in pixels from the // node's offsetParent as returned from marginBox(). // Return value will be in the form: //| { l: 50, t: 200, w: 300: h: 150, x: 100, y: 300 } // Does not act as a setter. If includeScroll is passed, the x and // y params are affected as one would expect in dojo.position(). var n = byId(node), s = gcs(n), mb = d._getMarginBox(n, s); var abs = d.position(n, includeScroll); mb.x = abs.x; mb.y = abs.y; return mb; } // ============================= // Element attribute Functions // ============================= // dojo.attr() should conform to http://www.w3.org/TR/DOM-Level-2-Core/ var _propNames = { // properties renamed to avoid clashes with reserved words "class": "className", "for": "htmlFor", // properties written as camelCase tabindex: "tabIndex", readonly: "readOnly", colspan: "colSpan", frameborder: "frameBorder", rowspan: "rowSpan", valuetype: "valueType" }, _attrNames = { // original attribute names classname: "class", htmlfor: "for", // for IE tabindex: "tabIndex", readonly: "readOnly" }, _forcePropNames = { innerHTML: 1, className: 1, htmlFor: d.isIE, value: 1 }; var _fixAttrName = function(/*String*/ name){ return _attrNames[name.toLowerCase()] || name; }; var _hasAttr = function(node, name){ var attr = node.getAttributeNode && node.getAttributeNode(name); return attr && attr.specified; // Boolean }; // There is a difference in the presence of certain properties and their default values // between browsers. For example, on IE "disabled" is present on all elements, // but it is value is "false"; "tabIndex" of
    returns 0 by default on IE, yet other browsers // can return -1. 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 var lc = name.toLowerCase(); return _forcePropNames[_propNames[lc] || name] || _hasAttr(byId(node), _attrNames[lc] || name); // Boolean } var _evtHdlrMap = {}, _ctr = 0, _attrId = dojo._scopeName + "attrid", // the next dictionary lists elements with read-only innerHTML on IE _roInnerHtml = {col: 1, colgroup: 1, // frameset: 1, head: 1, html: 1, style: 1, table: 1, tbody: 1, tfoot: 1, thead: 1, tr: 1, title: 1}; 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 argument is a // map of attributes, acts as a setter. // // When passing functions as values, note that they will not be // directly assigned to slots on the node, but rather the default // behavior will be removed and the new behavior will be added // using `dojo.connect()`, meaning that event handler properties // will be normalized and that some caveats with regards to // non-standard behaviors for onsubmit apply. Namely that you // should cancel form submission using `dojo.stopEvent()` on the // passed event object instead of returning a boolean value from // the handler itself. // node: // id or reference to the element to get or set the 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 used as a setter, the DOM node // // example: // | // get the current value of the "foo" attribute on a node // | dojo.attr(dojo.byId("nodeId"), "foo"); // | // or we can just pass the id: // | dojo.attr("nodeId", "foo"); // // example: // | // use attr() to set the tab index // | dojo.attr("nodeId", "tabIndex", 3); // | // // example: // Set multiple values at once, including event handlers: // | dojo.attr("formId", { // | "foo": "bar", // | "tabIndex": -1, // | "method": "POST", // | "onsubmit": function(e){ // | // stop submitting the form. Note that the IE behavior // | // of returning true or false will have no effect here // | // since our handler is connect()ed to the built-in // | // onsubmit behavior and so we need to use // | // dojo.stopEvent() to ensure that the submission // | // doesn't proceed. // | dojo.stopEvent(e); // | // | // submit the form with Ajax // | dojo.xhrPost({ form: "formId" }); // | } // | }); // // example: // Style is s special case: Only set with an object hash of styles // | dojo.attr("someNode",{ // | id:"bar", // | style:{ // | width:"200px", height:"100px", color:"#000" // | } // | }); // // example: // Again, only set style as an object hash of styles: // | var obj = { color:"#fff", backgroundColor:"#000" }; // | dojo.attr("someNode", "style", obj); // | // | // though shorter to use `dojo.style()` in this case: // | dojo.style("someNode", obj); node = byId(node); var args = arguments.length, prop; if(args == 2 && typeof name != "string"){ // inline'd type check // the object form of setter: the 2nd argument is a dictionary for(var x in name){ d.attr(node, x, name[x]); } return node; // DomNode } var lc = name.toLowerCase(), propName = _propNames[lc] || name, forceProp = _forcePropNames[propName], attrName = _attrNames[lc] || name; if(args == 3){ // setter do{ if(propName == "style" && typeof value != "string"){ // inline'd type check // special case: setting a style d.style(node, value); break; } if(propName == "innerHTML"){ // special case: assigning HTML if(d.isIE && node.tagName.toLowerCase() in _roInnerHtml){ d.empty(node); node.appendChild(d._toDom(value, node.ownerDocument)); }else{ node[propName] = value; } break; } if(d.isFunction(value)){ // special case: assigning an event handler // 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][propName]; if(h){ d.disconnect(h); }else{ try{ delete node[propName]; }catch(e){} } // ensure that event objects are normalized, etc. _evtHdlrMap[attrId][propName] = d.connect(node, propName, value); break; } if(forceProp || typeof value == "boolean"){ // special case: forcing assignment to the property // special case: setting boolean to a property instead of attribute node[propName] = value; break; } // node's attribute node.setAttribute(attrName, value); }while(false); return node; // DomNode } // getter // should we access this attribute via a property or // via getAttribute()? value = node[propName]; if(forceProp && typeof value != "undefined"){ // node's property return value; // Anything } if(propName != "href" && (typeof value == "boolean" || d.isFunction(value))){ // node's property return value; // Anything } // node's attribute // we need _hasAttr() here to guard against IE returning a default value return _hasAttr(node, attrName) ? node.getAttribute(attrName) : null; // Anything } 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 byId(node).removeAttribute(_fixAttrName(name)); } dojo.getNodeProp = function(/*DomNode|String*/ node, /*String*/ name){ // summary: // Returns an effective value of a property or an attribute. // node: // id or reference to the element to remove the attribute from // name: // the name of the attribute node = byId(node); var lc = name.toLowerCase(), propName = _propNames[lc] || name; if((propName in node) && propName != "href"){ // node's property return node[propName]; // Anything } // node's attribute var attrName = _attrNames[lc] || name; return _hasAttr(node, attrName) ? node.getAttribute(attrName) : null; // Anything } dojo.create = function(tag, attrs, refNode, pos){ // summary: // Create an element, allowing for optional attribute decoration // and placement. // // description: // A DOM Element creation function. A shorthand method for creating a node or // a fragment, and allowing for a convenient optional attribute setting step, // as well as an optional DOM placement reference. //| // Attributes are set by passing the optional object through `dojo.attr`. // See `dojo.attr` for noted caveats and nuances, and API if applicable. //| // Placement is done via `dojo.place`, assuming the new node to be the action // node, passing along the optional reference node and position. // // tag: String|DomNode // A string of the element to create (eg: "div", "a", "p", "li", "script", "br"), // or an existing DOM node to process. // // attrs: Object // An object-hash of attributes to set on the newly created node. // Can be null, if you don't want to set any attributes/styles. // See: `dojo.attr` for a description of available attributes. // // refNode: String?|DomNode? // Optional reference node. Used by `dojo.place` to place the newly created // node somewhere in the dom relative to refNode. Can be a DomNode reference // or String ID of a node. // // pos: String? // Optional positional reference. Defaults to "last" by way of `dojo.place`, // though can be set to "first","after","before","last", "replace" or "only" // to further control the placement of the new node relative to the refNode. // 'refNode' is required if a 'pos' is specified. // // returns: DomNode // // example: // Create a DIV: // | var n = dojo.create("div"); // // example: // Create a DIV with content: // | var n = dojo.create("div", { innerHTML:"

    hi

    " }); // // example: // Place a new DIV in the BODY, with no attributes set // | var n = dojo.create("div", null, dojo.body()); // // example: // Create an UL, and populate it with LI's. Place the list as the first-child of a // node with id="someId": // | var ul = dojo.create("ul", null, "someId", "first"); // | var items = ["one", "two", "three", "four"]; // | dojo.forEach(items, function(data){ // | dojo.create("li", { innerHTML: data }, ul); // | }); // // example: // Create an anchor, with an href. Place in BODY: // | dojo.create("a", { href:"foo.html", title:"Goto FOO!" }, dojo.body()); // // example: // Create a `dojo.NodeList()` from a new element (for syntatic sugar): // | dojo.query(dojo.create('div')) // | .addClass("newDiv") // | .onclick(function(e){ console.log('clicked', e.target) }) // | .place("#someNode"); // redundant, but cleaner. var doc = d.doc; if(refNode){ refNode = byId(refNode); doc = refNode.ownerDocument; } if(typeof tag == "string"){ // inline'd type check tag = doc.createElement(tag); } if(attrs){ d.attr(tag, attrs); } if(refNode){ d.place(tag, refNode, pos); } return tag; // DomNode } /*===== dojo.empty = function(node){ // summary: // safely removes all children of the node. // node: DOMNode|String // a reference to a DOM node or an id. // example: // Destroy node's children byId: // | dojo.empty("someId"); // // example: // Destroy all nodes' children in a list by reference: // | dojo.query(".someNode").forEach(dojo.empty); } =====*/ d.empty = d.isIE ? function(node){ node = byId(node); for(var c; c = node.lastChild;){ // intentional assignment d.destroy(c); } } : function(node){ byId(node).innerHTML = ""; }; /*===== dojo._toDom = function(frag, doc){ // summary: // instantiates an HTML fragment returning the corresponding DOM. // frag: String // the HTML fragment // doc: DocumentNode? // optional document to use when creating DOM nodes, defaults to // dojo.doc if not specified. // returns: DocumentFragment // // example: // Create a table row: // | var tr = dojo._toDom("First!"); } =====*/ // support stuff for dojo._toDom var tagWrap = { option: ["select"], tbody: ["table"], thead: ["table"], tfoot: ["table"], tr: ["table", "tbody"], td: ["table", "tbody", "tr"], th: ["table", "thead", "tr"], legend: ["fieldset"], caption: ["table"], colgroup: ["table"], col: ["table", "colgroup"], li: ["ul"] }, reTag = /<\s*([\w\:]+)/, masterNode = {}, masterNum = 0, masterName = "__" + d._scopeName + "ToDomId"; // generate start/end tag strings to use // for the injection for each special tag wrap case. for(var param in tagWrap){ var tw = tagWrap[param]; tw.pre = param == "option" ? ' // | // | // | // | // // 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){ setValue(ret, _in, _d.fieldToObject(item)); 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(var i=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: // Create a serialized JSON string from a form node or string // ID identifying the form to serialize return _d.toJson(_d.formToObject(formNode), prettyPrint); // String } dojo.queryToObject = function(/*String*/ str){ // summary: // Create an object representing a de-serialized query section of a // URL. Query keys with multiple values are returned in an array. // // example: // This string: // // | "foo=bar&foo=baz&thinger=%20spaces%20=blah&zonk=blarg&" // // results in this object structure: // // | { // | foo: [ "bar", "baz" ], // | thinger: " spaces =blah", // | zonk: "blarg" // | } // // Note that spaces and other urlencoded entities are correctly // handled. // 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(typeof ret[name] == "string"){ // inline'd type check ret[name] = [ret[name]]; } if(_d.isArray(ret[name])){ ret[name].push(val); }else{ ret[name] = val; } } }); return ret; // Object } // need to block async callbacks from snatching this thread as the result // of an async callback might call another sync XHR, this hangs khtml forever // must checked by watchInFlight() dojo._blockAsync = false; // MOW: remove dojo._contentHandlers alias in 2.0 var handlers = _d._contentHandlers = dojo.contentHandlers = { // summary: // A map of availble XHR transport handle types. Name matches the // `handleAs` attribute passed to XHR calls. // // description: // A map of availble XHR transport handle types. Name matches the // `handleAs` attribute passed to XHR calls. Each contentHandler is // called, passing the xhr object for manipulation. The return value // from the contentHandler will be passed to the `load` or `handle` // functions defined in the original xhr call. // // example: // Creating a custom content-handler: // | dojo.contentHandlers.makeCaps = function(xhr){ // | return xhr.responseText.toUpperCase(); // | } // | // and later: // | dojo.xhrGet({ // | url:"foo.txt", // | handleAs:"makeCaps", // | load: function(data){ /* data is a toUpper version of foo.txt */ } // | }); text: function(xhr){ // summary: A contentHandler which simply returns the plaintext response data return xhr.responseText; }, json: function(xhr){ // summary: A contentHandler which returns a JavaScript object created from the response data return _d.fromJson(xhr.responseText || null); }, "json-comment-filtered": function(xhr){ // summary: A contentHandler which expects comment-filtered JSON. // description: // A contentHandler which expects comment-filtered JSON. // the json-comment-filtered option was implemented to prevent // "JavaScript Hijacking", but it is less secure than standard JSON. Use // standard JSON instead. JSON prefixing can be used to subvert hijacking. // // Will throw a notice suggesting to use application/json mimetype, as // json-commenting can introduce security issues. To decrease the chances of hijacking, // use the standard `json` contentHandler, and prefix your "JSON" with: {}&& // // use djConfig.useCommentedJson = true to turn off the notice if(!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){ // summary: A contentHandler which evaluates the response data, expecting it to be valid JavaScript // FIXME: try Moz and IE specific eval variants? return _d.eval(xhr.responseText); }, xml: function(xhr){ // summary: A contentHandler returning an XML Document parsed from the response data var result = xhr.responseXML; if(_d.isIE && (!result || !result.documentElement)){ //WARNING: this branch used by the xml handling in dojo.io.iframe, //so be sure to test dojo.io.iframe if making changes below. var ms = function(n){ return "MSXML" + n + ".DOMDocument"; } var dp = ["Microsoft.XMLDOM", ms(6), ms(4), ms(3), ms(2)]; _d.some(dp, function(p){ try{ var dom = new ActiveXObject(p); dom.async = false; dom.loadXML(xhr.responseText); result = dom; }catch(e){ return false; } return true; }); } return result; // DOMDocument }, "json-comment-optional": function(xhr){ // summary: A contentHandler which checks the presence of comment-filtered JSON and // alternates between the `json` and `json-comment-filtered` contentHandlers. if(xhr.responseText && /^[^{\[]*\/\*/.test(xhr.responseText)){ return handlers["json-comment-filtered"](xhr); }else{ return handlers["json"](xhr); } } }; /*===== 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 a form. Used to extract the form values // and send to the server. // preventCache: Boolean? // Default is false. If true, then a // "dojo.preventCache" parameter is sent in the request // with a value that changes with each request // (timestamp). Useful only with GET-type requests. // handleAs: String? // Acceptable values depend on the type of IO // transport (see specific IO calls for more information). // rawBody: String? // Sets the raw body for an HTTP request. If this is used, then the content // property is ignored. This is mostly useful for HTTP methods that have // a body to their requests, like PUT or POST. This property can be used instead // of postData and putData for dojo.rawXhrPost and dojo.rawXhrPut respectively. // ioPublish: Boolean? // Set this explicitly to false to prevent publishing of topics related to // IO operations. Otherwise, if djConfig.ioPublish is set to true, topics // will be published via dojo.publish for different phases of an IO operation. // See dojo.__IoPublish for a list of topics that are published. // load: Function? // This function will be // called on a successful HTTP response code. // error: Function? // This function will // be called when the request fails due to a network or server error, the url // is invalid, etc. It will also be called if the load or handle callback throws an // exception, unless djConfig.debugAtAllCosts is true. This allows deployed applications // to continue to run even when a logic error happens in the callback, while making // it easier to troubleshoot while in debug mode. // handle: Function? // 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.ioPublish = ioPublish; this.load = function(response, ioArgs){ // ioArgs: dojo.__IoCallbackArgs // Provides additional information about the request. // response: Object // The response in the format as defined with handleAs. } this.error = function(response, ioArgs){ // ioArgs: dojo.__IoCallbackArgs // Provides additional information about the request. // response: Object // The response in the format as defined with handleAs. } this.handle = function(loadOrError, response, ioArgs){ // loadOrError: String // Provides a string that tells you whether this function // was called because of success (load) or failure (error). // response: Object // The response in the format as defined with handleAs. // ioArgs: dojo.__IoCallbackArgs // Provides additional information about the request. } } =====*/ /*===== 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.__IoPublish = function(){ // summary: // This is a list of IO topics that can be published // if djConfig.ioPublish is set to true. IO topics can be // published for any Input/Output, network operation. So, // dojo.xhr, dojo.io.script and dojo.io.iframe can all // trigger these topics to be published. // start: String // "/dojo/io/start" is sent when there are no outstanding IO // requests, and a new IO request is started. No arguments // are passed with this topic. // send: String // "/dojo/io/send" is sent whenever a new IO request is started. // It passes the dojo.Deferred for the request with the topic. // load: String // "/dojo/io/load" is sent whenever an IO request has loaded // successfully. It passes the response and the dojo.Deferred // for the request with the topic. // error: String // "/dojo/io/error" is sent whenever an IO request has errored. // It passes the error and the dojo.Deferred // for the request with the topic. // done: String // "/dojo/io/done" is sent whenever an IO request has completed, // either by loading or by erroring. It passes the error and // the dojo.Deferred for the request with the topic. // stop: String // "/dojo/io/stop" is sent when all outstanding IO requests have // finished. No arguments are passed with this topic. this.start = "/dojo/io/start"; this.send = "/dojo/io/send"; this.load = "/dojo/io/load"; this.error = "/dojo/io/error"; this.done = "/dojo/io/done"; this.stop = "/dojo/io/stop"; } =====*/ 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){ var form = _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); }); } //Plug in topic publishing, if dojo.publish is loaded. if(cfg.ioPublish && _d.publish && ioArgs.args.ioPublish !== false){ d.addCallbacks( function(res){ _d.publish("/dojo/io/load", [d, res]); return res; }, function(res){ _d.publish("/dojo/io/error", [d, res]); return res; } ); d.addBoth(function(res){ _d.publish("/dojo/io/done", [d, res]); return res; }); } 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 = handlers[dfd.ioArgs.handleAs](dfd.ioArgs.xhr); return ret === undefined ? null : ret; } var _deferError = function(/*Error*/error, /*Deferred*/dfd){ // summary: errHandler function for dojo._ioSetArgs call. if(!dfd.ioArgs.args.failOk){ console.error(error); } return error; } // 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 = []; //Use a separate count for knowing if we are starting/stopping io calls. //Cannot use _inFlight.length since it can change at a different time than //when we want to do this kind of test. We only want to decrement the count //after a callback/errback has finished, since the callback/errback should be //considered as part of finishing a request. var _pubCount = 0; var _checkPubCount = function(dfd){ if(_pubCount <= 0){ _pubCount = 0; if(cfg.ioPublish && _d.publish && (!dfd || dfd && dfd.ioArgs.args.ioPublish !== false)){ _d.publish("/dojo/io/stop"); } } }; 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(var i = 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); _pubCount -= 1; }else if(tif.ioCheck(dfd)){ _inFlight.splice(i--, 1); tif.resHandle(dfd); _pubCount -= 1; }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(); _pubCount -= 1; } } }; if(dojo.config.debugAtAllCosts){ func.call(this); }else{ try{ func.call(this); }catch(e){ dfd.errback(e); } } } } _checkPubCount(dfd); if(!_inFlight.length){ clearInterval(_inFlightIntvl); _inFlightIntvl = null; return; } } 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._ioNotifyStart = function(/*Deferred*/dfd){ // summary: // If dojo.publish is available, publish topics // about the start of a request queue and/or the // the beginning of request. // description: // Used by IO transports. An IO transport should // call this method before making the network connection. if(cfg.ioPublish && _d.publish && dfd.ioArgs.args.ioPublish !== false){ if(!_pubCount){ _d.publish("/dojo/io/start"); } _pubCount += 1; _d.publish("/dojo/io/send", [dfd]); } } _d._ioWatch = function(dfd, validCheck, ioCheck, resHandle){ // summary: // Watches the io request represented by dfd to see if it completes. // dfd: Deferred // The Deferred object to watch. // validCheck: Function // Function used to check if the IO request is still valid. Gets the dfd // object as its only argument. // ioCheck: Function // Function used to check if basic IO call worked. Gets the dfd // object as its only argument. // resHandle: Function // Function used to process response. Gets the dfd // object as its only argument. var args = dfd.ioArgs.args; if(args.timeout){ dfd.startTime = (new Date()).getTime(); } _inFlight.push({dfd: dfd, validCheck: validCheck, ioCheck: ioCheck, resHandle: resHandle}); if(!_inFlightIntvl){ _inFlightIntvl = setInterval(_watchInFlight, 50); } // handle sync requests //A weakness: async calls in flight //could have their handlers called as part of the //_watchInFlight call, before the sync's callbacks // are called. if(args.sync){ _watchInFlight(); } } 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. See `dojo.contentHandlers` // sync: Boolean? // false is default. Indicates whether the request should // be a synchronous (blocking) request. // headers: Object? // Additional HTTP headers to send in the request. // failOk: Boolean? // false is default. Indicates whether a request should be // allowed to fail (and therefore no console error message in // the event of a failure) this.handleAs = handleAs; this.sync = sync; this.headers = headers; this.failOk = failOk; } }); =====*/ 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); var ioArgs = dfd.ioArgs; //Pass the args to _xhrObj, to allow alternate XHR calls based specific calls, like //the one used for iframe proxies. var xhr = ioArgs.xhr = _d._xhrObj(ioArgs.args); //If XHR factory fails, cancel the deferred. if(!xhr){ dfd.cancel(); return dfd; } //Allow for specifying the HTTP body completely. if("postData" in args){ ioArgs.query = args.postData; }else if("putData" in args){ ioArgs.query = args.putData; }else if("rawBody" in args){ ioArgs.query = args.rawBody; }else if((arguments.length > 2 && !hasBody) || "POST|PUT".indexOf(method.toUpperCase()) == -1){ //Check for hasBody being passed. If no hasBody, //then only append query string if not a POST or PUT request. _d._ioAddQueryToUrl(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" 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 if(args.headers[hdr]){ //Only add header if it has a value. This allows for instnace, skipping //insertion of X-Requested-With by specifying empty value. xhr.setRequestHeader(hdr, args.headers[hdr]); } } } // FIXME: is this appropriate for all content types? xhr.setRequestHeader("Content-Type", args.contentType || _defaultContentType); if(!args.headers || !("X-Requested-With" in args.headers)){ xhr.setRequestHeader("X-Requested-With", "XMLHttpRequest"); } // FIXME: set other headers here! _d._ioNotifyStart(dfd); if(dojo.config.debugAtAllCosts){ xhr.send(ioArgs.query); }else{ try{ xhr.send(ioArgs.query); }catch(e){ 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"); /* Animation loosely package based on Dan Pupius' work, contributed under CLA: http://pupius.co.uk/js/Toolkit.Drawing.js */ (function(){ var d = dojo; var _mixin = d._mixin; 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; }; dojo._Line.prototype.getValue = function(/*float*/ n){ // summary: Returns the point on the line // n: a floating point number greater than 0 and less than 1 return ((this.end - this.start) * n) + this.start; // Decimal }; dojo.Animation = function(args){ // summary: // A generic animation class that fires callbacks into its handlers // object at various states. // description: // A generic animation class that fires callbacks into its handlers // object at various states. Nearly all dojo animation functions // return an instance of this method, usually without calling the // .play() method beforehand. Therefore, you will likely need to // call .play() on instances of `dojo.Animation` when one is // returned. // args: Object // The 'magic argument', mixing all the properties into this // animation instance. _mixin(this, args); if(d.isArray(this.curve)){ this.curve = new d._Line(this.curve[0], this.curve[1]); } }; // Alias to drop come 2.0: d._Animation = d.Animation; d.extend(dojo.Animation, { // 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: 1000/rate = fps) rate: 20 /* 50 fps */, /*===== // delay: Integer? // The time in milliseconds to wait before starting animation after it // has been .play()'ed delay: null, // beforeBegin: Event? // Synthetic event fired before a 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 time a `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, _getStep: function(){ var _p = this._percent, _e = this.easing ; return _e ? _e(_p) : _p; }, _fire: function(/*Event*/ evt, /*Array?*/ args){ // summary: // Convenience function. Fire event "evt" and pass it the // arguments specified in "args". // description: // Convenience function. Fire event "evt" and pass it the // arguments specified in "args". // Fires the callback in the scope of the `dojo.Animation` // instance. // evt: // The event to fire. // args: // The arguments to pass to the event. var a = args||[]; if(this[evt]){ if(d.config.debugAtAllCosts){ this[evt].apply(this, a); }else{ try{ this[evt].apply(this, a); }catch(e){ // squelch and log because we shouldn't allow exceptions in // synthetic event handlers to cause the internal timer to run // amuck, potentially pegging the CPU. I'm not a fan of this // squelch, but hopefully logging will make it clear what's // going on console.error("exception in animation handler for:", evt); console.error(e); } } } return this; // 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. // returns: dojo.Animation // The instance to allow chaining. var _t = this; if(_t._delayTimer){ _t._clearTimer(); } if(gotoStart){ _t._stopTimer(); _t._active = _t._paused = false; _t._percent = 0; }else if(_t._active && !_t._paused){ return _t; } _t._fire("beforeBegin", [_t.node]); var de = delay || _t.delay, _p = dojo.hitch(_t, "_play", gotoStart); if(de > 0){ _t._delayTimer = setTimeout(_p, de); return _t; } _p(); return _t; }, _play: function(gotoStart){ var _t = this; if(_t._delayTimer){ _t._clearTimer(); } _t._startTime = new Date().valueOf(); if(_t._paused){ _t._startTime -= _t.duration * _t._percent; } _t._active = true; _t._paused = false; var value = _t.curve.getValue(_t._getStep()); if(!_t._percent){ if(!_t._startRepeatCount){ _t._startRepeatCount = _t.repeat; } _t._fire("onBegin", [value]); } _t._fire("onPlay", [value]); _t._cycle(); return _t; // dojo.Animation }, pause: function(){ // summary: Pauses a running animation. var _t = this; if(_t._delayTimer){ _t._clearTimer(); } _t._stopTimer(); if(!_t._active){ return _t; /*dojo.Animation*/ } _t._paused = true; _t._fire("onPause", [_t.curve.getValue(_t._getStep())]); return _t; // dojo.Animation }, gotoPercent: function(/*Decimal*/ percent, /*Boolean?*/ andPlay){ // summary: // Sets the progress of the animation. // percent: // A percentage in decimal notation (between and including 0.0 and 1.0). // andPlay: // If true, play the animation after setting the progress. var _t = this; _t._stopTimer(); _t._active = _t._paused = true; _t._percent = percent; if(andPlay){ _t.play(); } return _t; // dojo.Animation }, stop: function(/*boolean?*/ gotoEnd){ // summary: Stops a running animation. // gotoEnd: If true, the animation will end. var _t = this; if(_t._delayTimer){ _t._clearTimer(); } if(!_t._timer){ return _t; /* dojo.Animation */ } _t._stopTimer(); if(gotoEnd){ _t._percent = 1; } _t._fire("onStop", [_t.curve.getValue(_t._getStep())]); _t._active = _t._paused = false; return _t; // dojo.Animation }, status: function(){ // summary: // Returns a string token representation of the status of // the animation, one of: "paused", "playing", "stopped" if(this._active){ return this._paused ? "paused" : "playing"; // String } return "stopped"; // String }, _cycle: function(){ var _t = this; if(_t._active){ var curr = new Date().valueOf(); var step = (curr - _t._startTime) / (_t.duration); if(step >= 1){ step = 1; } _t._percent = step; // Perform easing if(_t.easing){ step = _t.easing(step); } _t._fire("onAnimate", [_t.curve.getValue(step)]); if(_t._percent < 1){ _t._startTimer(); }else{ _t._active = false; if(_t.repeat > 0){ _t.repeat--; _t.play(null, true); }else if(_t.repeat == -1){ _t.play(null, true); }else{ if(_t._startRepeatCount){ _t.repeat = _t._startRepeatCount; _t._startRepeatCount = 0; } } _t._percent = 0; _t._fire("onEnd", [_t.node]); !_t.repeat && _t._stopTimer(); } } return _t; // dojo.Animation }, _clearTimer: function(){ // summary: Clear the play delay timer clearTimeout(this._delayTimer); delete this._delayTimer; } }); // the local timer, stubbed into all Animation instances var ctr = 0, timer = null, runner = { run: function(){} }; d.extend(d.Animation, { _startTimer: function(){ if(!this._timer){ this._timer = d.connect(runner, "run", this, "_cycle"); ctr++; } if(!timer){ timer = setInterval(d.hitch(runner, "run"), this.rate); } }, _stopTimer: function(){ if(this._timer){ d.disconnect(this._timer); this._timer = null; ctr--; } if(ctr <= 0){ clearInterval(timer); timer = null; ctr = 0; } } }); 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) args.node = d.byId(args.node); var fArgs = _mixin({ properties: {} }, args), props = (fArgs.properties.opacity = {}); props.start = !("start" in fArgs) ? function(){ return +d.style(fArgs.node, "opacity")||0; } : fArgs.start; props.end = fArgs.end; 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(_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(_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(var p 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(); } } }; PropLine.prototype.getValue = function(r){ var ret = {}; for(var p in this._properties){ var prop = this._properties[p], 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" : 0); } } 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 'units' 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. Defaults to 'px' if ommitted. // // example: // Animate width, height, and padding over 2 seconds... the // pedantic way: // | dojo.animateProperty({ node: node, duration:2000, // | properties: { // | width: { start: '200', end: '400', units:"px" }, // | height: { start:'200', end: '400', units:"px" }, // | paddingTop: { start:'5', end:'50', units:"px" } // | } // | }).play(); // Note 'paddingTop' is used over 'padding-top'. Multi-name CSS properties // are written using "mixed case", as the hyphen is illegal as an object key. // // example: // Plug in a different easing function and register a callback for // when the animation ends. Easing functions accept values between // zero and one and return a value on that basis. In this case, an // exponential-in curve. // | 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(node){ // | // called when the animation finishes. The animation // | // target is passed to this function // | } // | }).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(){ // | console.log("animation ended"); // | }); // | // play the animation now: // | anim.play(); // // example: // Each property can be a function whose return value is substituted along. // Additionally, each measurement (eg: start, end) can be a function. The node // reference is passed direcly to callbacks. // | dojo.animateProperty({ // | node:"mine", // | properties:{ // | height:function(node){ // | // shrink this node by 50% // | return dojo.position(node).h / 2 // | }, // | width:{ // | start:function(node){ return 100; }, // | end:function(node){ return 200; } // | } // | } // | }).play(); // var n = args.node = d.byId(args.node); if(!args.easing){ args.easing = d._defaultEasing; } var anim = new d.Animation(args); d.connect(anim, "beforeBegin", anim, function(){ var pm = {}; for(var p in this.properties){ // Make shallow copy of properties into pm because we overwrite // some values below. In particular if start/end are functions // we don't want to overwrite them or the functions won't be // called if the animation is reused. if(p == "width" || p == "height"){ this.node.display = "block"; } var prop = this.properties[p]; if(d.isFunction(prop)){ prop = prop(n); } prop = pm[p] = _mixin({}, (d.isObject(prop) ? prop: { end: prop })); if(d.isFunction(prop.start)){ prop.start = prop.start(n); } if(d.isFunction(prop.end)){ prop.end = prop.end(n); } 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") ? +v : (isColor ? v : parseFloat(v)); } if(!("end" in prop)){ prop.end = getStyle(n, p); }else if(!("start" in prop)){ prop.start = getStyle(n, p); } if(isColor){ prop.start = new d.Color(prop.start); prop.end = new d.Color(prop.end); }else{ prop.start = (p == "opacity") ? +prop.start : parseFloat(prop.start); } } this.curve = new PropLine(pm); }); d.connect(anim, "onAnimate", d.hitch(d, "style", anim.node)); return anim; // dojo.Animation }; 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({ // dojo.Animation 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. dojo.forEach(dojo.config.require, function(i){ dojo["require"](i); }); } //INSERT dojo.i18n._preloadLocalizations HERE //Check if document already complete, and if so, just trigger page load //listeners. NOTE: does not work with Firefox before 3.6. To support //those browsers, set djConfig.afterOnLoad = true when you know Dojo is added //after page load. 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. if(dojo.isBrowser && (document.readyState === "complete" || dojo.config.afterOnLoad)){ window.setTimeout(dojo._loadInit, 100); } })();