2 Copyright (c) 2004-2008, The Dojo Foundation All Rights Reserved.
3 Available via Academic Free License >= 2.1 OR the modified BSD license.
4 see: http://dojotoolkit.org/license for details
8 This is a compiled version of Dojo, built for deployment and not for
9 development. To get an editable version, please visit:
11 http://dojotoolkit.org
13 for documentation and information on getting the source.
19 dojo, dijit, and dojox must always be the first three, and in that order.
28 /**Build will replace this comment with a scoped djConfig **/
30 //The null below can be relaced by a build-time value used instead of djConfig.scopeMap.
33 //See if new scopes need to be defined.
34 if((sMap || (typeof djConfig != "undefined" && djConfig.scopeMap)) && (typeof window != "undefined")){
35 var scopeDef = "", scopePrefix = "", scopeSuffix = "", scopeMap = {}, scopeMapRev = {};
36 sMap = sMap || djConfig.scopeMap;
37 for(var i = 0; i < sMap.length; i++){
38 //Make local variables, then global variables that use the locals.
39 var newScope = sMap[i];
40 scopeDef += "var " + newScope[0] + " = {}; " + newScope[1] + " = " + newScope[0] + ";" + newScope[1] + "._scopeName = '" + newScope[1] + "';";
41 scopePrefix += (i == 0 ? "" : ",") + newScope[0];
42 scopeSuffix += (i == 0 ? "" : ",") + newScope[1];
43 scopeMap[newScope[0]] = newScope[1];
44 scopeMapRev[newScope[1]] = newScope[0];
47 eval(scopeDef + "dojo._scopeArgs = [" + scopeSuffix + "];");
49 dojo._scopePrefixArgs = scopePrefix;
50 dojo._scopePrefix = "(function(" + scopePrefix + "){";
51 dojo._scopeSuffix = "})(" + scopeSuffix + ")";
52 dojo._scopeMap = scopeMap;
53 dojo._scopeMapRev = scopeMapRev;
58 // 'djConfig' does not exist under 'dojo.*' so that it can be set before the
59 // 'dojo' variable exists.
61 // Setting any of these variables *after* the library has loaded does
66 // Application code can set the global 'djConfig' prior to loading
67 // the library to override certain global settings for how dojo works.
70 // Defaults to `false`. If set to `true`, ensures that Dojo provides
71 // extended debugging feedback via Firebug. If Firebug is not available
72 // on your platform, setting `isDebug` to `true` will force Dojo to
73 // pull in (and display) the version of Firebug Lite which is
74 // integrated into the Dojo distribution, thereby always providing a
75 // debugging/logging console when `isDebug` is enabled. Note that
76 // Firebug's `console.*` methods are ALWAYS defined by Dojo. If
77 // `isDebug` is false and you are on a platform without Firebug, these
78 // methods will be defined as no-ops.
80 // debugAtAllCosts: Boolean
81 // Defaults to `false`. If set to `true`, this triggers an alternate
82 // mode of the package system in which dependencies are detected and
83 // only then are resources evaluated in dependency order via
84 // `<script>` tag inclusion. This may double-request resources and
85 // cause problems with scripts which expect `dojo.require()` to
86 // preform synchronously. `debugAtAllCosts` can be an invaluable
87 // debugging aid, but when using it, ensure that all code which
88 // depends on Dojo modules is wrapped in `dojo.addOnLoad()` handlers.
89 // Due to the somewhat unpredictable side-effects of using
90 // `debugAtAllCosts`, it is strongly recommended that you enable this
91 // flag as a last resort. `debugAtAllCosts` has no effect when loading
92 // resources across domains. For usage information, see the
93 // [Dojo Book](http://dojotoolkit.org/book/book-dojo/part-4-meta-dojo-making-your-dojo-code-run-faster-and-better/debugging-facilities/deb)
94 debugAtAllCosts: false,
96 // The locale to assume for loading localized resources in this page,
97 // specified according to [RFC 3066](http://www.ietf.org/rfc/rfc3066.txt).
98 // Must be specified entirely in lowercase, e.g. `en-us` and `zh-cn`.
99 // See the documentation for `dojo.i18n` and `dojo.requireLocalization`
100 // for details on loading localized resources. If no locale is specified,
101 // Dojo assumes the locale of the user agent, according to `navigator.userLanguage`
102 // or `navigator.language` properties.
104 // extraLocale: Array
105 // No default value. Specifies additional locales whose
106 // resources should also be loaded alongside the default locale when
107 // calls to `dojo.requireLocalization()` are processed.
108 extraLocale: undefined,
110 // The directory in which `dojo.js` is located. Under normal
111 // conditions, Dojo auto-detects the correct location from which it
112 // was loaded. You may need to manually configure `baseUrl` in cases
113 // where you have renamed `dojo.js` or in which `<base>` tags confuse
114 // some browsers (e.g. IE 6). The variable `dojo.baseUrl` is assigned
115 // either the value of `djConfig.baseUrl` if one is provided or the
116 // auto-detected root if not. Other modules are located relative to
119 // modulePaths: Object
120 // A map of module names to paths relative to `dojo.baseUrl`. The
121 // key/value pairs correspond directly to the arguments which
122 // `dojo.registerModulePath` accepts. Specifiying
123 // `djConfig.modulePaths = { "foo": "../../bar" }` is the equivalent
124 // of calling `dojo.registerModulePath("foo", "../../bar");`. Multiple
125 // modules may be configured via `djConfig.modulePaths`.
127 // afterOnLoad: Boolean
128 // Indicates Dojo was added to the page after the page load. In this case
129 // Dojo will not wait for the page DOMContentLoad/load events and fire
130 // its dojo.addOnLoad callbacks after making sure all outstanding
131 // dojo.required modules have loaded.
133 // addOnLoad: Function or Array
134 // Adds a callback via dojo.addOnLoad. Useful when Dojo is added after
135 // the page loads and djConfig.afterOnLoad is true. Supports the same
136 // arguments as dojo.addOnLoad. When using a function reference, use
137 // `djConfig.addOnLoad = function(){};`. For object with function name use
138 // `djConfig.addOnLoad = [myObject, "functionName"];` and for object with
139 // function reference use
140 // `djConfig.addOnLoad = [myObject, function(){}];`
143 // An array of module names to be loaded immediately after dojo.js has been included
152 // if((!this["console"])||(!console["firebug"])){
154 if(!this["console"]){
159 // Be careful to leave 'log' always at the end
161 "assert", "count", "debug", "dir", "dirxml", "error", "group",
162 "groupEnd", "info", "profile", "profileEnd", "time", "timeEnd",
163 "trace", "warn", "log"
170 console[tcn] = ('log' in console) ? function(){
171 var a = Array.apply({}, arguments);
173 console["log"](a.join(" "));
179 //TODOC: HOW TO DOC THIS?
180 // dojo is the root variable of (almost all) our public symbols -- make sure it is defined.
181 if(typeof dojo == "undefined"){
185 _scopePrefixArgs: "",
194 //Need placeholders for dijit and dojox for scoping code.
195 if(typeof dijit == "undefined"){
196 this.dijit = {_scopeName: "dijit"};
198 if(typeof dojox == "undefined"){
199 this.dojox = {_scopeName: "dojox"};
203 d._scopeArgs = [dojo, dijit, dojox];
209 // Alias for the global scope
210 // (e.g. the window object in a browser).
212 // Refer to 'dojo.global' rather than referring to window to ensure your
213 // code runs correctly in contexts other than web browsers (e.g. Rhino on a server).
218 d.config =/*===== djConfig = =====*/{
220 debugAtAllCosts: false
223 if(typeof djConfig != "undefined"){
224 for(var opt in djConfig){
225 d.config[opt] = djConfig[opt];
229 var _platforms = ["Browser", "Rhino", "Spidermonkey", "Mobile"];
231 while((t=_platforms.shift())){
236 // Override locale setting, if specified
238 // summary: the locale as defined by Dojo (read-only)
241 dojo.locale = d.config.locale;
243 var rev = "$Rev: 15729 $".match(/\d+/);
247 // version number of dojo
249 // Major version. If total version is "1.2.0beta1", will be 1
251 // Minor version. If total version is "1.2.0beta1", will be 2
253 // Patch version. If total version is "1.2.0beta1", will be 0
255 // Descriptor flag. If total version is "1.2.0beta1", will be "beta1"
257 // The SVN rev from which dojo was pulled
258 major: 1, minor: 2, patch: 2, flag: "",
259 revision: rev ? +rev[0] : 999999, //FIXME: use NaN?
260 toString: function(){
262 return major + "." + minor + "." + patch + flag + " (" + revision + ")"; // String
267 // Register with the OpenAjax hub
268 if(typeof OpenAjax != "undefined"){
269 OpenAjax.hub.registerLibrary(dojo._scopeName, "http://dojotoolkit.org", d.version.toString());
272 dojo._mixin = function(/*Object*/ obj, /*Object*/ props){
274 // Adds all properties and methods of props to obj. This addition
275 // is "prototype extension safe", so that instances of objects
276 // will not pass along prototype defaults.
279 // the "tobj" condition avoid copying properties in "props"
280 // inherited from Object.prototype. For example, if obj has a custom
281 // toString() method, don't overwrite it with the toString() method
282 // that props inherited from Object.prototype
283 if(tobj[x] === undefined || tobj[x] != props[x]){
287 // IE doesn't recognize custom toStrings in for..in
288 if(d["isIE"] && props){
289 var p = props.toString;
290 if(typeof p == "function" && p != obj.toString && p != tobj.toString &&
291 p != "\nfunction toString() {\n [native code]\n}\n"){
292 obj.toString = props.toString;
295 return obj; // Object
298 dojo.mixin = function(/*Object*/obj, /*Object...*/props){
300 // Adds all properties and methods of props to obj and returns the
301 // (now modified) obj.
303 // `dojo.mixin` can mix multiple source objects into a
304 // destionation object which is then returned. Unlike regular
305 // `for...in` iteration, `dojo.mixin` is also smart about avoiding
306 // extensions which other toolkits may unwisely add to the root
309 // The object to mix properties into. Also the return value.
311 // One or more objects whose values are successively copied into
312 // obj. If more than one of these objects contain the same value,
313 // the one specified last in the function call will "win".
315 // make a shallow copy of an object
316 // | var copy = dojo.mixin({}, source);
318 // many class constructors often take an object which specifies
319 // values to be configured on the object. In this case, it is
320 // often simplest to call `dojo.mixin` on the `this` object:
321 // | dojo.declare("acme.Base", null, {
322 // | constructor: function(properties){
323 // | // property configuration:
324 // | dojo.mixin(this, properties);
329 // | quip: "I wasn't born yesterday, you know - I've seen movies.",
333 // | // create an instance of the class and configure it
334 // | var b = new acme.Base({quip: "That's what it does!" });
336 // copy in properties from multiple objects
337 // | var flattened = dojo.mixin(
339 // | name: "Frylock",
343 // | name: "Carl Brutanananadilewski"
347 // | // will print "Carl Brutanananadilewski"
349 // | // will print "true"
351 for(var i=1, l=arguments.length; i<l; i++){
352 d._mixin(obj, arguments[i]);
354 return obj; // Object
357 dojo._getProp = function(/*Array*/parts, /*Boolean*/create, /*Object*/context){
358 var obj=context || d.global;
359 for(var i=0, p; obj && (p=parts[i]); i++){
360 if(i == 0 && this._scopeMap[p]){
361 p = this._scopeMap[p];
363 obj = (p in obj ? obj[p] : (create ? obj[p]={} : undefined));
368 dojo.setObject = function(/*String*/name, /*Object*/value, /*Object?*/context){
370 // Set a property from a dot-separated string, such as "A.B.C"
372 // Useful for longer api chains where you have to test each object in
373 // the chain, or when you have an object reference in string format.
374 // Objects are created as needed along `path`. Returns the passed
375 // value if setting is successful or `undefined` if not.
377 // Path to a property, in the form "A.B.C".
379 // Optional. Object to use as root of path. Defaults to
382 // set the value of `foo.bar.baz`, regardless of whether
383 // intermediate objects already exist:
384 // | dojo.setObject("foo.bar.baz", value);
386 // without `dojo.setObject`, we often see code like this:
387 // | // ensure that intermediate objects are available
388 // | if(!obj["parent"]){ obj.parent = {}; }
389 // | if(!obj.parent["child"]){ obj.parent.child= {}; }
390 // | // now we can safely set the property
391 // | obj.parent.child.prop = "some value";
392 // wheras with `dojo.setObject`, we can shorten that to:
393 // | dojo.setObject("parent.child.prop", "some value", obj);
394 var parts=name.split("."), p=parts.pop(), obj=d._getProp(parts, true, context);
395 return obj && p ? (obj[p]=value) : undefined; // Object
398 dojo.getObject = function(/*String*/name, /*Boolean*/create, /*Object*/context){
400 // Get a property from a dot-separated string, such as "A.B.C"
402 // Useful for longer api chains where you have to test each object in
403 // the chain, or when you have an object reference in string format.
405 // Path to an property, in the form "A.B.C".
407 // Optional. Object to use as root of path. Defaults to
408 // 'dojo.global'. Null may be passed.
410 // Optional. Defaults to `false`. If `true`, Objects will be
411 // created at any point along the 'path' that is undefined.
412 return d._getProp(name.split("."), create, context); // Object
415 dojo.exists = function(/*String*/name, /*Object?*/obj){
417 // determine if an object supports a given method
419 // useful for longer api chains where you have to test each object in
422 // Path to an object, in the form "A.B.C".
424 // Object to use as root of path. Defaults to
425 // 'dojo.global'. Null may be passed.
427 // | // define an object
432 // | // search the global scope
433 // | dojo.exists("foo.bar"); // true
434 // | dojo.exists("foo.bar.baz"); // false
436 // | // search from a particular scope
437 // | dojo.exists("bar", foo); // true
438 // | dojo.exists("bar.baz", foo); // false
439 return !!d.getObject(name, false, obj); // Boolean
443 dojo["eval"] = function(/*String*/ scriptFragment){
445 // Perform an evaluation in the global scope. Use this rather than
446 // calling 'eval()' directly.
448 // Placed in a separate function to minimize size of trapped
449 // exceptions. Calling eval() directly from some other scope may
450 // complicate tracebacks on some platforms.
452 // The result of the evaluation. Often `undefined`
456 // - JSC eval() takes an optional second argument which can be 'unsafe'.
457 // - Mozilla/SpiderMonkey eval() takes an optional second argument which is the
458 // scope object for new symbols.
460 // FIXME: investigate Joseph Smarr's technique for IE:
461 // http://josephsmarr.com/2007/01/31/fixing-eval-to-use-global-scope-in-ie/
463 // http://trac.dojotoolkit.org/ticket/744
464 return d.global.eval ? d.global.eval(scriptFragment) : eval(scriptFragment); // Object
468 dojo.deprecated = function(behaviour, extra, removal){
470 // Log a debug message to indicate that a behavior has been
473 // The API or behavior being deprecated. Usually in the form
474 // of "myApp.someFunction()".
476 // Text to append to the message. Often provides advice on a
477 // new function or facility to achieve the same goal during
478 // the deprecation period.
480 // Text to indicate when in the future the behavior will be
481 // removed. Usually a version number.
483 // | dojo.deprecated("myApp.getTemp()", "use myApp.getLocaleTemp() instead", "1.0");
486 dojo.experimental = function(moduleName, extra){
487 // summary: Marks code as experimental.
489 // This can be used to mark a function, file, or module as
490 // experimental. Experimental code is not ready to be used, and the
491 // APIs are subject to change without notice. Experimental code may be
492 // completed deleted without going through the normal deprecation
494 // moduleName: String
495 // The name of a module, or the name of a module file or a specific
498 // some additional message for the user
500 // | dojo.experimental("dojo.data.Result");
502 // | dojo.experimental("dojo.weather.toKelvin()", "PENDING approval from NOAA");
506 //Real functions declared in dojo._firebug.firebug.
507 d.deprecated = d.experimental = function(){};
513 * loader.js - A bootstrap module. Runs before the hostenv_*.js file. Contains
514 * all of the package loading methods.
526 dojo: { name: "dojo", value: "." },
527 // dojox: { name: "dojox", value: "../dojox" },
528 // dijit: { name: "dijit", value: "../dijit" },
529 doh: { name: "doh", value: "../util/doh" },
530 tests: { name: "tests", value: "tests" }
533 _moduleHasPrefix: function(/*String*/module){
534 // summary: checks to see if module has been established
535 var mp = this._modulePrefixes;
536 return !!(mp[module] && mp[module].value); // Boolean
539 _getModulePrefix: function(/*String*/module){
540 // summary: gets the prefix associated with module
541 var mp = this._modulePrefixes;
542 if(this._moduleHasPrefix(module)){
543 return mp[module].value; // String
545 return module; // String
551 // This variable is referenced by packages outside of bootstrap:
552 // FloatingPane.js and undo/browser.js
555 //Egad! Lots of test files push on this directly instead of using dojo.addOnLoad.
558 _loadNotifying: false
562 dojo._loadPath = function(/*String*/relpath, /*String?*/module, /*Function?*/cb){
564 // Load a Javascript module given a relative path
567 // Loads and interprets the script located at relpath, which is
568 // relative to the script root directory. If the script is found but
569 // its interpretation causes a runtime exception, that exception is
570 // not caught by us, so the caller will see it. We return a true
571 // value if and only if the script is found.
574 // A relative path to a script (no leading '/', and typically ending
577 // A module whose existance to check for after loading a path. Can be
578 // used to determine success or failure of the load.
580 // a callback function to pass the result of evaluating the script
582 var uri = ((relpath.charAt(0) == '/' || relpath.match(/^\w+:/)) ? "" : this.baseUrl) + relpath;
584 return !module ? this._loadUri(uri, cb) : this._loadUriAndCheck(uri, module, cb); // Boolean
587 return false; // Boolean
591 dojo._loadUri = function(/*String*/uri, /*Function?*/cb){
593 // Loads JavaScript from a URI
595 // Reads the contents of the URI, and evaluates the contents. This is
596 // used to load modules as well as resource bundles. Returns true if
597 // it succeeded. Returns false if the URI reading failed. Throws if
598 // the evaluation throws.
599 // uri: a uri which points at the script to be loaded
601 // a callback function to process the result of evaluating the script
602 // as an expression, typically used by the resource bundle loader to
603 // load JSON-style resources
605 if(this._loadedUrls[uri]){
606 return true; // Boolean
608 var contents = this._getText(uri, true);
609 if(!contents){ return false; } // Boolean
610 this._loadedUrls[uri] = true;
611 this._loadedUrls.push(uri);
613 contents = '('+contents+')';
615 //Only do the scoping if no callback. If a callback is specified,
616 //it is most likely the i18n bundle stuff.
617 contents = this._scopePrefix + contents + this._scopeSuffix;
619 if(d.isMoz){ contents += "\r\n//@ sourceURL=" + uri; } // debugging assist for Firebug
620 var value = d["eval"](contents);
622 return true; // Boolean
625 // FIXME: probably need to add logging to this method
626 dojo._loadUriAndCheck = function(/*String*/uri, /*String*/moduleName, /*Function?*/cb){
627 // summary: calls loadUri then findModule and returns true if both succeed
630 ok = this._loadUri(uri, cb);
632 console.error("failed loading " + uri + " with error: " + e);
634 return !!(ok && this._loadedModules[moduleName]); // Boolean
637 dojo.loaded = function(){
639 // signal fired when initial environment and package loading is
640 // complete. You may use dojo.addOnLoad() or dojo.connect() to
641 // this method in order to handle initialization tasks that
642 // require the environment to be initialized. In a browser host,
643 // declarative widgets will be constructed when this function
645 this._loadNotifying = true;
646 this._postLoad = true;
647 var mll = d._loaders;
649 //Clear listeners so new ones can be added
650 //For other xdomain package loads after the initial load.
653 for(var x = 0; x < mll.length; x++){
657 this._loadNotifying = false;
659 //Make sure nothing else got added to the onload queue
660 //after this first run. If something did, and we are not waiting for any
661 //more inflight resources, run again.
662 if(d._postLoad && d._inFlightCount == 0 && mll.length){
667 dojo.unloaded = function(){
669 // signal fired by impending environment destruction. You may use
670 // dojo.addOnUnload() or dojo.connect() to this method to perform
671 // page/application cleanup methods. See dojo.addOnUnload for more info.
672 var mll = this._unloaders;
678 d._onto = function(arr, obj, fn){
682 var func = (typeof fn == "string") ? obj[fn] : fn;
683 arr.push(function(){ func.call(obj); });
687 dojo.addOnLoad = function(/*Object?*/obj, /*String|Function*/functionName){
689 // Registers a function to be triggered after the DOM has finished
690 // loading and widgets declared in markup have been instantiated.
691 // Images and CSS files may or may not have finished downloading when
692 // the specified function is called. (Note that widgets' CSS and HTML
693 // code is guaranteed to be downloaded before said widgets are
696 // | dojo.addOnLoad(functionPointer);
697 // | dojo.addOnLoad(object, "functionName");
698 // | dojo.addOnLoad(object, function(){ /* ... */});
700 d._onto(d._loaders, obj, functionName);
702 //Added for xdomain loading. dojo.addOnLoad is used to
703 //indicate callbacks after doing some dojo.require() statements.
704 //In the xdomain case, if all the requires are loaded (after initial
705 //page load), then immediately call any listeners.
706 if(d._postLoad && d._inFlightCount == 0 && !d._loadNotifying){
711 //Support calling dojo.addOnLoad via djConfig.addOnLoad. Support all the
712 //call permutations of dojo.addOnLoad. Mainly useful when dojo is added
713 //to the page after the page has loaded.
714 var dca = d.config.addOnLoad;
716 d.addOnLoad[(dca instanceof Array ? "apply" : "call")](d, dca);
719 dojo.addOnUnload = function(/*Object?*/obj, /*String|Function?*/functionName){
721 // registers a function to be triggered when the page unloads. In a browser
722 // enviroment, the functions will be triggered during the window.onbeforeunload
723 // event. Be careful doing work during window.onbeforeunload. onbeforeunload
724 // can be triggered if a link to download a file is clicked, or if the link is a
725 // javascript: link. In these cases, the onbeforeunload event fires, but the
726 // document is not actually destroyed. So be careful about doing destructive
727 // operations in a dojo.addOnUnload callback.
729 // | dojo.addOnUnload(functionPointer)
730 // | dojo.addOnUnload(object, "functionName")
731 // | dojo.addOnUnload(object, function(){ /* ... */});
733 d._onto(d._unloaders, obj, functionName);
736 dojo._modulesLoaded = function(){
737 if(d._postLoad){ return; }
738 if(d._inFlightCount > 0){
739 console.warn("files still in flight!");
745 dojo._callLoaded = function(){
747 // The "object" check is for IE, and the other opera check fixes an
748 // issue in Opera where it could not find the body element in some
749 // widget test cases. For 0.9, maybe route all browsers through the
750 // setTimeout (need protection still for non-browser environments
751 // though). This might also help the issue with FF 2.0 and freezing
752 // issues where we try to do sync xhr while background css images are
753 // being loaded (trac #2572)? Consider for 0.9.
754 if(typeof setTimeout == "object" || (dojo.config.useXDomain && d.isOpera)){
756 setTimeout(function(){dojo.loaded();}, 0);
758 setTimeout(dojo._scopeName + ".loaded();", 0);
765 dojo._getModuleSymbols = function(/*String*/modulename){
767 // Converts a module name in dotted JS notation to an array
768 // representing the path in the source tree
769 var syms = modulename.split(".");
770 for(var i = syms.length; i>0; i--){
771 var parentModule = syms.slice(0, i).join(".");
772 if((i==1) && !this._moduleHasPrefix(parentModule)){
773 // Support default module directory (sibling of dojo) for top-level modules
774 syms[0] = "../" + syms[0];
776 var parentModulePath = this._getModulePrefix(parentModule);
777 if(parentModulePath != parentModule){
778 syms.splice(0, i, parentModulePath);
784 return syms; // Array
787 dojo._global_omit_module_check = false;
789 dojo.loadInit = function(/*Function*/init){
791 // Executes a function that needs to be executed for the loader's dojo.requireIf
792 // resolutions to work. This is needed mostly for the xdomain loader case where
793 // a function needs to be executed to set up the possible values for a dojo.requireIf
796 // a function reference. Executed immediately.
797 // description: This function is mainly a marker for the xdomain loader to know parts of
798 // code that needs be executed outside the function wrappper that is placed around modules.
799 // The init function could be executed more than once, and it should make no assumptions
800 // on what is loaded, or what modules are available. Only the functionality in Dojo Base
801 // is allowed to be used. Avoid using this method. For a valid use case,
802 // see the source for dojox.gfx.
806 dojo._loadModule = dojo.require = function(/*String*/moduleName, /*Boolean?*/omitModuleCheck){
808 // loads a Javascript module from the appropriate URI
810 // module name to load, using periods for separators,
811 // e.g. "dojo.date.locale". Module paths are de-referenced by dojo's
812 // internal mapping of locations to names and are disambiguated by
813 // longest prefix. See `dojo.registerModulePath()` for details on
814 // registering new modules.
816 // if `true`, omitModuleCheck skips the step of ensuring that the
817 // loaded file actually defines the symbol it is referenced by.
818 // For example if it called as `dojo.require("a.b.c")` and the
819 // file located at `a/b/c.js` does not define an object `a.b.c`,
820 // and exception will be throws whereas no exception is raised
821 // when called as `dojo.require("a.b.c", true)`
823 // `dojo.require("A.B")` first checks to see if symbol A.B is
824 // defined. If it is, it is simply returned (nothing to do).
826 // If it is not defined, it will look for `A/B.js` in the script root
829 // `dojo.require` throws an excpetion if it cannot find a file
830 // to load, or if the symbol `A.B` is not defined after loading.
832 // It returns the object `A.B`.
834 // `dojo.require()` does nothing about importing symbols into
835 // the current namespace. It is presumed that the caller will
836 // take care of that. For example, to import all symbols into a
837 // local block, you might write:
839 // | with (dojo.require("A.B")) {
843 // And to import just the leaf symbol to a local variable:
845 // | var B = dojo.require("A.B");
847 // returns: the required namespace object
848 omitModuleCheck = this._global_omit_module_check || omitModuleCheck;
850 //Check if it is already loaded.
851 var module = this._loadedModules[moduleName];
856 // convert periods to slashes
857 var relpath = this._getModuleSymbols(moduleName).join("/") + '.js';
859 var modArg = (!omitModuleCheck) ? moduleName : null;
860 var ok = this._loadPath(relpath, modArg);
862 if(!ok && !omitModuleCheck){
863 throw new Error("Could not load '" + moduleName + "'; last tried '" + relpath + "'");
866 // check that the symbol was defined
867 // Don't bother if we're doing xdomain (asynchronous) loading.
868 if(!omitModuleCheck && !this._isXDomain){
869 // pass in false so we can give better error
870 module = this._loadedModules[moduleName];
872 throw new Error("symbol '" + moduleName + "' is not defined after loading '" + relpath + "'");
879 dojo.provide = function(/*String*/ resourceName){
881 // Each javascript source file must have at least one
882 // `dojo.provide()` call at the top of the file, corresponding to
883 // the file name. For example, `js/dojo/foo.js` must have
884 // `dojo.provide("dojo.foo");` before any calls to
885 // `dojo.require()` are made.
887 // Each javascript source file is called a resource. When a
888 // resource is loaded by the browser, `dojo.provide()` registers
889 // that it has been loaded.
891 // For backwards compatibility reasons, in addition to registering
892 // the resource, `dojo.provide()` also ensures that the javascript
893 // object for the module exists. For example,
894 // `dojo.provide("dojox.data.FlickrStore")`, in addition to
895 // registering that `FlickrStore.js` is a resource for the
896 // `dojox.data` module, will ensure that the `dojox.data`
897 // javascript object exists, so that calls like
898 // `dojo.data.foo = function(){ ... }` don't fail.
900 // In the case of a build where multiple javascript source files
901 // are combined into one bigger file (similar to a .lib or .jar
902 // file), that file may contain multiple dojo.provide() calls, to
903 // note that it includes multiple resources.
905 //Make sure we have a string.
906 resourceName = resourceName + "";
907 return (d._loadedModules[resourceName] = d.getObject(resourceName, true)); // Object
910 //Start of old bootstrap2:
912 dojo.platformRequire = function(/*Object*/modMap){
914 // require one or more modules based on which host environment
915 // Dojo is currently operating in
917 // This method takes a "map" of arrays which one can use to
918 // optionally load dojo modules. The map is indexed by the
919 // possible dojo.name_ values, with two additional values:
920 // "default" and "common". The items in the "default" array will
921 // be loaded if none of the other items have been choosen based on
922 // dojo.name_, set by your host environment. The items in the
923 // "common" array will *always* be loaded, regardless of which
926 // | dojo.platformRequire({
928 // | "foo.sample", // simple module
930 // | ["foo.bar.baz", true] // skip object check in _loadModule (dojo.require)
932 // | default: [ "foo.sample._base" ],
933 // | common: [ "important.module.common" ]
936 var common = modMap.common || [];
937 var result = common.concat(modMap[d._name] || modMap["default"] || []);
939 for(var x=0; x<result.length; x++){
940 var curr = result[x];
941 if(curr.constructor == Array){
942 d._loadModule.apply(d, curr);
949 dojo.requireIf = function(/*Boolean*/ condition, /*String*/ resourceName){
951 // If the condition is true then call dojo.require() for the specified
953 if(condition === true){
954 // FIXME: why do we support chained require()'s here? does the build system?
956 for(var i = 1; i < arguments.length; i++){
957 args.push(arguments[i]);
959 d.require.apply(d, args);
963 dojo.requireAfterIf = d.requireIf;
965 dojo.registerModulePath = function(/*String*/module, /*String*/prefix){
967 // maps a module name to a path
969 // An unregistered module is given the default path of ../[module],
970 // relative to Dojo root. For example, module acme is mapped to
971 // ../acme. If you want to use a different module name, use
972 // dojo.registerModulePath.
974 // If your dojo.js is located at this location in the web root:
975 // | /myapp/js/dojo/dojo/dojo.js
976 // and your modules are located at:
977 // | /myapp/js/foo/bar.js
978 // | /myapp/js/foo/baz.js
979 // | /myapp/js/foo/thud/xyzzy.js
980 // Your application can tell Dojo to locate the "foo" namespace by calling:
981 // | dojo.registerModulePath("foo", "../../foo");
982 // At which point you can then use dojo.require() to load the
983 // modules (assuming they provide() the same things which are
984 // required). The full code might be:
985 // | <script type="text/javascript"
986 // | src="/myapp/js/dojo/dojo/dojo.js"></script>
987 // | <script type="text/javascript">
988 // | dojo.registerModulePath("foo", "../../foo");
989 // | dojo.require("foo.bar");
990 // | dojo.require("foo.baz");
991 // | dojo.require("foo.thud.xyzzy");
993 d._modulePrefixes[module] = { name: module, value: prefix };
996 dojo.requireLocalization = function(/*String*/moduleName, /*String*/bundleName, /*String?*/locale, /*String?*/availableFlatLocales){
998 // Declares translated resources and loads them if necessary, in the
999 // same style as dojo.require. Contents of the resource bundle are
1000 // typically strings, but may be any name/value pair, represented in
1001 // JSON format. See also `dojo.i18n.getLocalization`.
1004 // Load translated resource bundles provided underneath the "nls"
1005 // directory within a package. Translated resources may be located in
1006 // different packages throughout the source tree.
1008 // Each directory is named for a locale as specified by RFC 3066,
1009 // (http://www.ietf.org/rfc/rfc3066.txt), normalized in lowercase.
1010 // Note that the two bundles in the example do not define all the
1011 // same variants. For a given locale, bundles will be loaded for
1012 // that locale and all more general locales above it, including a
1013 // fallback at the root directory. For example, a declaration for
1014 // the "de-at" locale will first load `nls/de-at/bundleone.js`,
1015 // then `nls/de/bundleone.js` and finally `nls/bundleone.js`. The
1016 // data will be flattened into a single Object so that lookups
1017 // will follow this cascading pattern. An optional build step can
1018 // preload the bundles to avoid data redundancy and the multiple
1019 // network hits normally required to load these resources.
1022 // name of the package containing the "nls" directory in which the
1026 // bundle name, i.e. the filename without the '.js' suffix
1029 // the locale to load (optional) By default, the browser's user
1030 // locale as defined by dojo.locale
1032 // availableFlatLocales:
1033 // A comma-separated list of the available, flattened locales for this
1034 // bundle. This argument should only be set by the build process.
1037 // A particular widget may define one or more resource bundles,
1038 // structured in a program as follows, where moduleName is
1039 // mycode.mywidget and bundleNames available include bundleone and
1045 // | bundleone.js (the fallback translation, English in this example)
1046 // | bundletwo.js (also a fallback translation)
1053 // | (empty; use the fallback translation)
1065 d.require("dojo.i18n");
1066 d.i18n._requireLocalization.apply(d.hostenv, arguments);
1070 var ore = new RegExp("^(([^:/?#]+):)?(//([^/?#]*))?([^?#]*)(\\?([^#]*))?(#(.*))?$");
1071 var ire = new RegExp("^((([^\\[:]+):)?([^@]+)@)?(\\[([^\\]]+)\\]|([^\\[:]*))(:([0-9]+))?$");
1073 dojo._Url = function(/*dojo._Url||String...*/){
1075 // Constructor to create an object representing a URL.
1076 // It is marked as private, since we might consider removing
1077 // or simplifying it.
1079 // Each argument is evaluated in order relative to the next until
1080 // a canonical uri is produced. To get an absolute Uri relative to
1081 // the current document use:
1082 // new dojo._Url(document.baseURI, url)
1088 // resolve uri components relative to each other
1089 for(var i = 1; i<_a.length; i++){
1090 if(!_a[i]){ continue; }
1092 // Safari doesn't support this.constructor so we have to be explicit
1093 // FIXME: Tracked (and fixed) in Webkit bug 3537.
1094 // http://bugs.webkit.org/show_bug.cgi?id=3537
1095 var relobj = new d._Url(_a[i]+"");
1096 var uriobj = new d._Url(uri[0]+"");
1099 relobj.path == "" &&
1101 !relobj.authority &&
1104 if(relobj.fragment != n){
1105 uriobj.fragment = relobj.fragment;
1108 }else if(!relobj.scheme){
1109 relobj.scheme = uriobj.scheme;
1111 if(!relobj.authority){
1112 relobj.authority = uriobj.authority;
1114 if(relobj.path.charAt(0) != "/"){
1115 var path = uriobj.path.substring(0,
1116 uriobj.path.lastIndexOf("/") + 1) + relobj.path;
1118 var segs = path.split("/");
1119 for(var j = 0; j < segs.length; j++){
1121 // flatten "./" references
1122 if(j == segs.length - 1){
1128 }else if(j > 0 && !(j == 1 && segs[0] == "") &&
1129 segs[j] == ".." && segs[j-1] != ".."){
1130 // flatten "../" references
1131 if(j == (segs.length - 1)){
1135 segs.splice(j - 1, 2);
1140 relobj.path = segs.join("/");
1147 uri.push(relobj.scheme, ":");
1149 if(relobj.authority){
1150 uri.push("//", relobj.authority);
1152 uri.push(relobj.path);
1154 uri.push("?", relobj.query);
1156 if(relobj.fragment){
1157 uri.push("#", relobj.fragment);
1161 this.uri = uri.join("");
1163 // break the uri into its main components
1164 var r = this.uri.match(ore);
1166 this.scheme = r[2] || (r[1] ? "" : n);
1167 this.authority = r[4] || (r[3] ? "" : n);
1168 this.path = r[5]; // can never be undefined
1169 this.query = r[7] || (r[6] ? "" : n);
1170 this.fragment = r[9] || (r[8] ? "" : n);
1172 if(this.authority != n){
1173 // server based naming authority
1174 r = this.authority.match(ire);
1176 this.user = r[3] || n;
1177 this.password = r[4] || n;
1178 this.host = r[6] || r[7]; // ipv6 || ipv4
1179 this.port = r[9] || n;
1183 dojo._Url.prototype.toString = function(){ return this.uri; };
1185 dojo.moduleUrl = function(/*String*/module, /*dojo._Url||String*/url){
1187 // Returns a `dojo._Url` object relative to a module.
1189 // | var pngPath = dojo.moduleUrl("acme","images/small.png");
1190 // | // list the object properties
1191 // | // create an image and set it's source to pngPath's value:
1192 // | var img = document.createElement("img");
1193 // | // NOTE: we assign the string representation of the url object
1194 // | img.src = pngPath.toString();
1195 // | // add our image to the document
1196 // | dojo.body().appendChild(img);
1198 // you may de-reference as far as you like down the package
1199 // hierarchy. This is sometimes handy to avoid lenghty relative
1200 // urls or for building portable sub-packages. In this example,
1201 // the `acme.widget` and `acme.util` directories may be located
1202 // under different roots (see `dojo.registerModulePath`) but the
1203 // the modules which reference them can be unaware of their
1204 // relative locations on the filesystem:
1205 // | // somewhere in a configuration block
1206 // | dojo.registerModulePath("acme.widget", "../../acme/widget");
1207 // | dojo.registerModulePath("acme.util", "../../util");
1211 // | // code in a module using acme resources
1212 // | var tmpltPath = dojo.moduleUrl("acme.widget","templates/template.html");
1213 // | var dataPath = dojo.moduleUrl("acme.util","resources/data.json");
1215 var loc = d._getModuleSymbols(module).join('/');
1216 if(!loc){ return null; }
1217 if(loc.lastIndexOf("/") != loc.length-1){
1221 //If the path is an absolute path (starts with a / or is on another
1222 //domain/xdomain) then don't add the baseUrl.
1223 var colonIndex = loc.indexOf(":");
1224 if(loc.charAt(0) != "/" && (colonIndex == -1 || colonIndex > loc.indexOf("/"))){
1225 loc = d.baseUrl + loc;
1228 return new d._Url(loc, url); // String
1235 // | if(dojo.isBrowser){ ... }
1240 // | if(dojo.isFF > 1){ ... }
1245 // | if(dojo.isIE > 6){
1252 // | if(dojo.isSafari){ ... }
1255 // | if(dojo.isSafari && navigator.userAgent.indexOf("iPhone") != -1){
1256 // | // we are iPhone. Note, iPod touch reports "iPod" above and fails this test.
1261 // isBrowser: Boolean
1262 // True if the client is a web-browser
1264 // isFF: Number | undefined
1265 // Version as a Number if client is FireFox. undefined otherwise. Corresponds to
1266 // major detected FireFox version (1.5, 2, 3, etc.)
1268 // isIE: Number | undefined
1269 // Version as a Number if client is MSIE(PC). undefined otherwise. Corresponds to
1270 // major detected IE version (6, 7, 8, etc.)
1272 // isKhtml: Number | undefined
1273 // Version as a Number if client is a KTHML-derived browser (Konqueror,
1274 // Safari, etc.). undefined otherwise. Corresponds to major detected version.
1276 // isMozilla: Number | undefined
1277 // Version as a Number if client is a Mozilla-based browser (Firefox,
1278 // SeaMonkey). undefined otherwise. Corresponds to major detected version.
1280 // isOpera: Number | undefined
1281 // Version as a Number if client is Opera. undefined otherwise. Corresponds to
1282 // major detected version.
1284 // isSafari: Number | undefined
1285 // Version as a Number if client is Safari or iPhone. undefined otherwise.
1290 if(typeof window != 'undefined'){
1291 dojo.isBrowser = true;
1292 dojo._name = "browser";
1295 // attempt to figure out the path to dojo if it isn't set in the config
1298 // this is a scope protection closure. We set browser versions and grab
1299 // the URL we were loaded from here.
1301 // grab the node we were loaded from
1302 if(document && document.getElementsByTagName){
1303 var scripts = document.getElementsByTagName("script");
1304 var rePkg = /dojo(\.xd)?\.js(\W|$)/i;
1305 for(var i = 0; i < scripts.length; i++){
1306 var src = scripts[i].getAttribute("src");
1307 if(!src){ continue; }
1308 var m = src.match(rePkg);
1310 // find out where we came from
1311 if(!d.config.baseUrl){
1312 d.config.baseUrl = src.substring(0, m.index);
1314 // and find out if we need to modify our behavior
1315 var cfg = scripts[i].getAttribute("djConfig");
1317 var cfgo = eval("({ "+cfg+" })");
1319 dojo.config[x] = cfgo[x];
1322 break; // "first Dojo wins"
1326 d.baseUrl = d.config.baseUrl;
1328 // fill in the rendering support information in dojo.render.*
1330 var dua = n.userAgent;
1331 var dav = n.appVersion;
1332 var tv = parseFloat(dav);
1334 if(dua.indexOf("Opera") >= 0){ d.isOpera = tv; }
1335 // safari detection derived from:
1336 // http://developer.apple.com/internet/safari/faq.html#anchor2
1337 // http://developer.apple.com/internet/safari/uamatrix.html
1338 var index = Math.max(dav.indexOf("WebKit"), dav.indexOf("Safari"), 0);
1340 // try to grab the explicit Safari version first. If we don't get
1341 // one, look for 419.3+ as the indication that we're on something
1342 // "Safari 3-ish". Lastly, default to "Safari 2" handling.
1343 d.isSafari = parseFloat(dav.split("Version/")[1]) ||
1344 (parseFloat(dav.substr(index + 7)) > 419.3) ? 3 : 2;
1346 if(dua.indexOf("AdobeAIR") >= 0){ d.isAIR = 1; }
1347 if(dav.indexOf("Konqueror") >= 0 || d.isSafari){ d.isKhtml = tv; }
1348 if(dua.indexOf("Gecko") >= 0 && !d.isKhtml){ d.isMozilla = d.isMoz = tv; }
1350 d.isFF = parseFloat(dua.split("Firefox/")[1]) || undefined;
1352 if(document.all && !d.isOpera){
1353 d.isIE = parseFloat(dav.split("MSIE ")[1]) || undefined;
1356 //Workaround to get local file loads of dojo to work on IE 7
1357 //by forcing to not use native xhr.
1358 if(dojo.isIE && window.location.protocol === "file:"){
1359 dojo.config.ieForceActiveXXhr=true;
1362 var cm = document.compatMode;
1363 d.isQuirks = cm == "BackCompat" || cm == "QuirksMode" || d.isIE < 6;
1365 // TODO: is the HTML LANG attribute relevant?
1366 d.locale = dojo.config.locale || (d.isIE ? n.userLanguage : n.language).toLowerCase();
1368 // These are in order of decreasing likelihood; this will change in time.
1369 d._XMLHTTP_PROGIDS = ['Msxml2.XMLHTTP', 'Microsoft.XMLHTTP', 'Msxml2.XMLHTTP.4.0'];
1371 d._xhrObj = function(){
1373 // does the work of portably generating a new XMLHTTPRequest
1377 if(!dojo.isIE || !dojo.config.ieForceActiveXXhr){
1378 try{ http = new XMLHttpRequest(); }catch(e){}
1381 for(var i=0; i<3; ++i){
1382 var progid = d._XMLHTTP_PROGIDS[i];
1384 http = new ActiveXObject(progid);
1390 d._XMLHTTP_PROGIDS = [progid]; // so faster next time
1397 throw new Error("XMLHTTP not available: "+last_e);
1400 return http; // XMLHTTPRequest instance
1403 d._isDocumentOk = function(http){
1404 var stat = http.status || 0;
1405 return (stat >= 200 && stat < 300) || // Boolean
1406 stat == 304 || // allow any 2XX response code
1407 stat == 1223 || // get it out of the cache
1408 (!stat && (location.protocol=="file:" || location.protocol=="chrome:") ); // Internet Explorer mangled the status code
1411 //See if base tag is in use.
1412 //This is to fix http://trac.dojotoolkit.org/ticket/3973,
1413 //but really, we need to find out how to get rid of the dojo._Url reference
1414 //below and still have DOH work with the dojo.i18n test following some other
1415 //test that uses the test frame to load a document (trac #2757).
1416 //Opera still has problems, but perhaps a larger issue of base tag support
1417 //with XHR requests (hasBase is true, but the request is still made to document
1418 //path, not base path).
1419 var owloc = window.location+"";
1420 var base = document.getElementsByTagName("base");
1421 var hasBase = (base && base.length > 0);
1423 d._getText = function(/*URI*/ uri, /*Boolean*/ fail_ok){
1424 // summary: Read the contents of the specified uri and return those contents.
1426 // A relative or absolute uri. If absolute, it still must be in
1427 // the same "domain" as we are.
1429 // Default false. If fail_ok and loading fails, return null
1430 // instead of throwing.
1431 // returns: The response text. null is returned when there is a
1432 // failure and failure is okay (an exception otherwise)
1434 // alert("_getText: " + uri);
1436 // NOTE: must be declared before scope switches ie. this._xhrObj()
1437 var http = this._xhrObj();
1439 if(!hasBase && dojo._Url){
1440 uri = (new dojo._Url(owloc, uri)).toString();
1448 if(d.config.cacheBust){
1449 //Make sure we have a string before string methods are used on uri
1451 uri += (uri.indexOf("?") == -1 ? "?" : "&") + String(d.config.cacheBust).replace(/\W+/g,"");
1454 http.open('GET', uri, false);
1458 if(!d._isDocumentOk(http)){
1459 var err = Error("Unable to load "+uri+" status:"+ http.status);
1460 err.status = http.status;
1461 err.responseText = http.responseText;
1465 if(fail_ok){ return null; } // null
1466 // rethrow the exception
1469 return http.responseText; // String
1472 d._windowUnloaders = [];
1474 d.windowUnloaded = function(){
1476 // signal fired by impending window destruction. You may use
1477 // dojo.addOnWIndowUnload() or dojo.connect() to this method to perform
1478 // page/application cleanup methods. See dojo.addOnWindowUnload for more info.
1479 var mll = this._windowUnloaders;
1485 d.addOnWindowUnload = function(/*Object?*/obj, /*String|Function?*/functionName){
1487 // registers a function to be triggered when window.onunload fires.
1488 // Be careful trying to modify the DOM or access JavaScript properties
1489 // during this phase of page unloading: they may not always be available.
1490 // Consider dojo.addOnUnload() if you need to modify the DOM or do heavy
1493 // | dojo.addOnWindowUnload(functionPointer)
1494 // | dojo.addOnWindowUnload(object, "functionName")
1495 // | dojo.addOnWindowUnload(object, function(){ /* ... */});
1497 d._onto(d._windowUnloaders, obj, functionName);
1501 dojo._initFired = false;
1502 // BEGIN DOMContentLoaded, from Dean Edwards (http://dean.edwards.name/weblog/2006/06/again/)
1503 dojo._loadInit = function(e){
1504 dojo._initFired = true;
1505 // allow multiple calls, only first one will take effect
1506 // A bug in khtml calls events callbacks for document for event which isnt supported
1507 // for example a created contextmenu event calls DOMContentLoaded, workaround
1508 var type = (e && e.type) ? e.type.toLowerCase() : "load";
1509 if(arguments.callee.initialized || (type != "domcontentloaded" && type != "load")){ return; }
1510 arguments.callee.initialized = true;
1511 if("_khtmlTimer" in dojo){
1512 clearInterval(dojo._khtmlTimer);
1513 delete dojo._khtmlTimer;
1516 if(dojo._inFlightCount == 0){
1517 dojo._modulesLoaded();
1521 dojo._fakeLoadInit = function(){
1522 dojo._loadInit({type: "load"});
1525 if(!dojo.config.afterOnLoad){
1526 // START DOMContentLoaded
1527 // Mozilla and Opera 9 expose the event we could use
1528 if(document.addEventListener){
1530 // due to a threading issue in Firefox 2.0, we can't enable
1531 // DOMContentLoaded on that platform. For more information, see:
1532 // http://trac.dojotoolkit.org/ticket/1704
1533 if(dojo.isOpera || dojo.isFF >= 3 || (dojo.isMoz && dojo.config.enableMozDomContentLoaded === true)){
1534 document.addEventListener("DOMContentLoaded", dojo._loadInit, null);
1537 // mainly for Opera 8.5, won't be fired if DOMContentLoaded fired already.
1538 // also used for Mozilla because of trac #1640
1539 window.addEventListener("load", dojo._loadInit, null);
1543 window.addEventListener("load", dojo._loadInit, null);
1544 }else if(/(WebKit|khtml)/i.test(navigator.userAgent)){ // sniff
1545 dojo._khtmlTimer = setInterval(function(){
1546 if(/loaded|complete/.test(document.readyState)){
1547 dojo._loadInit(); // call the onload handler
1551 // END DOMContentLoaded
1556 var _handleNodeEvent = function(/*String*/evtName, /*Function*/fp){
1558 // non-destructively adds the specified function to the node's
1560 // evtName: should be in the form "onclick" for "onclick" handlers.
1561 // Make sure you pass in the "on" part.
1562 var oldHandler = _w[evtName] || function(){};
1563 _w[evtName] = function(){
1564 fp.apply(_w, arguments);
1565 oldHandler.apply(_w, arguments);
1570 // for Internet Explorer. readyState will not be achieved on init
1571 // call, but dojo doesn't need it however, we'll include it
1572 // because we don't know if there are other functions added that
1573 // might. Note that this has changed because the build process
1574 // strips all comments -- including conditional ones.
1575 if(!dojo.config.afterOnLoad){
1576 document.write('<scr'+'ipt defer src="//:" '
1577 + 'onreadystatechange="if(this.readyState==\'complete\'){' + dojo._scopeName + '._loadInit();}">'
1583 document.namespaces.add("v","urn:schemas-microsoft-com:vml");
1584 document.createStyleSheet().addRule("v\\:*", "behavior:url(#default#VML)");
1588 // FIXME: dojo.unloaded requires dojo scope, so using anon function wrapper.
1589 _handleNodeEvent("onbeforeunload", function() { dojo.unloaded(); });
1590 _handleNodeEvent("onunload", function() { dojo.windowUnloaded(); });
1594 OpenAjax.subscribe("OpenAjax", "onload", function(){
1595 if(dojo._inFlightCount == 0){
1596 dojo._modulesLoaded();
1600 OpenAjax.subscribe("OpenAjax", "onunload", function(){
1604 } //if (typeof window != 'undefined')
1606 //Register any module paths set up in djConfig. Need to do this
1607 //in the hostenvs since hostenv_browser can read djConfig from a
1608 //script tag's attribute.
1610 var mp = dojo.config["modulePaths"];
1612 for(var param in mp){
1613 dojo.registerModulePath(param, mp[param]);
1618 //Load debug code if necessary.
1619 if(dojo.config.isDebug){
1620 dojo.require("dojo._firebug.firebug");
1623 if(dojo.config.debugAtAllCosts){
1624 dojo.config.useXDomain = true;
1625 dojo.require("dojo._base._loader.loader_xd");
1626 dojo.require("dojo._base._loader.loader_debug");
1627 dojo.require("dojo.i18n");
1630 if(!dojo._hasResource["dojo._base.lang"]){ //_hasResource checks added by build. Do not use _hasResource directly in your code.
1631 dojo._hasResource["dojo._base.lang"] = true;
1632 dojo.provide("dojo._base.lang");
1634 // Crockford (ish) functions
1636 dojo.isString = function(/*anything*/ it){
1638 // Return true if it is a String
1639 return !!arguments.length && it != null && (typeof it == "string" || it instanceof String); // Boolean
1642 dojo.isArray = function(/*anything*/ it){
1644 // Return true if it is an Array
1645 return it && (it instanceof Array || typeof it == "array"); // Boolean
1649 dojo.isFunction = function(it){
1650 // summary: Return true if it is a Function
1656 dojo.isFunction = (function(){
1657 var _isFunction = function(/*anything*/ it){
1658 return it && (typeof it == "function" || it instanceof Function); // Boolean
1661 return dojo.isSafari ?
1662 // only slow this down w/ gratuitious casting in Safari since it's what's b0rken
1663 function(/*anything*/ it){
1664 if(typeof it == "function" && it == "[object NodeList]"){ return false; }
1665 return _isFunction(it); // Boolean
1669 dojo.isObject = function(/*anything*/ it){
1671 // Returns true if it is a JavaScript object (or an Array, a Function
1673 return it !== undefined &&
1674 (it === null || typeof it == "object" || dojo.isArray(it) || dojo.isFunction(it)); // Boolean
1677 dojo.isArrayLike = function(/*anything*/ it){
1679 // similar to dojo.isArray() but more permissive
1681 // Doesn't strongly test for "arrayness". Instead, settles for "isn't
1682 // a string or number and has a length property". Arguments objects
1683 // and DOM collections will return true when passed to
1684 // dojo.isArrayLike(), but will return false when passed to
1687 // If it walks like a duck and quicks like a duck, return `true`
1689 return it && it !== undefined && // Boolean
1690 // keep out built-in constructors (Number, String, ...) which have length
1692 !d.isString(it) && !d.isFunction(it) &&
1693 !(it.tagName && it.tagName.toLowerCase() == 'form') &&
1694 (d.isArray(it) || isFinite(it.length));
1697 dojo.isAlien = function(/*anything*/ it){
1699 // Returns true if it is a built-in function or some other kind of
1700 // oddball that *should* report as a function but doesn't
1701 return it && !dojo.isFunction(it) && /\{\s*\[native code\]\s*\}/.test(String(it)); // Boolean
1704 dojo.extend = function(/*Object*/ constructor, /*Object...*/ props){
1706 // Adds all properties and methods of props to constructor's
1707 // prototype, making them available to all instances created with
1709 for(var i=1, l=arguments.length; i<l; i++){
1710 dojo._mixin(constructor.prototype, arguments[i]);
1712 return constructor; // Object
1715 dojo._hitchArgs = function(scope, method /*,...*/){
1716 var pre = dojo._toArray(arguments, 2);
1717 var named = dojo.isString(method);
1719 // arrayify arguments
1720 var args = dojo._toArray(arguments);
1721 // locate our method
1722 var f = named ? (scope||dojo.global)[method] : method;
1723 // invoke with collected args
1724 return f && f.apply(scope || this, pre.concat(args)); // mixed
1728 dojo.hitch = function(/*Object*/scope, /*Function|String*/method /*,...*/){
1730 // Returns a function that will only ever execute in the a given scope.
1731 // This allows for easy use of object member functions
1732 // in callbacks and other places in which the "this" keyword may
1733 // otherwise not reference the expected scope.
1734 // Any number of default positional arguments may be passed as parameters
1736 // Each of these values will be used to "placehold" (similar to curry)
1737 // for the hitched function.
1739 // The scope to use when method executes. If method is a string,
1740 // scope is also the object containing method.
1742 // A function to be hitched to scope, or the name of the method in
1743 // scope to be hitched.
1745 // | dojo.hitch(foo, "bar")();
1746 // runs foo.bar() in the scope of foo
1748 // | dojo.hitch(foo, myFunction);
1749 // returns a function that runs myFunction in the scope of foo
1750 if(arguments.length > 2){
1751 return dojo._hitchArgs.apply(dojo, arguments); // Function
1757 if(dojo.isString(method)){
1758 scope = scope || dojo.global;
1759 if(!scope[method]){ throw(['dojo.hitch: scope["', method, '"] is null (scope="', scope, '")'].join('')); }
1760 return function(){ return scope[method].apply(scope, arguments || []); }; // Function
1762 return !scope ? method : function(){ return method.apply(scope, arguments || []); }; // Function
1766 dojo.delegate = function(obj, props){
1768 // returns a new object which "looks" to obj for properties which it
1769 // does not have a value for. Optionally takes a bag of properties to
1770 // seed the returned object with initially.
1772 // This is a small implementaton of the Boodman/Crockford delegation
1773 // pattern in JavaScript. An intermediate object constructor mediates
1774 // the prototype chain for the returned object, using it to delegate
1775 // down to obj for property lookup when object-local lookup fails.
1776 // This can be thought of similarly to ES4's "wrap", save that it does
1777 // not act on types but rather on pure objects.
1779 // The object to delegate to for properties not found directly on the
1780 // return object or in props.
1782 // an object containing properties to assign to the returned object
1784 // an Object of anonymous type
1786 // | var foo = { bar: "baz" };
1787 // | var thinger = dojo.delegate(foo, { thud: "xyzzy"});
1788 // | thinger.bar == "baz"; // delegated to foo
1789 // | foo.thud == undefined; // by definition
1790 // | thinger.thud == "xyzzy"; // mixed in from props
1791 // | foo.bar = "thonk";
1792 // | thinger.bar == "thonk"; // still delegated to foo's bar
1796 dojo.delegate = dojo._delegate = (function(){
1797 // boodman/crockford delegation w/ cornford optimization
1799 return function(obj, props){
1800 TMP.prototype = obj;
1801 var tmp = new TMP();
1803 dojo._mixin(tmp, props);
1805 return tmp; // Object
1810 dojo._toArray = function(obj, offset, startWith){
1812 // Converts an array-like object (i.e. arguments, DOMCollection) to an
1813 // array. Returns a new Array with the elements of obj.
1815 // the object to "arrayify". We expect the object to have, at a
1816 // minimum, a length property which corresponds to integer-indexed
1819 // the location in obj to start iterating from. Defaults to 0.
1821 // startWith: Array?
1822 // An array to pack with the properties of obj. If provided,
1823 // properties in obj are appended at the end of startWith and
1824 // startWith is the returned array.
1829 var efficient = function(obj, offset, startWith){
1830 return (startWith||[]).concat(Array.prototype.slice.call(obj, offset||0));
1833 var slow = function(obj, offset, startWith){
1834 var arr = startWith||[];
1835 for(var x = offset || 0; x < obj.length; x++){
1841 dojo._toArray = (!dojo.isIE) ? efficient : function(obj){
1842 return ((obj.item) ? slow : efficient).apply(this, arguments);
1847 dojo.partial = function(/*Function|String*/method /*, ...*/){
1849 // similar to hitch() except that the scope object is left to be
1850 // whatever the execution context eventually becomes.
1852 // Calling dojo.partial is the functional equivalent of calling:
1853 // | dojo.hitch(null, funcName, ...);
1855 return dojo.hitch.apply(dojo, arr.concat(dojo._toArray(arguments))); // Function
1858 dojo.clone = function(/*anything*/ o){
1860 // Clones objects (including DOM nodes) and all children.
1861 // Warning: do not clone cyclic structures.
1863 if(dojo.isArray(o)){
1865 for(var i = 0; i < o.length; ++i){
1866 r.push(dojo.clone(o[i]));
1870 if(!dojo.isObject(o)){
1871 return o; /*anything*/
1873 if(o.nodeType && o.cloneNode){ // isNode
1874 return o.cloneNode(true); // Node
1876 if(o instanceof Date){
1877 return new Date(o.getTime()); // Date
1880 var r = new o.constructor(); // specific to dojo.declare()'d classes!
1882 if(!(i in r) || r[i] != o[i]){
1883 r[i] = dojo.clone(o[i]);
1889 dojo.trim = function(/*String*/ str){
1891 // trims whitespaces from both sides of the string
1893 // This version of trim() was selected for inclusion into the base due
1894 // to its compact size and relatively good performance (see Steven
1896 // http://blog.stevenlevithan.com/archives/faster-trim-javascript).
1897 // The fastest but longest version of this function is located at
1898 // dojo.string.trim()
1899 return str.replace(/^\s\s*/, '').replace(/\s\s*$/, ''); // String
1904 if(!dojo._hasResource["dojo._base.declare"]){ //_hasResource checks added by build. Do not use _hasResource directly in your code.
1905 dojo._hasResource["dojo._base.declare"] = true;
1906 dojo.provide("dojo._base.declare");
1909 // this file courtesy of the TurboAjax Group, licensed under a Dojo CLA
1911 dojo.declare = function(/*String*/ className, /*Function|Function[]*/ superclass, /*Object*/ props){
1913 // Create a feature-rich constructor from compact notation
1915 // The name of the constructor (loosely, a "class")
1916 // stored in the "declaredClass" property in the created prototype
1918 // May be null, a Function, or an Array of Functions. If an array,
1919 // the first element is used as the prototypical ancestor and
1920 // any following Functions become mixin ancestors.
1922 // An object whose properties are copied to the
1923 // created prototype.
1924 // Add an instance-initialization function by making it a property
1925 // named "constructor".
1927 // Create a constructor using a compact notation for inheritance and
1928 // prototype extension.
1930 // All superclasses (including mixins) must be Functions (not simple Objects).
1932 // Mixin ancestors provide a type of multiple inheritance. Prototypes of mixin
1933 // ancestors are copied to the new class: changes to mixin prototypes will
1934 // not affect classes to which they have been mixed in.
1936 // "className" is cached in "declaredClass" property of the new class.
1939 // | dojo.declare("my.classes.bar", my.classes.foo, {
1940 // | // properties to be added to the class prototype
1942 // | // initialization function
1943 // | constructor: function(){
1944 // | this.myComplicatedObject = new ReallyComplicatedObject();
1946 // | // other functions
1947 // | someMethod: function(){
1952 // process superclass argument
1953 var dd = arguments.callee, mixins;
1954 if(dojo.isArray(superclass)){
1955 mixins = superclass;
1956 superclass = mixins.shift();
1958 // construct intermediate classes for mixins
1960 dojo.forEach(mixins, function(m){
1961 if(!m){ throw(className + ": mixin #" + i + " is null"); } // It's likely a required module is not loaded
1962 superclass = dd._delegate(superclass, m);
1965 // create constructor
1966 var ctor = dd._delegate(superclass);
1967 // extend with "props"
1968 props = props || {};
1970 // more prototype decoration
1971 dojo.extend(ctor, {declaredClass: className, _constructor: props.constructor/*, preamble: null*/});
1972 // special help for IE
1973 ctor.prototype.constructor = ctor;
1974 // create named reference
1975 return dojo.setObject(className, ctor); // Function
1978 dojo.mixin(dojo.declare, {
1979 _delegate: function(base, mixin){
1980 var bp = (base||0).prototype, mp = (mixin||0).prototype, dd=dojo.declare;
1981 // fresh constructor, fresh prototype
1982 var ctor = dd._makeCtor();
1984 dojo.mixin(ctor, {superclass: bp, mixin: mp, extend: dd._extend});
1986 if(base){ctor.prototype = dojo._delegate(bp);}
1987 // add mixin and core
1988 dojo.extend(ctor, dd._core, mp||0, {_constructor: null, preamble: null});
1989 // special help for IE
1990 ctor.prototype.constructor = ctor;
1991 // name this class for debugging
1992 ctor.prototype.declaredClass = (bp||0).declaredClass + '_' + (mp||0).declaredClass;
1995 _extend: function(props){
1997 for(i in props){ if(dojo.isFunction(fn=props[i]) && !0[i]){fn.nom=i;fn.ctor=this;} }
1998 dojo.extend(this, props);
2000 _makeCtor: function(){
2001 // we have to make a function, but don't want to close over anything
2002 return function(){ this._construct(arguments); };
2005 _construct: function(args){
2006 var c=args.callee, s=c.superclass, ct=s&&s.constructor, m=c.mixin, mct=m&&m.constructor, a=args, ii, fn;
2007 // side-effect of = used on purpose here, lint may complain, don't try this at home
2009 // FIXME: preambles for each mixin should be allowed
2011 // should we allow the preamble here NOT to modify the
2012 // default args, but instead to act on each mixin
2013 // independently of the class instance being constructed
2014 // (for impedence matching)?
2016 // allow any first argument w/ a "preamble" property to act as a
2017 // class preamble (not exclusive of the prototype preamble)
2018 if(/*dojo.isFunction*/((fn = a[0].preamble))){
2019 a = fn.apply(this, a) || a;
2022 // prototype preamble
2023 if((fn = c.prototype.preamble)){a = fn.apply(this, a) || a;}
2025 // need to provide an optional prototype-settable
2026 // "_explicitSuper" property which disables this
2027 // initialize superclass
2028 if(ct&&ct.apply){ct.apply(this, a);}
2030 if(mct&&mct.apply){mct.apply(this, a);}
2032 if((ii=c.prototype._constructor)){ii.apply(this, args);}
2033 // post construction
2034 if(this.constructor.prototype==c.prototype && (ct=this.postscript)){ ct.apply(this, args); }
2036 _findMixin: function(mixin){
2037 var c = this.constructor, p, m;
2041 if(m==mixin || (m instanceof mixin.constructor)){return p;}
2042 if(m && m._findMixin && (m=m._findMixin(mixin))){return m;}
2043 c = p && p.constructor;
2046 _findMethod: function(name, method, ptype, has){
2047 // consciously trading readability for bytes and speed in this low-level method
2048 var p=ptype, c, m, f;
2052 // find method by name in our mixin ancestor
2053 if(m && (m=this._findMethod(name, method, m, has))){return m;}
2054 // if we found a named method that either exactly-is or exactly-is-not 'method'
2055 if((f=p[name])&&(has==(f==method))){return p;}
2059 // if we couldn't find an ancestor in our primary chain, try a mixin chain
2060 return !has && (p=this._findMixin(ptype)) && this._findMethod(name, method, p, has);
2062 inherited: function(name, args, newArgs){
2063 // optionalize name argument
2065 if(!dojo.isString(a[0])){newArgs=args; args=name; name=args.callee.nom;}
2067 var c = args.callee, p = this.constructor.prototype, fn, mp;
2068 // if not an instance override
2069 if(this[name] != c || p[name] == c){
2070 // start from memoized prototype, or
2071 // find a prototype that has property 'name' == 'c'
2072 mp = (c.ctor||0).superclass || this._findMethod(name, c, p, true);
2073 if(!mp){throw(this.declaredClass + ': inherited method "' + name + '" mismatch');}
2074 // find a prototype that has property 'name' != 'c'
2075 p = this._findMethod(name, c, mp, false);
2077 // we expect 'name' to be in prototype 'p'
2079 if(!fn){throw(mp.declaredClass + ': inherited method "' + name + '" not found');}
2080 // if the function exists, invoke it in our scope
2081 return fn.apply(this, a);
2088 if(!dojo._hasResource["dojo._base.connect"]){ //_hasResource checks added by build. Do not use _hasResource directly in your code.
2089 dojo._hasResource["dojo._base.connect"] = true;
2090 dojo.provide("dojo._base.connect");
2093 // this file courtesy of the TurboAjax Group, licensed under a Dojo CLA
2095 // low-level delegation machinery
2097 // create a dispatcher function
2098 getDispatcher: function(){
2099 // following comments pulled out-of-line to prevent cloning them
2100 // in the returned function.
2101 // - indices (i) that are really in the array of listeners (ls) will
2102 // not be in Array.prototype. This is the 'sparse array' trick
2103 // that keeps us safe from libs that take liberties with built-in
2105 // - listener is invoked with current scope (this)
2107 var ap=Array.prototype, c=arguments.callee, ls=c._listeners, t=c.target;
2108 // return value comes from original target function
2109 var r = t && t.apply(this, arguments);
2110 // make local copy of listener array so it is immutable during processing
2112 lls = [].concat(ls);
2114 // invoke listeners after target function
2117 lls[i].apply(this, arguments);
2120 // return value comes from original target function
2124 // add a listener to an object
2125 add: function(/*Object*/ source, /*String*/ method, /*Function*/ listener){
2126 // Whenever 'method' is invoked, 'listener' will have the same scope.
2127 // Trying to supporting a context object for the listener led to
2129 // Non trivial to provide 'once' functionality here
2130 // because listener could be the result of a dojo.hitch call,
2131 // in which case two references to the same hitch target would not
2133 source = source || dojo.global;
2134 // The source method is either null, a dispatcher, or some other function
2135 var f = source[method];
2136 // Ensure a dispatcher
2137 if(!f||!f._listeners){
2138 var d = dojo._listener.getDispatcher();
2139 // original target function is special
2141 // dispatcher holds a list of listeners
2143 // redirect source to dispatcher
2144 f = source[method] = d;
2146 // The contract is that a handle is returned that can
2147 // identify this listener for disconnect.
2149 // The type of the handle is private. Here is it implemented as Integer.
2150 // DOM event code has this same contract but handle is Function
2151 // in non-IE browsers.
2153 // We could have separate lists of before and after listeners.
2154 return f._listeners.push(listener) ; /*Handle*/
2156 // remove a listener from an object
2157 remove: function(/*Object*/ source, /*String*/ method, /*Handle*/ handle){
2158 var f = (source||dojo.global)[method];
2159 // remember that handle is the index+1 (0 is not a valid handle)
2160 if(f && f._listeners && handle--){
2161 delete f._listeners[handle];
2166 // Multiple delegation for arbitrary methods.
2168 // This unit knows nothing about DOM,
2169 // but we include DOM aware
2170 // documentation and dontFix
2171 // argument here to help the autodocs.
2172 // Actual DOM aware code is in event.js.
2174 dojo.connect = function(/*Object|null*/ obj,
2176 /*Object|null*/ context,
2177 /*String|Function*/ method,
2178 /*Boolean*/ dontFix){
2180 // Create a link that calls one function when another executes.
2183 // Connects method to event, so that after event fires, method
2184 // does too. All connected functions are passed the same arguments as
2185 // the event function was initially called with. You may connect as
2186 // many methods to event as needed.
2188 // event must be a string. If obj is null, dojo.global is used.
2190 // null arguments may simply be omitted.
2192 // obj[event] can resolve to a function or undefined (null).
2193 // If obj[event] is null, it is assigned a function.
2195 // The return value is a handle that is needed to
2196 // remove this connection with dojo.disconnect.
2199 // The source object for the event function.
2200 // Defaults to dojo.global if null.
2201 // If obj is a DOM node, the connection is delegated
2202 // to the DOM event manager (unless dontFix is true).
2205 // String name of the event function in obj.
2206 // I.e. identifies a property obj[event].
2209 // The object that method will receive as "this".
2211 // If context is null and method is a function, then method
2212 // inherits the context of event.
2214 // If method is a string then context must be the source
2215 // object object for method (context[method]). If context is null,
2216 // dojo.global is used.
2219 // A function reference, or name of a function in context.
2220 // The function identified by method fires after event does.
2221 // method receives the same arguments as the event.
2222 // See context argument comments for information on method's scope.
2225 // If obj is a DOM node, set dontFix to true to prevent delegation
2226 // of this connection to the DOM event manager.
2229 // When obj.onchange(), do ui.update():
2230 // | dojo.connect(obj, "onchange", ui, "update");
2231 // | dojo.connect(obj, "onchange", ui, ui.update); // same
2234 // Using return value for disconnect:
2235 // | var link = dojo.connect(obj, "onchange", ui, "update");
2237 // | dojo.disconnect(link);
2240 // When onglobalevent executes, watcher.handler is invoked:
2241 // | dojo.connect(null, "onglobalevent", watcher, "handler");
2244 // When ob.onCustomEvent executes, customEventHandler is invoked:
2245 // | dojo.connect(ob, "onCustomEvent", null, "customEventHandler");
2246 // | dojo.connect(ob, "onCustomEvent", "customEventHandler"); // same
2249 // When ob.onCustomEvent executes, customEventHandler is invoked
2250 // with the same scope (this):
2251 // | dojo.connect(ob, "onCustomEvent", null, customEventHandler);
2252 // | dojo.connect(ob, "onCustomEvent", customEventHandler); // same
2255 // When globalEvent executes, globalHandler is invoked
2256 // with the same scope (this):
2257 // | dojo.connect(null, "globalEvent", null, globalHandler);
2258 // | dojo.connect("globalEvent", globalHandler); // same
2260 // normalize arguments
2261 var a=arguments, args=[], i=0;
2262 // if a[0] is a String, obj was ommited
2263 args.push(dojo.isString(a[0]) ? null : a[i++], a[i++]);
2264 // if the arg-after-next is a String or Function, context was NOT omitted
2266 args.push(dojo.isString(a1)||dojo.isFunction(a1) ? a[i++] : null, a[i++]);
2267 // absorb any additional arguments
2268 for(var l=a.length; i<l; i++){ args.push(a[i]); }
2269 // do the actual work
2270 return dojo._connect.apply(this, args); /*Handle*/
2273 // used by non-browser hostenvs. always overriden by event.js
2274 dojo._connect = function(obj, event, context, method){
2275 var l=dojo._listener, h=l.add(obj, event, dojo.hitch(context, method));
2276 return [obj, event, h, l]; // Handle
2279 dojo.disconnect = function(/*Handle*/ handle){
2281 // Remove a link created by dojo.connect.
2283 // Removes the connection between event and the method referenced by handle.
2285 // the return value of the dojo.connect call that created the connection.
2286 if(handle && handle[0] !== undefined){
2287 dojo._disconnect.apply(this, handle);
2288 // let's not keep this reference
2293 dojo._disconnect = function(obj, event, handle, listener){
2294 listener.remove(obj, event, handle);
2297 // topic publish/subscribe
2301 dojo.subscribe = function(/*String*/ topic, /*Object|null*/ context, /*String|Function*/ method){
2303 // Attach a listener to a named topic. The listener function is invoked whenever the
2304 // named topic is published (see: dojo.publish).
2305 // Returns a handle which is needed to unsubscribe this listener.
2307 // Scope in which method will be invoked, or null for default scope.
2309 // The name of a function in context, or a function reference. This is the function that
2310 // is invoked when topic is published.
2312 // | dojo.subscribe("alerts", null, function(caption, message){ alert(caption + "\n" + message); };
2313 // | dojo.publish("alerts", [ "read this", "hello world" ]);
2315 // support for 2 argument invocation (omitting context) depends on hitch
2316 return [topic, dojo._listener.add(dojo._topics, topic, dojo.hitch(context, method))]; /*Handle*/
2319 dojo.unsubscribe = function(/*Handle*/ handle){
2321 // Remove a topic listener.
2323 // The handle returned from a call to subscribe.
2325 // | var alerter = dojo.subscribe("alerts", null, function(caption, message){ alert(caption + "\n" + message); };
2327 // | dojo.unsubscribe(alerter);
2329 dojo._listener.remove(dojo._topics, handle[0], handle[1]);
2333 dojo.publish = function(/*String*/ topic, /*Array*/ args){
2335 // Invoke all listener method subscribed to topic.
2337 // The name of the topic to publish.
2339 // An array of arguments. The arguments will be applied
2340 // to each topic subscriber (as first class parameters, via apply).
2342 // | dojo.subscribe("alerts", null, function(caption, message){ alert(caption + "\n" + message); };
2343 // | dojo.publish("alerts", [ "read this", "hello world" ]);
2345 // Note that args is an array, which is more efficient vs variable length
2346 // argument list. Ideally, var args would be implemented via Array
2347 // throughout the APIs.
2348 var f = dojo._topics[topic];
2350 f.apply(this, args||[]);
2354 dojo.connectPublisher = function( /*String*/ topic,
2355 /*Object|null*/ obj,
2358 // Ensure that everytime obj.event() is called, a message is published
2359 // on the topic. Returns a handle which can be passed to
2360 // dojo.disconnect() to disable subsequent automatic publication on
2363 // The name of the topic to publish.
2365 // The source object for the event function. Defaults to dojo.global
2368 // The name of the event function in obj.
2369 // I.e. identifies a property obj[event].
2371 // | dojo.connectPublisher("/ajax/start", dojo, "xhrGet");
2372 var pf = function(){ dojo.publish(topic, arguments); }
2373 return (event) ? dojo.connect(obj, event, pf) : dojo.connect(obj, pf); //Handle
2378 if(!dojo._hasResource["dojo._base.Deferred"]){ //_hasResource checks added by build. Do not use _hasResource directly in your code.
2379 dojo._hasResource["dojo._base.Deferred"] = true;
2380 dojo.provide("dojo._base.Deferred");
2383 dojo.Deferred = function(/*Function?*/ canceller){
2385 // Encapsulates a sequence of callbacks in response to a value that
2386 // may not yet be available. This is modeled after the Deferred class
2387 // from Twisted <http://twistedmatrix.com>.
2389 // JavaScript has no threads, and even if it did, threads are hard.
2390 // Deferreds are a way of abstracting non-blocking events, such as the
2391 // final response to an XMLHttpRequest. Deferreds create a promise to
2392 // return a response a some point in the future and an easy way to
2393 // register your interest in receiving that response.
2395 // The most important methods for Deffered users are:
2397 // * addCallback(handler)
2398 // * addErrback(handler)
2399 // * callback(result)
2400 // * errback(result)
2402 // In general, when a function returns a Deferred, users then "fill
2403 // in" the second half of the contract by registering callbacks and
2404 // error handlers. You may register as many callback and errback
2405 // handlers as you like and they will be executed in the order
2406 // registered when a result is provided. Usually this result is
2407 // provided as the result of an asynchronous operation. The code
2408 // "managing" the Deferred (the code that made the promise to provide
2409 // an answer later) will use the callback() and errback() methods to
2410 // communicate with registered listeners about the result of the
2411 // operation. At this time, all registered result handlers are called
2412 // *with the most recent result value*.
2414 // Deferred callback handlers are treated as a chain, and each item in
2415 // the chain is required to return a value that will be fed into
2416 // successive handlers. The most minimal callback may be registered
2419 // | var d = new dojo.Deferred();
2420 // | d.addCallback(function(result){ return result; });
2422 // Perhaps the most common mistake when first using Deferreds is to
2423 // forget to return a value (in most cases, the value you were
2426 // The sequence of callbacks is internally represented as a list of
2427 // 2-tuples containing the callback/errback pair. For example, the
2428 // following call sequence:
2430 // | var d = new dojo.Deferred();
2431 // | d.addCallback(myCallback);
2432 // | d.addErrback(myErrback);
2433 // | d.addBoth(myBoth);
2434 // | d.addCallbacks(myCallback, myErrback);
2436 // is translated into a Deferred with the following internal
2440 // | [myCallback, null],
2441 // | [null, myErrback],
2442 // | [myBoth, myBoth],
2443 // | [myCallback, myErrback]
2446 // The Deferred also keeps track of its current status (fired). Its
2447 // status may be one of three things:
2449 // * -1: no value yet (initial condition)
2453 // A Deferred will be in the error state if one of the following three
2454 // conditions are met:
2456 // 1. The result given to callback or errback is "instanceof" Error
2457 // 2. The previous callback or errback raised an exception while
2459 // 3. The previous callback or errback returned a value
2460 // "instanceof" Error
2462 // Otherwise, the Deferred will be in the success state. The state of
2463 // the Deferred determines the next element in the callback sequence
2466 // When a callback or errback occurs with the example deferred chain,
2467 // something equivalent to the following will happen (imagine
2468 // that exceptions are caught and returned):
2470 // | // d.callback(result) or d.errback(result)
2471 // | if(!(result instanceof Error)){
2472 // | result = myCallback(result);
2474 // | if(result instanceof Error){
2475 // | result = myErrback(result);
2477 // | result = myBoth(result);
2478 // | if(result instanceof Error){
2479 // | result = myErrback(result);
2481 // | result = myCallback(result);
2484 // The result is then stored away in case another step is added to the
2485 // callback sequence. Since the Deferred already has a value
2486 // available, any new callbacks added will be called immediately.
2488 // There are two other "advanced" details about this implementation
2491 // Callbacks are allowed to return Deferred instances themselves, so
2492 // you can build complicated sequences of events with ease.
2494 // The creator of the Deferred may specify a canceller. The canceller
2495 // is a function that will be called if Deferred.cancel is called
2496 // before the Deferred fires. You can use this to implement clean
2497 // aborting of an XMLHttpRequest, etc. Note that cancel will fire the
2498 // deferred with a CancelledError (unless your canceller returns
2499 // another kind of error), so the errbacks should be prepared to
2500 // handle that error for cancellable Deferreds.
2502 // | var deferred = new dojo.Deferred();
2503 // | setTimeout(function(){ deferred.callback({success: true}); }, 1000);
2504 // | return deferred;
2506 // Deferred objects are often used when making code asynchronous. It
2507 // may be easiest to write functions in a synchronous manner and then
2508 // split code using a deferred to trigger a response to a long-lived
2509 // operation. For example, instead of register a callback function to
2510 // denote when a rendering operation completes, the function can
2511 // simply return a deferred:
2513 // | // callback style:
2514 // | function renderLotsOfData(data, callback){
2515 // | var success = false
2517 // | for(var x in data){
2518 // | renderDataitem(data[x]);
2520 // | success = true;
2523 // | callback(success);
2527 // | // using callback style
2528 // | renderLotsOfData(someDataObj, function(success){
2529 // | // handles success or failure
2531 // | promptUserToRecover();
2534 // | // NOTE: no way to add another callback here!!
2536 // Using a Deferred doesn't simplify the sending code any, but it
2537 // provides a standard interface for callers and senders alike,
2538 // providing both with a simple way to service multiple callbacks for
2539 // an operation and freeing both sides from worrying about details
2540 // such as "did this get called already?". With Deferreds, new
2541 // callbacks can be added at any time.
2543 // | // Deferred style:
2544 // | function renderLotsOfData(data){
2545 // | var d = new dojo.Deferred();
2547 // | for(var x in data){
2548 // | renderDataitem(data[x]);
2550 // | d.callback(true);
2552 // | d.errback(new Error("rendering failed"));
2557 // | // using Deferred style
2558 // | renderLotsOfData(someDataObj).addErrback(function(){
2559 // | promptUserToRecover();
2561 // | // NOTE: addErrback and addCallback both return the Deferred
2562 // | // again, so we could chain adding callbacks or save the
2563 // | // deferred for later should we need to be notified again.
2565 // In this example, renderLotsOfData is syncrhonous and so both
2566 // versions are pretty artificial. Putting the data display on a
2567 // timeout helps show why Deferreds rock:
2569 // | // Deferred style and async func
2570 // | function renderLotsOfData(data){
2571 // | var d = new dojo.Deferred();
2572 // | setTimeout(function(){
2574 // | for(var x in data){
2575 // | renderDataitem(data[x]);
2577 // | d.callback(true);
2579 // | d.errback(new Error("rendering failed"));
2585 // | // using Deferred style
2586 // | renderLotsOfData(someDataObj).addErrback(function(){
2587 // | promptUserToRecover();
2590 // Note that the caller doesn't have to change his code at all to
2591 // handle the asynchronous case.
2594 this.id = this._nextId();
2597 this.results = [null, null];
2598 this.canceller = canceller;
2599 this.silentlyCancelled = false;
2602 dojo.extend(dojo.Deferred, {
2604 makeCalled: function(){
2606 // returns a new, empty deferred, which is already in the called
2607 // state. Calling callback() or errback() on this deferred will
2608 // yeild an error and adding new handlers to it will result in
2609 // them being called immediately.
2610 var deferred = new dojo.Deferred();
2611 deferred.callback();
2615 toString: function(){
2617 if(this.fired == -1){
2620 state = this.fired ? 'success' : 'error';
2622 return 'Deferred(' + this.id + ', ' + state + ')';
2626 _nextId: (function(){
2628 return function(){ return n++; };
2633 // Cancels a Deferred that has not yet received a value, or is
2634 // waiting on another Deferred as its value.
2636 // If a canceller is defined, the canceller is called. If the
2637 // canceller did not return an error, or there was no canceller,
2638 // then the errback chain is started.
2640 if(this.fired == -1){
2642 err = this.canceller(this);
2644 this.silentlyCancelled = true;
2646 if(this.fired == -1){
2647 if(!(err instanceof Error)){
2649 err = new Error("Deferred Cancelled");
2650 err.dojoType = "cancel";
2651 err.cancelResult = res;
2655 }else if( (this.fired == 0) &&
2656 (this.results[0] instanceof dojo.Deferred)
2658 this.results[0].cancel();
2663 _resback: function(res){
2665 // The private primitive that means either callback or errback
2666 this.fired = ((res instanceof Error) ? 1 : 0);
2667 this.results[this.fired] = res;
2672 if(this.fired != -1){
2673 if(!this.silentlyCancelled){
2674 throw new Error("already called!");
2676 this.silentlyCancelled = false;
2681 callback: function(res){
2683 // Begin the callback sequence with a non-error value.
2686 callback or errback should only be called once on a given
2693 errback: function(/*Error*/res){
2695 // Begin the callback sequence with an error result.
2697 if(!(res instanceof Error)){
2698 res = new Error(res);
2703 addBoth: function(/*Function|Object*/cb, /*String?*/cbfn){
2705 // Add the same function as both a callback and an errback as the
2706 // next element on the callback sequence.This is useful for code
2707 // that you want to guarantee to run, e.g. a finalizer.
2708 var enclosed = dojo.hitch.apply(dojo, arguments);
2709 return this.addCallbacks(enclosed, enclosed); // dojo.Deferred
2712 addCallback: function(/*Function|Object*/cb, /*String?*/cbfn /*...*/){
2714 // Add a single callback to the end of the callback sequence.
2715 return this.addCallbacks(dojo.hitch.apply(dojo, arguments)); // dojo.Deferred
2718 addErrback: function(cb, cbfn){
2720 // Add a single callback to the end of the callback sequence.
2721 return this.addCallbacks(null, dojo.hitch.apply(dojo, arguments)); // dojo.Deferred
2724 addCallbacks: function(cb, eb){
2726 // Add separate callback and errback to the end of the callback
2728 this.chain.push([cb, eb])
2729 if(this.fired >= 0){
2732 return this; // dojo.Deferred
2737 // Used internally to exhaust the callback sequence when a result
2739 var chain = this.chain;
2740 var fired = this.fired;
2741 var res = this.results[fired];
2745 (chain.length > 0) &&
2749 var f = chain.shift()[fired];
2751 var func = function(){
2753 //If no response, then use previous response.
2754 if(typeof ret != "undefined"){
2757 fired = ((res instanceof Error) ? 1 : 0);
2758 if(res instanceof dojo.Deferred){
2761 // inlined from _pause()
2764 (self.paused == 0) &&
2770 // inlined from _unpause
2774 if(dojo.config.isDebug){
2786 this.results[fired] = res;
2787 if((cb)&&(this.paused)){
2788 // this is for "tail recursion" in case the dependent
2789 // deferred is already fired
2797 if(!dojo._hasResource["dojo._base.json"]){ //_hasResource checks added by build. Do not use _hasResource directly in your code.
2798 dojo._hasResource["dojo._base.json"] = true;
2799 dojo.provide("dojo._base.json");
2801 dojo.fromJson = function(/*String*/ json){
2803 // Parses a [JSON](http://json.org) string to return a JavaScript object. Throws for invalid JSON strings.
2805 // a string literal of a JSON item, for instance:
2806 // `'{ "foo": [ "bar", 1, { "baz": "thud" } ] }'`
2808 return eval("(" + json + ")"); // Object
2811 dojo._escapeString = function(/*String*/str){
2813 // Adds escape sequences for non-visual characters, double quote and
2814 // backslash and surrounds with double quotes to form a valid string
2816 return ('"' + str.replace(/(["\\])/g, '\\$1') + '"').
2817 replace(/[\f]/g, "\\f").replace(/[\b]/g, "\\b").replace(/[\n]/g, "\\n").
2818 replace(/[\t]/g, "\\t").replace(/[\r]/g, "\\r"); // string
2821 dojo.toJsonIndentStr = "\t";
2822 dojo.toJson = function(/*Object*/ it, /*Boolean?*/ prettyPrint, /*String?*/ _indentStr){
2824 // Returns a [JSON](http://json.org) serialization of an object.
2827 // Returns a [JSON](http://json.org) serialization of an object.
2828 // Note that this doesn't check for infinite recursion, so don't do that!
2831 // an object to be serialized. Objects may define their own
2832 // serialization via a special "__json__" or "json" function
2833 // property. If a specialized serializer has been defined, it will
2834 // be used as a fallback.
2837 // if true, we indent objects and arrays to make the output prettier.
2838 // The variable dojo.toJsonIndentStr is used as the indent string
2839 // -- to use something other than the default (tab),
2840 // change that variable before calling dojo.toJson().
2843 // private variable for recursive calls when pretty printing, do not use.
2845 if(it === undefined){
2848 var objtype = typeof it;
2849 if(objtype == "number" || objtype == "boolean"){
2855 if(dojo.isString(it)){
2856 return dojo._escapeString(it);
2859 var recurse = arguments.callee;
2860 // short-circuit for objects that support "json" serialization
2861 // if they return "self" then just pass-through...
2863 _indentStr = _indentStr || "";
2864 var nextIndent = prettyPrint ? _indentStr + dojo.toJsonIndentStr : "";
2865 var tf = it.__json__||it.json;
2866 if(dojo.isFunction(tf)){
2867 newObj = tf.call(it);
2869 return recurse(newObj, prettyPrint, nextIndent);
2872 if(it.nodeType && it.cloneNode){ // isNode
2873 // we can't seriailize DOM nodes as regular objects because they have cycles
2874 // DOM nodes could be serialized with something like outerHTML, but
2875 // that can be provided by users in the form of .json or .__json__ function.
2876 throw new Error("Can't serialize DOM nodes");
2879 var sep = prettyPrint ? " " : "";
2880 var newLine = prettyPrint ? "\n" : "";
2883 if(dojo.isArray(it)){
2884 var res = dojo.map(it, function(obj){
2885 var val = recurse(obj, prettyPrint, nextIndent);
2886 if(typeof val != "string"){
2889 return newLine + nextIndent + val;
2891 return "[" + res.join("," + sep) + newLine + _indentStr + "]";
2894 // look in the registry
2897 newObj = dojo.json.jsonRegistry.match(it);
2898 return recurse(newObj, prettyPrint, nextIndent);
2902 // it's a function with no adapter, skip it
2904 if(objtype == "function"){
2905 return null; // null
2907 // generic object code path
2908 var output = [], key;
2911 if(typeof key == "number"){
2912 keyStr = '"' + key + '"';
2913 }else if(typeof key == "string"){
2914 keyStr = dojo._escapeString(key);
2916 // skip non-string or number keys
2919 val = recurse(it[key], prettyPrint, nextIndent);
2920 if(typeof val != "string"){
2921 // skip non-serializable values
2924 // FIXME: use += on Moz!!
2925 // MOW NOTE: using += is a pain because you have to account for the dangling comma...
2926 output.push(newLine + nextIndent + keyStr + ":" + sep + val);
2928 return "{" + output.join("," + sep) + newLine + _indentStr + "}"; // String
2933 if(!dojo._hasResource["dojo._base.array"]){ //_hasResource checks added by build. Do not use _hasResource directly in your code.
2934 dojo._hasResource["dojo._base.array"] = true;
2936 dojo.provide("dojo._base.array");
2939 var _getParts = function(arr, obj, cb){
2941 dojo.isString(arr) ? arr.split("") : arr,
2943 // FIXME: cache the anonymous functions we create here?
2944 dojo.isString(cb) ? new Function("item", "index", "array", cb) : cb
2949 indexOf: function( /*Array*/ array,
2951 /*Integer?*/ fromIndex,
2952 /*Boolean?*/ findLast){
2954 // locates the first index of the provided value in the
2955 // passed array. If the value is not found, -1 is returned.
2957 // For details on this method, see:
2958 // http://developer.mozilla.org/en/docs/Core_JavaScript_1.5_Reference:Global_Objects:Array:indexOf
2960 var step = 1, end = array.length || 0, i = 0;
2965 if(fromIndex != undefined){ i = fromIndex; }
2966 if((findLast && i > end) || i < end){
2967 for(; i != end; i += step){
2968 if(array[i] == value){ return i; }
2971 return -1; // Number
2974 lastIndexOf: function(/*Array*/array, /*Object*/value, /*Integer?*/fromIndex){
2976 // locates the last index of the provided value in the passed
2977 // array. If the value is not found, -1 is returned.
2979 // For details on this method, see:
2980 // http://developer.mozilla.org/en/docs/Core_JavaScript_1.5_Reference:Global_Objects:Array:lastIndexOf
2981 return dojo.indexOf(array, value, fromIndex, true); // Number
2984 forEach: function(/*Array|String*/arr, /*Function|String*/callback, /*Object?*/thisObject){
2986 // for every item in arr, callback is invoked. Return values are ignored.
2988 // the array to iterate over. If a string, operates on individual characters.
2990 // a function is invoked with three arguments: item, index, and array
2992 // may be used to scope the call to callback
2994 // This function corresponds to the JavaScript 1.6
2995 // Array.forEach() method. For more details, see:
2996 // http://developer.mozilla.org/en/docs/Core_JavaScript_1.5_Reference:Global_Objects:Array:forEach
2998 // | // log out all members of the array:
3000 // | [ "thinger", "blah", "howdy", 10 ],
3001 // | function(item){
3006 // | // log out the members and their indexes
3008 // | [ "thinger", "blah", "howdy", 10 ],
3009 // | function(item, idx, arr){
3014 // | // use a scoped object member as the callback
3017 // | prefix: "logged via obj.callback:",
3018 // | callback: function(item){
3023 // | // specifying the scope function executes the callback in that scope
3025 // | [ "thinger", "blah", "howdy", 10 ],
3030 // | // alternately, we can accomplish the same thing with dojo.hitch()
3032 // | [ "thinger", "blah", "howdy", 10 ],
3033 // | dojo.hitch(obj, "callback")
3036 // match the behavior of the built-in forEach WRT empty arrs
3037 if(!arr || !arr.length){ return; }
3039 // FIXME: there are several ways of handilng thisObject. Is
3040 // dojo.global always the default context?
3041 var _p = _getParts(arr, thisObject, callback); arr = _p[0];
3042 for(var i=0,l=arr.length; i<l; ++i){
3043 _p[2].call(_p[1], arr[i], i, arr);
3047 _everyOrSome: function(/*Boolean*/every, /*Array|String*/arr, /*Function|String*/callback, /*Object?*/thisObject){
3048 var _p = _getParts(arr, thisObject, callback); arr = _p[0];
3049 for(var i=0,l=arr.length; i<l; ++i){
3050 var result = !!_p[2].call(_p[1], arr[i], i, arr);
3052 return result; // Boolean
3055 return every; // Boolean
3058 every: function(/*Array|String*/arr, /*Function|String*/callback, /*Object?*/thisObject){
3060 // Determines whether or not every item in arr satisfies the
3061 // condition implemented by callback.
3063 // the array to iterate on. If a string, operates on individual characters.
3065 // a function is invoked with three arguments: item, index,
3066 // and array and returns true if the condition is met.
3068 // may be used to scope the call to callback
3070 // This function corresponds to the JavaScript 1.6
3071 // Array.every() method. For more details, see:
3072 // http://developer.mozilla.org/en/docs/Core_JavaScript_1.5_Reference:Global_Objects:Array:every
3074 // | // returns false
3075 // | dojo.every([1, 2, 3, 4], function(item){ return item>1; });
3077 // | // returns true
3078 // | dojo.every([1, 2, 3, 4], function(item){ return item>0; });
3079 return this._everyOrSome(true, arr, callback, thisObject); // Boolean
3082 some: function(/*Array|String*/arr, /*Function|String*/callback, /*Object?*/thisObject){
3084 // Determines whether or not any item in arr satisfies the
3085 // condition implemented by callback.
3087 // the array to iterate over. If a string, operates on individual characters.
3089 // a function is invoked with three arguments: item, index,
3090 // and array and returns true if the condition is met.
3092 // may be used to scope the call to callback
3094 // This function corresponds to the JavaScript 1.6
3095 // Array.some() method. For more details, see:
3096 // http://developer.mozilla.org/en/docs/Core_JavaScript_1.5_Reference:Global_Objects:Array:some
3099 // | dojo.some([1, 2, 3, 4], function(item){ return item>1; });
3102 // | dojo.some([1, 2, 3, 4], function(item){ return item<1; });
3103 return this._everyOrSome(false, arr, callback, thisObject); // Boolean
3106 map: function(/*Array|String*/arr, /*Function|String*/callback, /*Function?*/thisObject){
3108 // applies callback to each element of arr and returns
3109 // an Array with the results
3111 // the array to iterate on. If a string, operates on
3112 // individual characters.
3114 // a function is invoked with three arguments, (item, index,
3115 // array), and returns a value
3117 // may be used to scope the call to callback
3119 // This function corresponds to the JavaScript 1.6 Array.map()
3120 // method. For more details, see:
3121 // http://developer.mozilla.org/en/docs/Core_JavaScript_1.5_Reference:Global_Objects:Array:map
3123 // | // returns [2, 3, 4, 5]
3124 // | dojo.map([1, 2, 3, 4], function(item){ return item+1 });
3126 var _p = _getParts(arr, thisObject, callback); arr = _p[0];
3127 var outArr = (arguments[3] ? (new arguments[3]()) : []);
3128 for(var i=0,l=arr.length; i<l; ++i){
3129 outArr.push(_p[2].call(_p[1], arr[i], i, arr));
3131 return outArr; // Array
3134 filter: function(/*Array*/arr, /*Function|String*/callback, /*Object?*/thisObject){
3136 // Returns a new Array with those items from arr that match the
3137 // condition implemented by callback.
3139 // the array to iterate over.
3141 // a function that is invoked with three arguments (item,
3142 // index, array). The return of this function is expected to
3143 // be a boolean which determines whether the passed-in item
3144 // will be included in the returned array.
3146 // may be used to scope the call to callback
3148 // This function corresponds to the JavaScript 1.6
3149 // Array.filter() method. For more details, see:
3150 // http://developer.mozilla.org/en/docs/Core_JavaScript_1.5_Reference:Global_Objects:Array:filter
3152 // | // returns [2, 3, 4]
3153 // | dojo.filter([1, 2, 3, 4], function(item){ return item>1; });
3155 var _p = _getParts(arr, thisObject, callback); arr = _p[0];
3157 for(var i=0,l=arr.length; i<l; ++i){
3158 if(_p[2].call(_p[1], arr[i], i, arr)){
3159 outArr.push(arr[i]);
3162 return outArr; // Array
3169 if(!dojo._hasResource["dojo._base.Color"]){ //_hasResource checks added by build. Do not use _hasResource directly in your code.
3170 dojo._hasResource["dojo._base.Color"] = true;
3171 dojo.provide("dojo._base.Color");
3175 dojo.Color = function(/*Array|String|Object*/ color){
3177 // takes a named string, hex string, array of rgb or rgba values,
3178 // an object with r, g, b, and a properties, or another dojo.Color object
3179 if(color){ this.setColor(color); }
3182 // FIXME: there's got to be a more space-efficient way to encode or discover these!! Use hex?
3183 dojo.Color.named = {
3185 silver: [192,192,192],
3186 gray: [128,128,128],
3187 white: [255,255,255],
3190 purple: [128,0,128],
3191 fuchsia: [255,0,255],
3195 yellow: [255,255,0],
3203 dojo.extend(dojo.Color, {
3204 r: 255, g: 255, b: 255, a: 1,
3205 _set: function(r, g, b, a){
3206 var t = this; t.r = r; t.g = g; t.b = b; t.a = a;
3208 setColor: function(/*Array|String|Object*/ color){
3210 // takes a named string, hex string, array of rgb or rgba values,
3211 // an object with r, g, b, and a properties, or another dojo.Color object
3213 if(d.isString(color)){
3214 d.colorFromString(color, this);
3215 }else if(d.isArray(color)){
3216 d.colorFromArray(color, this);
3218 this._set(color.r, color.g, color.b, color.a);
3219 if(!(color instanceof d.Color)){ this.sanitize(); }
3221 return this; // dojo.Color
3223 sanitize: function(){
3225 // makes sure that the object has correct attributes
3227 // the default implementation does nothing, include dojo.colors to
3228 // augment it to real checks
3229 return this; // dojo.Color
3232 // summary: returns 3 component array of rgb values
3234 return [t.r, t.g, t.b]; // Array
3237 // summary: returns a 4 component array of rgba values
3239 return [t.r, t.g, t.b, t.a]; // Array
3242 // summary: returns a css color string in hexadecimal representation
3243 var arr = dojo.map(["r", "g", "b"], function(x){
3244 var s = this[x].toString(16);
3245 return s.length < 2 ? "0" + s : s;
3247 return "#" + arr.join(""); // String
3249 toCss: function(/*Boolean?*/ includeAlpha){
3250 // summary: returns a css color string in rgb(a) representation
3251 var t = this, rgb = t.r + ", " + t.g + ", " + t.b;
3252 return (includeAlpha ? "rgba(" + rgb + ", " + t.a : "rgb(" + rgb) + ")"; // String
3254 toString: function(){
3255 // summary: returns a visual representation of the color
3256 return this.toCss(true); // String
3260 dojo.blendColors = function(
3261 /*dojo.Color*/ start,
3267 // blend colors end and start with weight from 0 to 1, 0.5 being a 50/50 blend,
3268 // can reuse a previously allocated dojo.Color object for the result
3269 var d = dojo, t = obj || new dojo.Color();
3270 d.forEach(["r", "g", "b", "a"], function(x){
3271 t[x] = start[x] + (end[x] - start[x]) * weight;
3272 if(x != "a"){ t[x] = Math.round(t[x]); }
3274 return t.sanitize(); // dojo.Color
3277 dojo.colorFromRgb = function(/*String*/ color, /*dojo.Color?*/ obj){
3278 // summary: get rgb(a) array from css-style color declarations
3279 var m = color.toLowerCase().match(/^rgba?\(([\s\.,0-9]+)\)/);
3280 return m && dojo.colorFromArray(m[1].split(/\s*,\s*/), obj); // dojo.Color
3283 dojo.colorFromHex = function(/*String*/ color, /*dojo.Color?*/ obj){
3284 // summary: converts a hex string with a '#' prefix to a color object.
3285 // Supports 12-bit #rgb shorthand.
3286 var d = dojo, t = obj || new d.Color(),
3287 bits = (color.length == 4) ? 4 : 8,
3288 mask = (1 << bits) - 1;
3289 color = Number("0x" + color.substr(1));
3291 return null; // dojo.Color
3293 d.forEach(["b", "g", "r"], function(x){
3294 var c = color & mask;
3296 t[x] = bits == 4 ? 17 * c : c;
3299 return t; // dojo.Color
3302 dojo.colorFromArray = function(/*Array*/ a, /*dojo.Color?*/ obj){
3303 // summary: builds a color from 1, 2, 3, or 4 element array
3304 var t = obj || new dojo.Color();
3305 t._set(Number(a[0]), Number(a[1]), Number(a[2]), Number(a[3]));
3306 if(isNaN(t.a)){ t.a = 1; }
3307 return t.sanitize(); // dojo.Color
3310 dojo.colorFromString = function(/*String*/ str, /*dojo.Color?*/ obj){
3312 // parses str for a color value.
3314 // Acceptable input values for str may include arrays of any form
3315 // accepted by dojo.colorFromArray, hex strings such as "#aaaaaa", or
3316 // rgb or rgba strings such as "rgb(133, 200, 16)" or "rgba(10, 10,
3319 // a dojo.Color object. If obj is passed, it will be the return value.
3320 var a = dojo.Color.named[str];
3321 return a && dojo.colorFromArray(a, obj) || dojo.colorFromRgb(str, obj) || dojo.colorFromHex(str, obj);
3326 if(!dojo._hasResource["dojo._base"]){ //_hasResource checks added by build. Do not use _hasResource directly in your code.
3327 dojo._hasResource["dojo._base"] = true;
3328 dojo.provide("dojo._base");
3340 if(!dojo._hasResource["dojo._base.window"]){ //_hasResource checks added by build. Do not use _hasResource directly in your code.
3341 dojo._hasResource["dojo._base.window"] = true;
3342 dojo.provide("dojo._base.window");
3347 // Alias for the current document. 'dojo.doc' can be modified
3348 // for temporary context shifting. Also see dojo.withDoc().
3350 // Refer to dojo.doc rather
3351 // than referring to 'window.document' to ensure your code runs
3352 // correctly in managed contexts.
3354 // | n.appendChild(dojo.doc.createElement('div'));
3357 dojo.doc = window["document"] || null;
3359 dojo.body = function(){
3361 // Return the body element of the document
3362 // return the body object associated with dojo.doc
3364 // | dojo.body().appendChild(dojo.doc.createElement('div'));
3366 // Note: document.body is not defined for a strict xhtml document
3367 // Would like to memoize this, but dojo.doc can change vi dojo.withDoc().
3368 return dojo.doc.body || dojo.doc.getElementsByTagName("body")[0]; // Node
3371 dojo.setContext = function(/*Object*/globalObject, /*DocumentElement*/globalDocument){
3373 // changes the behavior of many core Dojo functions that deal with
3374 // namespace and DOM lookup, changing them to work in a new global
3375 // context (e.g., an iframe). The varibles dojo.global and dojo.doc
3376 // are modified as a result of calling this function and the result of
3377 // `dojo.body()` likewise differs.
3378 dojo.global = globalObject;
3379 dojo.doc = globalDocument;
3382 dojo._fireCallback = function(callback, context, cbArguments){
3383 if(context && dojo.isString(callback)){
3384 callback = context[callback];
3386 return callback.apply(context, cbArguments || [ ]);
3389 dojo.withGlobal = function( /*Object*/globalObject,
3390 /*Function*/callback,
3391 /*Object?*/thisObject,
3392 /*Array?*/cbArguments){
3394 // Call callback with globalObject as dojo.global and
3395 // globalObject.document as dojo.doc. If provided, globalObject
3396 // will be executed in the context of object thisObject
3398 // When callback() returns or throws an error, the dojo.global
3399 // and dojo.doc will be restored to its previous state.
3401 var oldGlob = dojo.global;
3402 var oldDoc = dojo.doc;
3404 dojo.setContext(globalObject, globalObject.document);
3405 rval = dojo._fireCallback(callback, thisObject, cbArguments);
3407 dojo.setContext(oldGlob, oldDoc);
3412 dojo.withDoc = function( /*Object*/documentObject,
3413 /*Function*/callback,
3414 /*Object?*/thisObject,
3415 /*Array?*/cbArguments){
3417 // Call callback with documentObject as dojo.doc. If provided,
3418 // callback will be executed in the context of object thisObject
3420 // When callback() returns or throws an error, the dojo.doc will
3421 // be restored to its previous state.
3423 var oldDoc = dojo.doc;
3425 dojo.doc = documentObject;
3426 rval = dojo._fireCallback(callback, thisObject, cbArguments);
3435 if(!dojo._hasResource["dojo._base.event"]){ //_hasResource checks added by build. Do not use _hasResource directly in your code.
3436 dojo._hasResource["dojo._base.event"] = true;
3437 dojo.provide("dojo._base.event");
3440 // this file courtesy of the TurboAjax Group, licensed under a Dojo CLA
3443 // DOM event listener machinery
3444 var del = (dojo._event_listener = {
3445 add: function(/*DOMNode*/node, /*String*/name, /*Function*/fp){
3447 name = del._normalizeEventName(name);
3448 fp = del._fixCallback(name, fp);
3450 if(!dojo.isIE && (name == "mouseenter" || name == "mouseleave")){
3453 name = (name == "mouseenter") ? "mouseover" : "mouseout";
3455 // check tagName to fix a FF2 bug with invalid nodes (hidden child DIV of INPUT)
3456 // which causes isDecendant to return false which causes
3457 // spurious, and more importantly, incorrect mouse events to fire.
3458 // TODO: remove tagName check when Firefox 2 is no longer supported
3459 try{ e.relatedTarget.tagName; } catch(e2){ return; }
3460 if(!dojo.isDescendant(e.relatedTarget, node)){
3461 // e.type = oname; // FIXME: doesn't take? SJM: event.type is generally immutable.
3462 return ofp.call(this, e);
3466 node.addEventListener(name, fp, false);
3467 return fp; /*Handle*/
3469 remove: function(/*DOMNode*/node, /*String*/event, /*Handle*/handle){
3471 // clobbers the listener from the node
3473 // DOM node to attach the event to
3475 // the name of the handler to remove the function from
3477 // the handle returned from add
3479 event = del._normalizeEventName(event);
3480 if(!dojo.isIE && (event == "mouseenter" || event == "mouseleave")){
3481 event = (event == "mouseenter") ? "mouseover" : "mouseout";
3484 node.removeEventListener(event, handle, false);
3487 _normalizeEventName: function(/*String*/name){
3488 // Generally, name should be lower case, unless it is special
3489 // somehow (e.g. a Mozilla DOM event).
3491 return name.slice(0,2) =="on" ? name.slice(2) : name;
3493 _fixCallback: function(/*String*/name, fp){
3494 // By default, we only invoke _fixEvent for 'keypress'
3495 // If code is added to _fixEvent for other events, we have
3496 // to revisit this optimization.
3497 // This also applies to _fixEvent overrides for Safari and Opera
3499 return name != "keypress" ? fp : function(e){ return fp.call(this, del._fixEvent(e, this)); };
3501 _fixEvent: function(evt, sender){
3502 // _fixCallback only attaches us to keypress.
3503 // Switch on evt.type anyway because we might
3504 // be called directly from dojo.fixEvent.
3507 del._setKeyChar(evt);
3512 _setKeyChar: function(evt){
3513 evt.keyChar = evt.charCode ? String.fromCharCode(evt.charCode) : '';
3514 evt.charOrCode = evt.keyChar || evt.keyCode;
3516 // For IE and Safari: some ctrl-key combinations (mostly w/punctuation) do not emit a char code in IE
3517 // we map those virtual key codes to ascii here
3518 // not valid for all (non-US) keyboards, so maybe we shouldn't bother
3538 dojo.fixEvent = function(/*Event*/evt, /*DOMNode*/sender){
3540 // normalizes properties on the event object including event
3541 // bubbling methods, keystroke normalization, and x/y positions
3543 // native event object
3545 // node to treat as "currentTarget"
3546 return del._fixEvent(evt, sender);
3549 dojo.stopEvent = function(/*Event*/evt){
3551 // prevents propagation and clobbers the default action of the
3554 // The event object. If omitted, window.event is used on IE.
3555 evt.preventDefault();
3556 evt.stopPropagation();
3557 // NOTE: below, this method is overridden for IE
3560 // the default listener to use on dontFix nodes, overriden for IE
3561 var node_listener = dojo._listener;
3563 // Unify connect and event listeners
3564 dojo._connect = function(obj, event, context, method, dontFix){
3565 // FIXME: need a more strict test
3566 var isNode = obj && (obj.nodeType||obj.attachEvent||obj.addEventListener);
3567 // choose one of three listener options: raw (connect.js), DOM event on a Node, custom event on a Node
3568 // we need the third option to provide leak prevention on broken browsers (IE)
3569 var lid = !isNode ? 0 : (!dontFix ? 1 : 2), l = [dojo._listener, del, node_listener][lid];
3570 // create a listener
3571 var h = l.add(obj, event, dojo.hitch(context, method));
3572 // formerly, the disconnect package contained "l" directly, but if client code
3573 // leaks the disconnect package (by connecting it to a node), referencing "l"
3574 // compounds the problem.
3575 // instead we return a listener id, which requires custom _disconnect below.
3576 // return disconnect package
3577 return [ obj, event, h, lid ];
3580 dojo._disconnect = function(obj, event, handle, listener){
3581 ([dojo._listener, del, node_listener][listener]).remove(obj, event, handle);
3586 // Public: client code should test
3587 // keyCode against these named constants, as the
3588 // actual codes can vary by browser.
3590 // summary: definitions for common key values
3626 NUMPAD_MULTIPLY: 106,
3651 // IE event normalization
3653 var _trySetKeyCode = function(e, code){
3655 // squelch errors when keyCode is read-only
3656 // (e.g. if keyCode is ctrl or shift)
3657 return (e.keyCode = code);
3663 // by default, use the standard listener
3664 var iel = dojo._listener;
3665 var listenersName = dojo._ieListenersName = "_" + dojo._scopeName + "_listeners";
3666 // dispatcher tracking property
3667 if(!dojo.config._allow_leaks){
3668 // custom listener that handles leak protection for DOM events
3669 node_listener = iel = dojo._ie_listener = {
3670 // support handler indirection: event handler functions are
3671 // referenced here. Event dispatchers hold only indices.
3673 // add a listener to an object
3674 add: function(/*Object*/ source, /*String*/ method, /*Function*/ listener){
3675 source = source || dojo.global;
3676 var f = source[method];
3677 if(!f||!f[listenersName]){
3678 var d = dojo._getIeDispatcher();
3679 // original target function is special
3680 d.target = f && (ieh.push(f) - 1);
3681 // dispatcher holds a list of indices into handlers table
3682 d[listenersName] = [];
3683 // redirect source to dispatcher
3684 f = source[method] = d;
3686 return f[listenersName].push(ieh.push(listener) - 1) ; /*Handle*/
3688 // remove a listener from an object
3689 remove: function(/*Object*/ source, /*String*/ method, /*Handle*/ handle){
3690 var f = (source||dojo.global)[method], l = f && f[listenersName];
3691 if(f && l && handle--){
3692 delete ieh[l[handle]];
3698 var ieh = iel.handlers;
3702 add: function(/*DOMNode*/node, /*String*/event, /*Function*/fp){
3703 if(!node){return;} // undefined
3704 event = del._normalizeEventName(event);
3705 if(event=="onkeypress"){
3706 // we need to listen to onkeydown to synthesize
3707 // keypress events that otherwise won't fire
3709 var kd = node.onkeydown;
3710 if(!kd || !kd[listenersName] || !kd._stealthKeydownHandle){
3711 var h = del.add(node, "onkeydown", del._stealthKeyDown);
3712 kd = node.onkeydown;
3713 kd._stealthKeydownHandle = h;
3714 kd._stealthKeydownRefs = 1;
3716 kd._stealthKeydownRefs++;
3719 return iel.add(node, event, del._fixCallback(fp));
3721 remove: function(/*DOMNode*/node, /*String*/event, /*Handle*/handle){
3722 event = del._normalizeEventName(event);
3723 iel.remove(node, event, handle);
3724 if(event=="onkeypress"){
3725 var kd = node.onkeydown;
3726 if(--kd._stealthKeydownRefs <= 0){
3727 iel.remove(node, "onkeydown", kd._stealthKeydownHandle);
3728 delete kd._stealthKeydownHandle;
3732 _normalizeEventName: function(/*String*/eventName){
3733 // Generally, eventName should be lower case, unless it is
3734 // special somehow (e.g. a Mozilla event)
3736 return eventName.slice(0,2) != "on" ? "on" + eventName : eventName;
3739 _fixEvent: function(/*Event*/evt, /*DOMNode*/sender){
3741 // normalizes properties on the event object including event
3742 // bubbling methods, keystroke normalization, and x/y positions
3743 // evt: native event object
3744 // sender: node to treat as "currentTarget"
3746 var w = sender && (sender.ownerDocument || sender.document || sender).parentWindow || window;
3749 if(!evt){return(evt);}
3750 evt.target = evt.srcElement;
3751 evt.currentTarget = (sender || evt.srcElement);
3752 evt.layerX = evt.offsetX;
3753 evt.layerY = evt.offsetY;
3754 // FIXME: scroll position query is duped from dojo.html to
3755 // avoid dependency on that entire module. Now that HTML is in
3756 // Base, we should convert back to something similar there.
3757 var se = evt.srcElement, doc = (se && se.ownerDocument) || document;
3758 // DO NOT replace the following to use dojo.body(), in IE, document.documentElement should be used
3759 // here rather than document.body
3760 var docBody = ((dojo.isIE < 6) || (doc["compatMode"] == "BackCompat")) ? doc.body : doc.documentElement;
3761 var offset = dojo._getIeDocumentElementOffset();
3762 evt.pageX = evt.clientX + dojo._fixIeBiDiScrollLeft(docBody.scrollLeft || 0) - offset.x;
3763 evt.pageY = evt.clientY + (docBody.scrollTop || 0) - offset.y;
3764 if(evt.type == "mouseover"){
3765 evt.relatedTarget = evt.fromElement;
3767 if(evt.type == "mouseout"){
3768 evt.relatedTarget = evt.toElement;
3770 evt.stopPropagation = del._stopPropagation;
3771 evt.preventDefault = del._preventDefault;
3772 return del._fixKeys(evt);
3774 _fixKeys: function(evt){
3777 var c = ("charCode" in evt ? evt.charCode : evt.keyCode);
3779 // CTRL-ENTER is CTRL-ASCII(10) on IE, but CTRL-ENTER on Mozilla
3782 }else if(c==13||c==27){
3783 c=0; // Mozilla considers ENTER and ESC non-printable
3785 c=99; // Mozilla maps CTRL-BREAK to CTRL-c
3787 // Mozilla sets keyCode to 0 when there is a charCode
3788 // but that stops the event on IE.
3790 del._setKeyChar(evt);
3795 _stealthKeyDown: function(evt){
3796 // IE doesn't fire keypress for most non-printable characters.
3797 // other browsers do, we simulate it here.
3798 var kp = evt.currentTarget.onkeypress;
3799 // only works if kp exists and is a dispatcher
3800 if(!kp || !kp[listenersName]){ return; }
3801 // munge key/charCode
3803 // These are Windows Virtual Key Codes
3804 // http://msdn.microsoft.com/library/default.asp?url=/library/en-us/winui/WinUI/WindowsUserInterface/UserInput/VirtualKeyCodes.asp
3805 var unprintable = (k!=13)&&(k!=32)&&(k!=27)&&(k<48||k>90)&&(k<96||k>111)&&(k<186||k>192)&&(k<219||k>222);
3806 // synthesize keypress for most unprintables and CTRL-keys
3807 if(unprintable||evt.ctrlKey){
3808 var c = unprintable ? 0 : k;
3811 return; // IE will post CTRL-BREAK, CTRL-ENTER as keypress natively
3812 }else if(c>95 && c<106){
3813 c -= 48; // map CTRL-[numpad 0-9] to ASCII
3814 }else if((!evt.shiftKey)&&(c>=65&&c<=90)){
3815 c += 32; // map CTRL-[A-Z] to lowercase
3817 c = del._punctMap[c] || c; // map other problematic CTRL combinations to ASCII
3820 // simulate a keypress event
3821 var faux = del._synthesizeEvent(evt, {type: 'keypress', faux: true, charCode: c});
3822 kp.call(evt.currentTarget, faux);
3823 evt.cancelBubble = faux.cancelBubble;
3824 evt.returnValue = faux.returnValue;
3825 _trySetKeyCode(evt, faux.keyCode);
3828 // Called in Event scope
3829 _stopPropagation: function(){
3830 this.cancelBubble = true;
3832 _preventDefault: function(){
3833 // Setting keyCode to 0 is the only way to prevent certain keypresses (namely
3834 // ctrl-combinations that correspond to menu accelerator keys).
3835 // Otoh, it prevents upstream listeners from getting this information
3836 // Try to split the difference here by clobbering keyCode only for ctrl
3837 // combinations. If you still need to access the key upstream, bubbledKeyCode is
3838 // provided as a workaround.
3839 this.bubbledKeyCode = this.keyCode;
3840 if(this.ctrlKey){_trySetKeyCode(this, 0);}
3841 this.returnValue = false;
3845 // override stopEvent for IE
3846 dojo.stopEvent = function(evt){
3847 evt = evt || window.event;
3848 del._stopPropagation.call(evt);
3849 del._preventDefault.call(evt);
3853 del._synthesizeEvent = function(evt, props){
3854 var faux = dojo.mixin({}, evt, props);
3855 del._setKeyChar(faux);
3856 // FIXME: would prefer to use dojo.hitch: dojo.hitch(evt, evt.preventDefault);
3857 // but it throws an error when preventDefault is invoked on Safari
3858 // does Event.preventDefault not support "apply" on Safari?
3859 faux.preventDefault = function(){ evt.preventDefault(); };
3860 faux.stopPropagation = function(){ evt.stopPropagation(); };
3864 // Opera event normalization
3867 _fixEvent: function(evt, sender){
3872 c=99; // Mozilla maps CTRL-BREAK to CTRL-c
3874 // can't trap some keys at all, like INSERT and DELETE
3875 // there is no differentiating info between DELETE and ".", or INSERT and "-"
3876 c = ((c<41)&&(!evt.shiftKey) ? 0 : c);
3877 if((evt.ctrlKey)&&(!evt.shiftKey)&&(c>=65)&&(c<=90)){
3878 // lowercase CTRL-[A-Z] keys
3881 return del._synthesizeEvent(evt, { charCode: c });
3888 // Safari event normalization
3891 del._remove = del.remove;
3894 add: function(/*DOMNode*/node, /*String*/event, /*Function*/fp){
3895 if(!node){return;} // undefined
3896 var handle = del._add(node, event, fp);
3897 if(del._normalizeEventName(event) == "keypress"){
3898 // we need to listen to onkeydown to synthesize
3899 // keypress events that otherwise won't fire
3900 // in Safari 3.1+: https://lists.webkit.org/pipermail/webkit-dev/2007-December/002992.html
3901 handle._stealthKeyDownHandle = del._add(node, "keydown", function(evt){
3902 //A variation on the IE _stealthKeydown function
3903 //Synthesize an onkeypress event, but only for unprintable characters.
3905 // These are Windows Virtual Key Codes
3906 // http://msdn.microsoft.com/library/default.asp?url=/library/en-us/winui/WinUI/WindowsUserInterface/UserInput/VirtualKeyCodes.asp
3907 var unprintable = (k!=13)&&(k!=32)&&(k!=27)&&(k<48||k>90)&&(k<96||k>111)&&(k<186||k>192)&&(k<219||k>222);
3908 // synthesize keypress for most unprintables and CTRL-keys
3909 if(unprintable||evt.ctrlKey){
3910 var c = unprintable ? 0 : k;
3913 return; // IE will post CTRL-BREAK, CTRL-ENTER as keypress natively
3914 }else if(c>95 && c<106){
3915 c -= 48; // map CTRL-[numpad 0-9] to ASCII
3916 }else if((!evt.shiftKey)&&(c>=65&&c<=90)){
3917 c += 32; // map CTRL-[A-Z] to lowercase
3919 c = del._punctMap[c] || c; // map other problematic CTRL combinations to ASCII
3922 // simulate a keypress event
3923 var faux = del._synthesizeEvent(evt, {type: 'keypress', faux: true, charCode: c});
3924 fp.call(evt.currentTarget, faux);
3928 return handle; /*Handle*/
3931 remove: function(/*DOMNode*/node, /*String*/event, /*Handle*/handle){
3933 if(handle._stealthKeyDownHandle){
3934 del._remove(node, "keydown", handle._stealthKeyDownHandle);
3936 del._remove(node, event, handle);
3939 _fixEvent: function(evt, sender){
3942 if(evt.faux){ return evt; }
3943 var c = evt.charCode;
3945 return del._synthesizeEvent(evt, {charCode: c, faux: true});
3954 // keep this out of the closure
3955 // closing over 'iel' or 'ieh' b0rks leak prevention
3956 // ls[i] is an index into the master handler array
3957 dojo._ieDispatcher = function(args, sender){
3958 var ap=Array.prototype, h=dojo._ie_listener.handlers, c=args.callee, ls=c[dojo._ieListenersName], t=h[c.target];
3959 // return value comes from original target function
3960 var r = t && t.apply(sender, args);
3961 // make local copy of listener array so it's immutable during processing
3962 var lls = [].concat(ls);
3963 // invoke listeners after target function
3966 h[lls[i]].apply(sender, args);
3971 dojo._getIeDispatcher = function(){
3972 // ensure the returned function closes over nothing ("new Function" apparently doesn't close)
3973 return new Function(dojo._scopeName + "._ieDispatcher(arguments, this)"); // function
3975 // keep this out of the closure to reduce RAM allocation
3976 dojo._event_listener._fixCallback = function(fp){
3977 var f = dojo._event_listener._fixEvent;
3978 return function(e){ return fp.call(this, f(e, this)); };
3984 if(!dojo._hasResource["dojo._base.html"]){ //_hasResource checks added by build. Do not use _hasResource directly in your code.
3985 dojo._hasResource["dojo._base.html"] = true;
3987 dojo.provide("dojo._base.html");
3989 // FIXME: need to add unit tests for all the semi-public methods
3992 document.execCommand("BackgroundImageCache", false, true);
3994 // sane browsers don't have cache "issues"
3997 // =============================
3999 // =============================
4002 dojo.byId = function(id, doc){
4004 // Returns DOM node with matching `id` attribute or `null`
4005 // if not found, similar to "$" function in another library.
4006 // If `id` is a DomNode, this function is a no-op.
4008 // id: String|DOMNode
4009 // A string to match an HTML id attribute or a reference to a DOM Node
4012 // Document to work in. Defaults to the current value of
4013 // dojo.doc. Can be used to retrieve
4014 // node references from other documents.
4016 if(dojo.isIE || dojo.isOpera){
4017 dojo.byId = function(id, doc){
4018 if(dojo.isString(id)){
4019 var _d = doc || dojo.doc;
4020 var te = _d.getElementById(id);
4021 // attributes.id.value is better than just id in case the
4022 // user has a name=id inside a form
4023 if(te && te.attributes.id.value == id){
4026 var eles = _d.all[id];
4027 if(!eles || !eles.length){ return eles; }
4028 // if more than 1, choose first with the correct id
4030 while((te=eles[i++])){
4031 if(te.attributes.id.value == id){ return te; }
4035 return id; // DomNode
4039 dojo.byId = function(id, doc){
4040 return dojo.isString(id) ? (doc || dojo.doc).getElementById(id) : id; // DomNode
4050 var _destroyContainer = null;
4051 dojo.addOnWindowUnload(function(){
4052 _destroyContainer=null; //prevent IE leak
4055 dojo._destroyElement = function(/*String||DomNode*/node){
4057 // removes node from its parent, clobbers it and all of its
4060 // the element to be destroyed, either as an ID or a reference
4062 node = d.byId(node);
4064 if(!_destroyContainer || _destroyContainer.ownerDocument != node.ownerDocument){
4065 _destroyContainer = node.ownerDocument.createElement("div");
4067 _destroyContainer.appendChild(node.parentNode ? node.parentNode.removeChild(node) : node);
4068 // NOTE: see http://trac.dojotoolkit.org/ticket/2931. This may be a bug and not a feature
4069 _destroyContainer.innerHTML = "";
4075 dojo.isDescendant = function(/*DomNode|String*/node, /*DomNode|String*/ancestor){
4077 // Returns true if node is a descendant of ancestor
4078 // node: id or node reference to test
4079 // ancestor: id or node reference of potential parent to test against
4081 node = d.byId(node);
4082 ancestor = d.byId(ancestor);
4084 if(node === ancestor){
4085 return true; // Boolean
4087 node = node.parentNode;
4089 }catch(e){ /* squelch, return false */ }
4090 return false; // Boolean
4093 dojo.setSelectable = function(/*DomNode|String*/node, /*Boolean*/selectable){
4094 // summary: enable or disable selection on a node
4096 // id or reference to node
4098 node = d.byId(node);
4100 node.style.MozUserSelect = selectable ? "" : "none";
4101 }else if(d.isKhtml){
4102 node.style.KhtmlUserSelect = selectable ? "auto" : "none";
4104 var v = (node.unselectable = selectable ? "" : "on");
4105 d.query("*", node).forEach("item.unselectable = '"+v+"'");
4107 //FIXME: else? Opera?
4110 var _insertBefore = function(/*Node*/node, /*Node*/ref){
4111 ref.parentNode.insertBefore(node, ref);
4112 return true; // boolean
4115 var _insertAfter = function(/*Node*/node, /*Node*/ref){
4117 // Try to insert node after ref
4118 var pn = ref.parentNode;
4119 if(ref == pn.lastChild){
4120 pn.appendChild(node);
4122 return _insertBefore(node, ref.nextSibling); // boolean
4124 return true; // boolean
4127 dojo.place = function(/*String|DomNode*/node, /*String|DomNode*/refNode, /*String?|Number?*/position){
4129 // Attempt to insert node into the DOM, choosing from various positioning options.
4130 // Returns true if successful, false otherwise.
4132 // id or node reference to place relative to refNode
4134 // id or node reference to use as basis for placement
4136 // string noting the position of node relative to refNode or a
4137 // number indicating the location in the childNodes collection of refNode.
4138 // Accepted string values are:
4144 // "first" and "last" indicate positions as children of refNode. position defaults
4145 // to "last" if not specified
4147 // FIXME: need to write tests for this!!!!
4148 if(!node || !refNode){
4149 return false; // boolean
4151 node = d.byId(node);
4152 refNode = d.byId(refNode);
4153 if(typeof position == "number"){
4154 var cn = refNode.childNodes;
4155 if(!cn.length || cn.length <= position){
4156 refNode.appendChild(node);
4159 return _insertBefore(node, position <= 0 ? refNode.firstChild : cn[position]);
4163 return _insertBefore(node, refNode); // boolean
4165 return _insertAfter(node, refNode); // boolean
4167 if(refNode.firstChild){
4168 return _insertBefore(node, refNode.firstChild); // boolean
4170 // else fallthrough...
4171 default: // aka: last
4172 refNode.appendChild(node);
4173 return true; // boolean
4177 // Box functions will assume this model.
4178 // On IE/Opera, BORDER_BOX will be set if the primary document is in quirks mode.
4179 // Can be set to change behavior of box setters.
4183 // "content-box" (default)
4184 dojo.boxModel = "content-box";
4186 // We punt per-node box mode testing completely.
4187 // If anybody cares, we can provide an additional (optional) unit
4188 // that overrides existing code to include per-node box sensitivity.
4190 // Opera documentation claims that Opera 9 uses border-box in BackCompat mode.
4191 // but experiments (Opera 9.10.8679 on Windows Vista) indicate that it actually continues to use content-box.
4192 // IIRC, earlier versions of Opera did in fact use border-box.
4193 // Opera guys, this is really confusing. Opera being broken in quirks mode is not our fault.
4195 if(d.isIE /*|| dojo.isOpera*/){
4196 var _dcm = document.compatMode;
4197 // client code may have to adjust if compatMode varies across iframes
4198 d.boxModel = _dcm == "BackCompat" || _dcm == "QuirksMode" || d.isIE<6 ? "border-box" : "content-box"; // FIXME: remove IE < 6 support?
4201 // =============================
4203 // =============================
4205 // getComputedStyle drives most of the style code.
4206 // Wherever possible, reuse the returned object.
4208 // API functions below that need to access computed styles accept an
4209 // optional computedStyle parameter.
4210 // If this parameter is omitted, the functions will call getComputedStyle themselves.
4211 // This way, calling code can access computedStyle once, and then pass the reference to
4212 // multiple API functions.
4215 dojo.getComputedStyle = function(node){
4217 // Returns a "computed style" object.
4220 // Gets a "computed style" object which can be used to gather
4221 // information about the current state of the rendered node.
4223 // Note that this may behave differently on different browsers.
4224 // Values may have different formats and value encodings across
4227 // Note also that this method is expensive. Wherever possible,
4228 // reuse the returned object.
4230 // Use the dojo.style() method for more consistent (pixelized)
4234 // A reference to a DOM node. Does NOT support taking an
4235 // ID string for speed reasons.
4237 // | dojo.getComputedStyle(dojo.byId('foo')).borderWidth;
4238 return; // CSS2Properties
4242 // Although we normally eschew argument validation at this
4243 // level, here we test argument 'node' for (duck)type.
4244 // Argument node must also implement Element. (Note: we check
4245 // against HTMLElement rather than Element for interop with prototype.js)
4246 // Because 'document' is the 'parentNode' of 'body'
4247 // it is frequently sent to this function even
4248 // though it is not Element.
4251 gcs = function(/*DomNode*/node){
4253 if(node instanceof HTMLElement){
4254 var dv = node.ownerDocument.defaultView;
4255 s = dv.getComputedStyle(node, null);
4256 if(!s && node.style){
4257 node.style.display = "";
4258 s = dv.getComputedStyle(node, null);
4264 gcs = function(node){
4265 // IE (as of 7) doesn't expose Element like sane browsers
4266 return node.nodeType == 1 /* ELEMENT_NODE*/ ? node.currentStyle : {};
4269 gcs = function(node){
4270 return node instanceof HTMLElement ?
4271 node.ownerDocument.defaultView.getComputedStyle(node, null) : {};
4274 dojo.getComputedStyle = gcs;
4277 dojo._toPixelValue = function(element, value){
4278 // style values can be floats, client code may want
4279 // to round for integer pixels.
4280 return parseFloat(value) || 0;
4283 dojo._toPixelValue = function(element, avalue){
4284 if(!avalue){ return 0; }
4285 // on IE7, medium is usually 4 pixels
4286 if(avalue=="medium"){ return 4; }
4287 // style values can be floats, client code may
4288 // want to round this value for integer pixels.
4289 if(avalue.slice && (avalue.slice(-2)=='px')){ return parseFloat(avalue); }
4291 var sLeft = style.left;
4292 var rsLeft = runtimeStyle.left;
4293 runtimeStyle.left = currentStyle.left;
4295 // 'avalue' may be incompatible with style.left, which can cause IE to throw
4296 // this has been observed for border widths using "thin", "medium", "thick" constants
4297 // those particular constants could be trapped by a lookup
4298 // but perhaps there are more
4299 style.left = avalue;
4300 avalue = style.pixelLeft;
4305 runtimeStyle.left = rsLeft;
4310 var px = d._toPixelValue;
4312 // FIXME: there opacity quirks on FF that we haven't ported over. Hrm.
4314 dojo._getOpacity = function(node){
4316 // Returns the current opacity of the passed node as a
4317 // floating-point value between 0 and 1.
4319 // a reference to a DOM node. Does NOT support taking an
4320 // ID string for speed reasons.
4321 // returns: Number between 0 and 1
4326 var astr = "DXImageTransform.Microsoft.Alpha";
4327 var af = function(n, f){
4329 return n.filters.item(astr);
4331 return f ? {} : null;
4335 dojo._getOpacity = d.isIE ? function(node){
4337 return af(node).Opacity / 100; // Number
4342 return gcs(node).opacity;
4346 dojo._setOpacity = function(node, opacity){
4348 // set the opacity of the passed node portably. Returns the
4349 // new opacity of the node.
4351 // a reference to a DOM node. Does NOT support taking an
4352 // ID string for performance reasons.
4354 // A Number between 0 and 1. 0 specifies transparent.
4355 // returns: Number between 0 and 1
4360 dojo._setOpacity = d.isIE ? function(/*DomNode*/node, /*Number*/opacity){
4361 var ov = opacity * 100;
4362 node.style.zoom = 1.0;
4364 // on IE7 Alpha(Filter opacity=100) makes text look fuzzy so disable it altogether (bug #2661),
4365 //but still update the opacity value so we can get a correct reading if it is read later.
4366 af(node, 1).Enabled = (opacity == 1 ? false : true);
4369 node.style.filter += " progid:"+astr+"(Opacity="+ov+")";
4371 af(node, 1).Opacity = ov;
4374 if(node.nodeName.toLowerCase() == "tr"){
4375 d.query("> td", node).forEach(function(i){
4376 d._setOpacity(i, opacity);
4380 } : function(node, opacity){
4381 return node.style.opacity = opacity;
4384 var _pixelNamesCache = {
4385 left: true, top: true
4387 var _pixelRegExp = /margin|padding|width|height|max|min|offset/; // |border
4388 var _toStyleValue = function(node, type, value){
4389 type = type.toLowerCase(); // FIXME: should we really be doing string case conversion here? Should we cache it? Need to profile!
4391 if(value == "auto"){
4392 if(type == "height"){ return node.offsetHeight; }
4393 if(type == "width"){ return node.offsetWidth; }
4395 if(type == "fontweight"){
4397 case 700: return "bold";
4399 default: return "normal";
4403 if(!(type in _pixelNamesCache)){
4404 _pixelNamesCache[type] = _pixelRegExp.test(type);
4406 return _pixelNamesCache[type] ? px(node, value) : value;
4409 var _floatStyle = d.isIE ? "styleFloat" : "cssFloat";
4410 var _floatAliases = { "cssFloat": _floatStyle, "styleFloat": _floatStyle, "float": _floatStyle };
4414 dojo.style = function( /*DomNode|String*/ node,
4415 /*String?|Object?*/ style,
4418 // Accesses styles on a node. If 2 arguments are
4419 // passed, acts as a getter. If 3 arguments are passed, acts
4422 // id or reference to node to get/set style for
4424 // the style property to set in DOM-accessor format
4425 // ("borderWidth", not "border-width") or an object with key/value
4426 // pairs suitable for setting each property.
4428 // If passed, sets value on the node for style, handling
4429 // cross-browser concerns.
4431 // Passing only an ID or node returns the computed style object of
4433 // | dojo.style("thinger");
4435 // Passing a node and a style property returns the current
4436 // normalized, computed value for that property:
4437 // | dojo.style("thinger", "opacity"); // 1 by default
4440 // Passing a node, a style property, and a value changes the
4441 // current display of the node and returns the new computed value
4442 // | dojo.style("thinger", "opacity", 0.5); // == 0.5
4445 // Passing a node, an object-style style property sets each of the values in turn and returns the computed style object of the node:
4446 // | dojo.style("thinger", {
4447 // | "opacity": 0.5,
4448 // | "border": "3px solid black",
4453 // When the CSS style property is hyphenated, the JavaScript property is camelCased.
4454 // font-size becomes fontSize, and so on.
4455 // | dojo.style("thinger",{
4456 // | fontSize:"14pt",
4457 // | letterSpacing:"1.2em"
4461 // dojo.NodeList implements .style() using the same syntax, omitting the "node" parameter, calling
4462 // dojo.style() on every element of the list. See: dojo.query and dojo.NodeList
4463 // | dojo.query(".someClassName").style("visibility","hidden");
4465 // | dojo.query("#baz > div").style({
4467 // | fontSize:"13pt"
4470 var n = d.byId(node), args = arguments.length, op = (style=="opacity");
4471 style = _floatAliases[style] || style;
4473 return op ? d._setOpacity(n, value) : n.style[style] = value; /*Number*/
4475 if(args == 2 && op){
4476 return d._getOpacity(n);
4479 if(args == 2 && !d.isString(style)){
4480 for(var x in style){
4481 d.style(node, x, style[x]);
4485 return (args == 1) ? s : _toStyleValue(n, style, s[style]||n.style[style]); /* CSS2Properties||String||Number */
4488 // =============================
4490 // =============================
4492 dojo._getPadExtents = function(/*DomNode*/n, /*Object*/computedStyle){
4494 // Returns object with special values specifically useful for node
4497 // * l/t = left/top padding (respectively)
4498 // * w = the total of the left and right padding
4499 // * h = the total of the top and bottom padding
4501 // If 'node' has position, l/t forms the origin for child nodes.
4502 // The w/h are used for calculating boxes.
4503 // Normally application code will not need to invoke this
4504 // directly, and will use the ...box... functions instead.
4506 s = computedStyle||gcs(n),
4507 l = px(n, s.paddingLeft),
4508 t = px(n, s.paddingTop);
4512 w: l+px(n, s.paddingRight),
4513 h: t+px(n, s.paddingBottom)
4517 dojo._getBorderExtents = function(/*DomNode*/n, /*Object*/computedStyle){
4519 // returns an object with properties useful for noting the border
4522 // * l/t = the sum of left/top border (respectively)
4523 // * w = the sum of the left and right border
4524 // * h = the sum of the top and bottom border
4526 // The w/h are used for calculating boxes.
4527 // Normally application code will not need to invoke this
4528 // directly, and will use the ...box... functions instead.
4531 s = computedStyle||gcs(n),
4532 bl = (s.borderLeftStyle != ne ? px(n, s.borderLeftWidth) : 0),
4533 bt = (s.borderTopStyle != ne ? px(n, s.borderTopWidth) : 0);
4537 w: bl + (s.borderRightStyle!=ne ? px(n, s.borderRightWidth) : 0),
4538 h: bt + (s.borderBottomStyle!=ne ? px(n, s.borderBottomWidth) : 0)
4542 dojo._getPadBorderExtents = function(/*DomNode*/n, /*Object*/computedStyle){
4544 // returns object with properties useful for box fitting with
4545 // regards to padding.
4547 // * l/t = the sum of left/top padding and left/top border (respectively)
4548 // * w = the sum of the left and right padding and border
4549 // * h = the sum of the top and bottom padding and border
4551 // The w/h are used for calculating boxes.
4552 // Normally application code will not need to invoke this
4553 // directly, and will use the ...box... functions instead.
4555 s = computedStyle||gcs(n),
4556 p = d._getPadExtents(n, s),
4557 b = d._getBorderExtents(n, s);
4566 dojo._getMarginExtents = function(n, computedStyle){
4568 // returns object with properties useful for box fitting with
4569 // regards to box margins (i.e., the outer-box).
4571 // * l/t = marginLeft, marginTop, respectively
4572 // * w = total width, margin inclusive
4573 // * h = total height, margin inclusive
4575 // The w/h are used for calculating boxes.
4576 // Normally application code will not need to invoke this
4577 // directly, and will use the ...box... functions instead.
4579 s = computedStyle||gcs(n),
4580 l = px(n, s.marginLeft),
4581 t = px(n, s.marginTop),
4582 r = px(n, s.marginRight),
4583 b = px(n, s.marginBottom);
4584 if(d.isSafari && (s.position != "absolute")){
4585 // FIXME: Safari's version of the computed right margin
4586 // is the space between our right edge and the right edge
4587 // of our offsetParent.
4588 // What we are looking for is the actual margin value as
4589 // determined by CSS.
4590 // Hack solution is to assume left/right margins are the same.
4601 // Box getters work in any box context because offsetWidth/clientWidth
4602 // are invariant wrt box context
4604 // They do *not* work for display: inline objects that have padding styles
4605 // because the user agent ignores padding (it's bogus styling in any case)
4607 // Be careful with IMGs because they are inline or block depending on
4608 // browser and browser mode.
4610 // Although it would be easier to read, there are not separate versions of
4611 // _getMarginBox for each browser because:
4612 // 1. the branching is not expensive
4613 // 2. factoring the shared code wastes cycles (function call overhead)
4614 // 3. duplicating the shared code wastes bytes
4616 dojo._getMarginBox = function(/*DomNode*/node, /*Object*/computedStyle){
4618 // returns an object that encodes the width, height, left and top
4619 // positions of the node's margin box.
4620 var s = computedStyle||gcs(node), me = d._getMarginExtents(node, s);
4621 var l = node.offsetLeft - me.l, t = node.offsetTop - me.t, p = node.parentNode;
4624 // If offsetParent has a computed overflow != visible, the offsetLeft is decreased
4625 // by the parent's border.
4626 // We don't want to compute the parent's style, so instead we examine node's
4627 // computed left/top which is more stable.
4628 var sl = parseFloat(s.left), st = parseFloat(s.top);
4629 if(!isNaN(sl) && !isNaN(st)){
4632 // If child's computed left/top are not parseable as a number (e.g. "auto"), we
4633 // have no choice but to examine the parent's computed style.
4636 if(pcs.overflow != "visible"){
4637 var be = d._getBorderExtents(p, pcs);
4638 l += be.l, t += be.t;
4642 }else if(d.isOpera){
4643 // On Opera, offsetLeft includes the parent's border
4645 var be = d._getBorderExtents(p);
4653 w: node.offsetWidth + me.w,
4654 h: node.offsetHeight + me.h
4658 dojo._getContentBox = function(node, computedStyle){
4660 // Returns an object that encodes the width, height, left and top
4661 // positions of the node's content box, irrespective of the
4662 // current box model.
4664 // clientWidth/Height are important since the automatically account for scrollbars
4665 // fallback to offsetWidth/Height for special cases (see #3378)
4666 var s=computedStyle||gcs(node), pe=d._getPadExtents(node, s), be=d._getBorderExtents(node, s), w=node.clientWidth, h;
4668 w=node.offsetWidth, h=node.offsetHeight;
4670 h=node.clientHeight, be.w = be.h = 0;
4672 // On Opera, offsetLeft includes the parent's border
4673 if(d.isOpera){ pe.l += be.l; pe.t += be.t; };
4682 dojo._getBorderBox = function(node, computedStyle){
4683 var s=computedStyle||gcs(node), pe=d._getPadExtents(node, s), cb=d._getContentBox(node, s);
4692 // Box setters depend on box context because interpretation of width/height styles
4693 // vary wrt box context.
4695 // The value of dojo.boxModel is used to determine box context.
4696 // dojo.boxModel can be set directly to change behavior.
4698 // Beware of display: inline objects that have padding styles
4699 // because the user agent ignores padding (it's a bogus setup anyway)
4701 // Be careful with IMGs because they are inline or block depending on
4702 // browser and browser mode.
4704 // Elements other than DIV may have special quirks, like built-in
4705 // margins or padding, or values not detectable via computedStyle.
4706 // In particular, margins on TABLE do not seems to appear
4707 // at all in computedStyle on Mozilla.
4709 dojo._setBox = function(/*DomNode*/node, /*Number?*/l, /*Number?*/t, /*Number?*/w, /*Number?*/h, /*String?*/u){
4711 // sets width/height/left/top in the current (native) box-model
4712 // dimentions. Uses the unit passed in u.
4713 // node: DOM Node reference. Id string not supported for performance reasons.
4714 // l: optional. left offset from parent.
4715 // t: optional. top offset from parent.
4716 // w: optional. width in current box model.
4717 // h: optional. width in current box model.
4718 // u: optional. unit measure to use for other measures. Defaults to "px".
4721 if(!isNaN(l)){ s.left = l+u; }
4722 if(!isNaN(t)){ s.top = t+u; }
4723 if(w>=0){ s.width = w+u; }
4724 if(h>=0){ s.height = h+u; }
4727 dojo._isButtonTag = function(/*DomNode*/node) {
4729 // True if the node is BUTTON or INPUT.type="button".
4730 return node.tagName == "BUTTON"
4731 || node.tagName=="INPUT" && node.getAttribute("type").toUpperCase() == "BUTTON"; // boolean
4734 dojo._usesBorderBox = function(/*DomNode*/node){
4736 // True if the node uses border-box layout.
4738 // We could test the computed style of node to see if a particular box
4739 // has been specified, but there are details and we choose not to bother.
4741 // TABLE and BUTTON (and INPUT type=button) are always border-box by default.
4742 // If you have assigned a different box to either one via CSS then
4743 // box functions will break.
4745 var n = node.tagName;
4746 return d.boxModel=="border-box" || n=="TABLE" || dojo._isButtonTag(node); // boolean
4749 dojo._setContentSize = function(/*DomNode*/node, /*Number*/widthPx, /*Number*/heightPx, /*Object*/computedStyle){
4751 // Sets the size of the node's contents, irrespective of margins,
4752 // padding, or borders.
4753 if(d._usesBorderBox(node)){
4754 var pb = d._getPadBorderExtents(node, computedStyle);
4755 if(widthPx >= 0){ widthPx += pb.w; }
4756 if(heightPx >= 0){ heightPx += pb.h; }
4758 d._setBox(node, NaN, NaN, widthPx, heightPx);
4761 dojo._setMarginBox = function(/*DomNode*/node, /*Number?*/leftPx, /*Number?*/topPx,
4762 /*Number?*/widthPx, /*Number?*/heightPx,
4763 /*Object*/computedStyle){
4765 // sets the size of the node's margin box and placement
4766 // (left/top), irrespective of box model. Think of it as a
4767 // passthrough to dojo._setBox that handles box-model vagaries for
4770 var s = computedStyle||gcs(node);
4771 // Some elements have special padding, margin, and box-model settings.
4772 // To use box functions you may need to set padding, margin explicitly.
4773 // Controlling box-model is harder, in a pinch you might set dojo.boxModel.
4774 var bb=d._usesBorderBox(node),
4775 pb=bb ? _nilExtents : d._getPadBorderExtents(node, s);
4776 if (dojo.isSafari) {
4777 // on Safari (3.1.2), button nodes with no explicit size have a default margin
4778 // setting an explicit size eliminates the margin.
4779 // We have to swizzle the width to get correct margin reading.
4780 if (dojo._isButtonTag(node)){
4781 var ns = node.style;
4782 if (widthPx>=0 && !ns.width) { ns.width = "4px"; }
4783 if (heightPx>=0 && !ns.height) { ns.height = "4px"; }
4786 var mb=d._getMarginExtents(node, s);
4787 if(widthPx>=0){ widthPx = Math.max(widthPx - pb.w - mb.w, 0); }
4788 if(heightPx>=0){ heightPx = Math.max(heightPx - pb.h - mb.h, 0); }
4789 d._setBox(node, leftPx, topPx, widthPx, heightPx);
4792 var _nilExtents = { l:0, t:0, w:0, h:0 };
4796 dojo.marginBox = function(/*DomNode|String*/node, /*Object?*/box){
4798 // Getter/setter for the margin-box of node.
4800 // Returns an object in the expected format of box (regardless
4801 // if box is passed). The object might look like:
4802 // `{ l: 50, t: 200, w: 300: h: 150 }`
4803 // for a node offset from its parent 50px to the left, 200px from
4804 // the top with a margin width of 300px and a margin-height of
4807 // id or reference to DOM Node to get/set box for
4809 // If passed, denotes that dojo.marginBox() should
4810 // update/set the margin box for node. Box is an object in the
4811 // above format. All properties are optional if passed.
4812 var n=d.byId(node), s=gcs(n), b=box;
4813 return !b ? d._getMarginBox(n, s) : d._setMarginBox(n, b.l, b.t, b.w, b.h, s); // Object
4816 dojo.contentBox = function(/*DomNode|String*/node, /*Object?*/box){
4818 // Getter/setter for the content-box of node.
4820 // Returns an object in the expected format of box (regardless if box is passed).
4821 // The object might look like:
4822 // `{ l: 50, t: 200, w: 300: h: 150 }`
4823 // for a node offset from its parent 50px to the left, 200px from
4824 // the top with a content width of 300px and a content-height of
4825 // 150px. Note that the content box may have a much larger border
4826 // or margin box, depending on the box model currently in use and
4827 // CSS values set/inherited for node.
4829 // id or reference to DOM Node to get/set box for
4831 // If passed, denotes that dojo.contentBox() should
4832 // update/set the content box for node. Box is an object in the
4833 // above format. All properties are optional if passed.
4834 var n=d.byId(node), s=gcs(n), b=box;
4835 return !b ? d._getContentBox(n, s) : d._setContentSize(n, b.w, b.h, s); // Object
4838 // =============================
4840 // =============================
4842 var _sumAncestorProperties = function(node, prop){
4843 if(!(node = (node||0).parentNode)){return 0};
4844 var val, retVal = 0, _b = d.body();
4845 while(node && node.style){
4846 if(gcs(node).position == "fixed"){
4852 // opera and khtml #body & #html has the same values, we only
4854 if(node == _b){ break; }
4856 node = node.parentNode;
4858 return retVal; // integer
4861 dojo._docScroll = function(){
4865 de = d.doc.documentElement;
4867 y: (_w.pageYOffset || de.scrollTop || _b.scrollTop || 0),
4868 x: (_w.pageXOffset || d._fixIeBiDiScrollLeft(de.scrollLeft) || _b.scrollLeft || 0)
4872 dojo._isBodyLtr = function(){
4873 //FIXME: could check html and body tags directly instead of computed style? need to ignore case, accept empty values
4874 return !("_bodyLtr" in d) ?
4875 d._bodyLtr = gcs(d.body()).direction == "ltr" :
4876 d._bodyLtr; // Boolean
4879 dojo._getIeDocumentElementOffset = function(){
4881 // The following values in IE contain an offset:
4884 // node.getBoundingClientRect().left
4885 // node.getBoundingClientRect().top
4886 // But other position related values do not contain this offset, such as
4887 // node.offsetLeft, node.offsetTop, node.style.left and node.style.top.
4888 // The offset is always (2, 2) in LTR direction. When the body is in RTL
4889 // direction, the offset counts the width of left scroll bar's width.
4890 // This function computes the actual offset.
4892 //NOTE: assumes we're being called in an IE browser
4894 var de = d.doc.documentElement;
4895 //FIXME: use this instead? var de = d.compatMode == "BackCompat" ? d.body : d.documentElement;
4897 return (d.isIE >= 7) ?
4898 {x: de.getBoundingClientRect().left, y: de.getBoundingClientRect().top}
4901 {x: d._isBodyLtr() || window.parent == window ?
4902 de.clientLeft : de.offsetWidth - de.clientWidth - de.clientLeft,
4903 y: de.clientTop}; // Object
4906 dojo._fixIeBiDiScrollLeft = function(/*Integer*/ scrollLeft){
4907 // In RTL direction, scrollLeft should be a negative value, but IE
4908 // returns a positive one. All codes using documentElement.scrollLeft
4909 // must call this function to fix this error, otherwise the position
4910 // will offset to right when there is a horizontal scrollbar.
4912 if(d.isIE && !dojo._isBodyLtr()){
4913 var de = dd.compatMode == "BackCompat" ? dd.body : dd.documentElement;
4914 return scrollLeft + de.clientWidth - de.scrollWidth; // Integer
4916 return scrollLeft; // Integer
4919 dojo._abs = function(/*DomNode*/node, /*Boolean?*/includeScroll){
4921 // Gets the position of the passed element relative to
4922 // the viewport (if includeScroll==false), or relative to the
4923 // document root (if includeScroll==true).
4925 // Returns an object of the form:
4926 // { x: 100, y: 300 }
4927 // if includeScroll is passed, the x and y values will include any
4928 // document offsets that may affect the position relative to the
4931 // FIXME: need to decide in the brave-new-world if we're going to be
4932 // margin-box or border-box.
4933 var ownerDocument = node.ownerDocument;
4939 // targetBoxType == "border-box"
4941 if(d.isIE || (d.isFF >= 3)){
4942 var client = node.getBoundingClientRect();
4945 // in FF3 you have to subract the document element margins
4946 var dv = node.ownerDocument.defaultView;
4947 cs=dv.getComputedStyle(db.parentNode, null);
4949 var offset = (d.isIE) ? d._getIeDocumentElementOffset() : { x: px(db.parentNode,cs.marginLeft), y: px(db.parentNode,cs.marginTop)};
4950 ret.x = client.left - offset.x;
4951 ret.y = client.top - offset.y;
4953 if(node["offsetParent"]){
4955 // in Safari, if the node is an absolutely positioned child of
4956 // the body and the body has a margin the offset of the child
4957 // and the body contain the body's margins, so we need to end
4959 // FIXME: getting contrary results to the above in latest WebKit.
4961 //(node.style.getPropertyValue("position") == "absolute") &&
4962 (gcs(node).position == "absolute") &&
4963 (node.parentNode == db)){
4966 endNode = db.parentNode;
4968 // Opera seems to be double counting for some elements
4971 if(d.isOpera&&cs.position!="absolute"){
4974 ret.x -= _sumAncestorProperties(n, "scrollLeft");
4975 ret.y -= _sumAncestorProperties(n, "scrollTop");
4979 var n = curnode.offsetLeft;
4980 //FIXME: ugly hack to workaround the submenu in
4981 //popupmenu2 does not shown up correctly in opera.
4982 //Someone have a better workaround?
4983 if(!d.isOpera || n > 0){
4984 ret.x += isNaN(n) ? 0 : n;
4986 var t = curnode.offsetTop;
4987 ret.y += isNaN(t) ? 0 : t;
4988 var cs = gcs(curnode);
4989 if(curnode != node){
4991 ret.x += px(curnode, cs.borderLeftWidth);
4992 ret.y += px(curnode, cs.borderTopWidth);
4994 // tried left+right with differently sized left/right borders
4995 // it really is 2xleft border in FF, not left+right, even in RTL!
4996 ret.x += 2*px(curnode,cs.borderLeftWidth);
4997 ret.y += 2*px(curnode,cs.borderTopWidth);
5000 // static children in a static div in FF2 are affected by the div's border as well
5001 // but offsetParent will skip this div!
5002 if(d.isFF&&cs.position=="static"){
5003 var parent=curnode.parentNode;
5004 while(parent!=curnode.offsetParent){
5005 var pcs=gcs(parent);
5006 if(pcs.position=="static"){
5007 ret.x += px(curnode,pcs.borderLeftWidth);
5008 ret.y += px(curnode,pcs.borderTopWidth);
5010 parent=parent.parentNode;
5013 curnode = curnode.offsetParent;
5014 }while((curnode != endNode) && curnode);
5015 }else if(node.x && node.y){
5016 ret.x += isNaN(node.x) ? 0 : node.x;
5017 ret.y += isNaN(node.y) ? 0 : node.y;
5020 // account for document scrolling
5021 // if offsetParent is used, ret value already includes scroll position
5022 // so we may have to actually remove that value if !includeScroll
5024 var scroll = d._docScroll();
5029 return ret; // object
5032 // FIXME: need a setter for coords or a moveTo!!
5033 dojo.coords = function(/*DomNode|String*/node, /*Boolean?*/includeScroll){
5035 // Returns an object that measures margin box width/height and
5036 // absolute positioning data from dojo._abs().
5039 // Returns an object that measures margin box width/height and
5040 // absolute positioning data from dojo._abs().
5041 // Return value will be in the form:
5042 // `{ l: 50, t: 200, w: 300: h: 150, x: 100, y: 300 }`
5043 // Does not act as a setter. If includeScroll is passed, the x and
5044 // y params are affected as one would expect in dojo._abs().
5045 var n=d.byId(node), s=gcs(n), mb=d._getMarginBox(n, s);
5046 var abs = d._abs(n, includeScroll);
5052 // =============================
5053 // Element attribute Functions
5054 // =============================
5056 var ieLT8 = d.isIE < 8;
5058 var _fixAttrName = function(/*String*/name){
5059 switch(name.toLowerCase()){
5061 // Internet Explorer will only set or remove tabindex
5062 // if it is spelled "tabIndex"
5064 return ieLT8 ? "tabIndex" : "tabindex";
5065 case "for": case "htmlfor":
5066 // to pick up for attrib set in markup via getAttribute() IE<8 uses "htmlFor" and others use "for"
5067 // get/setAttribute works in all as long use same value for both get/set
5068 return ieLT8 ? "htmlFor" : "for";
5070 return d.isIE ? "className" : "class";
5076 // non-deprecated HTML4 attributes with default values
5077 // http://www.w3.org/TR/html401/index/attributes.html
5078 // FF and Safari will return the default values if you
5079 // access the attributes via a property but not
5080 // via getAttribute()
5084 frameborder: "frameborder",
5087 scrolling: "scrolling",
5091 valuetype: "valueType"
5094 dojo.hasAttr = function(/*DomNode|String*/node, /*String*/name){
5096 // Returns true if the requested attribute is specified on the
5097 // given element, and false otherwise.
5099 // id or reference to the element to check
5101 // the name of the attribute
5103 // true if the requested attribute is specified on the
5104 // given element, and false otherwise
5105 node = d.byId(node);
5106 var fixName = _fixAttrName(name);
5107 fixName = fixName == "htmlFor" ? "for" : fixName; //IE<8 uses htmlFor except in this case
5108 var attr = node.getAttributeNode && node.getAttributeNode(fixName);
5109 return attr ? attr.specified : false; // Boolean
5117 var _attrId = dojo._scopeName + "attrid";
5119 dojo.attr = function(/*DomNode|String*/node, /*String|Object*/name, /*String?*/value){
5121 // Gets or sets an attribute on an HTML element.
5123 // Handles normalized getting and setting of attributes on DOM
5124 // Nodes. If 2 arguments are passed, and a the second argumnt is a
5125 // string, acts as a getter.
5127 // If a third argument is passed, or if the second argumnt is a
5128 // map of attributes, acts as a setter.
5130 // When passing functions as values, note that they will not be
5131 // directly assigned to slots on the node, but rather the default
5132 // behavior will be removed and the new behavior will be added
5133 // using `dojo.connect()`, meaning that event handler properties
5134 // will be normalized and that some caveats with regards to
5135 // non-standard behaviors for onsubmit apply. Namely that you
5136 // should cancel form submission using `dojo.stopEvent()` on the
5137 // passed event object instead of returning a boolean value from
5138 // the handler itself.
5140 // id or reference to the element to get or set the attribute on
5142 // the name of the attribute to get or set.
5144 // The value to set for the attribute
5146 // when used as a getter, the value of the requested attribute
5147 // or null if that attribute does not have a specified or
5150 // when user as a setter, undefined
5153 // | // get the current value of the "foo" attribute on a node
5154 // | dojo.attr(dojo.byId("nodeId"), "foo");
5155 // | // or we can just pass the id:
5156 // | dojo.attr("nodeId", "foo");
5159 // | // use attr() to set the tab index
5160 // | dojo.attr("nodeId", "tabindex", 3);
5164 // | // set multiple values at once, including event handlers:
5165 // | dojo.attr("formId", {
5167 // | "tabindex": -1,
5168 // | "method": "POST",
5169 // | "onsubmit": function(e){
5170 // | // stop submitting the form. Note that the IE behavior
5171 // | // of returning true or false will have no effect here
5172 // | // since our handler is connect()ed to the built-in
5173 // | // onsubmit behavior and so we need to use
5174 // | // dojo.stopEvent() to ensure that the submission
5175 // | // doesn't proceed.
5176 // | dojo.stopEvent(e);
5178 // | // submit the form with Ajax
5179 // | dojo.xhrPost({ form: "formId" });
5183 var args = arguments.length;
5184 if(args == 2 && !d.isString(name)){
5185 for(var x in name){ d.attr(node, x, name[x]); }
5188 node = d.byId(node);
5189 name = _fixAttrName(name);
5192 // what about when the name is "style" and value is an object?
5193 // It seems natural to pass it in to dojo.style(node,
5194 // value)...should we support this?
5195 if(d.isFunction(value)){
5196 // clobber if we can
5197 var attrId = d.attr(node, _attrId);
5200 d.attr(node, _attrId, attrId);
5202 if(!_evtHdlrMap[attrId]){
5203 _evtHdlrMap[attrId] = {};
5205 var h = _evtHdlrMap[attrId][name];
5214 // ensure that event objects are normalized, etc.
5215 _evtHdlrMap[attrId][name] = d.connect(node, name, value);
5218 (typeof value == "boolean")|| // e.g. onsubmit, disabled
5219 (name == "innerHTML")
5222 }else if((name == "style")&&(!d.isString(value))){
5223 d.style(node, value);
5225 node.setAttribute(name, value);
5229 // should we access this attribute via a property or
5230 // via getAttribute()?
5231 var prop = _attrProps[name.toLowerCase()];
5235 var attrValue = node[name];
5236 return (typeof attrValue == 'boolean' || typeof attrValue == 'function') ? attrValue
5237 : (d.hasAttr(node, name) ? node.getAttribute(name) : null);
5242 dojo.removeAttr = function(/*DomNode|String*/node, /*String*/name){
5244 // Removes an attribute from an HTML element.
5246 // id or reference to the element to remove the attribute from
5248 // the name of the attribute to remove
5249 d.byId(node).removeAttribute(_fixAttrName(name));
5253 dojo.createElement = function(type, attrs, parent, position){
5254 // TODO: need to finish this!
5258 // =============================
5259 // (CSS) Class Functions
5260 // =============================
5261 var _className = "className";
5263 dojo.hasClass = function(/*DomNode|String*/node, /*String*/classStr){
5265 // Returns whether or not the specified classes are a portion of the
5266 // class list currently applied to the node.
5267 return ((" "+ d.byId(node)[_className] +" ").indexOf(" "+ classStr +" ") >= 0); // Boolean
5270 dojo.addClass = function(/*DomNode|String*/node, /*String*/classStr){
5272 // Adds the specified classes to the end of the class list on the
5274 node = d.byId(node);
5275 var cls = node[_className];
5276 if((" "+ cls +" ").indexOf(" " + classStr + " ") < 0){
5277 node[_className] = cls + (cls ? ' ' : '') + classStr;
5281 dojo.removeClass = function(/*DomNode|String*/node, /*String*/classStr){
5282 // summary: Removes the specified classes from node.
5283 node = d.byId(node);
5284 var t = d.trim((" " + node[_className] + " ").replace(" " + classStr + " ", " "));
5285 if(node[_className] != t){ node[_className] = t; }
5288 dojo.toggleClass = function(/*DomNode|String*/node, /*String*/classStr, /*Boolean?*/condition){
5290 // Adds a class to node if not present, or removes if present.
5291 // Pass a boolean condition if you want to explicitly add or remove.
5293 // If passed, true means to add the class, false means to remove.
5294 if(condition === undefined){
5295 condition = !d.hasClass(node, classStr);
5297 d[condition ? "addClass" : "removeClass"](node, classStr);
5304 if(!dojo._hasResource["dojo._base.NodeList"]){ //_hasResource checks added by build. Do not use _hasResource directly in your code.
5305 dojo._hasResource["dojo._base.NodeList"] = true;
5306 dojo.provide("dojo._base.NodeList");
5314 var tnl = function(arr){
5315 // decorate an array to make it look like a NodeList
5316 arr.constructor = dojo.NodeList;
5317 dojo._mixin(arr, dojo.NodeList.prototype);
5321 var _mapIntoDojo = function(func, alwaysThis){
5322 // returns a function which, when executed in the scope of its caller,
5323 // applies the passed arguments to a particular dojo.* function (named
5324 // in func) and aggregates the returns. if alwaysThis is true, it
5325 // always returns the scope object and not the collected returns from
5329 var aa = d._toArray(_a, 0, [null]);
5330 var s = this.map(function(i){
5332 return d[func].apply(d, aa);
5334 return (alwaysThis || ( (_a.length > 1) || !d.isString(_a[0]) )) ? this : s; // String||dojo.NodeList
5338 dojo.NodeList = function(){
5340 // dojo.NodeList is as subclass of Array which adds syntactic
5341 // sugar for chaining, common iteration operations, animation,
5342 // and node manipulation. NodeLists are most often returned as
5343 // the result of dojo.query() calls.
5345 // create a node list from a node
5346 // | new dojo.NodeList(dojo.byId("foo"));
5348 return tnl(Array.apply(null, arguments));
5351 dojo.NodeList._wrap = tnl;
5353 dojo.extend(dojo.NodeList, {
5354 // http://developer.mozilla.org/en/docs/Core_JavaScript_1.5_Reference:Global_Objects:Array#Methods
5356 // FIXME: handle return values for #3244
5357 // http://trac.dojotoolkit.org/ticket/3244
5360 // need to wrap or implement:
5361 // join (perhaps w/ innerHTML/outerHTML overload for toString() of items?)
5365 slice: function(/*===== begin, end =====*/){
5367 // Returns a new NodeList, maintaining this one in place
5369 // This method behaves exactly like the Array.slice method
5370 // with the caveat that it returns a dojo.NodeList and not a
5371 // raw Array. For more details, see:
5372 // http://developer.mozilla.org/en/docs/Core_JavaScript_1.5_Reference:Global_Objects:Array:slice
5374 // Can be a positive or negative integer, with positive
5375 // integers noting the offset to begin at, and negative
5376 // integers denoting an offset from the end (i.e., to the left
5379 // Optional parameter to describe what position relative to
5380 // the NodeList's zero index to end the slice at. Like begin,
5381 // can be positive or negative.
5382 var a = d._toArray(arguments);
5383 return tnl(a.slice.apply(this, a));
5386 splice: function(/*===== index, howmany, item =====*/){
5388 // Returns a new NodeList, manipulating this NodeList based on
5389 // the arguments passed, potentially splicing in new elements
5390 // at an offset, optionally deleting elements
5392 // This method behaves exactly like the Array.splice method
5393 // with the caveat that it returns a dojo.NodeList and not a
5394 // raw Array. For more details, see:
5395 // <http://developer.mozilla.org/en/docs/Core_JavaScript_1.5_Reference:Global_Objects:Array:splice>
5397 // begin can be a positive or negative integer, with positive
5398 // integers noting the offset to begin at, and negative
5399 // integers denoting an offset from the end (i.e., to the left
5401 // howmany: Integer?
5402 // Optional parameter to describe what position relative to
5403 // the NodeList's zero index to end the slice at. Like begin,
5404 // can be positive or negative.
5406 // Any number of optional parameters may be passed in to be
5407 // spliced into the NodeList
5410 var a = d._toArray(arguments);
5411 return tnl(a.splice.apply(this, a));
5414 concat: function(/*===== item =====*/){
5416 // Returns a new NodeList comprised of items in this NodeList
5417 // as well as items passed in as parameters
5419 // This method behaves exactly like the Array.concat method
5420 // with the caveat that it returns a dojo.NodeList and not a
5421 // raw Array. For more details, see:
5422 // <http://developer.mozilla.org/en/docs/Core_JavaScript_1.5_Reference:Global_Objects:Array:concat>
5424 // Any number of optional parameters may be passed in to be
5425 // spliced into the NodeList
5428 var a = d._toArray(arguments, 0, [this]);
5429 return tnl(a.concat.apply([], a));
5432 indexOf: function(/*Object*/ value, /*Integer?*/ fromIndex){
5434 // see dojo.indexOf(). The primary difference is that the acted-on
5435 // array is implicitly this NodeList
5437 // The value to search for.
5439 // The loction to start searching from. Optional. Defaults to 0.
5441 // For more details on the behavior of indexOf, see:
5442 // <http://developer.mozilla.org/en/docs/Core_JavaScript_1.5_Reference:Global_Objects:Array:indexOf>
5444 // Positive Integer or 0 for a match, -1 of not found.
5445 return d.indexOf(this, value, fromIndex); // Integer
5448 lastIndexOf: function(/*===== value, fromIndex =====*/){
5450 // see dojo.lastIndexOf(). The primary difference is that the
5451 // acted-on array is implicitly this NodeList
5453 // For more details on the behavior of lastIndexOf, see:
5454 // <http://developer.mozilla.org/en/docs/Core_JavaScript_1.5_Reference:Global_Objects:Array:lastIndexOf>
5456 // The value to search for.
5457 // fromIndex: Integer?
5458 // The loction to start searching from. Optional. Defaults to 0.
5460 // Positive Integer or 0 for a match, -1 of not found.
5461 return d.lastIndexOf.apply(d, d._toArray(arguments, 0, [this])); // Integer
5464 every: function(/*Function*/callback, /*Object?*/thisObject){
5466 // see `dojo.every()` and:
5467 // <http://developer.mozilla.org/en/docs/Core_JavaScript_1.5_Reference:Global_Objects:Array:every>
5468 // Takes the same structure of arguments and returns as
5469 // dojo.every() with the caveat that the passed array is
5470 // implicitly this NodeList
5471 return d.every(this, callback, thisObject); // Boolean
5474 some: function(/*Function*/callback, /*Object?*/thisObject){
5476 // see dojo.some() and:
5477 // http://developer.mozilla.org/en/docs/Core_JavaScript_1.5_Reference:Global_Objects:Array:some
5478 // Takes the same structure of arguments and returns as
5479 // dojo.some() with the caveat that the passed array is
5480 // implicitly this NodeList
5481 return d.some(this, callback, thisObject); // Boolean
5484 map: function(/*Function*/ func, /*Function?*/ obj){
5486 // see dojo.map(). The primary difference is that the acted-on
5487 // array is implicitly this NodeList and the return is a
5488 // dojo.NodeList (a subclass of Array)
5490 return d.map(this, func, obj, d.NodeList); // dojo.NodeList
5493 forEach: function(callback, thisObj){
5495 // see dojo.forEach(). The primary difference is that the acted-on
5496 // array is implicitly this NodeList
5498 d.forEach(this, callback, thisObj);
5499 // non-standard return to allow easier chaining
5500 return this; // dojo.NodeList
5507 // Returns the box objects all elements in a node list as
5508 // an Array (*not* a NodeList)
5510 return d.map(this, d.coords); // Array
5514 attr: function(property, value){
5516 // gets or sets the DOM attribute for every element in the
5519 // the attribute to get/set
5521 // optional. The value to set the property to
5523 // if no value is passed, the result is an array of attribute values
5524 // If a value is passed, the return is this NodeList
5525 return; // dojo.NodeList
5529 style: function(property, value){
5531 // gets or sets the CSS property for every element in the NodeList
5533 // the CSS property to get/set, in JavaScript notation
5534 // ("lineHieght" instead of "line-height")
5536 // optional. The value to set the property to
5538 // if no value is passed, the result is an array of strings.
5539 // If a value is passed, the return is this NodeList
5540 return; // dojo.NodeList
5544 addClass: function(className){
5546 // adds the specified class to every node in the list
5547 // className: String
5548 // the CSS class to add
5549 return; // dojo.NodeList
5552 removeClass: function(className){
5554 // removes the specified class from every node in the list
5555 // className: String
5556 // the CSS class to add
5558 // dojo.NodeList, this list
5559 return; // dojo.NodeList
5562 toggleClass: function(className, condition){
5564 // Adds a class to node if not present, or removes if present.
5565 // Pass a boolean condition if you want to explicitly add or remove.
5566 // condition: Boolean?
5567 // If passed, true means to add the class, false means to remove.
5568 // className: String
5569 // the CSS class to add
5570 return; // dojo.NodeList
5573 connect: function(methodName, objOrFunc, funcName){
5575 // attach event handlers to every item of the NodeList. Uses dojo.connect()
5576 // so event properties are normalized
5577 // methodName: String
5578 // the name of the method to attach to. For DOM events, this should be
5579 // the lower-case name of the event
5580 // objOrFunc: Object|Function|String
5581 // if 2 arguments are passed (methodName, objOrFunc), objOrFunc should
5582 // reference a function or be the name of the function in the global
5583 // namespace to attach. If 3 arguments are provided
5584 // (methodName, objOrFunc, funcName), objOrFunc must be the scope to
5585 // locate the bound function in
5586 // funcName: String?
5587 // optional. A string naming the function in objOrFunc to bind to the
5588 // event. May also be a function reference.
5590 // add an onclick handler to every button on the page
5591 // | dojo.query("div:nth-child(odd)").connect("onclick", function(e){
5595 // attach foo.bar() to every odd div's onmouseover
5596 // | dojo.query("div:nth-child(odd)").connect("onmouseover", foo, "bar");
5599 attr: _mapIntoDojo("attr"),
5600 style: _mapIntoDojo("style"),
5601 addClass: _mapIntoDojo("addClass", true),
5602 removeClass: _mapIntoDojo("removeClass", true),
5603 toggleClass: _mapIntoDojo("toggleClass", true),
5604 connect: _mapIntoDojo("connect", true),
5606 // FIXME: connectPublisher()? connectRunOnce()?
5608 place: function(/*String||Node*/ queryOrNode, /*String*/ position){
5610 // places elements of this node list relative to the first element matched
5611 // by queryOrNode. Returns the original NodeList.
5613 // may be a string representing any valid CSS3 selector or a DOM node.
5614 // In the selector case, only the first matching element will be used
5615 // for relative positioning.
5618 // * "last"||"end" (default)
5619 // * "first||"start"
5622 // or an offset in the childNodes property
5623 var item = d.query(queryOrNode)[0];
5624 return this.forEach(function(i){ d.place(i, item, position); }); // dojo.NodeList
5627 orphan: function(/*String?*/ simpleFilter){
5629 // removes elements in this list that match the simple
5630 // filter from their parents and returns them as a new
5633 // single-expression CSS filter
5635 // `dojo.NodeList` containing the orpahned elements
5636 return (simpleFilter ? d._filterQueryResult(this, simpleFilter) : this). // dojo.NodeList
5637 forEach("if(item.parentNode){ item.parentNode.removeChild(item); }");
5640 adopt: function(/*String||Array||DomNode*/ queryOrListOrNode, /*String?*/ position){
5642 // places any/all elements in queryOrListOrNode at a
5643 // position relative to the first element in this list.
5644 // Returns a dojo.NodeList of the adopted elements.
5645 // queryOrListOrNode:
5646 // a DOM node or a query string or a query result.
5647 // Represents the nodes to be adopted relative to the
5648 // first element of this NodeList.
5651 // * "last"||"end" (default)
5652 // * "first||"start"
5655 // or an offset in the childNodes property
5657 return d.query(queryOrListOrNode).forEach(function(ai){ // dojo.NodeList
5658 d.place(ai, item, position || "last");
5662 // FIXME: do we need this?
5663 query: function(/*String*/ queryStr){
5665 // Returns a new, flattened NodeList. Elements of the new list
5666 // satisfy the passed query but use elements of the
5667 // current NodeList as query roots.
5669 if(!queryStr){ return this; }
5671 // FIXME: probably slow
5673 var ret = d.NodeList();
5674 this.forEach(function(item){
5675 // FIXME: why would we ever get undefined here?
5676 ret = ret.concat(d.query(queryStr, item).filter(function(subItem){ return (subItem !== undefined); }));
5678 return ret; // dojo.NodeList
5681 filter: function(/*String*/ simpleQuery){
5683 // "masks" the built-in javascript filter() method to support
5684 // passing a simple string filter in addition to supporting
5685 // filtering function objects.
5687 // "regular" JS filter syntax as exposed in dojo.filter:
5688 // | dojo.query("*").filter(function(item){
5689 // | // highlight every paragraph
5690 // | return (item.nodeName == "p");
5691 // | }).styles("backgroundColor", "yellow");
5693 // the same filtering using a CSS selector
5694 // | dojo.query("*").filter("p").styles("backgroundColor", "yellow");
5698 var r = d.NodeList();
5699 var rp = function(t){
5700 if(t !== undefined){
5704 if(d.isString(simpleQuery)){
5705 items = d._filterQueryResult(this, _a[0]);
5707 // if we only got a string query, pass back the filtered results
5708 return items; // dojo.NodeList
5710 // if we got a callback, run it over the filtered items
5713 // handle the (callback, [thisObject]) case
5714 d.forEach(d.filter(items, _a[0], _a[1]), rp);
5715 return r; // dojo.NodeList
5719 // FIXME: should this be "copyTo" and include parenting info?
5722 // creates node clones of each element of this list
5723 // and returns a new list containing the clones
5727 addContent: function(/*String*/ content, /*String||Integer?*/ position){
5729 // add a node or some HTML as a string to every item in the list.
5730 // Returns the original list.
5732 // a copy of the HTML content is added to each item in the
5733 // list, with an optional position argument. If no position
5734 // argument is provided, the content is appended to the end of
5737 // the HTML in string format to add at position to every item
5740 // * "last"||"end" (default)
5741 // * "first||"start"
5744 // or an offset in the childNodes property
5746 // appends content to the end if the position is ommitted
5747 // | dojo.query("h3 > p").addContent("hey there!");
5749 // add something to the front of each element that has a "thinger" property:
5750 // | dojo.query("[thinger]").addContent("...", "first");
5752 // adds a header before each element of the list
5753 // | dojo.query(".note").addContent("<h4>NOTE:</h4>", "before");
5754 var ta = d.doc.createElement("span");
5755 if(d.isString(content)){
5756 ta.innerHTML = content;
5758 ta.appendChild(content);
5760 if(position === undefined){
5763 var ct = (position == "first" || position == "after") ? "lastChild" : "firstChild";
5764 this.forEach(function(item){
5765 var tn = ta.cloneNode(true);
5767 d.place(tn[ct], item, position);
5770 return this; // dojo.NodeList
5775 // clears all content from each node in the list
5776 return this.forEach("item.innerHTML='';"); // dojo.NodeList
5778 // FIXME: should we be checking for and/or disposing of widgets below these nodes?
5781 instantiate: function(/*String|Object*/ declaredClass, /*Object?*/ properties){
5783 // Create a new instance of a specified class, using the
5784 // specified properties and each node in the nodeList as a
5787 var c = d.isFunction(declaredClass) ? declaredClass : d.getObject(declaredClass);
5788 return this.forEach(function(i){
5789 new c(properties||{},i);
5793 at: function(/*===== index =====*/){
5795 // Returns a new NodeList comprised of items in this NodeList
5796 // at the given index or indices.
5797 // index: Integer...
5798 // One or more 0-based indices of items in the current NodeList.
5801 var nl = new dojo.NodeList();
5802 dojo.forEach(arguments, function(i) { if(this[i]) { nl.push(this[i]); } }, this);
5803 return nl; // dojo.NodeList
5808 // syntactic sugar for DOM events
5810 "blur", "focus", "click", "keydown", "keypress", "keyup", "mousedown",
5811 "mouseenter", "mouseleave", "mousemove", "mouseout", "mouseover",
5812 "mouseup", "submit", "load", "error"
5815 d.NodeList.prototype[_oe] = function(a, b){
5816 return this.connect(_oe, a, b);
5818 // FIXME: should these events trigger publishes?
5820 return (a ? this.connect(_oe, a, b) :
5821 this.forEach(function(n){
5823 // listeners get buried by
5824 // addEventListener and can't be dug back
5825 // out to be triggered externally.
5827 // http://developer.mozilla.org/en/docs/DOM:element
5831 // FIXME: need synthetic event support!
5832 var _e = { target: n, faux: true, type: evt };
5833 // dojo._event_listener._synthesizeEvent({}, { target: n, faux: true, type: evt });
5834 try{ n[evt](_e); }catch(e){ }
5835 try{ n[_oe](_e); }catch(e){ }
5847 if(!dojo._hasResource["dojo._base.query"]){ //_hasResource checks added by build. Do not use _hasResource directly in your code.
5848 dojo._hasResource["dojo._base.query"] = true;
5849 dojo.provide("dojo._base.query");
5853 dojo.query() architectural overview:
5855 dojo.query is a relatively full-featured CSS3 query library. It is
5856 designed to take any valid CSS3 selector and return the nodes matching
5857 the selector. To do this quickly, it processes queries in several
5858 steps, applying caching where profitable.
5860 The steps (roughly in reverse order of the way they appear in the code):
5861 1.) check to see if we already have a "query dispatcher"
5862 - if so, use that with the given parameterization. Skip to step 4.
5863 2.) attempt to determine which branch to dispatch the query to:
5864 - JS (optimized DOM iteration)
5865 - xpath (for browsers that support it and where it's fast)
5866 - native (not available in any browser yet)
5867 3.) tokenize and convert to executable "query dispatcher"
5868 - this is where the lion's share of the complexity in the
5869 system lies. In the DOM version, the query dispatcher is
5870 assembled as a chain of "yes/no" test functions pertaining to
5871 a section of a simple query statement (".blah:nth-child(odd)"
5872 but not "div div", which is 2 simple statements). Individual
5873 statement dispatchers are cached (to prevent re-definition)
5874 as are entire dispatch chains (to make re-execution of the
5876 - in the xpath path, tokenization yields a concatenation of
5877 parameterized xpath selectors. As with the DOM version, both
5878 simple selector blocks and overall evaluators are cached to
5879 prevent re-defintion
5880 4.) the resulting query dispatcher is called in the passed scope (by default the top-level document)
5881 - for DOM queries, this results in a recursive, top-down
5882 evaluation of nodes based on each simple query section
5883 - xpath queries can, thankfully, be executed in one shot
5884 5.) matched nodes are pruned to ensure they are unique
5888 // define everything in a closure for compressability reasons. "d" is an
5889 // alias to "dojo" since it's so frequently used. This seems a
5890 // transformation that the build system could perform on a per-file basis.
5892 ////////////////////////////////////////////////////////////////////////
5894 ////////////////////////////////////////////////////////////////////////
5897 var childNodesName = dojo.isIE ? "children" : "childNodes";
5898 var caseSensitive = false;
5900 var getQueryParts = function(query){
5901 // summary: state machine for query tokenization
5902 if(">~+".indexOf(query.charAt(query.length-1)) >= 0){
5905 query += " "; // ensure that we terminate the state machine
5907 var ts = function(s, e){
5908 return d.trim(query.slice(s, e));
5911 // the overall data graph of the full query, as represented by queryPart objects
5913 // state keeping vars
5914 var inBrackets = -1;
5916 var inMatchFor = -1;
5921 var lc = ""; // the last character
5922 var cc = ""; // the current character
5925 var x = 0; // index in the query
5926 var ql = query.length;
5927 var currentPart = null; // data structure representing the entire clause
5928 var _cp = null; // the current pseudo or attr matcher
5930 var endTag = function(){
5932 var tv = (inTag == x) ? null : ts(inTag, x); // .toLowerCase();
5933 currentPart[ (">~+".indexOf(tv) < 0) ? "tag" : "oper" ] = tv;
5938 var endId = function(){
5940 currentPart.id = ts(inId, x).replace(/\\/g, "");
5945 var endClass = function(){
5947 currentPart.classes.push(ts(inClass+1, x).replace(/\\/g, ""));
5952 var endAll = function(){
5953 endId(); endTag(); endClass();
5956 for(; lc=cc, cc=query.charAt(x),x<ql; x++){
5957 if(lc == "\\"){ continue; }
5959 // NOTE: I hate all this alloc, but it's shorter than writing tons of if's
5973 if(inBrackets >= 0){
5974 // look for a the close first
5977 _cp.attr = ts(inBrackets+1, x);
5979 _cp.matchFor = ts((inMatchFor||inBrackets+1), x);
5981 var cmf = _cp.matchFor;
5983 if( (cmf.charAt(0) == '"') || (cmf.charAt(0) == "'") ){
5984 _cp.matchFor = cmf.substring(1, cmf.length-1);
5987 currentPart.attrs.push(_cp);
5988 _cp = null; // necessaray?
5989 inBrackets = inMatchFor = -1;
5990 }else if(cc == "="){
5991 var addToCc = ("|~^$*".indexOf(lc) >=0 ) ? lc : "";
5992 _cp.type = addToCc+cc;
5993 _cp.attr = ts(inBrackets+1, x-addToCc.length);
5996 // now look for other clause parts
5997 }else if(inParens >= 0){
6000 _cp.value = ts(inParens+1, x);
6002 inPseudo = inParens = -1;
6004 }else if(cc == "#"){
6007 }else if(cc == "."){
6010 }else if(cc == ":"){
6013 }else if(cc == "["){
6018 attr: null, type: null, matchFor: null
6021 }else if(cc == "("){
6024 name: ts(inPseudo+1, x),
6027 currentPart.pseudos.push(_cp);
6030 }else if(cc == " " && lc != cc){
6031 // note that we expect the string to be " " terminated
6034 currentPart.pseudos.push({ name: ts(inPseudo+1, x) });
6036 currentPart.hasLoops = (
6037 currentPart.pseudos.length ||
6038 currentPart.attrs.length ||
6039 currentPart.classes.length );
6040 currentPart.query = ts(pStart, x);
6041 currentPart.otag = currentPart.tag = (currentPart["oper"]) ? null : (currentPart.tag || "*");
6042 if(currentPart.tag){ // FIXME: not valid in case-sensitive documents
6043 currentPart.tag = currentPart.tag.toUpperCase();
6045 qparts.push(currentPart);
6053 ////////////////////////////////////////////////////////////////////////
6055 ////////////////////////////////////////////////////////////////////////
6057 // this array is a lookup used to generate an attribute matching function.
6058 // There is a similar lookup/generator list for the DOM branch with similar
6059 // calling semantics.
6061 "*=": function(attr, value){
6062 return "[contains(@"+attr+", '"+ value +"')]";
6064 "^=": function(attr, value){
6065 return "[starts-with(@"+attr+", '"+ value +"')]";
6067 "$=": function(attr, value){
6068 return "[substring(@"+attr+", string-length(@"+attr+")-"+(value.length-1)+")='"+value+"']";
6070 "~=": function(attr, value){
6071 return "[contains(concat(' ',@"+attr+",' '), ' "+ value +" ')]";
6073 "|=": function(attr, value){
6074 return "[contains(concat(' ',@"+attr+",' '), ' "+ value +"-')]";
6076 "=": function(attr, value){
6077 return "[@"+attr+"='"+ value +"']";
6081 // takes a list of attribute searches, the overall query, a function to
6082 // generate a default matcher, and a closure-bound method for providing a
6083 // matching function that generates whatever type of yes/no distinguisher
6084 // the query method needs. The method is a bit tortured and hard to read
6085 // because it needs to be used in both the XPath and DOM branches.
6086 var handleAttrs = function( attrList,
6090 d.forEach(query.attrs, function(attr){
6092 // type, attr, matchFor
6093 if(attr.type && attrList[attr.type]){
6094 matcher = attrList[attr.type](attr.attr, attr.matchFor);
6095 }else if(attr.attr.length){
6096 matcher = getDefault(attr.attr);
6098 if(matcher){ handleMatch(matcher); }
6102 var buildPath = function(query){
6104 var qparts = getQueryParts(d.trim(query));
6105 while(qparts.length){
6106 var tqp = qparts.shift();
6109 if(tqp.oper == ">"){
6111 // prefix = "/child::*";
6112 tqp = qparts.shift();
6113 }else if(tqp.oper == "~"){
6114 prefix = "/following-sibling::"; // get element following siblings
6115 tqp = qparts.shift();
6116 }else if(tqp.oper == "+"){
6118 // fails when selecting subsequent siblings by node type
6119 // because the position() checks the position in the list
6120 // of matching elements and not the localized siblings
6121 prefix = "/following-sibling::";
6122 postfix = "[position()=1]";
6123 tqp = qparts.shift();
6126 // prefix = "/descendant::*"
6129 // get the tag name (if any)
6131 xpath += prefix + tqp.tag + postfix;
6133 // check to see if it's got an id. Needs to come first in xpath.
6135 xpath += "[@id='"+tqp.id+"'][1]";
6138 d.forEach(tqp.classes, function(cn){
6139 var cnl = cn.length;
6141 if(cn.charAt(cnl-1) == "*"){
6142 padding = ""; cn = cn.substr(0, cnl-1);
6145 "[contains(concat(' ',@class,' '), ' "+
6146 cn + padding + "')]";
6149 handleAttrs(xPathAttrs, tqp,
6150 function(condition){
6151 return "[@"+condition+"]";
6158 // FIXME: need to implement pseudo-class checks!!
6163 var _xpathFuncCache = {};
6164 var getXPathFunc = function(path){
6165 if(_xpathFuncCache[path]){
6166 return _xpathFuncCache[path];
6170 // don't need to memoize. The closure scope handles it for us.
6171 var xpath = buildPath(path);
6173 var tf = function(parent){
6174 // XPath query strings are memoized.
6180 tdoc = (parent.nodeType == 9) ? parent : parent.ownerDocument;
6183 xpathResult = tdoc.evaluate(xpath, parent, null,
6184 // XPathResult.UNORDERED_NODE_ITERATOR_TYPE, null);
6185 XPathResult.ANY_TYPE, null);
6190 var result = xpathResult.iterateNext();
6193 result = xpathResult.iterateNext();
6197 return _xpathFuncCache[path] = tf;
6201 d.xPathMatch = function(query){
6202 // XPath based DOM query system. Handles a small subset of CSS
6203 // selectors, subset is identical to the non-XPath version of this
6206 return getXPathFunc(query)();
6210 ////////////////////////////////////////////////////////////////////////
6212 ////////////////////////////////////////////////////////////////////////
6214 var _filtersCache = {};
6215 var _simpleFiltersCache = {};
6217 // the basic building block of the yes/no chaining system. agree(f1, f2)
6218 // generates a new function which returns the boolean results of both of
6219 // the passed functions to a single logical-anded result.
6220 var agree = function(first, second){
6221 if(!first){ return second; }
6222 if(!second){ return first; }
6225 return first.apply(window, arguments) && second.apply(window, arguments);
6229 var _childElements = function(root){
6231 var te, x = 0, tret = root[childNodesName];
6232 while((te = tret[x++])){
6233 if(te.nodeType == 1){ ret.push(te); }
6238 var _nextSiblings = function(root, single){
6241 while(te = te.nextSibling){
6242 if(te.nodeType == 1){
6244 if(single){ break; }
6251 // we need to re-write the way "~" and "+" selectors are handled since
6252 // the left-hand selector simply modifies the right (which is the
6253 // actual search selector). We need to locate on search selector
6254 // instead of modifier to speed up these searches.
6256 var _filterDown = function(element, queryParts, matchArr, idx){
6258 // in the fast path! this function is called recursively and for
6259 // every run of a query.
6261 var isFinal = (queryParts.length == nidx);
6262 var tqp = queryParts[idx];
6264 // see if we can constrain our next level to direct children
6266 // find some eligable children to search
6267 var ecn = (tqp.oper == ">") ?
6268 _childElements(element) :
6269 _nextSiblings(element, (tqp.oper == "+"));
6271 if(!ecn || !ecn.length){
6275 isFinal = (queryParts.length == nidx);
6276 // kinda janky, too much array alloc
6277 var tf = getFilterFunc(queryParts[idx+1]);
6278 // for(var x=ecn.length-1, te; x>=0, te=ecn[x]; x--){
6279 for(var x=0, ecnl=ecn.length, te; x<ecnl, te=ecn[x]; x++){
6284 _filterDown(te, queryParts, matchArr, nidx);
6295 // otherwise, keep going down, unless we'er at the end
6296 var candidates = getElementsFunc(tqp)(element);
6298 while(candidates.length){
6299 matchArr.push(candidates.shift());
6302 candidates.unshift(0, matchArr.length-1);
6303 matchArr.splice.apply(matchArr, candidates);
6306 // if we're not yet at the bottom, keep going!
6307 while(candidates.length){
6308 _filterDown(candidates.shift(), queryParts, matchArr, nidx);
6313 var filterDown = function(elements, queryParts){
6316 // for every root, get the elements that match the descendant selector
6317 // for(var x=elements.length-1, te; x>=0, te=elements[x]; x--){
6318 var x = elements.length - 1, te;
6319 while((te = elements[x--])){
6320 _filterDown(te, queryParts, ret, 0);
6325 var getFilterFunc = function(q){
6326 // note: query can't have spaces!
6327 if(_filtersCache[q.query]){
6328 return _filtersCache[q.query];
6332 // does it have a tagName component?
6337 return (elem.nodeType == 1);
6345 (elem.nodeType == 1) &&
6346 (q[ caseSensitive ? "otag" : "tag" ] == elem.tagName)
6347 // (q.tag == elem.tagName.toLowerCase())
6355 // does the node have an ID?
6360 (elem.nodeType == 1) &&
6368 // if we have other query param parts, make sure we add them to the
6370 ff = agree(ff, getSimpleFilterFunc(q));
6373 return _filtersCache[q.query] = ff;
6376 var getNodeIndex = function(node){
6378 // we could have a more accurate caching mechanism by invalidating
6379 // caches after the query has finished, but I think that'd lead to
6380 // significantly more cache churn than the cache would provide
6381 // value for in the common case. Generally, we're more
6382 // conservative (and therefore, more accurate) than jQuery and
6383 // DomQuery WRT node node indexes, but there may be corner cases
6384 // in which we fall down. How much we care about them is TBD.
6386 var pn = node.parentNode;
6387 var pnc = pn.childNodes;
6389 // check to see if we can trust the cache. If not, re-key the whole
6390 // thing and return our node match from that.
6393 var child = pn.firstChild;
6398 var ci = node["__cachedIndex"];
6399 var cl = pn["__cachedLength"];
6401 // only handle cache building if we've gone out of sync
6402 if(((typeof cl == "number")&&(cl != pnc.length))||(typeof ci != "number")){
6403 // rip though the whole set, building cache indexes as we go
6404 pn["__cachedLength"] = pnc.length;
6407 // we only assign indexes for nodes with nodeType == 1, as per:
6408 // http://www.w3.org/TR/css3-selectors/#nth-child-pseudo
6409 // only elements are counted in the search order, and they
6410 // begin at 1 for the first child's index
6415 if(child.nodeType == 1){
6416 child["__cachedIndex"] = idx;
6419 child = child.nextSibling;
6423 // could be incorrect in some cases (node swaps involving the
6424 // passed node, etc.), but we ignore those due to the relative
6425 // unlikelihood of that occuring
6434 var _getAttr = function(elem, attr){
6435 if(attr == "class"){
6436 return elem.className || blank;
6439 return elem.htmlFor || blank;
6441 if(attr == "style"){
6442 return elem.style.cssText || blank;
6444 return (caseSensitive ? elem.getAttribute(attr) : elem.getAttribute(attr, 2)) || blank;
6448 "*=": function(attr, value){
6449 return function(elem){
6451 // an E element whose "foo" attribute value contains
6452 // the substring "bar"
6453 return (_getAttr(elem, attr).indexOf(value)>=0);
6456 "^=": function(attr, value){
6458 // an E element whose "foo" attribute value begins exactly
6459 // with the string "bar"
6460 return function(elem){
6461 return (_getAttr(elem, attr).indexOf(value)==0);
6464 "$=": function(attr, value){
6466 // an E element whose "foo" attribute value ends exactly
6467 // with the string "bar"
6468 var tval = " "+value;
6469 return function(elem){
6470 var ea = " "+_getAttr(elem, attr);
6471 return (ea.lastIndexOf(value)==(ea.length-value.length));
6474 "~=": function(attr, value){
6476 // an E element whose "foo" attribute value is a list of
6477 // space-separated values, one of which is exactly equal
6480 // return "[contains(concat(' ',@"+attr+",' '), ' "+ value +" ')]";
6481 var tval = " "+value+" ";
6482 return function(elem){
6483 var ea = " "+_getAttr(elem, attr)+" ";
6484 return (ea.indexOf(tval)>=0);
6487 "|=": function(attr, value){
6488 // E[hreflang|="en"]
6489 // an E element whose "hreflang" attribute has a
6490 // hyphen-separated list of values beginning (from the
6492 var valueDash = " "+value+"-";
6493 return function(elem){
6494 var ea = " "+(elem.getAttribute(attr, 2) || "");
6497 (ea.indexOf(valueDash)==0)
6501 "=": function(attr, value){
6502 return function(elem){
6503 return (_getAttr(elem, attr) == value);
6509 "checked": function(name, condition){
6510 return function(elem){
6511 return !!d.attr(elem, "checked");
6514 "first-child": function(name, condition){
6515 return function(elem){
6516 if(elem.nodeType != 1){ return false; }
6517 // check to see if any of the previous siblings are elements
6518 var fc = elem.previousSibling;
6519 while(fc && (fc.nodeType != 1)){
6520 fc = fc.previousSibling;
6525 "last-child": function(name, condition){
6526 return function(elem){
6527 if(elem.nodeType != 1){ return false; }
6528 // check to see if any of the next siblings are elements
6529 var nc = elem.nextSibling;
6530 while(nc && (nc.nodeType != 1)){
6531 nc = nc.nextSibling;
6536 "empty": function(name, condition){
6537 return function(elem){
6538 // DomQuery and jQuery get this wrong, oddly enough.
6539 // The CSS 3 selectors spec is pretty explicit about
6541 var cn = elem.childNodes;
6542 var cnl = elem.childNodes.length;
6543 // if(!cnl){ return true; }
6544 for(var x=cnl-1; x >= 0; x--){
6545 var nt = cn[x].nodeType;
6546 if((nt == 1)||(nt == 3)){ return false; }
6551 "contains": function(name, condition){
6552 return function(elem){
6553 // FIXME: I dislike this version of "contains", as
6554 // whimsical attribute could set it off. An inner-text
6555 // based version might be more accurate, but since
6556 // jQuery and DomQuery also potentially get this wrong,
6557 // I'm leaving it for now.
6558 if(condition.charAt(0)=='"' || condition.charAt(0)=="'"){//remove quote
6559 condition=condition.substr(1,condition.length-2);
6561 return (elem.innerHTML.indexOf(condition) >= 0);
6564 "not": function(name, condition){
6565 var ntf = getFilterFunc(getQueryParts(condition)[0]);
6566 return function(elem){
6567 return (!ntf(elem));
6570 "nth-child": function(name, condition){
6572 if(condition == "odd"){
6574 }else if(condition == "even"){
6577 if(condition.indexOf("n") != -1){
6578 var tparts = condition.split("n", 2);
6579 var pred = tparts[0] ? (tparts[0]=='-'?-1:pi(tparts[0])) : 1;
6580 var idx = tparts[1] ? pi(tparts[1]) : 0;
6581 var lb = 0, ub = -1;
6584 idx = (idx % pred) && (pred + (idx % pred));
6587 lb = idx - idx % pred;
6596 } //idx has to be greater than 0 when pred is negative; shall we throw an error here?
6599 return function(elem){
6600 var i=getNodeIndex(elem);
6601 return (i>=lb) && (ub<0 || i<=ub) && ((i % pred) == idx);
6607 //if(condition.indexOf("n") == -1){
6608 var ncount = pi(condition);
6609 return function(elem){
6610 return (getNodeIndex(elem) == ncount);
6615 var defaultGetter = (d.isIE) ? function(cond){
6616 var clc = cond.toLowerCase();
6617 return function(elem){
6618 return (caseSensitive ? elem.getAttribute(cond) : elem[cond]||elem[clc]);
6621 return function(elem){
6622 return (elem && elem.getAttribute && elem.hasAttribute(cond));
6626 var getSimpleFilterFunc = function(query){
6628 var fcHit = (_simpleFiltersCache[query.query]||_filtersCache[query.query]);
6629 if(fcHit){ return fcHit; }
6633 // the only case where we'll need the tag name is if we came from an ID query
6634 if(query.id){ // do we have an ID component?
6635 if(query.tag != "*"){
6636 ff = agree(ff, function(elem){
6637 return (elem.tagName == query[ caseSensitive ? "otag" : "tag" ]);
6642 // if there's a class in our query, generate a match function for it
6643 d.forEach(query.classes, function(cname, idx, arr){
6644 // get the class name
6645 var isWildcard = cname.charAt(cname.length-1) == "*";
6647 cname = cname.substr(0, cname.length-1);
6649 // I dislike the regex thing, even if memozied in a cache, but it's VERY short
6650 var re = new RegExp("(?:^|\\s)" + cname + (isWildcard ? ".*" : "") + "(?:\\s|$)");
6651 ff = agree(ff, function(elem){
6652 return re.test(elem.className);
6657 d.forEach(query.pseudos, function(pseudo){
6658 if(pseudos[pseudo.name]){
6659 ff = agree(ff, pseudos[pseudo.name](pseudo.name, pseudo.value));
6663 handleAttrs(attrs, query, defaultGetter,
6664 function(tmatcher){ ff = agree(ff, tmatcher); }
6667 ff = function(){ return true; };
6669 return _simpleFiltersCache[query.query] = ff;
6672 var _getElementsFuncCache = { };
6674 var getElementsFunc = function(query, root){
6675 var fHit = _getElementsFuncCache[query.query];
6676 if(fHit){ return fHit; }
6678 // NOTE: this function is in the fast path! not memoized!!!
6680 // the query doesn't contain any spaces, so there's only so many
6681 // things it could be
6683 if(query.id && !query.hasLoops && !query.tag){
6684 // ID-only query. Easy.
6685 return _getElementsFuncCache[query.query] = function(root){
6686 // FIXME: if root != document, check for parenting!
6687 return [ d.byId(query.id) ];
6691 var filterFunc = getSimpleFilterFunc(query);
6694 if(query.tag && query.id && !query.hasLoops){
6695 // we got a filtered ID search (e.g., "h4#thinger")
6696 retFunc = function(root){
6697 var te = d.byId(query.id, (root.ownerDocument||root)); //root itself may be a document
6705 if(!query.hasLoops){
6706 // it's just a plain-ol elements-by-tag-name query from the root
6707 retFunc = function(root){
6709 var te, x=0, tret = root.getElementsByTagName(query[ caseSensitive ? "otag" : "tag"]);
6710 while((te = tret[x++])){
6716 retFunc = function(root){
6718 var te, x = 0, tret = root.getElementsByTagName(query[ caseSensitive ? "otag" : "tag"]);
6719 while((te = tret[x++])){
6728 return _getElementsFuncCache[query.query] = retFunc;
6731 var _partsCache = {};
6733 ////////////////////////////////////////////////////////////////////////
6735 ////////////////////////////////////////////////////////////////////////
6737 // this is the second level of spliting, from full-length queries (e.g.,
6738 // "div.foo .bar") into simple query expressions (e.g., ["div.foo",
6740 var _queryFuncCache = {
6746 return root.getElementsByTagName("*");
6749 "+": function(root){ return _nextSiblings(root, true); },
6753 var getStepQueryFunc = function(query){
6754 // if it's trivial, get a fast-path dispatcher
6755 var qparts = getQueryParts(d.trim(query));
6756 // if(query[query.length-1] == ">"){ query += " *"; }
6757 if(qparts.length == 1){
6758 var tt = getElementsFunc(qparts[0]);
6759 tt.nozip = true; // FIXME: is this right? Shouldn't this be wrapped in a closure to mark the return?
6763 // otherwise, break it up and return a runner that iterates over the parts recursively
6764 var sqf = function(root){
6765 var localQueryParts = qparts.slice(0); // clone the src arr
6767 if(localQueryParts[0].oper == ">"){ // FIXME: what if it's + or ~?
6768 candidates = [ root ];
6771 candidates = getElementsFunc(localQueryParts.shift())(root);
6773 return filterDown(candidates, localQueryParts);
6778 // a specialized method that implements our primoridal "query optimizer".
6779 // This allows us to dispatch queries to the fastest subsystem we can get.
6780 var _getQueryFunc = (
6782 // XPath on the Webkit is slower than it's DOM iteration for most
6785 // we should try to capture some runtime speed data for each query
6786 // function to determine on the fly if we should stick w/ the
6787 // potentially optimized variant or if we should try something
6789 (document["evaluate"] && !d.isSafari) ?
6790 function(query, root){
6791 // has xpath support that's faster than DOM
6792 var qparts = query.split(" ");
6793 // can we handle it?
6794 if( (!caseSensitive) && // not strictly necessaray, but simplifies lots of stuff
6795 (document["evaluate"]) &&
6796 (query.indexOf(":") == -1) &&
6797 (query.indexOf("+") == -1) // skip direct sibling matches. See line ~344
6799 // dojo.debug(query);
6800 // should we handle it?
6802 // kind of a lame heuristic, but it works
6804 // a "div div div" style query
6805 ((qparts.length > 2)&&(query.indexOf(">") == -1))||
6806 // or something else with moderate complexity. kinda janky
6807 (qparts.length > 3)||
6808 (query.indexOf("[")>=0)||
6809 // or if it's a ".thinger" query
6810 ((1 == qparts.length)&&(0 <= query.indexOf(".")))
6813 // use get and cache a xpath runner for this selector
6814 return getXPathFunc(query);
6819 return getStepQueryFunc(query);
6820 } : getStepQueryFunc
6822 // uncomment to disable XPath for testing and tuning the DOM path
6823 // _getQueryFunc = getStepQueryFunc;
6825 // FIXME: we've got problems w/ the NodeList query()/filter() functions if we go XPath for everything
6827 // uncomment to disable DOM queries for testing and tuning XPath
6828 // _getQueryFunc = getXPathFunc;
6830 // this is the primary caching for full-query results. The query dispatcher
6831 // functions are generated here and then pickled for hash lookup in the
6833 var getQueryFunc = function(query){
6834 // return a cached version if one is available
6835 var qcz = query.charAt(0);
6836 if(d.doc["querySelectorAll"] &&
6837 ( (!d.isSafari) || (d.isSafari > 3.1) ) && // see #5832
6838 // as per CSS 3, we can't currently start w/ combinator:
6839 // http://www.w3.org/TR/css3-selectors/#w3cselgrammar
6840 (">+~".indexOf(qcz) == -1)
6842 return function(root){
6843 var r = root.querySelectorAll(query);
6844 r.nozip = true; // skip expensive duplication checks and just wrap in a NodeList
6848 if(_queryFuncCache[query]){ return _queryFuncCache[query]; }
6849 if(0 > query.indexOf(",")){
6850 // if it's not a compound query (e.g., ".foo, .bar"), cache and return a dispatcher
6851 return _queryFuncCache[query] = _getQueryFunc(query);
6853 // if it's a complex query, break it up into it's constituent parts
6854 // and return a dispatcher that will merge the parts when run
6856 // var parts = query.split(", ");
6857 var parts = query.split(/\s*,\s*/);
6858 var tf = function(root){
6859 var pindex = 0; // avoid array alloc for every invocation
6862 while((tp = parts[pindex++])){
6863 ret = ret.concat(_getQueryFunc(tp, tp.indexOf(" "))(root));
6867 // ...cache and return
6868 return _queryFuncCache[query] = tf;
6873 // Dean's Base2 uses a system whereby queries themselves note if
6874 // they'll need duplicate filtering. We need to get on that plan!!
6876 // attempt to efficiently determine if an item in a list is a dupe,
6877 // returning a list of "uniques", hopefully in doucment order
6879 var _zip = function(arr){
6880 if(arr && arr.nozip){ return d.NodeList._wrap(arr); }
6881 var ret = new d.NodeList();
6882 if(!arr){ return ret; }
6886 if(arr.length < 2){ return ret; }
6890 // we have to fork here for IE and XML docs because we can't set
6891 // expandos on their nodes (apparently). *sigh*
6892 if(d.isIE && caseSensitive){
6893 var szidx = _zipIdx+"";
6894 arr[0].setAttribute("_zipIdx", szidx);
6895 for(var x = 1, te; te = arr[x]; x++){
6896 if(arr[x].getAttribute("_zipIdx") != szidx){
6899 te.setAttribute("_zipIdx", szidx);
6902 arr[0]["_zipIdx"] = _zipIdx;
6903 for(var x = 1, te; te = arr[x]; x++){
6904 if(arr[x]["_zipIdx"] != _zipIdx){
6907 te["_zipIdx"] = _zipIdx;
6910 // FIXME: should we consider stripping these properties?
6914 // the main executor
6915 d.query = function(/*String*/ query, /*String|DOMNode?*/ root){
6917 // Returns nodes which match the given CSS3 selector, searching the
6918 // entire document by default but optionally taking a node to scope
6919 // the search by. Returns an instance of dojo.NodeList.
6921 // dojo.query() is the swiss army knife of DOM node manipulation in
6922 // Dojo. Much like Prototype's "$$" (bling-bling) function or JQuery's
6923 // "$" function, dojo.query provides robust, high-performance
6924 // CSS-based node selector support with the option of scoping searches
6925 // to a particular sub-tree of a document.
6927 // Supported Selectors:
6928 // --------------------
6930 // dojo.query() supports a rich set of CSS3 selectors, including:
6932 // * class selectors (e.g., `.foo`)
6933 // * node type selectors like `span`
6934 // * ` ` descendant selectors
6935 // * `>` child element selectors
6936 // * `#foo` style ID selectors
6937 // * `*` universal selector
6938 // * `~`, the immediately preceeded-by sibling selector
6939 // * `+`, the preceeded-by sibling selector
6940 // * attribute queries:
6941 // | * `[foo]` attribute presence selector
6942 // | * `[foo='bar']` attribute value exact match
6943 // | * `[foo~='bar']` attribute value list item match
6944 // | * `[foo^='bar']` attribute start match
6945 // | * `[foo$='bar']` attribute end match
6946 // | * `[foo*='bar']` attribute substring match
6947 // * `:first-child`, `:last-child` positional selectors
6948 // * `:empty` content emtpy selector
6949 // * `:empty` content emtpy selector
6950 // * `:checked` pseudo selector
6951 // * `:nth-child(n)`, `:nth-child(2n+1)` style positional calculations
6952 // * `:nth-child(even)`, `:nth-child(odd)` positional selectors
6953 // * `:not(...)` negation pseudo selectors
6955 // Any legal combination of these selectors will work with
6956 // `dojo.query()`, including compound selectors ("," delimited).
6957 // Very complex and useful searches can be constructed with this
6958 // palette of selectors and when combined with functions for
6959 // maniplation presented by dojo.NodeList, many types of DOM
6960 // manipulation operations become very straightforward.
6962 // Unsupported Selectors:
6963 // ----------------------
6965 // While dojo.query handles many CSS3 selectors, some fall outside of
6966 // what's resaonable for a programmatic node querying engine to
6967 // handle. Currently unsupported selectors include:
6969 // * namespace-differentiated selectors of any form
6970 // * all `::` pseduo-element selectors
6971 // * certain pseduo-selectors which don't get a lot of day-to-day use:
6972 // | * `:root`, `:lang()`, `:target`, `:focus`
6973 // * all visual and state selectors:
6974 // | * `:root`, `:active`, `:hover`, `:visisted`, `:link`,
6975 // `:enabled`, `:disabled`
6976 // * `:*-of-type` pseudo selectors
6978 // dojo.query and XML Documents:
6979 // -----------------------------
6981 // `dojo.query` currently only supports searching XML documents
6982 // whose tags and attributes are 100% lower-case. This is a known
6983 // limitation and will [be addressed soon](http://trac.dojotoolkit.org/ticket/3866)
6984 // Non-selector Queries:
6985 // ---------------------
6987 // If something other than a String is passed for the query,
6988 // `dojo.query` will return a new `dojo.NodeList` constructed from
6989 // that parameter alone and all further processing will stop. This
6990 // means that if you have a reference to a node or NodeList, you
6991 // can quickly construct a new NodeList from the original by
6992 // calling `dojo.query(node)` or `dojo.query(list)`.
6995 // The CSS3 expression to match against. For details on the syntax of
6996 // CSS3 selectors, see <http://www.w3.org/TR/css3-selectors/#selectors>
6998 // A DOMNode (or node id) to scope the search from. Optional.
6999 // returns: dojo.NodeList
7000 // An instance of `dojo.NodeList`. Many methods are available on
7001 // NodeLists for searching, iterating, manipulating, and handling
7002 // events on the matched nodes in the returned list.
7004 // search the entire document for elements with the class "foo":
7005 // | dojo.query(".foo");
7006 // these elements will match:
7007 // | <span class="foo"></span>
7008 // | <span class="foo bar"></span>
7009 // | <p class="thud foo"></p>
7011 // search the entire document for elements with the classes "foo" *and* "bar":
7012 // | dojo.query(".foo.bar");
7013 // these elements will match:
7014 // | <span class="foo bar"></span>
7015 // while these will not:
7016 // | <span class="foo"></span>
7017 // | <p class="thud foo"></p>
7019 // find `<span>` elements which are descendants of paragraphs and
7020 // which have a "highlighted" class:
7021 // | dojo.query("p span.highlighted");
7022 // the innermost span in this fragment matches:
7023 // | <p class="foo">
7025 // | <span class="highlighted foo bar">...</span>
7029 // set an "odd" class on all odd table rows inside of the table
7030 // `#tabular_data`, using the `>` (direct child) selector to avoid
7031 // affecting any nested tables:
7032 // | dojo.query("#tabular_data > tbody > tr:nth-child(odd)").addClass("odd");
7034 // remove all elements with the class "error" from the document
7035 // and store them in a list:
7036 // | var errors = dojo.query(".error").orphan();
7038 // add an onclick handler to every submit button in the document
7039 // which causes the form to be sent via Ajax instead:
7040 // | dojo.query("input[type='submit']").onclick(function(e){
7041 // | dojo.stopEvent(e); // prevent sending the form
7042 // | var btn = e.target;
7044 // | form: btn.form,
7045 // | load: function(data){
7046 // | // replace the form with the response
7047 // | var div = dojo.doc.createElement("div");
7048 // | dojo.place(div, btn.form, "after");
7049 // | div.innerHTML = data;
7050 // | dojo.style(btn.form, "display", "none");
7056 // NOTE: elementsById is not currently supported
7057 // NOTE: ignores xpath-ish queries for now
7059 if(query.constructor == d.NodeList){
7062 if(!d.isString(query)){
7063 return new d.NodeList(query); // dojo.NodeList
7065 if(d.isString(root)){
7066 root = d.byId(root);
7070 var od = root.ownerDocument||root.documentElement;
7071 caseSensitive = (root.contentType && root.contentType=="application/xml") || (!!od) && (d.isIE ? od.xml : (root.xmlVersion||od.xmlVersion));
7072 return _zip(getQueryFunc(query)(root)); // dojo.NodeList
7076 // exposing this was a mistake
7077 d.query.attrs = attrs;
7079 // exposing this because new pseudo matches are only executed through the
7080 // DOM query path (never through the xpath optimizing branch)
7081 d.query.pseudos = pseudos;
7083 // one-off function for filtering a NodeList based on a simple selector
7084 d._filterQueryResult = function(nodeList, simpleFilter){
7085 var tnl = new d.NodeList();
7086 var ff = (simpleFilter) ? getFilterFunc(getQueryParts(simpleFilter)[0]) : function(){ return true; };
7087 for(var x = 0, te; te = nodeList[x]; x++){
7088 if(ff(te)){ tnl.push(te); }
7096 if(!dojo._hasResource["dojo._base.xhr"]){ //_hasResource checks added by build. Do not use _hasResource directly in your code.
7097 dojo._hasResource["dojo._base.xhr"] = true;
7098 dojo.provide("dojo._base.xhr");
7106 function setValue(/*Object*/obj, /*String*/name, /*String*/value){
7108 // For the named property in object, set the value. If a value
7109 // already exists and it is a string, convert the value to be an
7111 var val = obj[name];
7112 if(_d.isString(val)){
7113 obj[name] = [val, value];
7114 }else if(_d.isArray(val)){
7121 dojo.formToObject = function(/*DOMNode||String*/ formNode){
7123 // dojo.formToObject returns the values encoded in an HTML form as
7124 // string properties in an object which it then returns. Disabled form
7125 // elements, buttons, and other non-value form elements are skipped.
7126 // Multi-select elements are returned as an array of string values.
7130 // | <form id="test_form">
7131 // | <input type="text" name="blah" value="blah">
7132 // | <input type="text" name="no_value" value="blah" disabled>
7133 // | <input type="button" name="no_value2" value="blah">
7134 // | <select type="select" multiple name="multi" size="5">
7135 // | <option value="blah">blah</option>
7136 // | <option value="thud" selected>thud</option>
7137 // | <option value="thonk" selected>thonk</option>
7141 // yields this object structure as the result of a call to
7153 var exclude = "file|submit|image|reset|button|";
7154 _d.forEach(dojo.byId(formNode).elements, function(item){
7155 var _in = item.name;
7156 var type = (item.type||"").toLowerCase();
7157 if(_in && type && exclude.indexOf(type) == -1 && !item.disabled){
7158 if(type == "radio" || type == "checkbox"){
7159 if(item.checked){ setValue(ret, _in, item.value); }
7160 }else if(item.multiple){
7162 _d.query("option", item).forEach(function(opt){
7164 setValue(ret, _in, opt.value);
7168 setValue(ret, _in, item.value);
7169 if(type == "image"){
7170 ret[_in+".x"] = ret[_in+".y"] = ret[_in].x = ret[_in].y = 0;
7175 return ret; // Object
7178 dojo.objectToQuery = function(/*Object*/ map){
7180 // takes a name/value mapping object and returns a string representing
7181 // a URL-encoded version of that object.
7193 // yields the following query string:
7195 // | "blah=blah&multi=thud&multi=thonk"
7197 // FIXME: need to implement encodeAscii!!
7198 var enc = encodeURIComponent;
7201 for(var name in map){
7202 var value = map[name];
7203 if(value != backstop[name]){
7204 var assign = enc(name) + "=";
7205 if(_d.isArray(value)){
7206 for(var i=0; i < value.length; i++){
7207 pairs.push(assign + enc(value[i]));
7210 pairs.push(assign + enc(value));
7214 return pairs.join("&"); // String
7217 dojo.formToQuery = function(/*DOMNode||String*/ formNode){
7219 // Returns a URL-encoded string representing the form passed as either a
7220 // node or string ID identifying the form to serialize
7221 return _d.objectToQuery(_d.formToObject(formNode)); // String
7224 dojo.formToJson = function(/*DOMNode||String*/ formNode, /*Boolean?*/prettyPrint){
7226 // return a serialized JSON string from a form node or string
7227 // ID identifying the form to serialize
7228 return _d.toJson(_d.formToObject(formNode), prettyPrint); // String
7231 dojo.queryToObject = function(/*String*/ str){
7233 // returns an object representing a de-serialized query section of a
7234 // URL. Query keys with multiple values are returned in an array.
7238 // | "foo=bar&foo=baz&thinger=%20spaces%20=blah&zonk=blarg&"
7240 // results in this object structure:
7243 // | foo: [ "bar", "baz" ],
7244 // | thinger: " spaces =blah",
7248 // Note that spaces and other urlencoded entities are correctly
7251 // FIXME: should we grab the URL string if we're not passed one?
7253 var qp = str.split("&");
7254 var dec = decodeURIComponent;
7255 _d.forEach(qp, function(item){
7257 var parts = item.split("=");
7258 var name = dec(parts.shift());
7259 var val = dec(parts.join("="));
7260 if(_d.isString(ret[name])){
7261 ret[name] = [ret[name]];
7263 if(_d.isArray(ret[name])){
7264 ret[name].push(val);
7270 return ret; // Object
7276 all bind() replacement APIs take the following argument structure:
7281 // all below are optional, but must be supported in some form by
7283 timeout: 1000, // milliseconds
7284 handleAs: "text", // replaces the always-wrong "mimetype"
7289 // browser-specific, MAY be unsupported
7290 sync: true, // defaults to false
7291 form: dojo.byId("someForm")
7295 // need to block async callbacks from snatching this thread as the result
7296 // of an async callback might call another sync XHR, this hangs khtml forever
7297 // must checked by watchInFlight()
7299 dojo._blockAsync = false;
7301 dojo._contentHandlers = {
7302 "text": function(xhr){ return xhr.responseText; },
7303 "json": function(xhr){
7304 return _d.fromJson(xhr.responseText || null);
7306 "json-comment-filtered": function(xhr){
7307 // NOTE: the json-comment-filtered option was implemented to prevent
7308 // "JavaScript Hijacking", but it is less secure than standard JSON. Use
7309 // standard JSON instead. JSON prefixing can be used to subvert hijacking.
7310 if(!dojo.config.useCommentedJson){
7311 console.warn("Consider using the standard mimetype:application/json."
7312 + " json-commenting can introduce security issues. To"
7313 + " decrease the chances of hijacking, use the standard the 'json' handler and"
7314 + " prefix your json with: {}&&\n"
7315 + "Use djConfig.useCommentedJson=true to turn off this message.");
7318 var value = xhr.responseText;
7319 var cStartIdx = value.indexOf("\/*");
7320 var cEndIdx = value.lastIndexOf("*\/");
7321 if(cStartIdx == -1 || cEndIdx == -1){
7322 throw new Error("JSON was not comment filtered");
7324 return _d.fromJson(value.substring(cStartIdx+2, cEndIdx));
7326 "javascript": function(xhr){
7327 // FIXME: try Moz and IE specific eval variants?
7328 return _d.eval(xhr.responseText);
7330 "xml": function(xhr){
7331 var result = xhr.responseXML;
7332 if(_d.isIE && (!result || result.documentElement == null)){
7333 _d.forEach(["MSXML2", "Microsoft", "MSXML", "MSXML3"], function(prefix){
7335 var dom = new ActiveXObject(prefix + ".XMLDOM");
7337 dom.loadXML(xhr.responseText);
7339 }catch(e){ /* Not available. Squelch and try next one. */ }
7342 return result; // DOMDocument
7346 dojo._contentHandlers["json-comment-optional"] = function(xhr){
7347 var handlers = _d._contentHandlers;
7348 if(xhr.responseText && xhr.responseText.indexOf("\/*") != -1){
7349 return handlers["json-comment-filtered"](xhr);
7351 return handlers["json"](xhr);
7356 dojo.__IoArgs = function(){
7358 // URL to server endpoint.
7360 // Contains properties with string values. These
7361 // properties will be serialized as name1=value2 and
7362 // passed in the request.
7363 // timeout: Integer?
7364 // Milliseconds to wait for the response. If this time
7365 // passes, the then error callbacks are called.
7367 // DOM node for a form. Used to extract the form values
7368 // and send to the server.
7369 // preventCache: Boolean?
7370 // Default is false. If true, then a
7371 // "dojo.preventCache" parameter is sent in the request
7372 // with a value that changes with each request
7373 // (timestamp). Useful only with GET-type requests.
7374 // handleAs: String?
7375 // Acceptable values depend on the type of IO
7376 // transport (see specific IO calls for more information).
7378 // function(response, ioArgs){} response is of type Object, ioArgs
7379 // is of type dojo.__IoCallbackArgs. This function will be
7380 // called on a successful HTTP response code.
7382 // function(response, ioArgs){} response is of type Object, ioArgs
7383 // is of type dojo.__IoCallbackArgs. This function will
7384 // be called when the request fails due to a network or server error, the url
7385 // is invalid, etc. It will also be called if the load or handle callback throws an
7386 // exception, unless djConfig.isDebug is true. This allows deployed applications
7387 // to continue to run even when a logic error happens in the callback, while making
7388 // it easier to troubleshoot while in debug mode.
7389 // handle: Function?
7390 // function(response, ioArgs){} response is of type Object, ioArgs
7391 // is of type dojo.__IoCallbackArgs. This function will
7392 // be called at the end of every request, whether or not an error occurs.
7394 this.content = content;
7395 this.timeout = timeout;
7397 this.preventCache = preventCache;
7398 this.handleAs = handleAs;
7401 this.handle = handle;
7406 dojo.__IoCallbackArgs = function(args, xhr, url, query, handleAs, id, canDelete, json){
7408 // the original object argument to the IO call.
7409 // xhr: XMLHttpRequest
7410 // For XMLHttpRequest calls only, the
7411 // XMLHttpRequest object that was used for the
7414 // The final URL used for the call. Many times it
7415 // will be different than the original args.url
7418 // For non-GET requests, the
7419 // name1=value1&name2=value2 parameters sent up in
7422 // The final indicator on how the response will be
7425 // For dojo.io.script calls only, the internal
7426 // script ID used for the request.
7427 // canDelete: Boolean
7428 // For dojo.io.script calls only, indicates
7429 // whether the script tag that represents the
7430 // request can be deleted after callbacks have
7431 // been called. Used internally to know when
7432 // cleanup can happen on JSONP-type requests.
7434 // For dojo.io.script calls only: holds the JSON
7435 // response for JSONP-type requests. Used
7436 // internally to hold on to the JSON responses.
7437 // You should not need to access it directly --
7438 // the same object should be passed to the success
7439 // callbacks directly.
7444 this.handleAs = handleAs;
7446 this.canDelete = canDelete;
7453 dojo._ioSetArgs = function(/*dojo.__IoArgs*/args,
7454 /*Function*/canceller,
7455 /*Function*/okHandler,
7456 /*Function*/errHandler){
7458 // sets up the Deferred and ioArgs property on the Deferred so it
7459 // can be used in an io call.
7461 // The args object passed into the public io call. Recognized properties on
7462 // the args object are:
7464 // The canceller function used for the Deferred object. The function
7465 // will receive one argument, the Deferred object that is related to the
7468 // The first OK callback to be registered with Deferred. It has the opportunity
7469 // to transform the OK response. It will receive one argument -- the Deferred
7470 // object returned from this function.
7472 // The first error callback to be registered with Deferred. It has the opportunity
7473 // to do cleanup on an error. It will receive two arguments: error (the
7474 // Error object) and dfd, the Deferred object returned from this function.
7476 var ioArgs = {args: args, url: args.url};
7478 //Get values from form if requestd.
7479 var formObject = null;
7481 var form = _d.byId(args.form);
7482 //IE requires going through getAttributeNode instead of just getAttribute in some form cases,
7483 //so use it for all. See #2844
7484 var actnNode = form.getAttributeNode("action");
7485 ioArgs.url = ioArgs.url || (actnNode ? actnNode.value : null);
7486 formObject = _d.formToObject(form);
7489 // set up the query params
7493 // potentially over-ride url-provided params w/ form values
7494 miArgs.push(formObject);
7497 // stuff in content over-rides what's set by form
7498 miArgs.push(args.content);
7500 if(args.preventCache){
7501 miArgs.push({"dojo.preventCache": new Date().valueOf()});
7503 ioArgs.query = _d.objectToQuery(_d.mixin.apply(null, miArgs));
7505 // .. and the real work of getting the deferred in order, etc.
7506 ioArgs.handleAs = args.handleAs || "text";
7507 var d = new _d.Deferred(canceller);
7508 d.addCallbacks(okHandler, function(error){
7509 return errHandler(error, d);
7512 //Support specifying load, error and handle callback functions from the args.
7513 //For those callbacks, the "this" object will be the args object.
7514 //The callbacks will get the deferred result value as the
7515 //first argument and the ioArgs object as the second argument.
7517 if(ld && _d.isFunction(ld)){
7518 d.addCallback(function(value){
7519 return ld.call(args, value, ioArgs);
7522 var err = args.error;
7523 if(err && _d.isFunction(err)){
7524 d.addErrback(function(value){
7525 return err.call(args, value, ioArgs);
7528 var handle = args.handle;
7529 if(handle && _d.isFunction(handle)){
7530 d.addBoth(function(value){
7531 return handle.call(args, value, ioArgs);
7537 // FIXME: need to wire up the xhr object's abort method to something
7538 // analagous in the Deferred
7542 var _deferredCancel = function(/*Deferred*/dfd){
7543 //summary: canceller function for dojo._ioSetArgs call.
7545 dfd.canceled = true;
7546 var xhr = dfd.ioArgs.xhr;
7547 var _at = typeof xhr.abort;
7548 if(_at == "function" || _at == "object" || _at == "unknown"){
7551 var err = dfd.ioArgs.error;
7553 err = new Error("xhr cancelled");
7554 err.dojoType="cancel";
7558 var _deferredOk = function(/*Deferred*/dfd){
7559 //summary: okHandler function for dojo._ioSetArgs call.
7561 var ret = _d._contentHandlers[dfd.ioArgs.handleAs](dfd.ioArgs.xhr);
7562 return (typeof ret == "undefined") ? null : ret;
7564 var _deferError = function(/*Error*/error, /*Deferred*/dfd){
7565 //summary: errHandler function for dojo._ioSetArgs call.
7571 // avoid setting a timer per request. It degrades performance on IE
7572 // something fierece if we don't use unified loops.
7573 var _inFlightIntvl = null;
7575 var _watchInFlight = function(){
7577 // internal method that checks each inflight XMLHttpRequest to see
7578 // if it has completed or if the timeout situation applies.
7580 var now = (new Date()).getTime();
7581 // make sure sync calls stay thread safe, if this callback is called
7582 // during a sync call and this results in another sync call before the
7583 // first sync call ends the browser hangs
7584 if(!_d._blockAsync){
7585 // we need manual loop because we often modify _inFlight (and therefore 'i') while iterating
7586 // note: the second clause is an assigment on purpose, lint may complain
7587 for(var i = 0, tif; i < _inFlight.length && (tif = _inFlight[i]); i++){
7589 var func = function(){
7590 if(!dfd || dfd.canceled || !tif.validCheck(dfd)){
7591 _inFlight.splice(i--, 1);
7592 }else if(tif.ioCheck(dfd)){
7593 _inFlight.splice(i--, 1);
7595 }else if(dfd.startTime){
7597 if(dfd.startTime + (dfd.ioArgs.args.timeout || 0) < now){
7598 _inFlight.splice(i--, 1);
7599 var err = new Error("timeout exceeded");
7600 err.dojoType = "timeout";
7602 //Cancel the request so the io module can do appropriate cleanup.
7607 if(dojo.config.isDebug){
7619 if(!_inFlight.length){
7620 clearInterval(_inFlightIntvl);
7621 _inFlightIntvl = null;
7627 dojo._ioCancelAll = function(){
7628 //summary: Cancels all pending IO requests, regardless of IO type
7629 //(xhr, script, iframe).
7631 _d.forEach(_inFlight, function(i){
7634 }catch(e){/*squelch*/}
7636 }catch(e){/*squelch*/}
7639 //Automatically call cancel all io calls on unload
7640 //in IE for trac issue #2357.
7642 _d.addOnWindowUnload(_d._ioCancelAll);
7645 _d._ioWatch = function(/*Deferred*/dfd,
7646 /*Function*/validCheck,
7647 /*Function*/ioCheck,
7648 /*Function*/resHandle){
7649 //summary: watches the io request represented by dfd to see if it completes.
7651 // The Deferred object to watch.
7653 // Function used to check if the IO request is still valid. Gets the dfd
7654 // object as its only argument.
7656 // Function used to check if basic IO call worked. Gets the dfd
7657 // object as its only argument.
7659 // Function used to process response. Gets the dfd
7660 // object as its only argument.
7661 if(dfd.ioArgs.args.timeout){
7662 dfd.startTime = (new Date()).getTime();
7664 _inFlight.push({dfd: dfd, validCheck: validCheck, ioCheck: ioCheck, resHandle: resHandle});
7665 if(!_inFlightIntvl){
7666 _inFlightIntvl = setInterval(_watchInFlight, 50);
7668 _watchInFlight(); // handle sync requests
7671 var _defaultContentType = "application/x-www-form-urlencoded";
7673 var _validCheck = function(/*Deferred*/dfd){
7674 return dfd.ioArgs.xhr.readyState; //boolean
7676 var _ioCheck = function(/*Deferred*/dfd){
7677 return 4 == dfd.ioArgs.xhr.readyState; //boolean
7679 var _resHandle = function(/*Deferred*/dfd){
7680 var xhr = dfd.ioArgs.xhr;
7681 if(_d._isDocumentOk(xhr)){
7684 var err = new Error("Unable to load " + dfd.ioArgs.url + " status:" + xhr.status);
7685 err.status = xhr.status;
7686 err.responseText = xhr.responseText;
7691 dojo._ioAddQueryToUrl = function(/*dojo.__IoCallbackArgs*/ioArgs){
7692 //summary: Adds query params discovered by the io deferred construction to the URL.
7693 //Only use this for operations which are fundamentally GET-type operations.
7694 if(ioArgs.query.length){
7695 ioArgs.url += (ioArgs.url.indexOf("?") == -1 ? "?" : "&") + ioArgs.query;
7696 ioArgs.query = null;
7701 dojo.declare("dojo.__XhrArgs", dojo.__IoArgs, {
7702 constructor: function(){
7704 // In addition to the properties listed for the dojo._IoArgs type,
7705 // the following properties are allowed for dojo.xhr* methods.
7706 // handleAs: String?
7707 // Acceptable values are: text (default), json, json-comment-optional,
7708 // json-comment-filtered, javascript, xml
7710 // false is default. Indicates whether the request should
7711 // be a synchronous (blocking) request.
7713 // Additional HTTP headers to send in the request.
7714 this.handleAs = handleAs;
7716 this.headers = headers;
7721 dojo.xhr = function(/*String*/ method, /*dojo.__XhrArgs*/ args, /*Boolean?*/ hasBody){
7723 // Sends an HTTP request with the given method.
7725 // Sends an HTTP request with the given method.
7726 // See also dojo.xhrGet(), xhrPost(), xhrPut() and dojo.xhrDelete() for shortcuts
7727 // for those HTTP methods. There are also methods for "raw" PUT and POST methods
7728 // via dojo.rawXhrPut() and dojo.rawXhrPost() respectively.
7730 // HTTP method to be used, such as GET, POST, PUT, DELETE. Should be uppercase.
7732 // If the request has an HTTP body, then pass true for hasBody.
7734 //Make the Deferred object for this xhr request.
7735 var dfd = _d._ioSetArgs(args, _deferredCancel, _deferredOk, _deferError);
7737 //Pass the args to _xhrObj, to allow xhr iframe proxy interceptions.
7738 dfd.ioArgs.xhr = _d._xhrObj(dfd.ioArgs.args);
7741 if("postData" in args){
7742 dfd.ioArgs.query = args.postData;
7743 }else if("putData" in args){
7744 dfd.ioArgs.query = args.putData;
7747 _d._ioAddQueryToUrl(dfd.ioArgs);
7750 // IE 6 is a steaming pile. It won't let you call apply() on the native function (xhr.open).
7751 // workaround for IE6's apply() "issues"
7752 var ioArgs = dfd.ioArgs;
7753 var xhr = ioArgs.xhr;
7754 xhr.open(method, ioArgs.url, args.sync !== true, args.user || undefined, args.password || undefined);
7756 for(var hdr in args.headers){
7757 if(hdr.toLowerCase() === "content-type" && !args.contentType){
7758 args.contentType = args.headers[hdr];
7760 xhr.setRequestHeader(hdr, args.headers[hdr]);
7764 // FIXME: is this appropriate for all content types?
7765 xhr.setRequestHeader("Content-Type", args.contentType || _defaultContentType);
7766 if(!args.headers || !args.headers["X-Requested-With"]){
7767 xhr.setRequestHeader("X-Requested-With", "XMLHttpRequest");
7769 // FIXME: set other headers here!
7770 if(dojo.config.isDebug){
7771 xhr.send(ioArgs.query);
7774 xhr.send(ioArgs.query);
7776 dfd.ioArgs.error = e;
7780 _d._ioWatch(dfd, _validCheck, _ioCheck, _resHandle);
7782 return dfd; // dojo.Deferred
7785 dojo.xhrGet = function(/*dojo.__XhrArgs*/ args){
7787 // Sends an HTTP GET request to the server.
7788 return _d.xhr("GET", args); // dojo.Deferred
7791 dojo.rawXhrPost = dojo.xhrPost = function(/*dojo.__XhrArgs*/ args){
7793 // Sends an HTTP POST request to the server. In addtion to the properties
7794 // listed for the dojo.__XhrArgs type, the following property is allowed:
7796 // String. Send raw data in the body of the POST request.
7797 return _d.xhr("POST", args, true); // dojo.Deferred
7800 dojo.rawXhrPut = dojo.xhrPut = function(/*dojo.__XhrArgs*/ args){
7802 // Sends an HTTP PUT request to the server. In addtion to the properties
7803 // listed for the dojo.__XhrArgs type, the following property is allowed:
7805 // String. Send raw data in the body of the PUT request.
7806 return _d.xhr("PUT", args, true); // dojo.Deferred
7809 dojo.xhrDelete = function(/*dojo.__XhrArgs*/ args){
7811 // Sends an HTTP DELETE request to the server.
7812 return _d.xhr("DELETE", args); //dojo.Deferred
7816 dojo.wrapForm = function(formNode){
7818 // A replacement for FormBind, but not implemented yet.
7820 // FIXME: need to think harder about what extensions to this we might
7821 // want. What should we allow folks to do w/ this? What events to
7823 throw new Error("dojo.wrapForm not yet implemented");
7830 if(!dojo._hasResource["dojo._base.fx"]){ //_hasResource checks added by build. Do not use _hasResource directly in your code.
7831 dojo._hasResource["dojo._base.fx"] = true;
7832 dojo.provide("dojo._base.fx");
7840 Animation losely package based on Dan Pupius' work, contributed under CLA:
7841 http://pupius.co.uk/js/Toolkit.Drawing.js
7847 dojo._Line = function(/*int*/ start, /*int*/ end){
7849 // dojo._Line is the object used to generate values from a start value
7852 // Beginning value for range
7854 // Ending value for range
7857 this.getValue = function(/*float*/ n){
7858 // summary: returns the point on the line
7859 // n: a floating point number greater than 0 and less than 1
7860 return ((this.end - this.start) * n) + this.start; // Decimal
7864 d.declare("dojo._Animation", null, {
7866 // A generic animation class that fires callbacks into its handlers
7867 // object at various states. Nearly all dojo animation functions
7868 // return an instance of this method, usually without calling the
7869 // .play() method beforehand. Therefore, you will likely need to
7870 // call .play() on instances of dojo._Animation when one is
7872 constructor: function(/*Object*/ args){
7873 d.mixin(this, args);
7874 if(d.isArray(this.curve)){
7877 this.curve = new d._Line(this.curve[0], this.curve[1]);
7881 // duration: Integer
7882 // The time in milliseonds the animation will take to run
7886 // curve: dojo._Line||Array
7887 // A two element array of start and end values, or a dojo._Line instance to be
7888 // used in the Animation.
7892 // A Function to adjust the acceleration (or deceleration) of the progress
7893 // across a dojo._Line
7898 // The number of times to loop the animation
7902 // the time in milliseconds to wait before advancing to next frame
7903 // (used as a fps timer: rate/1000 = fps)
7904 rate: 10 /* 100 fps */,
7908 // The time in milliseconds to wait before starting animation after it has been .play()'ed
7913 // beforeBegin: Event
7914 // Synthetic event fired before a dojo._Animation begins playing (synchronous)
7918 // Synthetic event fired as a dojo._Animation begins playing (useful?)
7922 // Synthetic event fired at each interval of a dojo._Animation
7926 // Synthetic event fired after the final frame of a dojo._Animation
7930 // Synthetic event fired any time a dojo._Animation is play()'ed
7934 // Synthetic event fired when a dojo._Animation is paused
7938 // Synthetic event fires when a dojo._Animation is stopped
7944 _startRepeatCount: 0,
7946 _fire: function(/*Event*/ evt, /*Array?*/ args){
7948 // Convenience function. Fire event "evt" and pass it the
7949 // arguments specified in "args".
7951 // The event to fire.
7953 // The arguments to pass to the event.
7955 if(dojo.config.isDebug){
7956 this[evt].apply(this, args||[]);
7959 this[evt].apply(this, args||[]);
7961 // squelch and log because we shouldn't allow exceptions in
7962 // synthetic event handlers to cause the internal timer to run
7963 // amuck, potentially pegging the CPU. I'm not a fan of this
7964 // squelch, but hopefully logging will make it clear what's
7966 console.error("exception in animation handler for:", evt);
7971 return this; // dojo._Animation
7974 play: function(/*int?*/ delay, /*Boolean?*/ gotoStart){
7976 // Start the animation.
7978 // How many milliseconds to delay before starting.
7980 // If true, starts the animation from the beginning; otherwise,
7981 // starts it from its current position.
7985 _t._active = _t._paused = false;
7987 }else if(_t._active && !_t._paused){
7988 return _t; // dojo._Animation
7991 _t._fire("beforeBegin");
7993 var de = delay||_t.delay;
7994 var _p = dojo.hitch(_t, "_play", gotoStart);
7997 return _t; // dojo._Animation
8003 _play: function(gotoStart){
8005 _t._startTime = new Date().valueOf();
8007 _t._startTime -= _t.duration * _t._percent;
8009 _t._endTime = _t._startTime + _t.duration;
8014 var value = _t.curve.getValue(_t._percent);
8016 if(!_t._startRepeatCount){
8017 _t._startRepeatCount = _t.repeat;
8019 _t._fire("onBegin", [value]);
8022 _t._fire("onPlay", [value]);
8025 return _t; // dojo._Animation
8029 // summary: Pauses a running animation.
8031 if(!this._active){ return this; /*dojo._Animation*/ }
8032 this._paused = true;
8033 this._fire("onPause", [this.curve.getValue(this._percent)]);
8034 return this; // dojo._Animation
8037 gotoPercent: function(/*Decimal*/ percent, /*Boolean?*/ andPlay){
8039 // Sets the progress of the animation.
8041 // A percentage in decimal notation (between and including 0.0 and 1.0).
8043 // If true, play the animation after setting the progress.
8045 this._active = this._paused = true;
8046 this._percent = percent;
8047 if(andPlay){ this.play(); }
8048 return this; // dojo._Animation
8051 stop: function(/*boolean?*/ gotoEnd){
8052 // summary: Stops a running animation.
8053 // gotoEnd: If true, the animation will end.
8054 if(!this._timer){ return this; /* dojo._Animation */ }
8059 this._fire("onStop", [this.curve.getValue(this._percent)]);
8060 this._active = this._paused = false;
8061 return this; // dojo._Animation
8065 // summary: Returns a string token representation of the status of
8066 // the animation, one of: "paused", "playing", "stopped"
8068 return this._paused ? "paused" : "playing"; // String
8070 return "stopped"; // String
8076 var curr = new Date().valueOf();
8077 var step = (curr - _t._startTime) / (_t._endTime - _t._startTime);
8086 step = _t.easing(step);
8089 _t._fire("onAnimate", [_t.curve.getValue(step)]);
8091 if(_t._percent < 1){
8098 _t.play(null, true);
8099 }else if(_t.repeat == -1){
8100 _t.play(null, true);
8102 if(_t._startRepeatCount){
8103 _t.repeat = _t._startRepeatCount;
8104 _t._startRepeatCount = 0;
8112 return _t; // dojo._Animation
8117 var _globalTimerList = [];
8122 dojo._Animation.prototype._startTimer = function(){
8123 // this._timer = setTimeout(dojo.hitch(this, "_cycle"), this.rate);
8125 this._timer = d.connect(runner, "run", this, "_cycle");
8129 timer = setInterval(d.hitch(runner, "run"), this.rate);
8133 dojo._Animation.prototype._stopTimer = function(){
8135 d.disconnect(this._timer);
8140 clearInterval(timer);
8146 var _makeFadeable = (d.isIE) ? function(node){
8147 // only set the zoom if the "tickle" value would be the same as the
8149 var ns = node.style;
8150 // don't set the width to auto if it didn't already cascade that way.
8151 // We don't want to f anyones designs
8152 if(!ns.width.length && d.style(node, "width") == "auto"){
8157 dojo._fade = function(/*Object*/ args){
8159 // Returns an animation that will fade the node defined by
8160 // args.node from the start to end values passed (args.start
8161 // args.end) (end is mandatory, start is optional)
8163 args.node = d.byId(args.node);
8164 var fArgs = d.mixin({ properties: {} }, args);
8165 var props = (fArgs.properties.opacity = {});
8166 props.start = !("start" in fArgs) ?
8168 return Number(d.style(fArgs.node, "opacity"));
8170 props.end = fArgs.end;
8172 var anim = d.animateProperty(fArgs);
8173 d.connect(anim, "beforeBegin", d.partial(_makeFadeable, fArgs.node));
8175 return anim; // dojo._Animation
8179 dojo.__FadeArgs = function(node, duration, easing){
8180 // node: DOMNode|String
8181 // The node referenced in the animation
8182 // duration: Integer?
8183 // Duration of the animation in milliseconds.
8184 // easing: Function?
8185 // An easing function.
8187 this.duration = duration;
8188 this.easing = easing;
8192 dojo.fadeIn = function(/*dojo.__FadeArgs*/ args){
8194 // Returns an animation that will fade node defined in 'args' from
8195 // its current opacity to fully opaque.
8196 return d._fade(d.mixin({ end: 1 }, args)); // dojo._Animation
8199 dojo.fadeOut = function(/*dojo.__FadeArgs*/ args){
8201 // Returns an animation that will fade node defined in 'args'
8202 // from its current opacity to fully transparent.
8203 return d._fade(d.mixin({ end: 0 }, args)); // dojo._Animation
8206 dojo._defaultEasing = function(/*Decimal?*/ n){
8207 // summary: The default easing function for dojo._Animation(s)
8208 return 0.5 + ((Math.sin((n + 1.5) * Math.PI))/2);
8211 var PropLine = function(properties){
8212 // PropLine is an internal class which is used to model the values of
8213 // an a group of CSS properties across an animation lifecycle. In
8214 // particular, the "getValue" function handles getting interpolated
8215 // values between start and end for a particular CSS value.
8216 this._properties = properties;
8217 for(var p in properties){
8218 var prop = properties[p];
8219 if(prop.start instanceof d.Color){
8220 // create a reusable temp color object to keep intermediate results
8221 prop.tempColor = new d.Color();
8224 this.getValue = function(r){
8226 for(var p in this._properties){
8227 var prop = this._properties[p];
8228 var start = prop.start;
8229 if(start instanceof d.Color){
8230 ret[p] = d.blendColors(start, prop.end, r, prop.tempColor).toCss();
8231 }else if(!d.isArray(start)){
8232 ret[p] = ((prop.end - start) * r) + start + (p != "opacity" ? prop.units||"px" : "");
8240 dojo.declare("dojo.__AnimArgs", [dojo.__FadeArgs], {
8241 // Properties: Object?
8242 // A hash map of style properties to Objects describing the transition,
8243 // such as the properties of dojo._Line with an additional 'unit' property
8246 //TODOC: add event callbacks
8250 dojo.animateProperty = function(/*dojo.__AnimArgs*/ args){
8252 // Returns an animation that will transition the properties of
8253 // node defined in 'args' depending how they are defined in
8254 // 'args.properties'
8257 // dojo.animateProperty is the foundation of most dojo.fx
8258 // animations. It takes an object of "properties" corresponding to
8259 // style properties, and animates them in parallel over a set
8263 // A simple animation that changes the width of the specified node.
8264 // | dojo.animateProperty({
8265 // | node: "nodeId",
8266 // | properties: { width: 400 },
8268 // Dojo figures out the start value for the width and converts the
8269 // integer specified for the width to the more expressive but
8270 // verbose form `{ width: { end: '400', units: 'px' } }` which you
8271 // can also specify directly
8274 // Animate width, height, and padding over 2 seconds... the
8276 // | dojo.animateProperty({ node: node, duration:2000,
8278 // | width: { start: '200', end: '400', unit:"px" },
8279 // | height: { start:'200', end: '400', unit:"px" },
8280 // | paddingTop: { start:'5', end:'50', unit:"px" }
8283 // Note 'paddingTop' is used over 'padding-top'. Multi-name CSS properties
8284 // are written using "mixed case", as the hyphen is illegal as an object key.
8287 // Plug in a different easing function and register a callback for
8288 // when the animation ends. Easing functions accept values between
8289 // zero and one and return a value on that basis. In this case, an
8290 // exponential-in curve.
8291 // | dojo.animateProperty({
8292 // | node: "nodeId",
8293 // | // dojo figures out the start value
8294 // | properties: { width: { end: 400 } },
8295 // | easing: function(n){
8296 // | return (n==0) ? 0 : Math.pow(2, 10 * (n - 1));
8298 // | onEnd: function(){
8299 // | // called when the animation finishes
8301 // | }).play(500); // delay playing half a second
8304 // Like all `dojo._Animation`s, animateProperty returns a handle to the
8305 // Animation instance, which fires the events common to Dojo FX. Use `dojo.connect`
8306 // to access these events outside of the Animation definiton:
8307 // | var anim = dojo.animateProperty({
8310 // | width:400, height:500
8313 // | dojo.connect(anim,"onEnd", function(){
8316 // | // play the animation now:
8319 args.node = d.byId(args.node);
8320 if(!args.easing){ args.easing = d._defaultEasing; }
8322 var anim = new d._Animation(args);
8323 d.connect(anim, "beforeBegin", anim, function(){
8325 for(var p in this.properties){
8326 // Make shallow copy of properties into pm because we overwrite
8327 // some values below. In particular if start/end are functions
8328 // we don't want to overwrite them or the functions won't be
8329 // called if the animation is reused.
8330 if(p == "width" || p == "height"){
8331 this.node.display = "block";
8333 var prop = this.properties[p];
8334 prop = pm[p] = d.mixin({}, (d.isObject(prop) ? prop: { end: prop }));
8336 if(d.isFunction(prop.start)){
8337 prop.start = prop.start();
8339 if(d.isFunction(prop.end)){
8340 prop.end = prop.end();
8342 var isColor = (p.toLowerCase().indexOf("color") >= 0);
8343 function getStyle(node, p){
8344 // dojo.style(node, "height") can return "auto" or "" on IE; this is more reliable:
8345 var v = ({height: node.offsetHeight, width: node.offsetWidth})[p];
8346 if(v !== undefined){ return v; }
8347 v = d.style(node, p);
8348 return (p=="opacity") ? Number(v) : (isColor ? v : parseFloat(v));
8350 if(!("end" in prop)){
8351 prop.end = getStyle(this.node, p);
8352 }else if(!("start" in prop)){
8353 prop.start = getStyle(this.node, p);
8357 prop.start = new d.Color(prop.start);
8358 prop.end = new d.Color(prop.end);
8360 prop.start = (p == "opacity") ? Number(prop.start) : parseFloat(prop.start);
8363 this.curve = new PropLine(pm);
8365 d.connect(anim, "onAnimate", d.hitch(d, "style", anim.node));
8366 return anim; // dojo._Animation
8369 dojo.anim = function( /*DOMNode|String*/ node,
8370 /*Object*/ properties,
8371 /*Integer?*/ duration,
8372 /*Function?*/ easing,
8373 /*Function?*/ onEnd,
8374 /*Integer?*/ delay){
8376 // A simpler interface to `dojo.animateProperty()`, also returns
8377 // an instance of `dojo._Animation` but begins the animation
8378 // immediately, unlike nearly every other Dojo animation API.
8380 // `dojo.anim` is a simpler (but somewhat less powerful) version
8381 // of `dojo.animateProperty`. It uses defaults for many basic properties
8382 // and allows for positional parameters to be used in place of the
8383 // packed "property bag" which is used for other Dojo animation
8386 // The `dojo._Animation` object returned from `dojo.anim` will be
8387 // already playing when it is returned from this function, so
8388 // calling play() on it again is (usually) a no-op.
8390 // a DOM node or the id of a node to animate CSS properties on
8392 // The number of milliseconds over which the animation
8393 // should run. Defaults to the global animation default duration
8396 // An easing function over which to calculate acceleration
8397 // and deceleration of the animation through its duration.
8398 // A default easing algorithm is provided, but you may
8399 // plug in any you wish. A large selection of easing algorithms
8400 // are available in `dojo.fx.easing`.
8402 // A function to be called when the animation finishes
8405 // The number of milliseconds to delay beginning the
8406 // animation by. The default is 0.
8409 // | dojo.anim("id", { opacity: 0 });
8411 // Fade out a node over a full second
8412 // | dojo.anim("id", { opacity: 0 }, 1000);
8413 return d.animateProperty({
8415 duration: duration||d._Animation.prototype.duration,
8416 properties: properties,
8425 if(!dojo._hasResource["dojo._base.browser"]){ //_hasResource checks added by build. Do not use _hasResource directly in your code.
8426 dojo._hasResource["dojo._base.browser"] = true;
8427 dojo.provide("dojo._base.browser");
8437 //Need this to be the last code segment in base, so do not place any
8438 //dojo.requireIf calls in this file. Otherwise, due to how the build system
8439 //puts all requireIf dependencies after the current file, the require calls
8440 //could be called before all of base is defined.
8441 if(dojo.config.require){
8442 dojo.forEach(dojo.config.require, "dojo['require'](item);");
8447 //INSERT dojo.i18n._preloadLocalizations HERE
8449 if(dojo.config.afterOnLoad && dojo.isBrowser){
8450 //Dojo is being added to the page after page load, so just trigger
8451 //the init sequence after a timeout. Using a timeout so the rest of this
8452 //script gets evaluated properly. This work needs to happen after the
8453 //dojo.config.require work done in dojo._base.
8454 window.setTimeout(dojo._fakeLoadInit, 1000);