/*
Copyright (c) 2004-2010, The Dojo Foundation All Rights Reserved.
Available via Academic Free License >= 2.1 OR the modified BSD license.
see: http://dojotoolkit.org/license for details
*/
/*
This is an optimized version of Dojo, built for deployment and not for
development. To get sources and documentation, please visit:
http://dojotoolkit.org
*/
;(function(){
/*
dojo, dijit, and dojox must always be the first three, and in that order.
djConfig.scopeMap = [
["dojo", "fojo"],
["dijit", "fijit"],
["dojox", "fojox"]
]
*/
/**Build will replace this comment with a scoped djConfig **/
//The null below can be relaced by a build-time value used instead of djConfig.scopeMap.
var sMap = null;
//See if new scopes need to be defined.
if((sMap || (typeof djConfig != "undefined" && djConfig.scopeMap)) && (typeof window != "undefined")){
var scopeDef = "", scopePrefix = "", scopeSuffix = "", scopeMap = {}, scopeMapRev = {};
sMap = sMap || djConfig.scopeMap;
for(var i = 0; i < sMap.length; i++){
//Make local variables, then global variables that use the locals.
var newScope = sMap[i];
scopeDef += "var " + newScope[0] + " = {}; " + newScope[1] + " = " + newScope[0] + ";" + newScope[1] + "._scopeName = '" + newScope[1] + "';";
scopePrefix += (i == 0 ? "" : ",") + newScope[0];
scopeSuffix += (i == 0 ? "" : ",") + newScope[1];
scopeMap[newScope[0]] = newScope[1];
scopeMapRev[newScope[1]] = newScope[0];
}
eval(scopeDef + "dojo._scopeArgs = [" + scopeSuffix + "];");
dojo._scopePrefixArgs = scopePrefix;
dojo._scopePrefix = "(function(" + scopePrefix + "){";
dojo._scopeSuffix = "})(" + scopeSuffix + ")";
dojo._scopeMap = scopeMap;
dojo._scopeMapRev = scopeMapRev;
}
/*=====
// note:
// 'djConfig' does not exist under 'dojo.*' so that it can be set before the
// 'dojo' variable exists.
// note:
// Setting any of these variables *after* the library has loaded does
// nothing at all.
djConfig = {
// summary:
// Application code can set the global 'djConfig' prior to loading
// the library to override certain global settings for how dojo works.
//
// isDebug: Boolean
// Defaults to `false`. If set to `true`, ensures that Dojo provides
// extended debugging feedback via Firebug. If Firebug is not available
// on your platform, setting `isDebug` to `true` will force Dojo to
// pull in (and display) the version of Firebug Lite which is
// integrated into the Dojo distribution, thereby always providing a
// debugging/logging console when `isDebug` is enabled. Note that
// Firebug's `console.*` methods are ALWAYS defined by Dojo. If
// `isDebug` is false and you are on a platform without Firebug, these
// methods will be defined as no-ops.
isDebug: false,
// debugAtAllCosts: Boolean
// Defaults to `false`. If set to `true`, this triggers an alternate
// mode of the package system in which dependencies are detected and
// only then are resources evaluated in dependency order via
// `
//
// This type of syntax works with both xdomain and normal loaders, so it is good
// practice to always use this idiom for on-the-fly code loading and in HTML script
// blocks. If at some point you change loaders and where the code is loaded from,
// it will all still work.
//
// More on how dojo.require
// `dojo.require("A.B")` first checks to see if symbol A.B is
// defined. If it is, it is simply returned (nothing to do).
//
// If it is not defined, it will look for `A/B.js` in the script root
// directory.
//
// `dojo.require` throws an excpetion if it cannot find a file
// to load, or if the symbol `A.B` is not defined after loading.
//
// It returns the object `A.B`, but note the caveats above about on-the-fly loading and
// HTML script blocks when the xdomain loader is loading a module.
//
// `dojo.require()` does nothing about importing symbols into
// the current namespace. It is presumed that the caller will
// take care of that. For example, to import all symbols into a
// local block, you might write:
//
// | with (dojo.require("A.B")) {
// | ...
// | }
//
// And to import just the leaf symbol to a local variable:
//
// | var B = dojo.require("A.B");
// | ...
// returns: the required namespace object
omitModuleCheck = d._global_omit_module_check || omitModuleCheck;
//Check if it is already loaded.
var module = d._loadedModules[moduleName];
if(module){
return module;
}
// convert periods to slashes
var relpath = d._getModuleSymbols(moduleName).join("/") + '.js';
var modArg = !omitModuleCheck ? moduleName : null;
var ok = d._loadPath(relpath, modArg);
if(!ok && !omitModuleCheck){
throw new Error("Could not load '" + moduleName + "'; last tried '" + relpath + "'");
}
// check that the symbol was defined
// Don't bother if we're doing xdomain (asynchronous) loading.
if(!omitModuleCheck && !d._isXDomain){
// pass in false so we can give better error
module = d._loadedModules[moduleName];
if(!module){
throw new Error("symbol '" + moduleName + "' is not defined after loading '" + relpath + "'");
}
}
return module;
}
dojo.provide = function(/*String*/ resourceName){
// summary:
// Register a resource with the package system. Works in conjunction with `dojo.require`
//
// description:
// Each javascript source file is called a resource. When a
// resource is loaded by the browser, `dojo.provide()` registers
// that it has been loaded.
//
// Each javascript source file must have at least one
// `dojo.provide()` call at the top of the file, corresponding to
// the file name. For example, `js/dojo/foo.js` must have
// `dojo.provide("dojo.foo");` before any calls to
// `dojo.require()` are made.
//
// For backwards compatibility reasons, in addition to registering
// the resource, `dojo.provide()` also ensures that the javascript
// object for the module exists. For example,
// `dojo.provide("dojox.data.FlickrStore")`, in addition to
// registering that `FlickrStore.js` is a resource for the
// `dojox.data` module, will ensure that the `dojox.data`
// javascript object exists, so that calls like
// `dojo.data.foo = function(){ ... }` don't fail.
//
// In the case of a build where multiple javascript source files
// are combined into one bigger file (similar to a .lib or .jar
// file), that file may contain multiple dojo.provide() calls, to
// note that it includes multiple resources.
//
// resourceName: String
// A dot-sperated string identifying a resource.
//
// example:
// Safely create a `my` object, and make dojo.require("my.CustomModule") work
// | dojo.provide("my.CustomModule");
//Make sure we have a string.
resourceName = resourceName + "";
return (d._loadedModules[resourceName] = d.getObject(resourceName, true)); // Object
}
//Start of old bootstrap2:
dojo.platformRequire = function(/*Object*/modMap){
// summary:
// require one or more modules based on which host environment
// Dojo is currently operating in
// description:
// This method takes a "map" of arrays which one can use to
// optionally load dojo modules. The map is indexed by the
// possible dojo.name_ values, with two additional values:
// "default" and "common". The items in the "default" array will
// be loaded if none of the other items have been choosen based on
// dojo.name_, set by your host environment. The items in the
// "common" array will *always* be loaded, regardless of which
// list is chosen.
// example:
// | dojo.platformRequire({
// | browser: [
// | "foo.sample", // simple module
// | "foo.test",
// | ["foo.bar.baz", true] // skip object check in _loadModule (dojo.require)
// | ],
// | default: [ "foo.sample._base" ],
// | common: [ "important.module.common" ]
// | });
var common = modMap.common || [];
var result = common.concat(modMap[d._name] || modMap["default"] || []);
for(var x=0; x
// |
d._modulePrefixes[module] = { name: module, value: prefix };
}
dojo.requireLocalization = function(/*String*/moduleName, /*String*/bundleName, /*String?*/locale, /*String?*/availableFlatLocales){
// summary:
// Declares translated resources and loads them if necessary, in the
// same style as dojo.require. Contents of the resource bundle are
// typically strings, but may be any name/value pair, represented in
// JSON format. See also `dojo.i18n.getLocalization`.
//
// description:
// Load translated resource bundles provided underneath the "nls"
// directory within a package. Translated resources may be located in
// different packages throughout the source tree.
//
// Each directory is named for a locale as specified by RFC 3066,
// (http://www.ietf.org/rfc/rfc3066.txt), normalized in lowercase.
// Note that the two bundles in the example do not define all the
// same variants. For a given locale, bundles will be loaded for
// that locale and all more general locales above it, including a
// fallback at the root directory. For example, a declaration for
// the "de-at" locale will first load `nls/de-at/bundleone.js`,
// then `nls/de/bundleone.js` and finally `nls/bundleone.js`. The
// data will be flattened into a single Object so that lookups
// will follow this cascading pattern. An optional build step can
// preload the bundles to avoid data redundancy and the multiple
// network hits normally required to load these resources.
//
// moduleName:
// name of the package containing the "nls" directory in which the
// bundle is found
//
// bundleName:
// bundle name, i.e. the filename without the '.js' suffix. Using "nls" as a
// a bundle name is not supported, since "nls" is the name of the folder
// that holds bundles. Using "nls" as the bundle name will cause problems
// with the custom build.
//
// locale:
// the locale to load (optional) By default, the browser's user
// locale as defined by dojo.locale
//
// availableFlatLocales:
// A comma-separated list of the available, flattened locales for this
// bundle. This argument should only be set by the build process.
//
// example:
// A particular widget may define one or more resource bundles,
// structured in a program as follows, where moduleName is
// mycode.mywidget and bundleNames available include bundleone and
// bundletwo:
// | ...
// | mycode/
// | mywidget/
// | nls/
// | bundleone.js (the fallback translation, English in this example)
// | bundletwo.js (also a fallback translation)
// | de/
// | bundleone.js
// | bundletwo.js
// | de-at/
// | bundleone.js
// | en/
// | (empty; use the fallback translation)
// | en-us/
// | bundleone.js
// | en-gb/
// | bundleone.js
// | es/
// | bundleone.js
// | bundletwo.js
// | ...etc
// | ...
//
d.require("dojo.i18n");
d.i18n._requireLocalization.apply(d.hostenv, arguments);
};
var ore = new RegExp("^(([^:/?#]+):)?(//([^/?#]*))?([^?#]*)(\\?([^#]*))?(#(.*))?$"),
ire = new RegExp("^((([^\\[:]+):)?([^@]+)@)?(\\[([^\\]]+)\\]|([^\\[:]*))(:([0-9]+))?$");
dojo._Url = function(/*dojo._Url|String...*/){
// summary:
// Constructor to create an object representing a URL.
// It is marked as private, since we might consider removing
// or simplifying it.
// description:
// Each argument is evaluated in order relative to the next until
// a canonical uri is produced. To get an absolute Uri relative to
// the current document use:
// new dojo._Url(document.baseURI, url)
var n = null,
_a = arguments,
uri = [_a[0]];
// resolve uri components relative to each other
for(var i = 1; i<_a.length; i++){
if(!_a[i]){ continue; }
// Safari doesn't support this.constructor so we have to be explicit
// FIXME: Tracked (and fixed) in Webkit bug 3537.
// http://bugs.webkit.org/show_bug.cgi?id=3537
var relobj = new d._Url(_a[i]+""),
uriobj = new d._Url(uri[0]+"");
if(
relobj.path == "" &&
!relobj.scheme &&
!relobj.authority &&
!relobj.query
){
if(relobj.fragment != n){
uriobj.fragment = relobj.fragment;
}
relobj = uriobj;
}else if(!relobj.scheme){
relobj.scheme = uriobj.scheme;
if(!relobj.authority){
relobj.authority = uriobj.authority;
if(relobj.path.charAt(0) != "/"){
var path = uriobj.path.substring(0,
uriobj.path.lastIndexOf("/") + 1) + relobj.path;
var segs = path.split("/");
for(var j = 0; j < segs.length; j++){
if(segs[j] == "."){
// flatten "./" references
if(j == segs.length - 1){
segs[j] = "";
}else{
segs.splice(j, 1);
j--;
}
}else if(j > 0 && !(j == 1 && segs[0] == "") &&
segs[j] == ".." && segs[j-1] != ".."){
// flatten "../" references
if(j == (segs.length - 1)){
segs.splice(j, 1);
segs[j - 1] = "";
}else{
segs.splice(j - 1, 2);
j -= 2;
}
}
}
relobj.path = segs.join("/");
}
}
}
uri = [];
if(relobj.scheme){
uri.push(relobj.scheme, ":");
}
if(relobj.authority){
uri.push("//", relobj.authority);
}
uri.push(relobj.path);
if(relobj.query){
uri.push("?", relobj.query);
}
if(relobj.fragment){
uri.push("#", relobj.fragment);
}
}
this.uri = uri.join("");
// break the uri into its main components
var r = this.uri.match(ore);
this.scheme = r[2] || (r[1] ? "" : n);
this.authority = r[4] || (r[3] ? "" : n);
this.path = r[5]; // can never be undefined
this.query = r[7] || (r[6] ? "" : n);
this.fragment = r[9] || (r[8] ? "" : n);
if(this.authority != n){
// server based naming authority
r = this.authority.match(ire);
this.user = r[3] || n;
this.password = r[4] || n;
this.host = r[6] || r[7]; // ipv6 || ipv4
this.port = r[9] || n;
}
}
dojo._Url.prototype.toString = function(){ return this.uri; };
dojo.moduleUrl = function(/*String*/module, /*dojo._Url||String*/url){
// summary:
// Returns a `dojo._Url` object relative to a module.
// example:
// | var pngPath = dojo.moduleUrl("acme","images/small.png");
// | console.dir(pngPath); // list the object properties
// | // create an image and set it's source to pngPath's value:
// | var img = document.createElement("img");
// | // NOTE: we assign the string representation of the url object
// | img.src = pngPath.toString();
// | // add our image to the document
// | dojo.body().appendChild(img);
// example:
// you may de-reference as far as you like down the package
// hierarchy. This is sometimes handy to avoid lenghty relative
// urls or for building portable sub-packages. In this example,
// the `acme.widget` and `acme.util` directories may be located
// under different roots (see `dojo.registerModulePath`) but the
// the modules which reference them can be unaware of their
// relative locations on the filesystem:
// | // somewhere in a configuration block
// | dojo.registerModulePath("acme.widget", "../../acme/widget");
// | dojo.registerModulePath("acme.util", "../../util");
// |
// | // ...
// |
// | // code in a module using acme resources
// | var tmpltPath = dojo.moduleUrl("acme.widget","templates/template.html");
// | var dataPath = dojo.moduleUrl("acme.util","resources/data.json");
var loc = d._getModuleSymbols(module).join('/');
if(!loc){ return null; }
if(loc.lastIndexOf("/") != loc.length-1){
loc += "/";
}
//If the path is an absolute path (starts with a / or is on another
//domain/xdomain) then don't add the baseUrl.
var colonIndex = loc.indexOf(":");
if(loc.charAt(0) != "/" && (colonIndex == -1 || colonIndex > loc.indexOf("/"))){
loc = d.baseUrl + loc;
}
return new d._Url(loc, url); // dojo._Url
}
})();
/*=====
dojo.isBrowser = {
// example:
// | if(dojo.isBrowser){ ... }
};
dojo.isFF = {
// example:
// | if(dojo.isFF > 1){ ... }
};
dojo.isIE = {
// example:
// | if(dojo.isIE > 6){
// | // we are IE7
// | }
};
dojo.isSafari = {
// example:
// | if(dojo.isSafari){ ... }
// example:
// Detect iPhone:
// | if(dojo.isSafari && navigator.userAgent.indexOf("iPhone") != -1){
// | // we are iPhone. Note, iPod touch reports "iPod" above and fails this test.
// | }
};
dojo = {
// isBrowser: Boolean
// True if the client is a web-browser
isBrowser: true,
// isFF: Number | undefined
// Version as a Number if client is FireFox. undefined otherwise. Corresponds to
// major detected FireFox version (1.5, 2, 3, etc.)
isFF: 2,
// isIE: Number | undefined
// Version as a Number if client is MSIE(PC). undefined otherwise. Corresponds to
// major detected IE version (6, 7, 8, etc.)
isIE: 6,
// isKhtml: Number | undefined
// Version as a Number if client is a KHTML browser. undefined otherwise. Corresponds to major
// detected version.
isKhtml: 0,
// isWebKit: Number | undefined
// Version as a Number if client is a WebKit-derived browser (Konqueror,
// Safari, Chrome, etc.). undefined otherwise.
isWebKit: 0,
// isMozilla: Number | undefined
// Version as a Number if client is a Mozilla-based browser (Firefox,
// SeaMonkey). undefined otherwise. Corresponds to major detected version.
isMozilla: 0,
// isOpera: Number | undefined
// Version as a Number if client is Opera. undefined otherwise. Corresponds to
// major detected version.
isOpera: 0,
// isSafari: Number | undefined
// Version as a Number if client is Safari or iPhone. undefined otherwise.
isSafari: 0,
// isChrome: Number | undefined
// Version as a Number if client is Chrome browser. undefined otherwise.
isChrome: 0
// isMac: Boolean
// True if the client runs on Mac
}
=====*/
if(typeof window != 'undefined'){
dojo.isBrowser = true;
dojo._name = "browser";
// attempt to figure out the path to dojo if it isn't set in the config
(function(){
var d = dojo;
// this is a scope protection closure. We set browser versions and grab
// the URL we were loaded from here.
// grab the node we were loaded from
if(document && document.getElementsByTagName){
var scripts = document.getElementsByTagName("script");
var rePkg = /dojo(\.xd)?\.js(\W|$)/i;
for(var i = 0; i < scripts.length; i++){
var src = scripts[i].getAttribute("src");
if(!src){ continue; }
var m = src.match(rePkg);
if(m){
// find out where we came from
if(!d.config.baseUrl){
d.config.baseUrl = src.substring(0, m.index);
}
// and find out if we need to modify our behavior
var cfg = scripts[i].getAttribute("djConfig");
if(cfg){
var cfgo = eval("({ "+cfg+" })");
for(var x in cfgo){
dojo.config[x] = cfgo[x];
}
}
break; // "first Dojo wins"
}
}
}
d.baseUrl = d.config.baseUrl;
// fill in the rendering support information in dojo.render.*
var n = navigator;
var dua = n.userAgent,
dav = n.appVersion,
tv = parseFloat(dav);
if(dua.indexOf("Opera") >= 0){ d.isOpera = tv; }
if(dua.indexOf("AdobeAIR") >= 0){ d.isAIR = 1; }
d.isKhtml = (dav.indexOf("Konqueror") >= 0) ? tv : 0;
d.isWebKit = parseFloat(dua.split("WebKit/")[1]) || undefined;
d.isChrome = parseFloat(dua.split("Chrome/")[1]) || undefined;
d.isMac = dav.indexOf("Macintosh") >= 0;
// safari detection derived from:
// http://developer.apple.com/internet/safari/faq.html#anchor2
// http://developer.apple.com/internet/safari/uamatrix.html
var index = Math.max(dav.indexOf("WebKit"), dav.indexOf("Safari"), 0);
if(index && !dojo.isChrome){
// try to grab the explicit Safari version first. If we don't get
// one, look for less than 419.3 as the indication that we're on something
// "Safari 2-ish".
d.isSafari = parseFloat(dav.split("Version/")[1]);
if(!d.isSafari || parseFloat(dav.substr(index + 7)) <= 419.3){
d.isSafari = 2;
}
}
if(dua.indexOf("Gecko") >= 0 && !d.isKhtml && !d.isWebKit){ d.isMozilla = d.isMoz = tv; }
if(d.isMoz){
//We really need to get away from this. Consider a sane isGecko approach for the future.
d.isFF = parseFloat(dua.split("Firefox/")[1] || dua.split("Minefield/")[1]) || undefined;
}
if(document.all && !d.isOpera){
d.isIE = parseFloat(dav.split("MSIE ")[1]) || undefined;
//In cases where the page has an HTTP header or META tag with
//X-UA-Compatible, then it is in emulation mode.
//Make sure isIE reflects the desired version.
//document.documentMode of 5 means quirks mode.
//Only switch the value if documentMode's major version
//is different from isIE's major version.
var mode = document.documentMode;
if(mode && mode != 5 && Math.floor(d.isIE) != mode){
d.isIE = mode;
}
}
//Workaround to get local file loads of dojo to work on IE 7
//by forcing to not use native xhr.
if(dojo.isIE && window.location.protocol === "file:"){
dojo.config.ieForceActiveXXhr=true;
}
d.isQuirks = document.compatMode == "BackCompat";
// TODO: is the HTML LANG attribute relevant?
d.locale = dojo.config.locale || (d.isIE ? n.userLanguage : n.language).toLowerCase();
// These are in order of decreasing likelihood; this will change in time.
d._XMLHTTP_PROGIDS = ['Msxml2.XMLHTTP', 'Microsoft.XMLHTTP', 'Msxml2.XMLHTTP.4.0'];
d._xhrObj = function(){
// summary:
// does the work of portably generating a new XMLHTTPRequest object.
var http, last_e;
if(!dojo.isIE || !dojo.config.ieForceActiveXXhr){
try{ http = new XMLHttpRequest(); }catch(e){}
}
if(!http){
for(var i=0; i<3; ++i){
var progid = d._XMLHTTP_PROGIDS[i];
try{
http = new ActiveXObject(progid);
}catch(e){
last_e = e;
}
if(http){
d._XMLHTTP_PROGIDS = [progid]; // so faster next time
break;
}
}
}
if(!http){
throw new Error("XMLHTTP not available: "+last_e);
}
return http; // XMLHTTPRequest instance
}
d._isDocumentOk = function(http){
var stat = http.status || 0,
lp = location.protocol;
return (stat >= 200 && stat < 300) || // Boolean
stat == 304 || // allow any 2XX response code
stat == 1223 || // get it out of the cache
// Internet Explorer mangled the status code OR we're Titanium/browser chrome/chrome extension requesting a local file
(!stat && (lp == "file:" || lp == "chrome:" || lp == "chrome-extension:" || lp == "app:") );
}
//See if base tag is in use.
//This is to fix http://trac.dojotoolkit.org/ticket/3973,
//but really, we need to find out how to get rid of the dojo._Url reference
//below and still have DOH work with the dojo.i18n test following some other
//test that uses the test frame to load a document (trac #2757).
//Opera still has problems, but perhaps a larger issue of base tag support
//with XHR requests (hasBase is true, but the request is still made to document
//path, not base path).
var owloc = window.location+"";
var base = document.getElementsByTagName("base");
var hasBase = (base && base.length > 0);
d._getText = function(/*URI*/ uri, /*Boolean*/ fail_ok){
// summary: Read the contents of the specified uri and return those contents.
// uri:
// A relative or absolute uri. If absolute, it still must be in
// the same "domain" as we are.
// fail_ok:
// Default false. If fail_ok and loading fails, return null
// instead of throwing.
// returns: The response text. null is returned when there is a
// failure and failure is okay (an exception otherwise)
// NOTE: must be declared before scope switches ie. this._xhrObj()
var http = d._xhrObj();
if(!hasBase && dojo._Url){
uri = (new dojo._Url(owloc, uri)).toString();
}
if(d.config.cacheBust){
//Make sure we have a string before string methods are used on uri
uri += "";
uri += (uri.indexOf("?") == -1 ? "?" : "&") + String(d.config.cacheBust).replace(/\W+/g,"");
}
http.open('GET', uri, false);
try{
http.send(null);
if(!d._isDocumentOk(http)){
var err = Error("Unable to load "+uri+" status:"+ http.status);
err.status = http.status;
err.responseText = http.responseText;
throw err;
}
}catch(e){
if(fail_ok){ return null; } // null
// rethrow the exception
throw e;
}
return http.responseText; // String
}
var _w = window;
var _handleNodeEvent = function(/*String*/evtName, /*Function*/fp){
// summary:
// non-destructively adds the specified function to the node's
// evtName handler.
// evtName: should be in the form "onclick" for "onclick" handlers.
// Make sure you pass in the "on" part.
var _a = _w.attachEvent || _w.addEventListener;
evtName = _w.attachEvent ? evtName : evtName.substring(2);
_a(evtName, function(){
fp.apply(_w, arguments);
}, false);
};
d._windowUnloaders = [];
d.windowUnloaded = function(){
// summary:
// signal fired by impending window destruction. You may use
// dojo.addOnWindowUnload() to register a listener for this
// event. NOTE: if you wish to dojo.connect() to this method
// to perform page/application cleanup, be aware that this
// event WILL NOT fire if no handler has been registered with
// dojo.addOnWindowUnload. This behavior started in Dojo 1.3.
// Previous versions always triggered dojo.windowUnloaded. See
// dojo.addOnWindowUnload for more info.
var mll = d._windowUnloaders;
while(mll.length){
(mll.pop())();
}
d = null;
};
var _onWindowUnloadAttached = 0;
d.addOnWindowUnload = function(/*Object?|Function?*/obj, /*String|Function?*/functionName){
// summary:
// registers a function to be triggered when window.onunload
// fires.
// description:
// The first time that addOnWindowUnload is called Dojo
// will register a page listener to trigger your unload
// handler with. Note that registering these handlers may
// destory "fastback" page caching in browsers that support
// it. Be careful trying to modify the DOM or access
// JavaScript properties during this phase of page unloading:
// they may not always be available. Consider
// dojo.addOnUnload() if you need to modify the DOM or do
// heavy JavaScript work since it fires at the eqivalent of
// the page's "onbeforeunload" event.
// example:
// | dojo.addOnWindowUnload(functionPointer)
// | dojo.addOnWindowUnload(object, "functionName");
// | dojo.addOnWindowUnload(object, function(){ /* ... */});
d._onto(d._windowUnloaders, obj, functionName);
if(!_onWindowUnloadAttached){
_onWindowUnloadAttached = 1;
_handleNodeEvent("onunload", d.windowUnloaded);
}
};
var _onUnloadAttached = 0;
d.addOnUnload = function(/*Object?|Function?*/obj, /*String|Function?*/functionName){
// summary:
// registers a function to be triggered when the page unloads.
// description:
// The first time that addOnUnload is called Dojo will
// register a page listener to trigger your unload handler
// with.
//
// In a browser enviroment, the functions will be triggered
// during the window.onbeforeunload event. Be careful of doing
// too much work in an unload handler. onbeforeunload can be
// triggered if a link to download a file is clicked, or if
// the link is a javascript: link. In these cases, the
// onbeforeunload event fires, but the document is not
// actually destroyed. So be careful about doing destructive
// operations in a dojo.addOnUnload callback.
//
// Further note that calling dojo.addOnUnload will prevent
// browsers from using a "fast back" cache to make page
// loading via back button instantaneous.
// example:
// | dojo.addOnUnload(functionPointer)
// | dojo.addOnUnload(object, "functionName")
// | dojo.addOnUnload(object, function(){ /* ... */});
d._onto(d._unloaders, obj, functionName);
if(!_onUnloadAttached){
_onUnloadAttached = 1;
_handleNodeEvent("onbeforeunload", dojo.unloaded);
}
};
})();
//START DOMContentLoaded
dojo._initFired = false;
dojo._loadInit = function(e){
if(dojo._scrollIntervalId){
clearInterval(dojo._scrollIntervalId);
dojo._scrollIntervalId = 0;
}
if(!dojo._initFired){
dojo._initFired = true;
//Help out IE to avoid memory leak.
if(!dojo.config.afterOnLoad && window.detachEvent){
window.detachEvent("onload", dojo._loadInit);
}
if(dojo._inFlightCount == 0){
dojo._modulesLoaded();
}
}
}
if(!dojo.config.afterOnLoad){
if(document.addEventListener){
//Standards. Hooray! Assumption here that if standards based,
//it knows about DOMContentLoaded. It is OK if it does not, the fall through
//to window onload should be good enough.
document.addEventListener("DOMContentLoaded", dojo._loadInit, false);
window.addEventListener("load", dojo._loadInit, false);
}else if(window.attachEvent){
window.attachEvent("onload", dojo._loadInit);
//DOMContentLoaded approximation. Diego Perini found this MSDN article
//that indicates doScroll is available after DOM ready, so do a setTimeout
//to check when it is available.
//http://msdn.microsoft.com/en-us/library/ms531426.aspx
if(!dojo.config.skipIeDomLoaded && self === self.top){
dojo._scrollIntervalId = setInterval(function (){
try{
//When dojo is loaded into an iframe in an IE HTML Application
//(HTA), such as in a selenium test, javascript in the iframe
//can't see anything outside of it, so self===self.top is true,
//but the iframe is not the top window and doScroll will be
//available before document.body is set. Test document.body
//before trying the doScroll trick
if(document.body){
document.documentElement.doScroll("left");
dojo._loadInit();
}
}catch (e){}
}, 30);
}
}
}
if(dojo.isIE){
try{
(function(){
document.namespaces.add("v", "urn:schemas-microsoft-com:vml");
var vmlElems = ["*", "group", "roundrect", "oval", "shape", "rect", "imagedata", "path", "textpath", "text"],
i = 0, l = 1, s = document.createStyleSheet();
if(dojo.isIE >= 8){
i = 1;
l = vmlElems.length;
}
for(; i < l; ++i){
s.addRule("v\\:" + vmlElems[i], "behavior:url(#default#VML); display:inline-block");
}
})();
}catch(e){}
}
//END DOMContentLoaded
/*
OpenAjax.subscribe("OpenAjax", "onload", function(){
if(dojo._inFlightCount == 0){
dojo._modulesLoaded();
}
});
OpenAjax.subscribe("OpenAjax", "onunload", function(){
dojo.unloaded();
});
*/
} //if (typeof window != 'undefined')
//Register any module paths set up in djConfig. Need to do this
//in the hostenvs since hostenv_browser can read djConfig from a
//script tag's attribute.
(function(){
var mp = dojo.config["modulePaths"];
if(mp){
for(var param in mp){
dojo.registerModulePath(param, mp[param]);
}
}
})();
//Load debug code if necessary.
if(dojo.config.isDebug){
dojo.require("dojo._firebug.firebug");
}
if(dojo.config.debugAtAllCosts){
dojo.config.useXDomain = true;
dojo.require("dojo._base._loader.loader_xd");
dojo.require("dojo._base._loader.loader_debug");
dojo.require("dojo.i18n");
}
if(!dojo._hasResource["dojo._base.lang"]){ //_hasResource checks added by build. Do not use _hasResource directly in your code.
dojo._hasResource["dojo._base.lang"] = true;
dojo.provide("dojo._base.lang");
(function(){
var d = dojo, opts = Object.prototype.toString;
// Crockford (ish) functions
dojo.isString = function(/*anything*/ it){
// summary:
// Return true if it is a String
return (typeof it == "string" || it instanceof String); // Boolean
}
dojo.isArray = function(/*anything*/ it){
// summary:
// Return true if it is an Array.
// Does not work on Arrays created in other windows.
return it && (it instanceof Array || typeof it == "array"); // Boolean
}
dojo.isFunction = function(/*anything*/ it){
// summary:
// Return true if it is a Function
return opts.call(it) === "[object Function]";
};
dojo.isObject = function(/*anything*/ it){
// summary:
// Returns true if it is a JavaScript object (or an Array, a Function
// or null)
return it !== undefined &&
(it === null || typeof it == "object" || d.isArray(it) || d.isFunction(it)); // Boolean
}
dojo.isArrayLike = function(/*anything*/ it){
// summary:
// similar to dojo.isArray() but more permissive
// description:
// Doesn't strongly test for "arrayness". Instead, settles for "isn't
// a string or number and has a length property". Arguments objects
// and DOM collections will return true when passed to
// dojo.isArrayLike(), but will return false when passed to
// dojo.isArray().
// returns:
// If it walks like a duck and quacks like a duck, return `true`
return it && it !== undefined && // Boolean
// keep out built-in constructors (Number, String, ...) which have length
// properties
!d.isString(it) && !d.isFunction(it) &&
!(it.tagName && it.tagName.toLowerCase() == 'form') &&
(d.isArray(it) || isFinite(it.length));
}
dojo.isAlien = function(/*anything*/ it){
// summary:
// Returns true if it is a built-in function or some other kind of
// oddball that *should* report as a function but doesn't
return it && !d.isFunction(it) && /\{\s*\[native code\]\s*\}/.test(String(it)); // Boolean
}
dojo.extend = function(/*Object*/ constructor, /*Object...*/ props){
// summary:
// Adds all properties and methods of props to constructor's
// prototype, making them available to all instances created with
// constructor.
for(var i=1, l=arguments.length; i 2){
return d._hitchArgs.apply(d, arguments); // Function
}
if(!method){
method = scope;
scope = null;
}
if(d.isString(method)){
scope = scope || d.global;
if(!scope[method]){ throw(['dojo.hitch: scope["', method, '"] is null (scope="', scope, '")'].join('')); }
return function(){ return scope[method].apply(scope, arguments || []); }; // Function
}
return !scope ? method : function(){ return method.apply(scope, arguments || []); }; // Function
}
/*=====
dojo.delegate = function(obj, props){
// summary:
// Returns a new object which "looks" to obj for properties which it
// does not have a value for. Optionally takes a bag of properties to
// seed the returned object with initially.
// description:
// This is a small implementaton of the Boodman/Crockford delegation
// pattern in JavaScript. An intermediate object constructor mediates
// the prototype chain for the returned object, using it to delegate
// down to obj for property lookup when object-local lookup fails.
// This can be thought of similarly to ES4's "wrap", save that it does
// not act on types but rather on pure objects.
// obj:
// The object to delegate to for properties not found directly on the
// return object or in props.
// props:
// an object containing properties to assign to the returned object
// returns:
// an Object of anonymous type
// example:
// | var foo = { bar: "baz" };
// | var thinger = dojo.delegate(foo, { thud: "xyzzy"});
// | thinger.bar == "baz"; // delegated to foo
// | foo.thud == undefined; // by definition
// | thinger.thud == "xyzzy"; // mixed in from props
// | foo.bar = "thonk";
// | thinger.bar == "thonk"; // still delegated to foo's bar
}
=====*/
dojo.delegate = dojo._delegate = (function(){
// boodman/crockford delegation w/ cornford optimization
function TMP(){}
return function(obj, props){
TMP.prototype = obj;
var tmp = new TMP();
TMP.prototype = null;
if(props){
d._mixin(tmp, props);
}
return tmp; // Object
}
})();
/*=====
dojo._toArray = function(obj, offset, startWith){
// summary:
// Converts an array-like object (i.e. arguments, DOMCollection) to an
// array. Returns a new Array with the elements of obj.
// obj: Object
// the object to "arrayify". We expect the object to have, at a
// minimum, a length property which corresponds to integer-indexed
// properties.
// offset: Number?
// the location in obj to start iterating from. Defaults to 0.
// Optional.
// startWith: Array?
// An array to pack with the properties of obj. If provided,
// properties in obj are appended at the end of startWith and
// startWith is the returned array.
}
=====*/
var efficient = function(obj, offset, startWith){
return (startWith||[]).concat(Array.prototype.slice.call(obj, offset||0));
};
var slow = function(obj, offset, startWith){
var arr = startWith||[];
for(var x = offset || 0; x < obj.length; x++){
arr.push(obj[x]);
}
return arr;
};
dojo._toArray =
d.isIE ? function(obj){
return ((obj.item) ? slow : efficient).apply(this, arguments);
} :
efficient;
dojo.partial = function(/*Function|String*/method /*, ...*/){
// summary:
// similar to hitch() except that the scope object is left to be
// whatever the execution context eventually becomes.
// description:
// Calling dojo.partial is the functional equivalent of calling:
// | dojo.hitch(null, funcName, ...);
var arr = [ null ];
return d.hitch.apply(d, arr.concat(d._toArray(arguments))); // Function
}
var extraNames = d._extraNames, extraLen = extraNames.length, empty = {};
dojo.clone = function(/*anything*/ o){
// summary:
// Clones objects (including DOM nodes) and all children.
// Warning: do not clone cyclic structures.
if(!o || typeof o != "object" || d.isFunction(o)){
// null, undefined, any non-object, or function
return o; // anything
}
if(o.nodeType && "cloneNode" in o){
// DOM Node
return o.cloneNode(true); // Node
}
if(o instanceof Date){
// Date
return new Date(o.getTime()); // Date
}
var r, i, l, s, name;
if(d.isArray(o)){
// array
r = [];
for(i = 0, l = o.length; i < l; ++i){
if(i in o){
r.push(d.clone(o[i]));
}
}
// we don't clone functions for performance reasons
// }else if(d.isFunction(o)){
// // function
// r = function(){ return o.apply(this, arguments); };
}else{
// generic objects
r = o.constructor ? new o.constructor() : {};
}
for(name in o){
// the "tobj" condition avoid copying properties in "source"
// inherited from Object.prototype. For example, if target has a custom
// toString() method, don't overwrite it with the toString() method
// that source inherited from Object.prototype
s = o[name];
if(!(name in r) || (r[name] !== s && (!(name in empty) || empty[name] !== s))){
r[name] = d.clone(s);
}
}
// IE doesn't recognize some custom functions in for..in
if(extraLen){
for(i = 0; i < extraLen; ++i){
name = extraNames[i];
s = o[name];
if(!(name in r) || (r[name] !== s && (!(name in empty) || empty[name] !== s))){
r[name] = s; // functions only, we don't clone them
}
}
}
return r; // Object
}
/*=====
dojo.trim = function(str){
// summary:
// Trims whitespace from both sides of the string
// str: String
// String to be trimmed
// returns: String
// Returns the trimmed string
// description:
// This version of trim() was selected for inclusion into the base due
// to its compact size and relatively good performance
// (see [Steven Levithan's blog](http://blog.stevenlevithan.com/archives/faster-trim-javascript)
// Uses String.prototype.trim instead, if available.
// The fastest but longest version of this function is located at
// dojo.string.trim()
return ""; // String
}
=====*/
dojo.trim = String.prototype.trim ?
function(str){ return str.trim(); } :
function(str){ return str.replace(/^\s\s*/, '').replace(/\s\s*$/, ''); };
/*=====
dojo.replace = function(tmpl, map, pattern){
// summary:
// Performs parameterized substitutions on a string. Throws an
// exception if any parameter is unmatched.
// tmpl: String
// String to be used as a template.
// map: Object|Function
// If an object, it is used as a dictionary to look up substitutions.
// If a function, it is called for every substitution with following
// parameters: a whole match, a name, an offset, and the whole template
// string (see https://developer.mozilla.org/en/Core_JavaScript_1.5_Reference/Global_Objects/String/replace
// for more details).
// pattern: RegEx?
// Optional regular expression objects that overrides the default pattern.
// Must be global and match one item. The default is: /\{([^\}]+)\}/g,
// which matches patterns like that: "{xxx}", where "xxx" is any sequence
// of characters, which doesn't include "}".
// returns: String
// Returns the substituted string.
// example:
// | // uses a dictionary for substitutions:
// | dojo.replace("Hello, {name.first} {name.last} AKA {nick}!",
// | {
// | nick: "Bob",
// | name: {
// | first: "Robert",
// | middle: "X",
// | last: "Cringely"
// | }
// | });
// | // returns: Hello, Robert Cringely AKA Bob!
// example:
// | // uses an array for substitutions:
// | dojo.replace("Hello, {0} {2}!",
// | ["Robert", "X", "Cringely"]);
// | // returns: Hello, Robert Cringely!
// example:
// | // uses a function for substitutions:
// | function sum(a){
// | var t = 0;
// | dojo.forEach(a, function(x){ t += x; });
// | return t;
// | }
// | dojo.replace(
// | "{count} payments averaging {avg} USD per payment.",
// | dojo.hitch(
// | { payments: [11, 16, 12] },
// | function(_, key){
// | switch(key){
// | case "count": return this.payments.length;
// | case "min": return Math.min.apply(Math, this.payments);
// | case "max": return Math.max.apply(Math, this.payments);
// | case "sum": return sum(this.payments);
// | case "avg": return sum(this.payments) / this.payments.length;
// | }
// | }
// | )
// | );
// | // prints: 3 payments averaging 13 USD per payment.
// example:
// | // uses an alternative PHP-like pattern for substitutions:
// | dojo.replace("Hello, ${0} ${2}!",
// | ["Robert", "X", "Cringely"], /\$\{([^\}]+)\}/g);
// | // returns: Hello, Robert Cringely!
return ""; // String
}
=====*/
var _pattern = /\{([^\}]+)\}/g;
dojo.replace = function(tmpl, map, pattern){
return tmpl.replace(pattern || _pattern, d.isFunction(map) ?
map : function(_, k){ return d.getObject(k, false, map); });
};
})();
}
if(!dojo._hasResource["dojo._base.array"]){ //_hasResource checks added by build. Do not use _hasResource directly in your code.
dojo._hasResource["dojo._base.array"] = true;
dojo.provide("dojo._base.array");
(function(){
var _getParts = function(arr, obj, cb){
return [
(typeof arr == "string") ? arr.split("") : arr,
obj || dojo.global,
// FIXME: cache the anonymous functions we create here?
(typeof cb == "string") ? new Function("item", "index", "array", cb) : cb
];
};
var everyOrSome = function(/*Boolean*/every, /*Array|String*/arr, /*Function|String*/callback, /*Object?*/thisObject){
var _p = _getParts(arr, thisObject, callback); arr = _p[0];
for(var i=0,l=arr.length; i end) || i < end){
for(; i != end; i += step){
if(array[i] == value){ return i; }
}
}
return -1; // Number
},
lastIndexOf: function(/*Array*/array, /*Object*/value, /*Integer?*/fromIndex){
// summary:
// locates the last index of the provided value in the passed
// array. If the value is not found, -1 is returned.
// description:
// This method corresponds to the JavaScript 1.6 Array.lastIndexOf method, with one difference: when
// run over sparse arrays, the Dojo function invokes the callback for every index whereas JavaScript
// 1.6's lastIndexOf skips the holes in the sparse array.
// For details on this method, see:
// https://developer.mozilla.org/en/Core_JavaScript_1.5_Reference/Objects/Array/lastIndexOf
return dojo.indexOf(array, value, fromIndex, true); // Number
},
forEach: function(/*Array|String*/arr, /*Function|String*/callback, /*Object?*/thisObject){
// summary:
// for every item in arr, callback is invoked. Return values are ignored.
// If you want to break out of the loop, consider using dojo.every() or dojo.some().
// forEach does not allow breaking out of the loop over the items in arr.
// arr:
// the array to iterate over. If a string, operates on individual characters.
// callback:
// a function is invoked with three arguments: item, index, and array
// thisObject:
// may be used to scope the call to callback
// description:
// This function corresponds to the JavaScript 1.6 Array.forEach() method, with one difference: when
// run over sparse arrays, this implemenation passes the "holes" in the sparse array to
// the callback function with a value of undefined. JavaScript 1.6's forEach skips the holes in the sparse array.
// For more details, see:
// https://developer.mozilla.org/en/Core_JavaScript_1.5_Reference/Objects/Array/forEach
// example:
// | // log out all members of the array:
// | dojo.forEach(
// | [ "thinger", "blah", "howdy", 10 ],
// | function(item){
// | console.log(item);
// | }
// | );
// example:
// | // log out the members and their indexes
// | dojo.forEach(
// | [ "thinger", "blah", "howdy", 10 ],
// | function(item, idx, arr){
// | console.log(item, "at index:", idx);
// | }
// | );
// example:
// | // use a scoped object member as the callback
// |
// | var obj = {
// | prefix: "logged via obj.callback:",
// | callback: function(item){
// | console.log(this.prefix, item);
// | }
// | };
// |
// | // specifying the scope function executes the callback in that scope
// | dojo.forEach(
// | [ "thinger", "blah", "howdy", 10 ],
// | obj.callback,
// | obj
// | );
// |
// | // alternately, we can accomplish the same thing with dojo.hitch()
// | dojo.forEach(
// | [ "thinger", "blah", "howdy", 10 ],
// | dojo.hitch(obj, "callback")
// | );
// match the behavior of the built-in forEach WRT empty arrs
if(!arr || !arr.length){ return; }
// FIXME: there are several ways of handilng thisObject. Is
// dojo.global always the default context?
var _p = _getParts(arr, thisObject, callback); arr = _p[0];
for(var i=0,l=arr.length; i1; });
// example:
// | // returns true
// | dojo.every([1, 2, 3, 4], function(item){ return item>0; });
return everyOrSome(true, arr, callback, thisObject); // Boolean
},
some: function(/*Array|String*/arr, /*Function|String*/callback, /*Object?*/thisObject){
// summary:
// Determines whether or not any item in arr satisfies the
// condition implemented by callback.
// arr:
// the array to iterate over. If a string, operates on individual characters.
// callback:
// a function is invoked with three arguments: item, index,
// and array and returns true if the condition is met.
// thisObject:
// may be used to scope the call to callback
// description:
// This function corresponds to the JavaScript 1.6 Array.some() method, with one difference: when
// run over sparse arrays, this implemenation passes the "holes" in the sparse array to
// the callback function with a value of undefined. JavaScript 1.6's some skips the holes in the sparse array.
// For more details, see:
// https://developer.mozilla.org/en/Core_JavaScript_1.5_Reference/Objects/Array/some
// example:
// | // is true
// | dojo.some([1, 2, 3, 4], function(item){ return item>1; });
// example:
// | // is false
// | dojo.some([1, 2, 3, 4], function(item){ return item<1; });
return everyOrSome(false, arr, callback, thisObject); // Boolean
},
map: function(/*Array|String*/arr, /*Function|String*/callback, /*Function?*/thisObject){
// summary:
// applies callback to each element of arr and returns
// an Array with the results
// arr:
// the array to iterate on. If a string, operates on
// individual characters.
// callback:
// a function is invoked with three arguments, (item, index,
// array), and returns a value
// thisObject:
// may be used to scope the call to callback
// description:
// This function corresponds to the JavaScript 1.6 Array.map() method, with one difference: when
// run over sparse arrays, this implemenation passes the "holes" in the sparse array to
// the callback function with a value of undefined. JavaScript 1.6's map skips the holes in the sparse array.
// For more details, see:
// https://developer.mozilla.org/en/Core_JavaScript_1.5_Reference/Objects/Array/map
// example:
// | // returns [2, 3, 4, 5]
// | dojo.map([1, 2, 3, 4], function(item){ return item+1 });
var _p = _getParts(arr, thisObject, callback); arr = _p[0];
var outArr = (arguments[3] ? (new arguments[3]()) : []);
for(var i=0,l=arr.length; i1; });
var _p = _getParts(arr, thisObject, callback); arr = _p[0];
var outArr = [];
for(var i=0,l=arr.length; i= 0; --j){
proto = lin[j].prototype;
if(!proto.hasOwnProperty("declaredClass")){
proto.declaredClass = "uniqName_" + (counter++);
}
name = proto.declaredClass;
if(!nameMap.hasOwnProperty(name)){
nameMap[name] = {count: 0, refs: [], cls: lin[j]};
++clsCount;
}
rec = nameMap[name];
if(top && top !== rec){
rec.refs.push(top);
++top.count;
}
top = rec;
}
++top.count;
roots[0].refs.push(top);
}
// remove classes without external references recursively
while(roots.length){
top = roots.pop();
result.push(top.cls);
--clsCount;
// optimization: follow a single-linked chain
while(refs = top.refs, refs.length == 1){
top = refs[0];
if(!top || --top.count){
// branch or end of chain => do not end to roots
top = 0;
break;
}
result.push(top.cls);
--clsCount;
}
if(top){
// branch
for(i = 0, l = refs.length; i < l; ++i){
top = refs[i];
if(!--top.count){
roots.push(top);
}
}
}
}
if(clsCount){
err("can't build consistent linearization");
}
// calculate the superclass offset
base = bases[0];
result[0] = base ?
base._meta && base === result[result.length - base._meta.bases.length] ?
base._meta.bases.length : 1 : 0;
return result;
}
function inherited(args, a, f){
var name, chains, bases, caller, meta, base, proto, opf, pos,
cache = this._inherited = this._inherited || {};
// crack arguments
if(typeof args == "string"){
name = args;
args = a;
a = f;
}
f = 0;
caller = args.callee;
name = name || caller.nom;
if(!name){
err("can't deduce a name to call inherited()");
}
meta = this.constructor._meta;
bases = meta.bases;
pos = cache.p;
if(name != cname){
// method
if(cache.c !== caller){
// cache bust
pos = 0;
base = bases[0];
meta = base._meta;
if(meta.hidden[name] !== caller){
// error detection
chains = meta.chains;
if(chains && typeof chains[name] == "string"){
err("calling chained method with inherited: " + name);
}
// find caller
do{
meta = base._meta;
proto = base.prototype;
if(meta && (proto[name] === caller && proto.hasOwnProperty(name) || meta.hidden[name] === caller)){
break;
}
}while(base = bases[++pos]); // intentional assignment
pos = base ? pos : -1;
}
}
// find next
base = bases[++pos];
if(base){
proto = base.prototype;
if(base._meta && proto.hasOwnProperty(name)){
f = proto[name];
}else{
opf = op[name];
do{
proto = base.prototype;
f = proto[name];
if(f && (base._meta ? proto.hasOwnProperty(name) : f !== opf)){
break;
}
}while(base = bases[++pos]); // intentional assignment
}
}
f = base && f || op[name];
}else{
// constructor
if(cache.c !== caller){
// cache bust
pos = 0;
meta = bases[0]._meta;
if(meta && meta.ctor !== caller){
// error detection
chains = meta.chains;
if(!chains || chains.constructor !== "manual"){
err("calling chained constructor with inherited");
}
// find caller
while(base = bases[++pos]){ // intentional assignment
meta = base._meta;
if(meta && meta.ctor === caller){
break;
}
}
pos = base ? pos : -1;
}
}
// find next
while(base = bases[++pos]){ // intentional assignment
meta = base._meta;
f = meta ? meta.ctor : base;
if(f){
break;
}
}
f = base && f;
}
// cache the found super method
cache.c = f;
cache.p = pos;
// now we have the result
if(f){
return a === true ? f : f.apply(this, a || args);
}
// intentionally if a super method was not found
}
function getInherited(name, args){
if(typeof name == "string"){
return this.inherited(name, args, true);
}
return this.inherited(name, true);
}
// emulation of "instanceof"
function isInstanceOf(cls){
var bases = this.constructor._meta.bases;
for(var i = 0, l = bases.length; i < l; ++i){
if(bases[i] === cls){
return true;
}
}
return this instanceof cls;
}
function mixOwn(target, source){
var name, i = 0, l = d._extraNames.length;
// add props adding metadata for incoming functions skipping a constructor
for(name in source){
if(name != cname && source.hasOwnProperty(name)){
target[name] = source[name];
}
}
// process unenumerable methods on IE
for(; i < l; ++i){
name = d._extraNames[i];
if(name != cname && source.hasOwnProperty(name)){
target[name] = source[name];
}
}
}
// implementation of safe mixin function
function safeMixin(target, source){
var name, t, i = 0, l = d._extraNames.length;
// add props adding metadata for incoming functions skipping a constructor
for(name in source){
t = source[name];
if((t !== op[name] || !(name in op)) && name != cname){
if(opts.call(t) == "[object Function]"){
// non-trivial function method => attach its name
t.nom = name;
}
target[name] = t;
}
}
// process unenumerable methods on IE
for(; i < l; ++i){
name = d._extraNames[i];
t = source[name];
if((t !== op[name] || !(name in op)) && name != cname){
if(opts.call(t) == "[object Function]"){
// non-trivial function method => attach its name
t.nom = name;
}
target[name] = t;
}
}
return target;
}
function extend(source){
safeMixin(this.prototype, source);
return this;
}
// chained constructor compatible with the legacy dojo.declare()
function chainedConstructor(bases, ctorSpecial){
return function(){
var a = arguments, args = a, a0 = a[0], f, i, m,
l = bases.length, preArgs;
if(!(this instanceof a.callee)){
// not called via new, so force it
return applyNew(a);
}
//this._inherited = {};
// perform the shaman's rituals of the original dojo.declare()
// 1) call two types of the preamble
if(ctorSpecial && (a0 && a0.preamble || this.preamble)){
// full blown ritual
preArgs = new Array(bases.length);
// prepare parameters
preArgs[0] = a;
for(i = 0;;){
// process the preamble of the 1st argument
a0 = a[0];
if(a0){
f = a0.preamble;
if(f){
a = f.apply(this, a) || a;
}
}
// process the preamble of this class
f = bases[i].prototype;
f = f.hasOwnProperty("preamble") && f.preamble;
if(f){
a = f.apply(this, a) || a;
}
// one peculiarity of the preamble:
// it is called if it is not needed,
// e.g., there is no constructor to call
// let's watch for the last constructor
// (see ticket #9795)
if(++i == l){
break;
}
preArgs[i] = a;
}
}
// 2) call all non-trivial constructors using prepared arguments
for(i = l - 1; i >= 0; --i){
f = bases[i];
m = f._meta;
f = m ? m.ctor : f;
if(f){
f.apply(this, preArgs ? preArgs[i] : a);
}
}
// 3) continue the original ritual: call the postscript
f = this.postscript;
if(f){
f.apply(this, args);
}
};
}
// chained constructor compatible with the legacy dojo.declare()
function singleConstructor(ctor, ctorSpecial){
return function(){
var a = arguments, t = a, a0 = a[0], f;
if(!(this instanceof a.callee)){
// not called via new, so force it
return applyNew(a);
}
//this._inherited = {};
// perform the shaman's rituals of the original dojo.declare()
// 1) call two types of the preamble
if(ctorSpecial){
// full blown ritual
if(a0){
// process the preamble of the 1st argument
f = a0.preamble;
if(f){
t = f.apply(this, t) || t;
}
}
f = this.preamble;
if(f){
// process the preamble of this class
f.apply(this, t);
// one peculiarity of the preamble:
// it is called even if it is not needed,
// e.g., there is no constructor to call
// let's watch for the last constructor
// (see ticket #9795)
}
}
// 2) call a constructor
if(ctor){
ctor.apply(this, a);
}
// 3) continue the original ritual: call the postscript
f = this.postscript;
if(f){
f.apply(this, a);
}
};
}
// plain vanilla constructor (can use inherited() to call its base constructor)
function simpleConstructor(bases){
return function(){
var a = arguments, i = 0, f, m;
if(!(this instanceof a.callee)){
// not called via new, so force it
return applyNew(a);
}
//this._inherited = {};
// perform the shaman's rituals of the original dojo.declare()
// 1) do not call the preamble
// 2) call the top constructor (it can use this.inherited())
for(; f = bases[i]; ++i){ // intentional assignment
m = f._meta;
f = m ? m.ctor : f;
if(f){
f.apply(this, a);
break;
}
}
// 3) call the postscript
f = this.postscript;
if(f){
f.apply(this, a);
}
};
}
function chain(name, bases, reversed){
return function(){
var b, m, f, i = 0, step = 1;
if(reversed){
i = bases.length - 1;
step = -1;
}
for(; b = bases[i]; i += step){ // intentional assignment
m = b._meta;
f = (m ? m.hidden : b.prototype)[name];
if(f){
f.apply(this, arguments);
}
}
};
}
// forceNew(ctor)
// return a new object that inherits from ctor.prototype but
// without actually running ctor on the object.
function forceNew(ctor){
// create object with correct prototype using a do-nothing
// constructor
xtor.prototype = ctor.prototype;
var t = new xtor;
xtor.prototype = null; // clean up
return t;
}
// applyNew(args)
// just like 'new ctor()' except that the constructor and its arguments come
// from args, which must be an array or an arguments object
function applyNew(args){
// create an object with ctor's prototype but without
// calling ctor on it.
var ctor = args.callee, t = forceNew(ctor);
// execute the real constructor on the new object
ctor.apply(t, args);
return t;
}
d.declare = function(className, superclass, props){
// crack parameters
if(typeof className != "string"){
props = superclass;
superclass = className;
className = "";
}
props = props || {};
var proto, i, t, ctor, name, bases, chains, mixins = 1, parents = superclass;
// build a prototype
if(opts.call(superclass) == "[object Array]"){
// C3 MRO
bases = c3mro(superclass);
t = bases[0];
mixins = bases.length - t;
superclass = bases[mixins];
}else{
bases = [0];
if(superclass){
if(opts.call(superclass) == "[object Function]"){
t = superclass._meta;
bases = bases.concat(t ? t.bases : superclass);
}else{
err("base class is not a callable constructor.");
}
}else if(superclass !== null){
err("unknown base class. Did you use dojo.require to pull it in?")
}
}
if(superclass){
for(i = mixins - 1;; --i){
proto = forceNew(superclass);
if(!i){
// stop if nothing to add (the last base)
break;
}
// mix in properties
t = bases[i];
(t._meta ? mixOwn : mix)(proto, t.prototype);
// chain in new constructor
ctor = new Function;
ctor.superclass = superclass;
ctor.prototype = proto;
superclass = proto.constructor = ctor;
}
}else{
proto = {};
}
// add all properties
safeMixin(proto, props);
// add constructor
t = props.constructor;
if(t !== op.constructor){
t.nom = cname;
proto.constructor = t;
}
// collect chains and flags
for(i = mixins - 1; i; --i){ // intentional assignment
t = bases[i]._meta;
if(t && t.chains){
chains = mix(chains || {}, t.chains);
}
}
if(proto["-chains-"]){
chains = mix(chains || {}, proto["-chains-"]);
}
// build ctor
t = !chains || !chains.hasOwnProperty(cname);
bases[0] = ctor = (chains && chains.constructor === "manual") ? simpleConstructor(bases) :
(bases.length == 1 ? singleConstructor(props.constructor, t) : chainedConstructor(bases, t));
// add meta information to the constructor
ctor._meta = {bases: bases, hidden: props, chains: chains,
parents: parents, ctor: props.constructor};
ctor.superclass = superclass && superclass.prototype;
ctor.extend = extend;
ctor.prototype = proto;
proto.constructor = ctor;
// add "standard" methods to the prototype
proto.getInherited = getInherited;
proto.inherited = inherited;
proto.isInstanceOf = isInstanceOf;
// add name if specified
if(className){
proto.declaredClass = className;
d.setObject(className, ctor);
}
// build chains and add them to the prototype
if(chains){
for(name in chains){
if(proto[name] && typeof chains[name] == "string" && name != cname){
t = proto[name] = chain(name, bases, chains[name] === "after");
t.nom = name;
}
}
}
// chained methods do not return values
// no need to chain "invisible" functions
return ctor; // Function
};
d.safeMixin = safeMixin;
/*=====
dojo.declare = function(className, superclass, props){
// summary:
// Create a feature-rich constructor from compact notation.
// className: String?:
// The optional name of the constructor (loosely, a "class")
// stored in the "declaredClass" property in the created prototype.
// It will be used as a global name for a created constructor.
// superclass: Function|Function[]:
// May be null, a Function, or an Array of Functions. This argument
// specifies a list of bases (the left-most one is the most deepest
// base).
// props: Object:
// An object whose properties are copied to the created prototype.
// Add an instance-initialization function by making it a property
// named "constructor".
// returns:
// New constructor function.
// description:
// Create a constructor using a compact notation for inheritance and
// prototype extension.
//
// Mixin ancestors provide a type of multiple inheritance.
// Prototypes of mixin ancestors are copied to the new class:
// changes to mixin prototypes will not affect classes to which
// they have been mixed in.
//
// Ancestors can be compound classes created by this version of
// dojo.declare. In complex cases all base classes are going to be
// linearized according to C3 MRO algorithm
// (see http://www.python.org/download/releases/2.3/mro/ for more
// details).
//
// "className" is cached in "declaredClass" property of the new class,
// if it was supplied. The immediate super class will be cached in
// "superclass" property of the new class.
//
// Methods in "props" will be copied and modified: "nom" property
// (the declared name of the method) will be added to all copied
// functions to help identify them for the internal machinery. Be
// very careful, while reusing methods: if you use the same
// function under different names, it can produce errors in some
// cases.
//
// It is possible to use constructors created "manually" (without
// dojo.declare) as bases. They will be called as usual during the
// creation of an instance, their methods will be chained, and even
// called by "this.inherited()".
//
// Special property "-chains-" governs how to chain methods. It is
// a dictionary, which uses method names as keys, and hint strings
// as values. If a hint string is "after", this method will be
// called after methods of its base classes. If a hint string is
// "before", this method will be called before methods of its base
// classes.
//
// If "constructor" is not mentioned in "-chains-" property, it will
// be chained using the legacy mode: using "after" chaining,
// calling preamble() method before each constructor, if available,
// and calling postscript() after all constructors were executed.
// If the hint is "after", it is chained as a regular method, but
// postscript() will be called after the chain of constructors.
// "constructor" cannot be chained "before", but it allows
// a special hint string: "manual", which means that constructors
// are not going to be chained in any way, and programmer will call
// them manually using this.inherited(). In the latter case
// postscript() will be called after the construction.
//
// All chaining hints are "inherited" from base classes and
// potentially can be overridden. Be very careful when overriding
// hints! Make sure that all chained methods can work in a proposed
// manner of chaining.
//
// Once a method was chained, it is impossible to unchain it. The
// only exception is "constructor". You don't need to define a
// method in order to supply a chaining hint.
//
// If a method is chained, it cannot use this.inherited() because
// all other methods in the hierarchy will be called automatically.
//
// Usually constructors and initializers of any kind are chained
// using "after" and destructors of any kind are chained as
// "before". Note that chaining assumes that chained methods do not
// return any value: any returned value will be discarded.
//
// example:
// | dojo.declare("my.classes.bar", my.classes.foo, {
// | // properties to be added to the class prototype
// | someValue: 2,
// | // initialization function
// | constructor: function(){
// | this.myComplicatedObject = new ReallyComplicatedObject();
// | },
// | // other functions
// | someMethod: function(){
// | doStuff();
// | }
// | });
//
// example:
// | var MyBase = dojo.declare(null, {
// | // constructor, properties, and methods go here
// | // ...
// | });
// | var MyClass1 = dojo.declare(MyBase, {
// | // constructor, properties, and methods go here
// | // ...
// | });
// | var MyClass2 = dojo.declare(MyBase, {
// | // constructor, properties, and methods go here
// | // ...
// | });
// | var MyDiamond = dojo.declare([MyClass1, MyClass2], {
// | // constructor, properties, and methods go here
// | // ...
// | });
//
// example:
// | var F = function(){ console.log("raw constructor"); };
// | F.prototype.method = function(){
// | console.log("raw method");
// | };
// | var A = dojo.declare(F, {
// | constructor: function(){
// | console.log("A.constructor");
// | },
// | method: function(){
// | console.log("before calling F.method...");
// | this.inherited(arguments);
// | console.log("...back in A");
// | }
// | });
// | new A().method();
// | // will print:
// | // raw constructor
// | // A.constructor
// | // before calling F.method...
// | // raw method
// | // ...back in A
//
// example:
// | var A = dojo.declare(null, {
// | "-chains-": {
// | destroy: "before"
// | }
// | });
// | var B = dojo.declare(A, {
// | constructor: function(){
// | console.log("B.constructor");
// | },
// | destroy: function(){
// | console.log("B.destroy");
// | }
// | });
// | var C = dojo.declare(B, {
// | constructor: function(){
// | console.log("C.constructor");
// | },
// | destroy: function(){
// | console.log("C.destroy");
// | }
// | });
// | new C().destroy();
// | // prints:
// | // B.constructor
// | // C.constructor
// | // C.destroy
// | // B.destroy
//
// example:
// | var A = dojo.declare(null, {
// | "-chains-": {
// | constructor: "manual"
// | }
// | });
// | var B = dojo.declare(A, {
// | constructor: function(){
// | // ...
// | // call the base constructor with new parameters
// | this.inherited(arguments, [1, 2, 3]);
// | // ...
// | }
// | });
//
// example:
// | var A = dojo.declare(null, {
// | "-chains-": {
// | m1: "before"
// | },
// | m1: function(){
// | console.log("A.m1");
// | },
// | m2: function(){
// | console.log("A.m2");
// | }
// | });
// | var B = dojo.declare(A, {
// | "-chains-": {
// | m2: "after"
// | },
// | m1: function(){
// | console.log("B.m1");
// | },
// | m2: function(){
// | console.log("B.m2");
// | }
// | });
// | var x = new B();
// | x.m1();
// | // prints:
// | // B.m1
// | // A.m1
// | x.m2();
// | // prints:
// | // A.m2
// | // B.m2
return new Function(); // Function
};
=====*/
/*=====
dojo.safeMixin = function(target, source){
// summary:
// Mix in properties skipping a constructor and decorating functions
// like it is done by dojo.declare.
// target: Object
// Target object to accept new properties.
// source: Object
// Source object for new properties.
// description:
// This function is used to mix in properties like dojo._mixin does,
// but it skips a constructor property and decorates functions like
// dojo.declare does.
//
// It is meant to be used with classes and objects produced with
// dojo.declare. Functions mixed in with dojo.safeMixin can use
// this.inherited() like normal methods.
//
// This function is used to implement extend() method of a constructor
// produced with dojo.declare().
//
// example:
// | var A = dojo.declare(null, {
// | m1: function(){
// | console.log("A.m1");
// | },
// | m2: function(){
// | console.log("A.m2");
// | }
// | });
// | var B = dojo.declare(A, {
// | m1: function(){
// | this.inherited(arguments);
// | console.log("B.m1");
// | }
// | });
// | B.extend({
// | m2: function(){
// | this.inherited(arguments);
// | console.log("B.m2");
// | }
// | });
// | var x = new B();
// | dojo.safeMixin(x, {
// | m1: function(){
// | this.inherited(arguments);
// | console.log("X.m1");
// | },
// | m2: function(){
// | this.inherited(arguments);
// | console.log("X.m2");
// | }
// | });
// | x.m2();
// | // prints:
// | // A.m1
// | // B.m1
// | // X.m1
};
=====*/
/*=====
Object.inherited = function(name, args, newArgs){
// summary:
// Calls a super method.
// name: String?
// The optional method name. Should be the same as the caller's
// name. Usually "name" is specified in complex dynamic cases, when
// the calling method was dynamically added, undecorated by
// dojo.declare, and it cannot be determined.
// args: Arguments
// The caller supply this argument, which should be the original
// "arguments".
// newArgs: Object?
// If "true", the found function will be returned without
// executing it.
// If Array, it will be used to call a super method. Otherwise
// "args" will be used.
// returns:
// Whatever is returned by a super method, or a super method itself,
// if "true" was specified as newArgs.
// description:
// This method is used inside method of classes produced with
// dojo.declare to call a super method (next in the chain). It is
// used for manually controlled chaining. Consider using the regular
// chaining, because it is faster. Use "this.inherited()" only in
// complex cases.
//
// This method cannot me called from automatically chained
// constructors including the case of a special (legacy)
// constructor chaining. It cannot be called from chained methods.
//
// If "this.inherited()" cannot find the next-in-chain method, it
// does nothing and returns "undefined". The last method in chain
// can be a default method implemented in Object, which will be
// called last.
//
// If "name" is specified, it is assumed that the method that
// received "args" is the parent method for this call. It is looked
// up in the chain list and if it is found the next-in-chain method
// is called. If it is not found, the first-in-chain method is
// called.
//
// If "name" is not specified, it will be derived from the calling
// method (using a methoid property "nom").
//
// example:
// | var B = dojo.declare(A, {
// | method1: function(a, b, c){
// | this.inherited(arguments);
// | },
// | method2: function(a, b){
// | return this.inherited(arguments, [a + b]);
// | }
// | });
// | // next method is not in the chain list because it is added
// | // manually after the class was created.
// | B.prototype.method3 = function(){
// | console.log("This is a dynamically-added method.");
// | this.inherited("method3", arguments);
// | };
// example:
// | var B = dojo.declare(A, {
// | method: function(a, b){
// | var super = this.inherited(arguments, true);
// | // ...
// | if(!super){
// | console.log("there is no super method");
// | return 0;
// | }
// | return super.apply(this, arguments);
// | }
// | });
return {}; // Object
}
=====*/
/*=====
Object.getInherited = function(name, args){
// summary:
// Returns a super method.
// name: String?
// The optional method name. Should be the same as the caller's
// name. Usually "name" is specified in complex dynamic cases, when
// the calling method was dynamically added, undecorated by
// dojo.declare, and it cannot be determined.
// args: Arguments
// The caller supply this argument, which should be the original
// "arguments".
// returns:
// Returns a super method (Function) or "undefined".
// description:
// This method is a convenience method for "this.inherited()".
// It uses the same algorithm but instead of executing a super
// method, it returns it, or "undefined" if not found.
//
// example:
// | var B = dojo.declare(A, {
// | method: function(a, b){
// | var super = this.getInherited(arguments);
// | // ...
// | if(!super){
// | console.log("there is no super method");
// | return 0;
// | }
// | return super.apply(this, arguments);
// | }
// | });
return {}; // Object
}
=====*/
/*=====
Object.isInstanceOf = function(cls){
// summary:
// Checks the inheritance chain to see if it is inherited from this
// class.
// cls: Function
// Class constructor.
// returns:
// "true", if this object is inherited from this class, "false"
// otherwise.
// description:
// This method is used with instances of classes produced with
// dojo.declare to determine of they support a certain interface or
// not. It models "instanceof" operator.
//
// example:
// | var A = dojo.declare(null, {
// | // constructor, properties, and methods go here
// | // ...
// | });
// | var B = dojo.declare(null, {
// | // constructor, properties, and methods go here
// | // ...
// | });
// | var C = dojo.declare([A, B], {
// | // constructor, properties, and methods go here
// | // ...
// | });
// | var D = dojo.declare(A, {
// | // constructor, properties, and methods go here
// | // ...
// | });
// |
// | var a = new A(), b = new B(), c = new C(), d = new D();
// |
// | console.log(a.isInstanceOf(A)); // true
// | console.log(b.isInstanceOf(A)); // false
// | console.log(c.isInstanceOf(A)); // true
// | console.log(d.isInstanceOf(A)); // true
// |
// | console.log(a.isInstanceOf(B)); // false
// | console.log(b.isInstanceOf(B)); // true
// | console.log(c.isInstanceOf(B)); // true
// | console.log(d.isInstanceOf(B)); // false
// |
// | console.log(a.isInstanceOf(C)); // false
// | console.log(b.isInstanceOf(C)); // false
// | console.log(c.isInstanceOf(C)); // true
// | console.log(d.isInstanceOf(C)); // false
// |
// | console.log(a.isInstanceOf(D)); // false
// | console.log(b.isInstanceOf(D)); // false
// | console.log(c.isInstanceOf(D)); // false
// | console.log(d.isInstanceOf(D)); // true
return {}; // Object
}
=====*/
/*=====
Object.extend = function(source){
// summary:
// Adds all properties and methods of source to constructor's
// prototype, making them available to all instances created with
// constructor. This method is specific to constructors created with
// dojo.declare.
// source: Object
// Source object which properties are going to be copied to the
// constructor's prototype.
// description:
// Adds source properties to the constructor's prototype. It can
// override existing properties.
//
// This method is similar to dojo.extend function, but it is specific
// to constructors produced by dojo.declare. It is implemented
// using dojo.safeMixin, and it skips a constructor property,
// and properly decorates copied functions.
//
// example:
// | var A = dojo.declare(null, {
// | m1: function(){},
// | s1: "Popokatepetl"
// | });
// | A.extend({
// | m1: function(){},
// | m2: function(){},
// | f1: true,
// | d1: 42
// | });
};
=====*/
})();
}
if(!dojo._hasResource["dojo._base.connect"]){ //_hasResource checks added by build. Do not use _hasResource directly in your code.
dojo._hasResource["dojo._base.connect"] = true;
dojo.provide("dojo._base.connect");
// this file courtesy of the TurboAjax Group, licensed under a Dojo CLA
// low-level delegation machinery
dojo._listener = {
// create a dispatcher function
getDispatcher: function(){
// following comments pulled out-of-line to prevent cloning them
// in the returned function.
// - indices (i) that are really in the array of listeners (ls) will
// not be in Array.prototype. This is the 'sparse array' trick
// that keeps us safe from libs that take liberties with built-in
// objects
// - listener is invoked with current scope (this)
return function(){
var ap=Array.prototype, c=arguments.callee, ls=c._listeners, t=c.target;
// return value comes from original target function
var r = t && t.apply(this, arguments);
// make local copy of listener array so it is immutable during processing
var i, lls;
lls = [].concat(ls);
// invoke listeners after target function
for(i in lls){
if(!(i in ap)){
lls[i].apply(this, arguments);
}
}
// return value comes from original target function
return r;
};
},
// add a listener to an object
add: function(/*Object*/ source, /*String*/ method, /*Function*/ listener){
// Whenever 'method' is invoked, 'listener' will have the same scope.
// Trying to supporting a context object for the listener led to
// complexity.
// Non trivial to provide 'once' functionality here
// because listener could be the result of a dojo.hitch call,
// in which case two references to the same hitch target would not
// be equivalent.
source = source || dojo.global;
// The source method is either null, a dispatcher, or some other function
var f = source[method];
// Ensure a dispatcher
if(!f || !f._listeners){
var d = dojo._listener.getDispatcher();
// original target function is special
d.target = f;
// dispatcher holds a list of listeners
d._listeners = [];
// redirect source to dispatcher
f = source[method] = d;
}
// The contract is that a handle is returned that can
// identify this listener for disconnect.
//
// The type of the handle is private. Here is it implemented as Integer.
// DOM event code has this same contract but handle is Function
// in non-IE browsers.
//
// We could have separate lists of before and after listeners.
return f._listeners.push(listener); /*Handle*/
},
// remove a listener from an object
remove: function(/*Object*/ source, /*String*/ method, /*Handle*/ handle){
var f = (source || dojo.global)[method];
// remember that handle is the index+1 (0 is not a valid handle)
if(f && f._listeners && handle--){
delete f._listeners[handle];
}
}
};
// Multiple delegation for arbitrary methods.
// This unit knows nothing about DOM, but we include DOM aware documentation
// and dontFix argument here to help the autodocs. Actual DOM aware code is in
// event.js.
dojo.connect = function(/*Object|null*/ obj,
/*String*/ event,
/*Object|null*/ context,
/*String|Function*/ method,
/*Boolean?*/ dontFix){
// summary:
// `dojo.connect` is the core event handling and delegation method in
// Dojo. It allows one function to "listen in" on the execution of
// any other, triggering the second whenever the first is called. Many
// listeners may be attached to a function, and source functions may
// be either regular function calls or DOM events.
//
// description:
// Connects listeners to actions, so that after event fires, a
// listener is called with the same arguments passed to the original
// function.
//
// Since `dojo.connect` allows the source of events to be either a
// "regular" JavaScript function or a DOM event, it provides a uniform
// interface for listening to all the types of events that an
// application is likely to deal with though a single, unified
// interface. DOM programmers may want to think of it as
// "addEventListener for everything and anything".
//
// When setting up a connection, the `event` parameter must be a
// string that is the name of the method/event to be listened for. If
// `obj` is null, `dojo.global` is assumed, meaning that connections
// to global methods are supported but also that you may inadvertently
// connect to a global by passing an incorrect object name or invalid
// reference.
//
// `dojo.connect` generally is forgiving. If you pass the name of a
// function or method that does not yet exist on `obj`, connect will
// not fail, but will instead set up a stub method. Similarly, null
// arguments may simply be omitted such that fewer than 4 arguments
// may be required to set up a connection See the examples for details.
//
// The return value is a handle that is needed to
// remove this connection with `dojo.disconnect`.
//
// obj:
// The source object for the event function.
// Defaults to `dojo.global` if null.
// If obj is a DOM node, the connection is delegated
// to the DOM event manager (unless dontFix is true).
//
// event:
// String name of the event function in obj.
// I.e. identifies a property `obj[event]`.
//
// context:
// The object that method will receive as "this".
//
// If context is null and method is a function, then method
// inherits the context of event.
//
// If method is a string then context must be the source
// object object for method (context[method]). If context is null,
// dojo.global is used.
//
// method:
// A function reference, or name of a function in context.
// The function identified by method fires after event does.
// method receives the same arguments as the event.
// See context argument comments for information on method's scope.
//
// dontFix:
// If obj is a DOM node, set dontFix to true to prevent delegation
// of this connection to the DOM event manager.
//
// example:
// When obj.onchange(), do ui.update():
// | dojo.connect(obj, "onchange", ui, "update");
// | dojo.connect(obj, "onchange", ui, ui.update); // same
//
// example:
// Using return value for disconnect:
// | var link = dojo.connect(obj, "onchange", ui, "update");
// | ...
// | dojo.disconnect(link);
//
// example:
// When onglobalevent executes, watcher.handler is invoked:
// | dojo.connect(null, "onglobalevent", watcher, "handler");
//
// example:
// When ob.onCustomEvent executes, customEventHandler is invoked:
// | dojo.connect(ob, "onCustomEvent", null, "customEventHandler");
// | dojo.connect(ob, "onCustomEvent", "customEventHandler"); // same
//
// example:
// When ob.onCustomEvent executes, customEventHandler is invoked
// with the same scope (this):
// | dojo.connect(ob, "onCustomEvent", null, customEventHandler);
// | dojo.connect(ob, "onCustomEvent", customEventHandler); // same
//
// example:
// When globalEvent executes, globalHandler is invoked
// with the same scope (this):
// | dojo.connect(null, "globalEvent", null, globalHandler);
// | dojo.connect("globalEvent", globalHandler); // same
// normalize arguments
var a=arguments, args=[], i=0;
// if a[0] is a String, obj was omitted
args.push(dojo.isString(a[0]) ? null : a[i++], a[i++]);
// if the arg-after-next is a String or Function, context was NOT omitted
var a1 = a[i+1];
args.push(dojo.isString(a1)||dojo.isFunction(a1) ? a[i++] : null, a[i++]);
// absorb any additional arguments
for(var l=a.length; i44
//
var returnDeferred = progressCallback == mutator ? this : new dojo.Deferred(promise.cancel);
var listener = {
resolved: resolvedCallback,
error: errorCallback,
progress: progressCallback,
deferred: returnDeferred
};
if(nextListener){
head = head.next = listener;
}
else{
nextListener = head = listener;
}
if(finished){
notify();
}
return returnDeferred.promise;
};
var deferred = this;
this.cancel = promise.cancel = function () {
// summary:
// Cancels the asynchronous operation
if(!finished){
var error = canceller && canceller(deferred);
if(!finished){
if (!(error instanceof Error)) {
error = new Error(error);
}
error.log = false;
deferred.reject(error);
}
}
}
freeze(promise);
};
dojo.extend(dojo.Deferred, {
addCallback: function (/*Function*/callback) {
return this.addCallbacks(dojo.hitch.apply(dojo, arguments));
},
addErrback: function (/*Function*/errback) {
return this.addCallbacks(null, dojo.hitch.apply(dojo, arguments));
},
addBoth: function (/*Function*/callback) {
var enclosed = dojo.hitch.apply(dojo, arguments);
return this.addCallbacks(enclosed, enclosed);
},
fired: -1
});
})();
dojo.when = function(promiseOrValue, /*Function?*/callback, /*Function?*/errback, /*Function?*/progressHandler){
// summary:
// This provides normalization between normal synchronous values and
// asynchronous promises, so you can interact with them in a common way
// example:
// | function printFirstAndList(items){
// | dojo.when(findFirst(items), console.log);
// | dojo.when(findLast(items), console.log);
// | }
// | function findFirst(items){
// | return dojo.when(items, function(items){
// | return items[0];
// | });
// | }
// | function findLast(items){
// | return dojo.when(items, function(items){
// | return items[items.length];
// | });
// | }
// And now all three of his functions can be used sync or async.
// | printFirstAndLast([1,2,3,4]) will work just as well as
// | printFirstAndLast(dojo.xhrGet(...));
if(promiseOrValue && typeof promiseOrValue.then === "function"){
return promiseOrValue.then(callback, errback, progressHandler);
}
return callback(promiseOrValue);
};
}
if(!dojo._hasResource["dojo._base.json"]){ //_hasResource checks added by build. Do not use _hasResource directly in your code.
dojo._hasResource["dojo._base.json"] = true;
dojo.provide("dojo._base.json");
dojo.fromJson = function(/*String*/ json){
// summary:
// Parses a [JSON](http://json.org) string to return a JavaScript object.
// description:
// Throws for invalid JSON strings, but it does not use a strict JSON parser. It
// delegates to eval(). The content passed to this method must therefore come
// from a trusted source.
// json:
// a string literal of a JSON item, for instance:
// `'{ "foo": [ "bar", 1, { "baz": "thud" } ] }'`
return eval("(" + json + ")"); // Object
}
dojo._escapeString = function(/*String*/str){
//summary:
// Adds escape sequences for non-visual characters, double quote and
// backslash and surrounds with double quotes to form a valid string
// literal.
return ('"' + str.replace(/(["\\])/g, '\\$1') + '"').
replace(/[\f]/g, "\\f").replace(/[\b]/g, "\\b").replace(/[\n]/g, "\\n").
replace(/[\t]/g, "\\t").replace(/[\r]/g, "\\r"); // string
}
dojo.toJsonIndentStr = "\t";
dojo.toJson = function(/*Object*/ it, /*Boolean?*/ prettyPrint, /*String?*/ _indentStr){
// summary:
// Returns a [JSON](http://json.org) serialization of an object.
// description:
// Returns a [JSON](http://json.org) serialization of an object.
// Note that this doesn't check for infinite recursion, so don't do that!
// it:
// an object to be serialized. Objects may define their own
// serialization via a special "__json__" or "json" function
// property. If a specialized serializer has been defined, it will
// be used as a fallback.
// prettyPrint:
// if true, we indent objects and arrays to make the output prettier.
// The variable `dojo.toJsonIndentStr` is used as the indent string --
// to use something other than the default (tab), change that variable
// before calling dojo.toJson().
// _indentStr:
// private variable for recursive calls when pretty printing, do not use.
// example:
// simple serialization of a trivial object
// | var jsonStr = dojo.toJson({ howdy: "stranger!", isStrange: true });
// | doh.is('{"howdy":"stranger!","isStrange":true}', jsonStr);
// example:
// a custom serializer for an objects of a particular class:
// | dojo.declare("Furby", null, {
// | furbies: "are strange",
// | furbyCount: 10,
// | __json__: function(){
// | },
// | });
if(it === undefined){
return "undefined";
}
var objtype = typeof it;
if(objtype == "number" || objtype == "boolean"){
return it + "";
}
if(it === null){
return "null";
}
if(dojo.isString(it)){
return dojo._escapeString(it);
}
// recurse
var recurse = arguments.callee;
// short-circuit for objects that support "json" serialization
// if they return "self" then just pass-through...
var newObj;
_indentStr = _indentStr || "";
var nextIndent = prettyPrint ? _indentStr + dojo.toJsonIndentStr : "";
var tf = it.__json__||it.json;
if(dojo.isFunction(tf)){
newObj = tf.call(it);
if(it !== newObj){
return recurse(newObj, prettyPrint, nextIndent);
}
}
if(it.nodeType && it.cloneNode){ // isNode
// we can't seriailize DOM nodes as regular objects because they have cycles
// DOM nodes could be serialized with something like outerHTML, but
// that can be provided by users in the form of .json or .__json__ function.
throw new Error("Can't serialize DOM nodes");
}
var sep = prettyPrint ? " " : "";
var newLine = prettyPrint ? "\n" : "";
// array
if(dojo.isArray(it)){
var res = dojo.map(it, function(obj){
var val = recurse(obj, prettyPrint, nextIndent);
if(typeof val != "string"){
val = "undefined";
}
return newLine + nextIndent + val;
});
return "[" + res.join("," + sep) + newLine + _indentStr + "]";
}
/*
// look in the registry
try {
window.o = it;
newObj = dojo.json.jsonRegistry.match(it);
return recurse(newObj, prettyPrint, nextIndent);
}catch(e){
// console.log(e);
}
// it's a function with no adapter, skip it
*/
if(objtype == "function"){
return null; // null
}
// generic object code path
var output = [], key;
for(key in it){
var keyStr, val;
if(typeof key == "number"){
keyStr = '"' + key + '"';
}else if(typeof key == "string"){
keyStr = dojo._escapeString(key);
}else{
// skip non-string or number keys
continue;
}
val = recurse(it[key], prettyPrint, nextIndent);
if(typeof val != "string"){
// skip non-serializable values
continue;
}
// FIXME: use += on Moz!!
// MOW NOTE: using += is a pain because you have to account for the dangling comma...
output.push(newLine + nextIndent + keyStr + ":" + sep + val);
}
return "{" + output.join("," + sep) + newLine + _indentStr + "}"; // String
}
}
if(!dojo._hasResource["dojo._base.Color"]){ //_hasResource checks added by build. Do not use _hasResource directly in your code.
dojo._hasResource["dojo._base.Color"] = true;
dojo.provide("dojo._base.Color");
(function(){
var d = dojo;
dojo.Color = function(/*Array|String|Object*/ color){
// summary:
// Takes a named string, hex string, array of rgb or rgba values,
// an object with r, g, b, and a properties, or another `dojo.Color` object
// and creates a new Color instance to work from.
//
// example:
// Work with a Color instance:
// | var c = new dojo.Color();
// | c.setColor([0,0,0]); // black
// | var hex = c.toHex(); // #000000
//
// example:
// Work with a node's color:
// | var color = dojo.style("someNode", "backgroundColor");
// | var n = new dojo.Color(color);
// | // adjust the color some
// | n.r *= .5;
// | console.log(n.toString()); // rgb(128, 255, 255);
if(color){ this.setColor(color); }
};
// FIXME:
// there's got to be a more space-efficient way to encode or discover
// these!! Use hex?
dojo.Color.named = {
black: [0,0,0],
silver: [192,192,192],
gray: [128,128,128],
white: [255,255,255],
maroon: [128,0,0],
red: [255,0,0],
purple: [128,0,128],
fuchsia: [255,0,255],
green: [0,128,0],
lime: [0,255,0],
olive: [128,128,0],
yellow: [255,255,0],
navy: [0,0,128],
blue: [0,0,255],
teal: [0,128,128],
aqua: [0,255,255],
transparent: d.config.transparentColor || [255,255,255]
};
dojo.extend(dojo.Color, {
r: 255, g: 255, b: 255, a: 1,
_set: function(r, g, b, a){
var t = this; t.r = r; t.g = g; t.b = b; t.a = a;
},
setColor: function(/*Array|String|Object*/ color){
// summary:
// Takes a named string, hex string, array of rgb or rgba values,
// an object with r, g, b, and a properties, or another `dojo.Color` object
// and sets this color instance to that value.
//
// example:
// | var c = new dojo.Color(); // no color
// | c.setColor("#ededed"); // greyish
if(d.isString(color)){
d.colorFromString(color, this);
}else if(d.isArray(color)){
d.colorFromArray(color, this);
}else{
this._set(color.r, color.g, color.b, color.a);
if(!(color instanceof d.Color)){ this.sanitize(); }
}
return this; // dojo.Color
},
sanitize: function(){
// summary:
// Ensures the object has correct attributes
// description:
// the default implementation does nothing, include dojo.colors to
// augment it with real checks
return this; // dojo.Color
},
toRgb: function(){
// summary:
// Returns 3 component array of rgb values
// example:
// | var c = new dojo.Color("#000000");
// | console.log(c.toRgb()); // [0,0,0]
var t = this;
return [t.r, t.g, t.b]; // Array
},
toRgba: function(){
// summary:
// Returns a 4 component array of rgba values from the color
// represented by this object.
var t = this;
return [t.r, t.g, t.b, t.a]; // Array
},
toHex: function(){
// summary:
// Returns a CSS color string in hexadecimal representation
// example:
// | console.log(new dojo.Color([0,0,0]).toHex()); // #000000
var arr = d.map(["r", "g", "b"], function(x){
var s = this[x].toString(16);
return s.length < 2 ? "0" + s : s;
}, this);
return "#" + arr.join(""); // String
},
toCss: function(/*Boolean?*/ includeAlpha){
// summary:
// Returns a css color string in rgb(a) representation
// example:
// | var c = new dojo.Color("#FFF").toCss();
// | console.log(c); // rgb('255','255','255')
var t = this, rgb = t.r + ", " + t.g + ", " + t.b;
return (includeAlpha ? "rgba(" + rgb + ", " + t.a : "rgb(" + rgb) + ")"; // String
},
toString: function(){
// summary:
// Returns a visual representation of the color
return this.toCss(true); // String
}
});
dojo.blendColors = function(
/*dojo.Color*/ start,
/*dojo.Color*/ end,
/*Number*/ weight,
/*dojo.Color?*/ obj
){
// summary:
// Blend colors end and start with weight from 0 to 1, 0.5 being a 50/50 blend,
// can reuse a previously allocated dojo.Color object for the result
var t = obj || new d.Color();
d.forEach(["r", "g", "b", "a"], function(x){
t[x] = start[x] + (end[x] - start[x]) * weight;
if(x != "a"){ t[x] = Math.round(t[x]); }
});
return t.sanitize(); // dojo.Color
};
dojo.colorFromRgb = function(/*String*/ color, /*dojo.Color?*/ obj){
// summary:
// Returns a `dojo.Color` instance from a string of the form
// "rgb(...)" or "rgba(...)". Optionally accepts a `dojo.Color`
// object to update with the parsed value and return instead of
// creating a new object.
// returns:
// A dojo.Color object. If obj is passed, it will be the return value.
var m = color.toLowerCase().match(/^rgba?\(([\s\.,0-9]+)\)/);
return m && dojo.colorFromArray(m[1].split(/\s*,\s*/), obj); // dojo.Color
};
dojo.colorFromHex = function(/*String*/ color, /*dojo.Color?*/ obj){
// summary:
// Converts a hex string with a '#' prefix to a color object.
// Supports 12-bit #rgb shorthand. Optionally accepts a
// `dojo.Color` object to update with the parsed value.
//
// returns:
// A dojo.Color object. If obj is passed, it will be the return value.
//
// example:
// | var thing = dojo.colorFromHex("#ededed"); // grey, longhand
//
// example:
// | var thing = dojo.colorFromHex("#000"); // black, shorthand
var t = obj || new d.Color(),
bits = (color.length == 4) ? 4 : 8,
mask = (1 << bits) - 1;
color = Number("0x" + color.substr(1));
if(isNaN(color)){
return null; // dojo.Color
}
d.forEach(["b", "g", "r"], function(x){
var c = color & mask;
color >>= bits;
t[x] = bits == 4 ? 17 * c : c;
});
t.a = 1;
return t; // dojo.Color
};
dojo.colorFromArray = function(/*Array*/ a, /*dojo.Color?*/ obj){
// summary:
// Builds a `dojo.Color` from a 3 or 4 element array, mapping each
// element in sequence to the rgb(a) values of the color.
// example:
// | var myColor = dojo.colorFromArray([237,237,237,0.5]); // grey, 50% alpha
// returns:
// A dojo.Color object. If obj is passed, it will be the return value.
var t = obj || new d.Color();
t._set(Number(a[0]), Number(a[1]), Number(a[2]), Number(a[3]));
if(isNaN(t.a)){ t.a = 1; }
return t.sanitize(); // dojo.Color
};
dojo.colorFromString = function(/*String*/ str, /*dojo.Color?*/ obj){
// summary:
// Parses `str` for a color value. Accepts hex, rgb, and rgba
// style color values.
// description:
// Acceptable input values for str may include arrays of any form
// accepted by dojo.colorFromArray, hex strings such as "#aaaaaa", or
// rgb or rgba strings such as "rgb(133, 200, 16)" or "rgba(10, 10,
// 10, 50)"
// returns:
// A dojo.Color object. If obj is passed, it will be the return value.
var a = d.Color.named[str];
return a && d.colorFromArray(a, obj) || d.colorFromRgb(str, obj) || d.colorFromHex(str, obj);
};
})();
}
if(!dojo._hasResource["dojo._base"]){ //_hasResource checks added by build. Do not use _hasResource directly in your code.
dojo._hasResource["dojo._base"] = true;
dojo.provide("dojo._base");
}
if(!dojo._hasResource["dojo._base.window"]){ //_hasResource checks added by build. Do not use _hasResource directly in your code.
dojo._hasResource["dojo._base.window"] = true;
dojo.provide("dojo._base.window");
/*=====
dojo.doc = {
// summary:
// Alias for the current document. 'dojo.doc' can be modified
// for temporary context shifting. Also see dojo.withDoc().
// description:
// Refer to dojo.doc rather
// than referring to 'window.document' to ensure your code runs
// correctly in managed contexts.
// example:
// | n.appendChild(dojo.doc.createElement('div'));
}
=====*/
dojo.doc = window["document"] || null;
dojo.body = function(){
// summary:
// Return the body element of the document
// return the body object associated with dojo.doc
// example:
// | dojo.body().appendChild(dojo.doc.createElement('div'));
// Note: document.body is not defined for a strict xhtml document
// Would like to memoize this, but dojo.doc can change vi dojo.withDoc().
return dojo.doc.body || dojo.doc.getElementsByTagName("body")[0]; // Node
}
dojo.setContext = function(/*Object*/globalObject, /*DocumentElement*/globalDocument){
// summary:
// changes the behavior of many core Dojo functions that deal with
// namespace and DOM lookup, changing them to work in a new global
// context (e.g., an iframe). The varibles dojo.global and dojo.doc
// are modified as a result of calling this function and the result of
// `dojo.body()` likewise differs.
dojo.global = globalObject;
dojo.doc = globalDocument;
};
dojo.withGlobal = function( /*Object*/globalObject,
/*Function*/callback,
/*Object?*/thisObject,
/*Array?*/cbArguments){
// summary:
// Invoke callback with globalObject as dojo.global and
// globalObject.document as dojo.doc.
// description:
// Invoke callback with globalObject as dojo.global and
// globalObject.document as dojo.doc. If provided, globalObject
// will be executed in the context of object thisObject
// When callback() returns or throws an error, the dojo.global
// and dojo.doc will be restored to its previous state.
var oldGlob = dojo.global;
try{
dojo.global = globalObject;
return dojo.withDoc.call(null, globalObject.document, callback, thisObject, cbArguments);
}finally{
dojo.global = oldGlob;
}
}
dojo.withDoc = function( /*DocumentElement*/documentObject,
/*Function*/callback,
/*Object?*/thisObject,
/*Array?*/cbArguments){
// summary:
// Invoke callback with documentObject as dojo.doc.
// description:
// Invoke callback with documentObject as dojo.doc. If provided,
// callback will be executed in the context of object thisObject
// When callback() returns or throws an error, the dojo.doc will
// be restored to its previous state.
var oldDoc = dojo.doc,
oldLtr = dojo._bodyLtr,
oldQ = dojo.isQuirks;
try{
dojo.doc = documentObject;
delete dojo._bodyLtr; // uncache
dojo.isQuirks = dojo.doc.compatMode == "BackCompat"; // no need to check for QuirksMode which was Opera 7 only
if(thisObject && typeof callback == "string"){
callback = thisObject[callback];
}
return callback.apply(thisObject, cbArguments || []);
}finally{
dojo.doc = oldDoc;
delete dojo._bodyLtr; // in case it was undefined originally, and set to true/false by the alternate document
if(oldLtr !== undefined){ dojo._bodyLtr = oldLtr; }
dojo.isQuirks = oldQ;
}
};
}
if(!dojo._hasResource["dojo._base.event"]){ //_hasResource checks added by build. Do not use _hasResource directly in your code.
dojo._hasResource["dojo._base.event"] = true;
dojo.provide("dojo._base.event");
// this file courtesy of the TurboAjax Group, licensed under a Dojo CLA
(function(){
// DOM event listener machinery
var del = (dojo._event_listener = {
add: function(/*DOMNode*/ node, /*String*/ name, /*Function*/ fp){
if(!node){return;}
name = del._normalizeEventName(name);
fp = del._fixCallback(name, fp);
var oname = name;
if(
!dojo.isIE &&
(name == "mouseenter" || name == "mouseleave")
){
var ofp = fp;
//oname = name;
name = (name == "mouseenter") ? "mouseover" : "mouseout";
fp = function(e){
if(!dojo.isDescendant(e.relatedTarget, node)){
// e.type = oname; // FIXME: doesn't take? SJM: event.type is generally immutable.
return ofp.call(this, e);
}
}
}
node.addEventListener(name, fp, false);
return fp; /*Handle*/
},
remove: function(/*DOMNode*/ node, /*String*/ event, /*Handle*/ handle){
// summary:
// clobbers the listener from the node
// node:
// DOM node to attach the event to
// event:
// the name of the handler to remove the function from
// handle:
// the handle returned from add
if(node){
event = del._normalizeEventName(event);
if(!dojo.isIE && (event == "mouseenter" || event == "mouseleave")){
event = (event == "mouseenter") ? "mouseover" : "mouseout";
}
node.removeEventListener(event, handle, false);
}
},
_normalizeEventName: function(/*String*/ name){
// Generally, name should be lower case, unless it is special
// somehow (e.g. a Mozilla DOM event).
// Remove 'on'.
return name.slice(0,2) =="on" ? name.slice(2) : name;
},
_fixCallback: function(/*String*/ name, fp){
// By default, we only invoke _fixEvent for 'keypress'
// If code is added to _fixEvent for other events, we have
// to revisit this optimization.
// This also applies to _fixEvent overrides for Safari and Opera
// below.
return name != "keypress" ? fp : function(e){ return fp.call(this, del._fixEvent(e, this)); };
},
_fixEvent: function(evt, sender){
// _fixCallback only attaches us to keypress.
// Switch on evt.type anyway because we might
// be called directly from dojo.fixEvent.
switch(evt.type){
case "keypress":
del._setKeyChar(evt);
break;
}
return evt;
},
_setKeyChar: function(evt){
evt.keyChar = evt.charCode ? String.fromCharCode(evt.charCode) : '';
evt.charOrCode = evt.keyChar || evt.keyCode;
},
// For IE and Safari: some ctrl-key combinations (mostly w/punctuation) do not emit a char code in IE
// we map those virtual key codes to ascii here
// not valid for all (non-US) keyboards, so maybe we shouldn't bother
_punctMap: {
106:42,
111:47,
186:59,
187:43,
188:44,
189:45,
190:46,
191:47,
192:96,
219:91,
220:92,
221:93,
222:39
}
});
// DOM events
dojo.fixEvent = function(/*Event*/ evt, /*DOMNode*/ sender){
// summary:
// normalizes properties on the event object including event
// bubbling methods, keystroke normalization, and x/y positions
// evt: Event
// native event object
// sender: DOMNode
// node to treat as "currentTarget"
return del._fixEvent(evt, sender);
}
dojo.stopEvent = function(/*Event*/ evt){
// summary:
// prevents propagation and clobbers the default action of the
// passed event
// evt: Event
// The event object. If omitted, window.event is used on IE.
evt.preventDefault();
evt.stopPropagation();
// NOTE: below, this method is overridden for IE
}
// the default listener to use on dontFix nodes, overriden for IE
var node_listener = dojo._listener;
// Unify connect and event listeners
dojo._connect = function(obj, event, context, method, dontFix){
// FIXME: need a more strict test
var isNode = obj && (obj.nodeType||obj.attachEvent||obj.addEventListener);
// choose one of three listener options: raw (connect.js), DOM event on a Node, custom event on a Node
// we need the third option to provide leak prevention on broken browsers (IE)
var lid = isNode ? (dontFix ? 2 : 1) : 0, l = [dojo._listener, del, node_listener][lid];
// create a listener
var h = l.add(obj, event, dojo.hitch(context, method));
// formerly, the disconnect package contained "l" directly, but if client code
// leaks the disconnect package (by connecting it to a node), referencing "l"
// compounds the problem.
// instead we return a listener id, which requires custom _disconnect below.
// return disconnect package
return [ obj, event, h, lid ];
}
dojo._disconnect = function(obj, event, handle, listener){
([dojo._listener, del, node_listener][listener]).remove(obj, event, handle);
}
// Constants
// Public: client code should test
// keyCode against these named constants, as the
// actual codes can vary by browser.
dojo.keys = {
// summary:
// Definitions for common key values
BACKSPACE: 8,
TAB: 9,
CLEAR: 12,
ENTER: 13,
SHIFT: 16,
CTRL: 17,
ALT: 18,
META: dojo.isSafari ? 91 : 224, // the apple key on macs
PAUSE: 19,
CAPS_LOCK: 20,
ESCAPE: 27,
SPACE: 32,
PAGE_UP: 33,
PAGE_DOWN: 34,
END: 35,
HOME: 36,
LEFT_ARROW: 37,
UP_ARROW: 38,
RIGHT_ARROW: 39,
DOWN_ARROW: 40,
INSERT: 45,
DELETE: 46,
HELP: 47,
LEFT_WINDOW: 91,
RIGHT_WINDOW: 92,
SELECT: 93,
NUMPAD_0: 96,
NUMPAD_1: 97,
NUMPAD_2: 98,
NUMPAD_3: 99,
NUMPAD_4: 100,
NUMPAD_5: 101,
NUMPAD_6: 102,
NUMPAD_7: 103,
NUMPAD_8: 104,
NUMPAD_9: 105,
NUMPAD_MULTIPLY: 106,
NUMPAD_PLUS: 107,
NUMPAD_ENTER: 108,
NUMPAD_MINUS: 109,
NUMPAD_PERIOD: 110,
NUMPAD_DIVIDE: 111,
F1: 112,
F2: 113,
F3: 114,
F4: 115,
F5: 116,
F6: 117,
F7: 118,
F8: 119,
F9: 120,
F10: 121,
F11: 122,
F12: 123,
F13: 124,
F14: 125,
F15: 126,
NUM_LOCK: 144,
SCROLL_LOCK: 145,
// virtual key mapping
copyKey: dojo.isMac && !dojo.isAIR ? (dojo.isSafari ? 91 : 224 ) : 17
};
var evtCopyKey = dojo.isMac ? "metaKey" : "ctrlKey";
dojo.isCopyKey = function(e){
// summary:
// Checks an event for the copy key (meta on Mac, and ctrl anywhere else)
// e: Event
// Event object to examine
return e[evtCopyKey]; // Boolean
};
// Public: decoding mouse buttons from events
/*=====
dojo.mouseButtons = {
// LEFT: Number
// Numeric value of the left mouse button for the platform.
LEFT: 0,
// MIDDLE: Number
// Numeric value of the middle mouse button for the platform.
MIDDLE: 1,
// RIGHT: Number
// Numeric value of the right mouse button for the platform.
RIGHT: 2,
isButton: function(e, button){
// summary:
// Checks an event object for a pressed button
// e: Event
// Event object to examine
// button: Number
// The button value (example: dojo.mouseButton.LEFT)
return e.button == button; // Boolean
},
isLeft: function(e){
// summary:
// Checks an event object for the pressed left button
// e: Event
// Event object to examine
return e.button == 0; // Boolean
},
isMiddle: function(e){
// summary:
// Checks an event object for the pressed middle button
// e: Event
// Event object to examine
return e.button == 1; // Boolean
},
isRight: function(e){
// summary:
// Checks an event object for the pressed right button
// e: Event
// Event object to examine
return e.button == 2; // Boolean
}
};
=====*/
if(dojo.isIE){
dojo.mouseButtons = {
LEFT: 1,
MIDDLE: 4,
RIGHT: 2,
// helper functions
isButton: function(e, button){ return e.button & button; },
isLeft: function(e){ return e.button & 1; },
isMiddle: function(e){ return e.button & 4; },
isRight: function(e){ return e.button & 2; }
};
}else{
dojo.mouseButtons = {
LEFT: 0,
MIDDLE: 1,
RIGHT: 2,
// helper functions
isButton: function(e, button){ return e.button == button; },
isLeft: function(e){ return e.button == 0; },
isMiddle: function(e){ return e.button == 1; },
isRight: function(e){ return e.button == 2; }
};
}
// IE event normalization
if(dojo.isIE){
var _trySetKeyCode = function(e, code){
try{
// squelch errors when keyCode is read-only
// (e.g. if keyCode is ctrl or shift)
return (e.keyCode = code);
}catch(e){
return 0;
}
}
// by default, use the standard listener
var iel = dojo._listener;
var listenersName = (dojo._ieListenersName = "_" + dojo._scopeName + "_listeners");
// dispatcher tracking property
if(!dojo.config._allow_leaks){
// custom listener that handles leak protection for DOM events
node_listener = iel = dojo._ie_listener = {
// support handler indirection: event handler functions are
// referenced here. Event dispatchers hold only indices.
handlers: [],
// add a listener to an object
add: function(/*Object*/ source, /*String*/ method, /*Function*/ listener){
source = source || dojo.global;
var f = source[method];
if(!f||!f[listenersName]){
var d = dojo._getIeDispatcher();
// original target function is special
d.target = f && (ieh.push(f) - 1);
// dispatcher holds a list of indices into handlers table
d[listenersName] = [];
// redirect source to dispatcher
f = source[method] = d;
}
return f[listenersName].push(ieh.push(listener) - 1) ; /*Handle*/
},
// remove a listener from an object
remove: function(/*Object*/ source, /*String*/ method, /*Handle*/ handle){
var f = (source||dojo.global)[method], l = f && f[listenersName];
if(f && l && handle--){
delete ieh[l[handle]];
delete l[handle];
}
}
};
// alias used above
var ieh = iel.handlers;
}
dojo.mixin(del, {
add: function(/*DOMNode*/ node, /*String*/ event, /*Function*/ fp){
if(!node){return;} // undefined
event = del._normalizeEventName(event);
if(event=="onkeypress"){
// we need to listen to onkeydown to synthesize
// keypress events that otherwise won't fire
// on IE
var kd = node.onkeydown;
if(!kd || !kd[listenersName] || !kd._stealthKeydownHandle){
var h = del.add(node, "onkeydown", del._stealthKeyDown);
kd = node.onkeydown;
kd._stealthKeydownHandle = h;
kd._stealthKeydownRefs = 1;
}else{
kd._stealthKeydownRefs++;
}
}
return iel.add(node, event, del._fixCallback(fp));
},
remove: function(/*DOMNode*/ node, /*String*/ event, /*Handle*/ handle){
event = del._normalizeEventName(event);
iel.remove(node, event, handle);
if(event=="onkeypress"){
var kd = node.onkeydown;
if(--kd._stealthKeydownRefs <= 0){
iel.remove(node, "onkeydown", kd._stealthKeydownHandle);
delete kd._stealthKeydownHandle;
}
}
},
_normalizeEventName: function(/*String*/ eventName){
// Generally, eventName should be lower case, unless it is
// special somehow (e.g. a Mozilla event)
// ensure 'on'
return eventName.slice(0,2) != "on" ? "on" + eventName : eventName;
},
_nop: function(){},
_fixEvent: function(/*Event*/ evt, /*DOMNode*/ sender){
// summary:
// normalizes properties on the event object including event
// bubbling methods, keystroke normalization, and x/y positions
// evt:
// native event object
// sender:
// node to treat as "currentTarget"
if(!evt){
var w = sender && (sender.ownerDocument || sender.document || sender).parentWindow || window;
evt = w.event;
}
if(!evt){return(evt);}
evt.target = evt.srcElement;
evt.currentTarget = (sender || evt.srcElement);
evt.layerX = evt.offsetX;
evt.layerY = evt.offsetY;
// FIXME: scroll position query is duped from dojo.html to
// avoid dependency on that entire module. Now that HTML is in
// Base, we should convert back to something similar there.
var se = evt.srcElement, doc = (se && se.ownerDocument) || document;
// DO NOT replace the following to use dojo.body(), in IE, document.documentElement should be used
// here rather than document.body
var docBody = ((dojo.isIE < 6) || (doc["compatMode"] == "BackCompat")) ? doc.body : doc.documentElement;
var offset = dojo._getIeDocumentElementOffset();
evt.pageX = evt.clientX + dojo._fixIeBiDiScrollLeft(docBody.scrollLeft || 0) - offset.x;
evt.pageY = evt.clientY + (docBody.scrollTop || 0) - offset.y;
if(evt.type == "mouseover"){
evt.relatedTarget = evt.fromElement;
}
if(evt.type == "mouseout"){
evt.relatedTarget = evt.toElement;
}
evt.stopPropagation = del._stopPropagation;
evt.preventDefault = del._preventDefault;
return del._fixKeys(evt);
},
_fixKeys: function(evt){
switch(evt.type){
case "keypress":
var c = ("charCode" in evt ? evt.charCode : evt.keyCode);
if (c==10){
// CTRL-ENTER is CTRL-ASCII(10) on IE, but CTRL-ENTER on Mozilla
c=0;
evt.keyCode = 13;
}else if(c==13||c==27){
c=0; // Mozilla considers ENTER and ESC non-printable
}else if(c==3){
c=99; // Mozilla maps CTRL-BREAK to CTRL-c
}
// Mozilla sets keyCode to 0 when there is a charCode
// but that stops the event on IE.
evt.charCode = c;
del._setKeyChar(evt);
break;
}
return evt;
},
_stealthKeyDown: function(evt){
// IE doesn't fire keypress for most non-printable characters.
// other browsers do, we simulate it here.
var kp = evt.currentTarget.onkeypress;
// only works if kp exists and is a dispatcher
if(!kp || !kp[listenersName]){ return; }
// munge key/charCode
var k=evt.keyCode;
// These are Windows Virtual Key Codes
// http://msdn.microsoft.com/library/default.asp?url=/library/en-us/winui/WinUI/WindowsUserInterface/UserInput/VirtualKeyCodes.asp
var unprintable = k!=13 && k!=32 && k!=27 && (k<48||k>90) && (k<96||k>111) && (k<186||k>192) && (k<219||k>222);
// synthesize keypress for most unprintables and CTRL-keys
if(unprintable||evt.ctrlKey){
var c = unprintable ? 0 : k;
if(evt.ctrlKey){
if(k==3 || k==13){
return; // IE will post CTRL-BREAK, CTRL-ENTER as keypress natively
}else if(c>95 && c<106){
c -= 48; // map CTRL-[numpad 0-9] to ASCII
}else if((!evt.shiftKey)&&(c>=65&&c<=90)){
c += 32; // map CTRL-[A-Z] to lowercase
}else{
c = del._punctMap[c] || c; // map other problematic CTRL combinations to ASCII
}
}
// simulate a keypress event
var faux = del._synthesizeEvent(evt, {type: 'keypress', faux: true, charCode: c});
kp.call(evt.currentTarget, faux);
evt.cancelBubble = faux.cancelBubble;
evt.returnValue = faux.returnValue;
_trySetKeyCode(evt, faux.keyCode);
}
},
// Called in Event scope
_stopPropagation: function(){
this.cancelBubble = true;
},
_preventDefault: function(){
// Setting keyCode to 0 is the only way to prevent certain keypresses (namely
// ctrl-combinations that correspond to menu accelerator keys).
// Otoh, it prevents upstream listeners from getting this information
// Try to split the difference here by clobbering keyCode only for ctrl
// combinations. If you still need to access the key upstream, bubbledKeyCode is
// provided as a workaround.
this.bubbledKeyCode = this.keyCode;
if(this.ctrlKey){_trySetKeyCode(this, 0);}
this.returnValue = false;
}
});
// override stopEvent for IE
dojo.stopEvent = function(evt){
evt = evt || window.event;
del._stopPropagation.call(evt);
del._preventDefault.call(evt);
}
}
del._synthesizeEvent = function(evt, props){
var faux = dojo.mixin({}, evt, props);
del._setKeyChar(faux);
// FIXME: would prefer to use dojo.hitch: dojo.hitch(evt, evt.preventDefault);
// but it throws an error when preventDefault is invoked on Safari
// does Event.preventDefault not support "apply" on Safari?
faux.preventDefault = function(){ evt.preventDefault(); };
faux.stopPropagation = function(){ evt.stopPropagation(); };
return faux;
}
// Opera event normalization
if(dojo.isOpera){
dojo.mixin(del, {
_fixEvent: function(evt, sender){
switch(evt.type){
case "keypress":
var c = evt.which;
if(c==3){
c=99; // Mozilla maps CTRL-BREAK to CTRL-c
}
// can't trap some keys at all, like INSERT and DELETE
// there is no differentiating info between DELETE and ".", or INSERT and "-"
c = c<41 && !evt.shiftKey ? 0 : c;
if(evt.ctrlKey && !evt.shiftKey && c>=65 && c<=90){
// lowercase CTRL-[A-Z] keys
c += 32;
}
return del._synthesizeEvent(evt, { charCode: c });
}
return evt;
}
});
}
// Webkit event normalization
if(dojo.isWebKit){
del._add = del.add;
del._remove = del.remove;
dojo.mixin(del, {
add: function(/*DOMNode*/ node, /*String*/ event, /*Function*/ fp){
if(!node){return;} // undefined
var handle = del._add(node, event, fp);
if(del._normalizeEventName(event) == "keypress"){
// we need to listen to onkeydown to synthesize
// keypress events that otherwise won't fire
// in Safari 3.1+: https://lists.webkit.org/pipermail/webkit-dev/2007-December/002992.html
handle._stealthKeyDownHandle = del._add(node, "keydown", function(evt){
//A variation on the IE _stealthKeydown function
//Synthesize an onkeypress event, but only for unprintable characters.
var k=evt.keyCode;
// These are Windows Virtual Key Codes
// http://msdn.microsoft.com/library/default.asp?url=/library/en-us/winui/WinUI/WindowsUserInterface/UserInput/VirtualKeyCodes.asp
var unprintable = k!=13 && k!=32 && (k<48 || k>90) && (k<96 || k>111) && (k<186 || k>192) && (k<219 || k>222);
// synthesize keypress for most unprintables and CTRL-keys
if(unprintable || evt.ctrlKey){
var c = unprintable ? 0 : k;
if(evt.ctrlKey){
if(k==3 || k==13){
return; // IE will post CTRL-BREAK, CTRL-ENTER as keypress natively
}else if(c>95 && c<106){
c -= 48; // map CTRL-[numpad 0-9] to ASCII
}else if(!evt.shiftKey && c>=65 && c<=90){
c += 32; // map CTRL-[A-Z] to lowercase
}else{
c = del._punctMap[c] || c; // map other problematic CTRL combinations to ASCII
}
}
// simulate a keypress event
var faux = del._synthesizeEvent(evt, {type: 'keypress', faux: true, charCode: c});
fp.call(evt.currentTarget, faux);
}
});
}
return handle; /*Handle*/
},
remove: function(/*DOMNode*/ node, /*String*/ event, /*Handle*/ handle){
if(node){
if(handle._stealthKeyDownHandle){
del._remove(node, "keydown", handle._stealthKeyDownHandle);
}
del._remove(node, event, handle);
}
},
_fixEvent: function(evt, sender){
switch(evt.type){
case "keypress":
if(evt.faux){ return evt; }
var c = evt.charCode;
c = c>=32 ? c : 0;
return del._synthesizeEvent(evt, {charCode: c, faux: true});
}
return evt;
}
});
}
})();
if(dojo.isIE){
// keep this out of the closure
// closing over 'iel' or 'ieh' b0rks leak prevention
// ls[i] is an index into the master handler array
dojo._ieDispatcher = function(args, sender){
var ap = Array.prototype,
h = dojo._ie_listener.handlers,
c = args.callee,
ls = c[dojo._ieListenersName],
t = h[c.target];
// return value comes from original target function
var r = t && t.apply(sender, args);
// make local copy of listener array so it's immutable during processing
var lls = [].concat(ls);
// invoke listeners after target function
for(var i in lls){
var f = h[lls[i]];
if(!(i in ap) && f){
f.apply(sender, args);
}
}
return r;
}
dojo._getIeDispatcher = function(){
// ensure the returned function closes over nothing ("new Function" apparently doesn't close)
return new Function(dojo._scopeName + "._ieDispatcher(arguments, this)"); // function
}
// keep this out of the closure to reduce RAM allocation
dojo._event_listener._fixCallback = function(fp){
var f = dojo._event_listener._fixEvent;
return function(e){ return fp.call(this, f(e, this)); };
}
}
}
if(!dojo._hasResource["dojo._base.html"]){ //_hasResource checks added by build. Do not use _hasResource directly in your code.
dojo._hasResource["dojo._base.html"] = true;
dojo.provide("dojo._base.html");
// FIXME: need to add unit tests for all the semi-public methods
try{
document.execCommand("BackgroundImageCache", false, true);
}catch(e){
// sane browsers don't have cache "issues"
}
// =============================
// DOM Functions
// =============================
/*=====
dojo.byId = function(id, doc){
// summary:
// Returns DOM node with matching `id` attribute or `null`
// if not found. If `id` is a DomNode, this function is a no-op.
//
// id: String|DOMNode
// A string to match an HTML id attribute or a reference to a DOM Node
//
// doc: Document?
// Document to work in. Defaults to the current value of
// dojo.doc. Can be used to retrieve
// node references from other documents.
//
// example:
// Look up a node by ID:
// | var n = dojo.byId("foo");
//
// example:
// Check if a node exists, and use it.
// | var n = dojo.byId("bar");
// | if(n){ doStuff() ... }
//
// example:
// Allow string or DomNode references to be passed to a custom function:
// | var foo = function(nodeOrId){
// | nodeOrId = dojo.byId(nodeOrId);
// | // ... more stuff
// | }
=====*/
if(dojo.isIE || dojo.isOpera){
dojo.byId = function(id, doc){
if(typeof id != "string"){
return id;
}
var _d = doc || dojo.doc, te = _d.getElementById(id);
// attributes.id.value is better than just id in case the
// user has a name=id inside a form
if(te && (te.attributes.id.value == id || te.id == id)){
return te;
}else{
var eles = _d.all[id];
if(!eles || eles.nodeName){
eles = [eles];
}
// if more than 1, choose first with the correct id
var i=0;
while((te=eles[i++])){
if((te.attributes && te.attributes.id && te.attributes.id.value == id)
|| te.id == id){
return te;
}
}
}
};
}else{
dojo.byId = function(id, doc){
// inline'd type check
return (typeof id == "string") ? (doc || dojo.doc).getElementById(id) : id; // DomNode
};
}
/*=====
};
=====*/
(function(){
var d = dojo;
var byId = d.byId;
var _destroyContainer = null,
_destroyDoc;
d.addOnWindowUnload(function(){
_destroyContainer = null; //prevent IE leak
});
/*=====
dojo._destroyElement = function(node){
// summary:
// Existing alias for `dojo.destroy`. Deprecated, will be removed
// in 2.0
}
=====*/
dojo._destroyElement = dojo.destroy = function(/*String|DomNode*/node){
// summary:
// Removes a node from its parent, clobbering it and all of its
// children.
//
// description:
// Removes a node from its parent, clobbering it and all of its
// children. Function only works with DomNodes, and returns nothing.
//
// node:
// A String ID or DomNode reference of the element to be destroyed
//
// example:
// Destroy a node byId:
// | dojo.destroy("someId");
//
// example:
// Destroy all nodes in a list by reference:
// | dojo.query(".someNode").forEach(dojo.destroy);
node = byId(node);
try{
var doc = node.ownerDocument;
// cannot use _destroyContainer.ownerDocument since this can throw an exception on IE
if(!_destroyContainer || _destroyDoc != doc){
_destroyContainer = doc.createElement("div");
_destroyDoc = doc;
}
_destroyContainer.appendChild(node.parentNode ? node.parentNode.removeChild(node) : node);
// NOTE: see http://trac.dojotoolkit.org/ticket/2931. This may be a bug and not a feature
_destroyContainer.innerHTML = "";
}catch(e){
/* squelch */
}
};
dojo.isDescendant = function(/*DomNode|String*/node, /*DomNode|String*/ancestor){
// summary:
// Returns true if node is a descendant of ancestor
// node: string id or node reference to test
// ancestor: string id or node reference of potential parent to test against
//
// example:
// Test is node id="bar" is a descendant of node id="foo"
// | if(dojo.isDescendant("bar", "foo")){ ... }
try{
node = byId(node);
ancestor = byId(ancestor);
while(node){
if(node == ancestor){
return true; // Boolean
}
node = node.parentNode;
}
}catch(e){ /* squelch, return false */ }
return false; // Boolean
};
dojo.setSelectable = function(/*DomNode|String*/node, /*Boolean*/selectable){
// summary:
// Enable or disable selection on a node
// node:
// id or reference to node
// selectable:
// state to put the node in. false indicates unselectable, true
// allows selection.
// example:
// Make the node id="bar" unselectable
// | dojo.setSelectable("bar");
// example:
// Make the node id="bar" selectable
// | dojo.setSelectable("bar", true);
node = byId(node);
if(d.isMozilla){
node.style.MozUserSelect = selectable ? "" : "none";
}else if(d.isKhtml || d.isWebKit){
node.style.KhtmlUserSelect = selectable ? "auto" : "none";
}else if(d.isIE){
var v = (node.unselectable = selectable ? "" : "on");
d.query("*", node).forEach("item.unselectable = '"+v+"'");
}
//FIXME: else? Opera?
};
var _insertBefore = function(/*DomNode*/node, /*DomNode*/ref){
var parent = ref.parentNode;
if(parent){
parent.insertBefore(node, ref);
}
};
var _insertAfter = function(/*DomNode*/node, /*DomNode*/ref){
// summary:
// Try to insert node after ref
var parent = ref.parentNode;
if(parent){
if(parent.lastChild == ref){
parent.appendChild(node);
}else{
parent.insertBefore(node, ref.nextSibling);
}
}
};
dojo.place = function(node, refNode, position){
// summary:
// Attempt to insert node into the DOM, choosing from various positioning options.
// Returns the first argument resolved to a DOM node.
//
// node: String|DomNode
// id or node reference, or HTML fragment starting with "<" to place relative to refNode
//
// refNode: String|DomNode
// id or node reference to use as basis for placement
//
// position: String|Number?
// string noting the position of node relative to refNode or a
// number indicating the location in the childNodes collection of refNode.
// Accepted string values are:
// | * before
// | * after
// | * replace
// | * only
// | * first
// | * last
// "first" and "last" indicate positions as children of refNode, "replace" replaces refNode,
// "only" replaces all children. position defaults to "last" if not specified
//
// returns: DomNode
// Returned values is the first argument resolved to a DOM node.
//
// .place() is also a method of `dojo.NodeList`, allowing `dojo.query` node lookups.
//
// example:
// Place a node by string id as the last child of another node by string id:
// | dojo.place("someNode", "anotherNode");
//
// example:
// Place a node by string id before another node by string id
// | dojo.place("someNode", "anotherNode", "before");
//
// example:
// Create a Node, and place it in the body element (last child):
// | dojo.place("", dojo.body());
//
// example:
// Put a new LI as the first child of a list by id:
// | dojo.place("", "someUl", "first");
refNode = byId(refNode);
if(typeof node == "string"){ // inline'd type check
node = node.charAt(0) == "<" ? d._toDom(node, refNode.ownerDocument) : byId(node);
}
if(typeof position == "number"){ // inline'd type check
var cn = refNode.childNodes;
if(!cn.length || cn.length <= position){
refNode.appendChild(node);
}else{
_insertBefore(node, cn[position < 0 ? 0 : position]);
}
}else{
switch(position){
case "before":
_insertBefore(node, refNode);
break;
case "after":
_insertAfter(node, refNode);
break;
case "replace":
refNode.parentNode.replaceChild(node, refNode);
break;
case "only":
d.empty(refNode);
refNode.appendChild(node);
break;
case "first":
if(refNode.firstChild){
_insertBefore(node, refNode.firstChild);
break;
}
// else fallthrough...
default: // aka: last
refNode.appendChild(node);
}
}
return node; // DomNode
}
// Box functions will assume this model.
// On IE/Opera, BORDER_BOX will be set if the primary document is in quirks mode.
// Can be set to change behavior of box setters.
// can be either:
// "border-box"
// "content-box" (default)
dojo.boxModel = "content-box";
// We punt per-node box mode testing completely.
// If anybody cares, we can provide an additional (optional) unit
// that overrides existing code to include per-node box sensitivity.
// Opera documentation claims that Opera 9 uses border-box in BackCompat mode.
// but experiments (Opera 9.10.8679 on Windows Vista) indicate that it actually continues to use content-box.
// IIRC, earlier versions of Opera did in fact use border-box.
// Opera guys, this is really confusing. Opera being broken in quirks mode is not our fault.
if(d.isIE /*|| dojo.isOpera*/){
// client code may have to adjust if compatMode varies across iframes
d.boxModel = document.compatMode == "BackCompat" ? "border-box" : "content-box";
}
// =============================
// Style Functions
// =============================
// getComputedStyle drives most of the style code.
// Wherever possible, reuse the returned object.
//
// API functions below that need to access computed styles accept an
// optional computedStyle parameter.
// If this parameter is omitted, the functions will call getComputedStyle themselves.
// This way, calling code can access computedStyle once, and then pass the reference to
// multiple API functions.
/*=====
dojo.getComputedStyle = function(node){
// summary:
// Returns a "computed style" object.
//
// description:
// Gets a "computed style" object which can be used to gather
// information about the current state of the rendered node.
//
// Note that this may behave differently on different browsers.
// Values may have different formats and value encodings across
// browsers.
//
// Note also that this method is expensive. Wherever possible,
// reuse the returned object.
//
// Use the dojo.style() method for more consistent (pixelized)
// return values.
//
// node: DOMNode
// A reference to a DOM node. Does NOT support taking an
// ID string for speed reasons.
// example:
// | dojo.getComputedStyle(dojo.byId('foo')).borderWidth;
//
// example:
// Reusing the returned object, avoiding multiple lookups:
// | var cs = dojo.getComputedStyle(dojo.byId("someNode"));
// | var w = cs.width, h = cs.height;
return; // CSS2Properties
}
=====*/
// Although we normally eschew argument validation at this
// level, here we test argument 'node' for (duck)type,
// by testing nodeType, ecause 'document' is the 'parentNode' of 'body'
// it is frequently sent to this function even
// though it is not Element.
var gcs;
if(d.isWebKit){
gcs = function(/*DomNode*/node){
var s;
if(node.nodeType == 1){
var dv = node.ownerDocument.defaultView;
s = dv.getComputedStyle(node, null);
if(!s && node.style){
node.style.display = "";
s = dv.getComputedStyle(node, null);
}
}
return s || {};
};
}else if(d.isIE){
gcs = function(node){
// IE (as of 7) doesn't expose Element like sane browsers
return node.nodeType == 1 /* ELEMENT_NODE*/ ? node.currentStyle : {};
};
}else{
gcs = function(node){
return node.nodeType == 1 ?
node.ownerDocument.defaultView.getComputedStyle(node, null) : {};
};
}
dojo.getComputedStyle = gcs;
if(!d.isIE){
d._toPixelValue = function(element, value){
// style values can be floats, client code may want
// to round for integer pixels.
return parseFloat(value) || 0;
};
}else{
d._toPixelValue = function(element, avalue){
if(!avalue){ return 0; }
// on IE7, medium is usually 4 pixels
if(avalue == "medium"){ return 4; }
// style values can be floats, client code may
// want to round this value for integer pixels.
if(avalue.slice && avalue.slice(-2) == 'px'){ return parseFloat(avalue); }
with(element){
var sLeft = style.left;
var rsLeft = runtimeStyle.left;
runtimeStyle.left = currentStyle.left;
try{
// 'avalue' may be incompatible with style.left, which can cause IE to throw
// this has been observed for border widths using "thin", "medium", "thick" constants
// those particular constants could be trapped by a lookup
// but perhaps there are more
style.left = avalue;
avalue = style.pixelLeft;
}catch(e){
avalue = 0;
}
style.left = sLeft;
runtimeStyle.left = rsLeft;
}
return avalue;
}
}
var px = d._toPixelValue;
// FIXME: there opacity quirks on FF that we haven't ported over. Hrm.
/*=====
dojo._getOpacity = function(node){
// summary:
// Returns the current opacity of the passed node as a
// floating-point value between 0 and 1.
// node: DomNode
// a reference to a DOM node. Does NOT support taking an
// ID string for speed reasons.
// returns: Number between 0 and 1
return; // Number
}
=====*/
var astr = "DXImageTransform.Microsoft.Alpha";
var af = function(n, f){
try{
return n.filters.item(astr);
}catch(e){
return f ? {} : null;
}
};
dojo._getOpacity =
d.isIE ? function(node){
try{
return af(node).Opacity / 100; // Number
}catch(e){
return 1; // Number
}
} :
function(node){
return gcs(node).opacity;
};
/*=====
dojo._setOpacity = function(node, opacity){
// summary:
// set the opacity of the passed node portably. Returns the
// new opacity of the node.
// node: DOMNode
// a reference to a DOM node. Does NOT support taking an
// ID string for performance reasons.
// opacity: Number
// A Number between 0 and 1. 0 specifies transparent.
// returns: Number between 0 and 1
return; // Number
}
=====*/
dojo._setOpacity =
d.isIE ? function(/*DomNode*/node, /*Number*/opacity){
var ov = opacity * 100, opaque = opacity == 1;
node.style.zoom = opaque ? "" : 1;
if(!af(node)){
if(opaque){
return opacity;
}
node.style.filter += " progid:" + astr + "(Opacity=" + ov + ")";
}else{
af(node, 1).Opacity = ov;
}
// on IE7 Alpha(Filter opacity=100) makes text look fuzzy so disable it altogether (bug #2661),
//but still update the opacity value so we can get a correct reading if it is read later.
af(node, 1).Enabled = !opaque;
if(node.nodeName.toLowerCase() == "tr"){
d.query("> td", node).forEach(function(i){
d._setOpacity(i, opacity);
});
}
return opacity;
} :
function(node, opacity){
return node.style.opacity = opacity;
};
var _pixelNamesCache = {
left: true, top: true
};
var _pixelRegExp = /margin|padding|width|height|max|min|offset/; // |border
var _toStyleValue = function(node, type, value){
type = type.toLowerCase(); // FIXME: should we really be doing string case conversion here? Should we cache it? Need to profile!
if(d.isIE){
if(value == "auto"){
if(type == "height"){ return node.offsetHeight; }
if(type == "width"){ return node.offsetWidth; }
}
if(type == "fontweight"){
switch(value){
case 700: return "bold";
case 400:
default: return "normal";
}
}
}
if(!(type in _pixelNamesCache)){
_pixelNamesCache[type] = _pixelRegExp.test(type);
}
return _pixelNamesCache[type] ? px(node, value) : value;
};
var _floatStyle = d.isIE ? "styleFloat" : "cssFloat",
_floatAliases = { "cssFloat": _floatStyle, "styleFloat": _floatStyle, "float": _floatStyle }
;
// public API
dojo.style = function( /*DomNode|String*/ node,
/*String?|Object?*/ style,
/*String?*/ value){
// summary:
// Accesses styles on a node. If 2 arguments are
// passed, acts as a getter. If 3 arguments are passed, acts
// as a setter.
// description:
// Getting the style value uses the computed style for the node, so the value
// will be a calculated value, not just the immediate node.style value.
// Also when getting values, use specific style names,
// like "borderBottomWidth" instead of "border" since compound values like
// "border" are not necessarily reflected as expected.
// If you want to get node dimensions, use `dojo.marginBox()`,
// `dojo.contentBox()` or `dojo.position()`.
// node:
// id or reference to node to get/set style for
// style:
// the style property to set in DOM-accessor format
// ("borderWidth", not "border-width") or an object with key/value
// pairs suitable for setting each property.
// value:
// If passed, sets value on the node for style, handling
// cross-browser concerns. When setting a pixel value,
// be sure to include "px" in the value. For instance, top: "200px".
// Otherwise, in some cases, some browsers will not apply the style.
// example:
// Passing only an ID or node returns the computed style object of
// the node:
// | dojo.style("thinger");
// example:
// Passing a node and a style property returns the current
// normalized, computed value for that property:
// | dojo.style("thinger", "opacity"); // 1 by default
//
// example:
// Passing a node, a style property, and a value changes the
// current display of the node and returns the new computed value
// | dojo.style("thinger", "opacity", 0.5); // == 0.5
//
// example:
// Passing a node, an object-style style property sets each of the values in turn and returns the computed style object of the node:
// | dojo.style("thinger", {
// | "opacity": 0.5,
// | "border": "3px solid black",
// | "height": "300px"
// | });
//
// example:
// When the CSS style property is hyphenated, the JavaScript property is camelCased.
// font-size becomes fontSize, and so on.
// | dojo.style("thinger",{
// | fontSize:"14pt",
// | letterSpacing:"1.2em"
// | });
//
// example:
// dojo.NodeList implements .style() using the same syntax, omitting the "node" parameter, calling
// dojo.style() on every element of the list. See: `dojo.query()` and `dojo.NodeList()`
// | dojo.query(".someClassName").style("visibility","hidden");
// | // or
// | dojo.query("#baz > div").style({
// | opacity:0.75,
// | fontSize:"13pt"
// | });
var n = byId(node), args = arguments.length, op = (style == "opacity");
style = _floatAliases[style] || style;
if(args == 3){
return op ? d._setOpacity(n, value) : n.style[style] = value; /*Number*/
}
if(args == 2 && op){
return d._getOpacity(n);
}
var s = gcs(n);
if(args == 2 && typeof style != "string"){ // inline'd type check
for(var x in style){
d.style(node, x, style[x]);
}
return s;
}
return (args == 1) ? s : _toStyleValue(n, style, s[style] || n.style[style]); /* CSS2Properties||String||Number */
}
// =============================
// Box Functions
// =============================
dojo._getPadExtents = function(/*DomNode*/n, /*Object*/computedStyle){
// summary:
// Returns object with special values specifically useful for node
// fitting.
// description:
// Returns an object with `w`, `h`, `l`, `t` properties:
// | l/t = left/top padding (respectively)
// | w = the total of the left and right padding
// | h = the total of the top and bottom padding
// If 'node' has position, l/t forms the origin for child nodes.
// The w/h are used for calculating boxes.
// Normally application code will not need to invoke this
// directly, and will use the ...box... functions instead.
var
s = computedStyle||gcs(n),
l = px(n, s.paddingLeft),
t = px(n, s.paddingTop);
return {
l: l,
t: t,
w: l+px(n, s.paddingRight),
h: t+px(n, s.paddingBottom)
};
}
dojo._getBorderExtents = function(/*DomNode*/n, /*Object*/computedStyle){
// summary:
// returns an object with properties useful for noting the border
// dimensions.
// description:
// * l/t = the sum of left/top border (respectively)
// * w = the sum of the left and right border
// * h = the sum of the top and bottom border
//
// The w/h are used for calculating boxes.
// Normally application code will not need to invoke this
// directly, and will use the ...box... functions instead.
var
ne = "none",
s = computedStyle||gcs(n),
bl = (s.borderLeftStyle != ne ? px(n, s.borderLeftWidth) : 0),
bt = (s.borderTopStyle != ne ? px(n, s.borderTopWidth) : 0);
return {
l: bl,
t: bt,
w: bl + (s.borderRightStyle!=ne ? px(n, s.borderRightWidth) : 0),
h: bt + (s.borderBottomStyle!=ne ? px(n, s.borderBottomWidth) : 0)
};
}
dojo._getPadBorderExtents = function(/*DomNode*/n, /*Object*/computedStyle){
// summary:
// Returns object with properties useful for box fitting with
// regards to padding.
// description:
// * l/t = the sum of left/top padding and left/top border (respectively)
// * w = the sum of the left and right padding and border
// * h = the sum of the top and bottom padding and border
//
// The w/h are used for calculating boxes.
// Normally application code will not need to invoke this
// directly, and will use the ...box... functions instead.
var
s = computedStyle||gcs(n),
p = d._getPadExtents(n, s),
b = d._getBorderExtents(n, s);
return {
l: p.l + b.l,
t: p.t + b.t,
w: p.w + b.w,
h: p.h + b.h
};
}
dojo._getMarginExtents = function(n, computedStyle){
// summary:
// returns object with properties useful for box fitting with
// regards to box margins (i.e., the outer-box).
//
// * l/t = marginLeft, marginTop, respectively
// * w = total width, margin inclusive
// * h = total height, margin inclusive
//
// The w/h are used for calculating boxes.
// Normally application code will not need to invoke this
// directly, and will use the ...box... functions instead.
var
s = computedStyle||gcs(n),
l = px(n, s.marginLeft),
t = px(n, s.marginTop),
r = px(n, s.marginRight),
b = px(n, s.marginBottom);
if(d.isWebKit && (s.position != "absolute")){
// FIXME: Safari's version of the computed right margin
// is the space between our right edge and the right edge
// of our offsetParent.
// What we are looking for is the actual margin value as
// determined by CSS.
// Hack solution is to assume left/right margins are the same.
r = l;
}
return {
l: l,
t: t,
w: l+r,
h: t+b
};
}
// Box getters work in any box context because offsetWidth/clientWidth
// are invariant wrt box context
//
// They do *not* work for display: inline objects that have padding styles
// because the user agent ignores padding (it's bogus styling in any case)
//
// Be careful with IMGs because they are inline or block depending on
// browser and browser mode.
// Although it would be easier to read, there are not separate versions of
// _getMarginBox for each browser because:
// 1. the branching is not expensive
// 2. factoring the shared code wastes cycles (function call overhead)
// 3. duplicating the shared code wastes bytes
dojo._getMarginBox = function(/*DomNode*/node, /*Object*/computedStyle){
// summary:
// returns an object that encodes the width, height, left and top
// positions of the node's margin box.
var s = computedStyle || gcs(node), me = d._getMarginExtents(node, s);
var l = node.offsetLeft - me.l, t = node.offsetTop - me.t, p = node.parentNode;
if(d.isMoz){
// Mozilla:
// If offsetParent has a computed overflow != visible, the offsetLeft is decreased
// by the parent's border.
// We don't want to compute the parent's style, so instead we examine node's
// computed left/top which is more stable.
var sl = parseFloat(s.left), st = parseFloat(s.top);
if(!isNaN(sl) && !isNaN(st)){
l = sl, t = st;
}else{
// If child's computed left/top are not parseable as a number (e.g. "auto"), we
// have no choice but to examine the parent's computed style.
if(p && p.style){
var pcs = gcs(p);
if(pcs.overflow != "visible"){
var be = d._getBorderExtents(p, pcs);
l += be.l, t += be.t;
}
}
}
}else if(d.isOpera || (d.isIE > 7 && !d.isQuirks)){
// On Opera and IE 8, offsetLeft/Top includes the parent's border
if(p){
be = d._getBorderExtents(p);
l -= be.l;
t -= be.t;
}
}
return {
l: l,
t: t,
w: node.offsetWidth + me.w,
h: node.offsetHeight + me.h
};
}
dojo._getContentBox = function(node, computedStyle){
// summary:
// Returns an object that encodes the width, height, left and top
// positions of the node's content box, irrespective of the
// current box model.
// clientWidth/Height are important since the automatically account for scrollbars
// fallback to offsetWidth/Height for special cases (see #3378)
var s = computedStyle || gcs(node),
pe = d._getPadExtents(node, s),
be = d._getBorderExtents(node, s),
w = node.clientWidth,
h
;
if(!w){
w = node.offsetWidth, h = node.offsetHeight;
}else{
h = node.clientHeight, be.w = be.h = 0;
}
// On Opera, offsetLeft includes the parent's border
if(d.isOpera){ pe.l += be.l; pe.t += be.t; };
return {
l: pe.l,
t: pe.t,
w: w - pe.w - be.w,
h: h - pe.h - be.h
};
}
dojo._getBorderBox = function(node, computedStyle){
var s = computedStyle || gcs(node),
pe = d._getPadExtents(node, s),
cb = d._getContentBox(node, s)
;
return {
l: cb.l - pe.l,
t: cb.t - pe.t,
w: cb.w + pe.w,
h: cb.h + pe.h
};
}
// Box setters depend on box context because interpretation of width/height styles
// vary wrt box context.
//
// The value of dojo.boxModel is used to determine box context.
// dojo.boxModel can be set directly to change behavior.
//
// Beware of display: inline objects that have padding styles
// because the user agent ignores padding (it's a bogus setup anyway)
//
// Be careful with IMGs because they are inline or block depending on
// browser and browser mode.
//
// Elements other than DIV may have special quirks, like built-in
// margins or padding, or values not detectable via computedStyle.
// In particular, margins on TABLE do not seems to appear
// at all in computedStyle on Mozilla.
dojo._setBox = function(/*DomNode*/node, /*Number?*/l, /*Number?*/t, /*Number?*/w, /*Number?*/h, /*String?*/u){
// summary:
// sets width/height/left/top in the current (native) box-model
// dimentions. Uses the unit passed in u.
// node:
// DOM Node reference. Id string not supported for performance
// reasons.
// l:
// left offset from parent.
// t:
// top offset from parent.
// w:
// width in current box model.
// h:
// width in current box model.
// u:
// unit measure to use for other measures. Defaults to "px".
u = u || "px";
var s = node.style;
if(!isNaN(l)){ s.left = l + u; }
if(!isNaN(t)){ s.top = t + u; }
if(w >= 0){ s.width = w + u; }
if(h >= 0){ s.height = h + u; }
}
dojo._isButtonTag = function(/*DomNode*/node) {
// summary:
// True if the node is BUTTON or INPUT.type="button".
return node.tagName == "BUTTON"
|| node.tagName=="INPUT" && (node.getAttribute("type")||'').toUpperCase() == "BUTTON"; // boolean
}
dojo._usesBorderBox = function(/*DomNode*/node){
// summary:
// True if the node uses border-box layout.
// We could test the computed style of node to see if a particular box
// has been specified, but there are details and we choose not to bother.
// TABLE and BUTTON (and INPUT type=button) are always border-box by default.
// If you have assigned a different box to either one via CSS then
// box functions will break.
var n = node.tagName;
return d.boxModel=="border-box" || n=="TABLE" || d._isButtonTag(node); // boolean
}
dojo._setContentSize = function(/*DomNode*/node, /*Number*/widthPx, /*Number*/heightPx, /*Object*/computedStyle){
// summary:
// Sets the size of the node's contents, irrespective of margins,
// padding, or borders.
if(d._usesBorderBox(node)){
var pb = d._getPadBorderExtents(node, computedStyle);
if(widthPx >= 0){ widthPx += pb.w; }
if(heightPx >= 0){ heightPx += pb.h; }
}
d._setBox(node, NaN, NaN, widthPx, heightPx);
}
dojo._setMarginBox = function(/*DomNode*/node, /*Number?*/leftPx, /*Number?*/topPx,
/*Number?*/widthPx, /*Number?*/heightPx,
/*Object*/computedStyle){
// summary:
// sets the size of the node's margin box and placement
// (left/top), irrespective of box model. Think of it as a
// passthrough to dojo._setBox that handles box-model vagaries for
// you.
var s = computedStyle || gcs(node),
// Some elements have special padding, margin, and box-model settings.
// To use box functions you may need to set padding, margin explicitly.
// Controlling box-model is harder, in a pinch you might set dojo.boxModel.
bb = d._usesBorderBox(node),
pb = bb ? _nilExtents : d._getPadBorderExtents(node, s)
;
if(d.isWebKit){
// on Safari (3.1.2), button nodes with no explicit size have a default margin
// setting an explicit size eliminates the margin.
// We have to swizzle the width to get correct margin reading.
if(d._isButtonTag(node)){
var ns = node.style;
if(widthPx >= 0 && !ns.width) { ns.width = "4px"; }
if(heightPx >= 0 && !ns.height) { ns.height = "4px"; }
}
}
var mb = d._getMarginExtents(node, s);
if(widthPx >= 0){ widthPx = Math.max(widthPx - pb.w - mb.w, 0); }
if(heightPx >= 0){ heightPx = Math.max(heightPx - pb.h - mb.h, 0); }
d._setBox(node, leftPx, topPx, widthPx, heightPx);
}
var _nilExtents = { l:0, t:0, w:0, h:0 };
// public API
dojo.marginBox = function(/*DomNode|String*/node, /*Object?*/box){
// summary:
// Getter/setter for the margin-box of node.
// description:
// Getter/setter for the margin-box of node.
// Returns an object in the expected format of box (regardless
// if box is passed). The object might look like:
// `{ l: 50, t: 200, w: 300: h: 150 }`
// for a node offset from its parent 50px to the left, 200px from
// the top with a margin width of 300px and a margin-height of
// 150px.
// node:
// id or reference to DOM Node to get/set box for
// box:
// If passed, denotes that dojo.marginBox() should
// update/set the margin box for node. Box is an object in the
// above format. All properties are optional if passed.
// example:
// Retrieve the marginbox of a passed node
// | var box = dojo.marginBox("someNodeId");
// | console.dir(box);
//
// example:
// Set a node's marginbox to the size of another node
// | var box = dojo.marginBox("someNodeId");
// | dojo.marginBox("someOtherNode", box);
var n = byId(node), s = gcs(n), b = box;
return !b ? d._getMarginBox(n, s) : d._setMarginBox(n, b.l, b.t, b.w, b.h, s); // Object
}
dojo.contentBox = function(/*DomNode|String*/node, /*Object?*/box){
// summary:
// Getter/setter for the content-box of node.
// description:
// Returns an object in the expected format of box (regardless if box is passed).
// The object might look like:
// `{ l: 50, t: 200, w: 300: h: 150 }`
// for a node offset from its parent 50px to the left, 200px from
// the top with a content width of 300px and a content-height of
// 150px. Note that the content box may have a much larger border
// or margin box, depending on the box model currently in use and
// CSS values set/inherited for node.
// While the getter will return top and left values, the
// setter only accepts setting the width and height.
// node:
// id or reference to DOM Node to get/set box for
// box:
// If passed, denotes that dojo.contentBox() should
// update/set the content box for node. Box is an object in the
// above format, but only w (width) and h (height) are supported.
// All properties are optional if passed.
var n = byId(node), s = gcs(n), b = box;
return !b ? d._getContentBox(n, s) : d._setContentSize(n, b.w, b.h, s); // Object
}
// =============================
// Positioning
// =============================
var _sumAncestorProperties = function(node, prop){
if(!(node = (node||0).parentNode)){return 0}
var val, retVal = 0, _b = d.body();
while(node && node.style){
if(gcs(node).position == "fixed"){
return 0;
}
val = node[prop];
if(val){
retVal += val - 0;
// opera and khtml #body & #html has the same values, we only
// need one value
if(node == _b){ break; }
}
node = node.parentNode;
}
return retVal; // integer
}
dojo._docScroll = function(){
var n = d.global;
return "pageXOffset" in n? { x:n.pageXOffset, y:n.pageYOffset } :
(n=d.doc.documentElement, n.clientHeight? { x:d._fixIeBiDiScrollLeft(n.scrollLeft), y:n.scrollTop } :
(n=d.body(), { x:n.scrollLeft||0, y:n.scrollTop||0 }));
};
dojo._isBodyLtr = function(){
return "_bodyLtr" in d? d._bodyLtr :
d._bodyLtr = (d.body().dir || d.doc.documentElement.dir || "ltr").toLowerCase() == "ltr"; // Boolean
}
dojo._getIeDocumentElementOffset = function(){
// summary:
// returns the offset in x and y from the document body to the
// visual edge of the page
// description:
// The following values in IE contain an offset:
// | event.clientX
// | event.clientY
// | node.getBoundingClientRect().left
// | node.getBoundingClientRect().top
// But other position related values do not contain this offset,
// such as node.offsetLeft, node.offsetTop, node.style.left and
// node.style.top. The offset is always (2, 2) in LTR direction.
// When the body is in RTL direction, the offset counts the width
// of left scroll bar's width. This function computes the actual
// offset.
//NOTE: assumes we're being called in an IE browser
var de = d.doc.documentElement; // only deal with HTML element here, _abs handles body/quirks
if(d.isIE < 8){
var r = de.getBoundingClientRect(); // works well for IE6+
//console.debug('rect left,top = ' + r.left+','+r.top + ', html client left/top = ' + de.clientLeft+','+de.clientTop + ', rtl = ' + (!d._isBodyLtr()) + ', quirks = ' + d.isQuirks);
var l = r.left,
t = r.top;
if(d.isIE < 7){
l += de.clientLeft; // scrollbar size in strict/RTL, or,
t += de.clientTop; // HTML border size in strict
}
return {
x: l < 0? 0 : l, // FRAME element border size can lead to inaccurate negative values
y: t < 0? 0 : t
};
}else{
return {
x: 0,
y: 0
};
}
};
dojo._fixIeBiDiScrollLeft = function(/*Integer*/ scrollLeft){
// In RTL direction, scrollLeft should be a negative value, but IE < 8
// returns a positive one. All codes using documentElement.scrollLeft
// must call this function to fix this error, otherwise the position
// will offset to right when there is a horizontal scrollbar.
var dd = d.doc;
if(d.isIE < 8 && !d._isBodyLtr()){
var de = d.isQuirks ? dd.body : dd.documentElement;
return scrollLeft + de.clientWidth - de.scrollWidth; // Integer
}
return scrollLeft; // Integer
}
// FIXME: need a setter for coords or a moveTo!!
dojo._abs = dojo.position = function(/*DomNode*/node, /*Boolean?*/includeScroll){
// summary:
// Gets the position and size of the passed element relative to
// the viewport (if includeScroll==false), or relative to the
// document root (if includeScroll==true).
//
// description:
// Returns an object of the form:
// { x: 100, y: 300, w: 20, h: 15 }
// If includeScroll==true, the x and y values will include any
// document offsets that may affect the position relative to the
// viewport.
// Uses the border-box model (inclusive of border and padding but
// not margin). Does not act as a setter.
var db = d.body(), dh = db.parentNode, ret;
node = byId(node);
if(node["getBoundingClientRect"]){
// IE6+, FF3+, super-modern WebKit, and Opera 9.6+ all take this branch
ret = node.getBoundingClientRect();
ret = { x: ret.left, y: ret.top, w: ret.right - ret.left, h: ret.bottom - ret.top };
if(d.isIE){
// On IE there's a 2px offset that we need to adjust for, see _getIeDocumentElementOffset()
var offset = d._getIeDocumentElementOffset();
// fixes the position in IE, quirks mode
ret.x -= offset.x + (d.isQuirks ? db.clientLeft+db.offsetLeft : 0);
ret.y -= offset.y + (d.isQuirks ? db.clientTop+db.offsetTop : 0);
}else if(d.isFF == 3){
// In FF3 you have to subtract the document element margins.
// Fixed in FF3.5 though.
var cs = gcs(dh);
ret.x -= px(dh, cs.marginLeft) + px(dh, cs.borderLeftWidth);
ret.y -= px(dh, cs.marginTop) + px(dh, cs.borderTopWidth);
}
}else{
// FF2 and older WebKit
ret = {
x: 0,
y: 0,
w: node.offsetWidth,
h: node.offsetHeight
};
if(node["offsetParent"]){
ret.x -= _sumAncestorProperties(node, "scrollLeft");
ret.y -= _sumAncestorProperties(node, "scrollTop");
var curnode = node;
do{
var n = curnode.offsetLeft,
t = curnode.offsetTop;
ret.x += isNaN(n) ? 0 : n;
ret.y += isNaN(t) ? 0 : t;
cs = gcs(curnode);
if(curnode != node){
if(d.isMoz){
// tried left+right with differently sized left/right borders
// it really is 2xleft border in FF, not left+right, even in RTL!
ret.x += 2 * px(curnode,cs.borderLeftWidth);
ret.y += 2 * px(curnode,cs.borderTopWidth);
}else{
ret.x += px(curnode, cs.borderLeftWidth);
ret.y += px(curnode, cs.borderTopWidth);
}
}
// static children in a static div in FF2 are affected by the div's border as well
// but offsetParent will skip this div!
if(d.isMoz && cs.position=="static"){
var parent=curnode.parentNode;
while(parent!=curnode.offsetParent){
var pcs=gcs(parent);
if(pcs.position=="static"){
ret.x += px(curnode,pcs.borderLeftWidth);
ret.y += px(curnode,pcs.borderTopWidth);
}
parent=parent.parentNode;
}
}
curnode = curnode.offsetParent;
}while((curnode != dh) && curnode);
}else if(node.x && node.y){
ret.x += isNaN(node.x) ? 0 : node.x;
ret.y += isNaN(node.y) ? 0 : node.y;
}
}
// account for document scrolling
// if offsetParent is used, ret value already includes scroll position
// so we may have to actually remove that value if !includeScroll
if(includeScroll){
var scroll = d._docScroll();
ret.x += scroll.x;
ret.y += scroll.y;
}
return ret; // Object
}
dojo.coords = function(/*DomNode|String*/node, /*Boolean?*/includeScroll){
// summary:
// Deprecated: Use position() for border-box x/y/w/h
// or marginBox() for margin-box w/h/l/t.
// Returns an object representing a node's size and position.
//
// description:
// Returns an object that measures margin-box (w)idth/(h)eight
// and absolute position x/y of the border-box. Also returned
// is computed (l)eft and (t)op values in pixels from the
// node's offsetParent as returned from marginBox().
// Return value will be in the form:
//| { l: 50, t: 200, w: 300: h: 150, x: 100, y: 300 }
// Does not act as a setter. If includeScroll is passed, the x and
// y params are affected as one would expect in dojo.position().
var n = byId(node), s = gcs(n), mb = d._getMarginBox(n, s);
var abs = d.position(n, includeScroll);
mb.x = abs.x;
mb.y = abs.y;
return mb;
}
// =============================
// Element attribute Functions
// =============================
// dojo.attr() should conform to http://www.w3.org/TR/DOM-Level-2-Core/
var _propNames = {
// properties renamed to avoid clashes with reserved words
"class": "className",
"for": "htmlFor",
// properties written as camelCase
tabindex: "tabIndex",
readonly: "readOnly",
colspan: "colSpan",
frameborder: "frameBorder",
rowspan: "rowSpan",
valuetype: "valueType"
},
_attrNames = {
// original attribute names
classname: "class",
htmlfor: "for",
// for IE
tabindex: "tabIndex",
readonly: "readOnly"
},
_forcePropNames = {
innerHTML: 1,
className: 1,
htmlFor: d.isIE,
value: 1
};
var _fixAttrName = function(/*String*/ name){
return _attrNames[name.toLowerCase()] || name;
};
var _hasAttr = function(node, name){
var attr = node.getAttributeNode && node.getAttributeNode(name);
return attr && attr.specified; // Boolean
};
// There is a difference in the presence of certain properties and their default values
// between browsers. For example, on IE "disabled" is present on all elements,
// but it is value is "false"; "tabIndex" of
returns 0 by default on IE, yet other browsers
// can return -1.
dojo.hasAttr = function(/*DomNode|String*/node, /*String*/name){
// summary:
// Returns true if the requested attribute is specified on the
// given element, and false otherwise.
// node:
// id or reference to the element to check
// name:
// the name of the attribute
// returns:
// true if the requested attribute is specified on the
// given element, and false otherwise
var lc = name.toLowerCase();
return _forcePropNames[_propNames[lc] || name] || _hasAttr(byId(node), _attrNames[lc] || name); // Boolean
}
var _evtHdlrMap = {}, _ctr = 0,
_attrId = dojo._scopeName + "attrid",
// the next dictionary lists elements with read-only innerHTML on IE
_roInnerHtml = {col: 1, colgroup: 1,
// frameset: 1, head: 1, html: 1, style: 1,
table: 1, tbody: 1, tfoot: 1, thead: 1, tr: 1, title: 1};
dojo.attr = function(/*DomNode|String*/node, /*String|Object*/name, /*String?*/value){
// summary:
// Gets or sets an attribute on an HTML element.
// description:
// Handles normalized getting and setting of attributes on DOM
// Nodes. If 2 arguments are passed, and a the second argumnt is a
// string, acts as a getter.
//
// If a third argument is passed, or if the second argument is a
// map of attributes, acts as a setter.
//
// When passing functions as values, note that they will not be
// directly assigned to slots on the node, but rather the default
// behavior will be removed and the new behavior will be added
// using `dojo.connect()`, meaning that event handler properties
// will be normalized and that some caveats with regards to
// non-standard behaviors for onsubmit apply. Namely that you
// should cancel form submission using `dojo.stopEvent()` on the
// passed event object instead of returning a boolean value from
// the handler itself.
// node:
// id or reference to the element to get or set the attribute on
// name:
// the name of the attribute to get or set.
// value:
// The value to set for the attribute
// returns:
// when used as a getter, the value of the requested attribute
// or null if that attribute does not have a specified or
// default value;
//
// when used as a setter, the DOM node
//
// example:
// | // get the current value of the "foo" attribute on a node
// | dojo.attr(dojo.byId("nodeId"), "foo");
// | // or we can just pass the id:
// | dojo.attr("nodeId", "foo");
//
// example:
// | // use attr() to set the tab index
// | dojo.attr("nodeId", "tabIndex", 3);
// |
//
// example:
// Set multiple values at once, including event handlers:
// | dojo.attr("formId", {
// | "foo": "bar",
// | "tabIndex": -1,
// | "method": "POST",
// | "onsubmit": function(e){
// | // stop submitting the form. Note that the IE behavior
// | // of returning true or false will have no effect here
// | // since our handler is connect()ed to the built-in
// | // onsubmit behavior and so we need to use
// | // dojo.stopEvent() to ensure that the submission
// | // doesn't proceed.
// | dojo.stopEvent(e);
// |
// | // submit the form with Ajax
// | dojo.xhrPost({ form: "formId" });
// | }
// | });
//
// example:
// Style is s special case: Only set with an object hash of styles
// | dojo.attr("someNode",{
// | id:"bar",
// | style:{
// | width:"200px", height:"100px", color:"#000"
// | }
// | });
//
// example:
// Again, only set style as an object hash of styles:
// | var obj = { color:"#fff", backgroundColor:"#000" };
// | dojo.attr("someNode", "style", obj);
// |
// | // though shorter to use `dojo.style()` in this case:
// | dojo.style("someNode", obj);
node = byId(node);
var args = arguments.length, prop;
if(args == 2 && typeof name != "string"){ // inline'd type check
// the object form of setter: the 2nd argument is a dictionary
for(var x in name){
d.attr(node, x, name[x]);
}
return node; // DomNode
}
var lc = name.toLowerCase(),
propName = _propNames[lc] || name,
forceProp = _forcePropNames[propName],
attrName = _attrNames[lc] || name;
if(args == 3){
// setter
do{
if(propName == "style" && typeof value != "string"){ // inline'd type check
// special case: setting a style
d.style(node, value);
break;
}
if(propName == "innerHTML"){
// special case: assigning HTML
if(d.isIE && node.tagName.toLowerCase() in _roInnerHtml){
d.empty(node);
node.appendChild(d._toDom(value, node.ownerDocument));
}else{
node[propName] = value;
}
break;
}
if(d.isFunction(value)){
// special case: assigning an event handler
// clobber if we can
var attrId = d.attr(node, _attrId);
if(!attrId){
attrId = _ctr++;
d.attr(node, _attrId, attrId);
}
if(!_evtHdlrMap[attrId]){
_evtHdlrMap[attrId] = {};
}
var h = _evtHdlrMap[attrId][propName];
if(h){
d.disconnect(h);
}else{
try{
delete node[propName];
}catch(e){}
}
// ensure that event objects are normalized, etc.
_evtHdlrMap[attrId][propName] = d.connect(node, propName, value);
break;
}
if(forceProp || typeof value == "boolean"){
// special case: forcing assignment to the property
// special case: setting boolean to a property instead of attribute
node[propName] = value;
break;
}
// node's attribute
node.setAttribute(attrName, value);
}while(false);
return node; // DomNode
}
// getter
// should we access this attribute via a property or
// via getAttribute()?
value = node[propName];
if(forceProp && typeof value != "undefined"){
// node's property
return value; // Anything
}
if(propName != "href" && (typeof value == "boolean" || d.isFunction(value))){
// node's property
return value; // Anything
}
// node's attribute
// we need _hasAttr() here to guard against IE returning a default value
return _hasAttr(node, attrName) ? node.getAttribute(attrName) : null; // Anything
}
dojo.removeAttr = function(/*DomNode|String*/ node, /*String*/ name){
// summary:
// Removes an attribute from an HTML element.
// node:
// id or reference to the element to remove the attribute from
// name:
// the name of the attribute to remove
byId(node).removeAttribute(_fixAttrName(name));
}
dojo.getNodeProp = function(/*DomNode|String*/ node, /*String*/ name){
// summary:
// Returns an effective value of a property or an attribute.
// node:
// id or reference to the element to remove the attribute from
// name:
// the name of the attribute
node = byId(node);
var lc = name.toLowerCase(),
propName = _propNames[lc] || name;
if((propName in node) && propName != "href"){
// node's property
return node[propName]; // Anything
}
// node's attribute
var attrName = _attrNames[lc] || name;
return _hasAttr(node, attrName) ? node.getAttribute(attrName) : null; // Anything
}
dojo.create = function(tag, attrs, refNode, pos){
// summary:
// Create an element, allowing for optional attribute decoration
// and placement.
//
// description:
// A DOM Element creation function. A shorthand method for creating a node or
// a fragment, and allowing for a convenient optional attribute setting step,
// as well as an optional DOM placement reference.
//|
// Attributes are set by passing the optional object through `dojo.attr`.
// See `dojo.attr` for noted caveats and nuances, and API if applicable.
//|
// Placement is done via `dojo.place`, assuming the new node to be the action
// node, passing along the optional reference node and position.
//
// tag: String|DomNode
// A string of the element to create (eg: "div", "a", "p", "li", "script", "br"),
// or an existing DOM node to process.
//
// attrs: Object
// An object-hash of attributes to set on the newly created node.
// Can be null, if you don't want to set any attributes/styles.
// See: `dojo.attr` for a description of available attributes.
//
// refNode: String?|DomNode?
// Optional reference node. Used by `dojo.place` to place the newly created
// node somewhere in the dom relative to refNode. Can be a DomNode reference
// or String ID of a node.
//
// pos: String?
// Optional positional reference. Defaults to "last" by way of `dojo.place`,
// though can be set to "first","after","before","last", "replace" or "only"
// to further control the placement of the new node relative to the refNode.
// 'refNode' is required if a 'pos' is specified.
//
// returns: DomNode
//
// example:
// Create a DIV:
// | var n = dojo.create("div");
//
// example:
// Create a DIV with content:
// | var n = dojo.create("div", { innerHTML:"
hi
" });
//
// example:
// Place a new DIV in the BODY, with no attributes set
// | var n = dojo.create("div", null, dojo.body());
//
// example:
// Create an UL, and populate it with LI's. Place the list as the first-child of a
// node with id="someId":
// | var ul = dojo.create("ul", null, "someId", "first");
// | var items = ["one", "two", "three", "four"];
// | dojo.forEach(items, function(data){
// | dojo.create("li", { innerHTML: data }, ul);
// | });
//
// example:
// Create an anchor, with an href. Place in BODY:
// | dojo.create("a", { href:"foo.html", title:"Goto FOO!" }, dojo.body());
//
// example:
// Create a `dojo.NodeList()` from a new element (for syntatic sugar):
// | dojo.query(dojo.create('div'))
// | .addClass("newDiv")
// | .onclick(function(e){ console.log('clicked', e.target) })
// | .place("#someNode"); // redundant, but cleaner.
var doc = d.doc;
if(refNode){
refNode = byId(refNode);
doc = refNode.ownerDocument;
}
if(typeof tag == "string"){ // inline'd type check
tag = doc.createElement(tag);
}
if(attrs){ d.attr(tag, attrs); }
if(refNode){ d.place(tag, refNode, pos); }
return tag; // DomNode
}
/*=====
dojo.empty = function(node){
// summary:
// safely removes all children of the node.
// node: DOMNode|String
// a reference to a DOM node or an id.
// example:
// Destroy node's children byId:
// | dojo.empty("someId");
//
// example:
// Destroy all nodes' children in a list by reference:
// | dojo.query(".someNode").forEach(dojo.empty);
}
=====*/
d.empty =
d.isIE ? function(node){
node = byId(node);
for(var c; c = node.lastChild;){ // intentional assignment
d.destroy(c);
}
} :
function(node){
byId(node).innerHTML = "";
};
/*=====
dojo._toDom = function(frag, doc){
// summary:
// instantiates an HTML fragment returning the corresponding DOM.
// frag: String
// the HTML fragment
// doc: DocumentNode?
// optional document to use when creating DOM nodes, defaults to
// dojo.doc if not specified.
// returns: DocumentFragment
//
// example:
// Create a table row:
// | var tr = dojo._toDom("
First!
");
}
=====*/
// support stuff for dojo._toDom
var tagWrap = {
option: ["select"],
tbody: ["table"],
thead: ["table"],
tfoot: ["table"],
tr: ["table", "tbody"],
td: ["table", "tbody", "tr"],
th: ["table", "thead", "tr"],
legend: ["fieldset"],
caption: ["table"],
colgroup: ["table"],
col: ["table", "colgroup"],
li: ["ul"]
},
reTag = /<\s*([\w\:]+)/,
masterNode = {}, masterNum = 0,
masterName = "__" + d._scopeName + "ToDomId";
// generate start/end tag strings to use
// for the injection for each special tag wrap case.
for(var param in tagWrap){
var tw = tagWrap[param];
tw.pre = param == "option" ? '