/* 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