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: 15385 $".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: 0, 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 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 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);